[
  {
    "path": ".cursor/rules/code-style.mdc",
    "content": "---\ndescription: \nglobs: \nalwaysApply: false\n---\n# Code Style Guidelines\n\nThis document outlines the code style and conventions for the Amplitude TypeScript SDK monorepo.\n\n## TypeScript Conventions\n\n### General Rules\n- Use TypeScript strict mode with all compiler checks enabled as defined in [tsconfig.json](mdc:tsconfig.json)\n- Always define explicit return types for public methods and functions\n- Use meaningful variable and function names that clearly describe their purpose\n- Prefer `const` over `let` when variables won't be reassigned\n- Use template literals instead of string concatenation\n- Avoid `any` type - use proper typing or generic constraints instead\n\n### Interface and Type Definitions\n- Use `interface` for object shapes that might be extended\n- Use `type` for unions, intersections, and computed types\n- Export types that are used across package boundaries\n- Use PascalCase for interfaces and type names (e.g., `EventType`, `BrowserConfig`)\n\n### Function and Method Conventions\n- Use camelCase for function and method names\n- Use async/await instead of raw Promises for better readability\n- Keep functions focused on a single responsibility\n- Use proper JSDoc comments for public APIs\n\n### Import/Export Standards\n- Use named imports/exports over default exports for better tree-shaking\n- Group imports in this order: external libraries, internal packages, relative imports\n- Use absolute imports for cross-package references in the monorepo\n- Consistent barrel exports in `index.ts` files\n\n## Code Organization\n\n### File Structure\n- Follow the established pattern from [packages/analytics-browser/src](mdc:packages/analytics-browser/src)\n- Group related functionality in dedicated directories (config, plugins, utils, etc.)\n- Use descriptive file names that match their primary export\n\n### Class Organization\n- Private methods and properties should be prefixed with underscore\n- Group methods logically: constructor, public methods, private methods\n- Use readonly properties where appropriate\n- Implement proper error handling and validation\n\n## Formatting Rules\n\nThe project uses Prettier with the following configuration from [.prettierrc.json](mdc:.prettierrc.json):\n- Line width: 120 characters\n- Single quotes for strings\n- Trailing commas in all contexts\n- Proper prose wrapping for markdown\n\n## Linting Standards\n\nFollow the ESLint configuration defined in [.eslintrc.js](mdc:.eslintrc.js):\n- No unused variables (except function parameters)\n- Require explicit return types for TypeScript functions\n- No multiple empty lines\n- End files with newline\n- Avoid unsafe global access (window, globalThis, self) except in test files\n\n## Package-Specific Conventions\n\n### Browser Packages\n- Use feature detection instead of user agent sniffing\n- Implement proper error boundaries for browser APIs\n- Follow the established plugin architecture pattern\n- Ensure backwards compatibility with older browser versions\n\n### Node.js Packages  \n- Use appropriate Node.js APIs and avoid browser-specific code\n- Implement proper error handling for server environments\n- Follow semantic versioning for breaking changes\n\n## Testing Conventions\n- Use Jest for unit testing as configured in [jest.config.js](mdc:jest.config.js)\n- Follow the naming pattern `*.test.ts` for test files\n- Write descriptive test names that explain the expected behavior\n- Use proper mocking for external dependencies\n- Maintain high test coverage for public APIs\n\n## Error Handling\n- Use custom error classes with descriptive messages\n- Implement proper error boundaries in browser environments\n- Log errors with appropriate context for debugging\n- Provide meaningful error messages for developers\n\n## Performance Guidelines\n- Avoid blocking operations in browser environments\n- Use lazy loading for optional features\n- Implement proper caching strategies\n- Consider bundle size impact for browser packages\n- Use tree-shaking friendly exports\n"
  },
  {
    "path": ".cursor/rules/commit-and-pr-guidelines.mdc",
    "content": "---\ndescription: \nglobs: \nalwaysApply: false\n---\n# Commit and Pull Request Guidelines\n\nThis document outlines the commit message standards and pull request guidelines for the Amplitude TypeScript SDK.\n\n## Commit Message Standards\n\nFollow the [Conventional Commits](mdc:https:/www.conventionalcommits.org) specification as outlined in [CONTRIBUTING.md](mdc:CONTRIBUTING.md).\n\n### Commit Types\n- **feat**: New features (triggers minor release)\n- **fix**: Bug fixes (triggers patch release)  \n- **docs**: Documentation updates\n- **style**: Code style changes (formatting, missing semi-colons, etc.)\n- **refactor**: Code changes that neither fix bugs nor add features\n- **perf**: Performance improvements\n- **test**: Adding or updating tests\n- **build**: Changes to build system or dependencies\n- **ci**: Changes to CI configuration\n- **chore**: Other changes that don't modify src or test files\n- **revert**: Revert previous commits\n\n### Breaking Changes\n- Any commit with `BREAKING CHANGE` in the body triggers a major release\n- Use `!` after the type/scope for breaking changes: `feat!: remove deprecated API`\n- Clearly document migration path in commit body\n\n### Scope Guidelines\nUse package names as scopes when changes are package-specific:\n- `feat(analytics-browser): add new tracking method`\n- `fix(analytics-node): resolve memory leak issue`\n- `docs(session-replay): update installation guide`\n\n### Examples of Good Commit Messages\n\n```\nfeat(analytics-browser): add support for custom user properties\n\nThis change allows users to set custom properties that persist\nacross all events in a session.\n\nBREAKING CHANGE: The setUserProperties method now requires\nan explicit flush parameter. Use setUserProperties(props, true)\nto maintain previous behavior.\n\nCloses #123\n```\n\n```\nfix(analytics-core): prevent duplicate event submission\n\nAdded deduplication logic to prevent the same event from being\nsent multiple times when network issues cause retries.\n\nFixes #456\n```\n\n```\ndocs: update installation instructions for v2\n\n- Added Node.js version requirements\n- Updated package installation commands\n- Added migration guide from v1\n```\n\n## Pull Request Guidelines\n\n### PR Title Standards\n- Use the same format as commit messages\n- Title should be descriptive and concise\n- Include scope when PR affects specific package\n- Examples:\n  - `feat(analytics-browser): implement session tracking`\n  - `fix: resolve TypeScript compilation errors`\n  - `docs: update API documentation examples`\n\n### PR Description Template\nInclude the following sections in your PR description:\n\n```markdown\n## Summary\nBrief description of what this PR accomplishes.\n\n## Changes\n- List of specific changes made\n- New features added\n- Bugs fixed\n- Dependencies updated\n\n## Testing\n- [ ] Unit tests added/updated\n- [ ] Integration tests pass\n- [ ] Manual testing completed\n- [ ] Browser compatibility verified (if applicable)\n\n## Breaking Changes\nDescribe any breaking changes and migration steps required.\n\n## Related Issues\n- Closes #123\n- Related to #456\n\n## Checklist\n- [ ] Code follows project style guidelines\n- [ ] Self-review of code completed\n- [ ] Documentation updated\n- [ ] Tests added for new functionality\n- [ ] All tests pass\n- [ ] No new ESLint warnings\n```\n\n"
  },
  {
    "path": ".env.example",
    "content": "# Copy and paste this file to .env and fill in the values\nVITE_AMPLITUDE_API_KEY=<MY_AMPLITUDE_API_KEY>\nVITE_AMPLITUDE_USER_ID=<MY_AMPLITUDE_USER_ID>\nVITE_GTM_CONTAINER_ID=<MY_GTM_CONTAINER_ID>\n"
  },
  {
    "path": ".eslintignore",
    "content": "**/*.js\nexamples/\nplaywright.config.ts\n"
  },
  {
    "path": ".eslintrc.js",
    "content": "module.exports = {\n  root: true,\n  env: {\n    es6: true,\n    'jest/globals': true,\n  },\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    ecmaVersion: 2018,\n    project: 'packages/*/tsconfig.json',\n    sourceType: 'module',\n    tsconfigRootDir: __dirname,\n  },\n  plugins: ['@typescript-eslint', 'jest'],\n  extends: [\n    'eslint:recommended',\n    'plugin:@typescript-eslint/eslint-recommended',\n    'plugin:@typescript-eslint/recommended',\n    'plugin:@typescript-eslint/recommended-requiring-type-checking',\n    'plugin:jest/recommended',\n    'prettier',\n    \"plugin:import/recommended\",\n  ],\n  settings: {\n    'import/resolver': {\n      typescript: {\n        alwaysTryTypes: true,\n        project: 'packages/*/tsconfig.json',\n      },\n    },\n  },\n  rules: {\n    '@typescript-eslint/member-delimiter-style': 0,\n    '@typescript-eslint/no-explicit-any': 0,\n    '@typescript-eslint/no-unused-vars': ['error', { vars: 'all', args: 'none', ignoreRestSiblings: true }],\n    '@typescript-eslint/semi': 0,\n    '@typescript-eslint/space-before-function-paren': 0,\n    '@typescript-eslint/require-await': 0,\n    'comma-dangle': 0,\n    'new-cap': 0,\n    'eol-last': [2, 'always'],\n    'no-multiple-empty-lines': [2, { max: 1, maxEOF: 0 }],\n    'no-restricted-globals': [\n      'error',\n      {\n        name: 'globalThis',\n        message: 'Unsafe access to `globalThis`.',\n      },\n      {\n        name: 'window',\n        message: 'Unsafe access to `window`.',\n      },\n      {\n        name: 'self',\n        message: 'Unsafe access to `self`.',\n      },\n    ],\n    'import/no-extraneous-dependencies': [\n      'error',\n      {\n        optionalDependencies: false,\n      },\n    ],\n  },\n  overrides: [\n    {\n      // Allow test files and e2e helpers to access globals\n      files: ['*.test.ts', '*.spec.ts', '**/e2e/**/*.ts'],\n      rules: {\n        'no-restricted-globals': 'off',\n        'import/no-unresolved': 'off',\n        'import/named': 'off',\n        '@typescript-eslint/no-unsafe-assignment': 'off',\n        'import/no-extraneous-dependencies': 'off',\n        'import/no-unsafe-argument': 'off',\n        '@typescript-eslint/no-unsafe-member-access': 'off',\n        '@typescript-eslint/no-unsafe-call': 'off',\n        '@typescript-eslint/no-unsafe-argument': 'off',\n      },\n    },\n  ],\n};\n"
  },
  {
    "path": ".github/CODEOWNERS",
    "content": "# CODEOWNERS file for Amplitude TypeScript repository\n# This file defines code ownership for different parts of the repository.\n# When a pull request is opened that modifies files matching these patterns,\n# the specified teams/individuals will automatically be requested for review.\n#\n# More info: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners\n\n# Session Replay Packages (Browser)\n# Owned by the Session Replay SDK team\n/packages/session-replay-browser/ @amplitude/session-replay-sdk\n/packages/plugin-session-replay-browser/ @amplitude/session-replay-sdk\n/packages/segment-session-replay-plugin/ @amplitude/session-replay-sdk\n/packages/targeting/ @amplitude/session-replay-sdk\n\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/Bug_report.md",
    "content": "---\nname: Bug report 🐛\nabout: You're having technical issues\nlabels: 'bug'\n---\n\n<!--- Please fill out the template to the best of your ability -->\n\n## Expected Behavior\n<!--- What should have happened? -->\n\n## Current Behavior\n<!--- What went wrong? -->\n\n## Possible Solution\n<!--- (Not obligatory) Suggest a fix/reason -->\n\n## Steps to Reproduce\n<!--- Please provide a clear sequence of steps to reproduce this bug -->\n<!--- Include code and images, if relevant -->\n1.\n2.\n3.\n4.\n\n## Environment\n- JS SDK Version: <!--- E.g. 7.1.0 -->\n- Installation Method: <!-- I.e. NPM/yarn/pnpm or <script> import -->\n- Browser and Version: <!-- E.g. Chrome 84-->\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/Feature_request.md",
    "content": "---\nname: Feature Request 🚀\nabout: You'd like something added to the SDK\nlabels: 'enhancement'\n---\n\n<!--- Please fill out the template to the best of your ability -->\n\n## Summary\n\n<!-- Please describe what feature you would like added -->\n\n## Motivations\n\n<!-- Please explain what value this feature would add. E.g. what problem does it solve -->\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/Question.md",
    "content": "---\nname: Question ❓\nabout: Ask a question\nlabels: 'question'\n---\n\n## Summary\n\n<!-- What do you need help with? -->\n"
  },
  {
    "path": ".github/actions/build-and-test/action.yml",
    "content": "name: 'Build and Test'\ndescription: 'Install dependencies, build, test, and lint packages'\ninputs:\n  node-version:\n    description: 'Node.js version to use'\n    required: true\n\nruns:\n  using: \"composite\"\n  steps:\n    - name: Setup pnpm\n      uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4\n\n    - name: Setup Node.js ${{ inputs.node-version }}\n      uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4\n      with:\n        node-version: ${{ inputs.node-version }}\n        registry-url: 'https://registry.npmjs.org'\n        cache: 'pnpm'\n\n    - name: Install project dependencies\n      run: |\n        pnpm install --frozen-lockfile\n      shell: bash\n\n    - name: Build all packages\n      run: |\n        pnpm build\n      shell: bash\n\n    - name: Test all packages\n      run: |\n        pnpm test\n      shell: bash\n\n    - name: Lint all packages\n      run: |\n        pnpm lint\n      shell: bash\n\n    - name: Configure Git User\n      run: |\n        git config --global user.name amplitude-sdk-dev\n        git config --global user.email 249154226+amplitude-sdk-dev@users.noreply.github.com\n      shell: bash\n\n    - name: Configure AWS Credentials\n      uses: aws-actions/configure-aws-credentials@5fd3084fc36e372ff1fff382a39b10d03659f355 # v2\n      if: github.event.inputs.releaseType != 'dry-run'\n      with:\n        role-to-assume: arn:aws:iam::358203115967:role/github-actions-role\n        aws-region: us-west-2\n\n"
  },
  {
    "path": ".github/actions/e2e-test/action.yml",
    "content": "name: 'E2E Test'\ndescription: 'Setup environment, build packages, start dev server, and run Playwright E2E tests'\n\ninputs:\n  amplitude-api-key:\n    description: 'Amplitude API key for E2E tests'\n    required: true\n  amplitude-user-id:\n    description: 'Amplitude user ID for E2E tests'\n    required: false\n    default: 'github-actions-sdk-user'\n  server-port:\n    description: 'Port for the dev server'\n    required: false\n    default: '5173'\n  node-version:\n    description: 'Node.js version to use'\n    required: false\n    default: '20.x'\n\nruns:\n  using: 'composite'\n  steps:\n    - name: Cache dependencies\n      uses: actions/cache@2f8e54208210a422b2efd51efaa6bd6d7ca8920f # v3\n      with:\n        path: '**/node_modules'\n        key: ${{ runner.os }}-modules-${{ hashFiles('**/pnpm-lock.yaml') }}\n\n    - name: Setup Node.js\n      uses: actions/setup-node@3235b876344d2a9aa001b8d1453c930bba69e610 # v3\n      with:\n        node-version: ${{ inputs.node-version }}\n\n    - name: Setup pnpm\n      uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4\n\n    - name: Install project dependencies\n      shell: bash\n      run: pnpm install --frozen-lockfile\n\n    - name: Build all packages\n      shell: bash\n      run: pnpm build\n\n    - name: Create .env file\n      shell: bash\n      run: |\n        echo \"VITE_AMPLITUDE_API_KEY=${{ inputs.amplitude-api-key }}\" > .env\n        echo \"VITE_AMPLITUDE_USER_ID=${{ inputs.amplitude-user-id }}\" >> .env\n\n    - name: Start dev server\n      shell: bash\n      run: |\n        pnpm build:vite\n        pnpm start --port ${{ inputs.server-port }} &\n        sleep 10\n        curl -f http://localhost:${{ inputs.server-port }} || exit 1\n\n    - name: Run Playwright tests\n      shell: bash\n      run: pnpm test:playwright:ci\n\n    - name: Upload Playwright Report\n      if: always()\n      uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4\n      with:\n        name: playwright-report\n        path: playwright-report/\n        retention-days: 30\n\n    - name: Upload Test Results\n      if: always()\n      uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4\n      with:\n        name: test-results\n        path: test-results/\n        retention-days: 30\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "<!---\nThanks for contributing to the Amplitude TypeScript repository! 🎉\n\nPlease fill out the following sections to help us quickly review your pull request.\n--->\n\n### Summary\n\n<!-- What does the PR do? -->\n\n### Checklist\n\n* [ ] Does your PR title have the correct [title format](https://github.com/amplitude/Amplitude-TypeScript/blob/main/CONTRIBUTING.md#pr-commit-title-conventions)?\n* Does your PR have a breaking change?:  <!-- Yes or no -->\n"
  },
  {
    "path": ".github/workflows/ci-nx.yml",
    "content": "name: Continuous Integration (Nx)\n\non:\n  pull_request:\n    types: [opened, synchronize]\n\njobs:\n  check-deprecated-packages:\n    name: Check Deprecated Packages\n    runs-on: ubuntu-latest\n    \n    steps:\n      - name: Check out git repository\n        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3\n        with:\n          fetch-depth: 0  # Required to compare with base branch\n      \n      - name: Check for new usage of deprecated packages\n        env:\n          GITHUB_BASE_REF: ${{ github.base_ref }}\n        run: |\n          bash scripts/check-deprecated-packages.sh\n\n  build-docs:\n    name: Build Docs\n    runs-on: ubuntu-latest\n    \n    steps:\n      - name: Check out git repository\n        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3\n      \n      - name: Setup pnpm\n        uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4\n\n      - name: Setup Node.js 20\n        uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4\n        with:\n          node-version: 20\n          cache: 'pnpm'\n\n      - name: Install project dependencies\n        run: pnpm install --frozen-lockfile\n\n      - name: Build all packages\n        run: pnpm build\n\n      - name: Build docs\n        run: pnpm docs:check\n\n  build:\n    name: Build\n    strategy:\n      fail-fast: false\n      matrix:\n        node-version: [20.x, 22.x, 24.x]\n        os: [ubuntu-latest]\n    runs-on: ${{ matrix.os }}\n    \n    env:\n      NX_BASE: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || 'origin/main~1' }}\n      NX_HEAD: ${{ github.sha }}\n\n    steps:\n      - name: Check out git repository\n        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3\n        with:\n          fetch-depth: 0  # Required for NX affected commands\n\n      - name: Setup pnpm\n        uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4\n\n      - name: Setup Node.js ${{ matrix.node-version }}\n        uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4\n        with:\n          node-version: ${{ matrix.node-version }}\n          cache: 'pnpm'\n\n      - name: Install project dependencies\n        run: pnpm install --frozen-lockfile\n\n      - name: Set up NX base for affected commands\n        run: |\n          # Ensure we have the main branch reference for NX affected commands\n          git fetch origin main:main --depth=1 || git fetch origin main --depth=1\n\n      - name: Build affected packages\n        run: |\n          pnpm build:nx-affected\n\n      # https://github.com/amplitude/Amplitude-TypeScript/issues/281\n      - name: Check module dependencies\n        run: |\n          if grep -rnw 'packages/analytics-core/lib' -e '/// <reference types=\"node\" />'; then\n            exit 1\n          elif grep -rnw 'packages/analytics-browser/lib' -e '/// <reference types=\"node\" />'; then\n            exit 1\n          elif grep -rnw 'packages/analytics-marketing-analytics-browser/lib' -e '/// <reference types=\"node\" />'; then\n            exit 1\n          elif grep -rnw 'packages/analytics-react-native/lib' -e '/// <reference types=\"node\" />'; then\n            exit 1\n          fi\n\n      - name: Test affected packages\n        run: pnpm test:nx-affected\n\n      - name: Lint affected packages\n        run: pnpm lint:nx-affected\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: Continuous Integration\n\non:\n  push:\n    branches:\n      - main\n      - v1.x\n\njobs:\n  build:\n    name: Build\n    strategy:\n      fail-fast: false\n      matrix:\n        node-version: [20.x, 22.x, 24.x]\n        os: [ubuntu-latest]\n    runs-on: ${{ matrix.os }}\n\n    steps:\n      - name: Check out git repository\n        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3\n\n      - name: Setup pnpm\n        uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4\n\n      - name: Setup Node.js ${{ matrix.node-version }}\n        uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4\n        with:\n          node-version: ${{ matrix.node-version }}\n          cache: 'pnpm'\n\n      - name: Install project dependencies\n        run: |\n          pnpm install --frozen-lockfile\n\n      - name: Build all packages\n        run: |\n          pnpm build\n\n      # https://github.com/amplitude/Amplitude-TypeScript/issues/281\n      - name: Check module dependencies\n        run: |\n          if grep -rnw 'packages/analytics-core/lib' -e '/// <reference types=\"node\" />'; then\n            exit 1\n          elif grep -rnw 'packages/analytics-browser/lib' -e '/// <reference types=\"node\" />'; then\n            exit 1\n          elif grep -rnw 'packages/analytics-marketing-analytics-browser/lib' -e '/// <reference types=\"node\" />'; then\n            exit 1\n          elif grep -rnw 'packages/analytics-react-native/lib' -e '/// <reference types=\"node\" />'; then\n            exit 1\n          fi\n\n      - name: Build docs\n        run: |\n          pnpm docs:check\n\n      - name: Test all packages\n        run: |\n          pnpm test\n\n      - name: Lint all packages\n        run: |\n          pnpm lint\n"
  },
  {
    "path": ".github/workflows/docs.yml",
    "content": "name: Generate Docs\non: workflow_dispatch\njobs:\n  build-and-deploy:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3\n\n      - name: Setup pnpm\n        uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4\n      \n      - name: Setup\n        run: |\n          pnpm install --frozen-lockfile\n          pnpm build\n          pnpm docs\n\n      - name: Deploy\n        uses: JamesIves/github-pages-deploy-action@0f24da7de3e7e135102609a4c9633b025be8411b # 4.1.5\n        with:\n          branch: docs\n          folder: docs\n"
  },
  {
    "path": ".github/workflows/e2e-session-replay.yml",
    "content": "name: Session Replay Browser E2E\n\non:\n  pull_request:\n    types: [opened, synchronize]\n    paths:\n      - 'packages/session-replay-browser/**'\n      - 'test-server/session-replay-browser/**'\n  push:\n    branches:\n      - main\n    paths:\n      - 'packages/session-replay-browser/**'\n      - 'test-server/session-replay-browser/**'\n\n# Non-blocking: failures are visible in the checks list but do not prevent merging.\n# Once the suite is stable this job can be added to required status checks.\n\njobs:\n  e2e-session-replay:\n    name: Session Replay Browser E2E\n    if: github.actor != 'dependabot[bot]'\n    runs-on: ubuntu-latest\n    continue-on-error: true\n    permissions:\n      pull-requests: write\n    container:\n      image: mcr.microsoft.com/playwright:v1.55.0\n\n    steps:\n      - name: Check out repository\n        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3\n\n      - name: Setup pnpm\n        uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4\n\n      - name: Setup Node.js\n        uses: actions/setup-node@3235b876344d2a9aa001b8d1453c930bba69e610 # v3\n        with:\n          node-version: '20.x'\n\n      - name: Install dependencies\n        run: pnpm install --frozen-lockfile\n\n      - name: Build session-replay-browser and workspace dependencies\n        run: pnpm --filter @amplitude/session-replay-browser... build\n\n      - name: Run e2e tests (Chromium only)\n        working-directory: packages/session-replay-browser\n        run: npx playwright test --project=chromium\n\n      - name: Post test summary as PR comment\n        if: always() && github.event_name == 'pull_request'\n        uses: daun/playwright-report-summary@1229105480a2a4bdd91598d8a146fbab41343fce # v3\n        with:\n          report-file: packages/session-replay-browser/e2e/results.json\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          comment-title: 'Session Replay Browser E2E Results'\n\n      - name: Upload Playwright report\n        if: always()\n        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4\n        with:\n          name: sr-e2e-playwright-report\n          path: packages/session-replay-browser/playwright-report/\n          retention-days: 14\n\n      - name: Upload test results\n        if: always()\n        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4\n        with:\n          name: sr-e2e-test-results\n          path: packages/session-replay-browser/test-results/\n          retention-days: 14\n"
  },
  {
    "path": ".github/workflows/e2e.yml",
    "content": "name: E2E Tests\n\non:\n  push:\n    branches:\n      - main\n      - v1.x\n  pull_request:\n    types: [opened, synchronize]\n\njobs:\n  e2e:\n    name: E2E Tests\n    if: github.actor != 'dependabot[bot]'\n    runs-on: ubuntu-latest\n    container:\n      image: mcr.microsoft.com/playwright:v1.55.0\n\n    steps:\n      - name: Check out git repository\n        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3\n        with:\n          fetch-depth: 0\n\n      - name: Run E2E tests\n        uses: ./.github/actions/e2e-test\n        with:\n          amplitude-api-key: ${{ secrets.AMPLITUDE_API_KEY }}\n"
  },
  {
    "path": ".github/workflows/publish-single-package.yml",
    "content": "# This workflow is for publishing NEW packages that are currently private\n# It's separate from the main publish-v2.yml workflow which handles stable releases\n# Use this workflow for new packages that will only have beta/alpha versions\n# The 'latest' tag will always point to the most recent version (even if beta/alpha)\n# since these packages don't have stable releases yet\n#\n# IMPORTANT: Once a stable (non-beta/alpha) version is published to latest,\n# this workflow will prevent further beta/alpha publishing to maintain stability\nname: Publish New Package (Beta/Alpha with Latest Tag)\n\non:\n  workflow_dispatch:\n    inputs:\n      packageName:\n        type: string\n        description: \"Package name (e.g., unified, analytics-browser) - must be a valid package in packages/ directory\"\n        required: true\n      releaseTag:\n        type: choice\n        description: \"Release type - choose beta for testing releases or alpha for experimental releases (package will be published with latest tag, but only if no stable version exists)\"\n        required: true\n        options:\n          - beta\n          - alpha\n      dryRun:\n        type: boolean\n        description: \"Dry run (skip changelog update and npm publish) - recommended to test first\"\n        required: true\n        default: true\n\njobs:\n  # Authorization step - ensures only users with write permissions can trigger this workflow\n  authorize:\n    name: Authorize\n    runs-on: ubuntu-latest\n    steps:\n      - name: ${{ github.actor }} permission check to do a release\n        uses: \"lannonbr/repo-permission-check-action@2bb8c89ba8bf115c4bfab344d6a6f442b24c9a1f\" # 2.0.2\n        with:\n          permission: \"write\"\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\n  # Main publishing job - handles the actual package publishing process\n  # This workflow is specifically for NEW packages that are currently private\n  # It publishes beta/alpha versions but always uses 'latest' tag for the most recent version\n  # since these packages don't have stable releases yet\n  publish-package:\n    name: Publish New Package (Beta/Alpha with Latest Tag)\n    runs-on: ubuntu-latest\n    needs: [authorize]\n    permissions:\n      id-token: write\n      contents: write\n    env:\n      PACKAGE_NAME: ${{ github.event.inputs.packageName }}\n      RELEASE_TAG: ${{ github.event.inputs.releaseTag }}\n      DRY_RUN: ${{ github.event.inputs.dryRun }}\n      PACKAGE_PATH: packages/${{ github.event.inputs.packageName }}\n    strategy:\n      matrix:\n        node-version: [24.x]\n\n    steps:\n      # Checkout the repository with full history for version management\n      - name: Check out git repository\n        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3\n        with:\n          fetch-depth: 0\n\n      # Verify the specified package exists and has the required structure\n      - name: Verify package exists\n        run: |\n          if [ ! -d \"$PACKAGE_PATH\" ]; then\n            echo \"❌ Package directory $PACKAGE_PATH does not exist\"\n            exit 1\n          fi\n          if [ ! -f \"$PACKAGE_PATH/package.json\" ]; then\n            echo \"❌ package.json not found in $PACKAGE_PATH\"\n            exit 1\n          fi\n          echo \"✅ Package $PACKAGE_NAME found at $PACKAGE_PATH\"\n\n      # Check if latest published version is stable to prevent beta/alpha publishing\n      - name: Validate version publishing rules\n        run: |\n          echo \"🔍 Checking if package can publish beta/alpha versions...\"\n\n          # Get the package name from package.json\n          PACKAGE_JSON_NAME=$(node -p \"require('./$PACKAGE_PATH/package.json').name\")\n          echo \"Package name: $PACKAGE_JSON_NAME\"\n\n          # Check if package exists on npm and get latest version\n          if npm view \"$PACKAGE_JSON_NAME\" version 2>/dev/null; then\n            LATEST_VERSION=$(npm view \"$PACKAGE_JSON_NAME\" version 2>/dev/null)\n            echo \"Latest published version: $LATEST_VERSION\"\n\n            # Check if latest version is stable (doesn't contain beta or alpha)\n            if [[ \"$LATEST_VERSION\" == *\"beta\"* ]] || [[ \"$LATEST_VERSION\" == *\"alpha\"* ]]; then\n              echo \"✅ Latest version ($LATEST_VERSION) is pre-release, can publish beta/alpha\"\n            else\n              echo \"❌ ERROR: Latest version ($LATEST_VERSION) is stable (non-beta/alpha)\"\n              echo \"Once a stable version is published to latest, you cannot publish beta/alpha versions anymore.\"\n              echo \"This prevents version regression and maintains package stability.\"\n              echo \"\"\n              echo \"If you need to publish a new stable version, use the main publish workflow instead.\"\n              echo \"If this is a new package, ensure the first version is beta/alpha.\"\n              exit 1\n            fi\n          else\n            echo \"✅ Package not found on npm, this appears to be a new package\"\n            echo \"New packages can publish beta/alpha versions with latest tag\"\n          fi\n\n      - name: Setup PNPM\n        uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4\n\n      # Setup Node.js environment\n      - name: Setup Node.js ${{ matrix.node-version }}\n        uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4\n        with:\n          node-version: ${{ matrix.node-version }}\n          cache: \"pnpm\"\n\n      # Install all project dependencies\n      - name: Install project dependencies\n        run: |\n          pnpm install --frozen-lockfile\n\n      # Configure Git for automated commits\n      - name: Configure Git User\n        run: |\n          git config --global user.name amplitude-sdk-bot\n          git config --global user.email amplitude-sdk-bot@users.noreply.github.com\n\n      # Calculate new version and update package files\n      # This increments the patch version for beta/alpha releases\n      # For new packages, this will be the first version (e.g., 1.0.0-beta.1)\n      # The 'latest' tag will always point to the most recent version\n      - name: Calculate and update version\n        run: |\n          cd $PACKAGE_PATH\n          # Get current version - use node to extract just the version value\n          CURRENT_VERSION=$(node -p \"require('./package.json').version\")\n          echo \"Current version: $CURRENT_VERSION\"\n\n          # Simply increment the last digit of the version\n          # Extract the last digit and increment it\n          LAST_DIGIT=$(echo \"$CURRENT_VERSION\" | grep -o '[0-9][0-9]*$')\n          NEW_LAST_DIGIT=$((LAST_DIGIT + 1))\n\n          # Replace the last digit with the incremented value\n          NEW_VERSION=$(echo \"$CURRENT_VERSION\" | sed \"s/[0-9][0-9]*$/$NEW_LAST_DIGIT/\")\n\n          echo \"NEW_VERSION=$NEW_VERSION\" >> $GITHUB_ENV\n          echo \"✅ New version would be: $CURRENT_VERSION → $NEW_VERSION\"\n\n          # Update version in package.json immediately (needed for build)\n          npm pkg set version=\"$NEW_VERSION\"\n\n          # Update version in src/version.ts - this file must exist\n          if [ -f \"src/version.ts\" ]; then\n            echo \"Updating src/version.ts with new version\"\n            echo \"// Autogenerated by \\`pnpm version-file\\`. DO NOT EDIT\" > src/version.ts\n            echo \"export const VERSION = '$NEW_VERSION';\" >> src/version.ts\n            echo \"✅ Updated src/version.ts to version $NEW_VERSION\"\n          else\n            echo \"❌ ERROR: src/version.ts not found in $PACKAGE_NAME package\"\n            echo \"This file is required for version management. Please ensure the package has the correct structure.\"\n            exit 1\n          fi\n\n      # Dry run mode - shows what would be published without actually doing it\n      # This is the default mode to prevent accidental publishes\n      - name: Dry run summary and exit\n        if: ${{ env.DRY_RUN == 'true' }}\n        run: |\n          cd $PACKAGE_PATH\n          echo \"🔍 DRY RUN SUMMARY:\"\n          echo \"Package: $PACKAGE_NAME\"\n          echo \"Current version: $CURRENT_VERSION\"\n          echo \"New version would be: $NEW_VERSION\"\n          echo \"Release tag: latest (always latest for new packages)\"\n          echo \"Would publish: $PACKAGE_NAME@$NEW_VERSION with tag latest\"\n          echo \"✅ Dry run completed successfully - exiting without making changes\"\n          exit 0\n\n      # Build the package to ensure it compiles correctly\n      - name: Build package\n        run: |\n          pnpm build\n\n      # Run tests to ensure package quality\n      - name: Test package\n        run: |\n          pnpm test\n\n      # Lint the code to ensure code quality standards\n      - name: Lint package\n        run: |\n          pnpm lint\n\n      # Configure NPM authentication for publishing\n      - name: Configure NPM User\n        if: ${{ env.DRY_RUN == 'false' }}\n        run: |\n          echo \"//registry.npmjs.org/:_authToken=${{ secrets.NPM_PUBLISH_TOKEN }}\" > ~/.npmrc\n          npm whoami\n\n      # Temporarily make package public for publishing (will be restored to private later)\n      - name: Make package public for publishing\n        if: ${{ env.DRY_RUN == 'false' }}\n        run: |\n          cd $PACKAGE_PATH\n          echo \"Making package public for publishing\"\n\n          # Set private to false (version already updated)\n          npm pkg set private=false --json\n\n          echo \"✅ Made package public for publishing\"\n          echo \"Current package.json settings:\"\n          cat package.json | grep -E '\"(version|private)\"'\n\n      - name: Update changelog and publish\n        if: ${{ env.DRY_RUN == 'false' }}\n        run: |\n          cd $PACKAGE_PATH\n\n          # Generate changelog entry\n          echo \"Updating changelog for version $NEW_VERSION\"\n\n          # Check if CHANGELOG.md exists\n          if [ ! -f \"CHANGELOG.md\" ]; then\n            echo \"# Changelog\" > CHANGELOG.md\n            echo \"\" >> CHANGELOG.md\n          fi\n\n          # Add new version entry to changelog\n          TEMP_FILE=$(mktemp)\n          echo \"# Changelog\" > $TEMP_FILE\n          echo \"\" >> $TEMP_FILE\n          echo \"## $NEW_VERSION ($(date +%Y-%m-%d))\" >> $TEMP_FILE\n          echo \"\" >> $TEMP_FILE\n          echo \"- Release $NEW_VERSION\" >> $TEMP_FILE\n          echo \"\" >> $TEMP_FILE\n\n          # Append existing changelog content (skip the first \"# Changelog\" line)\n          if [ -f \"CHANGELOG.md\" ]; then\n            tail -n +2 CHANGELOG.md >> $TEMP_FILE\n          fi\n\n          mv $TEMP_FILE CHANGELOG.md\n          echo \"✅ Updated CHANGELOG.md\"\n\n          # Publish to npm with latest tag (always latest for new packages)\n          echo \"Publishing $PACKAGE_NAME@$NEW_VERSION with tag latest\"\n          pnpm publish --tag latest --access=public\n          echo \"✅ Published $PACKAGE_NAME@$NEW_VERSION to npm with tag latest\"\n\n      # Restore package to private and commit all changes\n      # This ensures the package remains private in the repository after publishing\n      - name: Restore package to private and commit changes\n        if: ${{ env.DRY_RUN == 'false' && always() }}\n        run: |\n          cd $PACKAGE_PATH\n          npm pkg set private=true --json\n          echo \"✅ Set package back to private\"\n\n          # Update version in the restored package.json (but keep private: true)\n          npm pkg set version=\"$NEW_VERSION\"\n\n          # Now commit the changes with the correct private setting\n          echo \"Committing version and changelog changes\"\n          git status\n          git add package.json CHANGELOG.md src/version.ts\n          git commit -m \"chore(release): publish @amplitude/$PACKAGE_NAME@$NEW_VERSION\"\n          git tag \"@amplitude/$PACKAGE_NAME@$NEW_VERSION\"\n          echo \"✅ Committed changes and created tag\"\n\n      # Push all changes and tags back to the repository\n      - name: Push changes\n        if: ${{ env.DRY_RUN == 'false' }}\n        run: |\n          # Get current branch name and push to it\n          CURRENT_BRANCH=$(git branch --show-current)\n          echo \"Pushing to current branch: $CURRENT_BRANCH\"\n          git push origin \"$CURRENT_BRANCH\"\n          git push origin \"@amplitude/$PACKAGE_NAME@$NEW_VERSION\"\n          echo \"✅ Pushed changes and tags to repository\"\n"
  },
  {
    "path": ".github/workflows/publish-v1.yml",
    "content": "name: Publish v1.x\n\non:\n  workflow_dispatch:\n    inputs:\n      releaseType:\n        type: choice\n        description: Release Type\n        options:\n          - release\n          - prerelease\n          - graduate\n\njobs:\n  authorize:\n    name: Authorize\n    runs-on: ubuntu-latest\n    steps:\n      - name: ${{ github.actor }} permission check to do a release\n        uses: 'lannonbr/repo-permission-check-action@2bb8c89ba8bf115c4bfab344d6a6f442b24c9a1f' # 2.0.2\n        with:\n          permission: 'write'\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\n  deploy:\n    name: Deploy\n    runs-on: ubuntu-latest\n    needs: [authorize]\n    permissions:\n      id-token: write\n      contents: write\n    env:\n      RELEASE_TYPE: ${{ github.event.inputs.releaseType }}\n    strategy:\n      matrix:\n        node-version: [18.15.x]\n\n    steps:\n      - name: Check out git repository\n        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3\n        with:\n          fetch-depth: 0\n          ref: v1.x\n\n      - name: Cache dependencies\n        uses: actions/cache@6f8efc29b200d32929f49075959781ed54ec270c # v3\n        with:\n          path: '**/node_modules'\n          key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}\n\n      - name: Setup Node.js ${{ matrix.node-version }}\n        uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4\n        with:\n          node-version: ${{ matrix.node-version }}\n\n      - name: Install project dependencies\n        run: |\n          yarn install --frozen-lockfile\n\n      - name: Build all packages\n        run: |\n          yarn build\n\n      - name: Test all packages\n        run: |\n          yarn test\n\n      - name: Lint all packages\n        run: |\n          yarn lint\n\n      - name: Configure Git User\n        run: |\n          git config --global user.name amplitude-sdk-bot\n          git config --global user.email amplitude-sdk-bot@users.noreply.github.com\n\n      - name: Configure NPM User\n        run: |\n          echo \"//registry.npmjs.org/:_authToken=${{ secrets.NPM_PUBLISH_TOKEN }}\" > ~/.npmrc\n          npm whoami\n\n      - name: Configure AWS Credentials\n        uses: aws-actions/configure-aws-credentials@5fd3084fc36e372ff1fff382a39b10d03659f355 # v2\n        with:\n          role-to-assume: arn:aws:iam::358203115967:role/github-actions-role\n          aws-region: us-west-2\n\n      # https://www.npmjs.com/package/@lerna/version#--conventional-prerelease\n      # patch: 1.0.0 -> 1.0.1-alpha.0\n      # minor: 1.0.0 -> 1.1.0-alpha.0\n      # major: 1.0.0 -> 2.0.0-alpha.0\n      - name: Create pre-release version\n        if: ${{ env.RELEASE_TYPE == 'prerelease'}}\n        run: |\n          GH_TOKEN=${{ secrets.GH_PUBLISH_TOKEN }} npm run deploy:version -- -y --conventional-prerelease --create-release github\n\n      # https://www.npmjs.com/package/@lerna/version#--conventional-graduate\n      # 1.0.0-alpha.0 -> 1.0.1\n      - name: Create graduate version\n        if: ${{ env.RELEASE_TYPE == 'graduate'}}\n        run: |\n          GH_TOKEN=${{ secrets.GH_PUBLISH_TOKEN }} npm run deploy:version -- -y --conventional-graduate --create-release github\n\n      # Use 'release' for the usual deployment\n      # NOTE: You probably want this\n      - name: Create release version\n        if: ${{ env.RELEASE_TYPE == 'release'}}\n        run: |\n          GH_TOKEN=${{ secrets.GH_PUBLISH_TOKEN }} npm run deploy:version -- -y --create-release github\n\n      # Use 'from git' option if `lerna version` has already been run\n      - name: Publish Release to NPM\n        run: |\n          GH_TOKEN=${{ secrets.GH_PUBLISH_TOKEN }} npm run deploy:publish -- from-git -y --pre-dist-tag v1-beta\n        env:\n          S3_BUCKET_NAME: ${{ secrets.S3_BUCKET_NAME }}\n"
  },
  {
    "path": ".github/workflows/publish-v2.yml",
    "content": "name: Publish v2.x\n\non:\n  workflow_dispatch:\n    inputs:\n      releaseType:\n        type: choice\n        description: Release type (release for main branch, prerelease for feature branches)\n        required: true\n        default: prerelease\n        options:\n          - release\n          - prerelease\n          - dry-run\n      branch:\n        type: string\n        description: Branch to create pre-release from (only applies to prerelease/dry-run).\n        required: false\n      skipLernaVersion:\n        type: boolean\n        description: Skip `lerna version` and E2E for release/prerelease recovery runs, then only run the publish step. Use this to recover from a partial npm publish where some packages were already released.\n        required: false\n        default: false\n\njobs:\n  authorize:\n    name: Authorize\n    runs-on: ubuntu-latest\n    steps:\n      - name: Check branch protection\n        env:\n          RELEASE_TYPE: ${{ github.event.inputs.releaseType }}\n          REF_NAME: ${{ github.ref_name }}\n        run: |\n          if [ \"$RELEASE_TYPE\" = \"dry-run\" ]; then\n            echo \"✅ Branch check skipped: dry-run mode allows any branch\"\n            echo \"Current branch: $REF_NAME\"\n            exit 0\n          fi\n          case \"$REF_NAME\" in\n            main|hotfix/*)\n              echo \"✅ Branch check passed: workflow is running from allowed branch ($REF_NAME)\"\n              ;;\n            *)\n              echo \"❌ This workflow can only be triggered from main or hotfix/* branches.\"\n              echo \"Current branch: $REF_NAME\"\n              exit 1\n              ;;\n          esac\n\n      - name: ${{ github.actor }} permission check to do a release\n        uses: 'lannonbr/repo-permission-check-action@2bb8c89ba8bf115c4bfab344d6a6f442b24c9a1f'\n        with:\n          permission: 'write'\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\n  e2e:\n    name: E2E Tests\n    runs-on: ubuntu-latest\n    needs: [authorize]\n    container:\n      image: mcr.microsoft.com/playwright:v1.55.0\n    outputs:\n      head_sha: ${{ steps.head-sha.outputs.sha }}\n\n    steps:\n      - name: Skip E2E for recovery publish\n        if: ${{ github.event.inputs.skipLernaVersion == 'true' }}\n        run: echo \"Skipping E2E because skipLernaVersion is true\"\n\n      - name: Check out git repository\n        if: ${{ github.event.inputs.skipLernaVersion != 'true' }}\n        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3\n        with:\n          fetch-depth: 0\n          ref: ${{ github.event.inputs.branch || github.ref_name }}\n\n      - name: Capture E2E HEAD SHA\n        id: head-sha\n        if: ${{ github.event.inputs.skipLernaVersion != 'true' }}\n        run: |\n          git config --global --add safe.directory \"$GITHUB_WORKSPACE\"\n          echo \"sha=$(git rev-parse HEAD)\" >> \"$GITHUB_OUTPUT\"\n\n      - name: Run E2E tests\n        if: ${{ github.event.inputs.skipLernaVersion != 'true' }}\n        uses: ./.github/actions/e2e-test\n        with:\n          amplitude-api-key: ${{ secrets.AMPLITUDE_API_KEY }}\n\n  deploy:\n    name: Deploy\n    runs-on: ubuntu-latest\n    needs: [authorize, e2e]\n    if: ${{ github.event.inputs.releaseType == 'release' }}\n    permissions:\n      id-token: write # Required for OIDC\n      contents: write\n    strategy:\n      matrix:\n        node-version: [24.x] # Ensure npm 11.5.1 or later is installed for OIDC, node 24.6 is minimal \n\n    steps:\n      - name: Validate protected branch\n        run: |\n          REF=\"${{ github.event.inputs.branch || github.ref_name }}\"\n          case \"$REF\" in\n            main)\n              echo \"✅ Branch check passed: main\"\n              ;;\n            hotfix/*)\n              echo \"✅ Branch check passed: hotfix branch ($REF)\"\n              ;;\n            *)\n              echo \"❌ Deploy can only run from main or hotfix/* branches.\"\n              echo \"Current branch: $REF\"\n              exit 1\n              ;;\n          esac\n\n      - name: Check out git repository\n        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3\n        with:\n          fetch-depth: 0\n          token: ${{ secrets.GH_PUBLISH_TOKEN }}\n          ref: ${{ github.event.inputs.branch || github.ref_name }}\n\n      - name: Build and Test\n        uses: ./.github/actions/build-and-test\n        with:\n          node-version: ${{ matrix.node-version }}\n\n      - name: Verify ref has not advanced since e2e checkout\n        if: ${{ github.event.inputs.skipLernaVersion != 'true' }}\n        env:\n          EXPECTED_SHA: ${{ needs.e2e.outputs.head_sha }}\n          REF: ${{ github.event.inputs.branch || github.ref_name }}\n        run: bash scripts/publish/check-ref-not-advanced.sh\n\n      # Only create release version when using from-git (default behavior)\n      # from-package mode uses existing package.json versions and doesn't need git tags\n      - name: Create release version\n        if: ${{ github.event.inputs.skipLernaVersion != 'true' }}\n        run: |\n          echo \"Running lerna version...\"\n          \n          # Temporarily disable exit on error to capture output even when command fails\n          set +e\n          OUTPUT=$(GH_TOKEN=${{ secrets.GH_PUBLISH_TOKEN }} pnpm deploy:version -y --no-private --create-release github 2>&1)\n          EXIT_CODE=$?\n          set -e\n          \n          # Always display the output first\n          echo \"=== Lerna Version Output ===\"\n          echo \"$OUTPUT\"\n          echo \"=== End Output ===\"\n          \n          # Now handle the exit code\n          if [ $EXIT_CODE -ne 0 ]; then\n            echo \"❌ Command failed with exit code: $EXIT_CODE\"\n            exit $EXIT_CODE\n          fi\n          \n          # Check if the output indicates no changed packages\n          if echo \"$OUTPUT\" | grep -q \"No changed packages to version\"; then\n            echo \"❌ No changed packages found to version. Failing the job.\"\n            exit 1\n          fi\n          \n          echo \"✅ Successfully created release version\"\n\n      # Publish to NPM (also uploads minified JS and source maps to S3)\n      - name: Publish Release to NPM\n        run: |\n          GH_TOKEN=${{ secrets.GH_PUBLISH_TOKEN }} pnpm deploy:publish\n        env:\n          S3_BUCKET_NAME: ${{ secrets.S3_BUCKET_NAME }}\n\n  prerelease:\n    name: Prerelease feature branch\n    runs-on: ubuntu-latest\n    needs: [authorize, e2e]\n    if: ${{ github.event.inputs.releaseType == 'prerelease' || github.event.inputs.releaseType == 'dry-run' }}\n    permissions:\n      id-token: write # Required for OIDC\n      contents: write\n    strategy:\n      matrix:\n        node-version: [24.x] # Ensure npm 11.5.1 or later is installed for OIDC, node 24.6 is minimal\n\n    steps:\n      - name: Determine branch to use\n        id: determine-branch\n        run: |\n          if [ -n \"${{ github.event.inputs.branch }}\" ]; then\n            echo \"branch=${{ github.event.inputs.branch }}\" >> $GITHUB_OUTPUT\n          else\n            echo \"❌ No branch specified. Please specify a branch to create pre-release from.\"\n            exit 1\n          fi\n\n      - name: Check out git repository\n        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3\n        with:\n          ref: ${{ steps.determine-branch.outputs.branch }}\n          fetch-depth: 0\n          token: ${{ secrets.GH_PUBLISH_TOKEN }}\n\n      - name: Build and Test\n        uses: ./.github/actions/build-and-test\n        with:\n          node-version: ${{ matrix.node-version }}\n\n      # Keep alphanumeric characters and hyphens, remove other invalid characters\n      # Examples:\n      #   - SR-1858 -> SR-1858\n      #   - feature/my-branch -> featuremy-branch\n      #   - fix_bug_123 -> fixbug123\n      #   - user@company.com -> usercompanycom\n      - name: Transform feature branch name\n        run: |\n          echo \"PREID=$(echo '${{ steps.determine-branch.outputs.branch }}' | tr -cd '[:alnum:]-')\" >> $GITHUB_ENV\n\n      # Use --no-push to prevent pushing to remote\n      # Version example: 1.0.0 -> 1.1.0-{preid}.0\n      - name: Dry run pre-release version\n        if: ${{ github.event.inputs.releaseType == 'dry-run' }}\n        run: |\n          GH_TOKEN=${{ secrets.GH_PUBLISH_TOKEN }} pnpm deploy:version:dry-run -y --preid ${{ env.PREID }}\n\n      - name: Pre-release version\n        if: ${{ github.event.inputs.releaseType == 'prerelease' && github.event.inputs.skipLernaVersion != 'true' }}\n        run: |\n            GH_TOKEN=${{ secrets.GH_PUBLISH_TOKEN }} pnpm deploy:version -y --no-private --conventional-prerelease --preid ${{ env.PREID }} --allow-branch ${{ steps.determine-branch.outputs.branch }} --create-release github\n\n      # Publish to NPM (also uploads minified JS and source maps to S3)\n      - name: Publish Pre-release to NPM\n        if: ${{ github.event.inputs.releaseType == 'prerelease' }}\n        run: |\n          GH_TOKEN=${{ secrets.GH_PUBLISH_TOKEN }} pnpm deploy:publish --no-git-checks --ignore-scripts --tag ${{ env.PREID }}\n        env:\n          S3_BUCKET_NAME: ${{ secrets.S3_BUCKET_NAME }}\n\n      - name: Dry run publish release to NPM\n        if: ${{ github.event.inputs.releaseType == 'dry-run' }}\n        env:\n          DRY_RUN: true\n        run: |\n          pnpm deploy:publish:dry-run\n"
  },
  {
    "path": ".github/workflows/rn-smoke.yml",
    "content": "name: React Native Smoke Test\n\non:\n  pull_request:\n    types: [opened, synchronize]\n  push:\n    branches: [main]\n\njobs:\n  ios-smoke:\n    name: iOS Simulator Smoke (Maestro)\n    runs-on: macos-14\n    timeout-minutes: 45\n\n    env:\n      APP_DIR: examples/react-native/app\n      BUNDLE_ID: org.reactjs.native.example.app\n      SIM_NAME: iPhone 15\n      # CocoaPods 1.14.3 hits `ArgumentError - pathname contains null byte` in\n      # Pathname#realdirpath on pnpm monorepos when the locale is not UTF-8\n      # (see https://github.com/CocoaPods/CocoaPods/issues/12866). macos-14\n      # runners default to an unset/C locale; pin it here.\n      LANG: en_US.UTF-8\n      LC_ALL: en_US.UTF-8\n\n    steps:\n      - name: Check out git repository\n        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3\n\n      - name: Setup pnpm\n        uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4\n\n      - name: Setup Node.js 20\n        uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4\n        with:\n          node-version: 20\n          cache: 'pnpm'\n\n      - name: Setup Ruby for CocoaPods\n        uses: ruby/setup-ruby@6aaa311d81eba98ae12eaffbcb63296ace0efcde # v1.307.0\n        with:\n          ruby-version: '3.2'\n          bundler-cache: true\n          working-directory: ${{ env.APP_DIR }}\n\n      - name: Install project dependencies\n        run: pnpm install --frozen-lockfile\n\n      - name: Build SDK and its workspace deps\n        run: pnpm --filter @amplitude/analytics-react-native... build\n\n      - name: Cache CocoaPods\n        uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4\n        with:\n          path: |\n            ${{ env.APP_DIR }}/ios/Pods\n            ~/Library/Caches/CocoaPods\n          key: pods-${{ runner.os }}-${{ hashFiles(format('{0}/ios/Podfile.lock', env.APP_DIR)) }}\n          restore-keys: |\n            pods-${{ runner.os }}-\n\n      - name: Pod install\n        working-directory: ${{ env.APP_DIR }}/ios\n        # Even with LANG/LC_ALL pinned, cocoapods 1.14.3 + pnpm intermittently\n        # raises `ArgumentError - pathname contains null byte` in\n        # Pathname#realdirpath (cocoapods/cocoapods#12866). Retry on failure\n        # before giving up — failures so far have always passed on the next try.\n        run: |\n          for attempt in 1 2 3; do\n            if bundle exec pod install; then\n              exit 0\n            fi\n            echo \"::warning::pod install attempt $attempt failed, retrying...\"\n            sleep 5\n          done\n          echo \"::error::pod install failed 3 times\"\n          exit 1\n\n      - name: Build iOS app (Release, simulator)\n        working-directory: ${{ env.APP_DIR }}\n        # Raw xcodebuild output is noisy; xcpretty would be nicer but isn't\n        # installed by default on macos-14 runners, and adding it as a Gemfile\n        # dependency for cosmetics isn't worth the install time.\n        run: |\n          xcodebuild \\\n            -workspace ios/app.xcworkspace \\\n            -scheme app \\\n            -configuration Release \\\n            -sdk iphonesimulator \\\n            -destination \"generic/platform=iOS Simulator\" \\\n            -derivedDataPath build \\\n            CODE_SIGN_IDENTITY=\"\" \\\n            CODE_SIGNING_REQUIRED=NO \\\n            CODE_SIGNING_ALLOWED=NO\n          test -d build/Build/Products/Release-iphonesimulator/app.app\n\n      - name: Boot iOS simulator\n        run: |\n          UDID=$(xcrun simctl list devices \"$SIM_NAME\" available -j | node -e \"\n            const data = JSON.parse(require('fs').readFileSync(0, 'utf8'));\n            const all = Object.values(data.devices).flat();\n            const match = all.find(d => d.name === process.env.SIM_NAME && d.isAvailable);\n            if (!match) { console.error('No available', process.env.SIM_NAME); process.exit(1); }\n            console.log(match.udid);\n          \")\n          echo \"SIM_UDID=$UDID\" >> $GITHUB_ENV\n          xcrun simctl boot \"$UDID\"\n          xcrun simctl bootstatus \"$UDID\" -b\n\n      - name: Install app on simulator\n        working-directory: ${{ env.APP_DIR }}\n        run: xcrun simctl install \"$SIM_UDID\" build/Build/Products/Release-iphonesimulator/app.app\n\n      - name: Install Maestro\n        run: |\n          curl -fsSL \"https://get.maestro.mobile.dev\" | bash\n          echo \"$HOME/.maestro/bin\" >> $GITHUB_PATH\n\n      - name: Run Maestro smoke flow\n        working-directory: ${{ env.APP_DIR }}\n        run: maestro test .maestro/smoke.yaml\n\n      - name: Dump simulator logs on failure\n        if: failure()\n        run: |\n          xcrun simctl spawn \"$SIM_UDID\" log show --last 5m --predicate 'process == \"app\"' || true\n"
  },
  {
    "path": ".github/workflows/semantic-pr.yml",
    "content": "name: Semantic PR Check\n\non:\n  pull_request:\n    types: [opened, synchronize, edited]\n\njobs:\n  pr-title-check: \n    name: Check PR for semantic title\n    runs-on: ubuntu-latest\n    steps:\n      - name: PR title is valid\n        if: >\n          startsWith(github.event.pull_request.title, 'feat:') || startsWith(github.event.pull_request.title, 'feat(') ||\n          startsWith(github.event.pull_request.title, 'fix:') || startsWith(github.event.pull_request.title, 'fix(') ||\n          startsWith(github.event.pull_request.title, 'perf:') || startsWith(github.event.pull_request.title, 'perf(') ||\n          startsWith(github.event.pull_request.title, 'docs:') || startsWith(github.event.pull_request.title, 'docs(') ||\n          startsWith(github.event.pull_request.title, 'test:') || startsWith(github.event.pull_request.title, 'test(') ||\n          startsWith(github.event.pull_request.title, 'refactor:') || startsWith(github.event.pull_request.title, 'refactor(') ||\n          startsWith(github.event.pull_request.title, 'style:') || startsWith(github.event.pull_request.title, 'style(') ||\n          startsWith(github.event.pull_request.title, 'build:') || startsWith(github.event.pull_request.title, 'build(') ||\n          startsWith(github.event.pull_request.title, 'ci:') || startsWith(github.event.pull_request.title, 'ci(') ||\n          startsWith(github.event.pull_request.title, 'chore:') || startsWith(github.event.pull_request.title, 'chore(') ||\n          startsWith(github.event.pull_request.title, 'revert:') || startsWith(github.event.pull_request.title, 'revert(')\n        run: |\n          echo 'Title checks passed'\n      - name: PR title is invalid\n        if: >\n          !startsWith(github.event.pull_request.title, 'feat:') && !startsWith(github.event.pull_request.title, 'feat(') &&\n          !startsWith(github.event.pull_request.title, 'fix:') && !startsWith(github.event.pull_request.title, 'fix(') &&\n          !startsWith(github.event.pull_request.title, 'perf:') && !startsWith(github.event.pull_request.title, 'perf(') &&\n          !startsWith(github.event.pull_request.title, 'docs:') && !startsWith(github.event.pull_request.title, 'docs(') &&\n          !startsWith(github.event.pull_request.title, 'test:') && !startsWith(github.event.pull_request.title, 'test(') &&\n          !startsWith(github.event.pull_request.title, 'refactor:') && !startsWith(github.event.pull_request.title, 'refactor(') &&\n          !startsWith(github.event.pull_request.title, 'style:') && !startsWith(github.event.pull_request.title, 'style(') &&\n          !startsWith(github.event.pull_request.title, 'build:') && !startsWith(github.event.pull_request.title, 'build(') &&\n          !startsWith(github.event.pull_request.title, 'ci:') && !startsWith(github.event.pull_request.title, 'ci(') &&\n          !startsWith(github.event.pull_request.title, 'chore:') && !startsWith(github.event.pull_request.title, 'chore(') &&\n          !startsWith(github.event.pull_request.title, 'revert:') && !startsWith(github.event.pull_request.title, 'revert(')\n        run: |\n          echo 'Pull request title is not valid. Please check https://github.com/amplitude/Amplitude-TypeScript/blob/main/CONTRIBUTING.md#pr-commit-title-conventions'\n          exit 1\n"
  },
  {
    "path": ".gitignore",
    "content": "node_modules/\n\n.DS_Store\n\nlib/\n*.tsbuildinfo\ncoverage/\ndocs/\n.idea/\n\n# macos\n.DS_Store\n\n# debug\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n.pnpm-debug.log*\n\n# These files are automatically generated by the TypeScript compiler\n# during the build process and can be easily recreated.\n*.d.ts\n*.d.ts.map\n.env\n.env.*\n!.env.example\n*.pem\n*.key\n*.p12\n*.pfx\nsecrets.*\n\nlerna-debug.log\n\n# Playwright\n**/test-results/\n**/playwright-report/\n**/playwright/.cache/\n**/playwright/.auth/\n\n# Nx\n.nx/cache/\n.nx/workspace-data/\n\n# Playground\npackages/analytics-browser/playground/html/amplitude.js\npackages/analytics-browser/playground/react-spa/public/amplitude.js\n.nx/cache\n.cursor/rules/nx-rules.mdc\n.github/instructions/nx.instructions.md\n.pnpm-store/"
  },
  {
    "path": ".husky/commit-msg",
    "content": "#!/bin/sh\n. \"$(dirname \"$0\")/_/husky.sh\"\n\npnpm commitlint --edit $1\n"
  },
  {
    "path": ".husky/pre-commit",
    "content": "#!/bin/sh\n. \"$(dirname \"$0\")/_/husky.sh\"\n\npnpm install --frozen-lockfile\npnpm lint:staged\n"
  },
  {
    "path": ".npmrc",
    "content": "# Hoist React Native / Metro / Babel packages so Metro can resolve them when\n# bundling the workspace example app (examples/react-native/app). Metro does\n# not understand pnpm's nested .pnpm store, so transitive deps of react-native\n# need to be visible from a flat node_modules.\npublic-hoist-pattern[]=*react-native*\npublic-hoist-pattern[]=@babel/*\npublic-hoist-pattern[]=@react-native/*\npublic-hoist-pattern[]=@react-native-community/*\npublic-hoist-pattern[]=metro\npublic-hoist-pattern[]=metro-*\n"
  },
  {
    "path": ".nvmrc",
    "content": "18\n"
  },
  {
    "path": ".prettierignore",
    "content": "*.md\n\n/.nx/workspace-data\n/.nx/cache"
  },
  {
    "path": ".prettierrc.json",
    "content": "{\n  \"printWidth\": 120,\n  \"proseWrap\": \"always\",\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}\n"
  },
  {
    "path": "AGENTS.md",
    "content": "# Repository Guidelines\n\nThis repository uses GitHub Actions for continuous integration. Contributors should replicate the CI steps locally before opening a pull request.\n\n## Local Environment Setup\n\nBefore running any tests or scripts, install dependencies and build the packages:\n\n```bash\npnpm install\npnpm build\n```\n\n## Testing and Linting\n\n1. Install dependencies with `pnpm install`.\n2. Build all packages with `pnpm build`.\n3. Verify documentation with `pnpm docs:check`.\n4. Run unit tests with `pnpm test` and example tests with `pnpm test:examples`.\n5. Lint the code using `pnpm lint`.\n\nThese steps must pass before you submit your PR.\n\n## Pull Request Requirements\n\n- PR titles must follow the [conventional commit](https://www.conventionalcommits.org/ ) format and, when possible, include the affected module name. Examples: `feat(browser): add feature` or `fix(plugin): correct bug`.\n- The CI matrix runs on Node.js `18.17.x`, `20.x`, and `22.x`. Ensure your code is compatible with these versions.\n\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to the Amplitude-TypeScript\n\n🎉 Thanks for your interest in contributing! 🎉\n\n## Getting Started\n\n### Create a new issue\n\nIf find issues while using this library or just reading through it, look to see if an issue has been created. If no issues are related, feel free to open a new one using the template.\n\n### Solve an issue\n\nIf you find any existing issues that you are interested in fixing, you are welcome to open a PR and we will gladly review your changes.\n\n### Making Changes\n\n#### Setup locally\n\nGetting setup is quick and easy. Follow the steps below to get your your dev environment up.\n\n1. Fork GitHub repo\n2. Install dependencies\n3. Build packages\n\n```\n$ git clone <HTTPS_OR_GIT_URL>\n$ pnpm install\n$ pnpm build\n```\n\nThis repo contains mutliple major versions of all packages. For contributions to version `1.x`, create a branch off `v1.x`. For contributions to the `2.x` (latest) version, create a branch off `main`. Refer to the table below for more infomation about the release status of each package.\n\n|Package|Version|Status|Dev Branch|\n|-|-|-|-|\n|Browser SDK|\n|`@amplitude/analytics-browser`|V2|Beta|`main`|\n|`@amplitude/analytics-browser`|V1|Current|`v1.x`|\n|`@amplitude/marketing-analytics-browser`|V1|Current|`v1.x`|\n|Node SDK|\n|`@amplitude/analytics-node`|V2|Unreleased|`main`|\n|`@amplitude/analytics-node`|V1|Current|`v1.x`|\n|ReactNative SDK|\n|`@amplitude/analytics-react-native`|V2|Unreleased|`main`|\n|`@amplitude/analytics-react-native`|V1|Current|`v1.x`|\n\n#### Test your changes\n\nBuilding quality software is one of our top priorities. We recommend getting your changes tested using manual and automated practices.\n\n```\n$ pnpm build\n$ pnpm test\n```\n\nWhen writing commit message, follow [PR Commit Title Conventions](#PR-Commit-Title-Conventions) for the format. A git hook will also run to verify that the format is followed.\n\n#### Deprecated Packages\n\nThe following packages are deprecated and **should not be added as dependencies** in new code:\n\n- `@amplitude/analytics-types`\n- `@amplitude/analytics-client-common`\n- `@amplitude/analytics-remote-config`\n\n**Replacements:**\n- For `@amplitude/analytics-types` and `@amplitude/analytics-client-common`: Use `@amplitude/analytics-core` instead\n- For `@amplitude/analytics-remote-config`: Use the new remote config client in `@amplitude/analytics-core` instead\n\nThese packages remain in the codebase for backward compatibility with existing code, but new dependencies on them are blocked by CI checks. If your PR fails the \"Check Deprecated Packages\" CI job, update your `package.json` to use the appropriate replacement from `@amplitude/analytics-core`.\n\n#### Open a PR\n\nOnce you are finished with your changes and feel good about the proposed changes, create a pull request. A team member will assist in getting them reviewed. We are excited to work with you on this.\n\nFor contributions to version `1.x`, open a pull request against `v1.x`. For contributions to the `2.x` (latest) version, open a pull request against `main`.\n\n#### Merge\n\nAs soon as your changes are approved, a team member will merge your PR to main and will get published shortly after.\n\n#### Publishing NPM package for the first time\n\nBecause the workflow uses Trusted Publishing, a new package can't be published from the publish workflow on the first try. \n\nTo publish a package for the first time (administrators only):\n1. run `pnpm install` from the route\n2. navigate to the root of the new package\n3. run `pnpm build`\n4. run `pnpm publish` (requires admin credentials with 2FA)\n5. navigate to the NPM homepage of the new package\n6. open \"Settings\" and configure it to use Trusted Publishing\n7. copy the same configuration used in [analytics browser](https://www.npmjs.com/package/@amplitude/analytics-browser/access). **case sensitive**\n8. now that it's in NPM and Trusted Publishing is enabled, this package can now be published from workflows\n\n#### Recovering a partial `publish-v2` workflow run\n\nUse this only when a previous `Publish v2.x` workflow run already created the release version and partially published packages to npm, but the workflow failed before all packages finished publishing.\n\nTo recover from that state:\n\n1. Open the `Publish v2.x` workflow in GitHub Actions.\n2. Click `Run workflow`.\n3. Select the same `releaseType` that the failed run used.\n4. Select the same branch that the failed run used, if applicable.\n5. Enable the `skipLernaVersion` checkbox.\n6. Run the workflow again.\n\nWhen `skipLernaVersion` is enabled, the workflow skips the `lerna version` step for `release` and `prerelease` runs and skips the E2E test step. This lets the workflow continue to the publish step without trying to create a second release version.\n\nDo not use `skipLernaVersion` for a normal release. It is only intended for recovery after a partial `publish-v2` run.\n\n## Practices\n\n### PR Commit Title Conventions\n\nPR titles should follow [conventional commit standards](https://www.conventionalcommits.org/en/v1.0.0/). This helps automate the release process.\n\n#### Commit Types\n\n- **Special Case**: Any commit with `BREAKING CHANGES` in the body: Creates major release\n- `feat(<optional scope>)`: New features (minimum minor release)\n- `fix(<optional scope>)`: Bug fixes (minimum patch release)\n- `perf(<optional scope>)`: Performance improvement\n- `docs(<optional scope>)`: Documentation updates\n- `test(<optional scope>)`: Test updates\n- `refactor(<optional scope>)`: Code change that neither fixes a bug nor adds a feature\n- `style(<optional scope>)`: Code style changes (e.g. formatting, commas, semi-colons)\n- `build(<optional scope>)`: Changes that affect the build system or external dependencies (e.g. pnpm, Npm)\n- `ci(<optional scope>)`: Changes to our CI configuration files and scripts\n- `chore(<optional scope>)`: Other changes that don't modify src or test files\n- `revert(<optional scope>)`: Revert commit\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2022 Amplitude Analytics\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://amplitude.com\" target=\"_blank\" align=\"center\">\n    <img src=\"https://static.amplitude.com/lightning/46c85bfd91905de8047f1ee65c7c93d6fa9ee6ea/static/media/amplitude-logo-with-text.4fb9e463.svg\" width=\"280\">\n  </a>\n  <br />\n</p>\n\n# Amplitude-TypeScript\n\nThis is Amplitude's latest version of the JavaScript SDK, written in TypeScript.\n## Development\n\nIf you plan on contributing to this SDK, here's how you can start.\n\n1. Clone GitHub repo\n2. Install dependencies\n3. Build and link packages\n\n```\n$ git clone git@github.com:amplitude/Amplitude-TypeScript.git\n$ nvm use\n$ pnpm --version\n$ pnpm install\n$ pnpm build\n```\n\nCheck our guidelines for repo contributions on [CONTRIBUTING.md](https://github.com/amplitude/Amplitude-TypeScript/blob/main/CONTRIBUTING.md).\n\n## Projects\n\n* Amplitude SDK for Web\n  * [@amplitude/analytics-browser@^2](https://github.com/amplitude/Amplitude-TypeScript/tree/main/packages/analytics-browser)\n  * [@amplitude/analytics-browser@^1](https://github.com/amplitude/Amplitude-TypeScript/tree/v1.x/packages/analytics-browser)\n  * [Installation and Quick Start](https://www.docs.developers.amplitude.com/data/sdks/browser-2/)\n* Amplitude SDK for Node.js\n  * [@amplitude/analytics-node](https://github.com/amplitude/Amplitude-TypeScript/tree/main/packages/analytics-node)\n  * [Installation and Quick Start](https://www.docs.developers.amplitude.com/data/sdks/typescript-node/)\n* Amplitude SDK for React Native\n  * [@amplitude/analytics-react-native](https://github.com/amplitude/Amplitude-TypeScript/tree/main/packages/analytics-react-native)\n  * [Installation and Quick Start](https://www.docs.developers.amplitude.com/data/sdks/typescript-react-native/)\n\n## Testing Locally\n\nTo test the SDK locally, you can run our test server.\n\nBefore running the test server for the first time, copy \".env.example\" as \".env\" and replace the variables in '.env' with your own variables.\n\nRun `pnpm dev` to run the test server. It will open up to the home page automatically in your default browser.\n\nFor more details visit the [Test Server README.md](/test-server/README.md)\n\n### Troubleshooting\n\nIf you ever see an error that looks like this while running an Nx command (pnpm test, pnpm build, etc...):\n\n```\n Lerna (powered by Nx)   DB transaction operation error: SqliteFailure(Error { code: SystemIoFailure, extended_code: 522 }, Some(\"disk I/O error\"))\n ```\n\nRun `npx nx reset` and try again\n\n## Documentation\n\nSee our [Typescript SDK](https://amplitude.github.io/Amplitude-TypeScript/) Reference for a list and description of all available SDK methods.\n"
  },
  {
    "path": "commitlint.config.js",
    "content": "module.exports = {\n  extends: ['@commitlint/config-conventional']\n};\n"
  },
  {
    "path": "context7.json",
    "content": "{\n  \"url\": \"https://context7.com/amplitude/amplitude-typescript\",\n  \"public_key\": \"pk_qGDvqFQPtTvDeSCjW3eUE\"\n}\n\n"
  },
  {
    "path": "example-proxy/.gitignore",
    "content": "# Dependencies\nnode_modules/\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Environment variables\n.env\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\n# Logs\nlogs\n*.log\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Coverage directory used by tools like istanbul\ncoverage/\n\n# nyc test coverage\n.nyc_output\n\n# Dependency directories\njspm_packages/\n\n# Optional npm cache directory\n.npm\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variables file\n.env\n\n# IDE files\n.vscode/\n.idea/\n*.swp\n*.swo\n\n# OS generated files\n.DS_Store\n.DS_Store?\n._*\n.Spotlight-V100\n.Trashes\nehthumbs.db\nThumbs.db "
  },
  {
    "path": "example-proxy/README.md",
    "content": "# Amplitude Proxy Server\n\nExample Express server acts as a proxy for Amplitude analytics, allowing you to intercept, log, and forward Amplitude tracking requests.\n\n## Features\n\n- ✅ Proxy single Amplitude events\n- ✅ Proxy batch Amplitude events  \n- ✅ CORS support for browser requests\n- ✅ Request logging and debugging\n- ✅ Health check endpoint\n- ✅ Test page for validation\n- ✅ Request monitoring and debugging\n\n## Quick Start\n\n### Option 1: Run from Root Directory\n\n```bash\n# From the project root directory\nnpm run proxy        # Start the proxy server\nnpm run proxy:dev    # Start with auto-restart (development)\n```"
  },
  {
    "path": "example-proxy/amplitude-proxy-server.js",
    "content": "const express = require('express');\nconst cors = require('cors');\nconst axios = require('axios');\nconst morgan = require('morgan');\n\nconst app = express();\nconst PORT = process.env.PORT || 3001;\n\n// Middleware\napp.use(cors());\napp.use(express.json());\napp.use(express.urlencoded({ extended: true }));\napp.use(morgan('combined'));\n\n// Amplitude API endpoints\nconst AMPLITUDE_API_BASE = 'https://api2.amplitude.com';\nconst AMPLITUDE_BATCH_API = 'https://api2.amplitude.com/batch';\n\n// Store for tracking requests (in-memory for demo purposes)\nconst requestLog = [];\n\n// Health check endpoint\napp.get('/health', (req, res) => {\n  res.json({ status: 'ok', timestamp: new Date().toISOString() });\n});\n\n// Proxy endpoint for single events\napp.post('/2/httpapi', async (req, res) => {\n  try {\n    console.log('📊 Received Amplitude event:', JSON.stringify(req.body, null, 2));\n    \n    // Log the request\n    requestLog.push({\n      timestamp: new Date().toISOString(),\n      type: 'single_event',\n      data: req.body\n    });\n\n    // Forward to Amplitude API\n    const response = await axios.post(AMPLITUDE_API_BASE + '/2/httpapi', req.body, {\n      headers: {\n        'Content-Type': 'application/json',\n        'User-Agent': 'Amplitude-Proxy-Server/1.0'\n      }\n    });\n\n    console.log('✅ Forwarded to Amplitude successfully');\n    res.status(response.status).json(response.data);\n  } catch (error) {\n    console.error('❌ Error forwarding to Amplitude:', error.response?.data || error.message);\n    res.status(error.response?.status || 500).json({\n      error: 'Failed to forward to Amplitude',\n      details: error.response?.data || error.message\n    });\n  }\n});\n\n// Proxy endpoint for batch events\napp.post('/batch', async (req, res) => {\n  try {\n    console.log('📦 Received Amplitude batch events:', JSON.stringify(req.body, null, 2));\n    \n    // Log the request\n    requestLog.push({\n      timestamp: new Date().toISOString(),\n      type: 'batch_events',\n      data: req.body\n    });\n\n    // Forward to Amplitude batch API\n    const response = await axios.post(AMPLITUDE_BATCH_API, req.body, {\n      headers: {\n        'Content-Type': 'application/json',\n        'User-Agent': 'Amplitude-Proxy-Server/1.0'\n      }\n    });\n\n    console.log('✅ Forwarded batch to Amplitude successfully');\n    res.status(response.status).json(response.data);\n  } catch (error) {\n    console.error('❌ Error forwarding batch to Amplitude:', error.response?.data || error.message);\n    res.status(error.response?.status || 500).json({\n      error: 'Failed to forward batch to Amplitude',\n      details: error.response?.data || error.message\n    });\n  }\n});\n\n// Debug endpoint to view logged requests\napp.get('/debug/requests', (req, res) => {\n  res.json({\n    total_requests: requestLog.length,\n    requests: requestLog.slice(-50) // Last 50 requests\n  });\n});\n\n// Clear debug logs\napp.delete('/debug/requests', (req, res) => {\n  requestLog.length = 0;\n  res.json({ message: 'Request log cleared' });\n});\n\n// Serve a simple test page\napp.get('/test', (req, res) => {\n  res.send(`\n    <!DOCTYPE html>\n    <html>\n    <head>\n        <title>Amplitude Proxy Test</title>\n        <script src=\"https://cdn.amplitude.com/libs/amplitude-8.21.0-min.gz.js\"></script>\n    </head>\n    <body>\n        <h1>Amplitude Proxy Test Page</h1>\n        <p>This page tests the Amplitude proxy server.</p>\n        <button onclick=\"sendTestEvent()\">Send Test Event</button>\n        <button onclick=\"sendBatchEvents()\">Send Batch Events</button>\n        <div id=\"status\"></div>\n\n        <script>\n            // Initialize Amplitude with proxy server\n            amplitude.getInstance().init('YOUR_API_KEY', null, {\n                serverUrl: 'http://localhost:${PORT}',\n                serverZone: 'US'\n            });\n\n            function sendTestEvent() {\n                amplitude.getInstance().logEvent('Test Event', {\n                    source: 'proxy_test',\n                    timestamp: Date.now()\n                });\n                document.getElementById('status').innerHTML = '<p>✅ Test event sent!</p>';\n            }\n\n            function sendBatchEvents() {\n                // Send multiple events\n                for (let i = 0; i < 3; i++) {\n                    amplitude.getInstance().logEvent('Batch Test Event', {\n                        batch_index: i,\n                        source: 'proxy_test',\n                        timestamp: Date.now()\n                    });\n                }\n                document.getElementById('status').innerHTML = '<p>✅ Batch events sent!</p>';\n            }\n        </script>\n    </body>\n    </html>\n  `);\n});\n\n// Start server\napp.listen(PORT, () => {\n  console.log(`🚀 Amplitude Proxy Server running on http://localhost:${PORT}`);\n  console.log(`📊 Single events: http://localhost:${PORT}/2/httpapi`);\n  console.log(`📦 Batch events: http://localhost:${PORT}/batch`);\n  console.log(`🔍 Debug logs: http://localhost:${PORT}/debug/requests`);\n  console.log(`🧪 Test page: http://localhost:${PORT}/test`);\n  console.log(`❤️  Health check: http://localhost:${PORT}/health`);\n});\n\nmodule.exports = app; "
  },
  {
    "path": "examples/browser/chrome-ext/amplitude-min.js",
    "content": "!function(){\"use strict\";var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},e(t,n)};function t(t,n){if(\"function\"!=typeof n&&null!==n)throw new TypeError(\"Class extends value \"+String(n)+\" is not a constructor or null\");function i(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(i.prototype=n.prototype,new i)}var n=function(){return n=Object.assign||function(e){for(var t,n=1,i=arguments.length;n<i;n++)for(var r in t=arguments[n])Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r]);return e},n.apply(this,arguments)};function i(e,t){var n={};for(var i in e)Object.prototype.hasOwnProperty.call(e,i)&&t.indexOf(i)<0&&(n[i]=e[i]);if(null!=e&&\"function\"==typeof Object.getOwnPropertySymbols){var r=0;for(i=Object.getOwnPropertySymbols(e);r<i.length;r++)t.indexOf(i[r])<0&&Object.prototype.propertyIsEnumerable.call(e,i[r])&&(n[i[r]]=e[i[r]])}return n}function r(e,t,n,i){return new(n||(n=Promise))((function(r,o){function s(e){try{a(i.next(e))}catch(e){o(e)}}function u(e){try{a(i.throw(e))}catch(e){o(e)}}function a(e){var t;e.done?r(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(s,u)}a((i=i.apply(e,t||[])).next())}))}function o(e,t){var n,i,r,o,s={label:0,sent:function(){if(1&r[0])throw r[1];return r[1]},trys:[],ops:[]};return o={next:u(0),throw:u(1),return:u(2)},\"function\"==typeof Symbol&&(o[Symbol.iterator]=function(){return this}),o;function u(u){return function(a){return function(u){if(n)throw new TypeError(\"Generator is already executing.\");for(;o&&(o=0,u[0]&&(s=0)),s;)try{if(n=1,i&&(r=2&u[0]?i.return:u[0]?i.throw||((r=i.return)&&r.call(i),0):i.next)&&!(r=r.call(i,u[1])).done)return r;switch(i=0,r&&(u=[2&u[0],r.value]),u[0]){case 0:case 1:r=u;break;case 4:return s.label++,{value:u[1],done:!1};case 5:s.label++,i=u[1],u=[0];continue;case 7:u=s.ops.pop(),s.trys.pop();continue;default:if(!(r=s.trys,(r=r.length>0&&r[r.length-1])||6!==u[0]&&2!==u[0])){s=0;continue}if(3===u[0]&&(!r||u[1]>r[0]&&u[1]<r[3])){s.label=u[1];break}if(6===u[0]&&s.label<r[1]){s.label=r[1],r=u;break}if(r&&s.label<r[2]){s.label=r[2],s.ops.push(u);break}r[2]&&s.ops.pop(),s.trys.pop();continue}u=t.call(e,s)}catch(e){u=[6,e],i=0}finally{n=r=0}if(5&u[0])throw u[1];return{value:u[0]?u[1]:void 0,done:!0}}([u,a])}}}function s(e){var t=\"function\"==typeof Symbol&&Symbol.iterator,n=t&&e[t],i=0;if(n)return n.call(e);if(e&&\"number\"==typeof e.length)return{next:function(){return e&&i>=e.length&&(e=void 0),{value:e&&e[i++],done:!e}}};throw new TypeError(t?\"Object is not iterable.\":\"Symbol.iterator is not defined.\")}function u(e,t){var n=\"function\"==typeof Symbol&&e[Symbol.iterator];if(!n)return e;var i,r,o=n.call(e),s=[];try{for(;(void 0===t||t-- >0)&&!(i=o.next()).done;)s.push(i.value)}catch(e){r={error:e}}finally{try{i&&!i.done&&(n=o.return)&&n.call(o)}finally{if(r)throw r.error}}return s}function a(e,t,n){if(n||2===arguments.length)for(var i,r=0,o=t.length;r<o;r++)!i&&r in t||(i||(i=Array.prototype.slice.call(t,0,r)),i[r]=t[r]);return e.concat(i||Array.prototype.slice.call(t))}var c,l,d,f,p,v,h=function(){return\"undefined\"!=typeof globalThis?globalThis:\"undefined\"!=typeof window?window:\"undefined\"!=typeof self?self:\"undefined\"!=typeof global?global:void 0},g=function(){var e,t=h();return(null===(e=null==t?void 0:t.location)||void 0===e?void 0:e.search)?t.location.search.substring(1).split(\"&\").filter(Boolean).reduce((function(e,t){var n=t.split(\"=\",2),i=y(n[0]),r=y(n[1]);return r?(e[i]=r,e):e}),{}):{}},y=function(e){void 0===e&&(e=\"\");try{return decodeURIComponent(e)}catch(e){return\"\"}},m=\"dclid\",b=\"fbclid\",I=\"gbraid\",_=\"gclid\",w=\"ko_click_id\",S=\"li_fat_id\",E=\"msclkid\",T=\"rtd_cid\",O=\"ttclid\",k=\"twclid\",P=\"wbraid\",R={utm_campaign:void 0,utm_content:void 0,utm_id:void 0,utm_medium:void 0,utm_source:void 0,utm_term:void 0,referrer:void 0,referring_domain:void 0,dclid:void 0,gbraid:void 0,gclid:void 0,fbclid:void 0,ko_click_id:void 0,li_fat_id:void 0,msclkid:void 0,rtd_cid:void 0,ttclid:void 0,twclid:void 0,wbraid:void 0},U=function(){function e(){}return e.prototype.parse=function(){return r(this,void 0,void 0,(function(){return o(this,(function(e){return[2,n(n(n(n({},R),this.getUtmParam()),this.getReferrer()),this.getClickIds())]}))}))},e.prototype.getUtmParam=function(){var e=g();return{utm_campaign:e.utm_campaign,utm_content:e.utm_content,utm_id:e.utm_id,utm_medium:e.utm_medium,utm_source:e.utm_source,utm_term:e.utm_term}},e.prototype.getReferrer=function(){var e,t,n={referrer:void 0,referring_domain:void 0};try{n.referrer=document.referrer||void 0,n.referring_domain=null!==(t=null===(e=n.referrer)||void 0===e?void 0:e.split(\"/\")[2])&&void 0!==t?t:void 0}catch(e){}return n},e.prototype.getClickIds=function(){var e,t=g();return(e={})[m]=t[m],e[b]=t[b],e[I]=t[I],e[_]=t[_],e[w]=t[w],e[S]=t[S],e[E]=t[E],e[T]=t[T],e[O]=t[O],e[k]=t[k],e[P]=t[P],e},e}();!function(e){e.SET=\"$set\",e.SET_ONCE=\"$setOnce\",e.ADD=\"$add\",e.APPEND=\"$append\",e.PREPEND=\"$prepend\",e.REMOVE=\"$remove\",e.PREINSERT=\"$preInsert\",e.POSTINSERT=\"$postInsert\",e.UNSET=\"$unset\",e.CLEAR_ALL=\"$clearAll\"}(c||(c={})),function(e){e.REVENUE_PRODUCT_ID=\"$productId\",e.REVENUE_QUANTITY=\"$quantity\",e.REVENUE_PRICE=\"$price\",e.REVENUE_TYPE=\"$revenueType\",e.REVENUE=\"$revenue\"}(l||(l={})),function(e){e.IDENTIFY=\"$identify\",e.GROUP_IDENTIFY=\"$groupidentify\",e.REVENUE=\"revenue_amount\"}(d||(d={})),function(e){e[e.None=0]=\"None\",e[e.Error=1]=\"Error\",e[e.Warn=2]=\"Warn\",e[e.Verbose=3]=\"Verbose\",e[e.Debug=4]=\"Debug\"}(f||(f={})),function(e){e.US=\"US\",e.EU=\"EU\"}(p||(p={})),function(e){e.Unknown=\"unknown\",e.Skipped=\"skipped\",e.Success=\"success\",e.RateLimit=\"rate_limit\",e.PayloadTooLarge=\"payload_too_large\",e.Invalid=\"invalid\",e.Failed=\"failed\",e.Timeout=\"Timeout\",e.SystemError=\"SystemError\"}(v||(v={}));var x=Object.freeze({__proto__:null,get SpecialEventType(){return d},get IdentifyOperation(){return c},get RevenueProperty(){return l},get LogLevel(){return f},get ServerZone(){return p},get Status(){return v}}),q=\"AMP\",D=\"\".concat(q,\"_unsent\"),L=\"https://api2.amplitude.com/2/httpapi\",A=function(e){if(Object.keys(e).length>1e3)return!1;for(var t in e){var n=e[t];if(!N(t,n))return!1}return!0},N=function(e,t){var n,i;if(\"string\"!=typeof e)return!1;if(Array.isArray(t)){var r=!0;try{for(var o=s(t),u=o.next();!u.done;u=o.next()){var a=u.value;if(Array.isArray(a))return!1;if(\"object\"==typeof a)r=r&&A(a);else if(![\"number\",\"string\"].includes(typeof a))return!1;if(!r)return!1}}catch(e){n={error:e}}finally{try{u&&!u.done&&(i=o.return)&&i.call(o)}finally{if(n)throw n.error}}}else{if(null==t)return!1;if(\"object\"==typeof t)return A(t);if(![\"number\",\"string\",\"boolean\"].includes(typeof t))return!1}return!0},j=function(){function e(){this._propertySet=new Set,this._properties={}}return e.prototype.getUserProperties=function(){return n({},this._properties)},e.prototype.set=function(e,t){return this._safeSet(c.SET,e,t),this},e.prototype.setOnce=function(e,t){return this._safeSet(c.SET_ONCE,e,t),this},e.prototype.append=function(e,t){return this._safeSet(c.APPEND,e,t),this},e.prototype.prepend=function(e,t){return this._safeSet(c.PREPEND,e,t),this},e.prototype.postInsert=function(e,t){return this._safeSet(c.POSTINSERT,e,t),this},e.prototype.preInsert=function(e,t){return this._safeSet(c.PREINSERT,e,t),this},e.prototype.remove=function(e,t){return this._safeSet(c.REMOVE,e,t),this},e.prototype.add=function(e,t){return this._safeSet(c.ADD,e,t),this},e.prototype.unset=function(e){return this._safeSet(c.UNSET,e,\"-\"),this},e.prototype.clearAll=function(){return this._properties={},this._properties[c.CLEAR_ALL]=\"-\",this},e.prototype._safeSet=function(e,t,n){if(this._validate(e,t,n)){var i=this._properties[e];return void 0===i&&(i={},this._properties[e]=i),i[t]=n,this._propertySet.add(t),!0}return!1},e.prototype._validate=function(e,t,n){return void 0===this._properties[c.CLEAR_ALL]&&(!this._propertySet.has(t)&&(e===c.ADD?\"number\"==typeof n:e===c.UNSET||e===c.REMOVE||N(t,n)))},e}(),C=function(e,t){return n(n({},t),{event_type:d.IDENTIFY,user_properties:e.getUserProperties()})},M=function(e,t,n){return void 0===t&&(t=0),void 0===n&&(n=v.Unknown),{event:e,code:t,message:n}},V=function(e){return e?(e^16*Math.random()>>e/4).toString(16):(String(1e7)+String(-1e3)+String(-4e3)+String(-8e3)+String(-1e11)).replace(/[018]/g,V)},F=function(){function e(e){this.client=e,this.queue=[],this.applying=!1,this.plugins=[]}return e.prototype.register=function(e,t){var n,i,s;return r(this,void 0,void 0,(function(){return o(this,(function(r){switch(r.label){case 0:return e.name=null!==(n=e.name)&&void 0!==n?n:V(),e.type=null!==(i=e.type)&&void 0!==i?i:\"enrichment\",[4,null===(s=e.setup)||void 0===s?void 0:s.call(e,t,this.client)];case 1:return r.sent(),this.plugins.push(e),[2]}}))}))},e.prototype.deregister=function(e){return this.plugins.splice(this.plugins.findIndex((function(t){return t.name===e})),1),Promise.resolve()},e.prototype.reset=function(e){this.applying=!1,this.plugins=[],this.client=e},e.prototype.push=function(e){var t=this;return new Promise((function(n){t.queue.push([e,n]),t.scheduleApply(0)}))},e.prototype.scheduleApply=function(e){var t=this;this.applying||(this.applying=!0,setTimeout((function(){t.apply(t.queue.shift()).then((function(){t.applying=!1,t.queue.length>0&&t.scheduleApply(0)}))}),e))},e.prototype.apply=function(e){return r(this,void 0,void 0,(function(){var t,i,r,a,c,l,d,f,p,v,h,g,y,m,b,I,_,w,S,E;return o(this,(function(o){switch(o.label){case 0:if(!e)return[2];t=u(e,1),i=t[0],r=u(e,2),a=r[1],c=this.plugins.filter((function(e){return\"before\"===e.type})),o.label=1;case 1:o.trys.push([1,6,7,8]),l=s(c),d=l.next(),o.label=2;case 2:return d.done?[3,5]:(g=d.value).execute?[4,g.execute(n({},i))]:[3,4];case 3:if(null===(y=o.sent()))return a({event:i,code:0,message:\"\"}),[2];i=y,o.label=4;case 4:return d=l.next(),[3,2];case 5:return[3,8];case 6:return f=o.sent(),_={error:f},[3,8];case 7:try{d&&!d.done&&(w=l.return)&&w.call(l)}finally{if(_)throw _.error}return[7];case 8:p=this.plugins.filter((function(e){return\"enrichment\"===e.type||void 0===e.type})),o.label=9;case 9:o.trys.push([9,14,15,16]),v=s(p),h=v.next(),o.label=10;case 10:return h.done?[3,13]:(g=h.value).execute?[4,g.execute(n({},i))]:[3,12];case 11:if(null===(y=o.sent()))return a({event:i,code:0,message:\"\"}),[2];i=y,o.label=12;case 12:return h=v.next(),[3,10];case 13:return[3,16];case 14:return m=o.sent(),S={error:m},[3,16];case 15:try{h&&!h.done&&(E=v.return)&&E.call(v)}finally{if(S)throw S.error}return[7];case 16:return b=this.plugins.filter((function(e){return\"destination\"===e.type})),I=b.map((function(e){var t=n({},i);return e.execute(t).catch((function(e){return M(t,0,String(e))}))})),Promise.all(I).then((function(e){var t=u(e,1)[0];a(t)})),[2]}}))}))},e.prototype.flush=function(){return r(this,void 0,void 0,(function(){var e,t,n,i=this;return o(this,(function(r){switch(r.label){case 0:return e=this.queue,this.queue=[],[4,Promise.all(e.map((function(e){return i.apply(e)})))];case 1:return r.sent(),t=this.plugins.filter((function(e){return\"destination\"===e.type})),n=t.map((function(e){return e.flush&&e.flush()})),[4,Promise.all(n)];case 2:return r.sent(),[2]}}))}))},e}(),Q=\"Event rejected due to exceeded retry count\",$=function(e){return{promise:e||Promise.resolve()}},K=function(){function e(e){void 0===e&&(e=\"$default\"),this.initializing=!1,this.q=[],this.dispatchQ=[],this.logEvent=this.track.bind(this),this.timeline=new F(this),this.name=e}return e.prototype._init=function(e){return r(this,void 0,void 0,(function(){return o(this,(function(t){switch(t.label){case 0:return this.config=e,this.timeline.reset(this),[4,this.runQueuedFunctions(\"q\")];case 1:return t.sent(),[2]}}))}))},e.prototype.runQueuedFunctions=function(e){return r(this,void 0,void 0,(function(){var t,n,i,r,u,a;return o(this,(function(o){switch(o.label){case 0:t=this[e],this[e]=[],o.label=1;case 1:o.trys.push([1,6,7,8]),n=s(t),i=n.next(),o.label=2;case 2:return i.done?[3,5]:[4,(0,i.value)()];case 3:o.sent(),o.label=4;case 4:return i=n.next(),[3,2];case 5:return[3,8];case 6:return r=o.sent(),u={error:r},[3,8];case 7:try{i&&!i.done&&(a=n.return)&&a.call(n)}finally{if(u)throw u.error}return[7];case 8:return[2]}}))}))},e.prototype.track=function(e,t,i){var r=function(e,t,i){return n(n(n({},\"string\"==typeof e?{event_type:e}:e),i),t&&{event_properties:t})}(e,t,i);return $(this.dispatch(r))},e.prototype.identify=function(e,t){var n=C(e,t);return $(this.dispatch(n))},e.prototype.groupIdentify=function(e,t,i,r){var o=function(e,t,i,r){var o;return n(n({},r),{event_type:d.GROUP_IDENTIFY,group_properties:i.getUserProperties(),groups:(o={},o[e]=t,o)})}(e,t,i,r);return $(this.dispatch(o))},e.prototype.setGroup=function(e,t,i){var r=function(e,t,i){var r,o=new j;return o.set(e,t),n(n({},i),{event_type:d.IDENTIFY,user_properties:o.getUserProperties(),groups:(r={},r[e]=t,r)})}(e,t,i);return $(this.dispatch(r))},e.prototype.revenue=function(e,t){var i=function(e,t){return n(n({},t),{event_type:d.REVENUE,event_properties:e.getEventProperties()})}(e,t);return $(this.dispatch(i))},e.prototype.add=function(e){return this.config?$(this.timeline.register(e,this.config)):(this.q.push(this.add.bind(this,e)),$())},e.prototype.remove=function(e){return this.config?$(this.timeline.deregister(e)):(this.q.push(this.remove.bind(this,e)),$())},e.prototype.dispatchWithCallback=function(e,t){if(!this.config)return t(M(e,0,\"Client not initialized\"));this.process(e).then(t)},e.prototype.dispatch=function(e){return r(this,void 0,void 0,(function(){var t=this;return o(this,(function(n){return this.config?[2,this.process(e)]:[2,new Promise((function(n){t.dispatchQ.push(t.dispatchWithCallback.bind(t,e,n))}))]}))}))},e.prototype.process=function(e){return r(this,void 0,void 0,(function(){var t,n,i;return o(this,(function(r){switch(r.label){case 0:return r.trys.push([0,2,,3]),this.config.optOut?[2,M(e,0,\"Event skipped due to optOut config\")]:[4,this.timeline.push(e)];case 1:return 200===(i=r.sent()).code?this.config.loggerProvider.log(i.message):this.config.loggerProvider.error(i.message),[2,i];case 2:return t=r.sent(),n=String(t),this.config.loggerProvider.error(n),[2,i=M(e,0,n)];case 3:return[2]}}))}))},e.prototype.setOptOut=function(e){this.config?this.config.optOut=Boolean(e):this.q.push(this.setOptOut.bind(this,Boolean(e)))},e.prototype.flush=function(){return $(this.timeline.flush())},e}(),B=function(){function e(){this.productId=\"\",this.quantity=1,this.price=0}return e.prototype.setProductId=function(e){return this.productId=e,this},e.prototype.setQuantity=function(e){return e>0&&(this.quantity=e),this},e.prototype.setPrice=function(e){return this.price=e,this},e.prototype.setRevenueType=function(e){return this.revenueType=e,this},e.prototype.setRevenue=function(e){return this.revenue=e,this},e.prototype.setEventProperties=function(e){return A(e)&&(this.properties=e),this},e.prototype.getEventProperties=function(){var e=this.properties?n({},this.properties):{};return e[l.REVENUE_PRODUCT_ID]=this.productId,e[l.REVENUE_QUANTITY]=this.quantity,e[l.REVENUE_PRICE]=this.price,e[l.REVENUE_TYPE]=this.revenueType,e[l.REVENUE]=this.revenue,e},e}(),z=\"Amplitude Logger \",W=function(){function e(){this.logLevel=f.None}return e.prototype.disable=function(){this.logLevel=f.None},e.prototype.enable=function(e){void 0===e&&(e=f.Warn),this.logLevel=e},e.prototype.log=function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];this.logLevel<f.Verbose||console.log(\"\".concat(z,\"[Log]: \").concat(e.join(\" \")))},e.prototype.warn=function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];this.logLevel<f.Warn||console.warn(\"\".concat(z,\"[Warn]: \").concat(e.join(\" \")))},e.prototype.error=function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];this.logLevel<f.Error||console.error(\"\".concat(z,\"[Error]: \").concat(e.join(\" \")))},e.prototype.debug=function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];this.logLevel<f.Debug||console.log(\"\".concat(z,\"[Debug]: \").concat(e.join(\" \")))},e}(),J=function(){return{flushMaxRetries:12,flushQueueSize:200,flushIntervalMillis:1e4,logLevel:f.Warn,loggerProvider:new W,optOut:!1,serverUrl:L,serverZone:\"US\",useBatch:!1}},Z=function(){function e(e){var t,n,i,r;this._optOut=!1;var o=J();this.apiKey=e.apiKey,this.flushIntervalMillis=null!==(t=e.flushIntervalMillis)&&void 0!==t?t:o.flushIntervalMillis,this.flushMaxRetries=e.flushMaxRetries||o.flushMaxRetries,this.flushQueueSize=e.flushQueueSize||o.flushQueueSize,this.loggerProvider=e.loggerProvider||o.loggerProvider,this.logLevel=null!==(n=e.logLevel)&&void 0!==n?n:o.logLevel,this.minIdLength=e.minIdLength,this.plan=e.plan,this.ingestionMetadata=e.ingestionMetadata,this.optOut=null!==(i=e.optOut)&&void 0!==i?i:o.optOut,this.serverUrl=e.serverUrl,this.serverZone=e.serverZone||o.serverZone,this.storageProvider=e.storageProvider,this.transportProvider=e.transportProvider,this.useBatch=null!==(r=e.useBatch)&&void 0!==r?r:o.useBatch,this.loggerProvider.enable(this.logLevel);var s=Y(e.serverUrl,e.serverZone,e.useBatch);this.serverZone=s.serverZone,this.serverUrl=s.serverUrl}return Object.defineProperty(e.prototype,\"optOut\",{get:function(){return this._optOut},set:function(e){this._optOut=e},enumerable:!1,configurable:!0}),e}(),G=function(e,t){return\"EU\"===e?t?\"https://api.eu.amplitude.com/batch\":\"https://api.eu.amplitude.com/2/httpapi\":t?\"https://api2.amplitude.com/batch\":L},Y=function(e,t,n){if(void 0===e&&(e=\"\"),void 0===t&&(t=J().serverZone),void 0===n&&(n=J().useBatch),e)return{serverUrl:e,serverZone:void 0};var i=[\"US\",\"EU\"].includes(t)?t:J().serverZone;return{serverZone:i,serverUrl:G(i,n)}},H=function(){function e(){this.name=\"amplitude\",this.type=\"destination\",this.retryTimeout=1e3,this.throttleTimeout=3e4,this.storageKey=\"\",this.scheduled=null,this.queue=[]}return e.prototype.setup=function(e){var t;return r(this,void 0,void 0,(function(){var n,i=this;return o(this,(function(r){switch(r.label){case 0:return this.config=e,this.storageKey=\"\".concat(D,\"_\").concat(this.config.apiKey.substring(0,10)),[4,null===(t=this.config.storageProvider)||void 0===t?void 0:t.get(this.storageKey)];case 1:return n=r.sent(),this.saveEvents(),n&&n.length>0&&Promise.all(n.map((function(e){return i.execute(e)}))).catch(),[2,Promise.resolve(void 0)]}}))}))},e.prototype.execute=function(e){var t=this;return new Promise((function(n){var i={event:e,attempts:0,callback:function(e){return n(e)},timeout:0};t.addToQueue(i)}))},e.prototype.addToQueue=function(){for(var e=this,t=[],n=0;n<arguments.length;n++)t[n]=arguments[n];var i=t.filter((function(t){return t.attempts<e.config.flushMaxRetries?(t.attempts+=1,!0):(e.fulfillRequest([t],500,Q),!1)}));i.forEach((function(t){e.queue=e.queue.concat(t),0!==t.timeout?setTimeout((function(){t.timeout=0,e.schedule(0)}),t.timeout):e.schedule(e.config.flushIntervalMillis)})),this.saveEvents()},e.prototype.schedule=function(e){var t=this;this.scheduled||(this.scheduled=setTimeout((function(){t.flush(!0).then((function(){t.queue.length>0&&t.schedule(e)}))}),e))},e.prototype.flush=function(e){return void 0===e&&(e=!1),r(this,void 0,void 0,(function(){var t,n,i,r=this;return o(this,(function(o){switch(o.label){case 0:return t=[],n=[],this.queue.forEach((function(e){return 0===e.timeout?t.push(e):n.push(e)})),this.queue=n,this.scheduled&&(clearTimeout(this.scheduled),this.scheduled=null),s=t,u=this.config.flushQueueSize,a=Math.max(u,1),i=s.reduce((function(e,t,n){var i=Math.floor(n/a);return e[i]||(e[i]=[]),e[i].push(t),e}),[]),[4,Promise.all(i.map((function(t){return r.send(t,e)})))];case 1:return o.sent(),[2]}var s,u,a}))}))},e.prototype.send=function(e,t){return void 0===t&&(t=!0),r(this,void 0,void 0,(function(){var n,r,s,u,a;return o(this,(function(o){switch(o.label){case 0:if(!this.config.apiKey)return[2,this.fulfillRequest(e,400,\"Event rejected due to missing API key\")];n={api_key:this.config.apiKey,events:e.map((function(e){var t=e.event;return t.extra,i(t,[\"extra\"])})),options:{min_id_length:this.config.minIdLength}},o.label=1;case 1:return o.trys.push([1,3,,4]),r=Y(this.config.serverUrl,this.config.serverZone,this.config.useBatch).serverUrl,[4,this.config.transportProvider.send(r,n)];case 2:if(null===(s=o.sent()))return this.fulfillRequest(e,0,\"Unexpected error occurred\"),[2];if(!t){if(\"body\"in s){u=\"\";try{u=JSON.stringify(s.body,null,2)}catch(e){}this.fulfillRequest(e,s.statusCode,\"\".concat(s.status,\": \").concat(u))}else this.fulfillRequest(e,s.statusCode,s.status);return[2]}return this.handleReponse(s,e),[3,4];case 3:return a=o.sent(),this.fulfillRequest(e,0,String(a)),[3,4];case 4:return[2]}}))}))},e.prototype.handleReponse=function(e,t){switch(e.status){case v.Success:this.handleSuccessResponse(e,t);break;case v.Invalid:this.handleInvalidResponse(e,t);break;case v.PayloadTooLarge:this.handlePayloadTooLargeResponse(e,t);break;case v.RateLimit:this.handleRateLimitResponse(e,t);break;default:this.handleOtherReponse(t)}},e.prototype.handleSuccessResponse=function(e,t){this.fulfillRequest(t,e.statusCode,\"Event tracked successfully\")},e.prototype.handleInvalidResponse=function(e,t){var n=this;if(e.body.missingField||e.body.error.startsWith(\"Invalid API key\"))this.fulfillRequest(t,e.statusCode,e.body.error);else{var i=a(a(a(a([],u(Object.values(e.body.eventsWithInvalidFields)),!1),u(Object.values(e.body.eventsWithMissingFields)),!1),u(Object.values(e.body.eventsWithInvalidIdLengths)),!1),u(e.body.silencedEvents),!1).flat(),r=new Set(i),o=t.filter((function(t,i){if(!r.has(i))return!0;n.fulfillRequest([t],e.statusCode,e.body.error)}));this.addToQueue.apply(this,a([],u(o),!1))}},e.prototype.handlePayloadTooLargeResponse=function(e,t){1!==t.length?(this.config.flushQueueSize/=2,this.addToQueue.apply(this,a([],u(t),!1))):this.fulfillRequest(t,e.statusCode,e.body.error)},e.prototype.handleRateLimitResponse=function(e,t){var n=this,i=Object.keys(e.body.exceededDailyQuotaUsers),r=Object.keys(e.body.exceededDailyQuotaDevices),o=e.body.throttledEvents,s=new Set(i),c=new Set(r),l=new Set(o),d=t.filter((function(t,i){if(!(t.event.user_id&&s.has(t.event.user_id)||t.event.device_id&&c.has(t.event.device_id)))return l.has(i)&&(t.timeout=n.throttleTimeout),!0;n.fulfillRequest([t],e.statusCode,e.body.error)}));this.addToQueue.apply(this,a([],u(d),!1))},e.prototype.handleOtherReponse=function(e){var t=this;this.addToQueue.apply(this,a([],u(e.map((function(e){return e.timeout=e.attempts*t.retryTimeout,e}))),!1))},e.prototype.fulfillRequest=function(e,t,n){this.saveEvents(),e.forEach((function(e){return e.callback(M(e.event,t,n))}))},e.prototype.saveEvents=function(){if(this.config.storageProvider){var e=Array.from(this.queue.map((function(e){return e.event})));this.config.storageProvider.set(this.storageKey,e)}},e}(),X=function(e){return void 0===e&&(e=0),((new Error).stack||\"\").split(\"\\n\").slice(2+e).map((function(e){return e.trim()}))},ee=function(e){return function(){var t=n({},e.config);return{logger:t.loggerProvider,logLevel:t.logLevel}}},te=function(e,t){var n,i;t=(t=t.replace(/\\[(\\w+)\\]/g,\".$1\")).replace(/^\\./,\"\");try{for(var r=s(t.split(\".\")),o=r.next();!o.done;o=r.next()){var u=o.value;if(!(u in e))return;e=e[u]}}catch(e){n={error:e}}finally{try{o&&!o.done&&(i=r.return)&&i.call(r)}finally{if(n)throw n.error}}return e},ne=function(e,t){return function(){var n,i,r={};try{for(var o=s(t),u=o.next();!u.done;u=o.next()){var a=u.value;r[a]=te(e,a)}}catch(e){n={error:e}}finally{try{u&&!u.done&&(i=o.return)&&i.call(o)}finally{if(n)throw n.error}}return r}},ie=function(e,t,n,i,r){return void 0===r&&(r=null),function(){for(var o=[],s=0;s<arguments.length;s++)o[s]=arguments[s];var u=n(),a=u.logger,c=u.logLevel;if(c&&c<f.Debug||!c||!a)return e.apply(r,o);var l={type:\"invoke public method\",name:t,args:o,stacktrace:X(1),time:{start:(new Date).toISOString()},states:{}};i&&l.states&&(l.states.before=i());var d=e.apply(r,o);return d&&d.promise?d.promise.then((function(){i&&l.states&&(l.states.after=i()),l.time&&(l.time.end=(new Date).toISOString()),a.debug(JSON.stringify(l,null,2))})):(i&&l.states&&(l.states.after=i()),l.time&&(l.time.end=(new Date).toISOString()),a.debug(JSON.stringify(l,null,2))),d}},re=function(){function e(){this.memoryStorage=new Map}return e.prototype.isEnabled=function(){return r(this,void 0,void 0,(function(){return o(this,(function(e){return[2,!0]}))}))},e.prototype.get=function(e){return r(this,void 0,void 0,(function(){return o(this,(function(t){return[2,this.memoryStorage.get(e)]}))}))},e.prototype.getRaw=function(e){return r(this,void 0,void 0,(function(){var t;return o(this,(function(n){switch(n.label){case 0:return[4,this.get(e)];case 1:return[2,(t=n.sent())?JSON.stringify(t):void 0]}}))}))},e.prototype.set=function(e,t){return r(this,void 0,void 0,(function(){return o(this,(function(n){return this.memoryStorage.set(e,t),[2]}))}))},e.prototype.remove=function(e){return r(this,void 0,void 0,(function(){return o(this,(function(t){return this.memoryStorage.delete(e),[2]}))}))},e.prototype.reset=function(){return r(this,void 0,void 0,(function(){return o(this,(function(e){return this.memoryStorage.clear(),[2]}))}))},e}(),oe=function(){function e(){}return e.prototype.send=function(e,t){return Promise.resolve(null)},e.prototype.buildResponse=function(e){var t,n,i,r,o,s,u,a,c,l,d,f,p,h,g,y,m,b,I,_,w,S;if(\"object\"!=typeof e)return null;var E=e.code||0,T=this.buildStatus(E);switch(T){case v.Success:return{status:T,statusCode:E,body:{eventsIngested:null!==(t=e.events_ingested)&&void 0!==t?t:0,payloadSizeBytes:null!==(n=e.payload_size_bytes)&&void 0!==n?n:0,serverUploadTime:null!==(i=e.server_upload_time)&&void 0!==i?i:0}};case v.Invalid:return{status:T,statusCode:E,body:{error:null!==(r=e.error)&&void 0!==r?r:\"\",missingField:null!==(o=e.missing_field)&&void 0!==o?o:\"\",eventsWithInvalidFields:null!==(s=e.events_with_invalid_fields)&&void 0!==s?s:{},eventsWithMissingFields:null!==(u=e.events_with_missing_fields)&&void 0!==u?u:{},eventsWithInvalidIdLengths:null!==(a=e.events_with_invalid_id_lengths)&&void 0!==a?a:{},epsThreshold:null!==(c=e.eps_threshold)&&void 0!==c?c:0,exceededDailyQuotaDevices:null!==(l=e.exceeded_daily_quota_devices)&&void 0!==l?l:{},silencedDevices:null!==(d=e.silenced_devices)&&void 0!==d?d:[],silencedEvents:null!==(f=e.silenced_events)&&void 0!==f?f:[],throttledDevices:null!==(p=e.throttled_devices)&&void 0!==p?p:{},throttledEvents:null!==(h=e.throttled_events)&&void 0!==h?h:[]}};case v.PayloadTooLarge:return{status:T,statusCode:E,body:{error:null!==(g=e.error)&&void 0!==g?g:\"\"}};case v.RateLimit:return{status:T,statusCode:E,body:{error:null!==(y=e.error)&&void 0!==y?y:\"\",epsThreshold:null!==(m=e.eps_threshold)&&void 0!==m?m:0,throttledDevices:null!==(b=e.throttled_devices)&&void 0!==b?b:{},throttledUsers:null!==(I=e.throttled_users)&&void 0!==I?I:{},exceededDailyQuotaDevices:null!==(_=e.exceeded_daily_quota_devices)&&void 0!==_?_:{},exceededDailyQuotaUsers:null!==(w=e.exceeded_daily_quota_users)&&void 0!==w?w:{},throttledEvents:null!==(S=e.throttled_events)&&void 0!==S?S:[]}};case v.Timeout:default:return{status:T,statusCode:E}}},e.prototype.buildStatus=function(e){return e>=200&&e<300?v.Success:429===e?v.RateLimit:413===e?v.PayloadTooLarge:408===e?v.Timeout:e>=400&&e<500?v.Invalid:e>=500?v.Failed:v.Unknown},e}(),se=function(e,t,n){return void 0===t&&(t=\"\"),void 0===n&&(n=10),[q,t,e.substring(0,n)].filter(Boolean).join(\"_\")},ue=function(){function e(e){this.options=n({},e)}return e.prototype.isEnabled=function(){return r(this,void 0,void 0,(function(){var t,n,i;return o(this,(function(r){switch(r.label){case 0:if(!h())return[2,!1];t=String(Date.now()),n=new e(this.options),i=\"AMP_TEST\",r.label=1;case 1:return r.trys.push([1,4,5,7]),[4,n.set(i,t)];case 2:return r.sent(),[4,n.get(i)];case 3:return[2,r.sent()===t];case 4:return r.sent(),[2,!1];case 5:return[4,n.remove(i)];case 6:return r.sent(),[7];case 7:return[2]}}))}))},e.prototype.get=function(e){return r(this,void 0,void 0,(function(){var t;return o(this,(function(n){switch(n.label){case 0:return[4,this.getRaw(e)];case 1:if(!(t=n.sent()))return[2,void 0];try{try{t=decodeURIComponent(atob(t))}catch(e){}return[2,JSON.parse(t)]}catch(e){return[2,void 0]}return[2]}}))}))},e.prototype.getRaw=function(e){var t;return r(this,void 0,void 0,(function(){var n,i,r;return o(this,(function(o){return n=h(),i=null!==(t=null==n?void 0:n.document.cookie.split(\"; \"))&&void 0!==t?t:[],(r=i.find((function(t){return 0===t.indexOf(e+\"=\")})))?[2,r.substring(e.length+1)]:[2,void 0]}))}))},e.prototype.set=function(e,t){var n;return r(this,void 0,void 0,(function(){var i,r,s,u,a,c;return o(this,(function(o){try{i=null!==(n=this.options.expirationDays)&&void 0!==n?n:0,s=void 0,(r=null!==t?i:-1)&&((u=new Date).setTime(u.getTime()+24*r*60*60*1e3),s=u),a=\"\".concat(e,\"=\").concat(btoa(encodeURIComponent(JSON.stringify(t)))),s&&(a+=\"; expires=\".concat(s.toUTCString())),a+=\"; path=/\",this.options.domain&&(a+=\"; domain=\".concat(this.options.domain)),this.options.secure&&(a+=\"; Secure\"),this.options.sameSite&&(a+=\"; SameSite=\".concat(this.options.sameSite)),(c=h())&&(c.document.cookie=a)}catch(e){}return[2]}))}))},e.prototype.remove=function(e){return r(this,void 0,void 0,(function(){return o(this,(function(t){switch(t.label){case 0:return[4,this.set(e,null)];case 1:return t.sent(),[2]}}))}))},e.prototype.reset=function(){return r(this,void 0,void 0,(function(){return o(this,(function(e){return[2]}))}))},e}(),ae=function(e){function n(){return null!==e&&e.apply(this,arguments)||this}return t(n,e),n.prototype.send=function(e,t){return r(this,void 0,void 0,(function(){var n,i;return o(this,(function(r){switch(r.label){case 0:if(\"undefined\"==typeof fetch)throw new Error(\"FetchTransport is not supported\");return n={headers:{\"Content-Type\":\"application/json\",Accept:\"*/*\"},body:JSON.stringify(t),method:\"POST\"},[4,fetch(e,n)];case 1:return[4,r.sent().json()];case 2:return i=r.sent(),[2,this.buildResponse(i)]}}))}))},n}(oe),ce=function(){function e(){}return e.prototype.getApplicationContext=function(){return{versionName:this.versionName,language:le(),platform:\"Web\",os:void 0,deviceModel:void 0}},e}(),le=function(){return\"undefined\"!=typeof navigator&&(navigator.languages&&navigator.languages[0]||navigator.language)||\"\"},de=function(){function e(){this.queue=[]}return e.prototype.logEvent=function(e){this.receiver?this.receiver(e):this.queue.length<512&&this.queue.push(e)},e.prototype.setEventReceiver=function(e){this.receiver=e,this.queue.length>0&&(this.queue.forEach((function(t){e(t)})),this.queue=[])},e}(),fe=function(){return fe=Object.assign||function(e){for(var t,n=1,i=arguments.length;n<i;n++)for(var r in t=arguments[n])Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r]);return e},fe.apply(this,arguments)},pe=function(e,t){var n=typeof e;if(n!==typeof t)return!1;for(var i=0,r=[\"string\",\"number\",\"boolean\",\"undefined\"];i<r.length;i++){if(r[i]===n)return e===t}if(null==e&&null==t)return!0;if(null==e||null==t)return!1;if(e.length!==t.length)return!1;var o=Array.isArray(e),s=Array.isArray(t);if(o!==s)return!1;if(!o||!s){var u=Object.keys(e).sort(),a=Object.keys(t).sort();if(!pe(u,a))return!1;var c=!0;return Object.keys(e).forEach((function(n){pe(e[n],t[n])||(c=!1)})),c}for(var l=0;l<e.length;l++)if(!pe(e[l],t[l]))return!1;return!0};Object.entries||(Object.entries=function(e){for(var t=Object.keys(e),n=t.length,i=new Array(n);n--;)i[n]=[t[n],e[t[n]]];return i});var ve=function(){function e(){this.identity={userProperties:{}},this.listeners=new Set}return e.prototype.editIdentity=function(){var e=this,t=fe({},this.identity.userProperties),n=fe(fe({},this.identity),{userProperties:t});return{setUserId:function(e){return n.userId=e,this},setDeviceId:function(e){return n.deviceId=e,this},setUserProperties:function(e){return n.userProperties=e,this},updateUserProperties:function(e){for(var t=n.userProperties||{},i=0,r=Object.entries(e);i<r.length;i++){var o=r[i],s=o[0],u=o[1];switch(s){case\"$set\":for(var a=0,c=Object.entries(u);a<c.length;a++){var l=c[a],d=l[0],f=l[1];t[d]=f}break;case\"$unset\":for(var p=0,v=Object.keys(u);p<v.length;p++){delete t[d=v[p]]}break;case\"$clearAll\":t={}}}return n.userProperties=t,this},commit:function(){return e.setIdentity(n),this}}},e.prototype.getIdentity=function(){return fe({},this.identity)},e.prototype.setIdentity=function(e){var t=fe({},this.identity);this.identity=fe({},e),pe(t,this.identity)||this.listeners.forEach((function(t){t(e)}))},e.prototype.addIdentityListener=function(e){this.listeners.add(e)},e.prototype.removeIdentityListener=function(e){this.listeners.delete(e)},e}(),he=\"undefined\"!=typeof globalThis?globalThis:\"undefined\"!=typeof global?global:self,ge=function(){function e(){this.identityStore=new ve,this.eventBridge=new de,this.applicationContextProvider=new ce}return e.getInstance=function(t){return he.analyticsConnectorInstances||(he.analyticsConnectorInstances={}),he.analyticsConnectorInstances[t]||(he.analyticsConnectorInstances[t]=new e),he.analyticsConnectorInstances[t]},e}(),ye=function(){return ge.getInstance(\"$default_instance\")},me=function(){function e(){this.name=\"identity\",this.type=\"before\",this.identityStore=ye().identityStore}return e.prototype.execute=function(e){return r(this,void 0,void 0,(function(){var t;return o(this,(function(n){return(t=e.user_properties)&&this.identityStore.editIdentity().updateUserProperties(t).commit(),[2,e]}))}))},e.prototype.setup=function(e){return Promise.resolve(void 0)},e}(),be=function(){var e,t,n,i;if(\"undefined\"==typeof navigator)return\"\";var r=navigator.userLanguage;return null!==(i=null!==(n=null!==(t=null===(e=navigator.languages)||void 0===e?void 0:e[0])&&void 0!==t?t:navigator.language)&&void 0!==n?n:r)&&void 0!==i?i:\"\"},Ie=function(e,t){return\"boolean\"==typeof e?e:!1!==(null==e?void 0:e[t])},_e=function(e){return Ie(e,\"attribution\")},we=function(e){var t,n,i=function(){return!1},r=void 0;return(n=e.defaultTracking,Ie(n,\"pageViews\"))&&(i=void 0,t=void 0,e.defaultTracking&&\"object\"==typeof e.defaultTracking&&e.defaultTracking.pageViews&&\"object\"==typeof e.defaultTracking.pageViews&&(\"trackOn\"in e.defaultTracking.pageViews&&(i=e.defaultTracking.pageViews.trackOn),\"trackHistoryChanges\"in e.defaultTracking.pageViews&&(r=e.defaultTracking.pageViews.trackHistoryChanges),\"eventType\"in e.defaultTracking.pageViews&&e.defaultTracking.pageViews.eventType&&(t=e.defaultTracking.pageViews.eventType))),{trackOn:i,trackHistoryChanges:r,eventType:t}},Se=function(e,t){Ee(e,t)},Ee=function(e,t){for(var n=0;n<t.length;n++){var i=t[n],r=i.name,o=i.args,s=i.resolve,u=e&&e[r];if(\"function\"==typeof u){var a=u.apply(e,o);\"function\"==typeof s&&s(null==a?void 0:a.promise)}}return e},Te=function(e){return e&&void 0!==e._q},Oe=function(){function e(){this.name=\"@amplitude/plugin-context-browser\",this.type=\"before\",this.eventId=0,this.library=\"amplitude-ts/\".concat(\"2.0.0-beta.5\"),\"undefined\"!=typeof navigator&&(this.userAgent=navigator.userAgent)}return e.prototype.setup=function(e){return this.config=e,this.eventId=this.config.lastEventId?this.config.lastEventId+1:0,Promise.resolve(void 0)},e.prototype.execute=function(e){return r(this,void 0,void 0,(function(){var t;return o(this,(function(i){return t=(new Date).getTime(),this.config.lastEventId=this.eventId,[2,n(n(n(n(n(n(n(n({user_id:this.config.userId,device_id:this.config.deviceId,session_id:this.config.sessionId,time:t},this.config.appVersion&&{app_version:this.config.appVersion}),this.config.trackingOptions.platform&&{platform:\"Web\"}),this.config.trackingOptions.language&&{language:be()}),this.config.trackingOptions.ipAddress&&{ip:\"$remote\"}),{insert_id:V(),partner_id:this.config.partnerId,plan:this.config.plan}),this.config.ingestionMetadata&&{ingestion_metadata:{source_name:this.config.ingestionMetadata.sourceName,source_version:this.config.ingestionMetadata.sourceVersion}}),e),{event_id:this.eventId++,library:this.library,user_agent:this.userAgent})]}))}))},e}(),ke=function(){function e(){}return e.prototype.isEnabled=function(){return r(this,void 0,void 0,(function(){var t,n,i;return o(this,(function(r){switch(r.label){case 0:if(!h())return[2,!1];t=String(Date.now()),n=new e,i=\"AMP_TEST\",r.label=1;case 1:return r.trys.push([1,4,5,7]),[4,n.set(i,t)];case 2:return r.sent(),[4,n.get(i)];case 3:return[2,r.sent()===t];case 4:return r.sent(),[2,!1];case 5:return[4,n.remove(i)];case 6:return r.sent(),[7];case 7:return[2]}}))}))},e.prototype.get=function(e){return r(this,void 0,void 0,(function(){var t;return o(this,(function(n){switch(n.label){case 0:return n.trys.push([0,2,,3]),[4,this.getRaw(e)];case 1:return(t=n.sent())?[2,JSON.parse(t)]:[2,void 0];case 2:return n.sent(),[2,void 0];case 3:return[2]}}))}))},e.prototype.getRaw=function(e){var t;return r(this,void 0,void 0,(function(){return o(this,(function(n){return[2,(null===(t=h())||void 0===t?void 0:t.localStorage.getItem(e))||void 0]}))}))},e.prototype.set=function(e,t){var n;return r(this,void 0,void 0,(function(){return o(this,(function(i){try{null===(n=h())||void 0===n||n.localStorage.setItem(e,JSON.stringify(t))}catch(e){}return[2]}))}))},e.prototype.remove=function(e){var t;return r(this,void 0,void 0,(function(){return o(this,(function(n){try{null===(t=h())||void 0===t||t.localStorage.removeItem(e)}catch(e){}return[2]}))}))},e.prototype.reset=function(){var e;return r(this,void 0,void 0,(function(){return o(this,(function(t){try{null===(e=h())||void 0===e||e.localStorage.clear()}catch(e){}return[2]}))}))},e}(),Pe=function(e){function n(){var t=null!==e&&e.apply(this,arguments)||this;return t.state={done:4},t}return t(n,e),n.prototype.send=function(e,t){return r(this,void 0,void 0,(function(){var n=this;return o(this,(function(i){return[2,new Promise((function(i,r){\"undefined\"==typeof XMLHttpRequest&&r(new Error(\"XHRTransport is not supported.\"));var o=new XMLHttpRequest;o.open(\"POST\",e,!0),o.onreadystatechange=function(){if(o.readyState===n.state.done)try{var e=o.responseText,t=JSON.parse(e),s=n.buildResponse(t);i(s)}catch(e){r(e)}},o.setRequestHeader(\"Content-Type\",\"application/json\"),o.setRequestHeader(\"Accept\",\"*/*\"),o.send(JSON.stringify(t))}))]}))}))},n}(oe),Re=function(e){function n(){return null!==e&&e.apply(this,arguments)||this}return t(n,e),n.prototype.send=function(e,t){return r(this,void 0,void 0,(function(){var n=this;return o(this,(function(i){return[2,new Promise((function(i,r){var o=h();if(!(null==o?void 0:o.navigator.sendBeacon))throw new Error(\"SendBeaconTransport is not supported\");try{var s=JSON.stringify(t);return i(o.navigator.sendBeacon(e,JSON.stringify(t))?n.buildResponse({code:200,events_ingested:t.events.length,payload_size_bytes:s.length,server_upload_time:Date.now()}):n.buildResponse({code:500}))}catch(e){r(e)}}))]}))}))},n}(oe),Ue=function(e,t,n){return void 0===n&&(n=!0),r(void 0,void 0,void 0,(function(){var i,r,s,a,c,l,d,f;return o(this,(function(o){switch(o.label){case 0:return i=function(e){return\"\".concat(q.toLowerCase(),\"_\").concat(e.substring(0,6))}(e),[4,t.getRaw(i)];case 1:return(r=o.sent())?n?[4,t.remove(i)]:[3,3]:[2,{optOut:!1}];case 2:o.sent(),o.label=3;case 3:return s=u(r.split(\".\"),5),a=s[0],c=s[1],l=s[2],d=s[3],f=s[4],[2,{deviceId:a,userId:qe(c),sessionId:xe(d),lastEventTime:xe(f),optOut:Boolean(l)}]}}))}))},xe=function(e){var t=parseInt(e,32);if(!isNaN(t))return t},qe=function(e){if(atob&&escape&&e)try{return decodeURIComponent(escape(atob(e)))}catch(e){return}},De=\"[Amplitude]\",Le=\"\".concat(De,\" Form Started\"),Ae=\"\".concat(De,\" Form Submitted\"),Ne=\"\".concat(De,\" File Downloaded\"),je=\"session_start\",Ce=\"session_end\",Me=\"\".concat(De,\" File Extension\"),Ve=\"\".concat(De,\" File Name\"),Fe=\"\".concat(De,\" Link ID\"),Qe=\"\".concat(De,\" Link Text\"),$e=\"\".concat(De,\" Link URL\"),Ke=\"\".concat(De,\" Form ID\"),Be=\"\".concat(De,\" Form Name\"),ze=\"\".concat(De,\" Form Destination\"),We=\"cookie\",Je=function(e){function n(t,n,i,r,o,s,u,a,c,l,d,p,v,h,g,y,m,b,I,_,w,S,E,T,O,k,P,R){void 0===i&&(i=new re),void 0===r&&(r={domain:\"\",expiration:365,sameSite:\"Lax\",secure:!1,upgrade:!0}),void 0===o&&(o=!0),void 0===u&&(u=1e3),void 0===a&&(a=5),void 0===c&&(c=30),void 0===l&&(l=We),void 0===h&&(h=new W),void 0===g&&(g=f.Warn),void 0===m&&(m=!1),void 0===_&&(_=\"\"),void 0===w&&(w=\"US\"),void 0===E&&(E=18e5),void 0===T&&(T=new ke),void 0===O&&(O={ipAddress:!0,language:!0,platform:!0}),void 0===k&&(k=\"fetch\"),void 0===P&&(P=!1);var U=e.call(this,{apiKey:t,storageProvider:T,transportProvider:Ye(k)})||this;return U.apiKey=t,U.appVersion=n,U.cookieOptions=r,U.defaultTracking=o,U.flushIntervalMillis=u,U.flushMaxRetries=a,U.flushQueueSize=c,U.identityStorage=l,U.ingestionMetadata=d,U.loggerProvider=h,U.logLevel=g,U.minIdLength=y,U.partnerId=b,U.plan=I,U.serverUrl=_,U.serverZone=w,U.sessionTimeout=E,U.storageProvider=T,U.trackingOptions=O,U.transport=k,U.useBatch=P,U._optOut=!1,U._cookieStorage=i,U.deviceId=s,U.lastEventId=p,U.lastEventTime=v,U.optOut=m,U.sessionId=S,U.userId=R,U.loggerProvider.enable(U.logLevel),U}return t(n,e),Object.defineProperty(n.prototype,\"cookieStorage\",{get:function(){return this._cookieStorage},set:function(e){this._cookieStorage!==e&&(this._cookieStorage=e,this.updateStorage())},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,\"deviceId\",{get:function(){return this._deviceId},set:function(e){this._deviceId!==e&&(this._deviceId=e,this.updateStorage())},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,\"userId\",{get:function(){return this._userId},set:function(e){this._userId!==e&&(this._userId=e,this.updateStorage())},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,\"sessionId\",{get:function(){return this._sessionId},set:function(e){this._sessionId!==e&&(this._sessionId=e,this.updateStorage())},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,\"optOut\",{get:function(){return this._optOut},set:function(e){this._optOut!==e&&(this._optOut=e,this.updateStorage())},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,\"lastEventTime\",{get:function(){return this._lastEventTime},set:function(e){this._lastEventTime!==e&&(this._lastEventTime=e,this.updateStorage())},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,\"lastEventId\",{get:function(){return this._lastEventId},set:function(e){this._lastEventId!==e&&(this._lastEventId=e,this.updateStorage())},enumerable:!1,configurable:!0}),n.prototype.updateStorage=function(){var e={deviceId:this._deviceId,userId:this._userId,sessionId:this._sessionId,optOut:this._optOut,lastEventTime:this._lastEventTime,lastEventId:this._lastEventId};this.cookieStorage.set(se(this.apiKey),e)},n}(Z),Ze=function(e,t,i){return void 0===t&&(t={}),r(void 0,void 0,void 0,(function(){var r,s,u,a,c,l,d,f,p,v,h,y,m,b,I,_,w,S,E,T,O,k,P,R,U,x,q,D,L,A,N,j,C,M;return o(this,(function(o){switch(o.label){case 0:return r=t.identityStorage||We,u=[n({},t.cookieOptions)],w={},r===We?[3,1]:(a=\"\",[3,5]);case 1:return null===(E=null===(S=t.cookieOptions)||void 0===S?void 0:S.domain)||void 0===E?[3,2]:(c=E,[3,4]);case 2:return[4,He()];case 3:c=o.sent(),o.label=4;case 4:a=c,o.label=5;case 5:return s=n.apply(void 0,u.concat([(w.domain=a,w.expiration=365,w.sameSite=\"Lax\",w.secure=!1,w.upgrade=!0,w)])),l=Ge(t.identityStorage,s),[4,Ue(e,l,null===(O=null===(T=t.cookieOptions)||void 0===T?void 0:T.upgrade)||void 0===O||O)];case 6:return d=o.sent(),[4,l.get(se(e))];case 7:return f=o.sent(),p=g(),v=null!==(U=null!==(R=null!==(P=null!==(k=t.deviceId)&&void 0!==k?k:p.deviceId)&&void 0!==P?P:null==f?void 0:f.deviceId)&&void 0!==R?R:d.deviceId)&&void 0!==U?U:V(),h=null==f?void 0:f.lastEventId,y=null!==(x=null==f?void 0:f.lastEventTime)&&void 0!==x?x:d.lastEventTime,m=null!==(D=null!==(q=t.optOut)&&void 0!==q?q:null==f?void 0:f.optOut)&&void 0!==D?D:d.optOut,b=null!==(A=null!==(L=t.sessionId)&&void 0!==L?L:null==f?void 0:f.sessionId)&&void 0!==A?A:d.sessionId,I=null!==(j=null!==(N=t.userId)&&void 0!==N?N:null==f?void 0:f.userId)&&void 0!==j?j:d.userId,i.previousSessionDeviceId=null!==(C=null==f?void 0:f.deviceId)&&void 0!==C?C:d.deviceId,i.previousSessionUserId=null!==(M=null==f?void 0:f.userId)&&void 0!==M?M:d.userId,_=n(n({},t.trackingOptions),{ipAddress:!0,language:!0,platform:!0}),[2,new Je(e,t.appVersion,l,s,t.defaultTracking,v,t.flushIntervalMillis,t.flushMaxRetries,t.flushQueueSize,r,t.ingestionMetadata,h,y,t.loggerProvider,t.logLevel,t.minIdLength,m,t.partnerId,t.plan,t.serverUrl,t.serverZone,b,t.sessionTimeout,t.storageProvider,_,t.transport,t.useBatch,I)]}}))}))},Ge=function(e,t){switch(void 0===e&&(e=We),void 0===t&&(t={}),e){case\"localStorage\":return new ke;case\"none\":return new re;default:return new ue(t)}},Ye=function(e){return\"xhr\"===e?new Pe:\"beacon\"===e?new Re:new ae},He=function(e){return r(void 0,void 0,void 0,(function(){var t,n,i,r,s,u,a;return o(this,(function(o){switch(o.label){case 0:return[4,(new ue).isEnabled()];case 1:if(!o.sent()||!e&&\"undefined\"==typeof location)return[2,\"\"];for(t=null!=e?e:location.hostname,n=t.split(\".\"),i=[],r=\"AMP_TLDTEST\",s=n.length-2;s>=0;--s)i.push(n.slice(s).join(\".\"));s=0,o.label=2;case 2:return s<i.length?(u=i[s],[4,(a=new ue({domain:\".\"+u})).set(r,1)]):[3,7];case 3:return o.sent(),[4,a.get(r)];case 4:return o.sent()?[4,a.remove(r)]:[3,6];case 5:return o.sent(),[2,\".\"+u];case 6:return s++,[3,2];case 7:return[2,\"\"]}}))}))},Xe=function(e){var t=e.split(\".\");return t.length<=2?e:t.slice(t.length-2,t.length).join(\".\")},et=function(e,t){return void 0===e&&(e=[]),void 0===t&&(t=\"\"),e.some((function(e){return e instanceof RegExp?e.test(t):e===t}))},tt=function(e){var t=this;void 0===e&&(e={});var s={name:\"@amplitude/plugin-web-attribution-browser\",type:\"before\",setup:function(t,s){var a;return r(this,void 0,void 0,(function(){var r,c,l,d,f,p,v;return o(this,(function(o){switch(o.label){case 0:return r=n({initialEmptyValue:\"EMPTY\",resetSessionOnNewCampaign:!1,excludeReferrers:(m=null===(a=t.cookieOptions)||void 0===a?void 0:a.domain,b=m,b?(b.startsWith(\".\")&&(b=b.substring(1)),[new RegExp(\"\".concat(b.replace(\".\",\"\\\\.\"),\"$\"))]):[])},e),t.loggerProvider.log(\"Installing @amplitude/plugin-web-attribution-browser.\"),c=t.cookieStorage,h=t.apiKey,void 0===(g=\"MKTG\")&&(g=\"\"),void 0===y&&(y=10),l=[q,g,h.substring(0,y)].filter(Boolean).join(\"_\"),[4,Promise.all([(new U).parse(),c.get(l)])];case 1:return d=u.apply(void 0,[o.sent(),2]),f=d[0],p=d[1],function(e,t,n){e.referrer;var r=e.referring_domain,o=i(e,[\"referrer\",\"referring_domain\"]),s=t||{};s.referrer;var u=s.referring_domain,a=i(s,[\"referrer\",\"referring_domain\"]);if(et(n.excludeReferrers,e.referring_domain))return!1;var c=JSON.stringify(o)!==JSON.stringify(a),l=Xe(r||\"\")!==Xe(u||\"\");return!t||c||l}(f,p,r)&&(r.resetSessionOnNewCampaign&&(s.setSessionId(Date.now()),t.loggerProvider.log(\"Created a new session for new campaign.\")),t.loggerProvider.log(\"Tracking attribution.\"),v=function(e,t){var i=n(n({},R),e),r=Object.entries(i).reduce((function(e,n){var i,r=u(n,2),o=r[0],s=r[1];return e.setOnce(\"initial_\".concat(o),null!==(i=null!=s?s:t.initialEmptyValue)&&void 0!==i?i:\"EMPTY\"),s?e.set(o,s):e.unset(o)}),new j);return C(r)}(f,r),s.track(v),c.set(l,f)),[2]}var h,g,y,m,b}))}))},execute:function(e){return r(t,void 0,void 0,(function(){return o(this,(function(t){return[2,e]}))}))}};return s},nt=function(e){var t={};for(var n in e){var i=e[n];i&&(t[n]=i)}return t},it=function(e){var t;void 0===e&&(e={});var i=h(),s=void 0,a=function(){return r(void 0,void 0,void 0,(function(){var t,i,r;return o(this,(function(o){switch(o.label){case 0:return i={event_type:null!==(r=e.eventType)&&void 0!==r?r:\"[Amplitude] Page Viewed\"},t=[{}],[4,rt()];case 1:return[2,(i.event_properties=n.apply(void 0,[n.apply(void 0,t.concat([o.sent()])),{\"[Amplitude] Page Domain\":\"undefined\"!=typeof location&&location.hostname||\"\",\"[Amplitude] Page Location\":\"undefined\"!=typeof location&&location.href||\"\",\"[Amplitude] Page Path\":\"undefined\"!=typeof location&&location.pathname||\"\",\"[Amplitude] Page Title\":\"undefined\"!=typeof document&&document.title||\"\",\"[Amplitude] Page URL\":\"undefined\"!=typeof location&&location.href.split(\"?\")[0]||\"\"}]),i)]}}))}))},c=function(){return void 0===e.trackOn||\"function\"==typeof e.trackOn&&e.trackOn()},l=\"undefined\"!=typeof location?location.href:null,d=function(){return r(void 0,void 0,void 0,(function(){var n,i,r;return o(this,(function(o){switch(o.label){case 0:return n=location.href,st(e.trackHistoryChanges,n,l||\"\")&&c()?(null==s||s.log(\"Tracking page view event\"),null!=t?[3,1]:[3,3]):[3,4];case 1:return r=(i=t).track,[4,a()];case 2:r.apply(i,[o.sent()]),o.label=3;case 3:o.label=4;case 4:return l=n,[2]}}))}))},f={name:\"@amplitude/plugin-page-view-tracking-browser\",type:\"enrichment\",setup:function(e,n){return r(void 0,void 0,void 0,(function(){var r,l;return o(this,(function(o){switch(o.label){case 0:return t=n,(s=e.loggerProvider).log(\"Installing @amplitude/plugin-page-view-tracking-browser\"),i&&(i.addEventListener(\"popstate\",(function(){d()})),i.history.pushState=new Proxy(i.history.pushState,{apply:function(e,t,n){var i=u(n,3),r=i[0],o=i[1],s=i[2];e.apply(t,[r,o,s]),d()}})),c()?(s.log(\"Tracking page view event\"),l=(r=t).track,[4,a()]):[3,2];case 1:l.apply(r,[o.sent()]),o.label=2;case 2:return[2]}}))}))},execute:function(t){return r(void 0,void 0,void 0,(function(){var i;return o(this,(function(r){switch(r.label){case 0:return\"attribution\"===e.trackOn&&ot(t)?(null==s||s.log(\"Enriching campaign event to page view event with campaign parameters\"),[4,a()]):[3,2];case 1:i=r.sent(),t.event_type=i.event_type,t.event_properties=n(n({},t.event_properties),i.event_properties),r.label=2;case 2:return[2,t]}}))}))}};return f},rt=function(){return r(void 0,void 0,void 0,(function(){var e;return o(this,(function(t){switch(t.label){case 0:return e=nt,[4,(new U).parse()];case 1:return[2,e.apply(void 0,[t.sent()])]}}))}))},ot=function(e){if(\"$identify\"===e.event_type&&e.user_properties){var t=e.user_properties,n=t[c.SET]||{},i=t[c.UNSET]||{},r=a(a([],u(Object.keys(n)),!1),u(Object.keys(i)),!1);return Object.keys(R).every((function(e){return r.includes(e)}))}return!1},st=function(e,t,n){return\"pathOnly\"===e?t.split(\"?\")[0]!==n.split(\"?\")[0]:t!==n},ut=function(){var e,t;return{name:\"@amplitude/plugin-session-handler\",type:\"before\",setup:function(n,i){return r(void 0,void 0,void 0,(function(){return o(this,(function(r){return e=n,t=i,[2]}))}))},execute:function(n){return r(void 0,void 0,void 0,(function(){var i,r;return o(this,(function(o){return i=Date.now(),n.event_type===je||n.event_type===Ce?(e.lastEventTime=i,[2,n]):(r=e.lastEventTime||i,i-r>e.sessionTimeout&&(t.setSessionId(i),n.session_id=t.getSessionId(),n.time=i),e.lastEventTime=i,[2,n])}))}))}}},at=function(e){function i(){return null!==e&&e.apply(this,arguments)||this}return t(i,e),i.prototype.init=function(e,t,i){var r,o;return void 0===e&&(e=\"\"),arguments.length>2?(r=t,o=i):\"string\"==typeof t?(r=t,o=void 0):(r=null==t?void 0:t.userId,o=t),$(this._init(n(n({},o),{userId:r,apiKey:e})))},i.prototype._init=function(t){return r(this,void 0,void 0,(function(){var i,s,u,a,c=this;return o(this,(function(l){switch(l.label){case 0:return this.initializing?[2]:(this.initializing=!0,[4,Ze(t.apiKey,t,this)]);case 1:return i=l.sent(),[4,e.prototype._init.call(this,i)];case 2:return l.sent(),(!this.config.sessionId||this.config.lastEventTime&&Date.now()-this.config.lastEventTime>this.config.sessionTimeout)&&this.setSessionId(Date.now()),(s=ye()).identityStore.setIdentity({userId:this.config.userId,deviceId:this.config.deviceId}),[4,this.add(new H).promise];case 3:return l.sent(),[4,this.add(new Oe).promise];case 4:return l.sent(),[4,this.add(ut()).promise];case 5:return l.sent(),[4,this.add(new me).promise];case 6:return l.sent(),f=this.config.defaultTracking,Ie(f,\"fileDownloads\")?[4,this.add({name:\"@amplitude/plugin-file-download-tracking-browser\",type:\"enrichment\",setup:function(e,t){return r(void 0,void 0,void 0,(function(){var n,i;return o(this,(function(r){return t?(n=function(e){var n;try{n=new URL(e.href,window.location.href)}catch(e){return}var r=i.exec(n.href),o=null==r?void 0:r[1];o&&e.addEventListener(\"click\",(function(){var i;o&&t.track(Ne,((i={})[Me]=o,i[Ve]=n.pathname,i[Fe]=e.id,i[Qe]=e.text,i[$e]=e.href,i))}))},i=/\\.(pdf|xlsx?|docx?|txt|rtf|csv|exe|key|pp(s|t|tx)|7z|pkg|rar|gz|zip|avi|mov|mp4|mpe?g|wmv|midi?|mp3|wav|wma)$/,Array.from(document.getElementsByTagName(\"a\")).forEach(n),\"undefined\"!=typeof MutationObserver&&new MutationObserver((function(e){e.forEach((function(e){e.addedNodes.forEach((function(e){\"A\"===e.nodeName&&n(e),\"querySelectorAll\"in e&&\"function\"==typeof e.querySelectorAll&&Array.from(e.querySelectorAll(\"a\")).map(n)}))}))})).observe(document.body,{subtree:!0,childList:!0}),[2]):(e.loggerProvider.warn(\"File download tracking requires a later version of @amplitude/analytics-browser. File download events are not tracked.\"),[2])}))}))},execute:function(e){return r(void 0,void 0,void 0,(function(){return o(this,(function(t){return[2,e]}))}))}}).promise]:[3,8];case 7:l.sent(),l.label=8;case 8:return function(e){return Ie(e,\"formInteractions\")}(this.config.defaultTracking)?[4,this.add({name:\"@amplitude/plugin-form-interaction-tracking-browser\",type:\"enrichment\",setup:function(e,t){return r(void 0,void 0,void 0,(function(){var n;return o(this,(function(i){return t?(n=function(e){var n=!1;e.addEventListener(\"change\",(function(){var i;n||t.track(Le,((i={})[Ke]=e.id,i[Be]=e.name,i[ze]=e.action,i)),n=!0}),{}),e.addEventListener(\"submit\",(function(){var i,r;n||t.track(Le,((i={})[Ke]=e.id,i[Be]=e.name,i[ze]=e.action,i)),t.track(Ae,((r={})[Ke]=e.id,r[Be]=e.name,r[ze]=e.action,r)),n=!1}))},Array.from(document.getElementsByTagName(\"form\")).forEach(n),\"undefined\"!=typeof MutationObserver&&new MutationObserver((function(e){e.forEach((function(e){e.addedNodes.forEach((function(e){\"FORM\"===e.nodeName&&n(e),\"querySelectorAll\"in e&&\"function\"==typeof e.querySelectorAll&&Array.from(e.querySelectorAll(\"form\")).map(n)}))}))})).observe(document.body,{subtree:!0,childList:!0}),[2]):(e.loggerProvider.warn(\"Form interaction tracking requires a later version of @amplitude/analytics-browser. Form interaction events are not tracked.\"),[2])}))}))},execute:function(e){return r(void 0,void 0,void 0,(function(){return o(this,(function(t){return[2,e]}))}))}}).promise]:[3,10];case 9:l.sent(),l.label=10;case 10:return _e(this.config.defaultTracking)?(d=this.config,u=_e(d.defaultTracking)&&d.defaultTracking&&\"object\"==typeof d.defaultTracking&&d.defaultTracking.attribution&&\"object\"==typeof d.defaultTracking.attribution?n({},d.defaultTracking.attribution):{},a=tt(u),[4,this.add(a).promise]):[3,12];case 11:l.sent(),l.label=12;case 12:return[4,this.add(it(we(this.config))).promise];case 13:return l.sent(),this.initializing=!1,[4,this.runQueuedFunctions(\"dispatchQ\")];case 14:return l.sent(),s.eventBridge.setEventReceiver((function(e){c.track(e.eventType,e.eventProperties)})),[2]}var d,f}))}))},i.prototype.getUserId=function(){var e;return null===(e=this.config)||void 0===e?void 0:e.userId},i.prototype.setUserId=function(e){this.config?e===this.config.userId&&void 0!==e||(this.config.userId=e,this.setSessionId(Date.now()),function(e){ye().identityStore.editIdentity().setUserId(e).commit()}(e)):this.q.push(this.setUserId.bind(this,e))},i.prototype.getDeviceId=function(){var e;return null===(e=this.config)||void 0===e?void 0:e.deviceId},i.prototype.setDeviceId=function(e){this.config?(this.config.deviceId=e,function(e){ye().identityStore.editIdentity().setDeviceId(e).commit()}(e)):this.q.push(this.setDeviceId.bind(this,e))},i.prototype.reset=function(){this.setDeviceId(V()),this.setUserId(void 0)},i.prototype.getSessionId=function(){var e;return null===(e=this.config)||void 0===e?void 0:e.sessionId},i.prototype.setSessionId=function(e){if(this.config){var t,n=this.getSessionId(),i=this.config.lastEventTime;if(this.config.sessionId=e,this.config.lastEventTime=void 0,t=this.config.defaultTracking,Ie(t,\"sessions\")){if(n&&i){var r={session_id:n,time:i+1};r.device_id=this.previousSessionDeviceId,r.user_id=this.previousSessionUserId,this.track(Ce,void 0,r)}this.track(je,void 0,{session_id:e,time:e-1}),this.previousSessionDeviceId=this.config.deviceId,this.previousSessionUserId=this.config.userId}}else this.q.push(this.setSessionId.bind(this,e))},i.prototype.setTransport=function(e){this.config?this.config.transportProvider=Ye(e):this.q.push(this.setTransport.bind(this,e))},i.prototype.identify=function(t,n){if(Te(t)){var i=t._q;t._q=[],t=Ee(new j,i)}return(null==n?void 0:n.user_id)&&this.setUserId(n.user_id),(null==n?void 0:n.device_id)&&this.setDeviceId(n.device_id),e.prototype.identify.call(this,t,n)},i.prototype.groupIdentify=function(t,n,i,r){if(Te(i)){var o=i._q;i._q=[],i=Ee(new j,o)}return e.prototype.groupIdentify.call(this,t,n,i,r)},i.prototype.revenue=function(t,n){if(Te(t)){var i=t._q;t._q=[],t=Ee(new B,i)}return e.prototype.revenue.call(this,t,n)},i}(K),ct=function(){var e=new at;return{init:ie(e.init.bind(e),\"init\",ee(e),ne(e,[\"config\"])),add:ie(e.add.bind(e),\"add\",ee(e),ne(e,[\"config.apiKey\",\"timeline.plugins\"])),remove:ie(e.remove.bind(e),\"remove\",ee(e),ne(e,[\"config.apiKey\",\"timeline.plugins\"])),track:ie(e.track.bind(e),\"track\",ee(e),ne(e,[\"config.apiKey\",\"timeline.queue.length\"])),logEvent:ie(e.logEvent.bind(e),\"logEvent\",ee(e),ne(e,[\"config.apiKey\",\"timeline.queue.length\"])),identify:ie(e.identify.bind(e),\"identify\",ee(e),ne(e,[\"config.apiKey\",\"timeline.queue.length\"])),groupIdentify:ie(e.groupIdentify.bind(e),\"groupIdentify\",ee(e),ne(e,[\"config.apiKey\",\"timeline.queue.length\"])),setGroup:ie(e.setGroup.bind(e),\"setGroup\",ee(e),ne(e,[\"config.apiKey\",\"timeline.queue.length\"])),revenue:ie(e.revenue.bind(e),\"revenue\",ee(e),ne(e,[\"config.apiKey\",\"timeline.queue.length\"])),flush:ie(e.flush.bind(e),\"flush\",ee(e),ne(e,[\"config.apiKey\",\"timeline.queue.length\"])),getUserId:ie(e.getUserId.bind(e),\"getUserId\",ee(e),ne(e,[\"config\",\"config.userId\"])),setUserId:ie(e.setUserId.bind(e),\"setUserId\",ee(e),ne(e,[\"config\",\"config.userId\"])),getDeviceId:ie(e.getDeviceId.bind(e),\"getDeviceId\",ee(e),ne(e,[\"config\",\"config.deviceId\"])),setDeviceId:ie(e.setDeviceId.bind(e),\"setDeviceId\",ee(e),ne(e,[\"config\",\"config.deviceId\"])),reset:ie(e.reset.bind(e),\"reset\",ee(e),ne(e,[\"config\",\"config.userId\",\"config.deviceId\"])),getSessionId:ie(e.getSessionId.bind(e),\"getSessionId\",ee(e),ne(e,[\"config\"])),setSessionId:ie(e.setSessionId.bind(e),\"setSessionId\",ee(e),ne(e,[\"config\"])),setOptOut:ie(e.setOptOut.bind(e),\"setOptOut\",ee(e),ne(e,[\"config\"])),setTransport:ie(e.setTransport.bind(e),\"setTransport\",ee(e),ne(e,[\"config\"]))}},lt=ct(),dt=lt.add,ft=lt.flush,pt=lt.getDeviceId,vt=lt.getSessionId,ht=lt.getUserId,gt=lt.groupIdentify,yt=lt.identify,mt=lt.init,bt=lt.logEvent,It=lt.remove,_t=lt.reset,wt=lt.revenue,St=lt.setDeviceId,Et=lt.setGroup,Tt=lt.setOptOut,Ot=lt.setSessionId,kt=lt.setTransport,Pt=lt.setUserId,Rt=lt.track,Ut=Object.freeze({__proto__:null,add:dt,flush:ft,getDeviceId:pt,getSessionId:vt,getUserId:ht,groupIdentify:gt,identify:yt,init:mt,logEvent:bt,remove:It,reset:_t,revenue:wt,setDeviceId:St,setGroup:Et,setOptOut:Tt,setSessionId:Ot,setTransport:kt,setUserId:Pt,track:Rt,Types:x,createInstance:ct,runQueuedFunctions:Se,Revenue:B,Identify:j});!function(){var e=h();if(e){var t=function(e){var t=ct(),n=h();return n&&n.amplitude&&n.amplitude._iq&&e&&(n.amplitude._iq[e]=t),t};if(e.amplitude=Object.assign(e.amplitude||{},Ut,{createInstance:t}),e.amplitude.invoked){var n=e.amplitude._q;e.amplitude._q=[],Se(Ut,n);for(var i=Object.keys(e.amplitude._iq)||[],r=0;r<i.length;r++){var o=i[r],s=Object.assign(e.amplitude._iq[o],t(o)),u=s._q;s._q=[],Se(s,u)}}}else console.error(\"[Amplitude] Error: GlobalScope is not defined\")}()}();\n"
  },
  {
    "path": "examples/browser/chrome-ext/background.js",
    "content": "/**\n * Amplitude using importScripts(). Create a copy of amplitude-min.js as part of your project and use the file path.\n */\nimportScripts('/amplitude-min.js');\n\n/**\n * Start by calling amplitude.init(). This must be done before any event tracking\n * preferrably in the root file of the project.\n *\n * Calling init() requires an API key\n * ```\n * amplitude.init(API_KEY)\n * ```\n *\n * Optionally, a user id can be provided when calling init()\n * ```\n * amplitude.init(API_KEY, 'example.extension.user@amplitude.com')\n * ```\n *\n * Optionally, a config object can be provided. Refer to https://amplitude.github.io/Amplitude-TypeScript/interfaces/Types.BrowserConfig.html\n * for object properties.\n */\namplitude.init('API_KEY', 'example.extension.user@amplitude.com');\n\nchrome.omnibox.onInputEntered.addListener((text) => {\n  amplitude.track('Input Entered', { value: text });\n  var newURL = 'https://www.google.com/search?q=' + encodeURIComponent(text);\n  chrome.tabs.update({ url: newURL });\n});\n\nchrome.omnibox.onDeleteSuggestion.addListener((text) => {\n  amplitude.track('Delete Suggestion', { value: text });\n});\n\nchrome.omnibox.onInputCancelled.addListener((text) => {\n  amplitude.track('Input Cancelled', { value: text });\n});\n\nchrome.omnibox.onInputChanged.addListener((text) => {\n  amplitude.track('Input Changed', { value: text });\n});\n\nchrome.omnibox.onInputStarted.addListener((text) => {\n  amplitude.track('Input Started', { value: text });\n});\n"
  },
  {
    "path": "examples/browser/chrome-ext/manifest.json",
    "content": "{\n  \"name\": \"Google Search Tracker\",\n  \"description\": \"Type 'g' plus a search term into the Omnibox to seach in google.com\",\n  \"version\": \"1.0\",\n  \"manifest_version\": 3,\n  \"background\": {\n    \"service_worker\": \"background.js\"\n  },\n  \"omnibox\": {\n    \"keyword\": \"g\"\n  }\n}\n"
  },
  {
    "path": "examples/browser/html-app/README.md",
    "content": "This is a demo project for instrumenting events using Amplitude Analytics SDK in an basic HTML page.\n\n## Getting Started\n\nFirst, run the development server:\n\n```bash\nnpm start\n# or\npnpm start\n```\n\nOpen [http://localhost:8080](http://localhost:8080) with your browser to see the result.\n"
  },
  {
    "path": "examples/browser/html-app/index.css",
    "content": "form {\n    /* Just to center the form on the page */\n    margin: 20px 0px;\n    width: 400px;\n  \n    /* To see the limits of the form */\n    padding: 1em;\n    border: 1px solid #ccc;\n    border-radius: 1em;\n  }\n  \n  div + div {\n    margin-top: 1em;\n  }\n  \n  label {\n    /* To make sure that all label have the same size and are properly align */\n    display: inline-block;\n    width: 90px;\n    text-align: right;\n  }\n  \n  input,\n  textarea {\n    /* To make sure that all text field have the same font settings\n       By default, textarea are set with a monospace font */\n    font: 1em sans-serif;\n  \n    /* To give the same size to all text field */\n    width: 300px;\n  \n    -moz-box-sizing: border-box;\n    box-sizing: border-box;\n  \n    /* To harmonize the look & feel of text field border */\n    border: 1px solid #999;\n  }\n  \n  input:focus,\n  textarea:focus {\n    /* To give a little highlight on active elements */\n    border-color: #000;\n  }\n  \n  textarea {\n    /* To properly align multiline text field with their label */\n    vertical-align: top;\n  \n    /* To give enough room to type some text */\n    height: 5em;\n  \n    /* To allow users to resize any textarea vertically\n       It works only on Chrome, Firefox and Safari */\n    resize: vertical;\n  }\n  \n  .button {\n    /* To position the buttons to the same position of the text fields */\n    padding-left: 90px; /* same size as the label elements */\n  }\n  \n  button {\n    /* This extra margin represent the same space as the space between\n       the labels and their text fields */\n    margin-left: 0.5em;\n  }\n  "
  },
  {
    "path": "examples/browser/html-app/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n    <title>HTML 5 Boilerplate</title>\n    <link rel=\"stylesheet\" href=\"index.css\">\n  </head>\n\t<script>\n    /**\n     * Install Amplitude using script loader. Refer to: https://github.com/amplitude/Amplitude-TypeScript/tree/main/packages/analytics-browser#using-script-loader.\n     */\n     !function(){\"use strict\";!function(e,t){var n=e.amplitude||{_q:[],_iq:{}};if(n.invoked)e.console&&console.error&&console.error(\"Amplitude snippet has been loaded.\");else{var r=function(e,t){e.prototype[t]=function(){return this._q.push({name:t,args:Array.prototype.slice.call(arguments,0)}),this}},s=function(e,t,n){return function(r){e._q.push({name:t,args:Array.prototype.slice.call(n,0),resolve:r})}},o=function(e,t,n){e[t]=function(){if(n)return{promise:new Promise(s(e,t,Array.prototype.slice.call(arguments)))}}},i=function(e){for(var t=0;t<m.length;t++)o(e,m[t],!1);for(var n=0;n<y.length;n++)o(e,y[n],!0)};n.invoked=!0;var a=t.createElement(\"script\");a.type=\"text/javascript\",a.integrity=\"sha384-lI19/rkWkq7akQskdqbaYBssAwNImFV9Iwejq7dylnP0Yx8TyWYX1PwAoaA5xrUp\",a.crossOrigin=\"anonymous\",a.async=!0,a.src=\"https://cdn.amplitude.com/libs/analytics-browser-2.1.3-min.js.gz\",a.onload=function(){e.amplitude.runQueuedFunctions||console.log(\"[Amplitude] Error: could not load SDK\")};var c=t.getElementsByTagName(\"script\")[0];c.parentNode.insertBefore(a,c);for(var u=function(){return this._q=[],this},l=[\"add\",\"append\",\"clearAll\",\"prepend\",\"set\",\"setOnce\",\"unset\",\"preInsert\",\"postInsert\",\"remove\",\"getUserProperties\"],p=0;p<l.length;p++)r(u,l[p]);n.Identify=u;for(var d=function(){return this._q=[],this},f=[\"getEventProperties\",\"setProductId\",\"setQuantity\",\"setPrice\",\"setRevenue\",\"setRevenueType\",\"setEventProperties\"],v=0;v<f.length;v++)r(d,f[v]);n.Revenue=d;var m=[\"getDeviceId\",\"setDeviceId\",\"getSessionId\",\"setSessionId\",\"getUserId\",\"setUserId\",\"setOptOut\",\"setTransport\",\"reset\",\"extendSession\"],y=[\"init\",\"add\",\"remove\",\"track\",\"logEvent\",\"identify\",\"groupIdentify\",\"setGroup\",\"revenue\",\"flush\"];i(n),n.createInstance=function(e){return n._iq[e]={_q:[]},i(n._iq[e]),n._iq[e]},e.amplitude=n}}(window,document)}();\n     /**\n     * Start by calling amplitude.init(). This must be done before any event tracking\n     * preferrably in the root file of the project.\n     *\n     * Calling init() requires an API key\n     * ```\n     * amplitude.init(API_KEY)\n     * ```\n     *\n     * Optionally, a user id can be provided when calling init()\n     * ```\n     * amplitude.init(API_KEY, 'example.html.user@amplitude.com')\n     * ```\n     *\n     * Optionally, a config object can be provided. Refer to https://amplitude.github.io/Amplitude-TypeScript/interfaces/Types.BrowserConfig.html\n     * for object properties.\n     */\n    amplitude.init('API_KEY', 'example.html.user@amplitude.com');\n  </script>\n  <body>\n    <h2>Amplitude Analytics Browser Example with HTML</h2>\n\n    <button onclick=\"amplitude.identify(new amplitude.Identify().set('role', 'engineer'))\">\n      Identify\n    </button>\n\n    <button onclick=\"amplitude.setGroup('org', 'engineering')\">\n      Group\n    </button>\n\n    <button onclick=\"amplitude.groupIdentify('org', 'engineering', new amplitude.Identify().set('technology', 'react.js'))\">\n      Group Identify\n    </button>\n\n    <button onclick=\"amplitude.track('Button Click', { name: 'HTML' })\">\n      Track\n    </button>\n\n    <form action=\"/\" method=\"post\">\n      <div>\n        <label for=\"name\">Name:</label>\n        <input type=\"text\" id=\"name\" maxlength=\"95\" value=\"Name\">\n      </div>\n    \n      <div>\n        <label for=\"mail\">Email:</label>\n        <input type=\"email\" id=\"mail\" name=\"user_email\" />\n      </div>\n    \n      <div>\n        <label for=\"msg\">Message:</label>\n        <textarea id=\"msg\" name=\"user_message\"></textarea>\n      </div>\n    \n      <div class=\"button\">\n        <button type=\"submit\">Send your message</button>\n      </div>\n    </form>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/browser/html-app/package.json",
    "content": "{\n  \"name\": \"html-app\",\n  \"version\": \"1.0.0\",\n  \"scripts\": {\n    \"start\": \"npx http-server\"\n  }\n}\n"
  },
  {
    "path": "examples/browser/next-app/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.js\n\n# testing\n/coverage\n\n# next.js\n/.next/\n/out/\n\n# production\n/build\n\n# misc\n.DS_Store\n*.pem\n\n# debug\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n.pnpm-debug.log*\n\n# local env files\n.env*.local\n\n# vercel\n.vercel\n\n# typescript\n*.tsbuildinfo\n"
  },
  {
    "path": "examples/browser/next-app/README.md",
    "content": "This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).\n\n## Getting Started\n\nFirst, run the development server:\n\n```bash\nnpm run dev\n# or\npnpm dev\n```\n\nOpen [http://localhost:3000](http://localhost:3000) with your browser to see the result.\n\nYou can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.\n\n[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.\n\nThe `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.\n\n## Learn More\n\nTo learn more about Next.js, take a look at the following resources:\n\n- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.\n- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.\n\nYou can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!\n\n## Deploy on Vercel\n\nThe easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.\n\nCheck out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.\n"
  },
  {
    "path": "examples/browser/next-app/eslint.config.mjs",
    "content": "import nextVitals from \"eslint-config-next/core-web-vitals\";\nimport nextTs from \"eslint-config-next/typescript\";\n\nconst eslintConfig = [\n  ...nextVitals,\n  ...nextTs,\n  {\n    ignores: [\".next/**\", \"out/**\", \"build/**\", \"next-env.d.ts\"],\n  },\n];\n\nexport default eslintConfig;\n"
  },
  {
    "path": "examples/browser/next-app/next.config.js",
    "content": "/** @type {import('next').NextConfig} */\nconst nextConfig = {\n  reactStrictMode: true,\n}\n\nmodule.exports = nextConfig\n"
  },
  {
    "path": "examples/browser/next-app/package.json",
    "content": "{\n  \"name\": \"next-app\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"next dev\",\n    \"build\": \"next build\",\n    \"start\": \"next start\",\n    \"lint\": \"eslint .\"\n  },\n  \"dependencies\": {\n    \"@amplitude/analytics-browser\": \"^2.0.0-beta\",\n    \"next\": \"16.1.5\",\n    \"react\": \"18.2.0\",\n    \"react-dom\": \"18.2.0\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"18.11.14\",\n    \"@types/react\": \"18.0.26\",\n    \"@types/react-dom\": \"18.0.9\",\n    \"eslint\": \"9.7.0\",\n    \"eslint-config-next\": \"16.1.5\",\n    \"typescript\": \"5.0.2\"\n  }\n}\n"
  },
  {
    "path": "examples/browser/next-app/pages/_app.tsx",
    "content": "import '../styles/globals.css'\nimport type { AppProps } from 'next/app'\nimport * as amplitude from '@amplitude/analytics-browser';\n\n/**\n * Start by calling amplitude.init(). This must be done before any event tracking\n * preferrably in the root file of the project.\n * \n * Calling init() requires an API key\n * ```\n * amplitude.init(API_KEY)\n * ```\n * \n * Optionally, a user id can be provided when calling init()\n * ```\n * amplitude.init(API_KEY, 'example.next.user@amplitude.com')\n * ```\n * \n * Optionally, a config object can be provided. Refer to https://amplitude.github.io/Amplitude-TypeScript/interfaces/Types.BrowserConfig.html\n * for object properties.\n */\namplitude.init('API_KEY', 'example.next.user@amplitude.com')\n\nfunction MyApp({ Component, pageProps }: AppProps) {\n  return <Component {...pageProps} />\n}\n\nexport default MyApp\n"
  },
  {
    "path": "examples/browser/next-app/pages/api/hello.ts",
    "content": "// Next.js API route support: https://nextjs.org/docs/api-routes/introduction\nimport type { NextApiRequest, NextApiResponse } from 'next';\n\ntype Data = {\n  name: string;\n};\n\nexport default function handler(req: NextApiRequest, res: NextApiResponse<Data>) {\n  res.status(200).json({ name: 'John Doe' });\n}\n"
  },
  {
    "path": "examples/browser/next-app/pages/index.tsx",
    "content": "import type { NextPage } from 'next'\nimport Head from 'next/head'\nimport styles from '../styles/Home.module.css'\nimport { identify, setGroup, groupIdentify, track, Identify } from '@amplitude/analytics-browser'\n\nconst Home: NextPage = () => {\n  return (\n    <div className={styles.container}>\n      <Head>\n        <title>Create Next App</title>\n        <meta name=\"description\" content=\"Generated by create next app\" />\n        <link rel=\"icon\" href=\"/favicon.ico\" />\n      </Head>\n\n      <main className={styles.main}>\n        <h1 className={styles.title}>\n          Amplitude Analytics Browser Example with Next\n        </h1>\n\n        <button onClick={() => identify(new Identify().set('role', 'engineer'))}>\n          Identify\n        </button>\n\n        <button onClick={() => setGroup('org', 'engineering')}>\n          Group\n        </button>\n\n        <button onClick={() => groupIdentify('org', 'engineering', new Identify().set('technology', 'react.js'))}>\n          Group Identify\n        </button>\n\n        <button onClick={() => track('Button Click', { name: 'App' })}>\n          Track\n        </button>\n      </main>\n    </div>\n  )\n}\n\nexport default Home\n"
  },
  {
    "path": "examples/browser/next-app/styles/Home.module.css",
    "content": ".container {\n  padding: 0 2rem;\n}\n\n.main {\n  min-height: 100vh;\n  padding: 4rem 0;\n  flex: 1;\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  align-items: center;\n}\n\n.footer {\n  display: flex;\n  flex: 1;\n  padding: 2rem 0;\n  border-top: 1px solid #eaeaea;\n  justify-content: center;\n  align-items: center;\n}\n\n.footer a {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  flex-grow: 1;\n}\n\n.title a {\n  color: #0070f3;\n  text-decoration: none;\n}\n\n.title a:hover,\n.title a:focus,\n.title a:active {\n  text-decoration: underline;\n}\n\n.title {\n  margin: 0;\n  line-height: 1.15;\n  font-size: 4rem;\n}\n\n.title,\n.description {\n  text-align: center;\n}\n\n.description {\n  margin: 4rem 0;\n  line-height: 1.5;\n  font-size: 1.5rem;\n}\n\n.code {\n  background: #fafafa;\n  border-radius: 5px;\n  padding: 0.75rem;\n  font-size: 1.1rem;\n  font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,\n    Bitstream Vera Sans Mono, Courier New, monospace;\n}\n\n.grid {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  flex-wrap: wrap;\n  max-width: 800px;\n}\n\n.card {\n  margin: 1rem;\n  padding: 1.5rem;\n  text-align: left;\n  color: inherit;\n  text-decoration: none;\n  border: 1px solid #eaeaea;\n  border-radius: 10px;\n  transition: color 0.15s ease, border-color 0.15s ease;\n  max-width: 300px;\n}\n\n.card:hover,\n.card:focus,\n.card:active {\n  color: #0070f3;\n  border-color: #0070f3;\n}\n\n.card h2 {\n  margin: 0 0 1rem 0;\n  font-size: 1.5rem;\n}\n\n.card p {\n  margin: 0;\n  font-size: 1.25rem;\n  line-height: 1.5;\n}\n\n.logo {\n  height: 1em;\n  margin-left: 0.5rem;\n}\n\n@media (max-width: 600px) {\n  .grid {\n    width: 100%;\n    flex-direction: column;\n  }\n}\n"
  },
  {
    "path": "examples/browser/next-app/styles/globals.css",
    "content": "html,\nbody {\n  padding: 0;\n  margin: 0;\n  font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,\n    Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;\n}\n\na {\n  color: inherit;\n  text-decoration: none;\n}\n\n* {\n  box-sizing: border-box;\n}\n"
  },
  {
    "path": "examples/browser/next-app/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es5\",\n    \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"strict\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"noEmit\": true,\n    \"esModuleInterop\": true,\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"jsx\": \"preserve\",\n    \"incremental\": true\n  },\n  \"include\": [\"next-env.d.ts\", \"**/*.ts\", \"**/*.tsx\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "examples/browser/react-app/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.js\n\n# testing\n/coverage\n\n# production\n/build\n\n# misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n"
  },
  {
    "path": "examples/browser/react-app/README.md",
    "content": "# Getting Started with Create React App\n\nThis project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).\n\n## Available Scripts\n\nIn the project directory, you can run:\n\n### `pnpm start`\n\nRuns the app in the development mode.\\\nOpen [http://localhost:3000](http://localhost:3000) to view it in the browser.\n\nThe page will reload if you make edits.\\\nYou will also see any lint errors in the console.\n\n### `pnpm test`\n\nLaunches the test runner in the interactive watch mode.\\\nSee the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.\n\n### `pnpm run build`\n\nBuilds the app for production to the `build` folder.\\\nIt correctly bundles React in production mode and optimizes the build for the best performance.\n\nThe build is minified and the filenames include the hashes.\\\nYour app is ready to be deployed!\n\nSee the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.\n\n### `pnpm run eject`\n\n**Note: this is a one-way operation. Once you `eject`, you can’t go back!**\n\nIf you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.\n\nInstead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.\n\nYou don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.\n\n## Learn More\n\nYou can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).\n\nTo learn React, check out the [React documentation](https://reactjs.org/).\n"
  },
  {
    "path": "examples/browser/react-app/package.json",
    "content": "{\n  \"name\": \"react-app\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"dependencies\": {\n    \"@amplitude/analytics-browser\": \"^2.0.0-beta\",\n    \"@testing-library/jest-dom\": \"^5.16.5\",\n    \"@testing-library/react\": \"^13.4.0\",\n    \"@testing-library/user-event\": \"^14.4.3\",\n    \"@types/jest\": \"^29.2.4\",\n    \"@types/node\": \"^18.11.14\",\n    \"@types/react\": \"^18.0.26\",\n    \"@types/react-dom\": \"^18.0.9\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"react-scripts\": \"5.0.1\",\n    \"typescript\": \"^4.6.3\",\n    \"web-vitals\": \"^3.1.0\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"test\": \"react-scripts test\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"eslintConfig\": {\n    \"extends\": [\n      \"react-app\",\n      \"react-app/jest\"\n    ]\n  },\n  \"browserslist\": {\n    \"production\": [\n      \">0.2%\",\n      \"not dead\",\n      \"not op_mini all\"\n    ],\n    \"development\": [\n      \"last 1 chrome version\",\n      \"last 1 firefox version\",\n      \"last 1 safari version\"\n    ]\n  }\n}\n"
  },
  {
    "path": "examples/browser/react-app/public/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <link rel=\"icon\" href=\"%PUBLIC_URL%/favicon.ico\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <meta name=\"theme-color\" content=\"#000000\" />\n    <meta\n      name=\"description\"\n      content=\"Web site created using create-react-app\"\n    />\n    <link rel=\"apple-touch-icon\" href=\"%PUBLIC_URL%/logo192.png\" />\n    <!--\n      manifest.json provides metadata used when your web app is installed on a\n      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/\n    -->\n    <link rel=\"manifest\" href=\"%PUBLIC_URL%/manifest.json\" />\n    <!--\n      Notice the use of %PUBLIC_URL% in the tags above.\n      It will be replaced with the URL of the `public` folder during the build.\n      Only files inside the `public` folder can be referenced from the HTML.\n\n      Unlike \"/favicon.ico\" or \"favicon.ico\", \"%PUBLIC_URL%/favicon.ico\" will\n      work correctly both with client-side routing and a non-root public URL.\n      Learn how to configure a non-root public URL by running `npm run build`.\n    -->\n    <title>React App</title>\n  </head>\n  <body>\n    <noscript>You need to enable JavaScript to run this app.</noscript>\n    <div id=\"root\"></div>\n    <!--\n      This HTML file is a template.\n      If you open it directly in the browser, you will see an empty page.\n\n      You can add webfonts, meta tags, or analytics to this file.\n      The build step will place the bundled scripts into the <body> tag.\n\n      To begin the development, run `npm start` or `yarn start`.\n      To create a production bundle, use `npm run build` or `yarn build`.\n    -->\n  </body>\n</html>\n"
  },
  {
    "path": "examples/browser/react-app/public/manifest.json",
    "content": "{\n  \"short_name\": \"React App\",\n  \"name\": \"Create React App Sample\",\n  \"icons\": [\n    {\n      \"src\": \"favicon.ico\",\n      \"sizes\": \"64x64 32x32 24x24 16x16\",\n      \"type\": \"image/x-icon\"\n    },\n    {\n      \"src\": \"logo192.png\",\n      \"type\": \"image/png\",\n      \"sizes\": \"192x192\"\n    },\n    {\n      \"src\": \"logo512.png\",\n      \"type\": \"image/png\",\n      \"sizes\": \"512x512\"\n    }\n  ],\n  \"start_url\": \".\",\n  \"display\": \"standalone\",\n  \"theme_color\": \"#000000\",\n  \"background_color\": \"#ffffff\"\n}\n"
  },
  {
    "path": "examples/browser/react-app/public/robots.txt",
    "content": "# https://www.robotstxt.org/robotstxt.html\nUser-agent: *\nDisallow:\n"
  },
  {
    "path": "examples/browser/react-app/src/App.css",
    "content": ".App {\n  text-align: center;\n}\n\n.App-logo {\n  height: 40vmin;\n  pointer-events: none;\n}\n\n@media (prefers-reduced-motion: no-preference) {\n  .App-logo {\n    animation: App-logo-spin infinite 20s linear;\n  }\n}\n\n.App-header {\n  background-color: #282c34;\n  min-height: 100vh;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n  font-size: calc(10px + 2vmin);\n  color: white;\n}\n\n.App-link {\n  color: #61dafb;\n}\n\n@keyframes App-logo-spin {\n  from {\n    transform: rotate(0deg);\n  }\n  to {\n    transform: rotate(360deg);\n  }\n}\n"
  },
  {
    "path": "examples/browser/react-app/src/App.test.tsx",
    "content": "import React from 'react';\nimport { render, screen } from '@testing-library/react';\nimport App from './App';\n\ntest('renders learn react link', () => {\n  render(<App />);\n  const linkElement = screen.getByText(/learn react/i);\n  expect(linkElement).toBeInTheDocument();\n});\n"
  },
  {
    "path": "examples/browser/react-app/src/App.tsx",
    "content": "import React, { useEffect } from 'react';\nimport logo from './logo.svg';\nimport './App.css';\nimport { track, identify, setGroup, groupIdentify, Identify } from '@amplitude/analytics-browser';\n\nfunction App() {\n  useEffect(() => {\n    track('Page View', {\n      name: 'App',\n    });\n  }, []);\n\n  return (\n    <div className=\"App\">\n      <header className=\"App-header\">\n        <img src={logo} className=\"App-logo\" alt=\"logo\" />\n        <h2>Amplitude Analytics Browser Example with React</h2>\n\n        <button onClick={() => identify(new Identify().set('role', 'engineer'))}>\n          Identify\n        </button>\n\n        <button onClick={() => setGroup('org', 'engineering')}>\n          Group\n        </button>\n\n        <button onClick={() => groupIdentify('org', 'engineering', new Identify().set('technology', 'react.js'))}>\n          Group Identify\n        </button>\n\n        <button onClick={() => track('Button Click', { name: 'App' })}>\n          Track\n        </button>\n      </header>\n    </div>\n  );\n}\n\nexport default App;\n"
  },
  {
    "path": "examples/browser/react-app/src/index.css",
    "content": "body {\n  margin: 0;\n  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',\n    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',\n    sans-serif;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\ncode {\n  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',\n    monospace;\n}\n"
  },
  {
    "path": "examples/browser/react-app/src/index.tsx",
    "content": "import React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport './index.css';\nimport App from './App';\nimport reportWebVitals from './reportWebVitals';\nimport * as amplitude from '@amplitude/analytics-browser';\n\n/**\n * Start by calling amplitude.init(). This must be done before any event tracking\n * preferrably in the root file of the project.\n * \n * Calling init() requires an API key\n * ```\n * amplitude.init(API_KEY)\n * ```\n * \n * Optionally, a user id can be provided when calling init()\n * ```\n * amplitude.init(API_KEY, 'example.react.user@amplitude.com')\n * ```\n * \n * Optionally, a config object can be provided. Refer to https://amplitude.github.io/Amplitude-TypeScript/interfaces/Types.BrowserConfig.html\n * for object properties.\n */\namplitude.init('API_KEY', 'example.react.user@amplitude.com');\n\nconst root = ReactDOM.createRoot(\n  document.getElementById('root') as HTMLElement\n);\nroot.render(\n  <React.StrictMode>\n    <App />\n  </React.StrictMode>\n);\n\n// If you want to start measuring performance in your app, pass a function\n// to log results (for example: reportWebVitals(console.log))\n// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals\nreportWebVitals();\n"
  },
  {
    "path": "examples/browser/react-app/src/reportWebVitals.ts",
    "content": "import { ReportHandler } from 'web-vitals';\n\nconst reportWebVitals = (onPerfEntry?: ReportHandler) => {\n  if (onPerfEntry && onPerfEntry instanceof Function) {\n    import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {\n      getCLS(onPerfEntry);\n      getFID(onPerfEntry);\n      getFCP(onPerfEntry);\n      getLCP(onPerfEntry);\n      getTTFB(onPerfEntry);\n    });\n  }\n};\n\nexport default reportWebVitals;\n"
  },
  {
    "path": "examples/browser/react-app/src/setupTests.ts",
    "content": "// jest-dom adds custom jest matchers for asserting on DOM nodes.\n// allows you to do things like:\n// expect(element).toHaveTextContent(/react/i)\n// learn more: https://github.com/testing-library/jest-dom\nimport '@testing-library/jest-dom';\n"
  },
  {
    "path": "examples/browser/react-app/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es5\",\n    \"lib\": [\n      \"dom\",\n      \"dom.iterable\",\n      \"esnext\"\n    ],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"esModuleInterop\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"strict\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"noFallthroughCasesInSwitch\": true,\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"noEmit\": true,\n    \"jsx\": \"react-jsx\"\n  },\n  \"include\": [\n    \"src\"\n  ]\n}\n"
  },
  {
    "path": "examples/browser/vue-app/.browserslistrc",
    "content": "> 1%\nlast 2 versions\nnot dead\nnot ie 11\n"
  },
  {
    "path": "examples/browser/vue-app/.eslintrc.js",
    "content": "module.exports = {\n  root: true,\n  env: {\n    node: true\n  },\n  'extends': [\n    'plugin:vue/vue3-essential',\n    'eslint:recommended',\n    '@vue/typescript/recommended'\n  ],\n  parserOptions: {\n    ecmaVersion: 2020\n  },\n  rules: {\n    'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',\n    'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'\n  }\n}\n"
  },
  {
    "path": "examples/browser/vue-app/.gitignore",
    "content": ".DS_Store\nnode_modules\n/dist\n\n\n# local env files\n.env.local\n.env.*.local\n\n# Log files\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\n\n# Editor directories and files\n.idea\n.vscode\n*.suo\n*.ntvs*\n*.njsproj\n*.sln\n*.sw?\n"
  },
  {
    "path": "examples/browser/vue-app/README.md",
    "content": "# vue-app\n\n## Project setup\n```\npnpm install\n```\n\n### Compiles and hot-reloads for development\n```\npnpm serve\n```\n\n### Compiles and minifies for production\n```\npnpm build\n```\n\n### Lints and fixes files\n```\npnpm lint\n```\n\n### Customize configuration\nSee [Configuration Reference](https://cli.vuejs.org/config/).\n"
  },
  {
    "path": "examples/browser/vue-app/babel.config.js",
    "content": "module.exports = {\n  presets: [\n    '@vue/cli-plugin-babel/preset'\n  ]\n}\n"
  },
  {
    "path": "examples/browser/vue-app/package.json",
    "content": "{\n  \"name\": \"vue-app\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"serve\": \"vue-cli-service serve\",\n    \"build\": \"vue-cli-service build\",\n    \"lint\": \"vue-cli-service lint\"\n  },\n  \"dependencies\": {\n    \"@amplitude/analytics-browser\": \"^2.0.0-beta\",\n    \"core-js\": \"^3.26.1\",\n    \"vue\": \"^3.2.45\",\n    \"vue-class-component\": \"^8.0.0-rc.1\"\n  },\n  \"devDependencies\": {\n    \"@typescript-eslint/eslint-plugin\": \"^5.46.1\",\n    \"@typescript-eslint/parser\": \"^5.46.1\",\n    \"@vue/cli-plugin-babel\": \"~5.0.0\",\n    \"@vue/cli-plugin-eslint\": \"~5.0.0\",\n    \"@vue/cli-plugin-typescript\": \"~5.0.0\",\n    \"@vue/cli-service\": \"~5.0.0\",\n    \"@vue/eslint-config-typescript\": \"^9.1.0\",\n    \"eslint\": \"^8.29.0\",\n    \"eslint-plugin-vue\": \"^9.8.0\",\n    \"typescript\": \"~4.5.5\"\n  }\n}\n"
  },
  {
    "path": "examples/browser/vue-app/public/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\">\n    <link rel=\"icon\" href=\"<%= BASE_URL %>favicon.ico\">\n    <title><%= htmlWebpackPlugin.options.title %></title>\n  </head>\n  <body>\n    <noscript>\n      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>\n    </noscript>\n    <div id=\"app\"></div>\n    <!-- built files will be auto injected -->\n  </body>\n</html>\n"
  },
  {
    "path": "examples/browser/vue-app/src/App.vue",
    "content": "<template>\n  <img alt=\"Vue logo\" src=\"./assets/logo.png\">\n  <HelloWorld msg=\"Amplitude Analytics Browser Example with Vue\"/>\n</template>\n\n<script lang=\"ts\">\nimport { Options, Vue } from 'vue-class-component';\nimport HelloWorld from './components/HelloWorld.vue';\nimport * as amplitude from '@amplitude/analytics-browser';\n\n@Options({\n  components: {\n    HelloWorld,\n  },\n  mounted: () => {\n    amplitude.track('Page View', {\n      name: 'App',\n    });\n  },\n})\nexport default class App extends Vue {}\n</script>\n\n<style>\n#app {\n  font-family: Avenir, Helvetica, Arial, sans-serif;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n  text-align: center;\n  color: #2c3e50;\n  margin-top: 60px;\n}\n</style>\n"
  },
  {
    "path": "examples/browser/vue-app/src/components/HelloWorld.vue",
    "content": "<template>\n  <div class=\"hello\">\n    <h1>{{ msg }}</h1>\n    <button @click=\"handleIdentifyClick\">\n      Identify\n    </button>\n\n    <button @click=\"handleGroupClick\">\n      Group\n    </button>\n\n    <button @click=\"handleGroupIdentify\">\n      Group Identify\n    </button>\n\n    <button @click=\"handleTrackClick\">\n      Track\n    </button>\n  </div>\n</template>\n\n<script lang=\"ts\">\nimport { Options, Vue } from 'vue-class-component';\nimport { track, identify, setGroup, groupIdentify, Identify } from '@amplitude/analytics-browser';\n\n@Options({\n  props: {\n    msg: String\n  },\n  methods: {\n    handleIdentifyClick() {\n      identify(new Identify().set('role', 'engineer'))\n    },\n    handleGroupClick() {\n      setGroup('org', 'engineering')\n    },\n    handleGroupIdentify() {\n      groupIdentify('org', 'engineering', new Identify().set('technology', 'react.js'))\n    },\n    handleTrackClick() {\n      track('Button Click', { name: 'App' })\n    },\n  },\n})\nexport default class HelloWorld extends Vue {\n  msg!: string\n}\n</script>\n\n<!-- Add \"scoped\" attribute to limit CSS to this component only -->\n<style scoped>\nh3 {\n  margin: 40px 0 0;\n}\nul {\n  list-style-type: none;\n  padding: 0;\n}\nli {\n  display: inline-block;\n  margin: 0 10px;\n}\na {\n  color: #42b983;\n}\n</style>\n"
  },
  {
    "path": "examples/browser/vue-app/src/main.ts",
    "content": "import { createApp } from 'vue';\nimport App from './App.vue';\nimport * as amplitude from '@amplitude/analytics-browser';\n\n/**\n * Start by calling amplitude.init(). This must be done before any event tracking\n * preferrably in the root file of the project.\n *\n * Calling init() requires an API key\n * ```\n * amplitude.init(API_KEY)\n * ```\n *\n * Optionally, a user id can be provided when calling init()\n * ```\n * amplitude.init(API_KEY, 'example.vue.user@amplitude.com')\n * ```\n *\n * Optionally, a config object can be provided. Refer to https://amplitude.github.io/Amplitude-TypeScript/interfaces/Types.BrowserConfig.html\n * for object properties.\n */\namplitude.init('API_KEY', 'example.vue.user@amplitude.com');\n\ncreateApp(App).mount('#app');\n"
  },
  {
    "path": "examples/browser/vue-app/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"esnext\",\n    \"module\": \"esnext\",\n    \"strict\": true,\n    \"jsx\": \"preserve\",\n    \"moduleResolution\": \"node\",\n    \"experimentalDecorators\": true,\n    \"skipLibCheck\": true,\n    \"esModuleInterop\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"useDefineForClassFields\": true,\n    \"sourceMap\": true,\n    \"baseUrl\": \".\",\n    \"types\": [\n      \"webpack-env\"\n    ],\n    \"paths\": {\n      \"@/*\": [\n        \"src/*\"\n      ]\n    },\n    \"lib\": [\n      \"esnext\",\n      \"dom\",\n      \"dom.iterable\",\n      \"scripthost\"\n    ]\n  },\n  \"include\": [\n    \"src/**/*.ts\",\n    \"src/**/*.tsx\",\n    \"src/**/*.vue\",\n    \"tests/**/*.ts\",\n    \"tests/**/*.tsx\"\n  ],\n  \"exclude\": [\n    \"node_modules\"\n  ]\n}\n"
  },
  {
    "path": "examples/browser/vue-app/vue.config.js",
    "content": "const { defineConfig } = require('@vue/cli-service')\nmodule.exports = defineConfig({\n  transpileDependencies: true,\n  lintOnSave: false\n})\n"
  },
  {
    "path": "examples/node/nest-app/.eslintrc.js",
    "content": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.json',\n    tsconfigRootDir : __dirname, \n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint/eslint-plugin'],\n  extends: [\n    'plugin:@typescript-eslint/recommended',\n    'plugin:prettier/recommended',\n  ],\n  root: true,\n  env: {\n    node: true,\n    jest: true,\n  },\n  ignorePatterns: ['.eslintrc.js'],\n  rules: {\n    '@typescript-eslint/interface-name-prefix': 'off',\n    '@typescript-eslint/explicit-function-return-type': 'off',\n    '@typescript-eslint/explicit-module-boundary-types': 'off',\n    '@typescript-eslint/no-explicit-any': 'off',\n  },\n};\n"
  },
  {
    "path": "examples/node/nest-app/.gitignore",
    "content": "# compiled output\n/dist\n/node_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\npnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# OS\n.DS_Store\n\n# Tests\n/coverage\n/.nyc_output\n\n# IDEs and editors\n/.idea\n.project\n.classpath\n.c9/\n*.launch\n.settings/\n*.sublime-workspace\n\n# IDE - VSCode\n.vscode/*\n!.vscode/settings.json\n!.vscode/tasks.json\n!.vscode/launch.json\n!.vscode/extensions.json"
  },
  {
    "path": "examples/node/nest-app/.prettierrc",
    "content": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\"\n}"
  },
  {
    "path": "examples/node/nest-app/README.md",
    "content": "## Description\nThis is an example Nest app generated with Nest CLI, with Amplitude TypeScript Node SDK integrated.\n\n[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.\n\n## Installation\n\n```bash\n$ npm install\n```\n\n## Running the app\n\nUpdate the Amplitude API key before running the app.\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\nOpen `http://localhost:3000/` in browser to view the available options.\n\n## Test\n\n```bash\n# unit tests\n$ npm run test\n\n# e2e tests\n$ npm run test:e2e\n\n# test coverage\n$ npm run test:cov\n```\n"
  },
  {
    "path": "examples/node/nest-app/nest-cli.json",
    "content": "{\n  \"$schema\": \"https://json.schemastore.org/nest-cli\",\n  \"collection\": \"@nestjs/schematics\",\n  \"sourceRoot\": \"src\"\n}\n"
  },
  {
    "path": "examples/node/nest-app/package.json",
    "content": "{\n  \"name\": \"nest-app\",\n  \"version\": \"0.0.1\",\n  \"description\": \"\",\n  \"author\": \"\",\n  \"private\": true,\n  \"license\": \"UNLICENSED\",\n  \"scripts\": {\n    \"prebuild\": \"rimraf dist\",\n    \"build\": \"nest build\",\n    \"format\": \"prettier --write \\\"src/**/*.ts\\\" \\\"test/**/*.ts\\\"\",\n    \"start\": \"nest start\",\n    \"start:dev\": \"nest start --watch\",\n    \"start:debug\": \"nest start --debug --watch\",\n    \"start:prod\": \"node dist/main\",\n    \"lint\": \"eslint \\\"{src,apps,libs,test}/**/*.ts\\\" --fix\"\n  },\n  \"dependencies\": {\n    \"@amplitude/analytics-node\": \"^1.0.0\",\n    \"@nestjs/common\": \"^9.2.1\",\n    \"@nestjs/core\": \"^9.2.1\",\n    \"@nestjs/platform-express\": \"^9.2.1\",\n    \"hbs\": \"^4.2.0\",\n    \"reflect-metadata\": \"^0.1.13\",\n    \"rimraf\": \"^3.0.2\",\n    \"rxjs\": \"^7.6.0\"\n  },\n  \"devDependencies\": {\n    \"@nestjs/cli\": \"^9.1.5\",\n    \"@nestjs/schematics\": \"^9.0.3\",\n    \"@types/express\": \"^4.17.14\",\n    \"@types/jest\": \"29.2.4\",\n    \"@types/node\": \"^18.11.14\",\n    \"@types/supertest\": \"^2.0.12\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.46.1\",\n    \"@typescript-eslint/parser\": \"^5.46.1\",\n    \"eslint\": \"^8.29.0\",\n    \"eslint-config-prettier\": \"^8.5.0\",\n    \"eslint-plugin-prettier\": \"^4.2.1\",\n    \"jest\": \"29.3.1\",\n    \"prettier\": \"^2.8.1\",\n    \"source-map-support\": \"^0.5.21\",\n    \"ts-jest\": \"29.0.3\",\n    \"ts-loader\": \"^9.4.2\",\n    \"ts-node\": \"^10.9.1\",\n    \"tsconfig-paths\": \"4.1.1\",\n    \"typescript\": \"^4.7.4\"\n  },\n  \"jest\": {\n    \"moduleFileExtensions\": [\n      \"js\",\n      \"json\",\n      \"ts\"\n    ],\n    \"rootDir\": \"src\",\n    \"testRegex\": \".*\\\\.spec\\\\.ts$\",\n    \"transform\": {\n      \"^.+\\\\.(t|j)s$\": \"ts-jest\"\n    },\n    \"collectCoverageFrom\": [\n      \"**/*.(t|j)s\"\n    ],\n    \"coverageDirectory\": \"../coverage\",\n    \"testEnvironment\": \"node\"\n  }\n}\n"
  },
  {
    "path": "examples/node/nest-app/src/app.controller.ts",
    "content": "import { Controller, Get, Render } from '@nestjs/common';\nimport { AppService } from './app.service';\nimport * as amplitude from '@amplitude/analytics-node';\n\nconst AMPLITUDE_API_KEY = '9f0e4a9f1c1233088b254e30ba3c80e1';\n\n@Controller()\nexport class AppController {\n  constructor(private readonly appService: AppService) {\n    amplitude.init(AMPLITUDE_API_KEY, {\n      logLevel: amplitude.Types.LogLevel.Debug,\n    });\n  }\n\n  @Get()\n  @Render('index')\n  getOptions(): any {\n    return this.appService.getOptions();\n  }\n\n  @Get('track')\n  async track(): Promise<string> {\n    await amplitude.track(\n      'nest-app example event',\n      { property1: '1' },\n      { user_id: 'test_user' },\n    ).promise;\n    return 'Triggered, check console output...';\n  }\n\n  @Get('identify')\n  async identify(): Promise<string> {\n    const identifyObj = new amplitude.Identify();\n    identifyObj.set('email', 'test_user@email.com');\n    identifyObj.set('role', 'test');\n    await amplitude.identify(identifyObj, { user_id: 'test_user' }).promise;\n    return 'Triggered, check console output...';\n  }\n\n  @Get('group')\n  async group(): Promise<string> {\n    await amplitude.setGroup('org', 'engineering', { user_id: 'test_user' })\n      .promise;\n    return 'Triggered, check console output...';\n  }\n\n  @Get('group-identify')\n  async groupIdentify(): Promise<string> {\n    await amplitude.groupIdentify(\n      'org',\n      'engineering',\n      new amplitude.Identify().set('technology', 'nest.js'),\n      { user_id: 'test_user' },\n    ).promise;\n    return 'Triggered, check console output...';\n  }\n\n  @Get('test')\n  async test(): Promise<string> {\n    const identifyObj = new amplitude.Identify();\n    identifyObj.set('email', 'marvin@test.com');\n    identifyObj.set('env', 'dev');\n    amplitude.identify(identifyObj);\n\n    amplitude.track('some event', undefined, { user_id: 'marvin' });\n    await amplitude.flush().promise;\n    return 'Triggered, check console output...';\n  }\n}\n"
  },
  {
    "path": "examples/node/nest-app/src/app.module.ts",
    "content": "import { Module } from '@nestjs/common';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\n\n@Module({\n  imports: [],\n  controllers: [AppController],\n  providers: [AppService],\n})\nexport class AppModule {}\n"
  },
  {
    "path": "examples/node/nest-app/src/app.service.ts",
    "content": "import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n  getOptions(): any {\n    return {\n      prerequisite: 'update AMPLITUDE_API_KEY before sending the event',\n      options: [\n        'GET \"/\", check the options',\n        'GET \"/track\", send track event',\n        'GET \"/identify\", send identify event, send a new track event to see the updated properties',\n        'GET \"/group\", send group event, send a new track event to see the updated properties',\n        'GET \"/group-identify\", send groupIdentify event, send a new track event to see the updated properties',\n      ],\n    };\n  }\n}\n"
  },
  {
    "path": "examples/node/nest-app/src/main.ts",
    "content": "import { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { NestExpressApplication } from '@nestjs/platform-express';\nimport { resolve } from 'path';\n\nasync function bootstrap() {\n  const app = await NestFactory.create<NestExpressApplication>(AppModule);\n\n  app.useStaticAssets(resolve('./src/public'));\n  app.setBaseViewsDir(resolve('./src/views'));\n  app.setViewEngine('hbs');\n\n  await app.listen(3000);\n}\nbootstrap();\n"
  },
  {
    "path": "examples/node/nest-app/src/views/index.hbs",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>App</title>\n  </head>\n  <body>\n    Prerequisite: {{ prerequisite }}\n    <ul>\n      {{#each options as |option|}}\n        <li>{{option}}</li>\n      {{/each}}\n    </ul>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/node/nest-app/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"exclude\": [\"node_modules\", \"test\", \"dist\", \"**/*spec.ts\"]\n}\n"
  },
  {
    "path": "examples/node/nest-app/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"removeComments\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"target\": \"es2017\",\n    \"sourceMap\": true,\n    \"outDir\": \"./dist\",\n    \"baseUrl\": \"./\",\n    \"incremental\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": false,\n    \"noImplicitAny\": false,\n    \"strictBindCallApply\": false,\n    \"forceConsistentCasingInFileNames\": false,\n    \"noFallthroughCasesInSwitch\": false\n  }\n}\n"
  },
  {
    "path": "examples/plugins/page-view-tracking-enrichment/index.ts",
    "content": "import { createInstance } from '@amplitude/analytics-browser';\nimport { EnrichmentPlugin } from '@amplitude/analytics-types';\n\n/**\n * This is an example plugin that enriches events with event_type \"Page View\" by adding\n * more event_properties on top of what @amplitude/analytics-browser provides out of the box\n *\n * @returns EnrichmentPlugin\n */\nexport const pageViewTrackingEnrichment = (): EnrichmentPlugin => {\n  return {\n    name: 'page-view-tracking-enrichment',\n    type: 'enrichment',\n    setup: async () => undefined,\n    execute: async (event) => {\n      if (event.event_type !== '[Amplitude] Page Viewed') {  // event name format if using Autocapture Pageviews \n        return event;\n      }\n      event.event_properties = {\n        ...event.event_properties,\n        // TODO: Add new event properties here\n        new_property: 'new_value',\n      };\n      return event;\n    },\n  };\n};\n\nconst instance = createInstance();\n\n/**\n * IMPORTANT: install plugin before calling init to make sure plugin is added by the time\n * init function sends out the \"Page View\" event\n */\ninstance.add(pageViewTrackingEnrichment());\n\n// initialize sdk\ninstance.init('API_KEY');\n"
  },
  {
    "path": "examples/plugins/react-native-idfa-plugin/idfaPlugin.ts",
    "content": "import { Types } from '@amplitude/analytics-react-native';\nimport ReactNativeIdfaAaid from '@sparkfabrik/react-native-idfa-aaid';\n\nexport default class IdfaPlugin implements Types.BeforePlugin {\n  name = 'idfa';\n  type = 'before' as const;\n  idfa: string | null = null;\n\n  async setup(_config: Types.Config): Promise<undefined> {\n    try {\n      const info = await ReactNativeIdfaAaid.getAdvertisingInfo();\n      this.idfa = info.id;\n    } catch (e) {\n      console.log(e);\n    }\n    return undefined;\n  }\n\n  async execute(context: Types.Event): Promise<Types.Event> {\n    if (this.idfa) {\n      context.idfa = this.idfa;\n    }\n    return context;\n  }\n}\n"
  },
  {
    "path": "examples/plugins/remove-event-key/index.ts",
    "content": "import { createInstance } from '@amplitude/analytics-browser';\nimport { EnrichmentPlugin } from '@amplitude/analytics-types';\nimport { BaseEvent } from '@amplitude/analytics-types/src';\n\ntype KeyOfEvent = keyof BaseEvent;\n\n/**\n * This is an example plugin that enriches all events by removing a list of keys from the\n * event payload. This plugin is helpful in cases where users prefer not to use default\n * values set by the @amplitude/analytics-browser library, for example:\n * - `event.time`\n * - `event.idfa`\n * - `event.idva`\n * - `event.ip`\n *\n * @param keysToRemove\n * @returns EnrichmentPlugin\n */\nexport const removeEventKeyEnrichment = (keysToRemove: KeyOfEvent[] = []): EnrichmentPlugin => {\n  return {\n    name: 'remove-event-key-enrichment',\n    type: 'enrichment',\n    setup: async () => undefined,\n    execute: async (event) => {\n      for (var key of keysToRemove) {\n        delete event[key];\n      }\n      return event;\n    },\n  };\n};\n\n/**\n * This is an example plugin that enriches all events by removing `event.time` from all events.\n * `event.time` uses `Date.now()` which is controlled by the device where the browser runs on.\n * The device clock can be easily manipulated yielding events having unreasonable time values.\n * With `event.time` being `undefined`, the time of the event is determined when the event was sent\n * successfully by the browser (\"Client Upload Time\"), determined by the server clock, rather than\n * when the event actually occurred. On majority of the cases, \"Client Upload Time\" can be\n * off by up to the configured `config.flushIntervalMillis`. By default `config.flushIntervalMillis`\n * is set to 1000 milliseconds. In rare cases where initial request to Amplitude fails due to\n * bad payload, throttled request, server error, etc, the time difference can be extended.\n */\nconst removeTimeEnrichment = removeEventKeyEnrichment(['time']);\n\nconst instance = createInstance();\n\n/**\n * IMPORTANT: install plugin before calling init to make sure plugin is added by the time\n * init function is called, and events are flushed.\n */\ninstance.add(removeTimeEnrichment);\n\n// initialize sdk\ninstance.init('API_KEY');\n"
  },
  {
    "path": "examples/react-native/app/.bundle/config",
    "content": "BUNDLE_PATH: \"vendor/bundle\"\nBUNDLE_FORCE_RUBY_PLATFORM: 1\n"
  },
  {
    "path": "examples/react-native/app/.eslintrc.js",
    "content": "module.exports = {\n  root: true,\n  extends: '@react-native',\n};\n"
  },
  {
    "path": "examples/react-native/app/.gitignore",
    "content": "# OSX\n#\n.DS_Store\n\n# Xcode\n#\nbuild/\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\nxcuserdata\n*.xccheckout\n*.moved-aside\nDerivedData\n*.hmap\n*.ipa\n*.xcuserstate\n**/.xcode.env.local\n\n# Android/IntelliJ\n#\nbuild/\n.idea\n.gradle\nlocal.properties\n*.iml\n*.hprof\n.cxx/\n*.keystore\n!debug.keystore\n\n# node.js\n#\nnode_modules/\nnpm-debug.log\nyarn-error.log\n\n# fastlane\n#\n# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the\n# screenshots whenever they are needed.\n# For more information about the recommended setup visit:\n# https://docs.fastlane.tools/best-practices/source-control/\n\n**/fastlane/report.xml\n**/fastlane/Preview.html\n**/fastlane/screenshots\n**/fastlane/test_output\n\n# Bundle artifact\n*.jsbundle\n\n# Ruby / CocoaPods\n**/Pods/\n/vendor/bundle/\n\n# Temporary files created by Metro to check the health of the file watcher\n.metro-health-check*\n\n# testing\n/coverage\n\n# Yarn\n.yarn/*\n!.yarn/patches\n!.yarn/plugins\n!.yarn/releases\n!.yarn/sdks\n!.yarn/versions\n"
  },
  {
    "path": "examples/react-native/app/.maestro/smoke.yaml",
    "content": "appId: org.reactjs.native.example.app\n---\n- launchApp\n- extendedWaitUntil:\n    visible:\n      text: \"Test Amplitude App\"\n    timeout: 15000\n"
  },
  {
    "path": "examples/react-native/app/.prettierrc.js",
    "content": "module.exports = {\n  arrowParens: 'avoid',\n  bracketSameLine: true,\n  bracketSpacing: false,\n  singleQuote: true,\n  trailingComma: 'all',\n};\n"
  },
  {
    "path": "examples/react-native/app/.watchmanconfig",
    "content": "{}\n"
  },
  {
    "path": "examples/react-native/app/.yarn/releases/yarn-stable-temp.cjs",
    "content": "#!/usr/bin/env node\n/* eslint-disable */\n//prettier-ignore\n(()=>{var $3e=Object.create;var LR=Object.defineProperty;var e_e=Object.getOwnPropertyDescriptor;var t_e=Object.getOwnPropertyNames;var r_e=Object.getPrototypeOf,n_e=Object.prototype.hasOwnProperty;var ve=(t=>typeof require<\"u\"?require:typeof Proxy<\"u\"?new Proxy(t,{get:(e,r)=>(typeof require<\"u\"?require:e)[r]}):t)(function(t){if(typeof require<\"u\")return require.apply(this,arguments);throw new Error('Dynamic require of \"'+t+'\" is not supported')});var Et=(t,e)=>()=>(t&&(e=t(t=0)),e);var _=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports),zt=(t,e)=>{for(var r in e)LR(t,r,{get:e[r],enumerable:!0})},i_e=(t,e,r,o)=>{if(e&&typeof e==\"object\"||typeof e==\"function\")for(let a of t_e(e))!n_e.call(t,a)&&a!==r&&LR(t,a,{get:()=>e[a],enumerable:!(o=e_e(e,a))||o.enumerable});return t};var $e=(t,e,r)=>(r=t!=null?$3e(r_e(t)):{},i_e(e||!t||!t.__esModule?LR(r,\"default\",{value:t,enumerable:!0}):r,t));var vi={};zt(vi,{SAFE_TIME:()=>x7,S_IFDIR:()=>wD,S_IFLNK:()=>ID,S_IFMT:()=>Mu,S_IFREG:()=>qw});var Mu,wD,qw,ID,x7,k7=Et(()=>{Mu=61440,wD=16384,qw=32768,ID=40960,x7=456789e3});var tr={};zt(tr,{EBADF:()=>Io,EBUSY:()=>s_e,EEXIST:()=>A_e,EINVAL:()=>a_e,EISDIR:()=>u_e,ENOENT:()=>l_e,ENOSYS:()=>o_e,ENOTDIR:()=>c_e,ENOTEMPTY:()=>p_e,EOPNOTSUPP:()=>h_e,EROFS:()=>f_e,ERR_DIR_CLOSED:()=>NR});function Ll(t,e){return Object.assign(new Error(`${t}: ${e}`),{code:t})}function s_e(t){return Ll(\"EBUSY\",t)}function o_e(t,e){return Ll(\"ENOSYS\",`${t}, ${e}`)}function a_e(t){return Ll(\"EINVAL\",`invalid argument, ${t}`)}function Io(t){return Ll(\"EBADF\",`bad file descriptor, ${t}`)}function l_e(t){return Ll(\"ENOENT\",`no such file or directory, ${t}`)}function c_e(t){return Ll(\"ENOTDIR\",`not a directory, ${t}`)}function u_e(t){return Ll(\"EISDIR\",`illegal operation on a directory, ${t}`)}function A_e(t){return Ll(\"EEXIST\",`file already exists, ${t}`)}function f_e(t){return Ll(\"EROFS\",`read-only filesystem, ${t}`)}function p_e(t){return Ll(\"ENOTEMPTY\",`directory not empty, ${t}`)}function h_e(t){return Ll(\"EOPNOTSUPP\",`operation not supported, ${t}`)}function NR(){return Ll(\"ERR_DIR_CLOSED\",\"Directory handle was closed\")}var BD=Et(()=>{});var Ea={};zt(Ea,{BigIntStatsEntry:()=>ty,DEFAULT_MODE:()=>UR,DirEntry:()=>OR,StatEntry:()=>ey,areStatsEqual:()=>_R,clearStats:()=>vD,convertToBigIntStats:()=>d_e,makeDefaultStats:()=>Q7,makeEmptyStats:()=>g_e});function Q7(){return new ey}function g_e(){return vD(Q7())}function vD(t){for(let e in t)if(Object.hasOwn(t,e)){let r=t[e];typeof r==\"number\"?t[e]=0:typeof r==\"bigint\"?t[e]=BigInt(0):MR.types.isDate(r)&&(t[e]=new Date(0))}return t}function d_e(t){let e=new ty;for(let r in t)if(Object.hasOwn(t,r)){let o=t[r];typeof o==\"number\"?e[r]=BigInt(o):MR.types.isDate(o)&&(e[r]=new Date(o))}return e.atimeNs=e.atimeMs*BigInt(1e6),e.mtimeNs=e.mtimeMs*BigInt(1e6),e.ctimeNs=e.ctimeMs*BigInt(1e6),e.birthtimeNs=e.birthtimeMs*BigInt(1e6),e}function _R(t,e){if(t.atimeMs!==e.atimeMs||t.birthtimeMs!==e.birthtimeMs||t.blksize!==e.blksize||t.blocks!==e.blocks||t.ctimeMs!==e.ctimeMs||t.dev!==e.dev||t.gid!==e.gid||t.ino!==e.ino||t.isBlockDevice()!==e.isBlockDevice()||t.isCharacterDevice()!==e.isCharacterDevice()||t.isDirectory()!==e.isDirectory()||t.isFIFO()!==e.isFIFO()||t.isFile()!==e.isFile()||t.isSocket()!==e.isSocket()||t.isSymbolicLink()!==e.isSymbolicLink()||t.mode!==e.mode||t.mtimeMs!==e.mtimeMs||t.nlink!==e.nlink||t.rdev!==e.rdev||t.size!==e.size||t.uid!==e.uid)return!1;let r=t,o=e;return!(r.atimeNs!==o.atimeNs||r.mtimeNs!==o.mtimeNs||r.ctimeNs!==o.ctimeNs||r.birthtimeNs!==o.birthtimeNs)}var MR,UR,OR,ey,ty,HR=Et(()=>{MR=$e(ve(\"util\")),UR=33188,OR=class{constructor(){this.name=\"\";this.path=\"\";this.mode=0}isBlockDevice(){return!1}isCharacterDevice(){return!1}isDirectory(){return(this.mode&61440)===16384}isFIFO(){return!1}isFile(){return(this.mode&61440)===32768}isSocket(){return!1}isSymbolicLink(){return(this.mode&61440)===40960}},ey=class{constructor(){this.uid=0;this.gid=0;this.size=0;this.blksize=0;this.atimeMs=0;this.mtimeMs=0;this.ctimeMs=0;this.birthtimeMs=0;this.atime=new Date(0);this.mtime=new Date(0);this.ctime=new Date(0);this.birthtime=new Date(0);this.dev=0;this.ino=0;this.mode=UR;this.nlink=1;this.rdev=0;this.blocks=1}isBlockDevice(){return!1}isCharacterDevice(){return!1}isDirectory(){return(this.mode&61440)===16384}isFIFO(){return!1}isFile(){return(this.mode&61440)===32768}isSocket(){return!1}isSymbolicLink(){return(this.mode&61440)===40960}},ty=class{constructor(){this.uid=BigInt(0);this.gid=BigInt(0);this.size=BigInt(0);this.blksize=BigInt(0);this.atimeMs=BigInt(0);this.mtimeMs=BigInt(0);this.ctimeMs=BigInt(0);this.birthtimeMs=BigInt(0);this.atimeNs=BigInt(0);this.mtimeNs=BigInt(0);this.ctimeNs=BigInt(0);this.birthtimeNs=BigInt(0);this.atime=new Date(0);this.mtime=new Date(0);this.ctime=new Date(0);this.birthtime=new Date(0);this.dev=BigInt(0);this.ino=BigInt(0);this.mode=BigInt(UR);this.nlink=BigInt(1);this.rdev=BigInt(0);this.blocks=BigInt(1)}isBlockDevice(){return!1}isCharacterDevice(){return!1}isDirectory(){return(this.mode&BigInt(61440))===BigInt(16384)}isFIFO(){return!1}isFile(){return(this.mode&BigInt(61440))===BigInt(32768)}isSocket(){return!1}isSymbolicLink(){return(this.mode&BigInt(61440))===BigInt(40960)}}});function w_e(t){let e,r;if(e=t.match(E_e))t=e[1];else if(r=t.match(C_e))t=`\\\\\\\\${r[1]?\".\\\\\":\"\"}${r[2]}`;else return t;return t.replace(/\\//g,\"\\\\\")}function I_e(t){t=t.replace(/\\\\/g,\"/\");let e,r;return(e=t.match(m_e))?t=`/${e[1]}`:(r=t.match(y_e))&&(t=`/unc/${r[1]?\".dot/\":\"\"}${r[2]}`),t}function DD(t,e){return t===le?R7(e):qR(e)}var Gw,Bt,dr,le,z,F7,m_e,y_e,E_e,C_e,qR,R7,Ca=Et(()=>{Gw=$e(ve(\"path\")),Bt={root:\"/\",dot:\".\",parent:\"..\"},dr={home:\"~\",nodeModules:\"node_modules\",manifest:\"package.json\",lockfile:\"yarn.lock\",virtual:\"__virtual__\",pnpJs:\".pnp.js\",pnpCjs:\".pnp.cjs\",pnpData:\".pnp.data.json\",pnpEsmLoader:\".pnp.loader.mjs\",rc:\".yarnrc.yml\",env:\".env\"},le=Object.create(Gw.default),z=Object.create(Gw.default.posix);le.cwd=()=>process.cwd();z.cwd=process.platform===\"win32\"?()=>qR(process.cwd()):process.cwd;process.platform===\"win32\"&&(z.resolve=(...t)=>t.length>0&&z.isAbsolute(t[0])?Gw.default.posix.resolve(...t):Gw.default.posix.resolve(z.cwd(),...t));F7=function(t,e,r){return e=t.normalize(e),r=t.normalize(r),e===r?\".\":(e.endsWith(t.sep)||(e=e+t.sep),r.startsWith(e)?r.slice(e.length):null)};le.contains=(t,e)=>F7(le,t,e);z.contains=(t,e)=>F7(z,t,e);m_e=/^([a-zA-Z]:.*)$/,y_e=/^\\/\\/(\\.\\/)?(.*)$/,E_e=/^\\/([a-zA-Z]:.*)$/,C_e=/^\\/unc\\/(\\.dot\\/)?(.*)$/;qR=process.platform===\"win32\"?I_e:t=>t,R7=process.platform===\"win32\"?w_e:t=>t;le.fromPortablePath=R7;le.toPortablePath=qR});async function PD(t,e){let r=\"0123456789abcdef\";await t.mkdirPromise(e.indexPath,{recursive:!0});let o=[];for(let a of r)for(let n of r)o.push(t.mkdirPromise(t.pathUtils.join(e.indexPath,`${a}${n}`),{recursive:!0}));return await Promise.all(o),e.indexPath}async function T7(t,e,r,o,a){let n=t.pathUtils.normalize(e),u=r.pathUtils.normalize(o),A=[],p=[],{atime:h,mtime:E}=a.stableTime?{atime:Mg,mtime:Mg}:await r.lstatPromise(u);await t.mkdirpPromise(t.pathUtils.dirname(e),{utimes:[h,E]}),await GR(A,p,t,n,r,u,{...a,didParentExist:!0});for(let I of A)await I();await Promise.all(p.map(I=>I()))}async function GR(t,e,r,o,a,n,u){let A=u.didParentExist?await L7(r,o):null,p=await a.lstatPromise(n),{atime:h,mtime:E}=u.stableTime?{atime:Mg,mtime:Mg}:p,I;switch(!0){case p.isDirectory():I=await v_e(t,e,r,o,A,a,n,p,u);break;case p.isFile():I=await S_e(t,e,r,o,A,a,n,p,u);break;case p.isSymbolicLink():I=await b_e(t,e,r,o,A,a,n,p,u);break;default:throw new Error(`Unsupported file type (${p.mode})`)}return(u.linkStrategy?.type!==\"HardlinkFromIndex\"||!p.isFile())&&((I||A?.mtime?.getTime()!==E.getTime()||A?.atime?.getTime()!==h.getTime())&&(e.push(()=>r.lutimesPromise(o,h,E)),I=!0),(A===null||(A.mode&511)!==(p.mode&511))&&(e.push(()=>r.chmodPromise(o,p.mode&511)),I=!0)),I}async function L7(t,e){try{return await t.lstatPromise(e)}catch{return null}}async function v_e(t,e,r,o,a,n,u,A,p){if(a!==null&&!a.isDirectory())if(p.overwrite)t.push(async()=>r.removePromise(o)),a=null;else return!1;let h=!1;a===null&&(t.push(async()=>{try{await r.mkdirPromise(o,{mode:A.mode})}catch(v){if(v.code!==\"EEXIST\")throw v}}),h=!0);let E=await n.readdirPromise(u),I=p.didParentExist&&!a?{...p,didParentExist:!1}:p;if(p.stableSort)for(let v of E.sort())await GR(t,e,r,r.pathUtils.join(o,v),n,n.pathUtils.join(u,v),I)&&(h=!0);else(await Promise.all(E.map(async x=>{await GR(t,e,r,r.pathUtils.join(o,x),n,n.pathUtils.join(u,x),I)}))).some(x=>x)&&(h=!0);return h}async function D_e(t,e,r,o,a,n,u,A,p,h){let E=await n.checksumFilePromise(u,{algorithm:\"sha1\"}),I=420,v=A.mode&511,x=`${E}${v!==I?v.toString(8):\"\"}`,C=r.pathUtils.join(h.indexPath,E.slice(0,2),`${x}.dat`),R;(ue=>(ue[ue.Lock=0]=\"Lock\",ue[ue.Rename=1]=\"Rename\"))(R||={});let N=1,U=await L7(r,C);if(a){let ae=U&&a.dev===U.dev&&a.ino===U.ino,fe=U?.mtimeMs!==B_e;if(ae&&fe&&h.autoRepair&&(N=0,U=null),!ae)if(p.overwrite)t.push(async()=>r.removePromise(o)),a=null;else return!1}let V=!U&&N===1?`${C}.${Math.floor(Math.random()*4294967296).toString(16).padStart(8,\"0\")}`:null,te=!1;return t.push(async()=>{if(!U&&(N===0&&await r.lockPromise(C,async()=>{let ae=await n.readFilePromise(u);await r.writeFilePromise(C,ae)}),N===1&&V)){let ae=await n.readFilePromise(u);await r.writeFilePromise(V,ae);try{await r.linkPromise(V,C)}catch(fe){if(fe.code===\"EEXIST\")te=!0,await r.unlinkPromise(V);else throw fe}}a||await r.linkPromise(C,o)}),e.push(async()=>{U||(await r.lutimesPromise(C,Mg,Mg),v!==I&&await r.chmodPromise(C,v)),V&&!te&&await r.unlinkPromise(V)}),!1}async function P_e(t,e,r,o,a,n,u,A,p){if(a!==null)if(p.overwrite)t.push(async()=>r.removePromise(o)),a=null;else return!1;return t.push(async()=>{let h=await n.readFilePromise(u);await r.writeFilePromise(o,h)}),!0}async function S_e(t,e,r,o,a,n,u,A,p){return p.linkStrategy?.type===\"HardlinkFromIndex\"?D_e(t,e,r,o,a,n,u,A,p,p.linkStrategy):P_e(t,e,r,o,a,n,u,A,p)}async function b_e(t,e,r,o,a,n,u,A,p){if(a!==null)if(p.overwrite)t.push(async()=>r.removePromise(o)),a=null;else return!1;return t.push(async()=>{await r.symlinkPromise(DD(r.pathUtils,await n.readlinkPromise(u)),o)}),!0}var Mg,B_e,jR=Et(()=>{Ca();Mg=new Date(456789e3*1e3),B_e=Mg.getTime()});function SD(t,e,r,o){let a=()=>{let n=r.shift();if(typeof n>\"u\")return null;let u=t.pathUtils.join(e,n);return Object.assign(t.statSync(u),{name:n,path:void 0})};return new jw(e,a,o)}var jw,N7=Et(()=>{BD();jw=class{constructor(e,r,o={}){this.path=e;this.nextDirent=r;this.opts=o;this.closed=!1}throwIfClosed(){if(this.closed)throw NR()}async*[Symbol.asyncIterator](){try{let e;for(;(e=await this.read())!==null;)yield e}finally{await this.close()}}read(e){let r=this.readSync();return typeof e<\"u\"?e(null,r):Promise.resolve(r)}readSync(){return this.throwIfClosed(),this.nextDirent()}close(e){return this.closeSync(),typeof e<\"u\"?e(null):Promise.resolve()}closeSync(){this.throwIfClosed(),this.opts.onClose?.(),this.closed=!0}}});function O7(t,e){if(t!==e)throw new Error(`Invalid StatWatcher status: expected '${e}', got '${t}'`)}var M7,ry,U7=Et(()=>{M7=ve(\"events\");HR();ry=class extends M7.EventEmitter{constructor(r,o,{bigint:a=!1}={}){super();this.status=\"ready\";this.changeListeners=new Map;this.startTimeout=null;this.fakeFs=r,this.path=o,this.bigint=a,this.lastStats=this.stat()}static create(r,o,a){let n=new ry(r,o,a);return n.start(),n}start(){O7(this.status,\"ready\"),this.status=\"running\",this.startTimeout=setTimeout(()=>{this.startTimeout=null,this.fakeFs.existsSync(this.path)||this.emit(\"change\",this.lastStats,this.lastStats)},3)}stop(){O7(this.status,\"running\"),this.status=\"stopped\",this.startTimeout!==null&&(clearTimeout(this.startTimeout),this.startTimeout=null),this.emit(\"stop\")}stat(){try{return this.fakeFs.statSync(this.path,{bigint:this.bigint})}catch{let o=this.bigint?new ty:new ey;return vD(o)}}makeInterval(r){let o=setInterval(()=>{let a=this.stat(),n=this.lastStats;_R(a,n)||(this.lastStats=a,this.emit(\"change\",a,n))},r.interval);return r.persistent?o:o.unref()}registerChangeListener(r,o){this.addListener(\"change\",r),this.changeListeners.set(r,this.makeInterval(o))}unregisterChangeListener(r){this.removeListener(\"change\",r);let o=this.changeListeners.get(r);typeof o<\"u\"&&clearInterval(o),this.changeListeners.delete(r)}unregisterAllChangeListeners(){for(let r of this.changeListeners.keys())this.unregisterChangeListener(r)}hasChangeListeners(){return this.changeListeners.size>0}ref(){for(let r of this.changeListeners.values())r.ref();return this}unref(){for(let r of this.changeListeners.values())r.unref();return this}}});function ny(t,e,r,o){let a,n,u,A;switch(typeof r){case\"function\":a=!1,n=!0,u=5007,A=r;break;default:({bigint:a=!1,persistent:n=!0,interval:u=5007}=r),A=o;break}let p=bD.get(t);typeof p>\"u\"&&bD.set(t,p=new Map);let h=p.get(e);return typeof h>\"u\"&&(h=ry.create(t,e,{bigint:a}),p.set(e,h)),h.registerChangeListener(A,{persistent:n,interval:u}),h}function Ug(t,e,r){let o=bD.get(t);if(typeof o>\"u\")return;let a=o.get(e);typeof a>\"u\"||(typeof r>\"u\"?a.unregisterAllChangeListeners():a.unregisterChangeListener(r),a.hasChangeListeners()||(a.stop(),o.delete(e)))}function _g(t){let e=bD.get(t);if(!(typeof e>\"u\"))for(let r of e.keys())Ug(t,r)}var bD,YR=Et(()=>{U7();bD=new WeakMap});function x_e(t){let e=t.match(/\\r?\\n/g);if(e===null)return H7.EOL;let r=e.filter(a=>a===`\\r\n`).length,o=e.length-r;return r>o?`\\r\n`:`\n`}function Hg(t,e){return e.replace(/\\r?\\n/g,x_e(t))}var _7,H7,gf,Uu,qg=Et(()=>{_7=ve(\"crypto\"),H7=ve(\"os\");jR();Ca();gf=class{constructor(e){this.pathUtils=e}async*genTraversePromise(e,{stableSort:r=!1}={}){let o=[e];for(;o.length>0;){let a=o.shift();if((await this.lstatPromise(a)).isDirectory()){let u=await this.readdirPromise(a);if(r)for(let A of u.sort())o.push(this.pathUtils.join(a,A));else throw new Error(\"Not supported\")}else yield a}}async checksumFilePromise(e,{algorithm:r=\"sha512\"}={}){let o=await this.openPromise(e,\"r\");try{let n=Buffer.allocUnsafeSlow(65536),u=(0,_7.createHash)(r),A=0;for(;(A=await this.readPromise(o,n,0,65536))!==0;)u.update(A===65536?n:n.slice(0,A));return u.digest(\"hex\")}finally{await this.closePromise(o)}}async removePromise(e,{recursive:r=!0,maxRetries:o=5}={}){let a;try{a=await this.lstatPromise(e)}catch(n){if(n.code===\"ENOENT\")return;throw n}if(a.isDirectory()){if(r){let n=await this.readdirPromise(e);await Promise.all(n.map(u=>this.removePromise(this.pathUtils.resolve(e,u))))}for(let n=0;n<=o;n++)try{await this.rmdirPromise(e);break}catch(u){if(u.code!==\"EBUSY\"&&u.code!==\"ENOTEMPTY\")throw u;n<o&&await new Promise(A=>setTimeout(A,n*100))}}else await this.unlinkPromise(e)}removeSync(e,{recursive:r=!0}={}){let o;try{o=this.lstatSync(e)}catch(a){if(a.code===\"ENOENT\")return;throw a}if(o.isDirectory()){if(r)for(let a of this.readdirSync(e))this.removeSync(this.pathUtils.resolve(e,a));this.rmdirSync(e)}else this.unlinkSync(e)}async mkdirpPromise(e,{chmod:r,utimes:o}={}){if(e=this.resolve(e),e===this.pathUtils.dirname(e))return;let a=e.split(this.pathUtils.sep),n;for(let u=2;u<=a.length;++u){let A=a.slice(0,u).join(this.pathUtils.sep);if(!this.existsSync(A)){try{await this.mkdirPromise(A)}catch(p){if(p.code===\"EEXIST\")continue;throw p}if(n??=A,r!=null&&await this.chmodPromise(A,r),o!=null)await this.utimesPromise(A,o[0],o[1]);else{let p=await this.statPromise(this.pathUtils.dirname(A));await this.utimesPromise(A,p.atime,p.mtime)}}}return n}mkdirpSync(e,{chmod:r,utimes:o}={}){if(e=this.resolve(e),e===this.pathUtils.dirname(e))return;let a=e.split(this.pathUtils.sep),n;for(let u=2;u<=a.length;++u){let A=a.slice(0,u).join(this.pathUtils.sep);if(!this.existsSync(A)){try{this.mkdirSync(A)}catch(p){if(p.code===\"EEXIST\")continue;throw p}if(n??=A,r!=null&&this.chmodSync(A,r),o!=null)this.utimesSync(A,o[0],o[1]);else{let p=this.statSync(this.pathUtils.dirname(A));this.utimesSync(A,p.atime,p.mtime)}}}return n}async copyPromise(e,r,{baseFs:o=this,overwrite:a=!0,stableSort:n=!1,stableTime:u=!1,linkStrategy:A=null}={}){return await T7(this,e,o,r,{overwrite:a,stableSort:n,stableTime:u,linkStrategy:A})}copySync(e,r,{baseFs:o=this,overwrite:a=!0}={}){let n=o.lstatSync(r),u=this.existsSync(e);if(n.isDirectory()){this.mkdirpSync(e);let p=o.readdirSync(r);for(let h of p)this.copySync(this.pathUtils.join(e,h),o.pathUtils.join(r,h),{baseFs:o,overwrite:a})}else if(n.isFile()){if(!u||a){u&&this.removeSync(e);let p=o.readFileSync(r);this.writeFileSync(e,p)}}else if(n.isSymbolicLink()){if(!u||a){u&&this.removeSync(e);let p=o.readlinkSync(r);this.symlinkSync(DD(this.pathUtils,p),e)}}else throw new Error(`Unsupported file type (file: ${r}, mode: 0o${n.mode.toString(8).padStart(6,\"0\")})`);let A=n.mode&511;this.chmodSync(e,A)}async changeFilePromise(e,r,o={}){return Buffer.isBuffer(r)?this.changeFileBufferPromise(e,r,o):this.changeFileTextPromise(e,r,o)}async changeFileBufferPromise(e,r,{mode:o}={}){let a=Buffer.alloc(0);try{a=await this.readFilePromise(e)}catch{}Buffer.compare(a,r)!==0&&await this.writeFilePromise(e,r,{mode:o})}async changeFileTextPromise(e,r,{automaticNewlines:o,mode:a}={}){let n=\"\";try{n=await this.readFilePromise(e,\"utf8\")}catch{}let u=o?Hg(n,r):r;n!==u&&await this.writeFilePromise(e,u,{mode:a})}changeFileSync(e,r,o={}){return Buffer.isBuffer(r)?this.changeFileBufferSync(e,r,o):this.changeFileTextSync(e,r,o)}changeFileBufferSync(e,r,{mode:o}={}){let a=Buffer.alloc(0);try{a=this.readFileSync(e)}catch{}Buffer.compare(a,r)!==0&&this.writeFileSync(e,r,{mode:o})}changeFileTextSync(e,r,{automaticNewlines:o=!1,mode:a}={}){let n=\"\";try{n=this.readFileSync(e,\"utf8\")}catch{}let u=o?Hg(n,r):r;n!==u&&this.writeFileSync(e,u,{mode:a})}async movePromise(e,r){try{await this.renamePromise(e,r)}catch(o){if(o.code===\"EXDEV\")await this.copyPromise(r,e),await this.removePromise(e);else throw o}}moveSync(e,r){try{this.renameSync(e,r)}catch(o){if(o.code===\"EXDEV\")this.copySync(r,e),this.removeSync(e);else throw o}}async lockPromise(e,r){let o=`${e}.flock`,a=1e3/60,n=Date.now(),u=null,A=async()=>{let p;try{[p]=await this.readJsonPromise(o)}catch{return Date.now()-n<500}try{return process.kill(p,0),!0}catch{return!1}};for(;u===null;)try{u=await this.openPromise(o,\"wx\")}catch(p){if(p.code===\"EEXIST\"){if(!await A())try{await this.unlinkPromise(o);continue}catch{}if(Date.now()-n<60*1e3)await new Promise(h=>setTimeout(h,a));else throw new Error(`Couldn't acquire a lock in a reasonable time (via ${o})`)}else throw p}await this.writePromise(u,JSON.stringify([process.pid]));try{return await r()}finally{try{await this.closePromise(u),await this.unlinkPromise(o)}catch{}}}async readJsonPromise(e){let r=await this.readFilePromise(e,\"utf8\");try{return JSON.parse(r)}catch(o){throw o.message+=` (in ${e})`,o}}readJsonSync(e){let r=this.readFileSync(e,\"utf8\");try{return JSON.parse(r)}catch(o){throw o.message+=` (in ${e})`,o}}async writeJsonPromise(e,r,{compact:o=!1}={}){let a=o?0:2;return await this.writeFilePromise(e,`${JSON.stringify(r,null,a)}\n`)}writeJsonSync(e,r,{compact:o=!1}={}){let a=o?0:2;return this.writeFileSync(e,`${JSON.stringify(r,null,a)}\n`)}async preserveTimePromise(e,r){let o=await this.lstatPromise(e),a=await r();typeof a<\"u\"&&(e=a),await this.lutimesPromise(e,o.atime,o.mtime)}async preserveTimeSync(e,r){let o=this.lstatSync(e),a=r();typeof a<\"u\"&&(e=a),this.lutimesSync(e,o.atime,o.mtime)}},Uu=class extends gf{constructor(){super(z)}}});var Ps,df=Et(()=>{qg();Ps=class extends gf{getExtractHint(e){return this.baseFs.getExtractHint(e)}resolve(e){return this.mapFromBase(this.baseFs.resolve(this.mapToBase(e)))}getRealPath(){return this.mapFromBase(this.baseFs.getRealPath())}async openPromise(e,r,o){return this.baseFs.openPromise(this.mapToBase(e),r,o)}openSync(e,r,o){return this.baseFs.openSync(this.mapToBase(e),r,o)}async opendirPromise(e,r){return Object.assign(await this.baseFs.opendirPromise(this.mapToBase(e),r),{path:e})}opendirSync(e,r){return Object.assign(this.baseFs.opendirSync(this.mapToBase(e),r),{path:e})}async readPromise(e,r,o,a,n){return await this.baseFs.readPromise(e,r,o,a,n)}readSync(e,r,o,a,n){return this.baseFs.readSync(e,r,o,a,n)}async writePromise(e,r,o,a,n){return typeof r==\"string\"?await this.baseFs.writePromise(e,r,o):await this.baseFs.writePromise(e,r,o,a,n)}writeSync(e,r,o,a,n){return typeof r==\"string\"?this.baseFs.writeSync(e,r,o):this.baseFs.writeSync(e,r,o,a,n)}async closePromise(e){return this.baseFs.closePromise(e)}closeSync(e){this.baseFs.closeSync(e)}createReadStream(e,r){return this.baseFs.createReadStream(e!==null?this.mapToBase(e):e,r)}createWriteStream(e,r){return this.baseFs.createWriteStream(e!==null?this.mapToBase(e):e,r)}async realpathPromise(e){return this.mapFromBase(await this.baseFs.realpathPromise(this.mapToBase(e)))}realpathSync(e){return this.mapFromBase(this.baseFs.realpathSync(this.mapToBase(e)))}async existsPromise(e){return this.baseFs.existsPromise(this.mapToBase(e))}existsSync(e){return this.baseFs.existsSync(this.mapToBase(e))}accessSync(e,r){return this.baseFs.accessSync(this.mapToBase(e),r)}async accessPromise(e,r){return this.baseFs.accessPromise(this.mapToBase(e),r)}async statPromise(e,r){return this.baseFs.statPromise(this.mapToBase(e),r)}statSync(e,r){return this.baseFs.statSync(this.mapToBase(e),r)}async fstatPromise(e,r){return this.baseFs.fstatPromise(e,r)}fstatSync(e,r){return this.baseFs.fstatSync(e,r)}lstatPromise(e,r){return this.baseFs.lstatPromise(this.mapToBase(e),r)}lstatSync(e,r){return this.baseFs.lstatSync(this.mapToBase(e),r)}async fchmodPromise(e,r){return this.baseFs.fchmodPromise(e,r)}fchmodSync(e,r){return this.baseFs.fchmodSync(e,r)}async chmodPromise(e,r){return this.baseFs.chmodPromise(this.mapToBase(e),r)}chmodSync(e,r){return this.baseFs.chmodSync(this.mapToBase(e),r)}async fchownPromise(e,r,o){return this.baseFs.fchownPromise(e,r,o)}fchownSync(e,r,o){return this.baseFs.fchownSync(e,r,o)}async chownPromise(e,r,o){return this.baseFs.chownPromise(this.mapToBase(e),r,o)}chownSync(e,r,o){return this.baseFs.chownSync(this.mapToBase(e),r,o)}async renamePromise(e,r){return this.baseFs.renamePromise(this.mapToBase(e),this.mapToBase(r))}renameSync(e,r){return this.baseFs.renameSync(this.mapToBase(e),this.mapToBase(r))}async copyFilePromise(e,r,o=0){return this.baseFs.copyFilePromise(this.mapToBase(e),this.mapToBase(r),o)}copyFileSync(e,r,o=0){return this.baseFs.copyFileSync(this.mapToBase(e),this.mapToBase(r),o)}async appendFilePromise(e,r,o){return this.baseFs.appendFilePromise(this.fsMapToBase(e),r,o)}appendFileSync(e,r,o){return this.baseFs.appendFileSync(this.fsMapToBase(e),r,o)}async writeFilePromise(e,r,o){return this.baseFs.writeFilePromise(this.fsMapToBase(e),r,o)}writeFileSync(e,r,o){return this.baseFs.writeFileSync(this.fsMapToBase(e),r,o)}async unlinkPromise(e){return this.baseFs.unlinkPromise(this.mapToBase(e))}unlinkSync(e){return this.baseFs.unlinkSync(this.mapToBase(e))}async utimesPromise(e,r,o){return this.baseFs.utimesPromise(this.mapToBase(e),r,o)}utimesSync(e,r,o){return this.baseFs.utimesSync(this.mapToBase(e),r,o)}async lutimesPromise(e,r,o){return this.baseFs.lutimesPromise(this.mapToBase(e),r,o)}lutimesSync(e,r,o){return this.baseFs.lutimesSync(this.mapToBase(e),r,o)}async mkdirPromise(e,r){return this.baseFs.mkdirPromise(this.mapToBase(e),r)}mkdirSync(e,r){return this.baseFs.mkdirSync(this.mapToBase(e),r)}async rmdirPromise(e,r){return this.baseFs.rmdirPromise(this.mapToBase(e),r)}rmdirSync(e,r){return this.baseFs.rmdirSync(this.mapToBase(e),r)}async rmPromise(e,r){return this.baseFs.rmPromise(this.mapToBase(e),r)}rmSync(e,r){return this.baseFs.rmSync(this.mapToBase(e),r)}async linkPromise(e,r){return this.baseFs.linkPromise(this.mapToBase(e),this.mapToBase(r))}linkSync(e,r){return this.baseFs.linkSync(this.mapToBase(e),this.mapToBase(r))}async symlinkPromise(e,r,o){let a=this.mapToBase(r);if(this.pathUtils.isAbsolute(e))return this.baseFs.symlinkPromise(this.mapToBase(e),a,o);let n=this.mapToBase(this.pathUtils.join(this.pathUtils.dirname(r),e)),u=this.baseFs.pathUtils.relative(this.baseFs.pathUtils.dirname(a),n);return this.baseFs.symlinkPromise(u,a,o)}symlinkSync(e,r,o){let a=this.mapToBase(r);if(this.pathUtils.isAbsolute(e))return this.baseFs.symlinkSync(this.mapToBase(e),a,o);let n=this.mapToBase(this.pathUtils.join(this.pathUtils.dirname(r),e)),u=this.baseFs.pathUtils.relative(this.baseFs.pathUtils.dirname(a),n);return this.baseFs.symlinkSync(u,a,o)}async readFilePromise(e,r){return this.baseFs.readFilePromise(this.fsMapToBase(e),r)}readFileSync(e,r){return this.baseFs.readFileSync(this.fsMapToBase(e),r)}readdirPromise(e,r){return this.baseFs.readdirPromise(this.mapToBase(e),r)}readdirSync(e,r){return this.baseFs.readdirSync(this.mapToBase(e),r)}async readlinkPromise(e){return this.mapFromBase(await this.baseFs.readlinkPromise(this.mapToBase(e)))}readlinkSync(e){return this.mapFromBase(this.baseFs.readlinkSync(this.mapToBase(e)))}async truncatePromise(e,r){return this.baseFs.truncatePromise(this.mapToBase(e),r)}truncateSync(e,r){return this.baseFs.truncateSync(this.mapToBase(e),r)}async ftruncatePromise(e,r){return this.baseFs.ftruncatePromise(e,r)}ftruncateSync(e,r){return this.baseFs.ftruncateSync(e,r)}watch(e,r,o){return this.baseFs.watch(this.mapToBase(e),r,o)}watchFile(e,r,o){return this.baseFs.watchFile(this.mapToBase(e),r,o)}unwatchFile(e,r){return this.baseFs.unwatchFile(this.mapToBase(e),r)}fsMapToBase(e){return typeof e==\"number\"?e:this.mapToBase(e)}}});var _u,q7=Et(()=>{df();_u=class extends Ps{constructor(r,{baseFs:o,pathUtils:a}){super(a);this.target=r,this.baseFs=o}getRealPath(){return this.target}getBaseFs(){return this.baseFs}mapFromBase(r){return r}mapToBase(r){return r}}});function G7(t){let e=t;return typeof t.path==\"string\"&&(e.path=le.toPortablePath(t.path)),e}var j7,Tn,Gg=Et(()=>{j7=$e(ve(\"fs\"));qg();Ca();Tn=class extends Uu{constructor(r=j7.default){super();this.realFs=r}getExtractHint(){return!1}getRealPath(){return Bt.root}resolve(r){return z.resolve(r)}async openPromise(r,o,a){return await new Promise((n,u)=>{this.realFs.open(le.fromPortablePath(r),o,a,this.makeCallback(n,u))})}openSync(r,o,a){return this.realFs.openSync(le.fromPortablePath(r),o,a)}async opendirPromise(r,o){return await new Promise((a,n)=>{typeof o<\"u\"?this.realFs.opendir(le.fromPortablePath(r),o,this.makeCallback(a,n)):this.realFs.opendir(le.fromPortablePath(r),this.makeCallback(a,n))}).then(a=>{let n=a;return Object.defineProperty(n,\"path\",{value:r,configurable:!0,writable:!0}),n})}opendirSync(r,o){let n=typeof o<\"u\"?this.realFs.opendirSync(le.fromPortablePath(r),o):this.realFs.opendirSync(le.fromPortablePath(r));return Object.defineProperty(n,\"path\",{value:r,configurable:!0,writable:!0}),n}async readPromise(r,o,a=0,n=0,u=-1){return await new Promise((A,p)=>{this.realFs.read(r,o,a,n,u,(h,E)=>{h?p(h):A(E)})})}readSync(r,o,a,n,u){return this.realFs.readSync(r,o,a,n,u)}async writePromise(r,o,a,n,u){return await new Promise((A,p)=>typeof o==\"string\"?this.realFs.write(r,o,a,this.makeCallback(A,p)):this.realFs.write(r,o,a,n,u,this.makeCallback(A,p)))}writeSync(r,o,a,n,u){return typeof o==\"string\"?this.realFs.writeSync(r,o,a):this.realFs.writeSync(r,o,a,n,u)}async closePromise(r){await new Promise((o,a)=>{this.realFs.close(r,this.makeCallback(o,a))})}closeSync(r){this.realFs.closeSync(r)}createReadStream(r,o){let a=r!==null?le.fromPortablePath(r):r;return this.realFs.createReadStream(a,o)}createWriteStream(r,o){let a=r!==null?le.fromPortablePath(r):r;return this.realFs.createWriteStream(a,o)}async realpathPromise(r){return await new Promise((o,a)=>{this.realFs.realpath(le.fromPortablePath(r),{},this.makeCallback(o,a))}).then(o=>le.toPortablePath(o))}realpathSync(r){return le.toPortablePath(this.realFs.realpathSync(le.fromPortablePath(r),{}))}async existsPromise(r){return await new Promise(o=>{this.realFs.exists(le.fromPortablePath(r),o)})}accessSync(r,o){return this.realFs.accessSync(le.fromPortablePath(r),o)}async accessPromise(r,o){return await new Promise((a,n)=>{this.realFs.access(le.fromPortablePath(r),o,this.makeCallback(a,n))})}existsSync(r){return this.realFs.existsSync(le.fromPortablePath(r))}async statPromise(r,o){return await new Promise((a,n)=>{o?this.realFs.stat(le.fromPortablePath(r),o,this.makeCallback(a,n)):this.realFs.stat(le.fromPortablePath(r),this.makeCallback(a,n))})}statSync(r,o){return o?this.realFs.statSync(le.fromPortablePath(r),o):this.realFs.statSync(le.fromPortablePath(r))}async fstatPromise(r,o){return await new Promise((a,n)=>{o?this.realFs.fstat(r,o,this.makeCallback(a,n)):this.realFs.fstat(r,this.makeCallback(a,n))})}fstatSync(r,o){return o?this.realFs.fstatSync(r,o):this.realFs.fstatSync(r)}async lstatPromise(r,o){return await new Promise((a,n)=>{o?this.realFs.lstat(le.fromPortablePath(r),o,this.makeCallback(a,n)):this.realFs.lstat(le.fromPortablePath(r),this.makeCallback(a,n))})}lstatSync(r,o){return o?this.realFs.lstatSync(le.fromPortablePath(r),o):this.realFs.lstatSync(le.fromPortablePath(r))}async fchmodPromise(r,o){return await new Promise((a,n)=>{this.realFs.fchmod(r,o,this.makeCallback(a,n))})}fchmodSync(r,o){return this.realFs.fchmodSync(r,o)}async chmodPromise(r,o){return await new Promise((a,n)=>{this.realFs.chmod(le.fromPortablePath(r),o,this.makeCallback(a,n))})}chmodSync(r,o){return this.realFs.chmodSync(le.fromPortablePath(r),o)}async fchownPromise(r,o,a){return await new Promise((n,u)=>{this.realFs.fchown(r,o,a,this.makeCallback(n,u))})}fchownSync(r,o,a){return this.realFs.fchownSync(r,o,a)}async chownPromise(r,o,a){return await new Promise((n,u)=>{this.realFs.chown(le.fromPortablePath(r),o,a,this.makeCallback(n,u))})}chownSync(r,o,a){return this.realFs.chownSync(le.fromPortablePath(r),o,a)}async renamePromise(r,o){return await new Promise((a,n)=>{this.realFs.rename(le.fromPortablePath(r),le.fromPortablePath(o),this.makeCallback(a,n))})}renameSync(r,o){return this.realFs.renameSync(le.fromPortablePath(r),le.fromPortablePath(o))}async copyFilePromise(r,o,a=0){return await new Promise((n,u)=>{this.realFs.copyFile(le.fromPortablePath(r),le.fromPortablePath(o),a,this.makeCallback(n,u))})}copyFileSync(r,o,a=0){return this.realFs.copyFileSync(le.fromPortablePath(r),le.fromPortablePath(o),a)}async appendFilePromise(r,o,a){return await new Promise((n,u)=>{let A=typeof r==\"string\"?le.fromPortablePath(r):r;a?this.realFs.appendFile(A,o,a,this.makeCallback(n,u)):this.realFs.appendFile(A,o,this.makeCallback(n,u))})}appendFileSync(r,o,a){let n=typeof r==\"string\"?le.fromPortablePath(r):r;a?this.realFs.appendFileSync(n,o,a):this.realFs.appendFileSync(n,o)}async writeFilePromise(r,o,a){return await new Promise((n,u)=>{let A=typeof r==\"string\"?le.fromPortablePath(r):r;a?this.realFs.writeFile(A,o,a,this.makeCallback(n,u)):this.realFs.writeFile(A,o,this.makeCallback(n,u))})}writeFileSync(r,o,a){let n=typeof r==\"string\"?le.fromPortablePath(r):r;a?this.realFs.writeFileSync(n,o,a):this.realFs.writeFileSync(n,o)}async unlinkPromise(r){return await new Promise((o,a)=>{this.realFs.unlink(le.fromPortablePath(r),this.makeCallback(o,a))})}unlinkSync(r){return this.realFs.unlinkSync(le.fromPortablePath(r))}async utimesPromise(r,o,a){return await new Promise((n,u)=>{this.realFs.utimes(le.fromPortablePath(r),o,a,this.makeCallback(n,u))})}utimesSync(r,o,a){this.realFs.utimesSync(le.fromPortablePath(r),o,a)}async lutimesPromise(r,o,a){return await new Promise((n,u)=>{this.realFs.lutimes(le.fromPortablePath(r),o,a,this.makeCallback(n,u))})}lutimesSync(r,o,a){this.realFs.lutimesSync(le.fromPortablePath(r),o,a)}async mkdirPromise(r,o){return await new Promise((a,n)=>{this.realFs.mkdir(le.fromPortablePath(r),o,this.makeCallback(a,n))})}mkdirSync(r,o){return this.realFs.mkdirSync(le.fromPortablePath(r),o)}async rmdirPromise(r,o){return await new Promise((a,n)=>{o?this.realFs.rmdir(le.fromPortablePath(r),o,this.makeCallback(a,n)):this.realFs.rmdir(le.fromPortablePath(r),this.makeCallback(a,n))})}rmdirSync(r,o){return this.realFs.rmdirSync(le.fromPortablePath(r),o)}async rmPromise(r,o){return await new Promise((a,n)=>{o?this.realFs.rm(le.fromPortablePath(r),o,this.makeCallback(a,n)):this.realFs.rm(le.fromPortablePath(r),this.makeCallback(a,n))})}rmSync(r,o){return this.realFs.rmSync(le.fromPortablePath(r),o)}async linkPromise(r,o){return await new Promise((a,n)=>{this.realFs.link(le.fromPortablePath(r),le.fromPortablePath(o),this.makeCallback(a,n))})}linkSync(r,o){return this.realFs.linkSync(le.fromPortablePath(r),le.fromPortablePath(o))}async symlinkPromise(r,o,a){return await new Promise((n,u)=>{this.realFs.symlink(le.fromPortablePath(r.replace(/\\/+$/,\"\")),le.fromPortablePath(o),a,this.makeCallback(n,u))})}symlinkSync(r,o,a){return this.realFs.symlinkSync(le.fromPortablePath(r.replace(/\\/+$/,\"\")),le.fromPortablePath(o),a)}async readFilePromise(r,o){return await new Promise((a,n)=>{let u=typeof r==\"string\"?le.fromPortablePath(r):r;this.realFs.readFile(u,o,this.makeCallback(a,n))})}readFileSync(r,o){let a=typeof r==\"string\"?le.fromPortablePath(r):r;return this.realFs.readFileSync(a,o)}async readdirPromise(r,o){return await new Promise((a,n)=>{o?o.recursive&&process.platform===\"win32\"?o.withFileTypes?this.realFs.readdir(le.fromPortablePath(r),o,this.makeCallback(u=>a(u.map(G7)),n)):this.realFs.readdir(le.fromPortablePath(r),o,this.makeCallback(u=>a(u.map(le.toPortablePath)),n)):this.realFs.readdir(le.fromPortablePath(r),o,this.makeCallback(a,n)):this.realFs.readdir(le.fromPortablePath(r),this.makeCallback(a,n))})}readdirSync(r,o){return o?o.recursive&&process.platform===\"win32\"?o.withFileTypes?this.realFs.readdirSync(le.fromPortablePath(r),o).map(G7):this.realFs.readdirSync(le.fromPortablePath(r),o).map(le.toPortablePath):this.realFs.readdirSync(le.fromPortablePath(r),o):this.realFs.readdirSync(le.fromPortablePath(r))}async readlinkPromise(r){return await new Promise((o,a)=>{this.realFs.readlink(le.fromPortablePath(r),this.makeCallback(o,a))}).then(o=>le.toPortablePath(o))}readlinkSync(r){return le.toPortablePath(this.realFs.readlinkSync(le.fromPortablePath(r)))}async truncatePromise(r,o){return await new Promise((a,n)=>{this.realFs.truncate(le.fromPortablePath(r),o,this.makeCallback(a,n))})}truncateSync(r,o){return this.realFs.truncateSync(le.fromPortablePath(r),o)}async ftruncatePromise(r,o){return await new Promise((a,n)=>{this.realFs.ftruncate(r,o,this.makeCallback(a,n))})}ftruncateSync(r,o){return this.realFs.ftruncateSync(r,o)}watch(r,o,a){return this.realFs.watch(le.fromPortablePath(r),o,a)}watchFile(r,o,a){return this.realFs.watchFile(le.fromPortablePath(r),o,a)}unwatchFile(r,o){return this.realFs.unwatchFile(le.fromPortablePath(r),o)}makeCallback(r,o){return(a,n)=>{a?o(a):r(n)}}}});var gn,Y7=Et(()=>{Gg();df();Ca();gn=class extends Ps{constructor(r,{baseFs:o=new Tn}={}){super(z);this.target=this.pathUtils.normalize(r),this.baseFs=o}getRealPath(){return this.pathUtils.resolve(this.baseFs.getRealPath(),this.target)}resolve(r){return this.pathUtils.isAbsolute(r)?z.normalize(r):this.baseFs.resolve(z.join(this.target,r))}mapFromBase(r){return r}mapToBase(r){return this.pathUtils.isAbsolute(r)?r:this.pathUtils.join(this.target,r)}}});var W7,Hu,K7=Et(()=>{Gg();df();Ca();W7=Bt.root,Hu=class extends Ps{constructor(r,{baseFs:o=new Tn}={}){super(z);this.target=this.pathUtils.resolve(Bt.root,r),this.baseFs=o}getRealPath(){return this.pathUtils.resolve(this.baseFs.getRealPath(),this.pathUtils.relative(Bt.root,this.target))}getTarget(){return this.target}getBaseFs(){return this.baseFs}mapToBase(r){let o=this.pathUtils.normalize(r);if(this.pathUtils.isAbsolute(r))return this.pathUtils.resolve(this.target,this.pathUtils.relative(W7,r));if(o.match(/^\\.\\.\\/?/))throw new Error(`Resolving this path (${r}) would escape the jail`);return this.pathUtils.resolve(this.target,r)}mapFromBase(r){return this.pathUtils.resolve(W7,this.pathUtils.relative(this.target,r))}}});var iy,z7=Et(()=>{df();iy=class extends Ps{constructor(r,o){super(o);this.instance=null;this.factory=r}get baseFs(){return this.instance||(this.instance=this.factory()),this.instance}set baseFs(r){this.instance=r}mapFromBase(r){return r}mapToBase(r){return r}}});var jg,wa,qp,V7=Et(()=>{jg=ve(\"fs\");qg();Gg();YR();BD();Ca();wa=4278190080,qp=class extends Uu{constructor({baseFs:r=new Tn,filter:o=null,magicByte:a=42,maxOpenFiles:n=1/0,useCache:u=!0,maxAge:A=5e3,typeCheck:p=jg.constants.S_IFREG,getMountPoint:h,factoryPromise:E,factorySync:I}){if(Math.floor(a)!==a||!(a>1&&a<=127))throw new Error(\"The magic byte must be set to a round value between 1 and 127 included\");super();this.fdMap=new Map;this.nextFd=3;this.isMount=new Set;this.notMount=new Set;this.realPaths=new Map;this.limitOpenFilesTimeout=null;this.baseFs=r,this.mountInstances=u?new Map:null,this.factoryPromise=E,this.factorySync=I,this.filter=o,this.getMountPoint=h,this.magic=a<<24,this.maxAge=A,this.maxOpenFiles=n,this.typeCheck=p}getExtractHint(r){return this.baseFs.getExtractHint(r)}getRealPath(){return this.baseFs.getRealPath()}saveAndClose(){if(_g(this),this.mountInstances)for(let[r,{childFs:o}]of this.mountInstances.entries())o.saveAndClose?.(),this.mountInstances.delete(r)}discardAndClose(){if(_g(this),this.mountInstances)for(let[r,{childFs:o}]of this.mountInstances.entries())o.discardAndClose?.(),this.mountInstances.delete(r)}resolve(r){return this.baseFs.resolve(r)}remapFd(r,o){let a=this.nextFd++|this.magic;return this.fdMap.set(a,[r,o]),a}async openPromise(r,o,a){return await this.makeCallPromise(r,async()=>await this.baseFs.openPromise(r,o,a),async(n,{subPath:u})=>this.remapFd(n,await n.openPromise(u,o,a)))}openSync(r,o,a){return this.makeCallSync(r,()=>this.baseFs.openSync(r,o,a),(n,{subPath:u})=>this.remapFd(n,n.openSync(u,o,a)))}async opendirPromise(r,o){return await this.makeCallPromise(r,async()=>await this.baseFs.opendirPromise(r,o),async(a,{subPath:n})=>await a.opendirPromise(n,o),{requireSubpath:!1})}opendirSync(r,o){return this.makeCallSync(r,()=>this.baseFs.opendirSync(r,o),(a,{subPath:n})=>a.opendirSync(n,o),{requireSubpath:!1})}async readPromise(r,o,a,n,u){if((r&wa)!==this.magic)return await this.baseFs.readPromise(r,o,a,n,u);let A=this.fdMap.get(r);if(typeof A>\"u\")throw Io(\"read\");let[p,h]=A;return await p.readPromise(h,o,a,n,u)}readSync(r,o,a,n,u){if((r&wa)!==this.magic)return this.baseFs.readSync(r,o,a,n,u);let A=this.fdMap.get(r);if(typeof A>\"u\")throw Io(\"readSync\");let[p,h]=A;return p.readSync(h,o,a,n,u)}async writePromise(r,o,a,n,u){if((r&wa)!==this.magic)return typeof o==\"string\"?await this.baseFs.writePromise(r,o,a):await this.baseFs.writePromise(r,o,a,n,u);let A=this.fdMap.get(r);if(typeof A>\"u\")throw Io(\"write\");let[p,h]=A;return typeof o==\"string\"?await p.writePromise(h,o,a):await p.writePromise(h,o,a,n,u)}writeSync(r,o,a,n,u){if((r&wa)!==this.magic)return typeof o==\"string\"?this.baseFs.writeSync(r,o,a):this.baseFs.writeSync(r,o,a,n,u);let A=this.fdMap.get(r);if(typeof A>\"u\")throw Io(\"writeSync\");let[p,h]=A;return typeof o==\"string\"?p.writeSync(h,o,a):p.writeSync(h,o,a,n,u)}async closePromise(r){if((r&wa)!==this.magic)return await this.baseFs.closePromise(r);let o=this.fdMap.get(r);if(typeof o>\"u\")throw Io(\"close\");this.fdMap.delete(r);let[a,n]=o;return await a.closePromise(n)}closeSync(r){if((r&wa)!==this.magic)return this.baseFs.closeSync(r);let o=this.fdMap.get(r);if(typeof o>\"u\")throw Io(\"closeSync\");this.fdMap.delete(r);let[a,n]=o;return a.closeSync(n)}createReadStream(r,o){return r===null?this.baseFs.createReadStream(r,o):this.makeCallSync(r,()=>this.baseFs.createReadStream(r,o),(a,{archivePath:n,subPath:u})=>{let A=a.createReadStream(u,o);return A.path=le.fromPortablePath(this.pathUtils.join(n,u)),A})}createWriteStream(r,o){return r===null?this.baseFs.createWriteStream(r,o):this.makeCallSync(r,()=>this.baseFs.createWriteStream(r,o),(a,{subPath:n})=>a.createWriteStream(n,o))}async realpathPromise(r){return await this.makeCallPromise(r,async()=>await this.baseFs.realpathPromise(r),async(o,{archivePath:a,subPath:n})=>{let u=this.realPaths.get(a);return typeof u>\"u\"&&(u=await this.baseFs.realpathPromise(a),this.realPaths.set(a,u)),this.pathUtils.join(u,this.pathUtils.relative(Bt.root,await o.realpathPromise(n)))})}realpathSync(r){return this.makeCallSync(r,()=>this.baseFs.realpathSync(r),(o,{archivePath:a,subPath:n})=>{let u=this.realPaths.get(a);return typeof u>\"u\"&&(u=this.baseFs.realpathSync(a),this.realPaths.set(a,u)),this.pathUtils.join(u,this.pathUtils.relative(Bt.root,o.realpathSync(n)))})}async existsPromise(r){return await this.makeCallPromise(r,async()=>await this.baseFs.existsPromise(r),async(o,{subPath:a})=>await o.existsPromise(a))}existsSync(r){return this.makeCallSync(r,()=>this.baseFs.existsSync(r),(o,{subPath:a})=>o.existsSync(a))}async accessPromise(r,o){return await this.makeCallPromise(r,async()=>await this.baseFs.accessPromise(r,o),async(a,{subPath:n})=>await a.accessPromise(n,o))}accessSync(r,o){return this.makeCallSync(r,()=>this.baseFs.accessSync(r,o),(a,{subPath:n})=>a.accessSync(n,o))}async statPromise(r,o){return await this.makeCallPromise(r,async()=>await this.baseFs.statPromise(r,o),async(a,{subPath:n})=>await a.statPromise(n,o))}statSync(r,o){return this.makeCallSync(r,()=>this.baseFs.statSync(r,o),(a,{subPath:n})=>a.statSync(n,o))}async fstatPromise(r,o){if((r&wa)!==this.magic)return this.baseFs.fstatPromise(r,o);let a=this.fdMap.get(r);if(typeof a>\"u\")throw Io(\"fstat\");let[n,u]=a;return n.fstatPromise(u,o)}fstatSync(r,o){if((r&wa)!==this.magic)return this.baseFs.fstatSync(r,o);let a=this.fdMap.get(r);if(typeof a>\"u\")throw Io(\"fstatSync\");let[n,u]=a;return n.fstatSync(u,o)}async lstatPromise(r,o){return await this.makeCallPromise(r,async()=>await this.baseFs.lstatPromise(r,o),async(a,{subPath:n})=>await a.lstatPromise(n,o))}lstatSync(r,o){return this.makeCallSync(r,()=>this.baseFs.lstatSync(r,o),(a,{subPath:n})=>a.lstatSync(n,o))}async fchmodPromise(r,o){if((r&wa)!==this.magic)return this.baseFs.fchmodPromise(r,o);let a=this.fdMap.get(r);if(typeof a>\"u\")throw Io(\"fchmod\");let[n,u]=a;return n.fchmodPromise(u,o)}fchmodSync(r,o){if((r&wa)!==this.magic)return this.baseFs.fchmodSync(r,o);let a=this.fdMap.get(r);if(typeof a>\"u\")throw Io(\"fchmodSync\");let[n,u]=a;return n.fchmodSync(u,o)}async chmodPromise(r,o){return await this.makeCallPromise(r,async()=>await this.baseFs.chmodPromise(r,o),async(a,{subPath:n})=>await a.chmodPromise(n,o))}chmodSync(r,o){return this.makeCallSync(r,()=>this.baseFs.chmodSync(r,o),(a,{subPath:n})=>a.chmodSync(n,o))}async fchownPromise(r,o,a){if((r&wa)!==this.magic)return this.baseFs.fchownPromise(r,o,a);let n=this.fdMap.get(r);if(typeof n>\"u\")throw Io(\"fchown\");let[u,A]=n;return u.fchownPromise(A,o,a)}fchownSync(r,o,a){if((r&wa)!==this.magic)return this.baseFs.fchownSync(r,o,a);let n=this.fdMap.get(r);if(typeof n>\"u\")throw Io(\"fchownSync\");let[u,A]=n;return u.fchownSync(A,o,a)}async chownPromise(r,o,a){return await this.makeCallPromise(r,async()=>await this.baseFs.chownPromise(r,o,a),async(n,{subPath:u})=>await n.chownPromise(u,o,a))}chownSync(r,o,a){return this.makeCallSync(r,()=>this.baseFs.chownSync(r,o,a),(n,{subPath:u})=>n.chownSync(u,o,a))}async renamePromise(r,o){return await this.makeCallPromise(r,async()=>await this.makeCallPromise(o,async()=>await this.baseFs.renamePromise(r,o),async()=>{throw Object.assign(new Error(\"EEXDEV: cross-device link not permitted\"),{code:\"EEXDEV\"})}),async(a,{subPath:n})=>await this.makeCallPromise(o,async()=>{throw Object.assign(new Error(\"EEXDEV: cross-device link not permitted\"),{code:\"EEXDEV\"})},async(u,{subPath:A})=>{if(a!==u)throw Object.assign(new Error(\"EEXDEV: cross-device link not permitted\"),{code:\"EEXDEV\"});return await a.renamePromise(n,A)}))}renameSync(r,o){return this.makeCallSync(r,()=>this.makeCallSync(o,()=>this.baseFs.renameSync(r,o),()=>{throw Object.assign(new Error(\"EEXDEV: cross-device link not permitted\"),{code:\"EEXDEV\"})}),(a,{subPath:n})=>this.makeCallSync(o,()=>{throw Object.assign(new Error(\"EEXDEV: cross-device link not permitted\"),{code:\"EEXDEV\"})},(u,{subPath:A})=>{if(a!==u)throw Object.assign(new Error(\"EEXDEV: cross-device link not permitted\"),{code:\"EEXDEV\"});return a.renameSync(n,A)}))}async copyFilePromise(r,o,a=0){let n=async(u,A,p,h)=>{if((a&jg.constants.COPYFILE_FICLONE_FORCE)!==0)throw Object.assign(new Error(`EXDEV: cross-device clone not permitted, copyfile '${A}' -> ${h}'`),{code:\"EXDEV\"});if(a&jg.constants.COPYFILE_EXCL&&await this.existsPromise(A))throw Object.assign(new Error(`EEXIST: file already exists, copyfile '${A}' -> '${h}'`),{code:\"EEXIST\"});let E;try{E=await u.readFilePromise(A)}catch{throw Object.assign(new Error(`EINVAL: invalid argument, copyfile '${A}' -> '${h}'`),{code:\"EINVAL\"})}await p.writeFilePromise(h,E)};return await this.makeCallPromise(r,async()=>await this.makeCallPromise(o,async()=>await this.baseFs.copyFilePromise(r,o,a),async(u,{subPath:A})=>await n(this.baseFs,r,u,A)),async(u,{subPath:A})=>await this.makeCallPromise(o,async()=>await n(u,A,this.baseFs,o),async(p,{subPath:h})=>u!==p?await n(u,A,p,h):await u.copyFilePromise(A,h,a)))}copyFileSync(r,o,a=0){let n=(u,A,p,h)=>{if((a&jg.constants.COPYFILE_FICLONE_FORCE)!==0)throw Object.assign(new Error(`EXDEV: cross-device clone not permitted, copyfile '${A}' -> ${h}'`),{code:\"EXDEV\"});if(a&jg.constants.COPYFILE_EXCL&&this.existsSync(A))throw Object.assign(new Error(`EEXIST: file already exists, copyfile '${A}' -> '${h}'`),{code:\"EEXIST\"});let E;try{E=u.readFileSync(A)}catch{throw Object.assign(new Error(`EINVAL: invalid argument, copyfile '${A}' -> '${h}'`),{code:\"EINVAL\"})}p.writeFileSync(h,E)};return this.makeCallSync(r,()=>this.makeCallSync(o,()=>this.baseFs.copyFileSync(r,o,a),(u,{subPath:A})=>n(this.baseFs,r,u,A)),(u,{subPath:A})=>this.makeCallSync(o,()=>n(u,A,this.baseFs,o),(p,{subPath:h})=>u!==p?n(u,A,p,h):u.copyFileSync(A,h,a)))}async appendFilePromise(r,o,a){return await this.makeCallPromise(r,async()=>await this.baseFs.appendFilePromise(r,o,a),async(n,{subPath:u})=>await n.appendFilePromise(u,o,a))}appendFileSync(r,o,a){return this.makeCallSync(r,()=>this.baseFs.appendFileSync(r,o,a),(n,{subPath:u})=>n.appendFileSync(u,o,a))}async writeFilePromise(r,o,a){return await this.makeCallPromise(r,async()=>await this.baseFs.writeFilePromise(r,o,a),async(n,{subPath:u})=>await n.writeFilePromise(u,o,a))}writeFileSync(r,o,a){return this.makeCallSync(r,()=>this.baseFs.writeFileSync(r,o,a),(n,{subPath:u})=>n.writeFileSync(u,o,a))}async unlinkPromise(r){return await this.makeCallPromise(r,async()=>await this.baseFs.unlinkPromise(r),async(o,{subPath:a})=>await o.unlinkPromise(a))}unlinkSync(r){return this.makeCallSync(r,()=>this.baseFs.unlinkSync(r),(o,{subPath:a})=>o.unlinkSync(a))}async utimesPromise(r,o,a){return await this.makeCallPromise(r,async()=>await this.baseFs.utimesPromise(r,o,a),async(n,{subPath:u})=>await n.utimesPromise(u,o,a))}utimesSync(r,o,a){return this.makeCallSync(r,()=>this.baseFs.utimesSync(r,o,a),(n,{subPath:u})=>n.utimesSync(u,o,a))}async lutimesPromise(r,o,a){return await this.makeCallPromise(r,async()=>await this.baseFs.lutimesPromise(r,o,a),async(n,{subPath:u})=>await n.lutimesPromise(u,o,a))}lutimesSync(r,o,a){return this.makeCallSync(r,()=>this.baseFs.lutimesSync(r,o,a),(n,{subPath:u})=>n.lutimesSync(u,o,a))}async mkdirPromise(r,o){return await this.makeCallPromise(r,async()=>await this.baseFs.mkdirPromise(r,o),async(a,{subPath:n})=>await a.mkdirPromise(n,o))}mkdirSync(r,o){return this.makeCallSync(r,()=>this.baseFs.mkdirSync(r,o),(a,{subPath:n})=>a.mkdirSync(n,o))}async rmdirPromise(r,o){return await this.makeCallPromise(r,async()=>await this.baseFs.rmdirPromise(r,o),async(a,{subPath:n})=>await a.rmdirPromise(n,o))}rmdirSync(r,o){return this.makeCallSync(r,()=>this.baseFs.rmdirSync(r,o),(a,{subPath:n})=>a.rmdirSync(n,o))}async rmPromise(r,o){return await this.makeCallPromise(r,async()=>await this.baseFs.rmPromise(r,o),async(a,{subPath:n})=>await a.rmPromise(n,o))}rmSync(r,o){return this.makeCallSync(r,()=>this.baseFs.rmSync(r,o),(a,{subPath:n})=>a.rmSync(n,o))}async linkPromise(r,o){return await this.makeCallPromise(o,async()=>await this.baseFs.linkPromise(r,o),async(a,{subPath:n})=>await a.linkPromise(r,n))}linkSync(r,o){return this.makeCallSync(o,()=>this.baseFs.linkSync(r,o),(a,{subPath:n})=>a.linkSync(r,n))}async symlinkPromise(r,o,a){return await this.makeCallPromise(o,async()=>await this.baseFs.symlinkPromise(r,o,a),async(n,{subPath:u})=>await n.symlinkPromise(r,u))}symlinkSync(r,o,a){return this.makeCallSync(o,()=>this.baseFs.symlinkSync(r,o,a),(n,{subPath:u})=>n.symlinkSync(r,u))}async readFilePromise(r,o){return this.makeCallPromise(r,async()=>await this.baseFs.readFilePromise(r,o),async(a,{subPath:n})=>await a.readFilePromise(n,o))}readFileSync(r,o){return this.makeCallSync(r,()=>this.baseFs.readFileSync(r,o),(a,{subPath:n})=>a.readFileSync(n,o))}async readdirPromise(r,o){return await this.makeCallPromise(r,async()=>await this.baseFs.readdirPromise(r,o),async(a,{subPath:n})=>await a.readdirPromise(n,o),{requireSubpath:!1})}readdirSync(r,o){return this.makeCallSync(r,()=>this.baseFs.readdirSync(r,o),(a,{subPath:n})=>a.readdirSync(n,o),{requireSubpath:!1})}async readlinkPromise(r){return await this.makeCallPromise(r,async()=>await this.baseFs.readlinkPromise(r),async(o,{subPath:a})=>await o.readlinkPromise(a))}readlinkSync(r){return this.makeCallSync(r,()=>this.baseFs.readlinkSync(r),(o,{subPath:a})=>o.readlinkSync(a))}async truncatePromise(r,o){return await this.makeCallPromise(r,async()=>await this.baseFs.truncatePromise(r,o),async(a,{subPath:n})=>await a.truncatePromise(n,o))}truncateSync(r,o){return this.makeCallSync(r,()=>this.baseFs.truncateSync(r,o),(a,{subPath:n})=>a.truncateSync(n,o))}async ftruncatePromise(r,o){if((r&wa)!==this.magic)return this.baseFs.ftruncatePromise(r,o);let a=this.fdMap.get(r);if(typeof a>\"u\")throw Io(\"ftruncate\");let[n,u]=a;return n.ftruncatePromise(u,o)}ftruncateSync(r,o){if((r&wa)!==this.magic)return this.baseFs.ftruncateSync(r,o);let a=this.fdMap.get(r);if(typeof a>\"u\")throw Io(\"ftruncateSync\");let[n,u]=a;return n.ftruncateSync(u,o)}watch(r,o,a){return this.makeCallSync(r,()=>this.baseFs.watch(r,o,a),(n,{subPath:u})=>n.watch(u,o,a))}watchFile(r,o,a){return this.makeCallSync(r,()=>this.baseFs.watchFile(r,o,a),()=>ny(this,r,o,a))}unwatchFile(r,o){return this.makeCallSync(r,()=>this.baseFs.unwatchFile(r,o),()=>Ug(this,r,o))}async makeCallPromise(r,o,a,{requireSubpath:n=!0}={}){if(typeof r!=\"string\")return await o();let u=this.resolve(r),A=this.findMount(u);return A?n&&A.subPath===\"/\"?await o():await this.getMountPromise(A.archivePath,async p=>await a(p,A)):await o()}makeCallSync(r,o,a,{requireSubpath:n=!0}={}){if(typeof r!=\"string\")return o();let u=this.resolve(r),A=this.findMount(u);return!A||n&&A.subPath===\"/\"?o():this.getMountSync(A.archivePath,p=>a(p,A))}findMount(r){if(this.filter&&!this.filter.test(r))return null;let o=\"\";for(;;){let a=r.substring(o.length),n=this.getMountPoint(a,o);if(!n)return null;if(o=this.pathUtils.join(o,n),!this.isMount.has(o)){if(this.notMount.has(o))continue;try{if(this.typeCheck!==null&&(this.baseFs.lstatSync(o).mode&jg.constants.S_IFMT)!==this.typeCheck){this.notMount.add(o);continue}}catch{return null}this.isMount.add(o)}return{archivePath:o,subPath:this.pathUtils.join(Bt.root,r.substring(o.length))}}}limitOpenFiles(r){if(this.mountInstances===null)return;let o=Date.now(),a=o+this.maxAge,n=r===null?0:this.mountInstances.size-r;for(let[u,{childFs:A,expiresAt:p,refCount:h}]of this.mountInstances.entries())if(!(h!==0||A.hasOpenFileHandles?.())){if(o>=p){A.saveAndClose?.(),this.mountInstances.delete(u),n-=1;continue}else if(r===null||n<=0){a=p;break}A.saveAndClose?.(),this.mountInstances.delete(u),n-=1}this.limitOpenFilesTimeout===null&&(r===null&&this.mountInstances.size>0||r!==null)&&isFinite(a)&&(this.limitOpenFilesTimeout=setTimeout(()=>{this.limitOpenFilesTimeout=null,this.limitOpenFiles(null)},a-o).unref())}async getMountPromise(r,o){if(this.mountInstances){let a=this.mountInstances.get(r);if(!a){let n=await this.factoryPromise(this.baseFs,r);a=this.mountInstances.get(r),a||(a={childFs:n(),expiresAt:0,refCount:0})}this.mountInstances.delete(r),this.limitOpenFiles(this.maxOpenFiles-1),this.mountInstances.set(r,a),a.expiresAt=Date.now()+this.maxAge,a.refCount+=1;try{return await o(a.childFs)}finally{a.refCount-=1}}else{let a=(await this.factoryPromise(this.baseFs,r))();try{return await o(a)}finally{a.saveAndClose?.()}}}getMountSync(r,o){if(this.mountInstances){let a=this.mountInstances.get(r);return a||(a={childFs:this.factorySync(this.baseFs,r),expiresAt:0,refCount:0}),this.mountInstances.delete(r),this.limitOpenFiles(this.maxOpenFiles-1),this.mountInstances.set(r,a),a.expiresAt=Date.now()+this.maxAge,o(a.childFs)}else{let a=this.factorySync(this.baseFs,r);try{return o(a)}finally{a.saveAndClose?.()}}}}});var Zt,WR,Yw,J7=Et(()=>{qg();Ca();Zt=()=>Object.assign(new Error(\"ENOSYS: unsupported filesystem access\"),{code:\"ENOSYS\"}),WR=class extends gf{constructor(){super(z)}getExtractHint(){throw Zt()}getRealPath(){throw Zt()}resolve(){throw Zt()}async openPromise(){throw Zt()}openSync(){throw Zt()}async opendirPromise(){throw Zt()}opendirSync(){throw Zt()}async readPromise(){throw Zt()}readSync(){throw Zt()}async writePromise(){throw Zt()}writeSync(){throw Zt()}async closePromise(){throw Zt()}closeSync(){throw Zt()}createWriteStream(){throw Zt()}createReadStream(){throw Zt()}async realpathPromise(){throw Zt()}realpathSync(){throw Zt()}async readdirPromise(){throw Zt()}readdirSync(){throw Zt()}async existsPromise(e){throw Zt()}existsSync(e){throw Zt()}async accessPromise(){throw Zt()}accessSync(){throw Zt()}async statPromise(){throw Zt()}statSync(){throw Zt()}async fstatPromise(e){throw Zt()}fstatSync(e){throw Zt()}async lstatPromise(e){throw Zt()}lstatSync(e){throw Zt()}async fchmodPromise(){throw Zt()}fchmodSync(){throw Zt()}async chmodPromise(){throw Zt()}chmodSync(){throw Zt()}async fchownPromise(){throw Zt()}fchownSync(){throw Zt()}async chownPromise(){throw Zt()}chownSync(){throw Zt()}async mkdirPromise(){throw Zt()}mkdirSync(){throw Zt()}async rmdirPromise(){throw Zt()}rmdirSync(){throw Zt()}async rmPromise(){throw Zt()}rmSync(){throw Zt()}async linkPromise(){throw Zt()}linkSync(){throw Zt()}async symlinkPromise(){throw Zt()}symlinkSync(){throw Zt()}async renamePromise(){throw Zt()}renameSync(){throw Zt()}async copyFilePromise(){throw Zt()}copyFileSync(){throw Zt()}async appendFilePromise(){throw Zt()}appendFileSync(){throw Zt()}async writeFilePromise(){throw Zt()}writeFileSync(){throw Zt()}async unlinkPromise(){throw Zt()}unlinkSync(){throw Zt()}async utimesPromise(){throw Zt()}utimesSync(){throw Zt()}async lutimesPromise(){throw Zt()}lutimesSync(){throw Zt()}async readFilePromise(){throw Zt()}readFileSync(){throw Zt()}async readlinkPromise(){throw Zt()}readlinkSync(){throw Zt()}async truncatePromise(){throw Zt()}truncateSync(){throw Zt()}async ftruncatePromise(e,r){throw Zt()}ftruncateSync(e,r){throw Zt()}watch(){throw Zt()}watchFile(){throw Zt()}unwatchFile(){throw Zt()}},Yw=WR;Yw.instance=new WR});var Gp,X7=Et(()=>{df();Ca();Gp=class extends Ps{constructor(r){super(le);this.baseFs=r}mapFromBase(r){return le.fromPortablePath(r)}mapToBase(r){return le.toPortablePath(r)}}});var k_e,KR,Q_e,mi,Z7=Et(()=>{Gg();df();Ca();k_e=/^[0-9]+$/,KR=/^(\\/(?:[^/]+\\/)*?(?:\\$\\$virtual|__virtual__))((?:\\/((?:[^/]+-)?[a-f0-9]+)(?:\\/([^/]+))?)?((?:\\/.*)?))$/,Q_e=/^([^/]+-)?[a-f0-9]+$/,mi=class extends Ps{constructor({baseFs:r=new Tn}={}){super(z);this.baseFs=r}static makeVirtualPath(r,o,a){if(z.basename(r)!==\"__virtual__\")throw new Error('Assertion failed: Virtual folders must be named \"__virtual__\"');if(!z.basename(o).match(Q_e))throw new Error(\"Assertion failed: Virtual components must be ended by an hexadecimal hash\");let u=z.relative(z.dirname(r),a).split(\"/\"),A=0;for(;A<u.length&&u[A]===\"..\";)A+=1;let p=u.slice(A);return z.join(r,o,String(A),...p)}static resolveVirtual(r){let o=r.match(KR);if(!o||!o[3]&&o[5])return r;let a=z.dirname(o[1]);if(!o[3]||!o[4])return a;if(!k_e.test(o[4]))return r;let u=Number(o[4]),A=\"../\".repeat(u),p=o[5]||\".\";return mi.resolveVirtual(z.join(a,A,p))}getExtractHint(r){return this.baseFs.getExtractHint(r)}getRealPath(){return this.baseFs.getRealPath()}realpathSync(r){let o=r.match(KR);if(!o)return this.baseFs.realpathSync(r);if(!o[5])return r;let a=this.baseFs.realpathSync(this.mapToBase(r));return mi.makeVirtualPath(o[1],o[3],a)}async realpathPromise(r){let o=r.match(KR);if(!o)return await this.baseFs.realpathPromise(r);if(!o[5])return r;let a=await this.baseFs.realpathPromise(this.mapToBase(r));return mi.makeVirtualPath(o[1],o[3],a)}mapToBase(r){if(r===\"\")return r;if(this.pathUtils.isAbsolute(r))return mi.resolveVirtual(r);let o=mi.resolveVirtual(this.baseFs.resolve(Bt.dot)),a=mi.resolveVirtual(this.baseFs.resolve(r));return z.relative(o,a)||Bt.dot}mapFromBase(r){return r}}});function F_e(t,e){return typeof zR.default.isUtf8<\"u\"?zR.default.isUtf8(t):Buffer.byteLength(e)===t.byteLength}var zR,$7,eY,xD,tY=Et(()=>{zR=$e(ve(\"buffer\")),$7=ve(\"url\"),eY=ve(\"util\");df();Ca();xD=class extends Ps{constructor(r){super(le);this.baseFs=r}mapFromBase(r){return r}mapToBase(r){if(typeof r==\"string\")return r;if(r instanceof URL)return(0,$7.fileURLToPath)(r);if(Buffer.isBuffer(r)){let o=r.toString();if(!F_e(r,o))throw new Error(\"Non-utf8 buffers are not supported at the moment. Please upvote the following issue if you encounter this error: https://github.com/yarnpkg/berry/issues/4942\");return o}throw new Error(`Unsupported path type: ${(0,eY.inspect)(r)}`)}}});var rY,Bo,mf,jp,kD,QD,sy,Lc,Nc,R_e,T_e,L_e,N_e,Ww,nY=Et(()=>{rY=ve(\"readline\"),Bo=Symbol(\"kBaseFs\"),mf=Symbol(\"kFd\"),jp=Symbol(\"kClosePromise\"),kD=Symbol(\"kCloseResolve\"),QD=Symbol(\"kCloseReject\"),sy=Symbol(\"kRefs\"),Lc=Symbol(\"kRef\"),Nc=Symbol(\"kUnref\"),Ww=class{constructor(e,r){this[R_e]=1;this[T_e]=void 0;this[L_e]=void 0;this[N_e]=void 0;this[Bo]=r,this[mf]=e}get fd(){return this[mf]}async appendFile(e,r){try{this[Lc](this.appendFile);let o=(typeof r==\"string\"?r:r?.encoding)??void 0;return await this[Bo].appendFilePromise(this.fd,e,o?{encoding:o}:void 0)}finally{this[Nc]()}}async chown(e,r){try{return this[Lc](this.chown),await this[Bo].fchownPromise(this.fd,e,r)}finally{this[Nc]()}}async chmod(e){try{return this[Lc](this.chmod),await this[Bo].fchmodPromise(this.fd,e)}finally{this[Nc]()}}createReadStream(e){return this[Bo].createReadStream(null,{...e,fd:this.fd})}createWriteStream(e){return this[Bo].createWriteStream(null,{...e,fd:this.fd})}datasync(){throw new Error(\"Method not implemented.\")}sync(){throw new Error(\"Method not implemented.\")}async read(e,r,o,a){try{this[Lc](this.read);let n;return Buffer.isBuffer(e)?n=e:(e??={},n=e.buffer??Buffer.alloc(16384),r=e.offset||0,o=e.length??n.byteLength,a=e.position??null),r??=0,o??=0,o===0?{bytesRead:o,buffer:n}:{bytesRead:await this[Bo].readPromise(this.fd,n,r,o,a),buffer:n}}finally{this[Nc]()}}async readFile(e){try{this[Lc](this.readFile);let r=(typeof e==\"string\"?e:e?.encoding)??void 0;return await this[Bo].readFilePromise(this.fd,r)}finally{this[Nc]()}}readLines(e){return(0,rY.createInterface)({input:this.createReadStream(e),crlfDelay:1/0})}async stat(e){try{return this[Lc](this.stat),await this[Bo].fstatPromise(this.fd,e)}finally{this[Nc]()}}async truncate(e){try{return this[Lc](this.truncate),await this[Bo].ftruncatePromise(this.fd,e)}finally{this[Nc]()}}utimes(e,r){throw new Error(\"Method not implemented.\")}async writeFile(e,r){try{this[Lc](this.writeFile);let o=(typeof r==\"string\"?r:r?.encoding)??void 0;await this[Bo].writeFilePromise(this.fd,e,o)}finally{this[Nc]()}}async write(...e){try{if(this[Lc](this.write),ArrayBuffer.isView(e[0])){let[r,o,a,n]=e;return{bytesWritten:await this[Bo].writePromise(this.fd,r,o??void 0,a??void 0,n??void 0),buffer:r}}else{let[r,o,a]=e;return{bytesWritten:await this[Bo].writePromise(this.fd,r,o,a),buffer:r}}}finally{this[Nc]()}}async writev(e,r){try{this[Lc](this.writev);let o=0;if(typeof r<\"u\")for(let a of e){let n=await this.write(a,void 0,void 0,r);o+=n.bytesWritten,r+=n.bytesWritten}else for(let a of e){let n=await this.write(a);o+=n.bytesWritten}return{buffers:e,bytesWritten:o}}finally{this[Nc]()}}readv(e,r){throw new Error(\"Method not implemented.\")}close(){if(this[mf]===-1)return Promise.resolve();if(this[jp])return this[jp];if(this[sy]--,this[sy]===0){let e=this[mf];this[mf]=-1,this[jp]=this[Bo].closePromise(e).finally(()=>{this[jp]=void 0})}else this[jp]=new Promise((e,r)=>{this[kD]=e,this[QD]=r}).finally(()=>{this[jp]=void 0,this[QD]=void 0,this[kD]=void 0});return this[jp]}[(Bo,mf,R_e=sy,T_e=jp,L_e=kD,N_e=QD,Lc)](e){if(this[mf]===-1){let r=new Error(\"file closed\");throw r.code=\"EBADF\",r.syscall=e.name,r}this[sy]++}[Nc](){if(this[sy]--,this[sy]===0){let e=this[mf];this[mf]=-1,this[Bo].closePromise(e).then(this[kD],this[QD])}}}});function Kw(t,e){e=new xD(e);let r=(o,a,n)=>{let u=o[a];o[a]=n,typeof u?.[oy.promisify.custom]<\"u\"&&(n[oy.promisify.custom]=u[oy.promisify.custom])};{r(t,\"exists\",(o,...a)=>{let u=typeof a[a.length-1]==\"function\"?a.pop():()=>{};process.nextTick(()=>{e.existsPromise(o).then(A=>{u(A)},()=>{u(!1)})})}),r(t,\"read\",(...o)=>{let[a,n,u,A,p,h]=o;if(o.length<=3){let E={};o.length<3?h=o[1]:(E=o[1],h=o[2]),{buffer:n=Buffer.alloc(16384),offset:u=0,length:A=n.byteLength,position:p}=E}if(u==null&&(u=0),A|=0,A===0){process.nextTick(()=>{h(null,0,n)});return}p==null&&(p=-1),process.nextTick(()=>{e.readPromise(a,n,u,A,p).then(E=>{h(null,E,n)},E=>{h(E,0,n)})})});for(let o of iY){let a=o.replace(/Promise$/,\"\");if(typeof t[a]>\"u\")continue;let n=e[o];if(typeof n>\"u\")continue;r(t,a,(...A)=>{let h=typeof A[A.length-1]==\"function\"?A.pop():()=>{};process.nextTick(()=>{n.apply(e,A).then(E=>{h(null,E)},E=>{h(E)})})})}t.realpath.native=t.realpath}{r(t,\"existsSync\",o=>{try{return e.existsSync(o)}catch{return!1}}),r(t,\"readSync\",(...o)=>{let[a,n,u,A,p]=o;return o.length<=3&&({offset:u=0,length:A=n.byteLength,position:p}=o[2]||{}),u==null&&(u=0),A|=0,A===0?0:(p==null&&(p=-1),e.readSync(a,n,u,A,p))});for(let o of O_e){let a=o;if(typeof t[a]>\"u\")continue;let n=e[o];typeof n>\"u\"||r(t,a,n.bind(e))}t.realpathSync.native=t.realpathSync}{let o=t.promises;for(let a of iY){let n=a.replace(/Promise$/,\"\");if(typeof o[n]>\"u\")continue;let u=e[a];typeof u>\"u\"||a!==\"open\"&&r(o,n,(A,...p)=>A instanceof Ww?A[n].apply(A,p):u.call(e,A,...p))}r(o,\"open\",async(...a)=>{let n=await e.openPromise(...a);return new Ww(n,e)})}t.read[oy.promisify.custom]=async(o,a,...n)=>({bytesRead:await e.readPromise(o,a,...n),buffer:a}),t.write[oy.promisify.custom]=async(o,a,...n)=>({bytesWritten:await e.writePromise(o,a,...n),buffer:a})}function FD(t,e){let r=Object.create(t);return Kw(r,e),r}var oy,O_e,iY,sY=Et(()=>{oy=ve(\"util\");tY();nY();O_e=new Set([\"accessSync\",\"appendFileSync\",\"createReadStream\",\"createWriteStream\",\"chmodSync\",\"fchmodSync\",\"chownSync\",\"fchownSync\",\"closeSync\",\"copyFileSync\",\"linkSync\",\"lstatSync\",\"fstatSync\",\"lutimesSync\",\"mkdirSync\",\"openSync\",\"opendirSync\",\"readlinkSync\",\"readFileSync\",\"readdirSync\",\"readlinkSync\",\"realpathSync\",\"renameSync\",\"rmdirSync\",\"rmSync\",\"statSync\",\"symlinkSync\",\"truncateSync\",\"ftruncateSync\",\"unlinkSync\",\"unwatchFile\",\"utimesSync\",\"watch\",\"watchFile\",\"writeFileSync\",\"writeSync\"]),iY=new Set([\"accessPromise\",\"appendFilePromise\",\"fchmodPromise\",\"chmodPromise\",\"fchownPromise\",\"chownPromise\",\"closePromise\",\"copyFilePromise\",\"linkPromise\",\"fstatPromise\",\"lstatPromise\",\"lutimesPromise\",\"mkdirPromise\",\"openPromise\",\"opendirPromise\",\"readdirPromise\",\"realpathPromise\",\"readFilePromise\",\"readdirPromise\",\"readlinkPromise\",\"renamePromise\",\"rmdirPromise\",\"rmPromise\",\"statPromise\",\"symlinkPromise\",\"truncatePromise\",\"ftruncatePromise\",\"unlinkPromise\",\"utimesPromise\",\"writeFilePromise\",\"writeSync\"])});function oY(t){let e=Math.ceil(Math.random()*4294967296).toString(16).padStart(8,\"0\");return`${t}${e}`}function aY(){if(VR)return VR;let t=le.toPortablePath(lY.default.tmpdir()),e=oe.realpathSync(t);return process.once(\"exit\",()=>{oe.rmtempSync()}),VR={tmpdir:t,realTmpdir:e}}var lY,Oc,VR,oe,cY=Et(()=>{lY=$e(ve(\"os\"));Gg();Ca();Oc=new Set,VR=null;oe=Object.assign(new Tn,{detachTemp(t){Oc.delete(t)},mktempSync(t){let{tmpdir:e,realTmpdir:r}=aY();for(;;){let o=oY(\"xfs-\");try{this.mkdirSync(z.join(e,o))}catch(n){if(n.code===\"EEXIST\")continue;throw n}let a=z.join(r,o);if(Oc.add(a),typeof t>\"u\")return a;try{return t(a)}finally{if(Oc.has(a)){Oc.delete(a);try{this.removeSync(a)}catch{}}}}},async mktempPromise(t){let{tmpdir:e,realTmpdir:r}=aY();for(;;){let o=oY(\"xfs-\");try{await this.mkdirPromise(z.join(e,o))}catch(n){if(n.code===\"EEXIST\")continue;throw n}let a=z.join(r,o);if(Oc.add(a),typeof t>\"u\")return a;try{return await t(a)}finally{if(Oc.has(a)){Oc.delete(a);try{await this.removePromise(a)}catch{}}}}},async rmtempPromise(){await Promise.all(Array.from(Oc.values()).map(async t=>{try{await oe.removePromise(t,{maxRetries:0}),Oc.delete(t)}catch{}}))},rmtempSync(){for(let t of Oc)try{oe.removeSync(t),Oc.delete(t)}catch{}}})});var zw={};zt(zw,{AliasFS:()=>_u,BasePortableFakeFS:()=>Uu,CustomDir:()=>jw,CwdFS:()=>gn,FakeFS:()=>gf,Filename:()=>dr,JailFS:()=>Hu,LazyFS:()=>iy,MountFS:()=>qp,NoFS:()=>Yw,NodeFS:()=>Tn,PortablePath:()=>Bt,PosixFS:()=>Gp,ProxiedFS:()=>Ps,VirtualFS:()=>mi,constants:()=>vi,errors:()=>tr,extendFs:()=>FD,normalizeLineEndings:()=>Hg,npath:()=>le,opendir:()=>SD,patchFs:()=>Kw,ppath:()=>z,setupCopyIndex:()=>PD,statUtils:()=>Ea,unwatchAllFiles:()=>_g,unwatchFile:()=>Ug,watchFile:()=>ny,xfs:()=>oe});var Pt=Et(()=>{k7();BD();HR();jR();N7();YR();qg();Ca();Ca();q7();qg();Y7();K7();z7();V7();J7();Gg();X7();df();Z7();sY();cY()});var hY=_((abt,pY)=>{pY.exports=fY;fY.sync=U_e;var uY=ve(\"fs\");function M_e(t,e){var r=e.pathExt!==void 0?e.pathExt:process.env.PATHEXT;if(!r||(r=r.split(\";\"),r.indexOf(\"\")!==-1))return!0;for(var o=0;o<r.length;o++){var a=r[o].toLowerCase();if(a&&t.substr(-a.length).toLowerCase()===a)return!0}return!1}function AY(t,e,r){return!t.isSymbolicLink()&&!t.isFile()?!1:M_e(e,r)}function fY(t,e,r){uY.stat(t,function(o,a){r(o,o?!1:AY(a,t,e))})}function U_e(t,e){return AY(uY.statSync(t),t,e)}});var EY=_((lbt,yY)=>{yY.exports=dY;dY.sync=__e;var gY=ve(\"fs\");function dY(t,e,r){gY.stat(t,function(o,a){r(o,o?!1:mY(a,e))})}function __e(t,e){return mY(gY.statSync(t),e)}function mY(t,e){return t.isFile()&&H_e(t,e)}function H_e(t,e){var r=t.mode,o=t.uid,a=t.gid,n=e.uid!==void 0?e.uid:process.getuid&&process.getuid(),u=e.gid!==void 0?e.gid:process.getgid&&process.getgid(),A=parseInt(\"100\",8),p=parseInt(\"010\",8),h=parseInt(\"001\",8),E=A|p,I=r&h||r&p&&a===u||r&A&&o===n||r&E&&n===0;return I}});var wY=_((ubt,CY)=>{var cbt=ve(\"fs\"),RD;process.platform===\"win32\"||global.TESTING_WINDOWS?RD=hY():RD=EY();CY.exports=JR;JR.sync=q_e;function JR(t,e,r){if(typeof e==\"function\"&&(r=e,e={}),!r){if(typeof Promise!=\"function\")throw new TypeError(\"callback not provided\");return new Promise(function(o,a){JR(t,e||{},function(n,u){n?a(n):o(u)})})}RD(t,e||{},function(o,a){o&&(o.code===\"EACCES\"||e&&e.ignoreErrors)&&(o=null,a=!1),r(o,a)})}function q_e(t,e){try{return RD.sync(t,e||{})}catch(r){if(e&&e.ignoreErrors||r.code===\"EACCES\")return!1;throw r}}});var bY=_((Abt,SY)=>{var ay=process.platform===\"win32\"||process.env.OSTYPE===\"cygwin\"||process.env.OSTYPE===\"msys\",IY=ve(\"path\"),G_e=ay?\";\":\":\",BY=wY(),vY=t=>Object.assign(new Error(`not found: ${t}`),{code:\"ENOENT\"}),DY=(t,e)=>{let r=e.colon||G_e,o=t.match(/\\//)||ay&&t.match(/\\\\/)?[\"\"]:[...ay?[process.cwd()]:[],...(e.path||process.env.PATH||\"\").split(r)],a=ay?e.pathExt||process.env.PATHEXT||\".EXE;.CMD;.BAT;.COM\":\"\",n=ay?a.split(r):[\"\"];return ay&&t.indexOf(\".\")!==-1&&n[0]!==\"\"&&n.unshift(\"\"),{pathEnv:o,pathExt:n,pathExtExe:a}},PY=(t,e,r)=>{typeof e==\"function\"&&(r=e,e={}),e||(e={});let{pathEnv:o,pathExt:a,pathExtExe:n}=DY(t,e),u=[],A=h=>new Promise((E,I)=>{if(h===o.length)return e.all&&u.length?E(u):I(vY(t));let v=o[h],x=/^\".*\"$/.test(v)?v.slice(1,-1):v,C=IY.join(x,t),R=!x&&/^\\.[\\\\\\/]/.test(t)?t.slice(0,2)+C:C;E(p(R,h,0))}),p=(h,E,I)=>new Promise((v,x)=>{if(I===a.length)return v(A(E+1));let C=a[I];BY(h+C,{pathExt:n},(R,N)=>{if(!R&&N)if(e.all)u.push(h+C);else return v(h+C);return v(p(h,E,I+1))})});return r?A(0).then(h=>r(null,h),r):A(0)},j_e=(t,e)=>{e=e||{};let{pathEnv:r,pathExt:o,pathExtExe:a}=DY(t,e),n=[];for(let u=0;u<r.length;u++){let A=r[u],p=/^\".*\"$/.test(A)?A.slice(1,-1):A,h=IY.join(p,t),E=!p&&/^\\.[\\\\\\/]/.test(t)?t.slice(0,2)+h:h;for(let I=0;I<o.length;I++){let v=E+o[I];try{if(BY.sync(v,{pathExt:a}))if(e.all)n.push(v);else return v}catch{}}}if(e.all&&n.length)return n;if(e.nothrow)return null;throw vY(t)};SY.exports=PY;PY.sync=j_e});var kY=_((fbt,XR)=>{\"use strict\";var xY=(t={})=>{let e=t.env||process.env;return(t.platform||process.platform)!==\"win32\"?\"PATH\":Object.keys(e).reverse().find(o=>o.toUpperCase()===\"PATH\")||\"Path\"};XR.exports=xY;XR.exports.default=xY});var TY=_((pbt,RY)=>{\"use strict\";var QY=ve(\"path\"),Y_e=bY(),W_e=kY();function FY(t,e){let r=t.options.env||process.env,o=process.cwd(),a=t.options.cwd!=null,n=a&&process.chdir!==void 0&&!process.chdir.disabled;if(n)try{process.chdir(t.options.cwd)}catch{}let u;try{u=Y_e.sync(t.command,{path:r[W_e({env:r})],pathExt:e?QY.delimiter:void 0})}catch{}finally{n&&process.chdir(o)}return u&&(u=QY.resolve(a?t.options.cwd:\"\",u)),u}function K_e(t){return FY(t)||FY(t,!0)}RY.exports=K_e});var LY=_((hbt,$R)=>{\"use strict\";var ZR=/([()\\][%!^\"`<>&|;, *?])/g;function z_e(t){return t=t.replace(ZR,\"^$1\"),t}function V_e(t,e){return t=`${t}`,t=t.replace(/(\\\\*)\"/g,'$1$1\\\\\"'),t=t.replace(/(\\\\*)$/,\"$1$1\"),t=`\"${t}\"`,t=t.replace(ZR,\"^$1\"),e&&(t=t.replace(ZR,\"^$1\")),t}$R.exports.command=z_e;$R.exports.argument=V_e});var OY=_((gbt,NY)=>{\"use strict\";NY.exports=/^#!(.*)/});var UY=_((dbt,MY)=>{\"use strict\";var J_e=OY();MY.exports=(t=\"\")=>{let e=t.match(J_e);if(!e)return null;let[r,o]=e[0].replace(/#! ?/,\"\").split(\" \"),a=r.split(\"/\").pop();return a===\"env\"?o:o?`${a} ${o}`:a}});var HY=_((mbt,_Y)=>{\"use strict\";var eT=ve(\"fs\"),X_e=UY();function Z_e(t){let r=Buffer.alloc(150),o;try{o=eT.openSync(t,\"r\"),eT.readSync(o,r,0,150,0),eT.closeSync(o)}catch{}return X_e(r.toString())}_Y.exports=Z_e});var YY=_((ybt,jY)=>{\"use strict\";var $_e=ve(\"path\"),qY=TY(),GY=LY(),e8e=HY(),t8e=process.platform===\"win32\",r8e=/\\.(?:com|exe)$/i,n8e=/node_modules[\\\\/].bin[\\\\/][^\\\\/]+\\.cmd$/i;function i8e(t){t.file=qY(t);let e=t.file&&e8e(t.file);return e?(t.args.unshift(t.file),t.command=e,qY(t)):t.file}function s8e(t){if(!t8e)return t;let e=i8e(t),r=!r8e.test(e);if(t.options.forceShell||r){let o=n8e.test(e);t.command=$_e.normalize(t.command),t.command=GY.command(t.command),t.args=t.args.map(n=>GY.argument(n,o));let a=[t.command].concat(t.args).join(\" \");t.args=[\"/d\",\"/s\",\"/c\",`\"${a}\"`],t.command=process.env.comspec||\"cmd.exe\",t.options.windowsVerbatimArguments=!0}return t}function o8e(t,e,r){e&&!Array.isArray(e)&&(r=e,e=null),e=e?e.slice(0):[],r=Object.assign({},r);let o={command:t,args:e,options:r,file:void 0,original:{command:t,args:e}};return r.shell?o:s8e(o)}jY.exports=o8e});var zY=_((Ebt,KY)=>{\"use strict\";var tT=process.platform===\"win32\";function rT(t,e){return Object.assign(new Error(`${e} ${t.command} ENOENT`),{code:\"ENOENT\",errno:\"ENOENT\",syscall:`${e} ${t.command}`,path:t.command,spawnargs:t.args})}function a8e(t,e){if(!tT)return;let r=t.emit;t.emit=function(o,a){if(o===\"exit\"){let n=WY(a,e,\"spawn\");if(n)return r.call(t,\"error\",n)}return r.apply(t,arguments)}}function WY(t,e){return tT&&t===1&&!e.file?rT(e.original,\"spawn\"):null}function l8e(t,e){return tT&&t===1&&!e.file?rT(e.original,\"spawnSync\"):null}KY.exports={hookChildProcess:a8e,verifyENOENT:WY,verifyENOENTSync:l8e,notFoundError:rT}});var sT=_((Cbt,ly)=>{\"use strict\";var VY=ve(\"child_process\"),nT=YY(),iT=zY();function JY(t,e,r){let o=nT(t,e,r),a=VY.spawn(o.command,o.args,o.options);return iT.hookChildProcess(a,o),a}function c8e(t,e,r){let o=nT(t,e,r),a=VY.spawnSync(o.command,o.args,o.options);return a.error=a.error||iT.verifyENOENTSync(a.status,o),a}ly.exports=JY;ly.exports.spawn=JY;ly.exports.sync=c8e;ly.exports._parse=nT;ly.exports._enoent=iT});var ZY=_((wbt,XY)=>{\"use strict\";function u8e(t,e){function r(){this.constructor=t}r.prototype=e.prototype,t.prototype=new r}function Yg(t,e,r,o){this.message=t,this.expected=e,this.found=r,this.location=o,this.name=\"SyntaxError\",typeof Error.captureStackTrace==\"function\"&&Error.captureStackTrace(this,Yg)}u8e(Yg,Error);Yg.buildMessage=function(t,e){var r={literal:function(h){return'\"'+a(h.text)+'\"'},class:function(h){var E=\"\",I;for(I=0;I<h.parts.length;I++)E+=h.parts[I]instanceof Array?n(h.parts[I][0])+\"-\"+n(h.parts[I][1]):n(h.parts[I]);return\"[\"+(h.inverted?\"^\":\"\")+E+\"]\"},any:function(h){return\"any character\"},end:function(h){return\"end of input\"},other:function(h){return h.description}};function o(h){return h.charCodeAt(0).toString(16).toUpperCase()}function a(h){return h.replace(/\\\\/g,\"\\\\\\\\\").replace(/\"/g,'\\\\\"').replace(/\\0/g,\"\\\\0\").replace(/\\t/g,\"\\\\t\").replace(/\\n/g,\"\\\\n\").replace(/\\r/g,\"\\\\r\").replace(/[\\x00-\\x0F]/g,function(E){return\"\\\\x0\"+o(E)}).replace(/[\\x10-\\x1F\\x7F-\\x9F]/g,function(E){return\"\\\\x\"+o(E)})}function n(h){return h.replace(/\\\\/g,\"\\\\\\\\\").replace(/\\]/g,\"\\\\]\").replace(/\\^/g,\"\\\\^\").replace(/-/g,\"\\\\-\").replace(/\\0/g,\"\\\\0\").replace(/\\t/g,\"\\\\t\").replace(/\\n/g,\"\\\\n\").replace(/\\r/g,\"\\\\r\").replace(/[\\x00-\\x0F]/g,function(E){return\"\\\\x0\"+o(E)}).replace(/[\\x10-\\x1F\\x7F-\\x9F]/g,function(E){return\"\\\\x\"+o(E)})}function u(h){return r[h.type](h)}function A(h){var E=new Array(h.length),I,v;for(I=0;I<h.length;I++)E[I]=u(h[I]);if(E.sort(),E.length>0){for(I=1,v=1;I<E.length;I++)E[I-1]!==E[I]&&(E[v]=E[I],v++);E.length=v}switch(E.length){case 1:return E[0];case 2:return E[0]+\" or \"+E[1];default:return E.slice(0,-1).join(\", \")+\", or \"+E[E.length-1]}}function p(h){return h?'\"'+a(h)+'\"':\"end of input\"}return\"Expected \"+A(t)+\" but \"+p(e)+\" found.\"};function A8e(t,e){e=e!==void 0?e:{};var r={},o={Start:gg},a=gg,n=function(L){return L||[]},u=function(L,K,re){return[{command:L,type:K}].concat(re||[])},A=function(L,K){return[{command:L,type:K||\";\"}]},p=function(L){return L},h=\";\",E=Br(\";\",!1),I=\"&\",v=Br(\"&\",!1),x=function(L,K){return K?{chain:L,then:K}:{chain:L}},C=function(L,K){return{type:L,line:K}},R=\"&&\",N=Br(\"&&\",!1),U=\"||\",V=Br(\"||\",!1),te=function(L,K){return K?{...L,then:K}:L},ae=function(L,K){return{type:L,chain:K}},fe=\"|&\",ue=Br(\"|&\",!1),me=\"|\",he=Br(\"|\",!1),Be=\"=\",we=Br(\"=\",!1),g=function(L,K){return{name:L,args:[K]}},Ee=function(L){return{name:L,args:[]}},Pe=\"(\",ce=Br(\"(\",!1),ne=\")\",ee=Br(\")\",!1),Ie=function(L,K){return{type:\"subshell\",subshell:L,args:K}},Fe=\"{\",At=Br(\"{\",!1),H=\"}\",at=Br(\"}\",!1),Re=function(L,K){return{type:\"group\",group:L,args:K}},ke=function(L,K){return{type:\"command\",args:K,envs:L}},xe=function(L){return{type:\"envs\",envs:L}},He=function(L){return L},Te=function(L){return L},Ve=/^[0-9]/,qe=Cs([[\"0\",\"9\"]],!1,!1),b=function(L,K,re){return{type:\"redirection\",subtype:K,fd:L!==null?parseInt(L):null,args:[re]}},w=\">>\",S=Br(\">>\",!1),y=\">&\",F=Br(\">&\",!1),J=\">\",X=Br(\">\",!1),Z=\"<<<\",ie=Br(\"<<<\",!1),be=\"<&\",Le=Br(\"<&\",!1),ot=\"<\",dt=Br(\"<\",!1),Gt=function(L){return{type:\"argument\",segments:[].concat(...L)}},$t=function(L){return L},bt=\"$'\",an=Br(\"$'\",!1),Qr=\"'\",mr=Br(\"'\",!1),br=function(L){return[{type:\"text\",text:L}]},Wr='\"\"',Kn=Br('\"\"',!1),Ls=function(){return{type:\"text\",text:\"\"}},Ti='\"',ps=Br('\"',!1),io=function(L){return L},Si=function(L){return{type:\"arithmetic\",arithmetic:L,quoted:!0}},Ns=function(L){return{type:\"shell\",shell:L,quoted:!0}},so=function(L){return{type:\"variable\",...L,quoted:!0}},uc=function(L){return{type:\"text\",text:L}},uu=function(L){return{type:\"arithmetic\",arithmetic:L,quoted:!1}},cp=function(L){return{type:\"shell\",shell:L,quoted:!1}},up=function(L){return{type:\"variable\",...L,quoted:!1}},Os=function(L){return{type:\"glob\",pattern:L}},Dn=/^[^']/,oo=Cs([\"'\"],!0,!1),Ms=function(L){return L.join(\"\")},yl=/^[^$\"]/,El=Cs([\"$\",'\"'],!0,!1),ao=`\\\\\n`,zn=Br(`\\\\\n`,!1),On=function(){return\"\"},Li=\"\\\\\",Mn=Br(\"\\\\\",!1),_i=/^[\\\\$\"`]/,rr=Cs([\"\\\\\",\"$\",'\"',\"`\"],!1,!1),Oe=function(L){return L},ii=\"\\\\a\",Ua=Br(\"\\\\a\",!1),hr=function(){return\"a\"},Ac=\"\\\\b\",Au=Br(\"\\\\b\",!1),fc=function(){return\"\\b\"},Cl=/^[Ee]/,DA=Cs([\"E\",\"e\"],!1,!1),fu=function(){return\"\\x1B\"},Ce=\"\\\\f\",Rt=Br(\"\\\\f\",!1),pc=function(){return\"\\f\"},Hi=\"\\\\n\",pu=Br(\"\\\\n\",!1),Yt=function(){return`\n`},wl=\"\\\\r\",PA=Br(\"\\\\r\",!1),Ap=function(){return\"\\r\"},hc=\"\\\\t\",SA=Br(\"\\\\t\",!1),Qn=function(){return\"\t\"},hi=\"\\\\v\",gc=Br(\"\\\\v\",!1),bA=function(){return\"\\v\"},sa=/^[\\\\'\"?]/,Ni=Cs([\"\\\\\",\"'\",'\"',\"?\"],!1,!1),_o=function(L){return String.fromCharCode(parseInt(L,16))},Ze=\"\\\\x\",lo=Br(\"\\\\x\",!1),dc=\"\\\\u\",hu=Br(\"\\\\u\",!1),qi=\"\\\\U\",gu=Br(\"\\\\U\",!1),xA=function(L){return String.fromCodePoint(parseInt(L,16))},Ha=/^[0-7]/,mc=Cs([[\"0\",\"7\"]],!1,!1),hs=/^[0-9a-fA-f]/,Ht=Cs([[\"0\",\"9\"],[\"a\",\"f\"],[\"A\",\"f\"]],!1,!1),Fn=Ag(),Ci=\"{}\",oa=Br(\"{}\",!1),co=function(){return\"{}\"},Us=\"-\",aa=Br(\"-\",!1),la=\"+\",Ho=Br(\"+\",!1),wi=\".\",gs=Br(\".\",!1),ds=function(L,K,re){return{type:\"number\",value:(L===\"-\"?-1:1)*parseFloat(K.join(\"\")+\".\"+re.join(\"\"))}},ms=function(L,K){return{type:\"number\",value:(L===\"-\"?-1:1)*parseInt(K.join(\"\"))}},_s=function(L){return{type:\"variable\",...L}},Un=function(L){return{type:\"variable\",name:L}},Pn=function(L){return L},ys=\"*\",We=Br(\"*\",!1),tt=\"/\",It=Br(\"/\",!1),ir=function(L,K,re){return{type:K===\"*\"?\"multiplication\":\"division\",right:re}},$=function(L,K){return K.reduce((re,pe)=>({left:re,...pe}),L)},ye=function(L,K,re){return{type:K===\"+\"?\"addition\":\"subtraction\",right:re}},Ne=\"$((\",pt=Br(\"$((\",!1),ht=\"))\",Tt=Br(\"))\",!1),er=function(L){return L},$r=\"$(\",Gi=Br(\"$(\",!1),es=function(L){return L},bi=\"${\",qo=Br(\"${\",!1),kA=\":-\",QA=Br(\":-\",!1),fp=function(L,K){return{name:L,defaultValue:K}},sg=\":-}\",du=Br(\":-}\",!1),og=function(L){return{name:L,defaultValue:[]}},mu=\":+\",uo=Br(\":+\",!1),FA=function(L,K){return{name:L,alternativeValue:K}},yc=\":+}\",ca=Br(\":+}\",!1),ag=function(L){return{name:L,alternativeValue:[]}},Ec=function(L){return{name:L}},Sm=\"$\",lg=Br(\"$\",!1),ei=function(L){return e.isGlobPattern(L)},pp=function(L){return L},cg=/^[a-zA-Z0-9_]/,RA=Cs([[\"a\",\"z\"],[\"A\",\"Z\"],[\"0\",\"9\"],\"_\"],!1,!1),Hs=function(){return ug()},yu=/^[$@*?#a-zA-Z0-9_\\-]/,qa=Cs([\"$\",\"@\",\"*\",\"?\",\"#\",[\"a\",\"z\"],[\"A\",\"Z\"],[\"0\",\"9\"],\"_\",\"-\"],!1,!1),ji=/^[()}<>$|&; \\t\"']/,ua=Cs([\"(\",\")\",\"}\",\"<\",\">\",\"$\",\"|\",\"&\",\";\",\" \",\"\t\",'\"',\"'\"],!1,!1),Eu=/^[<>&; \\t\"']/,Es=Cs([\"<\",\">\",\"&\",\";\",\" \",\"\t\",'\"',\"'\"],!1,!1),Cc=/^[ \\t]/,wc=Cs([\" \",\"\t\"],!1,!1),j=0,Dt=0,Il=[{line:1,column:1}],xi=0,Ic=[],ct=0,Cu;if(\"startRule\"in e){if(!(e.startRule in o))throw new Error(`Can't start parsing from rule \"`+e.startRule+'\".');a=o[e.startRule]}function ug(){return t.substring(Dt,j)}function yw(){return Bc(Dt,j)}function TA(L,K){throw K=K!==void 0?K:Bc(Dt,j),hg([pg(L)],t.substring(Dt,j),K)}function hp(L,K){throw K=K!==void 0?K:Bc(Dt,j),bm(L,K)}function Br(L,K){return{type:\"literal\",text:L,ignoreCase:K}}function Cs(L,K,re){return{type:\"class\",parts:L,inverted:K,ignoreCase:re}}function Ag(){return{type:\"any\"}}function fg(){return{type:\"end\"}}function pg(L){return{type:\"other\",description:L}}function gp(L){var K=Il[L],re;if(K)return K;for(re=L-1;!Il[re];)re--;for(K=Il[re],K={line:K.line,column:K.column};re<L;)t.charCodeAt(re)===10?(K.line++,K.column=1):K.column++,re++;return Il[L]=K,K}function Bc(L,K){var re=gp(L),pe=gp(K);return{start:{offset:L,line:re.line,column:re.column},end:{offset:K,line:pe.line,column:pe.column}}}function Ct(L){j<xi||(j>xi&&(xi=j,Ic=[]),Ic.push(L))}function bm(L,K){return new Yg(L,null,null,K)}function hg(L,K,re){return new Yg(Yg.buildMessage(L,K),L,K,re)}function gg(){var L,K,re;for(L=j,K=[],re=Qt();re!==r;)K.push(re),re=Qt();return K!==r?(re=wu(),re===r&&(re=null),re!==r?(Dt=L,K=n(re),L=K):(j=L,L=r)):(j=L,L=r),L}function wu(){var L,K,re,pe,Je;if(L=j,K=Iu(),K!==r){for(re=[],pe=Qt();pe!==r;)re.push(pe),pe=Qt();re!==r?(pe=dg(),pe!==r?(Je=xm(),Je===r&&(Je=null),Je!==r?(Dt=L,K=u(K,pe,Je),L=K):(j=L,L=r)):(j=L,L=r)):(j=L,L=r)}else j=L,L=r;if(L===r)if(L=j,K=Iu(),K!==r){for(re=[],pe=Qt();pe!==r;)re.push(pe),pe=Qt();re!==r?(pe=dg(),pe===r&&(pe=null),pe!==r?(Dt=L,K=A(K,pe),L=K):(j=L,L=r)):(j=L,L=r)}else j=L,L=r;return L}function xm(){var L,K,re,pe,Je;for(L=j,K=[],re=Qt();re!==r;)K.push(re),re=Qt();if(K!==r)if(re=wu(),re!==r){for(pe=[],Je=Qt();Je!==r;)pe.push(Je),Je=Qt();pe!==r?(Dt=L,K=p(re),L=K):(j=L,L=r)}else j=L,L=r;else j=L,L=r;return L}function dg(){var L;return t.charCodeAt(j)===59?(L=h,j++):(L=r,ct===0&&Ct(E)),L===r&&(t.charCodeAt(j)===38?(L=I,j++):(L=r,ct===0&&Ct(v))),L}function Iu(){var L,K,re;return L=j,K=Aa(),K!==r?(re=Ew(),re===r&&(re=null),re!==r?(Dt=L,K=x(K,re),L=K):(j=L,L=r)):(j=L,L=r),L}function Ew(){var L,K,re,pe,Je,mt,fr;for(L=j,K=[],re=Qt();re!==r;)K.push(re),re=Qt();if(K!==r)if(re=km(),re!==r){for(pe=[],Je=Qt();Je!==r;)pe.push(Je),Je=Qt();if(pe!==r)if(Je=Iu(),Je!==r){for(mt=[],fr=Qt();fr!==r;)mt.push(fr),fr=Qt();mt!==r?(Dt=L,K=C(re,Je),L=K):(j=L,L=r)}else j=L,L=r;else j=L,L=r}else j=L,L=r;else j=L,L=r;return L}function km(){var L;return t.substr(j,2)===R?(L=R,j+=2):(L=r,ct===0&&Ct(N)),L===r&&(t.substr(j,2)===U?(L=U,j+=2):(L=r,ct===0&&Ct(V))),L}function Aa(){var L,K,re;return L=j,K=mg(),K!==r?(re=vc(),re===r&&(re=null),re!==r?(Dt=L,K=te(K,re),L=K):(j=L,L=r)):(j=L,L=r),L}function vc(){var L,K,re,pe,Je,mt,fr;for(L=j,K=[],re=Qt();re!==r;)K.push(re),re=Qt();if(K!==r)if(re=Bl(),re!==r){for(pe=[],Je=Qt();Je!==r;)pe.push(Je),Je=Qt();if(pe!==r)if(Je=Aa(),Je!==r){for(mt=[],fr=Qt();fr!==r;)mt.push(fr),fr=Qt();mt!==r?(Dt=L,K=ae(re,Je),L=K):(j=L,L=r)}else j=L,L=r;else j=L,L=r}else j=L,L=r;else j=L,L=r;return L}function Bl(){var L;return t.substr(j,2)===fe?(L=fe,j+=2):(L=r,ct===0&&Ct(ue)),L===r&&(t.charCodeAt(j)===124?(L=me,j++):(L=r,ct===0&&Ct(he))),L}function Bu(){var L,K,re,pe,Je,mt;if(L=j,K=wg(),K!==r)if(t.charCodeAt(j)===61?(re=Be,j++):(re=r,ct===0&&Ct(we)),re!==r)if(pe=Go(),pe!==r){for(Je=[],mt=Qt();mt!==r;)Je.push(mt),mt=Qt();Je!==r?(Dt=L,K=g(K,pe),L=K):(j=L,L=r)}else j=L,L=r;else j=L,L=r;else j=L,L=r;if(L===r)if(L=j,K=wg(),K!==r)if(t.charCodeAt(j)===61?(re=Be,j++):(re=r,ct===0&&Ct(we)),re!==r){for(pe=[],Je=Qt();Je!==r;)pe.push(Je),Je=Qt();pe!==r?(Dt=L,K=Ee(K),L=K):(j=L,L=r)}else j=L,L=r;else j=L,L=r;return L}function mg(){var L,K,re,pe,Je,mt,fr,Cr,yn,oi,Oi;for(L=j,K=[],re=Qt();re!==r;)K.push(re),re=Qt();if(K!==r)if(t.charCodeAt(j)===40?(re=Pe,j++):(re=r,ct===0&&Ct(ce)),re!==r){for(pe=[],Je=Qt();Je!==r;)pe.push(Je),Je=Qt();if(pe!==r)if(Je=wu(),Je!==r){for(mt=[],fr=Qt();fr!==r;)mt.push(fr),fr=Qt();if(mt!==r)if(t.charCodeAt(j)===41?(fr=ne,j++):(fr=r,ct===0&&Ct(ee)),fr!==r){for(Cr=[],yn=Qt();yn!==r;)Cr.push(yn),yn=Qt();if(Cr!==r){for(yn=[],oi=Ga();oi!==r;)yn.push(oi),oi=Ga();if(yn!==r){for(oi=[],Oi=Qt();Oi!==r;)oi.push(Oi),Oi=Qt();oi!==r?(Dt=L,K=Ie(Je,yn),L=K):(j=L,L=r)}else j=L,L=r}else j=L,L=r}else j=L,L=r;else j=L,L=r}else j=L,L=r;else j=L,L=r}else j=L,L=r;else j=L,L=r;if(L===r){for(L=j,K=[],re=Qt();re!==r;)K.push(re),re=Qt();if(K!==r)if(t.charCodeAt(j)===123?(re=Fe,j++):(re=r,ct===0&&Ct(At)),re!==r){for(pe=[],Je=Qt();Je!==r;)pe.push(Je),Je=Qt();if(pe!==r)if(Je=wu(),Je!==r){for(mt=[],fr=Qt();fr!==r;)mt.push(fr),fr=Qt();if(mt!==r)if(t.charCodeAt(j)===125?(fr=H,j++):(fr=r,ct===0&&Ct(at)),fr!==r){for(Cr=[],yn=Qt();yn!==r;)Cr.push(yn),yn=Qt();if(Cr!==r){for(yn=[],oi=Ga();oi!==r;)yn.push(oi),oi=Ga();if(yn!==r){for(oi=[],Oi=Qt();Oi!==r;)oi.push(Oi),Oi=Qt();oi!==r?(Dt=L,K=Re(Je,yn),L=K):(j=L,L=r)}else j=L,L=r}else j=L,L=r}else j=L,L=r;else j=L,L=r}else j=L,L=r;else j=L,L=r}else j=L,L=r;else j=L,L=r;if(L===r){for(L=j,K=[],re=Qt();re!==r;)K.push(re),re=Qt();if(K!==r){for(re=[],pe=Bu();pe!==r;)re.push(pe),pe=Bu();if(re!==r){for(pe=[],Je=Qt();Je!==r;)pe.push(Je),Je=Qt();if(pe!==r){if(Je=[],mt=dp(),mt!==r)for(;mt!==r;)Je.push(mt),mt=dp();else Je=r;if(Je!==r){for(mt=[],fr=Qt();fr!==r;)mt.push(fr),fr=Qt();mt!==r?(Dt=L,K=ke(re,Je),L=K):(j=L,L=r)}else j=L,L=r}else j=L,L=r}else j=L,L=r}else j=L,L=r;if(L===r){for(L=j,K=[],re=Qt();re!==r;)K.push(re),re=Qt();if(K!==r){if(re=[],pe=Bu(),pe!==r)for(;pe!==r;)re.push(pe),pe=Bu();else re=r;if(re!==r){for(pe=[],Je=Qt();Je!==r;)pe.push(Je),Je=Qt();pe!==r?(Dt=L,K=xe(re),L=K):(j=L,L=r)}else j=L,L=r}else j=L,L=r}}}return L}function LA(){var L,K,re,pe,Je;for(L=j,K=[],re=Qt();re!==r;)K.push(re),re=Qt();if(K!==r){if(re=[],pe=mp(),pe!==r)for(;pe!==r;)re.push(pe),pe=mp();else re=r;if(re!==r){for(pe=[],Je=Qt();Je!==r;)pe.push(Je),Je=Qt();pe!==r?(Dt=L,K=He(re),L=K):(j=L,L=r)}else j=L,L=r}else j=L,L=r;return L}function dp(){var L,K,re;for(L=j,K=[],re=Qt();re!==r;)K.push(re),re=Qt();if(K!==r?(re=Ga(),re!==r?(Dt=L,K=Te(re),L=K):(j=L,L=r)):(j=L,L=r),L===r){for(L=j,K=[],re=Qt();re!==r;)K.push(re),re=Qt();K!==r?(re=mp(),re!==r?(Dt=L,K=Te(re),L=K):(j=L,L=r)):(j=L,L=r)}return L}function Ga(){var L,K,re,pe,Je;for(L=j,K=[],re=Qt();re!==r;)K.push(re),re=Qt();return K!==r?(Ve.test(t.charAt(j))?(re=t.charAt(j),j++):(re=r,ct===0&&Ct(qe)),re===r&&(re=null),re!==r?(pe=yg(),pe!==r?(Je=mp(),Je!==r?(Dt=L,K=b(re,pe,Je),L=K):(j=L,L=r)):(j=L,L=r)):(j=L,L=r)):(j=L,L=r),L}function yg(){var L;return t.substr(j,2)===w?(L=w,j+=2):(L=r,ct===0&&Ct(S)),L===r&&(t.substr(j,2)===y?(L=y,j+=2):(L=r,ct===0&&Ct(F)),L===r&&(t.charCodeAt(j)===62?(L=J,j++):(L=r,ct===0&&Ct(X)),L===r&&(t.substr(j,3)===Z?(L=Z,j+=3):(L=r,ct===0&&Ct(ie)),L===r&&(t.substr(j,2)===be?(L=be,j+=2):(L=r,ct===0&&Ct(Le)),L===r&&(t.charCodeAt(j)===60?(L=ot,j++):(L=r,ct===0&&Ct(dt))))))),L}function mp(){var L,K,re;for(L=j,K=[],re=Qt();re!==r;)K.push(re),re=Qt();return K!==r?(re=Go(),re!==r?(Dt=L,K=Te(re),L=K):(j=L,L=r)):(j=L,L=r),L}function Go(){var L,K,re;if(L=j,K=[],re=ws(),re!==r)for(;re!==r;)K.push(re),re=ws();else K=r;return K!==r&&(Dt=L,K=Gt(K)),L=K,L}function ws(){var L,K;return L=j,K=Ii(),K!==r&&(Dt=L,K=$t(K)),L=K,L===r&&(L=j,K=Qm(),K!==r&&(Dt=L,K=$t(K)),L=K,L===r&&(L=j,K=Fm(),K!==r&&(Dt=L,K=$t(K)),L=K,L===r&&(L=j,K=jo(),K!==r&&(Dt=L,K=$t(K)),L=K))),L}function Ii(){var L,K,re,pe;return L=j,t.substr(j,2)===bt?(K=bt,j+=2):(K=r,ct===0&&Ct(an)),K!==r?(re=ln(),re!==r?(t.charCodeAt(j)===39?(pe=Qr,j++):(pe=r,ct===0&&Ct(mr)),pe!==r?(Dt=L,K=br(re),L=K):(j=L,L=r)):(j=L,L=r)):(j=L,L=r),L}function Qm(){var L,K,re,pe;return L=j,t.charCodeAt(j)===39?(K=Qr,j++):(K=r,ct===0&&Ct(mr)),K!==r?(re=Ep(),re!==r?(t.charCodeAt(j)===39?(pe=Qr,j++):(pe=r,ct===0&&Ct(mr)),pe!==r?(Dt=L,K=br(re),L=K):(j=L,L=r)):(j=L,L=r)):(j=L,L=r),L}function Fm(){var L,K,re,pe;if(L=j,t.substr(j,2)===Wr?(K=Wr,j+=2):(K=r,ct===0&&Ct(Kn)),K!==r&&(Dt=L,K=Ls()),L=K,L===r)if(L=j,t.charCodeAt(j)===34?(K=Ti,j++):(K=r,ct===0&&Ct(ps)),K!==r){for(re=[],pe=NA();pe!==r;)re.push(pe),pe=NA();re!==r?(t.charCodeAt(j)===34?(pe=Ti,j++):(pe=r,ct===0&&Ct(ps)),pe!==r?(Dt=L,K=io(re),L=K):(j=L,L=r)):(j=L,L=r)}else j=L,L=r;return L}function jo(){var L,K,re;if(L=j,K=[],re=yp(),re!==r)for(;re!==r;)K.push(re),re=yp();else K=r;return K!==r&&(Dt=L,K=io(K)),L=K,L}function NA(){var L,K;return L=j,K=jr(),K!==r&&(Dt=L,K=Si(K)),L=K,L===r&&(L=j,K=Cp(),K!==r&&(Dt=L,K=Ns(K)),L=K,L===r&&(L=j,K=Pc(),K!==r&&(Dt=L,K=so(K)),L=K,L===r&&(L=j,K=Eg(),K!==r&&(Dt=L,K=uc(K)),L=K))),L}function yp(){var L,K;return L=j,K=jr(),K!==r&&(Dt=L,K=uu(K)),L=K,L===r&&(L=j,K=Cp(),K!==r&&(Dt=L,K=cp(K)),L=K,L===r&&(L=j,K=Pc(),K!==r&&(Dt=L,K=up(K)),L=K,L===r&&(L=j,K=Cw(),K!==r&&(Dt=L,K=Os(K)),L=K,L===r&&(L=j,K=pa(),K!==r&&(Dt=L,K=uc(K)),L=K)))),L}function Ep(){var L,K,re;for(L=j,K=[],Dn.test(t.charAt(j))?(re=t.charAt(j),j++):(re=r,ct===0&&Ct(oo));re!==r;)K.push(re),Dn.test(t.charAt(j))?(re=t.charAt(j),j++):(re=r,ct===0&&Ct(oo));return K!==r&&(Dt=L,K=Ms(K)),L=K,L}function Eg(){var L,K,re;if(L=j,K=[],re=fa(),re===r&&(yl.test(t.charAt(j))?(re=t.charAt(j),j++):(re=r,ct===0&&Ct(El))),re!==r)for(;re!==r;)K.push(re),re=fa(),re===r&&(yl.test(t.charAt(j))?(re=t.charAt(j),j++):(re=r,ct===0&&Ct(El)));else K=r;return K!==r&&(Dt=L,K=Ms(K)),L=K,L}function fa(){var L,K,re;return L=j,t.substr(j,2)===ao?(K=ao,j+=2):(K=r,ct===0&&Ct(zn)),K!==r&&(Dt=L,K=On()),L=K,L===r&&(L=j,t.charCodeAt(j)===92?(K=Li,j++):(K=r,ct===0&&Ct(Mn)),K!==r?(_i.test(t.charAt(j))?(re=t.charAt(j),j++):(re=r,ct===0&&Ct(rr)),re!==r?(Dt=L,K=Oe(re),L=K):(j=L,L=r)):(j=L,L=r)),L}function ln(){var L,K,re;for(L=j,K=[],re=Ao(),re===r&&(Dn.test(t.charAt(j))?(re=t.charAt(j),j++):(re=r,ct===0&&Ct(oo)));re!==r;)K.push(re),re=Ao(),re===r&&(Dn.test(t.charAt(j))?(re=t.charAt(j),j++):(re=r,ct===0&&Ct(oo)));return K!==r&&(Dt=L,K=Ms(K)),L=K,L}function Ao(){var L,K,re;return L=j,t.substr(j,2)===ii?(K=ii,j+=2):(K=r,ct===0&&Ct(Ua)),K!==r&&(Dt=L,K=hr()),L=K,L===r&&(L=j,t.substr(j,2)===Ac?(K=Ac,j+=2):(K=r,ct===0&&Ct(Au)),K!==r&&(Dt=L,K=fc()),L=K,L===r&&(L=j,t.charCodeAt(j)===92?(K=Li,j++):(K=r,ct===0&&Ct(Mn)),K!==r?(Cl.test(t.charAt(j))?(re=t.charAt(j),j++):(re=r,ct===0&&Ct(DA)),re!==r?(Dt=L,K=fu(),L=K):(j=L,L=r)):(j=L,L=r),L===r&&(L=j,t.substr(j,2)===Ce?(K=Ce,j+=2):(K=r,ct===0&&Ct(Rt)),K!==r&&(Dt=L,K=pc()),L=K,L===r&&(L=j,t.substr(j,2)===Hi?(K=Hi,j+=2):(K=r,ct===0&&Ct(pu)),K!==r&&(Dt=L,K=Yt()),L=K,L===r&&(L=j,t.substr(j,2)===wl?(K=wl,j+=2):(K=r,ct===0&&Ct(PA)),K!==r&&(Dt=L,K=Ap()),L=K,L===r&&(L=j,t.substr(j,2)===hc?(K=hc,j+=2):(K=r,ct===0&&Ct(SA)),K!==r&&(Dt=L,K=Qn()),L=K,L===r&&(L=j,t.substr(j,2)===hi?(K=hi,j+=2):(K=r,ct===0&&Ct(gc)),K!==r&&(Dt=L,K=bA()),L=K,L===r&&(L=j,t.charCodeAt(j)===92?(K=Li,j++):(K=r,ct===0&&Ct(Mn)),K!==r?(sa.test(t.charAt(j))?(re=t.charAt(j),j++):(re=r,ct===0&&Ct(Ni)),re!==r?(Dt=L,K=Oe(re),L=K):(j=L,L=r)):(j=L,L=r),L===r&&(L=OA()))))))))),L}function OA(){var L,K,re,pe,Je,mt,fr,Cr,yn,oi,Oi,Bg;return L=j,t.charCodeAt(j)===92?(K=Li,j++):(K=r,ct===0&&Ct(Mn)),K!==r?(re=ja(),re!==r?(Dt=L,K=_o(re),L=K):(j=L,L=r)):(j=L,L=r),L===r&&(L=j,t.substr(j,2)===Ze?(K=Ze,j+=2):(K=r,ct===0&&Ct(lo)),K!==r?(re=j,pe=j,Je=ja(),Je!==r?(mt=si(),mt!==r?(Je=[Je,mt],pe=Je):(j=pe,pe=r)):(j=pe,pe=r),pe===r&&(pe=ja()),pe!==r?re=t.substring(re,j):re=pe,re!==r?(Dt=L,K=_o(re),L=K):(j=L,L=r)):(j=L,L=r),L===r&&(L=j,t.substr(j,2)===dc?(K=dc,j+=2):(K=r,ct===0&&Ct(hu)),K!==r?(re=j,pe=j,Je=si(),Je!==r?(mt=si(),mt!==r?(fr=si(),fr!==r?(Cr=si(),Cr!==r?(Je=[Je,mt,fr,Cr],pe=Je):(j=pe,pe=r)):(j=pe,pe=r)):(j=pe,pe=r)):(j=pe,pe=r),pe!==r?re=t.substring(re,j):re=pe,re!==r?(Dt=L,K=_o(re),L=K):(j=L,L=r)):(j=L,L=r),L===r&&(L=j,t.substr(j,2)===qi?(K=qi,j+=2):(K=r,ct===0&&Ct(gu)),K!==r?(re=j,pe=j,Je=si(),Je!==r?(mt=si(),mt!==r?(fr=si(),fr!==r?(Cr=si(),Cr!==r?(yn=si(),yn!==r?(oi=si(),oi!==r?(Oi=si(),Oi!==r?(Bg=si(),Bg!==r?(Je=[Je,mt,fr,Cr,yn,oi,Oi,Bg],pe=Je):(j=pe,pe=r)):(j=pe,pe=r)):(j=pe,pe=r)):(j=pe,pe=r)):(j=pe,pe=r)):(j=pe,pe=r)):(j=pe,pe=r)):(j=pe,pe=r),pe!==r?re=t.substring(re,j):re=pe,re!==r?(Dt=L,K=xA(re),L=K):(j=L,L=r)):(j=L,L=r)))),L}function ja(){var L;return Ha.test(t.charAt(j))?(L=t.charAt(j),j++):(L=r,ct===0&&Ct(mc)),L}function si(){var L;return hs.test(t.charAt(j))?(L=t.charAt(j),j++):(L=r,ct===0&&Ct(Ht)),L}function pa(){var L,K,re,pe,Je;if(L=j,K=[],re=j,t.charCodeAt(j)===92?(pe=Li,j++):(pe=r,ct===0&&Ct(Mn)),pe!==r?(t.length>j?(Je=t.charAt(j),j++):(Je=r,ct===0&&Ct(Fn)),Je!==r?(Dt=re,pe=Oe(Je),re=pe):(j=re,re=r)):(j=re,re=r),re===r&&(re=j,t.substr(j,2)===Ci?(pe=Ci,j+=2):(pe=r,ct===0&&Ct(oa)),pe!==r&&(Dt=re,pe=co()),re=pe,re===r&&(re=j,pe=j,ct++,Je=Rm(),ct--,Je===r?pe=void 0:(j=pe,pe=r),pe!==r?(t.length>j?(Je=t.charAt(j),j++):(Je=r,ct===0&&Ct(Fn)),Je!==r?(Dt=re,pe=Oe(Je),re=pe):(j=re,re=r)):(j=re,re=r))),re!==r)for(;re!==r;)K.push(re),re=j,t.charCodeAt(j)===92?(pe=Li,j++):(pe=r,ct===0&&Ct(Mn)),pe!==r?(t.length>j?(Je=t.charAt(j),j++):(Je=r,ct===0&&Ct(Fn)),Je!==r?(Dt=re,pe=Oe(Je),re=pe):(j=re,re=r)):(j=re,re=r),re===r&&(re=j,t.substr(j,2)===Ci?(pe=Ci,j+=2):(pe=r,ct===0&&Ct(oa)),pe!==r&&(Dt=re,pe=co()),re=pe,re===r&&(re=j,pe=j,ct++,Je=Rm(),ct--,Je===r?pe=void 0:(j=pe,pe=r),pe!==r?(t.length>j?(Je=t.charAt(j),j++):(Je=r,ct===0&&Ct(Fn)),Je!==r?(Dt=re,pe=Oe(Je),re=pe):(j=re,re=r)):(j=re,re=r)));else K=r;return K!==r&&(Dt=L,K=Ms(K)),L=K,L}function Dc(){var L,K,re,pe,Je,mt;if(L=j,t.charCodeAt(j)===45?(K=Us,j++):(K=r,ct===0&&Ct(aa)),K===r&&(t.charCodeAt(j)===43?(K=la,j++):(K=r,ct===0&&Ct(Ho))),K===r&&(K=null),K!==r){if(re=[],Ve.test(t.charAt(j))?(pe=t.charAt(j),j++):(pe=r,ct===0&&Ct(qe)),pe!==r)for(;pe!==r;)re.push(pe),Ve.test(t.charAt(j))?(pe=t.charAt(j),j++):(pe=r,ct===0&&Ct(qe));else re=r;if(re!==r)if(t.charCodeAt(j)===46?(pe=wi,j++):(pe=r,ct===0&&Ct(gs)),pe!==r){if(Je=[],Ve.test(t.charAt(j))?(mt=t.charAt(j),j++):(mt=r,ct===0&&Ct(qe)),mt!==r)for(;mt!==r;)Je.push(mt),Ve.test(t.charAt(j))?(mt=t.charAt(j),j++):(mt=r,ct===0&&Ct(qe));else Je=r;Je!==r?(Dt=L,K=ds(K,re,Je),L=K):(j=L,L=r)}else j=L,L=r;else j=L,L=r}else j=L,L=r;if(L===r){if(L=j,t.charCodeAt(j)===45?(K=Us,j++):(K=r,ct===0&&Ct(aa)),K===r&&(t.charCodeAt(j)===43?(K=la,j++):(K=r,ct===0&&Ct(Ho))),K===r&&(K=null),K!==r){if(re=[],Ve.test(t.charAt(j))?(pe=t.charAt(j),j++):(pe=r,ct===0&&Ct(qe)),pe!==r)for(;pe!==r;)re.push(pe),Ve.test(t.charAt(j))?(pe=t.charAt(j),j++):(pe=r,ct===0&&Ct(qe));else re=r;re!==r?(Dt=L,K=ms(K,re),L=K):(j=L,L=r)}else j=L,L=r;if(L===r&&(L=j,K=Pc(),K!==r&&(Dt=L,K=_s(K)),L=K,L===r&&(L=j,K=Ya(),K!==r&&(Dt=L,K=Un(K)),L=K,L===r)))if(L=j,t.charCodeAt(j)===40?(K=Pe,j++):(K=r,ct===0&&Ct(ce)),K!==r){for(re=[],pe=Qt();pe!==r;)re.push(pe),pe=Qt();if(re!==r)if(pe=ts(),pe!==r){for(Je=[],mt=Qt();mt!==r;)Je.push(mt),mt=Qt();Je!==r?(t.charCodeAt(j)===41?(mt=ne,j++):(mt=r,ct===0&&Ct(ee)),mt!==r?(Dt=L,K=Pn(pe),L=K):(j=L,L=r)):(j=L,L=r)}else j=L,L=r;else j=L,L=r}else j=L,L=r}return L}function vl(){var L,K,re,pe,Je,mt,fr,Cr;if(L=j,K=Dc(),K!==r){for(re=[],pe=j,Je=[],mt=Qt();mt!==r;)Je.push(mt),mt=Qt();if(Je!==r)if(t.charCodeAt(j)===42?(mt=ys,j++):(mt=r,ct===0&&Ct(We)),mt===r&&(t.charCodeAt(j)===47?(mt=tt,j++):(mt=r,ct===0&&Ct(It))),mt!==r){for(fr=[],Cr=Qt();Cr!==r;)fr.push(Cr),Cr=Qt();fr!==r?(Cr=Dc(),Cr!==r?(Dt=pe,Je=ir(K,mt,Cr),pe=Je):(j=pe,pe=r)):(j=pe,pe=r)}else j=pe,pe=r;else j=pe,pe=r;for(;pe!==r;){for(re.push(pe),pe=j,Je=[],mt=Qt();mt!==r;)Je.push(mt),mt=Qt();if(Je!==r)if(t.charCodeAt(j)===42?(mt=ys,j++):(mt=r,ct===0&&Ct(We)),mt===r&&(t.charCodeAt(j)===47?(mt=tt,j++):(mt=r,ct===0&&Ct(It))),mt!==r){for(fr=[],Cr=Qt();Cr!==r;)fr.push(Cr),Cr=Qt();fr!==r?(Cr=Dc(),Cr!==r?(Dt=pe,Je=ir(K,mt,Cr),pe=Je):(j=pe,pe=r)):(j=pe,pe=r)}else j=pe,pe=r;else j=pe,pe=r}re!==r?(Dt=L,K=$(K,re),L=K):(j=L,L=r)}else j=L,L=r;return L}function ts(){var L,K,re,pe,Je,mt,fr,Cr;if(L=j,K=vl(),K!==r){for(re=[],pe=j,Je=[],mt=Qt();mt!==r;)Je.push(mt),mt=Qt();if(Je!==r)if(t.charCodeAt(j)===43?(mt=la,j++):(mt=r,ct===0&&Ct(Ho)),mt===r&&(t.charCodeAt(j)===45?(mt=Us,j++):(mt=r,ct===0&&Ct(aa))),mt!==r){for(fr=[],Cr=Qt();Cr!==r;)fr.push(Cr),Cr=Qt();fr!==r?(Cr=vl(),Cr!==r?(Dt=pe,Je=ye(K,mt,Cr),pe=Je):(j=pe,pe=r)):(j=pe,pe=r)}else j=pe,pe=r;else j=pe,pe=r;for(;pe!==r;){for(re.push(pe),pe=j,Je=[],mt=Qt();mt!==r;)Je.push(mt),mt=Qt();if(Je!==r)if(t.charCodeAt(j)===43?(mt=la,j++):(mt=r,ct===0&&Ct(Ho)),mt===r&&(t.charCodeAt(j)===45?(mt=Us,j++):(mt=r,ct===0&&Ct(aa))),mt!==r){for(fr=[],Cr=Qt();Cr!==r;)fr.push(Cr),Cr=Qt();fr!==r?(Cr=vl(),Cr!==r?(Dt=pe,Je=ye(K,mt,Cr),pe=Je):(j=pe,pe=r)):(j=pe,pe=r)}else j=pe,pe=r;else j=pe,pe=r}re!==r?(Dt=L,K=$(K,re),L=K):(j=L,L=r)}else j=L,L=r;return L}function jr(){var L,K,re,pe,Je,mt;if(L=j,t.substr(j,3)===Ne?(K=Ne,j+=3):(K=r,ct===0&&Ct(pt)),K!==r){for(re=[],pe=Qt();pe!==r;)re.push(pe),pe=Qt();if(re!==r)if(pe=ts(),pe!==r){for(Je=[],mt=Qt();mt!==r;)Je.push(mt),mt=Qt();Je!==r?(t.substr(j,2)===ht?(mt=ht,j+=2):(mt=r,ct===0&&Ct(Tt)),mt!==r?(Dt=L,K=er(pe),L=K):(j=L,L=r)):(j=L,L=r)}else j=L,L=r;else j=L,L=r}else j=L,L=r;return L}function Cp(){var L,K,re,pe;return L=j,t.substr(j,2)===$r?(K=$r,j+=2):(K=r,ct===0&&Ct(Gi)),K!==r?(re=wu(),re!==r?(t.charCodeAt(j)===41?(pe=ne,j++):(pe=r,ct===0&&Ct(ee)),pe!==r?(Dt=L,K=es(re),L=K):(j=L,L=r)):(j=L,L=r)):(j=L,L=r),L}function Pc(){var L,K,re,pe,Je,mt;return L=j,t.substr(j,2)===bi?(K=bi,j+=2):(K=r,ct===0&&Ct(qo)),K!==r?(re=Ya(),re!==r?(t.substr(j,2)===kA?(pe=kA,j+=2):(pe=r,ct===0&&Ct(QA)),pe!==r?(Je=LA(),Je!==r?(t.charCodeAt(j)===125?(mt=H,j++):(mt=r,ct===0&&Ct(at)),mt!==r?(Dt=L,K=fp(re,Je),L=K):(j=L,L=r)):(j=L,L=r)):(j=L,L=r)):(j=L,L=r)):(j=L,L=r),L===r&&(L=j,t.substr(j,2)===bi?(K=bi,j+=2):(K=r,ct===0&&Ct(qo)),K!==r?(re=Ya(),re!==r?(t.substr(j,3)===sg?(pe=sg,j+=3):(pe=r,ct===0&&Ct(du)),pe!==r?(Dt=L,K=og(re),L=K):(j=L,L=r)):(j=L,L=r)):(j=L,L=r),L===r&&(L=j,t.substr(j,2)===bi?(K=bi,j+=2):(K=r,ct===0&&Ct(qo)),K!==r?(re=Ya(),re!==r?(t.substr(j,2)===mu?(pe=mu,j+=2):(pe=r,ct===0&&Ct(uo)),pe!==r?(Je=LA(),Je!==r?(t.charCodeAt(j)===125?(mt=H,j++):(mt=r,ct===0&&Ct(at)),mt!==r?(Dt=L,K=FA(re,Je),L=K):(j=L,L=r)):(j=L,L=r)):(j=L,L=r)):(j=L,L=r)):(j=L,L=r),L===r&&(L=j,t.substr(j,2)===bi?(K=bi,j+=2):(K=r,ct===0&&Ct(qo)),K!==r?(re=Ya(),re!==r?(t.substr(j,3)===yc?(pe=yc,j+=3):(pe=r,ct===0&&Ct(ca)),pe!==r?(Dt=L,K=ag(re),L=K):(j=L,L=r)):(j=L,L=r)):(j=L,L=r),L===r&&(L=j,t.substr(j,2)===bi?(K=bi,j+=2):(K=r,ct===0&&Ct(qo)),K!==r?(re=Ya(),re!==r?(t.charCodeAt(j)===125?(pe=H,j++):(pe=r,ct===0&&Ct(at)),pe!==r?(Dt=L,K=Ec(re),L=K):(j=L,L=r)):(j=L,L=r)):(j=L,L=r),L===r&&(L=j,t.charCodeAt(j)===36?(K=Sm,j++):(K=r,ct===0&&Ct(lg)),K!==r?(re=Ya(),re!==r?(Dt=L,K=Ec(re),L=K):(j=L,L=r)):(j=L,L=r)))))),L}function Cw(){var L,K,re;return L=j,K=Cg(),K!==r?(Dt=j,re=ei(K),re?re=void 0:re=r,re!==r?(Dt=L,K=pp(K),L=K):(j=L,L=r)):(j=L,L=r),L}function Cg(){var L,K,re,pe,Je;if(L=j,K=[],re=j,pe=j,ct++,Je=Ig(),ct--,Je===r?pe=void 0:(j=pe,pe=r),pe!==r?(t.length>j?(Je=t.charAt(j),j++):(Je=r,ct===0&&Ct(Fn)),Je!==r?(Dt=re,pe=Oe(Je),re=pe):(j=re,re=r)):(j=re,re=r),re!==r)for(;re!==r;)K.push(re),re=j,pe=j,ct++,Je=Ig(),ct--,Je===r?pe=void 0:(j=pe,pe=r),pe!==r?(t.length>j?(Je=t.charAt(j),j++):(Je=r,ct===0&&Ct(Fn)),Je!==r?(Dt=re,pe=Oe(Je),re=pe):(j=re,re=r)):(j=re,re=r);else K=r;return K!==r&&(Dt=L,K=Ms(K)),L=K,L}function wg(){var L,K,re;if(L=j,K=[],cg.test(t.charAt(j))?(re=t.charAt(j),j++):(re=r,ct===0&&Ct(RA)),re!==r)for(;re!==r;)K.push(re),cg.test(t.charAt(j))?(re=t.charAt(j),j++):(re=r,ct===0&&Ct(RA));else K=r;return K!==r&&(Dt=L,K=Hs()),L=K,L}function Ya(){var L,K,re;if(L=j,K=[],yu.test(t.charAt(j))?(re=t.charAt(j),j++):(re=r,ct===0&&Ct(qa)),re!==r)for(;re!==r;)K.push(re),yu.test(t.charAt(j))?(re=t.charAt(j),j++):(re=r,ct===0&&Ct(qa));else K=r;return K!==r&&(Dt=L,K=Hs()),L=K,L}function Rm(){var L;return ji.test(t.charAt(j))?(L=t.charAt(j),j++):(L=r,ct===0&&Ct(ua)),L}function Ig(){var L;return Eu.test(t.charAt(j))?(L=t.charAt(j),j++):(L=r,ct===0&&Ct(Es)),L}function Qt(){var L,K;if(L=[],Cc.test(t.charAt(j))?(K=t.charAt(j),j++):(K=r,ct===0&&Ct(wc)),K!==r)for(;K!==r;)L.push(K),Cc.test(t.charAt(j))?(K=t.charAt(j),j++):(K=r,ct===0&&Ct(wc));else L=r;return L}if(Cu=a(),Cu!==r&&j===t.length)return Cu;throw Cu!==r&&j<t.length&&Ct(fg()),hg(Ic,xi<t.length?t.charAt(xi):null,xi<t.length?Bc(xi,xi+1):Bc(xi,xi))}XY.exports={SyntaxError:Yg,parse:A8e}});function LD(t,e={isGlobPattern:()=>!1}){try{return(0,$Y.parse)(t,e)}catch(r){throw r.location&&(r.message=r.message.replace(/(\\.)?$/,` (line ${r.location.start.line}, column ${r.location.start.column})$1`)),r}}function cy(t,{endSemicolon:e=!1}={}){return t.map(({command:r,type:o},a)=>`${ND(r)}${o===\";\"?a!==t.length-1||e?\";\":\"\":\" &\"}`).join(\" \")}function ND(t){return`${uy(t.chain)}${t.then?` ${oT(t.then)}`:\"\"}`}function oT(t){return`${t.type} ${ND(t.line)}`}function uy(t){return`${lT(t)}${t.then?` ${aT(t.then)}`:\"\"}`}function aT(t){return`${t.type} ${uy(t.chain)}`}function lT(t){switch(t.type){case\"command\":return`${t.envs.length>0?`${t.envs.map(e=>TD(e)).join(\" \")} `:\"\"}${t.args.map(e=>cT(e)).join(\" \")}`;case\"subshell\":return`(${cy(t.subshell)})${t.args.length>0?` ${t.args.map(e=>Vw(e)).join(\" \")}`:\"\"}`;case\"group\":return`{ ${cy(t.group,{endSemicolon:!0})} }${t.args.length>0?` ${t.args.map(e=>Vw(e)).join(\" \")}`:\"\"}`;case\"envs\":return t.envs.map(e=>TD(e)).join(\" \");default:throw new Error(`Unsupported command type:  \"${t.type}\"`)}}function TD(t){return`${t.name}=${t.args[0]?Wg(t.args[0]):\"\"}`}function cT(t){switch(t.type){case\"redirection\":return Vw(t);case\"argument\":return Wg(t);default:throw new Error(`Unsupported argument type: \"${t.type}\"`)}}function Vw(t){return`${t.subtype} ${t.args.map(e=>Wg(e)).join(\" \")}`}function Wg(t){return t.segments.map(e=>uT(e)).join(\"\")}function uT(t){let e=(o,a)=>a?`\"${o}\"`:o,r=o=>o===\"\"?\"''\":o.match(/[()}<>$|&;\"'\\n\\t ]/)?o.match(/['\\t\\p{C}]/u)?o.match(/'/)?`\"${o.replace(/[\"$\\t\\p{C}]/u,p8e)}\"`:`$'${o.replace(/[\\t\\p{C}]/u,tW)}'`:`'${o}'`:o;switch(t.type){case\"text\":return r(t.text);case\"glob\":return t.pattern;case\"shell\":return e(`$(${cy(t.shell)})`,t.quoted);case\"variable\":return e(typeof t.defaultValue>\"u\"?typeof t.alternativeValue>\"u\"?`\\${${t.name}}`:t.alternativeValue.length===0?`\\${${t.name}:+}`:`\\${${t.name}:+${t.alternativeValue.map(o=>Wg(o)).join(\" \")}}`:t.defaultValue.length===0?`\\${${t.name}:-}`:`\\${${t.name}:-${t.defaultValue.map(o=>Wg(o)).join(\" \")}}`,t.quoted);case\"arithmetic\":return`$(( ${OD(t.arithmetic)} ))`;default:throw new Error(`Unsupported argument segment type: \"${t.type}\"`)}}function OD(t){let e=a=>{switch(a){case\"addition\":return\"+\";case\"subtraction\":return\"-\";case\"multiplication\":return\"*\";case\"division\":return\"/\";default:throw new Error(`Can't extract operator from arithmetic expression of type \"${a}\"`)}},r=(a,n)=>n?`( ${a} )`:a,o=a=>r(OD(a),![\"number\",\"variable\"].includes(a.type));switch(t.type){case\"number\":return String(t.value);case\"variable\":return t.name;default:return`${o(t.left)} ${e(t.type)} ${o(t.right)}`}}var $Y,eW,f8e,tW,p8e,rW=Et(()=>{$Y=$e(ZY());eW=new Map([[\"\\f\",\"\\\\f\"],[`\n`,\"\\\\n\"],[\"\\r\",\"\\\\r\"],[\"\t\",\"\\\\t\"],[\"\\v\",\"\\\\v\"],[\"\\0\",\"\\\\0\"]]),f8e=new Map([[\"\\\\\",\"\\\\\\\\\"],[\"$\",\"\\\\$\"],['\"','\\\\\"'],...Array.from(eW,([t,e])=>[t,`\"$'${e}'\"`])]),tW=t=>eW.get(t)??`\\\\x${t.charCodeAt(0).toString(16).padStart(2,\"0\")}`,p8e=t=>f8e.get(t)??`\"$'${tW(t)}'\"`});var iW=_((Lbt,nW)=>{\"use strict\";function h8e(t,e){function r(){this.constructor=t}r.prototype=e.prototype,t.prototype=new r}function Kg(t,e,r,o){this.message=t,this.expected=e,this.found=r,this.location=o,this.name=\"SyntaxError\",typeof Error.captureStackTrace==\"function\"&&Error.captureStackTrace(this,Kg)}h8e(Kg,Error);Kg.buildMessage=function(t,e){var r={literal:function(h){return'\"'+a(h.text)+'\"'},class:function(h){var E=\"\",I;for(I=0;I<h.parts.length;I++)E+=h.parts[I]instanceof Array?n(h.parts[I][0])+\"-\"+n(h.parts[I][1]):n(h.parts[I]);return\"[\"+(h.inverted?\"^\":\"\")+E+\"]\"},any:function(h){return\"any character\"},end:function(h){return\"end of input\"},other:function(h){return h.description}};function o(h){return h.charCodeAt(0).toString(16).toUpperCase()}function a(h){return h.replace(/\\\\/g,\"\\\\\\\\\").replace(/\"/g,'\\\\\"').replace(/\\0/g,\"\\\\0\").replace(/\\t/g,\"\\\\t\").replace(/\\n/g,\"\\\\n\").replace(/\\r/g,\"\\\\r\").replace(/[\\x00-\\x0F]/g,function(E){return\"\\\\x0\"+o(E)}).replace(/[\\x10-\\x1F\\x7F-\\x9F]/g,function(E){return\"\\\\x\"+o(E)})}function n(h){return h.replace(/\\\\/g,\"\\\\\\\\\").replace(/\\]/g,\"\\\\]\").replace(/\\^/g,\"\\\\^\").replace(/-/g,\"\\\\-\").replace(/\\0/g,\"\\\\0\").replace(/\\t/g,\"\\\\t\").replace(/\\n/g,\"\\\\n\").replace(/\\r/g,\"\\\\r\").replace(/[\\x00-\\x0F]/g,function(E){return\"\\\\x0\"+o(E)}).replace(/[\\x10-\\x1F\\x7F-\\x9F]/g,function(E){return\"\\\\x\"+o(E)})}function u(h){return r[h.type](h)}function A(h){var E=new Array(h.length),I,v;for(I=0;I<h.length;I++)E[I]=u(h[I]);if(E.sort(),E.length>0){for(I=1,v=1;I<E.length;I++)E[I-1]!==E[I]&&(E[v]=E[I],v++);E.length=v}switch(E.length){case 1:return E[0];case 2:return E[0]+\" or \"+E[1];default:return E.slice(0,-1).join(\", \")+\", or \"+E[E.length-1]}}function p(h){return h?'\"'+a(h)+'\"':\"end of input\"}return\"Expected \"+A(t)+\" but \"+p(e)+\" found.\"};function g8e(t,e){e=e!==void 0?e:{};var r={},o={resolution:ke},a=ke,n=\"/\",u=Pe(\"/\",!1),A=function(qe,b){return{from:qe,descriptor:b}},p=function(qe){return{descriptor:qe}},h=\"@\",E=Pe(\"@\",!1),I=function(qe,b){return{fullName:qe,description:b}},v=function(qe){return{fullName:qe}},x=function(){return Be()},C=/^[^\\/@]/,R=ce([\"/\",\"@\"],!0,!1),N=/^[^\\/]/,U=ce([\"/\"],!0,!1),V=0,te=0,ae=[{line:1,column:1}],fe=0,ue=[],me=0,he;if(\"startRule\"in e){if(!(e.startRule in o))throw new Error(`Can't start parsing from rule \"`+e.startRule+'\".');a=o[e.startRule]}function Be(){return t.substring(te,V)}function we(){return At(te,V)}function g(qe,b){throw b=b!==void 0?b:At(te,V),Re([Ie(qe)],t.substring(te,V),b)}function Ee(qe,b){throw b=b!==void 0?b:At(te,V),at(qe,b)}function Pe(qe,b){return{type:\"literal\",text:qe,ignoreCase:b}}function ce(qe,b,w){return{type:\"class\",parts:qe,inverted:b,ignoreCase:w}}function ne(){return{type:\"any\"}}function ee(){return{type:\"end\"}}function Ie(qe){return{type:\"other\",description:qe}}function Fe(qe){var b=ae[qe],w;if(b)return b;for(w=qe-1;!ae[w];)w--;for(b=ae[w],b={line:b.line,column:b.column};w<qe;)t.charCodeAt(w)===10?(b.line++,b.column=1):b.column++,w++;return ae[qe]=b,b}function At(qe,b){var w=Fe(qe),S=Fe(b);return{start:{offset:qe,line:w.line,column:w.column},end:{offset:b,line:S.line,column:S.column}}}function H(qe){V<fe||(V>fe&&(fe=V,ue=[]),ue.push(qe))}function at(qe,b){return new Kg(qe,null,null,b)}function Re(qe,b,w){return new Kg(Kg.buildMessage(qe,b),qe,b,w)}function ke(){var qe,b,w,S;return qe=V,b=xe(),b!==r?(t.charCodeAt(V)===47?(w=n,V++):(w=r,me===0&&H(u)),w!==r?(S=xe(),S!==r?(te=qe,b=A(b,S),qe=b):(V=qe,qe=r)):(V=qe,qe=r)):(V=qe,qe=r),qe===r&&(qe=V,b=xe(),b!==r&&(te=qe,b=p(b)),qe=b),qe}function xe(){var qe,b,w,S;return qe=V,b=He(),b!==r?(t.charCodeAt(V)===64?(w=h,V++):(w=r,me===0&&H(E)),w!==r?(S=Ve(),S!==r?(te=qe,b=I(b,S),qe=b):(V=qe,qe=r)):(V=qe,qe=r)):(V=qe,qe=r),qe===r&&(qe=V,b=He(),b!==r&&(te=qe,b=v(b)),qe=b),qe}function He(){var qe,b,w,S,y;return qe=V,t.charCodeAt(V)===64?(b=h,V++):(b=r,me===0&&H(E)),b!==r?(w=Te(),w!==r?(t.charCodeAt(V)===47?(S=n,V++):(S=r,me===0&&H(u)),S!==r?(y=Te(),y!==r?(te=qe,b=x(),qe=b):(V=qe,qe=r)):(V=qe,qe=r)):(V=qe,qe=r)):(V=qe,qe=r),qe===r&&(qe=V,b=Te(),b!==r&&(te=qe,b=x()),qe=b),qe}function Te(){var qe,b,w;if(qe=V,b=[],C.test(t.charAt(V))?(w=t.charAt(V),V++):(w=r,me===0&&H(R)),w!==r)for(;w!==r;)b.push(w),C.test(t.charAt(V))?(w=t.charAt(V),V++):(w=r,me===0&&H(R));else b=r;return b!==r&&(te=qe,b=x()),qe=b,qe}function Ve(){var qe,b,w;if(qe=V,b=[],N.test(t.charAt(V))?(w=t.charAt(V),V++):(w=r,me===0&&H(U)),w!==r)for(;w!==r;)b.push(w),N.test(t.charAt(V))?(w=t.charAt(V),V++):(w=r,me===0&&H(U));else b=r;return b!==r&&(te=qe,b=x()),qe=b,qe}if(he=a(),he!==r&&V===t.length)return he;throw he!==r&&V<t.length&&H(ee()),Re(ue,fe<t.length?t.charAt(fe):null,fe<t.length?At(fe,fe+1):At(fe,fe))}nW.exports={SyntaxError:Kg,parse:g8e}});function MD(t){let e=t.match(/^\\*{1,2}\\/(.*)/);if(e)throw new Error(`The override for '${t}' includes a glob pattern. Glob patterns have been removed since their behaviours don't match what you'd expect. Set the override to '${e[1]}' instead.`);try{return(0,sW.parse)(t)}catch(r){throw r.location&&(r.message=r.message.replace(/(\\.)?$/,` (line ${r.location.start.line}, column ${r.location.start.column})$1`)),r}}function UD(t){let e=\"\";return t.from&&(e+=t.from.fullName,t.from.description&&(e+=`@${t.from.description}`),e+=\"/\"),e+=t.descriptor.fullName,t.descriptor.description&&(e+=`@${t.descriptor.description}`),e}var sW,oW=Et(()=>{sW=$e(iW())});var Vg=_((Obt,zg)=>{\"use strict\";function aW(t){return typeof t>\"u\"||t===null}function d8e(t){return typeof t==\"object\"&&t!==null}function m8e(t){return Array.isArray(t)?t:aW(t)?[]:[t]}function y8e(t,e){var r,o,a,n;if(e)for(n=Object.keys(e),r=0,o=n.length;r<o;r+=1)a=n[r],t[a]=e[a];return t}function E8e(t,e){var r=\"\",o;for(o=0;o<e;o+=1)r+=t;return r}function C8e(t){return t===0&&Number.NEGATIVE_INFINITY===1/t}zg.exports.isNothing=aW;zg.exports.isObject=d8e;zg.exports.toArray=m8e;zg.exports.repeat=E8e;zg.exports.isNegativeZero=C8e;zg.exports.extend=y8e});var Ay=_((Mbt,lW)=>{\"use strict\";function Jw(t,e){Error.call(this),this.name=\"YAMLException\",this.reason=t,this.mark=e,this.message=(this.reason||\"(unknown reason)\")+(this.mark?\" \"+this.mark.toString():\"\"),Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=new Error().stack||\"\"}Jw.prototype=Object.create(Error.prototype);Jw.prototype.constructor=Jw;Jw.prototype.toString=function(e){var r=this.name+\": \";return r+=this.reason||\"(unknown reason)\",!e&&this.mark&&(r+=\" \"+this.mark.toString()),r};lW.exports=Jw});var AW=_((Ubt,uW)=>{\"use strict\";var cW=Vg();function AT(t,e,r,o,a){this.name=t,this.buffer=e,this.position=r,this.line=o,this.column=a}AT.prototype.getSnippet=function(e,r){var o,a,n,u,A;if(!this.buffer)return null;for(e=e||4,r=r||75,o=\"\",a=this.position;a>0&&`\\0\\r\n\\x85\\u2028\\u2029`.indexOf(this.buffer.charAt(a-1))===-1;)if(a-=1,this.position-a>r/2-1){o=\" ... \",a+=5;break}for(n=\"\",u=this.position;u<this.buffer.length&&`\\0\\r\n\\x85\\u2028\\u2029`.indexOf(this.buffer.charAt(u))===-1;)if(u+=1,u-this.position>r/2-1){n=\" ... \",u-=5;break}return A=this.buffer.slice(a,u),cW.repeat(\" \",e)+o+A+n+`\n`+cW.repeat(\" \",e+this.position-a+o.length)+\"^\"};AT.prototype.toString=function(e){var r,o=\"\";return this.name&&(o+='in \"'+this.name+'\" '),o+=\"at line \"+(this.line+1)+\", column \"+(this.column+1),e||(r=this.getSnippet(),r&&(o+=`:\n`+r)),o};uW.exports=AT});var os=_((_bt,pW)=>{\"use strict\";var fW=Ay(),w8e=[\"kind\",\"resolve\",\"construct\",\"instanceOf\",\"predicate\",\"represent\",\"defaultStyle\",\"styleAliases\"],I8e=[\"scalar\",\"sequence\",\"mapping\"];function B8e(t){var e={};return t!==null&&Object.keys(t).forEach(function(r){t[r].forEach(function(o){e[String(o)]=r})}),e}function v8e(t,e){if(e=e||{},Object.keys(e).forEach(function(r){if(w8e.indexOf(r)===-1)throw new fW('Unknown option \"'+r+'\" is met in definition of \"'+t+'\" YAML type.')}),this.tag=t,this.kind=e.kind||null,this.resolve=e.resolve||function(){return!0},this.construct=e.construct||function(r){return r},this.instanceOf=e.instanceOf||null,this.predicate=e.predicate||null,this.represent=e.represent||null,this.defaultStyle=e.defaultStyle||null,this.styleAliases=B8e(e.styleAliases||null),I8e.indexOf(this.kind)===-1)throw new fW('Unknown kind \"'+this.kind+'\" is specified for \"'+t+'\" YAML type.')}pW.exports=v8e});var Jg=_((Hbt,gW)=>{\"use strict\";var hW=Vg(),_D=Ay(),D8e=os();function fT(t,e,r){var o=[];return t.include.forEach(function(a){r=fT(a,e,r)}),t[e].forEach(function(a){r.forEach(function(n,u){n.tag===a.tag&&n.kind===a.kind&&o.push(u)}),r.push(a)}),r.filter(function(a,n){return o.indexOf(n)===-1})}function P8e(){var t={scalar:{},sequence:{},mapping:{},fallback:{}},e,r;function o(a){t[a.kind][a.tag]=t.fallback[a.tag]=a}for(e=0,r=arguments.length;e<r;e+=1)arguments[e].forEach(o);return t}function fy(t){this.include=t.include||[],this.implicit=t.implicit||[],this.explicit=t.explicit||[],this.implicit.forEach(function(e){if(e.loadKind&&e.loadKind!==\"scalar\")throw new _D(\"There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.\")}),this.compiledImplicit=fT(this,\"implicit\",[]),this.compiledExplicit=fT(this,\"explicit\",[]),this.compiledTypeMap=P8e(this.compiledImplicit,this.compiledExplicit)}fy.DEFAULT=null;fy.create=function(){var e,r;switch(arguments.length){case 1:e=fy.DEFAULT,r=arguments[0];break;case 2:e=arguments[0],r=arguments[1];break;default:throw new _D(\"Wrong number of arguments for Schema.create function\")}if(e=hW.toArray(e),r=hW.toArray(r),!e.every(function(o){return o instanceof fy}))throw new _D(\"Specified list of super schemas (or a single Schema object) contains a non-Schema object.\");if(!r.every(function(o){return o instanceof D8e}))throw new _D(\"Specified list of YAML types (or a single Type object) contains a non-Type object.\");return new fy({include:e,explicit:r})};gW.exports=fy});var mW=_((qbt,dW)=>{\"use strict\";var S8e=os();dW.exports=new S8e(\"tag:yaml.org,2002:str\",{kind:\"scalar\",construct:function(t){return t!==null?t:\"\"}})});var EW=_((Gbt,yW)=>{\"use strict\";var b8e=os();yW.exports=new b8e(\"tag:yaml.org,2002:seq\",{kind:\"sequence\",construct:function(t){return t!==null?t:[]}})});var wW=_((jbt,CW)=>{\"use strict\";var x8e=os();CW.exports=new x8e(\"tag:yaml.org,2002:map\",{kind:\"mapping\",construct:function(t){return t!==null?t:{}}})});var HD=_((Ybt,IW)=>{\"use strict\";var k8e=Jg();IW.exports=new k8e({explicit:[mW(),EW(),wW()]})});var vW=_((Wbt,BW)=>{\"use strict\";var Q8e=os();function F8e(t){if(t===null)return!0;var e=t.length;return e===1&&t===\"~\"||e===4&&(t===\"null\"||t===\"Null\"||t===\"NULL\")}function R8e(){return null}function T8e(t){return t===null}BW.exports=new Q8e(\"tag:yaml.org,2002:null\",{kind:\"scalar\",resolve:F8e,construct:R8e,predicate:T8e,represent:{canonical:function(){return\"~\"},lowercase:function(){return\"null\"},uppercase:function(){return\"NULL\"},camelcase:function(){return\"Null\"}},defaultStyle:\"lowercase\"})});var PW=_((Kbt,DW)=>{\"use strict\";var L8e=os();function N8e(t){if(t===null)return!1;var e=t.length;return e===4&&(t===\"true\"||t===\"True\"||t===\"TRUE\")||e===5&&(t===\"false\"||t===\"False\"||t===\"FALSE\")}function O8e(t){return t===\"true\"||t===\"True\"||t===\"TRUE\"}function M8e(t){return Object.prototype.toString.call(t)===\"[object Boolean]\"}DW.exports=new L8e(\"tag:yaml.org,2002:bool\",{kind:\"scalar\",resolve:N8e,construct:O8e,predicate:M8e,represent:{lowercase:function(t){return t?\"true\":\"false\"},uppercase:function(t){return t?\"TRUE\":\"FALSE\"},camelcase:function(t){return t?\"True\":\"False\"}},defaultStyle:\"lowercase\"})});var bW=_((zbt,SW)=>{\"use strict\";var U8e=Vg(),_8e=os();function H8e(t){return 48<=t&&t<=57||65<=t&&t<=70||97<=t&&t<=102}function q8e(t){return 48<=t&&t<=55}function G8e(t){return 48<=t&&t<=57}function j8e(t){if(t===null)return!1;var e=t.length,r=0,o=!1,a;if(!e)return!1;if(a=t[r],(a===\"-\"||a===\"+\")&&(a=t[++r]),a===\"0\"){if(r+1===e)return!0;if(a=t[++r],a===\"b\"){for(r++;r<e;r++)if(a=t[r],a!==\"_\"){if(a!==\"0\"&&a!==\"1\")return!1;o=!0}return o&&a!==\"_\"}if(a===\"x\"){for(r++;r<e;r++)if(a=t[r],a!==\"_\"){if(!H8e(t.charCodeAt(r)))return!1;o=!0}return o&&a!==\"_\"}for(;r<e;r++)if(a=t[r],a!==\"_\"){if(!q8e(t.charCodeAt(r)))return!1;o=!0}return o&&a!==\"_\"}if(a===\"_\")return!1;for(;r<e;r++)if(a=t[r],a!==\"_\"){if(a===\":\")break;if(!G8e(t.charCodeAt(r)))return!1;o=!0}return!o||a===\"_\"?!1:a!==\":\"?!0:/^(:[0-5]?[0-9])+$/.test(t.slice(r))}function Y8e(t){var e=t,r=1,o,a,n=[];return e.indexOf(\"_\")!==-1&&(e=e.replace(/_/g,\"\")),o=e[0],(o===\"-\"||o===\"+\")&&(o===\"-\"&&(r=-1),e=e.slice(1),o=e[0]),e===\"0\"?0:o===\"0\"?e[1]===\"b\"?r*parseInt(e.slice(2),2):e[1]===\"x\"?r*parseInt(e,16):r*parseInt(e,8):e.indexOf(\":\")!==-1?(e.split(\":\").forEach(function(u){n.unshift(parseInt(u,10))}),e=0,a=1,n.forEach(function(u){e+=u*a,a*=60}),r*e):r*parseInt(e,10)}function W8e(t){return Object.prototype.toString.call(t)===\"[object Number]\"&&t%1===0&&!U8e.isNegativeZero(t)}SW.exports=new _8e(\"tag:yaml.org,2002:int\",{kind:\"scalar\",resolve:j8e,construct:Y8e,predicate:W8e,represent:{binary:function(t){return t>=0?\"0b\"+t.toString(2):\"-0b\"+t.toString(2).slice(1)},octal:function(t){return t>=0?\"0\"+t.toString(8):\"-0\"+t.toString(8).slice(1)},decimal:function(t){return t.toString(10)},hexadecimal:function(t){return t>=0?\"0x\"+t.toString(16).toUpperCase():\"-0x\"+t.toString(16).toUpperCase().slice(1)}},defaultStyle:\"decimal\",styleAliases:{binary:[2,\"bin\"],octal:[8,\"oct\"],decimal:[10,\"dec\"],hexadecimal:[16,\"hex\"]}})});var QW=_((Vbt,kW)=>{\"use strict\";var xW=Vg(),K8e=os(),z8e=new RegExp(\"^(?:[-+]?(?:0|[1-9][0-9_]*)(?:\\\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?|\\\\.[0-9_]+(?:[eE][-+]?[0-9]+)?|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\\\.[0-9_]*|[-+]?\\\\.(?:inf|Inf|INF)|\\\\.(?:nan|NaN|NAN))$\");function V8e(t){return!(t===null||!z8e.test(t)||t[t.length-1]===\"_\")}function J8e(t){var e,r,o,a;return e=t.replace(/_/g,\"\").toLowerCase(),r=e[0]===\"-\"?-1:1,a=[],\"+-\".indexOf(e[0])>=0&&(e=e.slice(1)),e===\".inf\"?r===1?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY:e===\".nan\"?NaN:e.indexOf(\":\")>=0?(e.split(\":\").forEach(function(n){a.unshift(parseFloat(n,10))}),e=0,o=1,a.forEach(function(n){e+=n*o,o*=60}),r*e):r*parseFloat(e,10)}var X8e=/^[-+]?[0-9]+e/;function Z8e(t,e){var r;if(isNaN(t))switch(e){case\"lowercase\":return\".nan\";case\"uppercase\":return\".NAN\";case\"camelcase\":return\".NaN\"}else if(Number.POSITIVE_INFINITY===t)switch(e){case\"lowercase\":return\".inf\";case\"uppercase\":return\".INF\";case\"camelcase\":return\".Inf\"}else if(Number.NEGATIVE_INFINITY===t)switch(e){case\"lowercase\":return\"-.inf\";case\"uppercase\":return\"-.INF\";case\"camelcase\":return\"-.Inf\"}else if(xW.isNegativeZero(t))return\"-0.0\";return r=t.toString(10),X8e.test(r)?r.replace(\"e\",\".e\"):r}function $8e(t){return Object.prototype.toString.call(t)===\"[object Number]\"&&(t%1!==0||xW.isNegativeZero(t))}kW.exports=new K8e(\"tag:yaml.org,2002:float\",{kind:\"scalar\",resolve:V8e,construct:J8e,predicate:$8e,represent:Z8e,defaultStyle:\"lowercase\"})});var pT=_((Jbt,FW)=>{\"use strict\";var eHe=Jg();FW.exports=new eHe({include:[HD()],implicit:[vW(),PW(),bW(),QW()]})});var hT=_((Xbt,RW)=>{\"use strict\";var tHe=Jg();RW.exports=new tHe({include:[pT()]})});var OW=_((Zbt,NW)=>{\"use strict\";var rHe=os(),TW=new RegExp(\"^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])$\"),LW=new RegExp(\"^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:[Tt]|[ \\\\t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\\\.([0-9]*))?(?:[ \\\\t]*(Z|([-+])([0-9][0-9]?)(?::([0-9][0-9]))?))?$\");function nHe(t){return t===null?!1:TW.exec(t)!==null||LW.exec(t)!==null}function iHe(t){var e,r,o,a,n,u,A,p=0,h=null,E,I,v;if(e=TW.exec(t),e===null&&(e=LW.exec(t)),e===null)throw new Error(\"Date resolve error\");if(r=+e[1],o=+e[2]-1,a=+e[3],!e[4])return new Date(Date.UTC(r,o,a));if(n=+e[4],u=+e[5],A=+e[6],e[7]){for(p=e[7].slice(0,3);p.length<3;)p+=\"0\";p=+p}return e[9]&&(E=+e[10],I=+(e[11]||0),h=(E*60+I)*6e4,e[9]===\"-\"&&(h=-h)),v=new Date(Date.UTC(r,o,a,n,u,A,p)),h&&v.setTime(v.getTime()-h),v}function sHe(t){return t.toISOString()}NW.exports=new rHe(\"tag:yaml.org,2002:timestamp\",{kind:\"scalar\",resolve:nHe,construct:iHe,instanceOf:Date,represent:sHe})});var UW=_(($bt,MW)=>{\"use strict\";var oHe=os();function aHe(t){return t===\"<<\"||t===null}MW.exports=new oHe(\"tag:yaml.org,2002:merge\",{kind:\"scalar\",resolve:aHe})});var qW=_((ext,HW)=>{\"use strict\";var Xg;try{_W=ve,Xg=_W(\"buffer\").Buffer}catch{}var _W,lHe=os(),gT=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\\r`;function cHe(t){if(t===null)return!1;var e,r,o=0,a=t.length,n=gT;for(r=0;r<a;r++)if(e=n.indexOf(t.charAt(r)),!(e>64)){if(e<0)return!1;o+=6}return o%8===0}function uHe(t){var e,r,o=t.replace(/[\\r\\n=]/g,\"\"),a=o.length,n=gT,u=0,A=[];for(e=0;e<a;e++)e%4===0&&e&&(A.push(u>>16&255),A.push(u>>8&255),A.push(u&255)),u=u<<6|n.indexOf(o.charAt(e));return r=a%4*6,r===0?(A.push(u>>16&255),A.push(u>>8&255),A.push(u&255)):r===18?(A.push(u>>10&255),A.push(u>>2&255)):r===12&&A.push(u>>4&255),Xg?Xg.from?Xg.from(A):new Xg(A):A}function AHe(t){var e=\"\",r=0,o,a,n=t.length,u=gT;for(o=0;o<n;o++)o%3===0&&o&&(e+=u[r>>18&63],e+=u[r>>12&63],e+=u[r>>6&63],e+=u[r&63]),r=(r<<8)+t[o];return a=n%3,a===0?(e+=u[r>>18&63],e+=u[r>>12&63],e+=u[r>>6&63],e+=u[r&63]):a===2?(e+=u[r>>10&63],e+=u[r>>4&63],e+=u[r<<2&63],e+=u[64]):a===1&&(e+=u[r>>2&63],e+=u[r<<4&63],e+=u[64],e+=u[64]),e}function fHe(t){return Xg&&Xg.isBuffer(t)}HW.exports=new lHe(\"tag:yaml.org,2002:binary\",{kind:\"scalar\",resolve:cHe,construct:uHe,predicate:fHe,represent:AHe})});var jW=_((rxt,GW)=>{\"use strict\";var pHe=os(),hHe=Object.prototype.hasOwnProperty,gHe=Object.prototype.toString;function dHe(t){if(t===null)return!0;var e=[],r,o,a,n,u,A=t;for(r=0,o=A.length;r<o;r+=1){if(a=A[r],u=!1,gHe.call(a)!==\"[object Object]\")return!1;for(n in a)if(hHe.call(a,n))if(!u)u=!0;else return!1;if(!u)return!1;if(e.indexOf(n)===-1)e.push(n);else return!1}return!0}function mHe(t){return t!==null?t:[]}GW.exports=new pHe(\"tag:yaml.org,2002:omap\",{kind:\"sequence\",resolve:dHe,construct:mHe})});var WW=_((nxt,YW)=>{\"use strict\";var yHe=os(),EHe=Object.prototype.toString;function CHe(t){if(t===null)return!0;var e,r,o,a,n,u=t;for(n=new Array(u.length),e=0,r=u.length;e<r;e+=1){if(o=u[e],EHe.call(o)!==\"[object Object]\"||(a=Object.keys(o),a.length!==1))return!1;n[e]=[a[0],o[a[0]]]}return!0}function wHe(t){if(t===null)return[];var e,r,o,a,n,u=t;for(n=new Array(u.length),e=0,r=u.length;e<r;e+=1)o=u[e],a=Object.keys(o),n[e]=[a[0],o[a[0]]];return n}YW.exports=new yHe(\"tag:yaml.org,2002:pairs\",{kind:\"sequence\",resolve:CHe,construct:wHe})});var zW=_((ixt,KW)=>{\"use strict\";var IHe=os(),BHe=Object.prototype.hasOwnProperty;function vHe(t){if(t===null)return!0;var e,r=t;for(e in r)if(BHe.call(r,e)&&r[e]!==null)return!1;return!0}function DHe(t){return t!==null?t:{}}KW.exports=new IHe(\"tag:yaml.org,2002:set\",{kind:\"mapping\",resolve:vHe,construct:DHe})});var py=_((sxt,VW)=>{\"use strict\";var PHe=Jg();VW.exports=new PHe({include:[hT()],implicit:[OW(),UW()],explicit:[qW(),jW(),WW(),zW()]})});var XW=_((oxt,JW)=>{\"use strict\";var SHe=os();function bHe(){return!0}function xHe(){}function kHe(){return\"\"}function QHe(t){return typeof t>\"u\"}JW.exports=new SHe(\"tag:yaml.org,2002:js/undefined\",{kind:\"scalar\",resolve:bHe,construct:xHe,predicate:QHe,represent:kHe})});var $W=_((axt,ZW)=>{\"use strict\";var FHe=os();function RHe(t){if(t===null||t.length===0)return!1;var e=t,r=/\\/([gim]*)$/.exec(t),o=\"\";return!(e[0]===\"/\"&&(r&&(o=r[1]),o.length>3||e[e.length-o.length-1]!==\"/\"))}function THe(t){var e=t,r=/\\/([gim]*)$/.exec(t),o=\"\";return e[0]===\"/\"&&(r&&(o=r[1]),e=e.slice(1,e.length-o.length-1)),new RegExp(e,o)}function LHe(t){var e=\"/\"+t.source+\"/\";return t.global&&(e+=\"g\"),t.multiline&&(e+=\"m\"),t.ignoreCase&&(e+=\"i\"),e}function NHe(t){return Object.prototype.toString.call(t)===\"[object RegExp]\"}ZW.exports=new FHe(\"tag:yaml.org,2002:js/regexp\",{kind:\"scalar\",resolve:RHe,construct:THe,predicate:NHe,represent:LHe})});var rK=_((lxt,tK)=>{\"use strict\";var qD;try{eK=ve,qD=eK(\"esprima\")}catch{typeof window<\"u\"&&(qD=window.esprima)}var eK,OHe=os();function MHe(t){if(t===null)return!1;try{var e=\"(\"+t+\")\",r=qD.parse(e,{range:!0});return!(r.type!==\"Program\"||r.body.length!==1||r.body[0].type!==\"ExpressionStatement\"||r.body[0].expression.type!==\"ArrowFunctionExpression\"&&r.body[0].expression.type!==\"FunctionExpression\")}catch{return!1}}function UHe(t){var e=\"(\"+t+\")\",r=qD.parse(e,{range:!0}),o=[],a;if(r.type!==\"Program\"||r.body.length!==1||r.body[0].type!==\"ExpressionStatement\"||r.body[0].expression.type!==\"ArrowFunctionExpression\"&&r.body[0].expression.type!==\"FunctionExpression\")throw new Error(\"Failed to resolve function\");return r.body[0].expression.params.forEach(function(n){o.push(n.name)}),a=r.body[0].expression.body.range,r.body[0].expression.body.type===\"BlockStatement\"?new Function(o,e.slice(a[0]+1,a[1]-1)):new Function(o,\"return \"+e.slice(a[0],a[1]))}function _He(t){return t.toString()}function HHe(t){return Object.prototype.toString.call(t)===\"[object Function]\"}tK.exports=new OHe(\"tag:yaml.org,2002:js/function\",{kind:\"scalar\",resolve:MHe,construct:UHe,predicate:HHe,represent:_He})});var Xw=_((uxt,iK)=>{\"use strict\";var nK=Jg();iK.exports=nK.DEFAULT=new nK({include:[py()],explicit:[XW(),$W(),rK()]})});var BK=_((Axt,Zw)=>{\"use strict\";var yf=Vg(),AK=Ay(),qHe=AW(),fK=py(),GHe=Xw(),Wp=Object.prototype.hasOwnProperty,GD=1,pK=2,hK=3,jD=4,dT=1,jHe=2,sK=3,YHe=/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F-\\x84\\x86-\\x9F\\uFFFE\\uFFFF]|[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?:[^\\uD800-\\uDBFF]|^)[\\uDC00-\\uDFFF]/,WHe=/[\\x85\\u2028\\u2029]/,KHe=/[,\\[\\]\\{\\}]/,gK=/^(?:!|!!|![a-z\\-]+!)$/i,dK=/^(?:!|[^,\\[\\]\\{\\}])(?:%[0-9a-f]{2}|[0-9a-z\\-#;\\/\\?:@&=\\+\\$,_\\.!~\\*'\\(\\)\\[\\]])*$/i;function oK(t){return Object.prototype.toString.call(t)}function qu(t){return t===10||t===13}function $g(t){return t===9||t===32}function Ia(t){return t===9||t===32||t===10||t===13}function hy(t){return t===44||t===91||t===93||t===123||t===125}function zHe(t){var e;return 48<=t&&t<=57?t-48:(e=t|32,97<=e&&e<=102?e-97+10:-1)}function VHe(t){return t===120?2:t===117?4:t===85?8:0}function JHe(t){return 48<=t&&t<=57?t-48:-1}function aK(t){return t===48?\"\\0\":t===97?\"\\x07\":t===98?\"\\b\":t===116||t===9?\"\t\":t===110?`\n`:t===118?\"\\v\":t===102?\"\\f\":t===114?\"\\r\":t===101?\"\\x1B\":t===32?\" \":t===34?'\"':t===47?\"/\":t===92?\"\\\\\":t===78?\"\\x85\":t===95?\"\\xA0\":t===76?\"\\u2028\":t===80?\"\\u2029\":\"\"}function XHe(t){return t<=65535?String.fromCharCode(t):String.fromCharCode((t-65536>>10)+55296,(t-65536&1023)+56320)}var mK=new Array(256),yK=new Array(256);for(Zg=0;Zg<256;Zg++)mK[Zg]=aK(Zg)?1:0,yK[Zg]=aK(Zg);var Zg;function ZHe(t,e){this.input=t,this.filename=e.filename||null,this.schema=e.schema||GHe,this.onWarning=e.onWarning||null,this.legacy=e.legacy||!1,this.json=e.json||!1,this.listener=e.listener||null,this.implicitTypes=this.schema.compiledImplicit,this.typeMap=this.schema.compiledTypeMap,this.length=t.length,this.position=0,this.line=0,this.lineStart=0,this.lineIndent=0,this.documents=[]}function EK(t,e){return new AK(e,new qHe(t.filename,t.input,t.position,t.line,t.position-t.lineStart))}function Sr(t,e){throw EK(t,e)}function YD(t,e){t.onWarning&&t.onWarning.call(null,EK(t,e))}var lK={YAML:function(e,r,o){var a,n,u;e.version!==null&&Sr(e,\"duplication of %YAML directive\"),o.length!==1&&Sr(e,\"YAML directive accepts exactly one argument\"),a=/^([0-9]+)\\.([0-9]+)$/.exec(o[0]),a===null&&Sr(e,\"ill-formed argument of the YAML directive\"),n=parseInt(a[1],10),u=parseInt(a[2],10),n!==1&&Sr(e,\"unacceptable YAML version of the document\"),e.version=o[0],e.checkLineBreaks=u<2,u!==1&&u!==2&&YD(e,\"unsupported YAML version of the document\")},TAG:function(e,r,o){var a,n;o.length!==2&&Sr(e,\"TAG directive accepts exactly two arguments\"),a=o[0],n=o[1],gK.test(a)||Sr(e,\"ill-formed tag handle (first argument) of the TAG directive\"),Wp.call(e.tagMap,a)&&Sr(e,'there is a previously declared suffix for \"'+a+'\" tag handle'),dK.test(n)||Sr(e,\"ill-formed tag prefix (second argument) of the TAG directive\"),e.tagMap[a]=n}};function Yp(t,e,r,o){var a,n,u,A;if(e<r){if(A=t.input.slice(e,r),o)for(a=0,n=A.length;a<n;a+=1)u=A.charCodeAt(a),u===9||32<=u&&u<=1114111||Sr(t,\"expected valid JSON character\");else YHe.test(A)&&Sr(t,\"the stream contains non-printable characters\");t.result+=A}}function cK(t,e,r,o){var a,n,u,A;for(yf.isObject(r)||Sr(t,\"cannot merge mappings; the provided source object is unacceptable\"),a=Object.keys(r),u=0,A=a.length;u<A;u+=1)n=a[u],Wp.call(e,n)||(e[n]=r[n],o[n]=!0)}function gy(t,e,r,o,a,n,u,A){var p,h;if(Array.isArray(a))for(a=Array.prototype.slice.call(a),p=0,h=a.length;p<h;p+=1)Array.isArray(a[p])&&Sr(t,\"nested arrays are not supported inside keys\"),typeof a==\"object\"&&oK(a[p])===\"[object Object]\"&&(a[p]=\"[object Object]\");if(typeof a==\"object\"&&oK(a)===\"[object Object]\"&&(a=\"[object Object]\"),a=String(a),e===null&&(e={}),o===\"tag:yaml.org,2002:merge\")if(Array.isArray(n))for(p=0,h=n.length;p<h;p+=1)cK(t,e,n[p],r);else cK(t,e,n,r);else!t.json&&!Wp.call(r,a)&&Wp.call(e,a)&&(t.line=u||t.line,t.position=A||t.position,Sr(t,\"duplicated mapping key\")),e[a]=n,delete r[a];return e}function mT(t){var e;e=t.input.charCodeAt(t.position),e===10?t.position++:e===13?(t.position++,t.input.charCodeAt(t.position)===10&&t.position++):Sr(t,\"a line break is expected\"),t.line+=1,t.lineStart=t.position}function Wi(t,e,r){for(var o=0,a=t.input.charCodeAt(t.position);a!==0;){for(;$g(a);)a=t.input.charCodeAt(++t.position);if(e&&a===35)do a=t.input.charCodeAt(++t.position);while(a!==10&&a!==13&&a!==0);if(qu(a))for(mT(t),a=t.input.charCodeAt(t.position),o++,t.lineIndent=0;a===32;)t.lineIndent++,a=t.input.charCodeAt(++t.position);else break}return r!==-1&&o!==0&&t.lineIndent<r&&YD(t,\"deficient indentation\"),o}function WD(t){var e=t.position,r;return r=t.input.charCodeAt(e),!!((r===45||r===46)&&r===t.input.charCodeAt(e+1)&&r===t.input.charCodeAt(e+2)&&(e+=3,r=t.input.charCodeAt(e),r===0||Ia(r)))}function yT(t,e){e===1?t.result+=\" \":e>1&&(t.result+=yf.repeat(`\n`,e-1))}function $He(t,e,r){var o,a,n,u,A,p,h,E,I=t.kind,v=t.result,x;if(x=t.input.charCodeAt(t.position),Ia(x)||hy(x)||x===35||x===38||x===42||x===33||x===124||x===62||x===39||x===34||x===37||x===64||x===96||(x===63||x===45)&&(a=t.input.charCodeAt(t.position+1),Ia(a)||r&&hy(a)))return!1;for(t.kind=\"scalar\",t.result=\"\",n=u=t.position,A=!1;x!==0;){if(x===58){if(a=t.input.charCodeAt(t.position+1),Ia(a)||r&&hy(a))break}else if(x===35){if(o=t.input.charCodeAt(t.position-1),Ia(o))break}else{if(t.position===t.lineStart&&WD(t)||r&&hy(x))break;if(qu(x))if(p=t.line,h=t.lineStart,E=t.lineIndent,Wi(t,!1,-1),t.lineIndent>=e){A=!0,x=t.input.charCodeAt(t.position);continue}else{t.position=u,t.line=p,t.lineStart=h,t.lineIndent=E;break}}A&&(Yp(t,n,u,!1),yT(t,t.line-p),n=u=t.position,A=!1),$g(x)||(u=t.position+1),x=t.input.charCodeAt(++t.position)}return Yp(t,n,u,!1),t.result?!0:(t.kind=I,t.result=v,!1)}function e6e(t,e){var r,o,a;if(r=t.input.charCodeAt(t.position),r!==39)return!1;for(t.kind=\"scalar\",t.result=\"\",t.position++,o=a=t.position;(r=t.input.charCodeAt(t.position))!==0;)if(r===39)if(Yp(t,o,t.position,!0),r=t.input.charCodeAt(++t.position),r===39)o=t.position,t.position++,a=t.position;else return!0;else qu(r)?(Yp(t,o,a,!0),yT(t,Wi(t,!1,e)),o=a=t.position):t.position===t.lineStart&&WD(t)?Sr(t,\"unexpected end of the document within a single quoted scalar\"):(t.position++,a=t.position);Sr(t,\"unexpected end of the stream within a single quoted scalar\")}function t6e(t,e){var r,o,a,n,u,A;if(A=t.input.charCodeAt(t.position),A!==34)return!1;for(t.kind=\"scalar\",t.result=\"\",t.position++,r=o=t.position;(A=t.input.charCodeAt(t.position))!==0;){if(A===34)return Yp(t,r,t.position,!0),t.position++,!0;if(A===92){if(Yp(t,r,t.position,!0),A=t.input.charCodeAt(++t.position),qu(A))Wi(t,!1,e);else if(A<256&&mK[A])t.result+=yK[A],t.position++;else if((u=VHe(A))>0){for(a=u,n=0;a>0;a--)A=t.input.charCodeAt(++t.position),(u=zHe(A))>=0?n=(n<<4)+u:Sr(t,\"expected hexadecimal character\");t.result+=XHe(n),t.position++}else Sr(t,\"unknown escape sequence\");r=o=t.position}else qu(A)?(Yp(t,r,o,!0),yT(t,Wi(t,!1,e)),r=o=t.position):t.position===t.lineStart&&WD(t)?Sr(t,\"unexpected end of the document within a double quoted scalar\"):(t.position++,o=t.position)}Sr(t,\"unexpected end of the stream within a double quoted scalar\")}function r6e(t,e){var r=!0,o,a=t.tag,n,u=t.anchor,A,p,h,E,I,v={},x,C,R,N;if(N=t.input.charCodeAt(t.position),N===91)p=93,I=!1,n=[];else if(N===123)p=125,I=!0,n={};else return!1;for(t.anchor!==null&&(t.anchorMap[t.anchor]=n),N=t.input.charCodeAt(++t.position);N!==0;){if(Wi(t,!0,e),N=t.input.charCodeAt(t.position),N===p)return t.position++,t.tag=a,t.anchor=u,t.kind=I?\"mapping\":\"sequence\",t.result=n,!0;r||Sr(t,\"missed comma between flow collection entries\"),C=x=R=null,h=E=!1,N===63&&(A=t.input.charCodeAt(t.position+1),Ia(A)&&(h=E=!0,t.position++,Wi(t,!0,e))),o=t.line,dy(t,e,GD,!1,!0),C=t.tag,x=t.result,Wi(t,!0,e),N=t.input.charCodeAt(t.position),(E||t.line===o)&&N===58&&(h=!0,N=t.input.charCodeAt(++t.position),Wi(t,!0,e),dy(t,e,GD,!1,!0),R=t.result),I?gy(t,n,v,C,x,R):h?n.push(gy(t,null,v,C,x,R)):n.push(x),Wi(t,!0,e),N=t.input.charCodeAt(t.position),N===44?(r=!0,N=t.input.charCodeAt(++t.position)):r=!1}Sr(t,\"unexpected end of the stream within a flow collection\")}function n6e(t,e){var r,o,a=dT,n=!1,u=!1,A=e,p=0,h=!1,E,I;if(I=t.input.charCodeAt(t.position),I===124)o=!1;else if(I===62)o=!0;else return!1;for(t.kind=\"scalar\",t.result=\"\";I!==0;)if(I=t.input.charCodeAt(++t.position),I===43||I===45)dT===a?a=I===43?sK:jHe:Sr(t,\"repeat of a chomping mode identifier\");else if((E=JHe(I))>=0)E===0?Sr(t,\"bad explicit indentation width of a block scalar; it cannot be less than one\"):u?Sr(t,\"repeat of an indentation width identifier\"):(A=e+E-1,u=!0);else break;if($g(I)){do I=t.input.charCodeAt(++t.position);while($g(I));if(I===35)do I=t.input.charCodeAt(++t.position);while(!qu(I)&&I!==0)}for(;I!==0;){for(mT(t),t.lineIndent=0,I=t.input.charCodeAt(t.position);(!u||t.lineIndent<A)&&I===32;)t.lineIndent++,I=t.input.charCodeAt(++t.position);if(!u&&t.lineIndent>A&&(A=t.lineIndent),qu(I)){p++;continue}if(t.lineIndent<A){a===sK?t.result+=yf.repeat(`\n`,n?1+p:p):a===dT&&n&&(t.result+=`\n`);break}for(o?$g(I)?(h=!0,t.result+=yf.repeat(`\n`,n?1+p:p)):h?(h=!1,t.result+=yf.repeat(`\n`,p+1)):p===0?n&&(t.result+=\" \"):t.result+=yf.repeat(`\n`,p):t.result+=yf.repeat(`\n`,n?1+p:p),n=!0,u=!0,p=0,r=t.position;!qu(I)&&I!==0;)I=t.input.charCodeAt(++t.position);Yp(t,r,t.position,!1)}return!0}function uK(t,e){var r,o=t.tag,a=t.anchor,n=[],u,A=!1,p;for(t.anchor!==null&&(t.anchorMap[t.anchor]=n),p=t.input.charCodeAt(t.position);p!==0&&!(p!==45||(u=t.input.charCodeAt(t.position+1),!Ia(u)));){if(A=!0,t.position++,Wi(t,!0,-1)&&t.lineIndent<=e){n.push(null),p=t.input.charCodeAt(t.position);continue}if(r=t.line,dy(t,e,hK,!1,!0),n.push(t.result),Wi(t,!0,-1),p=t.input.charCodeAt(t.position),(t.line===r||t.lineIndent>e)&&p!==0)Sr(t,\"bad indentation of a sequence entry\");else if(t.lineIndent<e)break}return A?(t.tag=o,t.anchor=a,t.kind=\"sequence\",t.result=n,!0):!1}function i6e(t,e,r){var o,a,n,u,A=t.tag,p=t.anchor,h={},E={},I=null,v=null,x=null,C=!1,R=!1,N;for(t.anchor!==null&&(t.anchorMap[t.anchor]=h),N=t.input.charCodeAt(t.position);N!==0;){if(o=t.input.charCodeAt(t.position+1),n=t.line,u=t.position,(N===63||N===58)&&Ia(o))N===63?(C&&(gy(t,h,E,I,v,null),I=v=x=null),R=!0,C=!0,a=!0):C?(C=!1,a=!0):Sr(t,\"incomplete explicit mapping pair; a key node is missed; or followed by a non-tabulated empty line\"),t.position+=1,N=o;else if(dy(t,r,pK,!1,!0))if(t.line===n){for(N=t.input.charCodeAt(t.position);$g(N);)N=t.input.charCodeAt(++t.position);if(N===58)N=t.input.charCodeAt(++t.position),Ia(N)||Sr(t,\"a whitespace character is expected after the key-value separator within a block mapping\"),C&&(gy(t,h,E,I,v,null),I=v=x=null),R=!0,C=!1,a=!1,I=t.tag,v=t.result;else if(R)Sr(t,\"can not read an implicit mapping pair; a colon is missed\");else return t.tag=A,t.anchor=p,!0}else if(R)Sr(t,\"can not read a block mapping entry; a multiline key may not be an implicit key\");else return t.tag=A,t.anchor=p,!0;else break;if((t.line===n||t.lineIndent>e)&&(dy(t,e,jD,!0,a)&&(C?v=t.result:x=t.result),C||(gy(t,h,E,I,v,x,n,u),I=v=x=null),Wi(t,!0,-1),N=t.input.charCodeAt(t.position)),t.lineIndent>e&&N!==0)Sr(t,\"bad indentation of a mapping entry\");else if(t.lineIndent<e)break}return C&&gy(t,h,E,I,v,null),R&&(t.tag=A,t.anchor=p,t.kind=\"mapping\",t.result=h),R}function s6e(t){var e,r=!1,o=!1,a,n,u;if(u=t.input.charCodeAt(t.position),u!==33)return!1;if(t.tag!==null&&Sr(t,\"duplication of a tag property\"),u=t.input.charCodeAt(++t.position),u===60?(r=!0,u=t.input.charCodeAt(++t.position)):u===33?(o=!0,a=\"!!\",u=t.input.charCodeAt(++t.position)):a=\"!\",e=t.position,r){do u=t.input.charCodeAt(++t.position);while(u!==0&&u!==62);t.position<t.length?(n=t.input.slice(e,t.position),u=t.input.charCodeAt(++t.position)):Sr(t,\"unexpected end of the stream within a verbatim tag\")}else{for(;u!==0&&!Ia(u);)u===33&&(o?Sr(t,\"tag suffix cannot contain exclamation marks\"):(a=t.input.slice(e-1,t.position+1),gK.test(a)||Sr(t,\"named tag handle cannot contain such characters\"),o=!0,e=t.position+1)),u=t.input.charCodeAt(++t.position);n=t.input.slice(e,t.position),KHe.test(n)&&Sr(t,\"tag suffix cannot contain flow indicator characters\")}return n&&!dK.test(n)&&Sr(t,\"tag name cannot contain such characters: \"+n),r?t.tag=n:Wp.call(t.tagMap,a)?t.tag=t.tagMap[a]+n:a===\"!\"?t.tag=\"!\"+n:a===\"!!\"?t.tag=\"tag:yaml.org,2002:\"+n:Sr(t,'undeclared tag handle \"'+a+'\"'),!0}function o6e(t){var e,r;if(r=t.input.charCodeAt(t.position),r!==38)return!1;for(t.anchor!==null&&Sr(t,\"duplication of an anchor property\"),r=t.input.charCodeAt(++t.position),e=t.position;r!==0&&!Ia(r)&&!hy(r);)r=t.input.charCodeAt(++t.position);return t.position===e&&Sr(t,\"name of an anchor node must contain at least one character\"),t.anchor=t.input.slice(e,t.position),!0}function a6e(t){var e,r,o;if(o=t.input.charCodeAt(t.position),o!==42)return!1;for(o=t.input.charCodeAt(++t.position),e=t.position;o!==0&&!Ia(o)&&!hy(o);)o=t.input.charCodeAt(++t.position);return t.position===e&&Sr(t,\"name of an alias node must contain at least one character\"),r=t.input.slice(e,t.position),Wp.call(t.anchorMap,r)||Sr(t,'unidentified alias \"'+r+'\"'),t.result=t.anchorMap[r],Wi(t,!0,-1),!0}function dy(t,e,r,o,a){var n,u,A,p=1,h=!1,E=!1,I,v,x,C,R;if(t.listener!==null&&t.listener(\"open\",t),t.tag=null,t.anchor=null,t.kind=null,t.result=null,n=u=A=jD===r||hK===r,o&&Wi(t,!0,-1)&&(h=!0,t.lineIndent>e?p=1:t.lineIndent===e?p=0:t.lineIndent<e&&(p=-1)),p===1)for(;s6e(t)||o6e(t);)Wi(t,!0,-1)?(h=!0,A=n,t.lineIndent>e?p=1:t.lineIndent===e?p=0:t.lineIndent<e&&(p=-1)):A=!1;if(A&&(A=h||a),(p===1||jD===r)&&(GD===r||pK===r?C=e:C=e+1,R=t.position-t.lineStart,p===1?A&&(uK(t,R)||i6e(t,R,C))||r6e(t,C)?E=!0:(u&&n6e(t,C)||e6e(t,C)||t6e(t,C)?E=!0:a6e(t)?(E=!0,(t.tag!==null||t.anchor!==null)&&Sr(t,\"alias node should not have any properties\")):$He(t,C,GD===r)&&(E=!0,t.tag===null&&(t.tag=\"?\")),t.anchor!==null&&(t.anchorMap[t.anchor]=t.result)):p===0&&(E=A&&uK(t,R))),t.tag!==null&&t.tag!==\"!\")if(t.tag===\"?\"){for(t.result!==null&&t.kind!==\"scalar\"&&Sr(t,'unacceptable node kind for !<?> tag; it should be \"scalar\", not \"'+t.kind+'\"'),I=0,v=t.implicitTypes.length;I<v;I+=1)if(x=t.implicitTypes[I],x.resolve(t.result)){t.result=x.construct(t.result),t.tag=x.tag,t.anchor!==null&&(t.anchorMap[t.anchor]=t.result);break}}else Wp.call(t.typeMap[t.kind||\"fallback\"],t.tag)?(x=t.typeMap[t.kind||\"fallback\"][t.tag],t.result!==null&&x.kind!==t.kind&&Sr(t,\"unacceptable node kind for !<\"+t.tag+'> tag; it should be \"'+x.kind+'\", not \"'+t.kind+'\"'),x.resolve(t.result)?(t.result=x.construct(t.result),t.anchor!==null&&(t.anchorMap[t.anchor]=t.result)):Sr(t,\"cannot resolve a node with !<\"+t.tag+\"> explicit tag\")):Sr(t,\"unknown tag !<\"+t.tag+\">\");return t.listener!==null&&t.listener(\"close\",t),t.tag!==null||t.anchor!==null||E}function l6e(t){var e=t.position,r,o,a,n=!1,u;for(t.version=null,t.checkLineBreaks=t.legacy,t.tagMap={},t.anchorMap={};(u=t.input.charCodeAt(t.position))!==0&&(Wi(t,!0,-1),u=t.input.charCodeAt(t.position),!(t.lineIndent>0||u!==37));){for(n=!0,u=t.input.charCodeAt(++t.position),r=t.position;u!==0&&!Ia(u);)u=t.input.charCodeAt(++t.position);for(o=t.input.slice(r,t.position),a=[],o.length<1&&Sr(t,\"directive name must not be less than one character in length\");u!==0;){for(;$g(u);)u=t.input.charCodeAt(++t.position);if(u===35){do u=t.input.charCodeAt(++t.position);while(u!==0&&!qu(u));break}if(qu(u))break;for(r=t.position;u!==0&&!Ia(u);)u=t.input.charCodeAt(++t.position);a.push(t.input.slice(r,t.position))}u!==0&&mT(t),Wp.call(lK,o)?lK[o](t,o,a):YD(t,'unknown document directive \"'+o+'\"')}if(Wi(t,!0,-1),t.lineIndent===0&&t.input.charCodeAt(t.position)===45&&t.input.charCodeAt(t.position+1)===45&&t.input.charCodeAt(t.position+2)===45?(t.position+=3,Wi(t,!0,-1)):n&&Sr(t,\"directives end mark is expected\"),dy(t,t.lineIndent-1,jD,!1,!0),Wi(t,!0,-1),t.checkLineBreaks&&WHe.test(t.input.slice(e,t.position))&&YD(t,\"non-ASCII line breaks are interpreted as content\"),t.documents.push(t.result),t.position===t.lineStart&&WD(t)){t.input.charCodeAt(t.position)===46&&(t.position+=3,Wi(t,!0,-1));return}if(t.position<t.length-1)Sr(t,\"end of the stream or a document separator is expected\");else return}function CK(t,e){t=String(t),e=e||{},t.length!==0&&(t.charCodeAt(t.length-1)!==10&&t.charCodeAt(t.length-1)!==13&&(t+=`\n`),t.charCodeAt(0)===65279&&(t=t.slice(1)));var r=new ZHe(t,e),o=t.indexOf(\"\\0\");for(o!==-1&&(r.position=o,Sr(r,\"null byte is not allowed in input\")),r.input+=\"\\0\";r.input.charCodeAt(r.position)===32;)r.lineIndent+=1,r.position+=1;for(;r.position<r.length-1;)l6e(r);return r.documents}function wK(t,e,r){e!==null&&typeof e==\"object\"&&typeof r>\"u\"&&(r=e,e=null);var o=CK(t,r);if(typeof e!=\"function\")return o;for(var a=0,n=o.length;a<n;a+=1)e(o[a])}function IK(t,e){var r=CK(t,e);if(r.length!==0){if(r.length===1)return r[0];throw new AK(\"expected a single document in the stream, but found more\")}}function c6e(t,e,r){return typeof e==\"object\"&&e!==null&&typeof r>\"u\"&&(r=e,e=null),wK(t,e,yf.extend({schema:fK},r))}function u6e(t,e){return IK(t,yf.extend({schema:fK},e))}Zw.exports.loadAll=wK;Zw.exports.load=IK;Zw.exports.safeLoadAll=c6e;Zw.exports.safeLoad=u6e});var WK=_((fxt,IT)=>{\"use strict\";var eI=Vg(),tI=Ay(),A6e=Xw(),f6e=py(),QK=Object.prototype.toString,FK=Object.prototype.hasOwnProperty,p6e=9,$w=10,h6e=13,g6e=32,d6e=33,m6e=34,RK=35,y6e=37,E6e=38,C6e=39,w6e=42,TK=44,I6e=45,LK=58,B6e=61,v6e=62,D6e=63,P6e=64,NK=91,OK=93,S6e=96,MK=123,b6e=124,UK=125,vo={};vo[0]=\"\\\\0\";vo[7]=\"\\\\a\";vo[8]=\"\\\\b\";vo[9]=\"\\\\t\";vo[10]=\"\\\\n\";vo[11]=\"\\\\v\";vo[12]=\"\\\\f\";vo[13]=\"\\\\r\";vo[27]=\"\\\\e\";vo[34]='\\\\\"';vo[92]=\"\\\\\\\\\";vo[133]=\"\\\\N\";vo[160]=\"\\\\_\";vo[8232]=\"\\\\L\";vo[8233]=\"\\\\P\";var x6e=[\"y\",\"Y\",\"yes\",\"Yes\",\"YES\",\"on\",\"On\",\"ON\",\"n\",\"N\",\"no\",\"No\",\"NO\",\"off\",\"Off\",\"OFF\"];function k6e(t,e){var r,o,a,n,u,A,p;if(e===null)return{};for(r={},o=Object.keys(e),a=0,n=o.length;a<n;a+=1)u=o[a],A=String(e[u]),u.slice(0,2)===\"!!\"&&(u=\"tag:yaml.org,2002:\"+u.slice(2)),p=t.compiledTypeMap.fallback[u],p&&FK.call(p.styleAliases,A)&&(A=p.styleAliases[A]),r[u]=A;return r}function vK(t){var e,r,o;if(e=t.toString(16).toUpperCase(),t<=255)r=\"x\",o=2;else if(t<=65535)r=\"u\",o=4;else if(t<=4294967295)r=\"U\",o=8;else throw new tI(\"code point within a string may not be greater than 0xFFFFFFFF\");return\"\\\\\"+r+eI.repeat(\"0\",o-e.length)+e}function Q6e(t){this.schema=t.schema||A6e,this.indent=Math.max(1,t.indent||2),this.noArrayIndent=t.noArrayIndent||!1,this.skipInvalid=t.skipInvalid||!1,this.flowLevel=eI.isNothing(t.flowLevel)?-1:t.flowLevel,this.styleMap=k6e(this.schema,t.styles||null),this.sortKeys=t.sortKeys||!1,this.lineWidth=t.lineWidth||80,this.noRefs=t.noRefs||!1,this.noCompatMode=t.noCompatMode||!1,this.condenseFlow=t.condenseFlow||!1,this.implicitTypes=this.schema.compiledImplicit,this.explicitTypes=this.schema.compiledExplicit,this.tag=null,this.result=\"\",this.duplicates=[],this.usedDuplicates=null}function DK(t,e){for(var r=eI.repeat(\" \",e),o=0,a=-1,n=\"\",u,A=t.length;o<A;)a=t.indexOf(`\n`,o),a===-1?(u=t.slice(o),o=A):(u=t.slice(o,a+1),o=a+1),u.length&&u!==`\n`&&(n+=r),n+=u;return n}function ET(t,e){return`\n`+eI.repeat(\" \",t.indent*e)}function F6e(t,e){var r,o,a;for(r=0,o=t.implicitTypes.length;r<o;r+=1)if(a=t.implicitTypes[r],a.resolve(e))return!0;return!1}function wT(t){return t===g6e||t===p6e}function my(t){return 32<=t&&t<=126||161<=t&&t<=55295&&t!==8232&&t!==8233||57344<=t&&t<=65533&&t!==65279||65536<=t&&t<=1114111}function R6e(t){return my(t)&&!wT(t)&&t!==65279&&t!==h6e&&t!==$w}function PK(t,e){return my(t)&&t!==65279&&t!==TK&&t!==NK&&t!==OK&&t!==MK&&t!==UK&&t!==LK&&(t!==RK||e&&R6e(e))}function T6e(t){return my(t)&&t!==65279&&!wT(t)&&t!==I6e&&t!==D6e&&t!==LK&&t!==TK&&t!==NK&&t!==OK&&t!==MK&&t!==UK&&t!==RK&&t!==E6e&&t!==w6e&&t!==d6e&&t!==b6e&&t!==B6e&&t!==v6e&&t!==C6e&&t!==m6e&&t!==y6e&&t!==P6e&&t!==S6e}function _K(t){var e=/^\\n* /;return e.test(t)}var HK=1,qK=2,GK=3,jK=4,KD=5;function L6e(t,e,r,o,a){var n,u,A,p=!1,h=!1,E=o!==-1,I=-1,v=T6e(t.charCodeAt(0))&&!wT(t.charCodeAt(t.length-1));if(e)for(n=0;n<t.length;n++){if(u=t.charCodeAt(n),!my(u))return KD;A=n>0?t.charCodeAt(n-1):null,v=v&&PK(u,A)}else{for(n=0;n<t.length;n++){if(u=t.charCodeAt(n),u===$w)p=!0,E&&(h=h||n-I-1>o&&t[I+1]!==\" \",I=n);else if(!my(u))return KD;A=n>0?t.charCodeAt(n-1):null,v=v&&PK(u,A)}h=h||E&&n-I-1>o&&t[I+1]!==\" \"}return!p&&!h?v&&!a(t)?HK:qK:r>9&&_K(t)?KD:h?jK:GK}function N6e(t,e,r,o){t.dump=function(){if(e.length===0)return\"''\";if(!t.noCompatMode&&x6e.indexOf(e)!==-1)return\"'\"+e+\"'\";var a=t.indent*Math.max(1,r),n=t.lineWidth===-1?-1:Math.max(Math.min(t.lineWidth,40),t.lineWidth-a),u=o||t.flowLevel>-1&&r>=t.flowLevel;function A(p){return F6e(t,p)}switch(L6e(e,u,t.indent,n,A)){case HK:return e;case qK:return\"'\"+e.replace(/'/g,\"''\")+\"'\";case GK:return\"|\"+SK(e,t.indent)+bK(DK(e,a));case jK:return\">\"+SK(e,t.indent)+bK(DK(O6e(e,n),a));case KD:return'\"'+M6e(e,n)+'\"';default:throw new tI(\"impossible error: invalid scalar style\")}}()}function SK(t,e){var r=_K(t)?String(e):\"\",o=t[t.length-1]===`\n`,a=o&&(t[t.length-2]===`\n`||t===`\n`),n=a?\"+\":o?\"\":\"-\";return r+n+`\n`}function bK(t){return t[t.length-1]===`\n`?t.slice(0,-1):t}function O6e(t,e){for(var r=/(\\n+)([^\\n]*)/g,o=function(){var h=t.indexOf(`\n`);return h=h!==-1?h:t.length,r.lastIndex=h,xK(t.slice(0,h),e)}(),a=t[0]===`\n`||t[0]===\" \",n,u;u=r.exec(t);){var A=u[1],p=u[2];n=p[0]===\" \",o+=A+(!a&&!n&&p!==\"\"?`\n`:\"\")+xK(p,e),a=n}return o}function xK(t,e){if(t===\"\"||t[0]===\" \")return t;for(var r=/ [^ ]/g,o,a=0,n,u=0,A=0,p=\"\";o=r.exec(t);)A=o.index,A-a>e&&(n=u>a?u:A,p+=`\n`+t.slice(a,n),a=n+1),u=A;return p+=`\n`,t.length-a>e&&u>a?p+=t.slice(a,u)+`\n`+t.slice(u+1):p+=t.slice(a),p.slice(1)}function M6e(t){for(var e=\"\",r,o,a,n=0;n<t.length;n++){if(r=t.charCodeAt(n),r>=55296&&r<=56319&&(o=t.charCodeAt(n+1),o>=56320&&o<=57343)){e+=vK((r-55296)*1024+o-56320+65536),n++;continue}a=vo[r],e+=!a&&my(r)?t[n]:a||vK(r)}return e}function U6e(t,e,r){var o=\"\",a=t.tag,n,u;for(n=0,u=r.length;n<u;n+=1)ed(t,e,r[n],!1,!1)&&(n!==0&&(o+=\",\"+(t.condenseFlow?\"\":\" \")),o+=t.dump);t.tag=a,t.dump=\"[\"+o+\"]\"}function _6e(t,e,r,o){var a=\"\",n=t.tag,u,A;for(u=0,A=r.length;u<A;u+=1)ed(t,e+1,r[u],!0,!0)&&((!o||u!==0)&&(a+=ET(t,e)),t.dump&&$w===t.dump.charCodeAt(0)?a+=\"-\":a+=\"- \",a+=t.dump);t.tag=n,t.dump=a||\"[]\"}function H6e(t,e,r){var o=\"\",a=t.tag,n=Object.keys(r),u,A,p,h,E;for(u=0,A=n.length;u<A;u+=1)E=\"\",u!==0&&(E+=\", \"),t.condenseFlow&&(E+='\"'),p=n[u],h=r[p],ed(t,e,p,!1,!1)&&(t.dump.length>1024&&(E+=\"? \"),E+=t.dump+(t.condenseFlow?'\"':\"\")+\":\"+(t.condenseFlow?\"\":\" \"),ed(t,e,h,!1,!1)&&(E+=t.dump,o+=E));t.tag=a,t.dump=\"{\"+o+\"}\"}function q6e(t,e,r,o){var a=\"\",n=t.tag,u=Object.keys(r),A,p,h,E,I,v;if(t.sortKeys===!0)u.sort();else if(typeof t.sortKeys==\"function\")u.sort(t.sortKeys);else if(t.sortKeys)throw new tI(\"sortKeys must be a boolean or a function\");for(A=0,p=u.length;A<p;A+=1)v=\"\",(!o||A!==0)&&(v+=ET(t,e)),h=u[A],E=r[h],ed(t,e+1,h,!0,!0,!0)&&(I=t.tag!==null&&t.tag!==\"?\"||t.dump&&t.dump.length>1024,I&&(t.dump&&$w===t.dump.charCodeAt(0)?v+=\"?\":v+=\"? \"),v+=t.dump,I&&(v+=ET(t,e)),ed(t,e+1,E,!0,I)&&(t.dump&&$w===t.dump.charCodeAt(0)?v+=\":\":v+=\": \",v+=t.dump,a+=v));t.tag=n,t.dump=a||\"{}\"}function kK(t,e,r){var o,a,n,u,A,p;for(a=r?t.explicitTypes:t.implicitTypes,n=0,u=a.length;n<u;n+=1)if(A=a[n],(A.instanceOf||A.predicate)&&(!A.instanceOf||typeof e==\"object\"&&e instanceof A.instanceOf)&&(!A.predicate||A.predicate(e))){if(t.tag=r?A.tag:\"?\",A.represent){if(p=t.styleMap[A.tag]||A.defaultStyle,QK.call(A.represent)===\"[object Function]\")o=A.represent(e,p);else if(FK.call(A.represent,p))o=A.represent[p](e,p);else throw new tI(\"!<\"+A.tag+'> tag resolver accepts not \"'+p+'\" style');t.dump=o}return!0}return!1}function ed(t,e,r,o,a,n){t.tag=null,t.dump=r,kK(t,r,!1)||kK(t,r,!0);var u=QK.call(t.dump);o&&(o=t.flowLevel<0||t.flowLevel>e);var A=u===\"[object Object]\"||u===\"[object Array]\",p,h;if(A&&(p=t.duplicates.indexOf(r),h=p!==-1),(t.tag!==null&&t.tag!==\"?\"||h||t.indent!==2&&e>0)&&(a=!1),h&&t.usedDuplicates[p])t.dump=\"*ref_\"+p;else{if(A&&h&&!t.usedDuplicates[p]&&(t.usedDuplicates[p]=!0),u===\"[object Object]\")o&&Object.keys(t.dump).length!==0?(q6e(t,e,t.dump,a),h&&(t.dump=\"&ref_\"+p+t.dump)):(H6e(t,e,t.dump),h&&(t.dump=\"&ref_\"+p+\" \"+t.dump));else if(u===\"[object Array]\"){var E=t.noArrayIndent&&e>0?e-1:e;o&&t.dump.length!==0?(_6e(t,E,t.dump,a),h&&(t.dump=\"&ref_\"+p+t.dump)):(U6e(t,E,t.dump),h&&(t.dump=\"&ref_\"+p+\" \"+t.dump))}else if(u===\"[object String]\")t.tag!==\"?\"&&N6e(t,t.dump,e,n);else{if(t.skipInvalid)return!1;throw new tI(\"unacceptable kind of an object to dump \"+u)}t.tag!==null&&t.tag!==\"?\"&&(t.dump=\"!<\"+t.tag+\"> \"+t.dump)}return!0}function G6e(t,e){var r=[],o=[],a,n;for(CT(t,r,o),a=0,n=o.length;a<n;a+=1)e.duplicates.push(r[o[a]]);e.usedDuplicates=new Array(n)}function CT(t,e,r){var o,a,n;if(t!==null&&typeof t==\"object\")if(a=e.indexOf(t),a!==-1)r.indexOf(a)===-1&&r.push(a);else if(e.push(t),Array.isArray(t))for(a=0,n=t.length;a<n;a+=1)CT(t[a],e,r);else for(o=Object.keys(t),a=0,n=o.length;a<n;a+=1)CT(t[o[a]],e,r)}function YK(t,e){e=e||{};var r=new Q6e(e);return r.noRefs||G6e(t,r),ed(r,0,t,!0,!0)?r.dump+`\n`:\"\"}function j6e(t,e){return YK(t,eI.extend({schema:f6e},e))}IT.exports.dump=YK;IT.exports.safeDump=j6e});var zK=_((pxt,ki)=>{\"use strict\";var zD=BK(),KK=WK();function VD(t){return function(){throw new Error(\"Function \"+t+\" is deprecated and cannot be used.\")}}ki.exports.Type=os();ki.exports.Schema=Jg();ki.exports.FAILSAFE_SCHEMA=HD();ki.exports.JSON_SCHEMA=pT();ki.exports.CORE_SCHEMA=hT();ki.exports.DEFAULT_SAFE_SCHEMA=py();ki.exports.DEFAULT_FULL_SCHEMA=Xw();ki.exports.load=zD.load;ki.exports.loadAll=zD.loadAll;ki.exports.safeLoad=zD.safeLoad;ki.exports.safeLoadAll=zD.safeLoadAll;ki.exports.dump=KK.dump;ki.exports.safeDump=KK.safeDump;ki.exports.YAMLException=Ay();ki.exports.MINIMAL_SCHEMA=HD();ki.exports.SAFE_SCHEMA=py();ki.exports.DEFAULT_SCHEMA=Xw();ki.exports.scan=VD(\"scan\");ki.exports.parse=VD(\"parse\");ki.exports.compose=VD(\"compose\");ki.exports.addConstructor=VD(\"addConstructor\")});var JK=_((hxt,VK)=>{\"use strict\";var Y6e=zK();VK.exports=Y6e});var ZK=_((gxt,XK)=>{\"use strict\";function W6e(t,e){function r(){this.constructor=t}r.prototype=e.prototype,t.prototype=new r}function td(t,e,r,o){this.message=t,this.expected=e,this.found=r,this.location=o,this.name=\"SyntaxError\",typeof Error.captureStackTrace==\"function\"&&Error.captureStackTrace(this,td)}W6e(td,Error);td.buildMessage=function(t,e){var r={literal:function(h){return'\"'+a(h.text)+'\"'},class:function(h){var E=\"\",I;for(I=0;I<h.parts.length;I++)E+=h.parts[I]instanceof Array?n(h.parts[I][0])+\"-\"+n(h.parts[I][1]):n(h.parts[I]);return\"[\"+(h.inverted?\"^\":\"\")+E+\"]\"},any:function(h){return\"any character\"},end:function(h){return\"end of input\"},other:function(h){return h.description}};function o(h){return h.charCodeAt(0).toString(16).toUpperCase()}function a(h){return h.replace(/\\\\/g,\"\\\\\\\\\").replace(/\"/g,'\\\\\"').replace(/\\0/g,\"\\\\0\").replace(/\\t/g,\"\\\\t\").replace(/\\n/g,\"\\\\n\").replace(/\\r/g,\"\\\\r\").replace(/[\\x00-\\x0F]/g,function(E){return\"\\\\x0\"+o(E)}).replace(/[\\x10-\\x1F\\x7F-\\x9F]/g,function(E){return\"\\\\x\"+o(E)})}function n(h){return h.replace(/\\\\/g,\"\\\\\\\\\").replace(/\\]/g,\"\\\\]\").replace(/\\^/g,\"\\\\^\").replace(/-/g,\"\\\\-\").replace(/\\0/g,\"\\\\0\").replace(/\\t/g,\"\\\\t\").replace(/\\n/g,\"\\\\n\").replace(/\\r/g,\"\\\\r\").replace(/[\\x00-\\x0F]/g,function(E){return\"\\\\x0\"+o(E)}).replace(/[\\x10-\\x1F\\x7F-\\x9F]/g,function(E){return\"\\\\x\"+o(E)})}function u(h){return r[h.type](h)}function A(h){var E=new Array(h.length),I,v;for(I=0;I<h.length;I++)E[I]=u(h[I]);if(E.sort(),E.length>0){for(I=1,v=1;I<E.length;I++)E[I-1]!==E[I]&&(E[v]=E[I],v++);E.length=v}switch(E.length){case 1:return E[0];case 2:return E[0]+\" or \"+E[1];default:return E.slice(0,-1).join(\", \")+\", or \"+E[E.length-1]}}function p(h){return h?'\"'+a(h)+'\"':\"end of input\"}return\"Expected \"+A(t)+\" but \"+p(e)+\" found.\"};function K6e(t,e){e=e!==void 0?e:{};var r={},o={Start:hu},a=hu,n=function($){return[].concat(...$)},u=\"-\",A=Qn(\"-\",!1),p=function($){return $},h=function($){return Object.assign({},...$)},E=\"#\",I=Qn(\"#\",!1),v=gc(),x=function(){return{}},C=\":\",R=Qn(\":\",!1),N=function($,ye){return{[$]:ye}},U=\",\",V=Qn(\",\",!1),te=function($,ye){return ye},ae=function($,ye,Ne){return Object.assign({},...[$].concat(ye).map(pt=>({[pt]:Ne})))},fe=function($){return $},ue=function($){return $},me=sa(\"correct indentation\"),he=\" \",Be=Qn(\" \",!1),we=function($){return $.length===ir*It},g=function($){return $.length===(ir+1)*It},Ee=function(){return ir++,!0},Pe=function(){return ir--,!0},ce=function(){return PA()},ne=sa(\"pseudostring\"),ee=/^[^\\r\\n\\t ?:,\\][{}#&*!|>'\"%@`\\-]/,Ie=hi([\"\\r\",`\n`,\"\t\",\" \",\"?\",\":\",\",\",\"]\",\"[\",\"{\",\"}\",\"#\",\"&\",\"*\",\"!\",\"|\",\">\",\"'\",'\"',\"%\",\"@\",\"`\",\"-\"],!0,!1),Fe=/^[^\\r\\n\\t ,\\][{}:#\"']/,At=hi([\"\\r\",`\n`,\"\t\",\" \",\",\",\"]\",\"[\",\"{\",\"}\",\":\",\"#\",'\"',\"'\"],!0,!1),H=function(){return PA().replace(/^ *| *$/g,\"\")},at=\"--\",Re=Qn(\"--\",!1),ke=/^[a-zA-Z\\/0-9]/,xe=hi([[\"a\",\"z\"],[\"A\",\"Z\"],\"/\",[\"0\",\"9\"]],!1,!1),He=/^[^\\r\\n\\t :,]/,Te=hi([\"\\r\",`\n`,\"\t\",\" \",\":\",\",\"],!0,!1),Ve=\"null\",qe=Qn(\"null\",!1),b=function(){return null},w=\"true\",S=Qn(\"true\",!1),y=function(){return!0},F=\"false\",J=Qn(\"false\",!1),X=function(){return!1},Z=sa(\"string\"),ie='\"',be=Qn('\"',!1),Le=function(){return\"\"},ot=function($){return $},dt=function($){return $.join(\"\")},Gt=/^[^\"\\\\\\0-\\x1F\\x7F]/,$t=hi(['\"',\"\\\\\",[\"\\0\",\"\u001f\"],\"\\x7F\"],!0,!1),bt='\\\\\"',an=Qn('\\\\\"',!1),Qr=function(){return'\"'},mr=\"\\\\\\\\\",br=Qn(\"\\\\\\\\\",!1),Wr=function(){return\"\\\\\"},Kn=\"\\\\/\",Ls=Qn(\"\\\\/\",!1),Ti=function(){return\"/\"},ps=\"\\\\b\",io=Qn(\"\\\\b\",!1),Si=function(){return\"\\b\"},Ns=\"\\\\f\",so=Qn(\"\\\\f\",!1),uc=function(){return\"\\f\"},uu=\"\\\\n\",cp=Qn(\"\\\\n\",!1),up=function(){return`\n`},Os=\"\\\\r\",Dn=Qn(\"\\\\r\",!1),oo=function(){return\"\\r\"},Ms=\"\\\\t\",yl=Qn(\"\\\\t\",!1),El=function(){return\"\t\"},ao=\"\\\\u\",zn=Qn(\"\\\\u\",!1),On=function($,ye,Ne,pt){return String.fromCharCode(parseInt(`0x${$}${ye}${Ne}${pt}`))},Li=/^[0-9a-fA-F]/,Mn=hi([[\"0\",\"9\"],[\"a\",\"f\"],[\"A\",\"F\"]],!1,!1),_i=sa(\"blank space\"),rr=/^[ \\t]/,Oe=hi([\" \",\"\t\"],!1,!1),ii=sa(\"white space\"),Ua=/^[ \\t\\n\\r]/,hr=hi([\" \",\"\t\",`\n`,\"\\r\"],!1,!1),Ac=`\\r\n`,Au=Qn(`\\r\n`,!1),fc=`\n`,Cl=Qn(`\n`,!1),DA=\"\\r\",fu=Qn(\"\\r\",!1),Ce=0,Rt=0,pc=[{line:1,column:1}],Hi=0,pu=[],Yt=0,wl;if(\"startRule\"in e){if(!(e.startRule in o))throw new Error(`Can't start parsing from rule \"`+e.startRule+'\".');a=o[e.startRule]}function PA(){return t.substring(Rt,Ce)}function Ap(){return _o(Rt,Ce)}function hc($,ye){throw ye=ye!==void 0?ye:_o(Rt,Ce),dc([sa($)],t.substring(Rt,Ce),ye)}function SA($,ye){throw ye=ye!==void 0?ye:_o(Rt,Ce),lo($,ye)}function Qn($,ye){return{type:\"literal\",text:$,ignoreCase:ye}}function hi($,ye,Ne){return{type:\"class\",parts:$,inverted:ye,ignoreCase:Ne}}function gc(){return{type:\"any\"}}function bA(){return{type:\"end\"}}function sa($){return{type:\"other\",description:$}}function Ni($){var ye=pc[$],Ne;if(ye)return ye;for(Ne=$-1;!pc[Ne];)Ne--;for(ye=pc[Ne],ye={line:ye.line,column:ye.column};Ne<$;)t.charCodeAt(Ne)===10?(ye.line++,ye.column=1):ye.column++,Ne++;return pc[$]=ye,ye}function _o($,ye){var Ne=Ni($),pt=Ni(ye);return{start:{offset:$,line:Ne.line,column:Ne.column},end:{offset:ye,line:pt.line,column:pt.column}}}function Ze($){Ce<Hi||(Ce>Hi&&(Hi=Ce,pu=[]),pu.push($))}function lo($,ye){return new td($,null,null,ye)}function dc($,ye,Ne){return new td(td.buildMessage($,ye),$,ye,Ne)}function hu(){var $;return $=xA(),$}function qi(){var $,ye,Ne;for($=Ce,ye=[],Ne=gu();Ne!==r;)ye.push(Ne),Ne=gu();return ye!==r&&(Rt=$,ye=n(ye)),$=ye,$}function gu(){var $,ye,Ne,pt,ht;return $=Ce,ye=hs(),ye!==r?(t.charCodeAt(Ce)===45?(Ne=u,Ce++):(Ne=r,Yt===0&&Ze(A)),Ne!==r?(pt=Pn(),pt!==r?(ht=mc(),ht!==r?(Rt=$,ye=p(ht),$=ye):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r),$}function xA(){var $,ye,Ne;for($=Ce,ye=[],Ne=Ha();Ne!==r;)ye.push(Ne),Ne=Ha();return ye!==r&&(Rt=$,ye=h(ye)),$=ye,$}function Ha(){var $,ye,Ne,pt,ht,Tt,er,$r,Gi;if($=Ce,ye=Pn(),ye===r&&(ye=null),ye!==r){if(Ne=Ce,t.charCodeAt(Ce)===35?(pt=E,Ce++):(pt=r,Yt===0&&Ze(I)),pt!==r){if(ht=[],Tt=Ce,er=Ce,Yt++,$r=tt(),Yt--,$r===r?er=void 0:(Ce=er,er=r),er!==r?(t.length>Ce?($r=t.charAt(Ce),Ce++):($r=r,Yt===0&&Ze(v)),$r!==r?(er=[er,$r],Tt=er):(Ce=Tt,Tt=r)):(Ce=Tt,Tt=r),Tt!==r)for(;Tt!==r;)ht.push(Tt),Tt=Ce,er=Ce,Yt++,$r=tt(),Yt--,$r===r?er=void 0:(Ce=er,er=r),er!==r?(t.length>Ce?($r=t.charAt(Ce),Ce++):($r=r,Yt===0&&Ze(v)),$r!==r?(er=[er,$r],Tt=er):(Ce=Tt,Tt=r)):(Ce=Tt,Tt=r);else ht=r;ht!==r?(pt=[pt,ht],Ne=pt):(Ce=Ne,Ne=r)}else Ce=Ne,Ne=r;if(Ne===r&&(Ne=null),Ne!==r){if(pt=[],ht=We(),ht!==r)for(;ht!==r;)pt.push(ht),ht=We();else pt=r;pt!==r?(Rt=$,ye=x(),$=ye):(Ce=$,$=r)}else Ce=$,$=r}else Ce=$,$=r;if($===r&&($=Ce,ye=hs(),ye!==r?(Ne=oa(),Ne!==r?(pt=Pn(),pt===r&&(pt=null),pt!==r?(t.charCodeAt(Ce)===58?(ht=C,Ce++):(ht=r,Yt===0&&Ze(R)),ht!==r?(Tt=Pn(),Tt===r&&(Tt=null),Tt!==r?(er=mc(),er!==r?(Rt=$,ye=N(Ne,er),$=ye):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r),$===r&&($=Ce,ye=hs(),ye!==r?(Ne=co(),Ne!==r?(pt=Pn(),pt===r&&(pt=null),pt!==r?(t.charCodeAt(Ce)===58?(ht=C,Ce++):(ht=r,Yt===0&&Ze(R)),ht!==r?(Tt=Pn(),Tt===r&&(Tt=null),Tt!==r?(er=mc(),er!==r?(Rt=$,ye=N(Ne,er),$=ye):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r),$===r))){if($=Ce,ye=hs(),ye!==r)if(Ne=co(),Ne!==r)if(pt=Pn(),pt!==r)if(ht=aa(),ht!==r){if(Tt=[],er=We(),er!==r)for(;er!==r;)Tt.push(er),er=We();else Tt=r;Tt!==r?(Rt=$,ye=N(Ne,ht),$=ye):(Ce=$,$=r)}else Ce=$,$=r;else Ce=$,$=r;else Ce=$,$=r;else Ce=$,$=r;if($===r)if($=Ce,ye=hs(),ye!==r)if(Ne=co(),Ne!==r){if(pt=[],ht=Ce,Tt=Pn(),Tt===r&&(Tt=null),Tt!==r?(t.charCodeAt(Ce)===44?(er=U,Ce++):(er=r,Yt===0&&Ze(V)),er!==r?($r=Pn(),$r===r&&($r=null),$r!==r?(Gi=co(),Gi!==r?(Rt=ht,Tt=te(Ne,Gi),ht=Tt):(Ce=ht,ht=r)):(Ce=ht,ht=r)):(Ce=ht,ht=r)):(Ce=ht,ht=r),ht!==r)for(;ht!==r;)pt.push(ht),ht=Ce,Tt=Pn(),Tt===r&&(Tt=null),Tt!==r?(t.charCodeAt(Ce)===44?(er=U,Ce++):(er=r,Yt===0&&Ze(V)),er!==r?($r=Pn(),$r===r&&($r=null),$r!==r?(Gi=co(),Gi!==r?(Rt=ht,Tt=te(Ne,Gi),ht=Tt):(Ce=ht,ht=r)):(Ce=ht,ht=r)):(Ce=ht,ht=r)):(Ce=ht,ht=r);else pt=r;pt!==r?(ht=Pn(),ht===r&&(ht=null),ht!==r?(t.charCodeAt(Ce)===58?(Tt=C,Ce++):(Tt=r,Yt===0&&Ze(R)),Tt!==r?(er=Pn(),er===r&&(er=null),er!==r?($r=mc(),$r!==r?(Rt=$,ye=ae(Ne,pt,$r),$=ye):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)}else Ce=$,$=r;else Ce=$,$=r}return $}function mc(){var $,ye,Ne,pt,ht,Tt,er;if($=Ce,ye=Ce,Yt++,Ne=Ce,pt=tt(),pt!==r?(ht=Ht(),ht!==r?(t.charCodeAt(Ce)===45?(Tt=u,Ce++):(Tt=r,Yt===0&&Ze(A)),Tt!==r?(er=Pn(),er!==r?(pt=[pt,ht,Tt,er],Ne=pt):(Ce=Ne,Ne=r)):(Ce=Ne,Ne=r)):(Ce=Ne,Ne=r)):(Ce=Ne,Ne=r),Yt--,Ne!==r?(Ce=ye,ye=void 0):ye=r,ye!==r?(Ne=We(),Ne!==r?(pt=Fn(),pt!==r?(ht=qi(),ht!==r?(Tt=Ci(),Tt!==r?(Rt=$,ye=fe(ht),$=ye):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r),$===r&&($=Ce,ye=tt(),ye!==r?(Ne=Fn(),Ne!==r?(pt=xA(),pt!==r?(ht=Ci(),ht!==r?(Rt=$,ye=fe(pt),$=ye):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r),$===r))if($=Ce,ye=Us(),ye!==r){if(Ne=[],pt=We(),pt!==r)for(;pt!==r;)Ne.push(pt),pt=We();else Ne=r;Ne!==r?(Rt=$,ye=ue(ye),$=ye):(Ce=$,$=r)}else Ce=$,$=r;return $}function hs(){var $,ye,Ne;for(Yt++,$=Ce,ye=[],t.charCodeAt(Ce)===32?(Ne=he,Ce++):(Ne=r,Yt===0&&Ze(Be));Ne!==r;)ye.push(Ne),t.charCodeAt(Ce)===32?(Ne=he,Ce++):(Ne=r,Yt===0&&Ze(Be));return ye!==r?(Rt=Ce,Ne=we(ye),Ne?Ne=void 0:Ne=r,Ne!==r?(ye=[ye,Ne],$=ye):(Ce=$,$=r)):(Ce=$,$=r),Yt--,$===r&&(ye=r,Yt===0&&Ze(me)),$}function Ht(){var $,ye,Ne;for($=Ce,ye=[],t.charCodeAt(Ce)===32?(Ne=he,Ce++):(Ne=r,Yt===0&&Ze(Be));Ne!==r;)ye.push(Ne),t.charCodeAt(Ce)===32?(Ne=he,Ce++):(Ne=r,Yt===0&&Ze(Be));return ye!==r?(Rt=Ce,Ne=g(ye),Ne?Ne=void 0:Ne=r,Ne!==r?(ye=[ye,Ne],$=ye):(Ce=$,$=r)):(Ce=$,$=r),$}function Fn(){var $;return Rt=Ce,$=Ee(),$?$=void 0:$=r,$}function Ci(){var $;return Rt=Ce,$=Pe(),$?$=void 0:$=r,$}function oa(){var $;return $=ds(),$===r&&($=la()),$}function co(){var $,ye,Ne;if($=ds(),$===r){if($=Ce,ye=[],Ne=Ho(),Ne!==r)for(;Ne!==r;)ye.push(Ne),Ne=Ho();else ye=r;ye!==r&&(Rt=$,ye=ce()),$=ye}return $}function Us(){var $;return $=wi(),$===r&&($=gs(),$===r&&($=ds(),$===r&&($=la()))),$}function aa(){var $;return $=wi(),$===r&&($=ds(),$===r&&($=Ho())),$}function la(){var $,ye,Ne,pt,ht,Tt;if(Yt++,$=Ce,ee.test(t.charAt(Ce))?(ye=t.charAt(Ce),Ce++):(ye=r,Yt===0&&Ze(Ie)),ye!==r){for(Ne=[],pt=Ce,ht=Pn(),ht===r&&(ht=null),ht!==r?(Fe.test(t.charAt(Ce))?(Tt=t.charAt(Ce),Ce++):(Tt=r,Yt===0&&Ze(At)),Tt!==r?(ht=[ht,Tt],pt=ht):(Ce=pt,pt=r)):(Ce=pt,pt=r);pt!==r;)Ne.push(pt),pt=Ce,ht=Pn(),ht===r&&(ht=null),ht!==r?(Fe.test(t.charAt(Ce))?(Tt=t.charAt(Ce),Ce++):(Tt=r,Yt===0&&Ze(At)),Tt!==r?(ht=[ht,Tt],pt=ht):(Ce=pt,pt=r)):(Ce=pt,pt=r);Ne!==r?(Rt=$,ye=H(),$=ye):(Ce=$,$=r)}else Ce=$,$=r;return Yt--,$===r&&(ye=r,Yt===0&&Ze(ne)),$}function Ho(){var $,ye,Ne,pt,ht;if($=Ce,t.substr(Ce,2)===at?(ye=at,Ce+=2):(ye=r,Yt===0&&Ze(Re)),ye===r&&(ye=null),ye!==r)if(ke.test(t.charAt(Ce))?(Ne=t.charAt(Ce),Ce++):(Ne=r,Yt===0&&Ze(xe)),Ne!==r){for(pt=[],He.test(t.charAt(Ce))?(ht=t.charAt(Ce),Ce++):(ht=r,Yt===0&&Ze(Te));ht!==r;)pt.push(ht),He.test(t.charAt(Ce))?(ht=t.charAt(Ce),Ce++):(ht=r,Yt===0&&Ze(Te));pt!==r?(Rt=$,ye=H(),$=ye):(Ce=$,$=r)}else Ce=$,$=r;else Ce=$,$=r;return $}function wi(){var $,ye;return $=Ce,t.substr(Ce,4)===Ve?(ye=Ve,Ce+=4):(ye=r,Yt===0&&Ze(qe)),ye!==r&&(Rt=$,ye=b()),$=ye,$}function gs(){var $,ye;return $=Ce,t.substr(Ce,4)===w?(ye=w,Ce+=4):(ye=r,Yt===0&&Ze(S)),ye!==r&&(Rt=$,ye=y()),$=ye,$===r&&($=Ce,t.substr(Ce,5)===F?(ye=F,Ce+=5):(ye=r,Yt===0&&Ze(J)),ye!==r&&(Rt=$,ye=X()),$=ye),$}function ds(){var $,ye,Ne,pt;return Yt++,$=Ce,t.charCodeAt(Ce)===34?(ye=ie,Ce++):(ye=r,Yt===0&&Ze(be)),ye!==r?(t.charCodeAt(Ce)===34?(Ne=ie,Ce++):(Ne=r,Yt===0&&Ze(be)),Ne!==r?(Rt=$,ye=Le(),$=ye):(Ce=$,$=r)):(Ce=$,$=r),$===r&&($=Ce,t.charCodeAt(Ce)===34?(ye=ie,Ce++):(ye=r,Yt===0&&Ze(be)),ye!==r?(Ne=ms(),Ne!==r?(t.charCodeAt(Ce)===34?(pt=ie,Ce++):(pt=r,Yt===0&&Ze(be)),pt!==r?(Rt=$,ye=ot(Ne),$=ye):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)),Yt--,$===r&&(ye=r,Yt===0&&Ze(Z)),$}function ms(){var $,ye,Ne;if($=Ce,ye=[],Ne=_s(),Ne!==r)for(;Ne!==r;)ye.push(Ne),Ne=_s();else ye=r;return ye!==r&&(Rt=$,ye=dt(ye)),$=ye,$}function _s(){var $,ye,Ne,pt,ht,Tt;return Gt.test(t.charAt(Ce))?($=t.charAt(Ce),Ce++):($=r,Yt===0&&Ze($t)),$===r&&($=Ce,t.substr(Ce,2)===bt?(ye=bt,Ce+=2):(ye=r,Yt===0&&Ze(an)),ye!==r&&(Rt=$,ye=Qr()),$=ye,$===r&&($=Ce,t.substr(Ce,2)===mr?(ye=mr,Ce+=2):(ye=r,Yt===0&&Ze(br)),ye!==r&&(Rt=$,ye=Wr()),$=ye,$===r&&($=Ce,t.substr(Ce,2)===Kn?(ye=Kn,Ce+=2):(ye=r,Yt===0&&Ze(Ls)),ye!==r&&(Rt=$,ye=Ti()),$=ye,$===r&&($=Ce,t.substr(Ce,2)===ps?(ye=ps,Ce+=2):(ye=r,Yt===0&&Ze(io)),ye!==r&&(Rt=$,ye=Si()),$=ye,$===r&&($=Ce,t.substr(Ce,2)===Ns?(ye=Ns,Ce+=2):(ye=r,Yt===0&&Ze(so)),ye!==r&&(Rt=$,ye=uc()),$=ye,$===r&&($=Ce,t.substr(Ce,2)===uu?(ye=uu,Ce+=2):(ye=r,Yt===0&&Ze(cp)),ye!==r&&(Rt=$,ye=up()),$=ye,$===r&&($=Ce,t.substr(Ce,2)===Os?(ye=Os,Ce+=2):(ye=r,Yt===0&&Ze(Dn)),ye!==r&&(Rt=$,ye=oo()),$=ye,$===r&&($=Ce,t.substr(Ce,2)===Ms?(ye=Ms,Ce+=2):(ye=r,Yt===0&&Ze(yl)),ye!==r&&(Rt=$,ye=El()),$=ye,$===r&&($=Ce,t.substr(Ce,2)===ao?(ye=ao,Ce+=2):(ye=r,Yt===0&&Ze(zn)),ye!==r?(Ne=Un(),Ne!==r?(pt=Un(),pt!==r?(ht=Un(),ht!==r?(Tt=Un(),Tt!==r?(Rt=$,ye=On(Ne,pt,ht,Tt),$=ye):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)):(Ce=$,$=r)))))))))),$}function Un(){var $;return Li.test(t.charAt(Ce))?($=t.charAt(Ce),Ce++):($=r,Yt===0&&Ze(Mn)),$}function Pn(){var $,ye;if(Yt++,$=[],rr.test(t.charAt(Ce))?(ye=t.charAt(Ce),Ce++):(ye=r,Yt===0&&Ze(Oe)),ye!==r)for(;ye!==r;)$.push(ye),rr.test(t.charAt(Ce))?(ye=t.charAt(Ce),Ce++):(ye=r,Yt===0&&Ze(Oe));else $=r;return Yt--,$===r&&(ye=r,Yt===0&&Ze(_i)),$}function ys(){var $,ye;if(Yt++,$=[],Ua.test(t.charAt(Ce))?(ye=t.charAt(Ce),Ce++):(ye=r,Yt===0&&Ze(hr)),ye!==r)for(;ye!==r;)$.push(ye),Ua.test(t.charAt(Ce))?(ye=t.charAt(Ce),Ce++):(ye=r,Yt===0&&Ze(hr));else $=r;return Yt--,$===r&&(ye=r,Yt===0&&Ze(ii)),$}function We(){var $,ye,Ne,pt,ht,Tt;if($=Ce,ye=tt(),ye!==r){for(Ne=[],pt=Ce,ht=Pn(),ht===r&&(ht=null),ht!==r?(Tt=tt(),Tt!==r?(ht=[ht,Tt],pt=ht):(Ce=pt,pt=r)):(Ce=pt,pt=r);pt!==r;)Ne.push(pt),pt=Ce,ht=Pn(),ht===r&&(ht=null),ht!==r?(Tt=tt(),Tt!==r?(ht=[ht,Tt],pt=ht):(Ce=pt,pt=r)):(Ce=pt,pt=r);Ne!==r?(ye=[ye,Ne],$=ye):(Ce=$,$=r)}else Ce=$,$=r;return $}function tt(){var $;return t.substr(Ce,2)===Ac?($=Ac,Ce+=2):($=r,Yt===0&&Ze(Au)),$===r&&(t.charCodeAt(Ce)===10?($=fc,Ce++):($=r,Yt===0&&Ze(Cl)),$===r&&(t.charCodeAt(Ce)===13?($=DA,Ce++):($=r,Yt===0&&Ze(fu)))),$}let It=2,ir=0;if(wl=a(),wl!==r&&Ce===t.length)return wl;throw wl!==r&&Ce<t.length&&Ze(bA()),dc(pu,Hi<t.length?t.charAt(Hi):null,Hi<t.length?_o(Hi,Hi+1):_o(Hi,Hi))}XK.exports={SyntaxError:td,parse:K6e}});function ez(t){return t.match(z6e)?t:JSON.stringify(t)}function rz(t){return typeof t>\"u\"?!0:typeof t==\"object\"&&t!==null&&!Array.isArray(t)?Object.keys(t).every(e=>rz(t[e])):!1}function BT(t,e,r){if(t===null)return`null\n`;if(typeof t==\"number\"||typeof t==\"boolean\")return`${t.toString()}\n`;if(typeof t==\"string\")return`${ez(t)}\n`;if(Array.isArray(t)){if(t.length===0)return`[]\n`;let o=\"  \".repeat(e);return`\n${t.map(n=>`${o}- ${BT(n,e+1,!1)}`).join(\"\")}`}if(typeof t==\"object\"&&t){let[o,a]=t instanceof JD?[t.data,!1]:[t,!0],n=\"  \".repeat(e),u=Object.keys(o);a&&u.sort((p,h)=>{let E=$K.indexOf(p),I=$K.indexOf(h);return E===-1&&I===-1?p<h?-1:p>h?1:0:E!==-1&&I===-1?-1:E===-1&&I!==-1?1:E-I});let A=u.filter(p=>!rz(o[p])).map((p,h)=>{let E=o[p],I=ez(p),v=BT(E,e+1,!0),x=h>0||r?n:\"\",C=I.length>1024?`? ${I}\n${x}:`:`${I}:`,R=v.startsWith(`\n`)?v:` ${v}`;return`${x}${C}${R}`}).join(e===0?`\n`:\"\")||`\n`;return r?`\n${A}`:`${A}`}throw new Error(`Unsupported value type (${t})`)}function Ba(t){try{let e=BT(t,0,!1);return e!==`\n`?e:\"\"}catch(e){throw e.location&&(e.message=e.message.replace(/(\\.)?$/,` (line ${e.location.start.line}, column ${e.location.start.column})$1`)),e}}function V6e(t){return t.endsWith(`\n`)||(t+=`\n`),(0,tz.parse)(t)}function X6e(t){if(J6e.test(t))return V6e(t);let e=(0,XD.safeLoad)(t,{schema:XD.FAILSAFE_SCHEMA,json:!0});if(e==null)return{};if(typeof e!=\"object\")throw new Error(`Expected an indexed object, got a ${typeof e} instead. Does your file follow Yaml's rules?`);if(Array.isArray(e))throw new Error(\"Expected an indexed object, got an array instead. Does your file follow Yaml's rules?\");return e}function Ki(t){return X6e(t)}var XD,tz,z6e,$K,JD,J6e,nz=Et(()=>{XD=$e(JK()),tz=$e(ZK()),z6e=/^(?![-?:,\\][{}#&*!|>'\"%@` \\t\\r\\n]).([ \\t]*(?![,\\][{}:# \\t\\r\\n]).)*$/,$K=[\"__metadata\",\"version\",\"resolution\",\"dependencies\",\"peerDependencies\",\"dependenciesMeta\",\"peerDependenciesMeta\",\"binaries\"],JD=class{constructor(e){this.data=e}};Ba.PreserveOrdering=JD;J6e=/^(#.*(\\r?\\n))*?#\\s+yarn\\s+lockfile\\s+v1\\r?\\n/i});var rI={};zt(rI,{parseResolution:()=>MD,parseShell:()=>LD,parseSyml:()=>Ki,stringifyArgument:()=>cT,stringifyArgumentSegment:()=>uT,stringifyArithmeticExpression:()=>OD,stringifyCommand:()=>lT,stringifyCommandChain:()=>uy,stringifyCommandChainThen:()=>aT,stringifyCommandLine:()=>ND,stringifyCommandLineThen:()=>oT,stringifyEnvSegment:()=>TD,stringifyRedirectArgument:()=>Vw,stringifyResolution:()=>UD,stringifyShell:()=>cy,stringifyShellLine:()=>cy,stringifySyml:()=>Ba,stringifyValueArgument:()=>Wg});var Nl=Et(()=>{rW();oW();nz()});var sz=_((Cxt,vT)=>{\"use strict\";var Z6e=t=>{let e=!1,r=!1,o=!1;for(let a=0;a<t.length;a++){let n=t[a];e&&/[a-zA-Z]/.test(n)&&n.toUpperCase()===n?(t=t.slice(0,a)+\"-\"+t.slice(a),e=!1,o=r,r=!0,a++):r&&o&&/[a-zA-Z]/.test(n)&&n.toLowerCase()===n?(t=t.slice(0,a-1)+\"-\"+t.slice(a-1),o=r,r=!1,e=!0):(e=n.toLowerCase()===n&&n.toUpperCase()!==n,o=r,r=n.toUpperCase()===n&&n.toLowerCase()!==n)}return t},iz=(t,e)=>{if(!(typeof t==\"string\"||Array.isArray(t)))throw new TypeError(\"Expected the input to be `string | string[]`\");e=Object.assign({pascalCase:!1},e);let r=a=>e.pascalCase?a.charAt(0).toUpperCase()+a.slice(1):a;return Array.isArray(t)?t=t.map(a=>a.trim()).filter(a=>a.length).join(\"-\"):t=t.trim(),t.length===0?\"\":t.length===1?e.pascalCase?t.toUpperCase():t.toLowerCase():(t!==t.toLowerCase()&&(t=Z6e(t)),t=t.replace(/^[_.\\- ]+/,\"\").toLowerCase().replace(/[_.\\- ]+(\\w|$)/g,(a,n)=>n.toUpperCase()).replace(/\\d+(\\w|$)/g,a=>a.toUpperCase()),r(t))};vT.exports=iz;vT.exports.default=iz});var oz=_((wxt,$6e)=>{$6e.exports=[{name:\"AppVeyor\",constant:\"APPVEYOR\",env:\"APPVEYOR\",pr:\"APPVEYOR_PULL_REQUEST_NUMBER\"},{name:\"Azure Pipelines\",constant:\"AZURE_PIPELINES\",env:\"SYSTEM_TEAMFOUNDATIONCOLLECTIONURI\",pr:\"SYSTEM_PULLREQUEST_PULLREQUESTID\"},{name:\"Appcircle\",constant:\"APPCIRCLE\",env:\"AC_APPCIRCLE\"},{name:\"Bamboo\",constant:\"BAMBOO\",env:\"bamboo_planKey\"},{name:\"Bitbucket Pipelines\",constant:\"BITBUCKET\",env:\"BITBUCKET_COMMIT\",pr:\"BITBUCKET_PR_ID\"},{name:\"Bitrise\",constant:\"BITRISE\",env:\"BITRISE_IO\",pr:\"BITRISE_PULL_REQUEST\"},{name:\"Buddy\",constant:\"BUDDY\",env:\"BUDDY_WORKSPACE_ID\",pr:\"BUDDY_EXECUTION_PULL_REQUEST_ID\"},{name:\"Buildkite\",constant:\"BUILDKITE\",env:\"BUILDKITE\",pr:{env:\"BUILDKITE_PULL_REQUEST\",ne:\"false\"}},{name:\"CircleCI\",constant:\"CIRCLE\",env:\"CIRCLECI\",pr:\"CIRCLE_PULL_REQUEST\"},{name:\"Cirrus CI\",constant:\"CIRRUS\",env:\"CIRRUS_CI\",pr:\"CIRRUS_PR\"},{name:\"AWS CodeBuild\",constant:\"CODEBUILD\",env:\"CODEBUILD_BUILD_ARN\"},{name:\"Codefresh\",constant:\"CODEFRESH\",env:\"CF_BUILD_ID\",pr:{any:[\"CF_PULL_REQUEST_NUMBER\",\"CF_PULL_REQUEST_ID\"]}},{name:\"Codeship\",constant:\"CODESHIP\",env:{CI_NAME:\"codeship\"}},{name:\"Drone\",constant:\"DRONE\",env:\"DRONE\",pr:{DRONE_BUILD_EVENT:\"pull_request\"}},{name:\"dsari\",constant:\"DSARI\",env:\"DSARI\"},{name:\"GitHub Actions\",constant:\"GITHUB_ACTIONS\",env:\"GITHUB_ACTIONS\",pr:{GITHUB_EVENT_NAME:\"pull_request\"}},{name:\"GitLab CI\",constant:\"GITLAB\",env:\"GITLAB_CI\",pr:\"CI_MERGE_REQUEST_ID\"},{name:\"GoCD\",constant:\"GOCD\",env:\"GO_PIPELINE_LABEL\"},{name:\"LayerCI\",constant:\"LAYERCI\",env:\"LAYERCI\",pr:\"LAYERCI_PULL_REQUEST\"},{name:\"Hudson\",constant:\"HUDSON\",env:\"HUDSON_URL\"},{name:\"Jenkins\",constant:\"JENKINS\",env:[\"JENKINS_URL\",\"BUILD_ID\"],pr:{any:[\"ghprbPullId\",\"CHANGE_ID\"]}},{name:\"Magnum CI\",constant:\"MAGNUM\",env:\"MAGNUM\"},{name:\"Netlify CI\",constant:\"NETLIFY\",env:\"NETLIFY\",pr:{env:\"PULL_REQUEST\",ne:\"false\"}},{name:\"Nevercode\",constant:\"NEVERCODE\",env:\"NEVERCODE\",pr:{env:\"NEVERCODE_PULL_REQUEST\",ne:\"false\"}},{name:\"Render\",constant:\"RENDER\",env:\"RENDER\",pr:{IS_PULL_REQUEST:\"true\"}},{name:\"Sail CI\",constant:\"SAIL\",env:\"SAILCI\",pr:\"SAIL_PULL_REQUEST_NUMBER\"},{name:\"Semaphore\",constant:\"SEMAPHORE\",env:\"SEMAPHORE\",pr:\"PULL_REQUEST_NUMBER\"},{name:\"Screwdriver\",constant:\"SCREWDRIVER\",env:\"SCREWDRIVER\",pr:{env:\"SD_PULL_REQUEST\",ne:\"false\"}},{name:\"Shippable\",constant:\"SHIPPABLE\",env:\"SHIPPABLE\",pr:{IS_PULL_REQUEST:\"true\"}},{name:\"Solano CI\",constant:\"SOLANO\",env:\"TDDIUM\",pr:\"TDDIUM_PR_ID\"},{name:\"Strider CD\",constant:\"STRIDER\",env:\"STRIDER\"},{name:\"TaskCluster\",constant:\"TASKCLUSTER\",env:[\"TASK_ID\",\"RUN_ID\"]},{name:\"TeamCity\",constant:\"TEAMCITY\",env:\"TEAMCITY_VERSION\"},{name:\"Travis CI\",constant:\"TRAVIS\",env:\"TRAVIS\",pr:{env:\"TRAVIS_PULL_REQUEST\",ne:\"false\"}},{name:\"Vercel\",constant:\"VERCEL\",env:\"NOW_BUILDER\"},{name:\"Visual Studio App Center\",constant:\"APPCENTER\",env:\"APPCENTER_BUILD_ID\"}]});var rd=_(Za=>{\"use strict\";var lz=oz(),Gu=process.env;Object.defineProperty(Za,\"_vendors\",{value:lz.map(function(t){return t.constant})});Za.name=null;Za.isPR=null;lz.forEach(function(t){let r=(Array.isArray(t.env)?t.env:[t.env]).every(function(o){return az(o)});if(Za[t.constant]=r,r)switch(Za.name=t.name,typeof t.pr){case\"string\":Za.isPR=!!Gu[t.pr];break;case\"object\":\"env\"in t.pr?Za.isPR=t.pr.env in Gu&&Gu[t.pr.env]!==t.pr.ne:\"any\"in t.pr?Za.isPR=t.pr.any.some(function(o){return!!Gu[o]}):Za.isPR=az(t.pr);break;default:Za.isPR=null}});Za.isCI=!!(Gu.CI||Gu.CONTINUOUS_INTEGRATION||Gu.BUILD_NUMBER||Gu.RUN_ID||Za.name);function az(t){return typeof t==\"string\"?!!Gu[t]:Object.keys(t).every(function(e){return Gu[e]===t[e]})}});var Hn,cn,nd,DT,ZD,cz,PT,ST,$D=Et(()=>{(function(t){t.StartOfInput=\"\\0\",t.EndOfInput=\"\u0001\",t.EndOfPartialInput=\"\u0002\"})(Hn||(Hn={}));(function(t){t[t.InitialNode=0]=\"InitialNode\",t[t.SuccessNode=1]=\"SuccessNode\",t[t.ErrorNode=2]=\"ErrorNode\",t[t.CustomNode=3]=\"CustomNode\"})(cn||(cn={}));nd=-1,DT=/^(-h|--help)(?:=([0-9]+))?$/,ZD=/^(--[a-z]+(?:-[a-z]+)*|-[a-zA-Z]+)$/,cz=/^-[a-zA-Z]{2,}$/,PT=/^([^=]+)=([\\s\\S]*)$/,ST=process.env.DEBUG_CLI===\"1\"});var it,yy,eP,bT,tP=Et(()=>{$D();it=class extends Error{constructor(e){super(e),this.clipanion={type:\"usage\"},this.name=\"UsageError\"}},yy=class extends Error{constructor(e,r){if(super(),this.input=e,this.candidates=r,this.clipanion={type:\"none\"},this.name=\"UnknownSyntaxError\",this.candidates.length===0)this.message=\"Command not found, but we're not sure what's the alternative.\";else if(this.candidates.every(o=>o.reason!==null&&o.reason===r[0].reason)){let[{reason:o}]=this.candidates;this.message=`${o}\n\n${this.candidates.map(({usage:a})=>`$ ${a}`).join(`\n`)}`}else if(this.candidates.length===1){let[{usage:o}]=this.candidates;this.message=`Command not found; did you mean:\n\n$ ${o}\n${bT(e)}`}else this.message=`Command not found; did you mean one of:\n\n${this.candidates.map(({usage:o},a)=>`${`${a}.`.padStart(4)} ${o}`).join(`\n`)}\n\n${bT(e)}`}},eP=class extends Error{constructor(e,r){super(),this.input=e,this.usages=r,this.clipanion={type:\"none\"},this.name=\"AmbiguousSyntaxError\",this.message=`Cannot find which to pick amongst the following alternatives:\n\n${this.usages.map((o,a)=>`${`${a}.`.padStart(4)} ${o}`).join(`\n`)}\n\n${bT(e)}`}},bT=t=>`While running ${t.filter(e=>e!==Hn.EndOfInput&&e!==Hn.EndOfPartialInput).map(e=>{let r=JSON.stringify(e);return e.match(/\\s/)||e.length===0||r!==`\"${e}\"`?r:e}).join(\" \")}`});function eqe(t){let e=t.split(`\n`),r=e.filter(a=>a.match(/\\S/)),o=r.length>0?r.reduce((a,n)=>Math.min(a,n.length-n.trimStart().length),Number.MAX_VALUE):0;return e.map(a=>a.slice(o).trimRight()).join(`\n`)}function Do(t,{format:e,paragraphs:r}){return t=t.replace(/\\r\\n?/g,`\n`),t=eqe(t),t=t.replace(/^\\n+|\\n+$/g,\"\"),t=t.replace(/^(\\s*)-([^\\n]*?)\\n+/gm,`$1-$2\n\n`),t=t.replace(/\\n(\\n)?\\n*/g,(o,a)=>a||\" \"),r&&(t=t.split(/\\n/).map(o=>{let a=o.match(/^\\s*[*-][\\t ]+(.*)/);if(!a)return o.match(/(.{1,80})(?: |$)/g).join(`\n`);let n=o.length-o.trimStart().length;return a[1].match(new RegExp(`(.{1,${78-n}})(?: |$)`,\"g\")).map((u,A)=>\" \".repeat(n)+(A===0?\"- \":\"  \")+u).join(`\n`)}).join(`\n\n`)),t=t.replace(/(`+)((?:.|[\\n])*?)\\1/g,(o,a,n)=>e.code(a+n+a)),t=t.replace(/(\\*\\*)((?:.|[\\n])*?)\\1/g,(o,a,n)=>e.bold(a+n+a)),t?`${t}\n`:\"\"}var xT,uz,Az,kT=Et(()=>{xT=Array(80).fill(\"\\u2501\");for(let t=0;t<=24;++t)xT[xT.length-t]=`\\x1B[38;5;${232+t}m\\u2501`;uz={header:t=>`\\x1B[1m\\u2501\\u2501\\u2501 ${t}${t.length<80-5?` ${xT.slice(t.length+5).join(\"\")}`:\":\"}\\x1B[0m`,bold:t=>`\\x1B[1m${t}\\x1B[22m`,error:t=>`\\x1B[31m\\x1B[1m${t}\\x1B[22m\\x1B[39m`,code:t=>`\\x1B[36m${t}\\x1B[39m`},Az={header:t=>t,bold:t=>t,error:t=>t,code:t=>t}});function Ko(t){return{...t,[nI]:!0}}function ju(t,e){return typeof t>\"u\"?[t,e]:typeof t==\"object\"&&t!==null&&!Array.isArray(t)?[void 0,t]:[t,e]}function rP(t,{mergeName:e=!1}={}){let r=t.match(/^([^:]+): (.*)$/m);if(!r)return\"validation failed\";let[,o,a]=r;return e&&(a=a[0].toLowerCase()+a.slice(1)),a=o!==\".\"||!e?`${o.replace(/^\\.(\\[|$)/,\"$1\")}: ${a}`:`: ${a}`,a}function iI(t,e){return e.length===1?new it(`${t}${rP(e[0],{mergeName:!0})}`):new it(`${t}:\n${e.map(r=>`\n- ${rP(r)}`).join(\"\")}`)}function id(t,e,r){if(typeof r>\"u\")return e;let o=[],a=[],n=A=>{let p=e;return e=A,n.bind(null,p)};if(!r(e,{errors:o,coercions:a,coercion:n}))throw iI(`Invalid value for ${t}`,o);for(let[,A]of a)A();return e}var nI,Ef=Et(()=>{tP();nI=Symbol(\"clipanion/isOption\")});var zo={};zt(zo,{KeyRelationship:()=>Yu,TypeAssertionError:()=>zp,applyCascade:()=>aI,as:()=>Eqe,assert:()=>dqe,assertWithErrors:()=>mqe,cascade:()=>oP,fn:()=>Cqe,hasAtLeastOneKey:()=>OT,hasExactLength:()=>dz,hasForbiddenKeys:()=>Uqe,hasKeyRelationship:()=>cI,hasMaxLength:()=>Iqe,hasMinLength:()=>wqe,hasMutuallyExclusiveKeys:()=>_qe,hasRequiredKeys:()=>Mqe,hasUniqueItems:()=>Bqe,isArray:()=>nP,isAtLeast:()=>LT,isAtMost:()=>Pqe,isBase64:()=>Tqe,isBoolean:()=>lqe,isDate:()=>uqe,isDict:()=>pqe,isEnum:()=>Ks,isHexColor:()=>Rqe,isISO8601:()=>Fqe,isInExclusiveRange:()=>bqe,isInInclusiveRange:()=>Sqe,isInstanceOf:()=>gqe,isInteger:()=>NT,isJSON:()=>Lqe,isLiteral:()=>pz,isLowerCase:()=>xqe,isMap:()=>fqe,isNegative:()=>vqe,isNullable:()=>Oqe,isNumber:()=>RT,isObject:()=>hz,isOneOf:()=>TT,isOptional:()=>Nqe,isPartial:()=>hqe,isPayload:()=>cqe,isPositive:()=>Dqe,isRecord:()=>sP,isSet:()=>Aqe,isString:()=>Cy,isTuple:()=>iP,isUUID4:()=>Qqe,isUnknown:()=>FT,isUpperCase:()=>kqe,makeTrait:()=>gz,makeValidator:()=>Hr,matchesRegExp:()=>oI,softAssert:()=>yqe});function qn(t){return t===null?\"null\":t===void 0?\"undefined\":t===\"\"?\"an empty string\":typeof t==\"symbol\"?`<${t.toString()}>`:Array.isArray(t)?\"an array\":JSON.stringify(t)}function Ey(t,e){if(t.length===0)return\"nothing\";if(t.length===1)return qn(t[0]);let r=t.slice(0,-1),o=t[t.length-1],a=t.length>2?`, ${e} `:` ${e} `;return`${r.map(n=>qn(n)).join(\", \")}${a}${qn(o)}`}function Kp(t,e){var r,o,a;return typeof e==\"number\"?`${(r=t?.p)!==null&&r!==void 0?r:\".\"}[${e}]`:tqe.test(e)?`${(o=t?.p)!==null&&o!==void 0?o:\"\"}.${e}`:`${(a=t?.p)!==null&&a!==void 0?a:\".\"}[${JSON.stringify(e)}]`}function QT(t,e,r){return t===1?e:r}function pr({errors:t,p:e}={},r){return t?.push(`${e??\".\"}: ${r}`),!1}function oqe(t,e){return r=>{t[e]=r}}function Wu(t,e){return r=>{let o=t[e];return t[e]=r,Wu(t,e).bind(null,o)}}function sI(t,e,r){let o=()=>(t(r()),a),a=()=>(t(e),o);return o}function FT(){return Hr({test:(t,e)=>!0})}function pz(t){return Hr({test:(e,r)=>e!==t?pr(r,`Expected ${qn(t)} (got ${qn(e)})`):!0})}function Cy(){return Hr({test:(t,e)=>typeof t!=\"string\"?pr(e,`Expected a string (got ${qn(t)})`):!0})}function Ks(t){let e=Array.isArray(t)?t:Object.values(t),r=e.every(a=>typeof a==\"string\"||typeof a==\"number\"),o=new Set(e);return o.size===1?pz([...o][0]):Hr({test:(a,n)=>o.has(a)?!0:r?pr(n,`Expected one of ${Ey(e,\"or\")} (got ${qn(a)})`):pr(n,`Expected a valid enumeration value (got ${qn(a)})`)})}function lqe(){return Hr({test:(t,e)=>{var r;if(typeof t!=\"boolean\"){if(typeof e?.coercions<\"u\"){if(typeof e?.coercion>\"u\")return pr(e,\"Unbound coercion result\");let o=aqe.get(t);if(typeof o<\"u\")return e.coercions.push([(r=e.p)!==null&&r!==void 0?r:\".\",e.coercion.bind(null,o)]),!0}return pr(e,`Expected a boolean (got ${qn(t)})`)}return!0}})}function RT(){return Hr({test:(t,e)=>{var r;if(typeof t!=\"number\"){if(typeof e?.coercions<\"u\"){if(typeof e?.coercion>\"u\")return pr(e,\"Unbound coercion result\");let o;if(typeof t==\"string\"){let a;try{a=JSON.parse(t)}catch{}if(typeof a==\"number\")if(JSON.stringify(a)===t)o=a;else return pr(e,`Received a number that can't be safely represented by the runtime (${t})`)}if(typeof o<\"u\")return e.coercions.push([(r=e.p)!==null&&r!==void 0?r:\".\",e.coercion.bind(null,o)]),!0}return pr(e,`Expected a number (got ${qn(t)})`)}return!0}})}function cqe(t){return Hr({test:(e,r)=>{var o;if(typeof r?.coercions>\"u\")return pr(r,\"The isPayload predicate can only be used with coercion enabled\");if(typeof r.coercion>\"u\")return pr(r,\"Unbound coercion result\");if(typeof e!=\"string\")return pr(r,`Expected a string (got ${qn(e)})`);let a;try{a=JSON.parse(e)}catch{return pr(r,`Expected a JSON string (got ${qn(e)})`)}let n={value:a};return t(a,Object.assign(Object.assign({},r),{coercion:Wu(n,\"value\")}))?(r.coercions.push([(o=r.p)!==null&&o!==void 0?o:\".\",r.coercion.bind(null,n.value)]),!0):!1}})}function uqe(){return Hr({test:(t,e)=>{var r;if(!(t instanceof Date)){if(typeof e?.coercions<\"u\"){if(typeof e?.coercion>\"u\")return pr(e,\"Unbound coercion result\");let o;if(typeof t==\"string\"&&fz.test(t))o=new Date(t);else{let a;if(typeof t==\"string\"){let n;try{n=JSON.parse(t)}catch{}typeof n==\"number\"&&(a=n)}else typeof t==\"number\"&&(a=t);if(typeof a<\"u\")if(Number.isSafeInteger(a)||!Number.isSafeInteger(a*1e3))o=new Date(a*1e3);else return pr(e,`Received a timestamp that can't be safely represented by the runtime (${t})`)}if(typeof o<\"u\")return e.coercions.push([(r=e.p)!==null&&r!==void 0?r:\".\",e.coercion.bind(null,o)]),!0}return pr(e,`Expected a date (got ${qn(t)})`)}return!0}})}function nP(t,{delimiter:e}={}){return Hr({test:(r,o)=>{var a;let n=r;if(typeof r==\"string\"&&typeof e<\"u\"&&typeof o?.coercions<\"u\"){if(typeof o?.coercion>\"u\")return pr(o,\"Unbound coercion result\");r=r.split(e)}if(!Array.isArray(r))return pr(o,`Expected an array (got ${qn(r)})`);let u=!0;for(let A=0,p=r.length;A<p&&(u=t(r[A],Object.assign(Object.assign({},o),{p:Kp(o,A),coercion:Wu(r,A)}))&&u,!(!u&&o?.errors==null));++A);return r!==n&&o.coercions.push([(a=o.p)!==null&&a!==void 0?a:\".\",o.coercion.bind(null,r)]),u}})}function Aqe(t,{delimiter:e}={}){let r=nP(t,{delimiter:e});return Hr({test:(o,a)=>{var n,u;if(Object.getPrototypeOf(o).toString()===\"[object Set]\")if(typeof a?.coercions<\"u\"){if(typeof a?.coercion>\"u\")return pr(a,\"Unbound coercion result\");let A=[...o],p=[...o];if(!r(p,Object.assign(Object.assign({},a),{coercion:void 0})))return!1;let h=()=>p.some((E,I)=>E!==A[I])?new Set(p):o;return a.coercions.push([(n=a.p)!==null&&n!==void 0?n:\".\",sI(a.coercion,o,h)]),!0}else{let A=!0;for(let p of o)if(A=t(p,Object.assign({},a))&&A,!A&&a?.errors==null)break;return A}if(typeof a?.coercions<\"u\"){if(typeof a?.coercion>\"u\")return pr(a,\"Unbound coercion result\");let A={value:o};return r(o,Object.assign(Object.assign({},a),{coercion:Wu(A,\"value\")}))?(a.coercions.push([(u=a.p)!==null&&u!==void 0?u:\".\",sI(a.coercion,o,()=>new Set(A.value))]),!0):!1}return pr(a,`Expected a set (got ${qn(o)})`)}})}function fqe(t,e){let r=nP(iP([t,e])),o=sP(e,{keys:t});return Hr({test:(a,n)=>{var u,A,p;if(Object.getPrototypeOf(a).toString()===\"[object Map]\")if(typeof n?.coercions<\"u\"){if(typeof n?.coercion>\"u\")return pr(n,\"Unbound coercion result\");let h=[...a],E=[...a];if(!r(E,Object.assign(Object.assign({},n),{coercion:void 0})))return!1;let I=()=>E.some((v,x)=>v[0]!==h[x][0]||v[1]!==h[x][1])?new Map(E):a;return n.coercions.push([(u=n.p)!==null&&u!==void 0?u:\".\",sI(n.coercion,a,I)]),!0}else{let h=!0;for(let[E,I]of a)if(h=t(E,Object.assign({},n))&&h,!h&&n?.errors==null||(h=e(I,Object.assign(Object.assign({},n),{p:Kp(n,E)}))&&h,!h&&n?.errors==null))break;return h}if(typeof n?.coercions<\"u\"){if(typeof n?.coercion>\"u\")return pr(n,\"Unbound coercion result\");let h={value:a};return Array.isArray(a)?r(a,Object.assign(Object.assign({},n),{coercion:void 0}))?(n.coercions.push([(A=n.p)!==null&&A!==void 0?A:\".\",sI(n.coercion,a,()=>new Map(h.value))]),!0):!1:o(a,Object.assign(Object.assign({},n),{coercion:Wu(h,\"value\")}))?(n.coercions.push([(p=n.p)!==null&&p!==void 0?p:\".\",sI(n.coercion,a,()=>new Map(Object.entries(h.value)))]),!0):!1}return pr(n,`Expected a map (got ${qn(a)})`)}})}function iP(t,{delimiter:e}={}){let r=dz(t.length);return Hr({test:(o,a)=>{var n;if(typeof o==\"string\"&&typeof e<\"u\"&&typeof a?.coercions<\"u\"){if(typeof a?.coercion>\"u\")return pr(a,\"Unbound coercion result\");o=o.split(e),a.coercions.push([(n=a.p)!==null&&n!==void 0?n:\".\",a.coercion.bind(null,o)])}if(!Array.isArray(o))return pr(a,`Expected a tuple (got ${qn(o)})`);let u=r(o,Object.assign({},a));for(let A=0,p=o.length;A<p&&A<t.length&&(u=t[A](o[A],Object.assign(Object.assign({},a),{p:Kp(a,A),coercion:Wu(o,A)}))&&u,!(!u&&a?.errors==null));++A);return u}})}function sP(t,{keys:e=null}={}){let r=nP(iP([e??Cy(),t]));return Hr({test:(o,a)=>{var n;if(Array.isArray(o)&&typeof a?.coercions<\"u\")return typeof a?.coercion>\"u\"?pr(a,\"Unbound coercion result\"):r(o,Object.assign(Object.assign({},a),{coercion:void 0}))?(o=Object.fromEntries(o),a.coercions.push([(n=a.p)!==null&&n!==void 0?n:\".\",a.coercion.bind(null,o)]),!0):!1;if(typeof o!=\"object\"||o===null)return pr(a,`Expected an object (got ${qn(o)})`);let u=Object.keys(o),A=!0;for(let p=0,h=u.length;p<h&&(A||a?.errors!=null);++p){let E=u[p],I=o[E];if(E===\"__proto__\"||E===\"constructor\"){A=pr(Object.assign(Object.assign({},a),{p:Kp(a,E)}),\"Unsafe property name\");continue}if(e!==null&&!e(E,a)){A=!1;continue}if(!t(I,Object.assign(Object.assign({},a),{p:Kp(a,E),coercion:Wu(o,E)}))){A=!1;continue}}return A}})}function pqe(t,e={}){return sP(t,e)}function hz(t,{extra:e=null}={}){let r=Object.keys(t),o=Hr({test:(a,n)=>{if(typeof a!=\"object\"||a===null)return pr(n,`Expected an object (got ${qn(a)})`);let u=new Set([...r,...Object.keys(a)]),A={},p=!0;for(let h of u){if(h===\"constructor\"||h===\"__proto__\")p=pr(Object.assign(Object.assign({},n),{p:Kp(n,h)}),\"Unsafe property name\");else{let E=Object.prototype.hasOwnProperty.call(t,h)?t[h]:void 0,I=Object.prototype.hasOwnProperty.call(a,h)?a[h]:void 0;typeof E<\"u\"?p=E(I,Object.assign(Object.assign({},n),{p:Kp(n,h),coercion:Wu(a,h)}))&&p:e===null?p=pr(Object.assign(Object.assign({},n),{p:Kp(n,h)}),`Extraneous property (got ${qn(I)})`):Object.defineProperty(A,h,{enumerable:!0,get:()=>I,set:oqe(a,h)})}if(!p&&n?.errors==null)break}return e!==null&&(p||n?.errors!=null)&&(p=e(A,n)&&p),p}});return Object.assign(o,{properties:t})}function hqe(t){return hz(t,{extra:sP(FT())})}function gz(t){return()=>t}function Hr({test:t}){return gz(t)()}function dqe(t,e){if(!e(t))throw new zp}function mqe(t,e){let r=[];if(!e(t,{errors:r}))throw new zp({errors:r})}function yqe(t,e){}function Eqe(t,e,{coerce:r=!1,errors:o,throw:a}={}){let n=o?[]:void 0;if(!r){if(e(t,{errors:n}))return a?t:{value:t,errors:void 0};if(a)throw new zp({errors:n});return{value:void 0,errors:n??!0}}let u={value:t},A=Wu(u,\"value\"),p=[];if(!e(t,{errors:n,coercion:A,coercions:p})){if(a)throw new zp({errors:n});return{value:void 0,errors:n??!0}}for(let[,h]of p)h();return a?u.value:{value:u.value,errors:void 0}}function Cqe(t,e){let r=iP(t);return(...o)=>{if(!r(o))throw new zp;return e(...o)}}function wqe(t){return Hr({test:(e,r)=>e.length>=t?!0:pr(r,`Expected to have a length of at least ${t} elements (got ${e.length})`)})}function Iqe(t){return Hr({test:(e,r)=>e.length<=t?!0:pr(r,`Expected to have a length of at most ${t} elements (got ${e.length})`)})}function dz(t){return Hr({test:(e,r)=>e.length!==t?pr(r,`Expected to have a length of exactly ${t} elements (got ${e.length})`):!0})}function Bqe({map:t}={}){return Hr({test:(e,r)=>{let o=new Set,a=new Set;for(let n=0,u=e.length;n<u;++n){let A=e[n],p=typeof t<\"u\"?t(A):A;if(o.has(p)){if(a.has(p))continue;pr(r,`Expected to contain unique elements; got a duplicate with ${qn(e)}`),a.add(p)}else o.add(p)}return a.size===0}})}function vqe(){return Hr({test:(t,e)=>t<=0?!0:pr(e,`Expected to be negative (got ${t})`)})}function Dqe(){return Hr({test:(t,e)=>t>=0?!0:pr(e,`Expected to be positive (got ${t})`)})}function LT(t){return Hr({test:(e,r)=>e>=t?!0:pr(r,`Expected to be at least ${t} (got ${e})`)})}function Pqe(t){return Hr({test:(e,r)=>e<=t?!0:pr(r,`Expected to be at most ${t} (got ${e})`)})}function Sqe(t,e){return Hr({test:(r,o)=>r>=t&&r<=e?!0:pr(o,`Expected to be in the [${t}; ${e}] range (got ${r})`)})}function bqe(t,e){return Hr({test:(r,o)=>r>=t&&r<e?!0:pr(o,`Expected to be in the [${t}; ${e}[ range (got ${r})`)})}function NT({unsafe:t=!1}={}){return Hr({test:(e,r)=>e!==Math.round(e)?pr(r,`Expected to be an integer (got ${e})`):!t&&!Number.isSafeInteger(e)?pr(r,`Expected to be a safe integer (got ${e})`):!0})}function oI(t){return Hr({test:(e,r)=>t.test(e)?!0:pr(r,`Expected to match the pattern ${t.toString()} (got ${qn(e)})`)})}function xqe(){return Hr({test:(t,e)=>t!==t.toLowerCase()?pr(e,`Expected to be all-lowercase (got ${t})`):!0})}function kqe(){return Hr({test:(t,e)=>t!==t.toUpperCase()?pr(e,`Expected to be all-uppercase (got ${t})`):!0})}function Qqe(){return Hr({test:(t,e)=>sqe.test(t)?!0:pr(e,`Expected to be a valid UUID v4 (got ${qn(t)})`)})}function Fqe(){return Hr({test:(t,e)=>fz.test(t)?!0:pr(e,`Expected to be a valid ISO 8601 date string (got ${qn(t)})`)})}function Rqe({alpha:t=!1}){return Hr({test:(e,r)=>(t?rqe.test(e):nqe.test(e))?!0:pr(r,`Expected to be a valid hexadecimal color string (got ${qn(e)})`)})}function Tqe(){return Hr({test:(t,e)=>iqe.test(t)?!0:pr(e,`Expected to be a valid base 64 string (got ${qn(t)})`)})}function Lqe(t=FT()){return Hr({test:(e,r)=>{let o;try{o=JSON.parse(e)}catch{return pr(r,`Expected to be a valid JSON string (got ${qn(e)})`)}return t(o,r)}})}function oP(t,...e){let r=Array.isArray(e[0])?e[0]:e;return Hr({test:(o,a)=>{var n,u;let A={value:o},p=typeof a?.coercions<\"u\"?Wu(A,\"value\"):void 0,h=typeof a?.coercions<\"u\"?[]:void 0;if(!t(o,Object.assign(Object.assign({},a),{coercion:p,coercions:h})))return!1;let E=[];if(typeof h<\"u\")for(let[,I]of h)E.push(I());try{if(typeof a?.coercions<\"u\"){if(A.value!==o){if(typeof a?.coercion>\"u\")return pr(a,\"Unbound coercion result\");a.coercions.push([(n=a.p)!==null&&n!==void 0?n:\".\",a.coercion.bind(null,A.value)])}(u=a?.coercions)===null||u===void 0||u.push(...h)}return r.every(I=>I(A.value,a))}finally{for(let I of E)I()}}})}function aI(t,...e){let r=Array.isArray(e[0])?e[0]:e;return oP(t,r)}function Nqe(t){return Hr({test:(e,r)=>typeof e>\"u\"?!0:t(e,r)})}function Oqe(t){return Hr({test:(e,r)=>e===null?!0:t(e,r)})}function Mqe(t,e){var r;let o=new Set(t),a=lI[(r=e?.missingIf)!==null&&r!==void 0?r:\"missing\"];return Hr({test:(n,u)=>{let A=new Set(Object.keys(n)),p=[];for(let h of o)a(A,h,n)||p.push(h);return p.length>0?pr(u,`Missing required ${QT(p.length,\"property\",\"properties\")} ${Ey(p,\"and\")}`):!0}})}function OT(t,e){var r;let o=new Set(t),a=lI[(r=e?.missingIf)!==null&&r!==void 0?r:\"missing\"];return Hr({test:(n,u)=>Object.keys(n).some(h=>a(o,h,n))?!0:pr(u,`Missing at least one property from ${Ey(Array.from(o),\"or\")}`)})}function Uqe(t,e){var r;let o=new Set(t),a=lI[(r=e?.missingIf)!==null&&r!==void 0?r:\"missing\"];return Hr({test:(n,u)=>{let A=new Set(Object.keys(n)),p=[];for(let h of o)a(A,h,n)&&p.push(h);return p.length>0?pr(u,`Forbidden ${QT(p.length,\"property\",\"properties\")} ${Ey(p,\"and\")}`):!0}})}function _qe(t,e){var r;let o=new Set(t),a=lI[(r=e?.missingIf)!==null&&r!==void 0?r:\"missing\"];return Hr({test:(n,u)=>{let A=new Set(Object.keys(n)),p=[];for(let h of o)a(A,h,n)&&p.push(h);return p.length>1?pr(u,`Mutually exclusive properties ${Ey(p,\"and\")}`):!0}})}function cI(t,e,r,o){var a,n;let u=new Set((a=o?.ignore)!==null&&a!==void 0?a:[]),A=lI[(n=o?.missingIf)!==null&&n!==void 0?n:\"missing\"],p=new Set(r),h=Hqe[e],E=e===Yu.Forbids?\"or\":\"and\";return Hr({test:(I,v)=>{let x=new Set(Object.keys(I));if(!A(x,t,I)||u.has(I[t]))return!0;let C=[];for(let R of p)(A(x,R,I)&&!u.has(I[R]))!==h.expect&&C.push(R);return C.length>=1?pr(v,`Property \"${t}\" ${h.message} ${QT(C.length,\"property\",\"properties\")} ${Ey(C,E)}`):!0}})}var tqe,rqe,nqe,iqe,sqe,fz,aqe,gqe,TT,zp,lI,Yu,Hqe,$a=Et(()=>{tqe=/^[a-zA-Z_][a-zA-Z0-9_]*$/;rqe=/^#[0-9a-f]{6}$/i,nqe=/^#[0-9a-f]{6}([0-9a-f]{2})?$/i,iqe=/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/,sqe=/^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}$/i,fz=/^(?:[1-9]\\d{3}(-?)(?:(?:0[1-9]|1[0-2])\\1(?:0[1-9]|1\\d|2[0-8])|(?:0[13-9]|1[0-2])\\1(?:29|30)|(?:0[13578]|1[02])(?:\\1)31|00[1-9]|0[1-9]\\d|[12]\\d{2}|3(?:[0-5]\\d|6[0-5]))|(?:[1-9]\\d(?:0[48]|[2468][048]|[13579][26])|(?:[2468][048]|[13579][26])00)(?:(-?)02(?:\\2)29|-?366))T(?:[01]\\d|2[0-3])(:?)[0-5]\\d(?:\\3[0-5]\\d)?(?:Z|[+-][01]\\d(?:\\3[0-5]\\d)?)$/;aqe=new Map([[\"true\",!0],[\"True\",!0],[\"1\",!0],[1,!0],[\"false\",!1],[\"False\",!1],[\"0\",!1],[0,!1]]);gqe=t=>Hr({test:(e,r)=>e instanceof t?!0:pr(r,`Expected an instance of ${t.name} (got ${qn(e)})`)}),TT=(t,{exclusive:e=!1}={})=>Hr({test:(r,o)=>{var a,n,u;let A=[],p=typeof o?.errors<\"u\"?[]:void 0;for(let h=0,E=t.length;h<E;++h){let I=typeof o?.errors<\"u\"?[]:void 0,v=typeof o?.coercions<\"u\"?[]:void 0;if(t[h](r,Object.assign(Object.assign({},o),{errors:I,coercions:v,p:`${(a=o?.p)!==null&&a!==void 0?a:\".\"}#${h+1}`}))){if(A.push([`#${h+1}`,v]),!e)break}else p?.push(I[0])}if(A.length===1){let[,h]=A[0];return typeof h<\"u\"&&((n=o?.coercions)===null||n===void 0||n.push(...h)),!0}return A.length>1?pr(o,`Expected to match exactly a single predicate (matched ${A.join(\", \")})`):(u=o?.errors)===null||u===void 0||u.push(...p),!1}});zp=class extends Error{constructor({errors:e}={}){let r=\"Type mismatch\";if(e&&e.length>0){r+=`\n`;for(let o of e)r+=`\n- ${o}`}super(r)}};lI={missing:(t,e)=>t.has(e),undefined:(t,e,r)=>t.has(e)&&typeof r[e]<\"u\",nil:(t,e,r)=>t.has(e)&&r[e]!=null,falsy:(t,e,r)=>t.has(e)&&!!r[e]};(function(t){t.Forbids=\"Forbids\",t.Requires=\"Requires\"})(Yu||(Yu={}));Hqe={[Yu.Forbids]:{expect:!1,message:\"forbids using\"},[Yu.Requires]:{expect:!0,message:\"requires using\"}}});var nt,Vp=Et(()=>{Ef();nt=class{constructor(){this.help=!1}static Usage(e){return e}async catch(e){throw e}async validateAndExecute(){let r=this.constructor.schema;if(Array.isArray(r)){let{isDict:a,isUnknown:n,applyCascade:u}=await Promise.resolve().then(()=>($a(),zo)),A=u(a(n()),r),p=[],h=[];if(!A(this,{errors:p,coercions:h}))throw iI(\"Invalid option schema\",p);for(let[,I]of h)I()}else if(r!=null)throw new Error(\"Invalid command schema\");let o=await this.execute();return typeof o<\"u\"?o:0}};nt.isOption=nI;nt.Default=[]});function va(t){ST&&console.log(t)}function yz(){let t={nodes:[]};for(let e=0;e<cn.CustomNode;++e)t.nodes.push(el());return t}function qqe(t){let e=yz(),r=[],o=e.nodes.length;for(let a of t){r.push(o);for(let n=0;n<a.nodes.length;++n)Cz(n)||e.nodes.push(Jqe(a.nodes[n],o));o+=a.nodes.length-cn.CustomNode+1}for(let a of r)wy(e,cn.InitialNode,a);return e}function Mc(t,e){return t.nodes.push(e),t.nodes.length-1}function Gqe(t){let e=new Set,r=o=>{if(e.has(o))return;e.add(o);let a=t.nodes[o];for(let u of Object.values(a.statics))for(let{to:A}of u)r(A);for(let[,{to:u}]of a.dynamics)r(u);for(let{to:u}of a.shortcuts)r(u);let n=new Set(a.shortcuts.map(({to:u})=>u));for(;a.shortcuts.length>0;){let{to:u}=a.shortcuts.shift(),A=t.nodes[u];for(let[p,h]of Object.entries(A.statics)){let E=Object.prototype.hasOwnProperty.call(a.statics,p)?a.statics[p]:a.statics[p]=[];for(let I of h)E.some(({to:v})=>I.to===v)||E.push(I)}for(let[p,h]of A.dynamics)a.dynamics.some(([E,{to:I}])=>p===E&&h.to===I)||a.dynamics.push([p,h]);for(let p of A.shortcuts)n.has(p.to)||(a.shortcuts.push(p),n.add(p.to))}};r(cn.InitialNode)}function jqe(t,{prefix:e=\"\"}={}){if(ST){va(`${e}Nodes are:`);for(let r=0;r<t.nodes.length;++r)va(`${e}  ${r}: ${JSON.stringify(t.nodes[r])}`)}}function Yqe(t,e,r=!1){va(`Running a vm on ${JSON.stringify(e)}`);let o=[{node:cn.InitialNode,state:{candidateUsage:null,requiredOptions:[],errorMessage:null,ignoreOptions:!1,options:[],path:[],positionals:[],remainder:null,selectedIndex:null,partial:!1,tokens:[]}}];jqe(t,{prefix:\"  \"});let a=[Hn.StartOfInput,...e];for(let n=0;n<a.length;++n){let u=a[n],A=u===Hn.EndOfInput||u===Hn.EndOfPartialInput,p=n-1;va(`  Processing ${JSON.stringify(u)}`);let h=[];for(let{node:E,state:I}of o){va(`    Current node is ${E}`);let v=t.nodes[E];if(E===cn.ErrorNode){h.push({node:E,state:I});continue}console.assert(v.shortcuts.length===0,\"Shortcuts should have been eliminated by now\");let x=Object.prototype.hasOwnProperty.call(v.statics,u);if(!r||n<a.length-1||x)if(x){let C=v.statics[u];for(let{to:R,reducer:N}of C)h.push({node:R,state:typeof N<\"u\"?aP(UT,N,I,u,p):I}),va(`      Static transition to ${R} found`)}else va(\"      No static transition found\");else{let C=!1;for(let R of Object.keys(v.statics))if(!!R.startsWith(u)){if(u===R)for(let{to:N,reducer:U}of v.statics[R])h.push({node:N,state:typeof U<\"u\"?aP(UT,U,I,u,p):I}),va(`      Static transition to ${N} found`);else for(let{to:N}of v.statics[R])h.push({node:N,state:{...I,remainder:R.slice(u.length)}}),va(`      Static transition to ${N} found (partial match)`);C=!0}C||va(\"      No partial static transition found\")}if(!A)for(let[C,{to:R,reducer:N}]of v.dynamics)aP(Xqe,C,I,u,p)&&(h.push({node:R,state:typeof N<\"u\"?aP(UT,N,I,u,p):I}),va(`      Dynamic transition to ${R} found (via ${C})`))}if(h.length===0&&A&&e.length===1)return[{node:cn.InitialNode,state:mz}];if(h.length===0)throw new yy(e,o.filter(({node:E})=>E!==cn.ErrorNode).map(({state:E})=>({usage:E.candidateUsage,reason:null})));if(h.every(({node:E})=>E===cn.ErrorNode))throw new yy(e,h.map(({state:E})=>({usage:E.candidateUsage,reason:E.errorMessage})));o=Kqe(h)}if(o.length>0){va(\"  Results:\");for(let n of o)va(`    - ${n.node} -> ${JSON.stringify(n.state)}`)}else va(\"  No results\");return o}function Wqe(t,e,{endToken:r=Hn.EndOfInput}={}){let o=Yqe(t,[...e,r]);return zqe(e,o.map(({state:a})=>a))}function Kqe(t){let e=0;for(let{state:r}of t)r.path.length>e&&(e=r.path.length);return t.filter(({state:r})=>r.path.length===e)}function zqe(t,e){let r=e.filter(v=>v.selectedIndex!==null),o=r.filter(v=>!v.partial);if(o.length>0&&(r=o),r.length===0)throw new Error;let a=r.filter(v=>v.selectedIndex===nd||v.requiredOptions.every(x=>x.some(C=>v.options.find(R=>R.name===C))));if(a.length===0)throw new yy(t,r.map(v=>({usage:v.candidateUsage,reason:null})));let n=0;for(let v of a)v.path.length>n&&(n=v.path.length);let u=a.filter(v=>v.path.length===n),A=v=>v.positionals.filter(({extra:x})=>!x).length+v.options.length,p=u.map(v=>({state:v,positionalCount:A(v)})),h=0;for(let{positionalCount:v}of p)v>h&&(h=v);let E=p.filter(({positionalCount:v})=>v===h).map(({state:v})=>v),I=Vqe(E);if(I.length>1)throw new eP(t,I.map(v=>v.candidateUsage));return I[0]}function Vqe(t){let e=[],r=[];for(let o of t)o.selectedIndex===nd?r.push(o):e.push(o);return r.length>0&&e.push({...mz,path:Ez(...r.map(o=>o.path)),options:r.reduce((o,a)=>o.concat(a.options),[])}),e}function Ez(t,e,...r){return e===void 0?Array.from(t):Ez(t.filter((o,a)=>o===e[a]),...r)}function el(){return{dynamics:[],shortcuts:[],statics:{}}}function Cz(t){return t===cn.SuccessNode||t===cn.ErrorNode}function MT(t,e=0){return{to:Cz(t.to)?t.to:t.to>=cn.CustomNode?t.to+e-cn.CustomNode+1:t.to+e,reducer:t.reducer}}function Jqe(t,e=0){let r=el();for(let[o,a]of t.dynamics)r.dynamics.push([o,MT(a,e)]);for(let o of t.shortcuts)r.shortcuts.push(MT(o,e));for(let[o,a]of Object.entries(t.statics))r.statics[o]=a.map(n=>MT(n,e));return r}function Ss(t,e,r,o,a){t.nodes[e].dynamics.push([r,{to:o,reducer:a}])}function wy(t,e,r,o){t.nodes[e].shortcuts.push({to:r,reducer:o})}function Vo(t,e,r,o,a){(Object.prototype.hasOwnProperty.call(t.nodes[e].statics,r)?t.nodes[e].statics[r]:t.nodes[e].statics[r]=[]).push({to:o,reducer:a})}function aP(t,e,r,o,a){if(Array.isArray(e)){let[n,...u]=e;return t[n](r,o,a,...u)}else return t[e](r,o,a)}var mz,Xqe,UT,tl,_T,Iy,lP=Et(()=>{$D();tP();mz={candidateUsage:null,requiredOptions:[],errorMessage:null,ignoreOptions:!1,path:[],positionals:[],options:[],remainder:null,selectedIndex:nd,partial:!1,tokens:[]};Xqe={always:()=>!0,isOptionLike:(t,e)=>!t.ignoreOptions&&e!==\"-\"&&e.startsWith(\"-\"),isNotOptionLike:(t,e)=>t.ignoreOptions||e===\"-\"||!e.startsWith(\"-\"),isOption:(t,e,r,o)=>!t.ignoreOptions&&e===o,isBatchOption:(t,e,r,o)=>!t.ignoreOptions&&cz.test(e)&&[...e.slice(1)].every(a=>o.has(`-${a}`)),isBoundOption:(t,e,r,o,a)=>{let n=e.match(PT);return!t.ignoreOptions&&!!n&&ZD.test(n[1])&&o.has(n[1])&&a.filter(u=>u.nameSet.includes(n[1])).every(u=>u.allowBinding)},isNegatedOption:(t,e,r,o)=>!t.ignoreOptions&&e===`--no-${o.slice(2)}`,isHelp:(t,e)=>!t.ignoreOptions&&DT.test(e),isUnsupportedOption:(t,e,r,o)=>!t.ignoreOptions&&e.startsWith(\"-\")&&ZD.test(e)&&!o.has(e),isInvalidOption:(t,e)=>!t.ignoreOptions&&e.startsWith(\"-\")&&!ZD.test(e)},UT={setCandidateState:(t,e,r,o)=>({...t,...o}),setSelectedIndex:(t,e,r,o)=>({...t,selectedIndex:o}),setPartialIndex:(t,e,r,o)=>({...t,selectedIndex:o,partial:!0}),pushBatch:(t,e,r,o)=>{let a=t.options.slice(),n=t.tokens.slice();for(let u=1;u<e.length;++u){let A=o.get(`-${e[u]}`),p=u===1?[0,2]:[u,u+1];a.push({name:A,value:!0}),n.push({segmentIndex:r,type:\"option\",option:A,slice:p})}return{...t,options:a,tokens:n}},pushBound:(t,e,r)=>{let[,o,a]=e.match(PT),n=t.options.concat({name:o,value:a}),u=t.tokens.concat([{segmentIndex:r,type:\"option\",slice:[0,o.length],option:o},{segmentIndex:r,type:\"assign\",slice:[o.length,o.length+1]},{segmentIndex:r,type:\"value\",slice:[o.length+1,o.length+a.length+1]}]);return{...t,options:n,tokens:u}},pushPath:(t,e,r)=>{let o=t.path.concat(e),a=t.tokens.concat({segmentIndex:r,type:\"path\"});return{...t,path:o,tokens:a}},pushPositional:(t,e,r)=>{let o=t.positionals.concat({value:e,extra:!1}),a=t.tokens.concat({segmentIndex:r,type:\"positional\"});return{...t,positionals:o,tokens:a}},pushExtra:(t,e,r)=>{let o=t.positionals.concat({value:e,extra:!0}),a=t.tokens.concat({segmentIndex:r,type:\"positional\"});return{...t,positionals:o,tokens:a}},pushExtraNoLimits:(t,e,r)=>{let o=t.positionals.concat({value:e,extra:tl}),a=t.tokens.concat({segmentIndex:r,type:\"positional\"});return{...t,positionals:o,tokens:a}},pushTrue:(t,e,r,o)=>{let a=t.options.concat({name:o,value:!0}),n=t.tokens.concat({segmentIndex:r,type:\"option\",option:o});return{...t,options:a,tokens:n}},pushFalse:(t,e,r,o)=>{let a=t.options.concat({name:o,value:!1}),n=t.tokens.concat({segmentIndex:r,type:\"option\",option:o});return{...t,options:a,tokens:n}},pushUndefined:(t,e,r,o)=>{let a=t.options.concat({name:e,value:void 0}),n=t.tokens.concat({segmentIndex:r,type:\"option\",option:e});return{...t,options:a,tokens:n}},pushStringValue:(t,e,r)=>{var o;let a=t.options[t.options.length-1],n=t.options.slice(),u=t.tokens.concat({segmentIndex:r,type:\"value\"});return a.value=((o=a.value)!==null&&o!==void 0?o:[]).concat([e]),{...t,options:n,tokens:u}},setStringValue:(t,e,r)=>{let o=t.options[t.options.length-1],a=t.options.slice(),n=t.tokens.concat({segmentIndex:r,type:\"value\"});return o.value=e,{...t,options:a,tokens:n}},inhibateOptions:t=>({...t,ignoreOptions:!0}),useHelp:(t,e,r,o)=>{let[,,a]=e.match(DT);return typeof a<\"u\"?{...t,options:[{name:\"-c\",value:String(o)},{name:\"-i\",value:a}]}:{...t,options:[{name:\"-c\",value:String(o)}]}},setError:(t,e,r,o)=>e===Hn.EndOfInput||e===Hn.EndOfPartialInput?{...t,errorMessage:`${o}.`}:{...t,errorMessage:`${o} (\"${e}\").`},setOptionArityError:(t,e)=>{let r=t.options[t.options.length-1];return{...t,errorMessage:`Not enough arguments to option ${r.name}.`}}},tl=Symbol(),_T=class{constructor(e,r){this.allOptionNames=new Map,this.arity={leading:[],trailing:[],extra:[],proxy:!1},this.options=[],this.paths=[],this.cliIndex=e,this.cliOpts=r}addPath(e){this.paths.push(e)}setArity({leading:e=this.arity.leading,trailing:r=this.arity.trailing,extra:o=this.arity.extra,proxy:a=this.arity.proxy}){Object.assign(this.arity,{leading:e,trailing:r,extra:o,proxy:a})}addPositional({name:e=\"arg\",required:r=!0}={}){if(!r&&this.arity.extra===tl)throw new Error(\"Optional parameters cannot be declared when using .rest() or .proxy()\");if(!r&&this.arity.trailing.length>0)throw new Error(\"Optional parameters cannot be declared after the required trailing positional arguments\");!r&&this.arity.extra!==tl?this.arity.extra.push(e):this.arity.extra!==tl&&this.arity.extra.length===0?this.arity.leading.push(e):this.arity.trailing.push(e)}addRest({name:e=\"arg\",required:r=0}={}){if(this.arity.extra===tl)throw new Error(\"Infinite lists cannot be declared multiple times in the same command\");if(this.arity.trailing.length>0)throw new Error(\"Infinite lists cannot be declared after the required trailing positional arguments\");for(let o=0;o<r;++o)this.addPositional({name:e});this.arity.extra=tl}addProxy({required:e=0}={}){this.addRest({required:e}),this.arity.proxy=!0}addOption({names:e,description:r,arity:o=0,hidden:a=!1,required:n=!1,allowBinding:u=!0}){if(!u&&o>1)throw new Error(\"The arity cannot be higher than 1 when the option only supports the --arg=value syntax\");if(!Number.isInteger(o))throw new Error(`The arity must be an integer, got ${o}`);if(o<0)throw new Error(`The arity must be positive, got ${o}`);let A=e.reduce((p,h)=>h.length>p.length?h:p,\"\");for(let p of e)this.allOptionNames.set(p,A);this.options.push({preferredName:A,nameSet:e,description:r,arity:o,hidden:a,required:n,allowBinding:u})}setContext(e){this.context=e}usage({detailed:e=!0,inlineOptions:r=!0}={}){let o=[this.cliOpts.binaryName],a=[];if(this.paths.length>0&&o.push(...this.paths[0]),e){for(let{preferredName:u,nameSet:A,arity:p,hidden:h,description:E,required:I}of this.options){if(h)continue;let v=[];for(let C=0;C<p;++C)v.push(` #${C}`);let x=`${A.join(\",\")}${v.join(\"\")}`;!r&&E?a.push({preferredName:u,nameSet:A,definition:x,description:E,required:I}):o.push(I?`<${x}>`:`[${x}]`)}o.push(...this.arity.leading.map(u=>`<${u}>`)),this.arity.extra===tl?o.push(\"...\"):o.push(...this.arity.extra.map(u=>`[${u}]`)),o.push(...this.arity.trailing.map(u=>`<${u}>`))}return{usage:o.join(\" \"),options:a}}compile(){if(typeof this.context>\"u\")throw new Error(\"Assertion failed: No context attached\");let e=yz(),r=cn.InitialNode,o=this.usage().usage,a=this.options.filter(A=>A.required).map(A=>A.nameSet);r=Mc(e,el()),Vo(e,cn.InitialNode,Hn.StartOfInput,r,[\"setCandidateState\",{candidateUsage:o,requiredOptions:a}]);let n=this.arity.proxy?\"always\":\"isNotOptionLike\",u=this.paths.length>0?this.paths:[[]];for(let A of u){let p=r;if(A.length>0){let v=Mc(e,el());wy(e,p,v),this.registerOptions(e,v),p=v}for(let v=0;v<A.length;++v){let x=Mc(e,el());Vo(e,p,A[v],x,\"pushPath\"),p=x}if(this.arity.leading.length>0||!this.arity.proxy){let v=Mc(e,el());Ss(e,p,\"isHelp\",v,[\"useHelp\",this.cliIndex]),Ss(e,v,\"always\",v,\"pushExtra\"),Vo(e,v,Hn.EndOfInput,cn.SuccessNode,[\"setSelectedIndex\",nd]),this.registerOptions(e,p)}this.arity.leading.length>0&&(Vo(e,p,Hn.EndOfInput,cn.ErrorNode,[\"setError\",\"Not enough positional arguments\"]),Vo(e,p,Hn.EndOfPartialInput,cn.SuccessNode,[\"setPartialIndex\",this.cliIndex]));let h=p;for(let v=0;v<this.arity.leading.length;++v){let x=Mc(e,el());(!this.arity.proxy||v+1!==this.arity.leading.length)&&this.registerOptions(e,x),(this.arity.trailing.length>0||v+1!==this.arity.leading.length)&&(Vo(e,x,Hn.EndOfInput,cn.ErrorNode,[\"setError\",\"Not enough positional arguments\"]),Vo(e,x,Hn.EndOfPartialInput,cn.SuccessNode,[\"setPartialIndex\",this.cliIndex])),Ss(e,h,\"isNotOptionLike\",x,\"pushPositional\"),h=x}let E=h;if(this.arity.extra===tl||this.arity.extra.length>0){let v=Mc(e,el());if(wy(e,h,v),this.arity.extra===tl){let x=Mc(e,el());this.arity.proxy||this.registerOptions(e,x),Ss(e,h,n,x,\"pushExtraNoLimits\"),Ss(e,x,n,x,\"pushExtraNoLimits\"),wy(e,x,v)}else for(let x=0;x<this.arity.extra.length;++x){let C=Mc(e,el());(!this.arity.proxy||x>0)&&this.registerOptions(e,C),Ss(e,E,n,C,\"pushExtra\"),wy(e,C,v),E=C}E=v}this.arity.trailing.length>0&&(Vo(e,E,Hn.EndOfInput,cn.ErrorNode,[\"setError\",\"Not enough positional arguments\"]),Vo(e,E,Hn.EndOfPartialInput,cn.SuccessNode,[\"setPartialIndex\",this.cliIndex]));let I=E;for(let v=0;v<this.arity.trailing.length;++v){let x=Mc(e,el());this.arity.proxy||this.registerOptions(e,x),v+1<this.arity.trailing.length&&(Vo(e,x,Hn.EndOfInput,cn.ErrorNode,[\"setError\",\"Not enough positional arguments\"]),Vo(e,x,Hn.EndOfPartialInput,cn.SuccessNode,[\"setPartialIndex\",this.cliIndex])),Ss(e,I,\"isNotOptionLike\",x,\"pushPositional\"),I=x}Ss(e,I,n,cn.ErrorNode,[\"setError\",\"Extraneous positional argument\"]),Vo(e,I,Hn.EndOfInput,cn.SuccessNode,[\"setSelectedIndex\",this.cliIndex]),Vo(e,I,Hn.EndOfPartialInput,cn.SuccessNode,[\"setSelectedIndex\",this.cliIndex])}return{machine:e,context:this.context}}registerOptions(e,r){Ss(e,r,[\"isOption\",\"--\"],r,\"inhibateOptions\"),Ss(e,r,[\"isBatchOption\",this.allOptionNames],r,[\"pushBatch\",this.allOptionNames]),Ss(e,r,[\"isBoundOption\",this.allOptionNames,this.options],r,\"pushBound\"),Ss(e,r,[\"isUnsupportedOption\",this.allOptionNames],cn.ErrorNode,[\"setError\",\"Unsupported option name\"]),Ss(e,r,[\"isInvalidOption\"],cn.ErrorNode,[\"setError\",\"Invalid option name\"]);for(let o of this.options)if(o.arity===0)for(let a of o.nameSet)Ss(e,r,[\"isOption\",a],r,[\"pushTrue\",o.preferredName]),a.startsWith(\"--\")&&!a.startsWith(\"--no-\")&&Ss(e,r,[\"isNegatedOption\",a],r,[\"pushFalse\",o.preferredName]);else{let a=Mc(e,el());for(let n of o.nameSet)Ss(e,r,[\"isOption\",n],a,[\"pushUndefined\",o.preferredName]);for(let n=0;n<o.arity;++n){let u=Mc(e,el());Vo(e,a,Hn.EndOfInput,cn.ErrorNode,\"setOptionArityError\"),Vo(e,a,Hn.EndOfPartialInput,cn.ErrorNode,\"setOptionArityError\"),Ss(e,a,\"isOptionLike\",cn.ErrorNode,\"setOptionArityError\");let A=o.arity===1?\"setStringValue\":\"pushStringValue\";Ss(e,a,\"isNotOptionLike\",u,A),a=u}wy(e,a,r)}}},Iy=class{constructor({binaryName:e=\"...\"}={}){this.builders=[],this.opts={binaryName:e}}static build(e,r={}){return new Iy(r).commands(e).compile()}getBuilderByIndex(e){if(!(e>=0&&e<this.builders.length))throw new Error(`Assertion failed: Out-of-bound command index (${e})`);return this.builders[e]}commands(e){for(let r of e)r(this.command());return this}command(){let e=new _T(this.builders.length,this.opts);return this.builders.push(e),e}compile(){let e=[],r=[];for(let a of this.builders){let{machine:n,context:u}=a.compile();e.push(n),r.push(u)}let o=qqe(e);return Gqe(o),{machine:o,contexts:r,process:(a,{partial:n}={})=>{let u=n?Hn.EndOfPartialInput:Hn.EndOfInput;return Wqe(o,a,{endToken:u})}}}}});function Iz(){return cP.default&&\"getColorDepth\"in cP.default.WriteStream.prototype?cP.default.WriteStream.prototype.getColorDepth():process.env.FORCE_COLOR===\"0\"?1:process.env.FORCE_COLOR===\"1\"||typeof process.stdout<\"u\"&&process.stdout.isTTY?8:1}function Bz(t){let e=wz;if(typeof e>\"u\"){if(t.stdout===process.stdout&&t.stderr===process.stderr)return null;let{AsyncLocalStorage:r}=ve(\"async_hooks\");e=wz=new r;let o=process.stdout._write;process.stdout._write=function(n,u,A){let p=e.getStore();return typeof p>\"u\"?o.call(this,n,u,A):p.stdout.write(n,u,A)};let a=process.stderr._write;process.stderr._write=function(n,u,A){let p=e.getStore();return typeof p>\"u\"?a.call(this,n,u,A):p.stderr.write(n,u,A)}}return r=>e.run(t,r)}var cP,wz,vz=Et(()=>{cP=$e(ve(\"tty\"),1)});var By,Dz=Et(()=>{Vp();By=class extends nt{constructor(e){super(),this.contexts=e,this.commands=[]}static from(e,r){let o=new By(r);o.path=e.path;for(let a of e.options)switch(a.name){case\"-c\":o.commands.push(Number(a.value));break;case\"-i\":o.index=Number(a.value);break}return o}async execute(){let e=this.commands;if(typeof this.index<\"u\"&&this.index>=0&&this.index<e.length&&(e=[e[this.index]]),e.length===0)this.context.stdout.write(this.cli.usage());else if(e.length===1)this.context.stdout.write(this.cli.usage(this.contexts[e[0]].commandClass,{detailed:!0}));else if(e.length>1){this.context.stdout.write(`Multiple commands match your selection:\n`),this.context.stdout.write(`\n`);let r=0;for(let o of this.commands)this.context.stdout.write(this.cli.usage(this.contexts[o].commandClass,{prefix:`${r++}. `.padStart(5)}));this.context.stdout.write(`\n`),this.context.stdout.write(`Run again with -h=<index> to see the longer details of any of those commands.\n`)}}}});async function bz(...t){let{resolvedOptions:e,resolvedCommandClasses:r,resolvedArgv:o,resolvedContext:a}=kz(t);return as.from(r,e).runExit(o,a)}async function xz(...t){let{resolvedOptions:e,resolvedCommandClasses:r,resolvedArgv:o,resolvedContext:a}=kz(t);return as.from(r,e).run(o,a)}function kz(t){let e,r,o,a;switch(typeof process<\"u\"&&typeof process.argv<\"u\"&&(o=process.argv.slice(2)),t.length){case 1:r=t[0];break;case 2:t[0]&&t[0].prototype instanceof nt||Array.isArray(t[0])?(r=t[0],Array.isArray(t[1])?o=t[1]:a=t[1]):(e=t[0],r=t[1]);break;case 3:Array.isArray(t[2])?(e=t[0],r=t[1],o=t[2]):t[0]&&t[0].prototype instanceof nt||Array.isArray(t[0])?(r=t[0],o=t[1],a=t[2]):(e=t[0],r=t[1],a=t[2]);break;default:e=t[0],r=t[1],o=t[2],a=t[3];break}if(typeof o>\"u\")throw new Error(\"The argv parameter must be provided when running Clipanion outside of a Node context\");return{resolvedOptions:e,resolvedCommandClasses:r,resolvedArgv:o,resolvedContext:a}}function Sz(t){return t()}var Pz,as,Qz=Et(()=>{$D();lP();kT();vz();Vp();Dz();Pz=Symbol(\"clipanion/errorCommand\");as=class{constructor({binaryLabel:e,binaryName:r=\"...\",binaryVersion:o,enableCapture:a=!1,enableColors:n}={}){this.registrations=new Map,this.builder=new Iy({binaryName:r}),this.binaryLabel=e,this.binaryName=r,this.binaryVersion=o,this.enableCapture=a,this.enableColors=n}static from(e,r={}){let o=new as(r),a=Array.isArray(e)?e:[e];for(let n of a)o.register(n);return o}register(e){var r;let o=new Map,a=new e;for(let p in a){let h=a[p];typeof h==\"object\"&&h!==null&&h[nt.isOption]&&o.set(p,h)}let n=this.builder.command(),u=n.cliIndex,A=(r=e.paths)!==null&&r!==void 0?r:a.paths;if(typeof A<\"u\")for(let p of A)n.addPath(p);this.registrations.set(e,{specs:o,builder:n,index:u});for(let[p,{definition:h}]of o.entries())h(n,p);n.setContext({commandClass:e})}process(e,r){let{input:o,context:a,partial:n}=typeof e==\"object\"&&Array.isArray(e)?{input:e,context:r}:e,{contexts:u,process:A}=this.builder.compile(),p=A(o,{partial:n}),h={...as.defaultContext,...a};switch(p.selectedIndex){case nd:{let E=By.from(p,u);return E.context=h,E.tokens=p.tokens,E}default:{let{commandClass:E}=u[p.selectedIndex],I=this.registrations.get(E);if(typeof I>\"u\")throw new Error(\"Assertion failed: Expected the command class to have been registered.\");let v=new E;v.context=h,v.tokens=p.tokens,v.path=p.path;try{for(let[x,{transformer:C}]of I.specs.entries())v[x]=C(I.builder,x,p,h);return v}catch(x){throw x[Pz]=v,x}}break}}async run(e,r){var o,a;let n,u={...as.defaultContext,...r},A=(o=this.enableColors)!==null&&o!==void 0?o:u.colorDepth>1;if(!Array.isArray(e))n=e;else try{n=this.process(e,u)}catch(E){return u.stdout.write(this.error(E,{colored:A})),1}if(n.help)return u.stdout.write(this.usage(n,{colored:A,detailed:!0})),0;n.context=u,n.cli={binaryLabel:this.binaryLabel,binaryName:this.binaryName,binaryVersion:this.binaryVersion,enableCapture:this.enableCapture,enableColors:this.enableColors,definitions:()=>this.definitions(),definition:E=>this.definition(E),error:(E,I)=>this.error(E,I),format:E=>this.format(E),process:(E,I)=>this.process(E,{...u,...I}),run:(E,I)=>this.run(E,{...u,...I}),usage:(E,I)=>this.usage(E,I)};let p=this.enableCapture&&(a=Bz(u))!==null&&a!==void 0?a:Sz,h;try{h=await p(()=>n.validateAndExecute().catch(E=>n.catch(E).then(()=>0)))}catch(E){return u.stdout.write(this.error(E,{colored:A,command:n})),1}return h}async runExit(e,r){process.exitCode=await this.run(e,r)}definition(e,{colored:r=!1}={}){if(!e.usage)return null;let{usage:o}=this.getUsageByRegistration(e,{detailed:!1}),{usage:a,options:n}=this.getUsageByRegistration(e,{detailed:!0,inlineOptions:!1}),u=typeof e.usage.category<\"u\"?Do(e.usage.category,{format:this.format(r),paragraphs:!1}):void 0,A=typeof e.usage.description<\"u\"?Do(e.usage.description,{format:this.format(r),paragraphs:!1}):void 0,p=typeof e.usage.details<\"u\"?Do(e.usage.details,{format:this.format(r),paragraphs:!0}):void 0,h=typeof e.usage.examples<\"u\"?e.usage.examples.map(([E,I])=>[Do(E,{format:this.format(r),paragraphs:!1}),I.replace(/\\$0/g,this.binaryName)]):void 0;return{path:o,usage:a,category:u,description:A,details:p,examples:h,options:n}}definitions({colored:e=!1}={}){let r=[];for(let o of this.registrations.keys()){let a=this.definition(o,{colored:e});!a||r.push(a)}return r}usage(e=null,{colored:r,detailed:o=!1,prefix:a=\"$ \"}={}){var n;if(e===null){for(let p of this.registrations.keys()){let h=p.paths,E=typeof p.usage<\"u\";if(!h||h.length===0||h.length===1&&h[0].length===0||((n=h?.some(x=>x.length===0))!==null&&n!==void 0?n:!1))if(e){e=null;break}else e=p;else if(E){e=null;continue}}e&&(o=!0)}let u=e!==null&&e instanceof nt?e.constructor:e,A=\"\";if(u)if(o){let{description:p=\"\",details:h=\"\",examples:E=[]}=u.usage||{};p!==\"\"&&(A+=Do(p,{format:this.format(r),paragraphs:!1}).replace(/^./,x=>x.toUpperCase()),A+=`\n`),(h!==\"\"||E.length>0)&&(A+=`${this.format(r).header(\"Usage\")}\n`,A+=`\n`);let{usage:I,options:v}=this.getUsageByRegistration(u,{inlineOptions:!1});if(A+=`${this.format(r).bold(a)}${I}\n`,v.length>0){A+=`\n`,A+=`${this.format(r).header(\"Options\")}\n`;let x=v.reduce((C,R)=>Math.max(C,R.definition.length),0);A+=`\n`;for(let{definition:C,description:R}of v)A+=`  ${this.format(r).bold(C.padEnd(x))}    ${Do(R,{format:this.format(r),paragraphs:!1})}`}if(h!==\"\"&&(A+=`\n`,A+=`${this.format(r).header(\"Details\")}\n`,A+=`\n`,A+=Do(h,{format:this.format(r),paragraphs:!0})),E.length>0){A+=`\n`,A+=`${this.format(r).header(\"Examples\")}\n`;for(let[x,C]of E)A+=`\n`,A+=Do(x,{format:this.format(r),paragraphs:!1}),A+=`${C.replace(/^/m,`  ${this.format(r).bold(a)}`).replace(/\\$0/g,this.binaryName)}\n`}}else{let{usage:p}=this.getUsageByRegistration(u);A+=`${this.format(r).bold(a)}${p}\n`}else{let p=new Map;for(let[v,{index:x}]of this.registrations.entries()){if(typeof v.usage>\"u\")continue;let C=typeof v.usage.category<\"u\"?Do(v.usage.category,{format:this.format(r),paragraphs:!1}):null,R=p.get(C);typeof R>\"u\"&&p.set(C,R=[]);let{usage:N}=this.getUsageByIndex(x);R.push({commandClass:v,usage:N})}let h=Array.from(p.keys()).sort((v,x)=>v===null?-1:x===null?1:v.localeCompare(x,\"en\",{usage:\"sort\",caseFirst:\"upper\"})),E=typeof this.binaryLabel<\"u\",I=typeof this.binaryVersion<\"u\";E||I?(E&&I?A+=`${this.format(r).header(`${this.binaryLabel} - ${this.binaryVersion}`)}\n\n`:E?A+=`${this.format(r).header(`${this.binaryLabel}`)}\n`:A+=`${this.format(r).header(`${this.binaryVersion}`)}\n`,A+=`  ${this.format(r).bold(a)}${this.binaryName} <command>\n`):A+=`${this.format(r).bold(a)}${this.binaryName} <command>\n`;for(let v of h){let x=p.get(v).slice().sort((R,N)=>R.usage.localeCompare(N.usage,\"en\",{usage:\"sort\",caseFirst:\"upper\"})),C=v!==null?v.trim():\"General commands\";A+=`\n`,A+=`${this.format(r).header(`${C}`)}\n`;for(let{commandClass:R,usage:N}of x){let U=R.usage.description||\"undocumented\";A+=`\n`,A+=`  ${this.format(r).bold(N)}\n`,A+=`    ${Do(U,{format:this.format(r),paragraphs:!1})}`}}A+=`\n`,A+=Do(\"You can also print more details about any of these commands by calling them with the `-h,--help` flag right after the command name.\",{format:this.format(r),paragraphs:!0})}return A}error(e,r){var o,{colored:a,command:n=(o=e[Pz])!==null&&o!==void 0?o:null}=r===void 0?{}:r;(!e||typeof e!=\"object\"||!(\"stack\"in e))&&(e=new Error(`Execution failed with a non-error rejection (rejected value: ${JSON.stringify(e)})`));let u=\"\",A=e.name.replace(/([a-z])([A-Z])/g,\"$1 $2\");A===\"Error\"&&(A=\"Internal Error\"),u+=`${this.format(a).error(A)}: ${e.message}\n`;let p=e.clipanion;return typeof p<\"u\"?p.type===\"usage\"&&(u+=`\n`,u+=this.usage(n)):e.stack&&(u+=`${e.stack.replace(/^.*\\n/,\"\")}\n`),u}format(e){var r;return((r=e??this.enableColors)!==null&&r!==void 0?r:as.defaultContext.colorDepth>1)?uz:Az}getUsageByRegistration(e,r){let o=this.registrations.get(e);if(typeof o>\"u\")throw new Error(\"Assertion failed: Unregistered command\");return this.getUsageByIndex(o.index,r)}getUsageByIndex(e,r){return this.builder.getBuilderByIndex(e).usage(r)}};as.defaultContext={env:process.env,stdin:process.stdin,stdout:process.stdout,stderr:process.stderr,colorDepth:Iz()}});var uI,Fz=Et(()=>{Vp();uI=class extends nt{async execute(){this.context.stdout.write(`${JSON.stringify(this.cli.definitions(),null,2)}\n`)}};uI.paths=[[\"--clipanion=definitions\"]]});var AI,Rz=Et(()=>{Vp();AI=class extends nt{async execute(){this.context.stdout.write(this.cli.usage())}};AI.paths=[[\"-h\"],[\"--help\"]]});function uP(t={}){return Ko({definition(e,r){var o;e.addProxy({name:(o=t.name)!==null&&o!==void 0?o:r,required:t.required})},transformer(e,r,o){return o.positionals.map(({value:a})=>a)}})}var HT=Et(()=>{Ef()});var fI,Tz=Et(()=>{Vp();HT();fI=class extends nt{constructor(){super(...arguments),this.args=uP()}async execute(){this.context.stdout.write(`${JSON.stringify(this.cli.process(this.args).tokens,null,2)}\n`)}};fI.paths=[[\"--clipanion=tokens\"]]});var pI,Lz=Et(()=>{Vp();pI=class extends nt{async execute(){var e;this.context.stdout.write(`${(e=this.cli.binaryVersion)!==null&&e!==void 0?e:\"<unknown>\"}\n`)}};pI.paths=[[\"-v\"],[\"--version\"]]});var qT={};zt(qT,{DefinitionsCommand:()=>uI,HelpCommand:()=>AI,TokensCommand:()=>fI,VersionCommand:()=>pI});var Nz=Et(()=>{Fz();Rz();Tz();Lz()});function Oz(t,e,r){let[o,a]=ju(e,r??{}),{arity:n=1}=a,u=t.split(\",\"),A=new Set(u);return Ko({definition(p){p.addOption({names:u,arity:n,hidden:a?.hidden,description:a?.description,required:a.required})},transformer(p,h,E){let I,v=typeof o<\"u\"?[...o]:void 0;for(let{name:x,value:C}of E.options)!A.has(x)||(I=x,v=v??[],v.push(C));return typeof v<\"u\"?id(I??h,v,a.validator):v}})}var Mz=Et(()=>{Ef()});function Uz(t,e,r){let[o,a]=ju(e,r??{}),n=t.split(\",\"),u=new Set(n);return Ko({definition(A){A.addOption({names:n,allowBinding:!1,arity:0,hidden:a.hidden,description:a.description,required:a.required})},transformer(A,p,h){let E=o;for(let{name:I,value:v}of h.options)!u.has(I)||(E=v);return E}})}var _z=Et(()=>{Ef()});function Hz(t,e,r){let[o,a]=ju(e,r??{}),n=t.split(\",\"),u=new Set(n);return Ko({definition(A){A.addOption({names:n,allowBinding:!1,arity:0,hidden:a.hidden,description:a.description,required:a.required})},transformer(A,p,h){let E=o;for(let{name:I,value:v}of h.options)!u.has(I)||(E??(E=0),v?E+=1:E=0);return E}})}var qz=Et(()=>{Ef()});function Gz(t={}){return Ko({definition(e,r){var o;e.addRest({name:(o=t.name)!==null&&o!==void 0?o:r,required:t.required})},transformer(e,r,o){let a=u=>{let A=o.positionals[u];return A.extra===tl||A.extra===!1&&u<e.arity.leading.length},n=0;for(;n<o.positionals.length&&a(n);)n+=1;return o.positionals.splice(0,n).map(({value:u})=>u)}})}var jz=Et(()=>{lP();Ef()});function Zqe(t,e,r){let[o,a]=ju(e,r??{}),{arity:n=1}=a,u=t.split(\",\"),A=new Set(u);return Ko({definition(p){p.addOption({names:u,arity:a.tolerateBoolean?0:n,hidden:a.hidden,description:a.description,required:a.required})},transformer(p,h,E,I){let v,x=o;typeof a.env<\"u\"&&I.env[a.env]&&(v=a.env,x=I.env[a.env]);for(let{name:C,value:R}of E.options)!A.has(C)||(v=C,x=R);return typeof x==\"string\"?id(v??h,x,a.validator):x}})}function $qe(t={}){let{required:e=!0}=t;return Ko({definition(r,o){var a;r.addPositional({name:(a=t.name)!==null&&a!==void 0?a:o,required:t.required})},transformer(r,o,a){var n;for(let u=0;u<a.positionals.length;++u){if(a.positionals[u].extra===tl||e&&a.positionals[u].extra===!0||!e&&a.positionals[u].extra===!1)continue;let[A]=a.positionals.splice(u,1);return id((n=t.name)!==null&&n!==void 0?n:o,A.value,t.validator)}}})}function Yz(t,...e){return typeof t==\"string\"?Zqe(t,...e):$qe(t)}var Wz=Et(()=>{lP();Ef()});var ge={};zt(ge,{Array:()=>Oz,Boolean:()=>Uz,Counter:()=>Hz,Proxy:()=>uP,Rest:()=>Gz,String:()=>Yz,applyValidator:()=>id,cleanValidationError:()=>rP,formatError:()=>iI,isOptionSymbol:()=>nI,makeCommandOption:()=>Ko,rerouteArguments:()=>ju});var Kz=Et(()=>{Ef();HT();Mz();_z();qz();jz();Wz()});var hI={};zt(hI,{Builtins:()=>qT,Cli:()=>as,Command:()=>nt,Option:()=>ge,UsageError:()=>it,formatMarkdownish:()=>Do,run:()=>xz,runExit:()=>bz});var qt=Et(()=>{tP();kT();Vp();Qz();Nz();Kz()});var zz=_((bkt,eGe)=>{eGe.exports={name:\"dotenv\",version:\"16.3.1\",description:\"Loads environment variables from .env file\",main:\"lib/main.js\",types:\"lib/main.d.ts\",exports:{\".\":{types:\"./lib/main.d.ts\",require:\"./lib/main.js\",default:\"./lib/main.js\"},\"./config\":\"./config.js\",\"./config.js\":\"./config.js\",\"./lib/env-options\":\"./lib/env-options.js\",\"./lib/env-options.js\":\"./lib/env-options.js\",\"./lib/cli-options\":\"./lib/cli-options.js\",\"./lib/cli-options.js\":\"./lib/cli-options.js\",\"./package.json\":\"./package.json\"},scripts:{\"dts-check\":\"tsc --project tests/types/tsconfig.json\",lint:\"standard\",\"lint-readme\":\"standard-markdown\",pretest:\"npm run lint && npm run dts-check\",test:\"tap tests/*.js --100 -Rspec\",prerelease:\"npm test\",release:\"standard-version\"},repository:{type:\"git\",url:\"git://github.com/motdotla/dotenv.git\"},funding:\"https://github.com/motdotla/dotenv?sponsor=1\",keywords:[\"dotenv\",\"env\",\".env\",\"environment\",\"variables\",\"config\",\"settings\"],readmeFilename:\"README.md\",license:\"BSD-2-Clause\",devDependencies:{\"@definitelytyped/dtslint\":\"^0.0.133\",\"@types/node\":\"^18.11.3\",decache:\"^4.6.1\",sinon:\"^14.0.1\",standard:\"^17.0.0\",\"standard-markdown\":\"^7.1.0\",\"standard-version\":\"^9.5.0\",tap:\"^16.3.0\",tar:\"^6.1.11\",typescript:\"^4.8.4\"},engines:{node:\">=12\"},browser:{fs:!1}}});var Zz=_((xkt,Cf)=>{var Vz=ve(\"fs\"),jT=ve(\"path\"),tGe=ve(\"os\"),rGe=ve(\"crypto\"),nGe=zz(),YT=nGe.version,iGe=/(?:^|^)\\s*(?:export\\s+)?([\\w.-]+)(?:\\s*=\\s*?|:\\s+?)(\\s*'(?:\\\\'|[^'])*'|\\s*\"(?:\\\\\"|[^\"])*\"|\\s*`(?:\\\\`|[^`])*`|[^#\\r\\n]+)?\\s*(?:#.*)?(?:$|$)/mg;function sGe(t){let e={},r=t.toString();r=r.replace(/\\r\\n?/mg,`\n`);let o;for(;(o=iGe.exec(r))!=null;){let a=o[1],n=o[2]||\"\";n=n.trim();let u=n[0];n=n.replace(/^(['\"`])([\\s\\S]*)\\1$/mg,\"$2\"),u==='\"'&&(n=n.replace(/\\\\n/g,`\n`),n=n.replace(/\\\\r/g,\"\\r\")),e[a]=n}return e}function oGe(t){let e=Xz(t),r=bs.configDotenv({path:e});if(!r.parsed)throw new Error(`MISSING_DATA: Cannot parse ${e} for an unknown reason`);let o=Jz(t).split(\",\"),a=o.length,n;for(let u=0;u<a;u++)try{let A=o[u].trim(),p=cGe(r,A);n=bs.decrypt(p.ciphertext,p.key);break}catch(A){if(u+1>=a)throw A}return bs.parse(n)}function aGe(t){console.log(`[dotenv@${YT}][INFO] ${t}`)}function lGe(t){console.log(`[dotenv@${YT}][WARN] ${t}`)}function GT(t){console.log(`[dotenv@${YT}][DEBUG] ${t}`)}function Jz(t){return t&&t.DOTENV_KEY&&t.DOTENV_KEY.length>0?t.DOTENV_KEY:process.env.DOTENV_KEY&&process.env.DOTENV_KEY.length>0?process.env.DOTENV_KEY:\"\"}function cGe(t,e){let r;try{r=new URL(e)}catch(A){throw A.code===\"ERR_INVALID_URL\"?new Error(\"INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:key_1234@dotenv.org/vault/.env.vault?environment=development\"):A}let o=r.password;if(!o)throw new Error(\"INVALID_DOTENV_KEY: Missing key part\");let a=r.searchParams.get(\"environment\");if(!a)throw new Error(\"INVALID_DOTENV_KEY: Missing environment part\");let n=`DOTENV_VAULT_${a.toUpperCase()}`,u=t.parsed[n];if(!u)throw new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${n} in your .env.vault file.`);return{ciphertext:u,key:o}}function Xz(t){let e=jT.resolve(process.cwd(),\".env\");return t&&t.path&&t.path.length>0&&(e=t.path),e.endsWith(\".vault\")?e:`${e}.vault`}function uGe(t){return t[0]===\"~\"?jT.join(tGe.homedir(),t.slice(1)):t}function AGe(t){aGe(\"Loading env from encrypted .env.vault\");let e=bs._parseVault(t),r=process.env;return t&&t.processEnv!=null&&(r=t.processEnv),bs.populate(r,e,t),{parsed:e}}function fGe(t){let e=jT.resolve(process.cwd(),\".env\"),r=\"utf8\",o=Boolean(t&&t.debug);t&&(t.path!=null&&(e=uGe(t.path)),t.encoding!=null&&(r=t.encoding));try{let a=bs.parse(Vz.readFileSync(e,{encoding:r})),n=process.env;return t&&t.processEnv!=null&&(n=t.processEnv),bs.populate(n,a,t),{parsed:a}}catch(a){return o&&GT(`Failed to load ${e} ${a.message}`),{error:a}}}function pGe(t){let e=Xz(t);return Jz(t).length===0?bs.configDotenv(t):Vz.existsSync(e)?bs._configVault(t):(lGe(`You set DOTENV_KEY but you are missing a .env.vault file at ${e}. Did you forget to build it?`),bs.configDotenv(t))}function hGe(t,e){let r=Buffer.from(e.slice(-64),\"hex\"),o=Buffer.from(t,\"base64\"),a=o.slice(0,12),n=o.slice(-16);o=o.slice(12,-16);try{let u=rGe.createDecipheriv(\"aes-256-gcm\",r,a);return u.setAuthTag(n),`${u.update(o)}${u.final()}`}catch(u){let A=u instanceof RangeError,p=u.message===\"Invalid key length\",h=u.message===\"Unsupported state or unable to authenticate data\";if(A||p){let E=\"INVALID_DOTENV_KEY: It must be 64 characters long (or more)\";throw new Error(E)}else if(h){let E=\"DECRYPTION_FAILED: Please check your DOTENV_KEY\";throw new Error(E)}else throw console.error(\"Error: \",u.code),console.error(\"Error: \",u.message),u}}function gGe(t,e,r={}){let o=Boolean(r&&r.debug),a=Boolean(r&&r.override);if(typeof e!=\"object\")throw new Error(\"OBJECT_REQUIRED: Please check the processEnv argument being passed to populate\");for(let n of Object.keys(e))Object.prototype.hasOwnProperty.call(t,n)?(a===!0&&(t[n]=e[n]),o&&GT(a===!0?`\"${n}\" is already defined and WAS overwritten`:`\"${n}\" is already defined and was NOT overwritten`)):t[n]=e[n]}var bs={configDotenv:fGe,_configVault:AGe,_parseVault:oGe,config:pGe,decrypt:hGe,parse:sGe,populate:gGe};Cf.exports.configDotenv=bs.configDotenv;Cf.exports._configVault=bs._configVault;Cf.exports._parseVault=bs._parseVault;Cf.exports.config=bs.config;Cf.exports.decrypt=bs.decrypt;Cf.exports.parse=bs.parse;Cf.exports.populate=bs.populate;Cf.exports=bs});var eV=_((kkt,$z)=>{\"use strict\";$z.exports=(t,...e)=>new Promise(r=>{r(t(...e))})});var sd=_((Qkt,WT)=>{\"use strict\";var dGe=eV(),tV=t=>{if(t<1)throw new TypeError(\"Expected `concurrency` to be a number from 1 and up\");let e=[],r=0,o=()=>{r--,e.length>0&&e.shift()()},a=(A,p,...h)=>{r++;let E=dGe(A,...h);p(E),E.then(o,o)},n=(A,p,...h)=>{r<t?a(A,p,...h):e.push(a.bind(null,A,p,...h))},u=(A,...p)=>new Promise(h=>n(A,h,...p));return Object.defineProperties(u,{activeCount:{get:()=>r},pendingCount:{get:()=>e.length}}),u};WT.exports=tV;WT.exports.default=tV});function Ku(t){return`YN${t.toString(10).padStart(4,\"0\")}`}function AP(t){let e=Number(t.slice(2));if(typeof wr[e]>\"u\")throw new Error(`Unknown message name: \"${t}\"`);return e}var wr,fP=Et(()=>{wr=(Oe=>(Oe[Oe.UNNAMED=0]=\"UNNAMED\",Oe[Oe.EXCEPTION=1]=\"EXCEPTION\",Oe[Oe.MISSING_PEER_DEPENDENCY=2]=\"MISSING_PEER_DEPENDENCY\",Oe[Oe.CYCLIC_DEPENDENCIES=3]=\"CYCLIC_DEPENDENCIES\",Oe[Oe.DISABLED_BUILD_SCRIPTS=4]=\"DISABLED_BUILD_SCRIPTS\",Oe[Oe.BUILD_DISABLED=5]=\"BUILD_DISABLED\",Oe[Oe.SOFT_LINK_BUILD=6]=\"SOFT_LINK_BUILD\",Oe[Oe.MUST_BUILD=7]=\"MUST_BUILD\",Oe[Oe.MUST_REBUILD=8]=\"MUST_REBUILD\",Oe[Oe.BUILD_FAILED=9]=\"BUILD_FAILED\",Oe[Oe.RESOLVER_NOT_FOUND=10]=\"RESOLVER_NOT_FOUND\",Oe[Oe.FETCHER_NOT_FOUND=11]=\"FETCHER_NOT_FOUND\",Oe[Oe.LINKER_NOT_FOUND=12]=\"LINKER_NOT_FOUND\",Oe[Oe.FETCH_NOT_CACHED=13]=\"FETCH_NOT_CACHED\",Oe[Oe.YARN_IMPORT_FAILED=14]=\"YARN_IMPORT_FAILED\",Oe[Oe.REMOTE_INVALID=15]=\"REMOTE_INVALID\",Oe[Oe.REMOTE_NOT_FOUND=16]=\"REMOTE_NOT_FOUND\",Oe[Oe.RESOLUTION_PACK=17]=\"RESOLUTION_PACK\",Oe[Oe.CACHE_CHECKSUM_MISMATCH=18]=\"CACHE_CHECKSUM_MISMATCH\",Oe[Oe.UNUSED_CACHE_ENTRY=19]=\"UNUSED_CACHE_ENTRY\",Oe[Oe.MISSING_LOCKFILE_ENTRY=20]=\"MISSING_LOCKFILE_ENTRY\",Oe[Oe.WORKSPACE_NOT_FOUND=21]=\"WORKSPACE_NOT_FOUND\",Oe[Oe.TOO_MANY_MATCHING_WORKSPACES=22]=\"TOO_MANY_MATCHING_WORKSPACES\",Oe[Oe.CONSTRAINTS_MISSING_DEPENDENCY=23]=\"CONSTRAINTS_MISSING_DEPENDENCY\",Oe[Oe.CONSTRAINTS_INCOMPATIBLE_DEPENDENCY=24]=\"CONSTRAINTS_INCOMPATIBLE_DEPENDENCY\",Oe[Oe.CONSTRAINTS_EXTRANEOUS_DEPENDENCY=25]=\"CONSTRAINTS_EXTRANEOUS_DEPENDENCY\",Oe[Oe.CONSTRAINTS_INVALID_DEPENDENCY=26]=\"CONSTRAINTS_INVALID_DEPENDENCY\",Oe[Oe.CANT_SUGGEST_RESOLUTIONS=27]=\"CANT_SUGGEST_RESOLUTIONS\",Oe[Oe.FROZEN_LOCKFILE_EXCEPTION=28]=\"FROZEN_LOCKFILE_EXCEPTION\",Oe[Oe.CROSS_DRIVE_VIRTUAL_LOCAL=29]=\"CROSS_DRIVE_VIRTUAL_LOCAL\",Oe[Oe.FETCH_FAILED=30]=\"FETCH_FAILED\",Oe[Oe.DANGEROUS_NODE_MODULES=31]=\"DANGEROUS_NODE_MODULES\",Oe[Oe.NODE_GYP_INJECTED=32]=\"NODE_GYP_INJECTED\",Oe[Oe.AUTHENTICATION_NOT_FOUND=33]=\"AUTHENTICATION_NOT_FOUND\",Oe[Oe.INVALID_CONFIGURATION_KEY=34]=\"INVALID_CONFIGURATION_KEY\",Oe[Oe.NETWORK_ERROR=35]=\"NETWORK_ERROR\",Oe[Oe.LIFECYCLE_SCRIPT=36]=\"LIFECYCLE_SCRIPT\",Oe[Oe.CONSTRAINTS_MISSING_FIELD=37]=\"CONSTRAINTS_MISSING_FIELD\",Oe[Oe.CONSTRAINTS_INCOMPATIBLE_FIELD=38]=\"CONSTRAINTS_INCOMPATIBLE_FIELD\",Oe[Oe.CONSTRAINTS_EXTRANEOUS_FIELD=39]=\"CONSTRAINTS_EXTRANEOUS_FIELD\",Oe[Oe.CONSTRAINTS_INVALID_FIELD=40]=\"CONSTRAINTS_INVALID_FIELD\",Oe[Oe.AUTHENTICATION_INVALID=41]=\"AUTHENTICATION_INVALID\",Oe[Oe.PROLOG_UNKNOWN_ERROR=42]=\"PROLOG_UNKNOWN_ERROR\",Oe[Oe.PROLOG_SYNTAX_ERROR=43]=\"PROLOG_SYNTAX_ERROR\",Oe[Oe.PROLOG_EXISTENCE_ERROR=44]=\"PROLOG_EXISTENCE_ERROR\",Oe[Oe.STACK_OVERFLOW_RESOLUTION=45]=\"STACK_OVERFLOW_RESOLUTION\",Oe[Oe.AUTOMERGE_FAILED_TO_PARSE=46]=\"AUTOMERGE_FAILED_TO_PARSE\",Oe[Oe.AUTOMERGE_IMMUTABLE=47]=\"AUTOMERGE_IMMUTABLE\",Oe[Oe.AUTOMERGE_SUCCESS=48]=\"AUTOMERGE_SUCCESS\",Oe[Oe.AUTOMERGE_REQUIRED=49]=\"AUTOMERGE_REQUIRED\",Oe[Oe.DEPRECATED_CLI_SETTINGS=50]=\"DEPRECATED_CLI_SETTINGS\",Oe[Oe.PLUGIN_NAME_NOT_FOUND=51]=\"PLUGIN_NAME_NOT_FOUND\",Oe[Oe.INVALID_PLUGIN_REFERENCE=52]=\"INVALID_PLUGIN_REFERENCE\",Oe[Oe.CONSTRAINTS_AMBIGUITY=53]=\"CONSTRAINTS_AMBIGUITY\",Oe[Oe.CACHE_OUTSIDE_PROJECT=54]=\"CACHE_OUTSIDE_PROJECT\",Oe[Oe.IMMUTABLE_INSTALL=55]=\"IMMUTABLE_INSTALL\",Oe[Oe.IMMUTABLE_CACHE=56]=\"IMMUTABLE_CACHE\",Oe[Oe.INVALID_MANIFEST=57]=\"INVALID_MANIFEST\",Oe[Oe.PACKAGE_PREPARATION_FAILED=58]=\"PACKAGE_PREPARATION_FAILED\",Oe[Oe.INVALID_RANGE_PEER_DEPENDENCY=59]=\"INVALID_RANGE_PEER_DEPENDENCY\",Oe[Oe.INCOMPATIBLE_PEER_DEPENDENCY=60]=\"INCOMPATIBLE_PEER_DEPENDENCY\",Oe[Oe.DEPRECATED_PACKAGE=61]=\"DEPRECATED_PACKAGE\",Oe[Oe.INCOMPATIBLE_OS=62]=\"INCOMPATIBLE_OS\",Oe[Oe.INCOMPATIBLE_CPU=63]=\"INCOMPATIBLE_CPU\",Oe[Oe.FROZEN_ARTIFACT_EXCEPTION=64]=\"FROZEN_ARTIFACT_EXCEPTION\",Oe[Oe.TELEMETRY_NOTICE=65]=\"TELEMETRY_NOTICE\",Oe[Oe.PATCH_HUNK_FAILED=66]=\"PATCH_HUNK_FAILED\",Oe[Oe.INVALID_CONFIGURATION_VALUE=67]=\"INVALID_CONFIGURATION_VALUE\",Oe[Oe.UNUSED_PACKAGE_EXTENSION=68]=\"UNUSED_PACKAGE_EXTENSION\",Oe[Oe.REDUNDANT_PACKAGE_EXTENSION=69]=\"REDUNDANT_PACKAGE_EXTENSION\",Oe[Oe.AUTO_NM_SUCCESS=70]=\"AUTO_NM_SUCCESS\",Oe[Oe.NM_CANT_INSTALL_EXTERNAL_SOFT_LINK=71]=\"NM_CANT_INSTALL_EXTERNAL_SOFT_LINK\",Oe[Oe.NM_PRESERVE_SYMLINKS_REQUIRED=72]=\"NM_PRESERVE_SYMLINKS_REQUIRED\",Oe[Oe.UPDATE_LOCKFILE_ONLY_SKIP_LINK=73]=\"UPDATE_LOCKFILE_ONLY_SKIP_LINK\",Oe[Oe.NM_HARDLINKS_MODE_DOWNGRADED=74]=\"NM_HARDLINKS_MODE_DOWNGRADED\",Oe[Oe.PROLOG_INSTANTIATION_ERROR=75]=\"PROLOG_INSTANTIATION_ERROR\",Oe[Oe.INCOMPATIBLE_ARCHITECTURE=76]=\"INCOMPATIBLE_ARCHITECTURE\",Oe[Oe.GHOST_ARCHITECTURE=77]=\"GHOST_ARCHITECTURE\",Oe[Oe.RESOLUTION_MISMATCH=78]=\"RESOLUTION_MISMATCH\",Oe[Oe.PROLOG_LIMIT_EXCEEDED=79]=\"PROLOG_LIMIT_EXCEEDED\",Oe[Oe.NETWORK_DISABLED=80]=\"NETWORK_DISABLED\",Oe[Oe.NETWORK_UNSAFE_HTTP=81]=\"NETWORK_UNSAFE_HTTP\",Oe[Oe.RESOLUTION_FAILED=82]=\"RESOLUTION_FAILED\",Oe[Oe.AUTOMERGE_GIT_ERROR=83]=\"AUTOMERGE_GIT_ERROR\",Oe[Oe.CONSTRAINTS_CHECK_FAILED=84]=\"CONSTRAINTS_CHECK_FAILED\",Oe[Oe.UPDATED_RESOLUTION_RECORD=85]=\"UPDATED_RESOLUTION_RECORD\",Oe[Oe.EXPLAIN_PEER_DEPENDENCIES_CTA=86]=\"EXPLAIN_PEER_DEPENDENCIES_CTA\",Oe[Oe.MIGRATION_SUCCESS=87]=\"MIGRATION_SUCCESS\",Oe[Oe.VERSION_NOTICE=88]=\"VERSION_NOTICE\",Oe[Oe.TIPS_NOTICE=89]=\"TIPS_NOTICE\",Oe[Oe.OFFLINE_MODE_ENABLED=90]=\"OFFLINE_MODE_ENABLED\",Oe))(wr||{})});var gI=_((Rkt,rV)=>{var mGe=\"2.0.0\",yGe=Number.MAX_SAFE_INTEGER||9007199254740991,EGe=16,CGe=256-6,wGe=[\"major\",\"premajor\",\"minor\",\"preminor\",\"patch\",\"prepatch\",\"prerelease\"];rV.exports={MAX_LENGTH:256,MAX_SAFE_COMPONENT_LENGTH:EGe,MAX_SAFE_BUILD_LENGTH:CGe,MAX_SAFE_INTEGER:yGe,RELEASE_TYPES:wGe,SEMVER_SPEC_VERSION:mGe,FLAG_INCLUDE_PRERELEASE:1,FLAG_LOOSE:2}});var dI=_((Tkt,nV)=>{var IGe=typeof process==\"object\"&&process.env&&process.env.NODE_DEBUG&&/\\bsemver\\b/i.test(process.env.NODE_DEBUG)?(...t)=>console.error(\"SEMVER\",...t):()=>{};nV.exports=IGe});var vy=_((wf,iV)=>{var{MAX_SAFE_COMPONENT_LENGTH:KT,MAX_SAFE_BUILD_LENGTH:BGe,MAX_LENGTH:vGe}=gI(),DGe=dI();wf=iV.exports={};var PGe=wf.re=[],SGe=wf.safeRe=[],lr=wf.src=[],cr=wf.t={},bGe=0,zT=\"[a-zA-Z0-9-]\",xGe=[[\"\\\\s\",1],[\"\\\\d\",vGe],[zT,BGe]],kGe=t=>{for(let[e,r]of xGe)t=t.split(`${e}*`).join(`${e}{0,${r}}`).split(`${e}+`).join(`${e}{1,${r}}`);return t},Vr=(t,e,r)=>{let o=kGe(e),a=bGe++;DGe(t,a,e),cr[t]=a,lr[a]=e,PGe[a]=new RegExp(e,r?\"g\":void 0),SGe[a]=new RegExp(o,r?\"g\":void 0)};Vr(\"NUMERICIDENTIFIER\",\"0|[1-9]\\\\d*\");Vr(\"NUMERICIDENTIFIERLOOSE\",\"\\\\d+\");Vr(\"NONNUMERICIDENTIFIER\",`\\\\d*[a-zA-Z-]${zT}*`);Vr(\"MAINVERSION\",`(${lr[cr.NUMERICIDENTIFIER]})\\\\.(${lr[cr.NUMERICIDENTIFIER]})\\\\.(${lr[cr.NUMERICIDENTIFIER]})`);Vr(\"MAINVERSIONLOOSE\",`(${lr[cr.NUMERICIDENTIFIERLOOSE]})\\\\.(${lr[cr.NUMERICIDENTIFIERLOOSE]})\\\\.(${lr[cr.NUMERICIDENTIFIERLOOSE]})`);Vr(\"PRERELEASEIDENTIFIER\",`(?:${lr[cr.NUMERICIDENTIFIER]}|${lr[cr.NONNUMERICIDENTIFIER]})`);Vr(\"PRERELEASEIDENTIFIERLOOSE\",`(?:${lr[cr.NUMERICIDENTIFIERLOOSE]}|${lr[cr.NONNUMERICIDENTIFIER]})`);Vr(\"PRERELEASE\",`(?:-(${lr[cr.PRERELEASEIDENTIFIER]}(?:\\\\.${lr[cr.PRERELEASEIDENTIFIER]})*))`);Vr(\"PRERELEASELOOSE\",`(?:-?(${lr[cr.PRERELEASEIDENTIFIERLOOSE]}(?:\\\\.${lr[cr.PRERELEASEIDENTIFIERLOOSE]})*))`);Vr(\"BUILDIDENTIFIER\",`${zT}+`);Vr(\"BUILD\",`(?:\\\\+(${lr[cr.BUILDIDENTIFIER]}(?:\\\\.${lr[cr.BUILDIDENTIFIER]})*))`);Vr(\"FULLPLAIN\",`v?${lr[cr.MAINVERSION]}${lr[cr.PRERELEASE]}?${lr[cr.BUILD]}?`);Vr(\"FULL\",`^${lr[cr.FULLPLAIN]}$`);Vr(\"LOOSEPLAIN\",`[v=\\\\s]*${lr[cr.MAINVERSIONLOOSE]}${lr[cr.PRERELEASELOOSE]}?${lr[cr.BUILD]}?`);Vr(\"LOOSE\",`^${lr[cr.LOOSEPLAIN]}$`);Vr(\"GTLT\",\"((?:<|>)?=?)\");Vr(\"XRANGEIDENTIFIERLOOSE\",`${lr[cr.NUMERICIDENTIFIERLOOSE]}|x|X|\\\\*`);Vr(\"XRANGEIDENTIFIER\",`${lr[cr.NUMERICIDENTIFIER]}|x|X|\\\\*`);Vr(\"XRANGEPLAIN\",`[v=\\\\s]*(${lr[cr.XRANGEIDENTIFIER]})(?:\\\\.(${lr[cr.XRANGEIDENTIFIER]})(?:\\\\.(${lr[cr.XRANGEIDENTIFIER]})(?:${lr[cr.PRERELEASE]})?${lr[cr.BUILD]}?)?)?`);Vr(\"XRANGEPLAINLOOSE\",`[v=\\\\s]*(${lr[cr.XRANGEIDENTIFIERLOOSE]})(?:\\\\.(${lr[cr.XRANGEIDENTIFIERLOOSE]})(?:\\\\.(${lr[cr.XRANGEIDENTIFIERLOOSE]})(?:${lr[cr.PRERELEASELOOSE]})?${lr[cr.BUILD]}?)?)?`);Vr(\"XRANGE\",`^${lr[cr.GTLT]}\\\\s*${lr[cr.XRANGEPLAIN]}$`);Vr(\"XRANGELOOSE\",`^${lr[cr.GTLT]}\\\\s*${lr[cr.XRANGEPLAINLOOSE]}$`);Vr(\"COERCE\",`(^|[^\\\\d])(\\\\d{1,${KT}})(?:\\\\.(\\\\d{1,${KT}}))?(?:\\\\.(\\\\d{1,${KT}}))?(?:$|[^\\\\d])`);Vr(\"COERCERTL\",lr[cr.COERCE],!0);Vr(\"LONETILDE\",\"(?:~>?)\");Vr(\"TILDETRIM\",`(\\\\s*)${lr[cr.LONETILDE]}\\\\s+`,!0);wf.tildeTrimReplace=\"$1~\";Vr(\"TILDE\",`^${lr[cr.LONETILDE]}${lr[cr.XRANGEPLAIN]}$`);Vr(\"TILDELOOSE\",`^${lr[cr.LONETILDE]}${lr[cr.XRANGEPLAINLOOSE]}$`);Vr(\"LONECARET\",\"(?:\\\\^)\");Vr(\"CARETTRIM\",`(\\\\s*)${lr[cr.LONECARET]}\\\\s+`,!0);wf.caretTrimReplace=\"$1^\";Vr(\"CARET\",`^${lr[cr.LONECARET]}${lr[cr.XRANGEPLAIN]}$`);Vr(\"CARETLOOSE\",`^${lr[cr.LONECARET]}${lr[cr.XRANGEPLAINLOOSE]}$`);Vr(\"COMPARATORLOOSE\",`^${lr[cr.GTLT]}\\\\s*(${lr[cr.LOOSEPLAIN]})$|^$`);Vr(\"COMPARATOR\",`^${lr[cr.GTLT]}\\\\s*(${lr[cr.FULLPLAIN]})$|^$`);Vr(\"COMPARATORTRIM\",`(\\\\s*)${lr[cr.GTLT]}\\\\s*(${lr[cr.LOOSEPLAIN]}|${lr[cr.XRANGEPLAIN]})`,!0);wf.comparatorTrimReplace=\"$1$2$3\";Vr(\"HYPHENRANGE\",`^\\\\s*(${lr[cr.XRANGEPLAIN]})\\\\s+-\\\\s+(${lr[cr.XRANGEPLAIN]})\\\\s*$`);Vr(\"HYPHENRANGELOOSE\",`^\\\\s*(${lr[cr.XRANGEPLAINLOOSE]})\\\\s+-\\\\s+(${lr[cr.XRANGEPLAINLOOSE]})\\\\s*$`);Vr(\"STAR\",\"(<|>)?=?\\\\s*\\\\*\");Vr(\"GTE0\",\"^\\\\s*>=\\\\s*0\\\\.0\\\\.0\\\\s*$\");Vr(\"GTE0PRE\",\"^\\\\s*>=\\\\s*0\\\\.0\\\\.0-0\\\\s*$\")});var pP=_((Lkt,sV)=>{var QGe=Object.freeze({loose:!0}),FGe=Object.freeze({}),RGe=t=>t?typeof t!=\"object\"?QGe:t:FGe;sV.exports=RGe});var VT=_((Nkt,lV)=>{var oV=/^[0-9]+$/,aV=(t,e)=>{let r=oV.test(t),o=oV.test(e);return r&&o&&(t=+t,e=+e),t===e?0:r&&!o?-1:o&&!r?1:t<e?-1:1},TGe=(t,e)=>aV(e,t);lV.exports={compareIdentifiers:aV,rcompareIdentifiers:TGe}});var Po=_((Okt,fV)=>{var hP=dI(),{MAX_LENGTH:cV,MAX_SAFE_INTEGER:gP}=gI(),{safeRe:uV,t:AV}=vy(),LGe=pP(),{compareIdentifiers:Dy}=VT(),rl=class{constructor(e,r){if(r=LGe(r),e instanceof rl){if(e.loose===!!r.loose&&e.includePrerelease===!!r.includePrerelease)return e;e=e.version}else if(typeof e!=\"string\")throw new TypeError(`Invalid version. Must be a string. Got type \"${typeof e}\".`);if(e.length>cV)throw new TypeError(`version is longer than ${cV} characters`);hP(\"SemVer\",e,r),this.options=r,this.loose=!!r.loose,this.includePrerelease=!!r.includePrerelease;let o=e.trim().match(r.loose?uV[AV.LOOSE]:uV[AV.FULL]);if(!o)throw new TypeError(`Invalid Version: ${e}`);if(this.raw=e,this.major=+o[1],this.minor=+o[2],this.patch=+o[3],this.major>gP||this.major<0)throw new TypeError(\"Invalid major version\");if(this.minor>gP||this.minor<0)throw new TypeError(\"Invalid minor version\");if(this.patch>gP||this.patch<0)throw new TypeError(\"Invalid patch version\");o[4]?this.prerelease=o[4].split(\".\").map(a=>{if(/^[0-9]+$/.test(a)){let n=+a;if(n>=0&&n<gP)return n}return a}):this.prerelease=[],this.build=o[5]?o[5].split(\".\"):[],this.format()}format(){return this.version=`${this.major}.${this.minor}.${this.patch}`,this.prerelease.length&&(this.version+=`-${this.prerelease.join(\".\")}`),this.version}toString(){return this.version}compare(e){if(hP(\"SemVer.compare\",this.version,this.options,e),!(e instanceof rl)){if(typeof e==\"string\"&&e===this.version)return 0;e=new rl(e,this.options)}return e.version===this.version?0:this.compareMain(e)||this.comparePre(e)}compareMain(e){return e instanceof rl||(e=new rl(e,this.options)),Dy(this.major,e.major)||Dy(this.minor,e.minor)||Dy(this.patch,e.patch)}comparePre(e){if(e instanceof rl||(e=new rl(e,this.options)),this.prerelease.length&&!e.prerelease.length)return-1;if(!this.prerelease.length&&e.prerelease.length)return 1;if(!this.prerelease.length&&!e.prerelease.length)return 0;let r=0;do{let o=this.prerelease[r],a=e.prerelease[r];if(hP(\"prerelease compare\",r,o,a),o===void 0&&a===void 0)return 0;if(a===void 0)return 1;if(o===void 0)return-1;if(o===a)continue;return Dy(o,a)}while(++r)}compareBuild(e){e instanceof rl||(e=new rl(e,this.options));let r=0;do{let o=this.build[r],a=e.build[r];if(hP(\"prerelease compare\",r,o,a),o===void 0&&a===void 0)return 0;if(a===void 0)return 1;if(o===void 0)return-1;if(o===a)continue;return Dy(o,a)}while(++r)}inc(e,r,o){switch(e){case\"premajor\":this.prerelease.length=0,this.patch=0,this.minor=0,this.major++,this.inc(\"pre\",r,o);break;case\"preminor\":this.prerelease.length=0,this.patch=0,this.minor++,this.inc(\"pre\",r,o);break;case\"prepatch\":this.prerelease.length=0,this.inc(\"patch\",r,o),this.inc(\"pre\",r,o);break;case\"prerelease\":this.prerelease.length===0&&this.inc(\"patch\",r,o),this.inc(\"pre\",r,o);break;case\"major\":(this.minor!==0||this.patch!==0||this.prerelease.length===0)&&this.major++,this.minor=0,this.patch=0,this.prerelease=[];break;case\"minor\":(this.patch!==0||this.prerelease.length===0)&&this.minor++,this.patch=0,this.prerelease=[];break;case\"patch\":this.prerelease.length===0&&this.patch++,this.prerelease=[];break;case\"pre\":{let a=Number(o)?1:0;if(!r&&o===!1)throw new Error(\"invalid increment argument: identifier is empty\");if(this.prerelease.length===0)this.prerelease=[a];else{let n=this.prerelease.length;for(;--n>=0;)typeof this.prerelease[n]==\"number\"&&(this.prerelease[n]++,n=-2);if(n===-1){if(r===this.prerelease.join(\".\")&&o===!1)throw new Error(\"invalid increment argument: identifier already exists\");this.prerelease.push(a)}}if(r){let n=[r,a];o===!1&&(n=[r]),Dy(this.prerelease[0],r)===0?isNaN(this.prerelease[1])&&(this.prerelease=n):this.prerelease=n}break}default:throw new Error(`invalid increment argument: ${e}`)}return this.raw=this.format(),this.build.length&&(this.raw+=`+${this.build.join(\".\")}`),this}};fV.exports=rl});var od=_((Mkt,hV)=>{var pV=Po(),NGe=(t,e,r=!1)=>{if(t instanceof pV)return t;try{return new pV(t,e)}catch(o){if(!r)return null;throw o}};hV.exports=NGe});var dV=_((Ukt,gV)=>{var OGe=od(),MGe=(t,e)=>{let r=OGe(t,e);return r?r.version:null};gV.exports=MGe});var yV=_((_kt,mV)=>{var UGe=od(),_Ge=(t,e)=>{let r=UGe(t.trim().replace(/^[=v]+/,\"\"),e);return r?r.version:null};mV.exports=_Ge});var wV=_((Hkt,CV)=>{var EV=Po(),HGe=(t,e,r,o,a)=>{typeof r==\"string\"&&(a=o,o=r,r=void 0);try{return new EV(t instanceof EV?t.version:t,r).inc(e,o,a).version}catch{return null}};CV.exports=HGe});var vV=_((qkt,BV)=>{var IV=od(),qGe=(t,e)=>{let r=IV(t,null,!0),o=IV(e,null,!0),a=r.compare(o);if(a===0)return null;let n=a>0,u=n?r:o,A=n?o:r,p=!!u.prerelease.length;if(!!A.prerelease.length&&!p)return!A.patch&&!A.minor?\"major\":u.patch?\"patch\":u.minor?\"minor\":\"major\";let E=p?\"pre\":\"\";return r.major!==o.major?E+\"major\":r.minor!==o.minor?E+\"minor\":r.patch!==o.patch?E+\"patch\":\"prerelease\"};BV.exports=qGe});var PV=_((Gkt,DV)=>{var GGe=Po(),jGe=(t,e)=>new GGe(t,e).major;DV.exports=jGe});var bV=_((jkt,SV)=>{var YGe=Po(),WGe=(t,e)=>new YGe(t,e).minor;SV.exports=WGe});var kV=_((Ykt,xV)=>{var KGe=Po(),zGe=(t,e)=>new KGe(t,e).patch;xV.exports=zGe});var FV=_((Wkt,QV)=>{var VGe=od(),JGe=(t,e)=>{let r=VGe(t,e);return r&&r.prerelease.length?r.prerelease:null};QV.exports=JGe});var Ol=_((Kkt,TV)=>{var RV=Po(),XGe=(t,e,r)=>new RV(t,r).compare(new RV(e,r));TV.exports=XGe});var NV=_((zkt,LV)=>{var ZGe=Ol(),$Ge=(t,e,r)=>ZGe(e,t,r);LV.exports=$Ge});var MV=_((Vkt,OV)=>{var eje=Ol(),tje=(t,e)=>eje(t,e,!0);OV.exports=tje});var dP=_((Jkt,_V)=>{var UV=Po(),rje=(t,e,r)=>{let o=new UV(t,r),a=new UV(e,r);return o.compare(a)||o.compareBuild(a)};_V.exports=rje});var qV=_((Xkt,HV)=>{var nje=dP(),ije=(t,e)=>t.sort((r,o)=>nje(r,o,e));HV.exports=ije});var jV=_((Zkt,GV)=>{var sje=dP(),oje=(t,e)=>t.sort((r,o)=>sje(o,r,e));GV.exports=oje});var mI=_(($kt,YV)=>{var aje=Ol(),lje=(t,e,r)=>aje(t,e,r)>0;YV.exports=lje});var mP=_((eQt,WV)=>{var cje=Ol(),uje=(t,e,r)=>cje(t,e,r)<0;WV.exports=uje});var JT=_((tQt,KV)=>{var Aje=Ol(),fje=(t,e,r)=>Aje(t,e,r)===0;KV.exports=fje});var XT=_((rQt,zV)=>{var pje=Ol(),hje=(t,e,r)=>pje(t,e,r)!==0;zV.exports=hje});var yP=_((nQt,VV)=>{var gje=Ol(),dje=(t,e,r)=>gje(t,e,r)>=0;VV.exports=dje});var EP=_((iQt,JV)=>{var mje=Ol(),yje=(t,e,r)=>mje(t,e,r)<=0;JV.exports=yje});var ZT=_((sQt,XV)=>{var Eje=JT(),Cje=XT(),wje=mI(),Ije=yP(),Bje=mP(),vje=EP(),Dje=(t,e,r,o)=>{switch(e){case\"===\":return typeof t==\"object\"&&(t=t.version),typeof r==\"object\"&&(r=r.version),t===r;case\"!==\":return typeof t==\"object\"&&(t=t.version),typeof r==\"object\"&&(r=r.version),t!==r;case\"\":case\"=\":case\"==\":return Eje(t,r,o);case\"!=\":return Cje(t,r,o);case\">\":return wje(t,r,o);case\">=\":return Ije(t,r,o);case\"<\":return Bje(t,r,o);case\"<=\":return vje(t,r,o);default:throw new TypeError(`Invalid operator: ${e}`)}};XV.exports=Dje});var $V=_((oQt,ZV)=>{var Pje=Po(),Sje=od(),{safeRe:CP,t:wP}=vy(),bje=(t,e)=>{if(t instanceof Pje)return t;if(typeof t==\"number\"&&(t=String(t)),typeof t!=\"string\")return null;e=e||{};let r=null;if(!e.rtl)r=t.match(CP[wP.COERCE]);else{let o;for(;(o=CP[wP.COERCERTL].exec(t))&&(!r||r.index+r[0].length!==t.length);)(!r||o.index+o[0].length!==r.index+r[0].length)&&(r=o),CP[wP.COERCERTL].lastIndex=o.index+o[1].length+o[2].length;CP[wP.COERCERTL].lastIndex=-1}return r===null?null:Sje(`${r[2]}.${r[3]||\"0\"}.${r[4]||\"0\"}`,e)};ZV.exports=bje});var tJ=_((aQt,eJ)=>{\"use strict\";eJ.exports=function(t){t.prototype[Symbol.iterator]=function*(){for(let e=this.head;e;e=e.next)yield e.value}}});var IP=_((lQt,rJ)=>{\"use strict\";rJ.exports=Cn;Cn.Node=ad;Cn.create=Cn;function Cn(t){var e=this;if(e instanceof Cn||(e=new Cn),e.tail=null,e.head=null,e.length=0,t&&typeof t.forEach==\"function\")t.forEach(function(a){e.push(a)});else if(arguments.length>0)for(var r=0,o=arguments.length;r<o;r++)e.push(arguments[r]);return e}Cn.prototype.removeNode=function(t){if(t.list!==this)throw new Error(\"removing node which does not belong to this list\");var e=t.next,r=t.prev;return e&&(e.prev=r),r&&(r.next=e),t===this.head&&(this.head=e),t===this.tail&&(this.tail=r),t.list.length--,t.next=null,t.prev=null,t.list=null,e};Cn.prototype.unshiftNode=function(t){if(t!==this.head){t.list&&t.list.removeNode(t);var e=this.head;t.list=this,t.next=e,e&&(e.prev=t),this.head=t,this.tail||(this.tail=t),this.length++}};Cn.prototype.pushNode=function(t){if(t!==this.tail){t.list&&t.list.removeNode(t);var e=this.tail;t.list=this,t.prev=e,e&&(e.next=t),this.tail=t,this.head||(this.head=t),this.length++}};Cn.prototype.push=function(){for(var t=0,e=arguments.length;t<e;t++)kje(this,arguments[t]);return this.length};Cn.prototype.unshift=function(){for(var t=0,e=arguments.length;t<e;t++)Qje(this,arguments[t]);return this.length};Cn.prototype.pop=function(){if(!!this.tail){var t=this.tail.value;return this.tail=this.tail.prev,this.tail?this.tail.next=null:this.head=null,this.length--,t}};Cn.prototype.shift=function(){if(!!this.head){var t=this.head.value;return this.head=this.head.next,this.head?this.head.prev=null:this.tail=null,this.length--,t}};Cn.prototype.forEach=function(t,e){e=e||this;for(var r=this.head,o=0;r!==null;o++)t.call(e,r.value,o,this),r=r.next};Cn.prototype.forEachReverse=function(t,e){e=e||this;for(var r=this.tail,o=this.length-1;r!==null;o--)t.call(e,r.value,o,this),r=r.prev};Cn.prototype.get=function(t){for(var e=0,r=this.head;r!==null&&e<t;e++)r=r.next;if(e===t&&r!==null)return r.value};Cn.prototype.getReverse=function(t){for(var e=0,r=this.tail;r!==null&&e<t;e++)r=r.prev;if(e===t&&r!==null)return r.value};Cn.prototype.map=function(t,e){e=e||this;for(var r=new Cn,o=this.head;o!==null;)r.push(t.call(e,o.value,this)),o=o.next;return r};Cn.prototype.mapReverse=function(t,e){e=e||this;for(var r=new Cn,o=this.tail;o!==null;)r.push(t.call(e,o.value,this)),o=o.prev;return r};Cn.prototype.reduce=function(t,e){var r,o=this.head;if(arguments.length>1)r=e;else if(this.head)o=this.head.next,r=this.head.value;else throw new TypeError(\"Reduce of empty list with no initial value\");for(var a=0;o!==null;a++)r=t(r,o.value,a),o=o.next;return r};Cn.prototype.reduceReverse=function(t,e){var r,o=this.tail;if(arguments.length>1)r=e;else if(this.tail)o=this.tail.prev,r=this.tail.value;else throw new TypeError(\"Reduce of empty list with no initial value\");for(var a=this.length-1;o!==null;a--)r=t(r,o.value,a),o=o.prev;return r};Cn.prototype.toArray=function(){for(var t=new Array(this.length),e=0,r=this.head;r!==null;e++)t[e]=r.value,r=r.next;return t};Cn.prototype.toArrayReverse=function(){for(var t=new Array(this.length),e=0,r=this.tail;r!==null;e++)t[e]=r.value,r=r.prev;return t};Cn.prototype.slice=function(t,e){e=e||this.length,e<0&&(e+=this.length),t=t||0,t<0&&(t+=this.length);var r=new Cn;if(e<t||e<0)return r;t<0&&(t=0),e>this.length&&(e=this.length);for(var o=0,a=this.head;a!==null&&o<t;o++)a=a.next;for(;a!==null&&o<e;o++,a=a.next)r.push(a.value);return r};Cn.prototype.sliceReverse=function(t,e){e=e||this.length,e<0&&(e+=this.length),t=t||0,t<0&&(t+=this.length);var r=new Cn;if(e<t||e<0)return r;t<0&&(t=0),e>this.length&&(e=this.length);for(var o=this.length,a=this.tail;a!==null&&o>e;o--)a=a.prev;for(;a!==null&&o>t;o--,a=a.prev)r.push(a.value);return r};Cn.prototype.splice=function(t,e,...r){t>this.length&&(t=this.length-1),t<0&&(t=this.length+t);for(var o=0,a=this.head;a!==null&&o<t;o++)a=a.next;for(var n=[],o=0;a&&o<e;o++)n.push(a.value),a=this.removeNode(a);a===null&&(a=this.tail),a!==this.head&&a!==this.tail&&(a=a.prev);for(var o=0;o<r.length;o++)a=xje(this,a,r[o]);return n};Cn.prototype.reverse=function(){for(var t=this.head,e=this.tail,r=t;r!==null;r=r.prev){var o=r.prev;r.prev=r.next,r.next=o}return this.head=e,this.tail=t,this};function xje(t,e,r){var o=e===t.head?new ad(r,null,e,t):new ad(r,e,e.next,t);return o.next===null&&(t.tail=o),o.prev===null&&(t.head=o),t.length++,o}function kje(t,e){t.tail=new ad(e,t.tail,null,t),t.head||(t.head=t.tail),t.length++}function Qje(t,e){t.head=new ad(e,null,t.head,t),t.tail||(t.tail=t.head),t.length++}function ad(t,e,r,o){if(!(this instanceof ad))return new ad(t,e,r,o);this.list=o,this.value=t,e?(e.next=this,this.prev=e):this.prev=null,r?(r.prev=this,this.next=r):this.next=null}try{tJ()(Cn)}catch{}});var aJ=_((cQt,oJ)=>{\"use strict\";var Fje=IP(),ld=Symbol(\"max\"),Bf=Symbol(\"length\"),Py=Symbol(\"lengthCalculator\"),EI=Symbol(\"allowStale\"),cd=Symbol(\"maxAge\"),If=Symbol(\"dispose\"),nJ=Symbol(\"noDisposeOnSet\"),xs=Symbol(\"lruList\"),Uc=Symbol(\"cache\"),sJ=Symbol(\"updateAgeOnGet\"),$T=()=>1,tL=class{constructor(e){if(typeof e==\"number\"&&(e={max:e}),e||(e={}),e.max&&(typeof e.max!=\"number\"||e.max<0))throw new TypeError(\"max must be a non-negative number\");let r=this[ld]=e.max||1/0,o=e.length||$T;if(this[Py]=typeof o!=\"function\"?$T:o,this[EI]=e.stale||!1,e.maxAge&&typeof e.maxAge!=\"number\")throw new TypeError(\"maxAge must be a number\");this[cd]=e.maxAge||0,this[If]=e.dispose,this[nJ]=e.noDisposeOnSet||!1,this[sJ]=e.updateAgeOnGet||!1,this.reset()}set max(e){if(typeof e!=\"number\"||e<0)throw new TypeError(\"max must be a non-negative number\");this[ld]=e||1/0,yI(this)}get max(){return this[ld]}set allowStale(e){this[EI]=!!e}get allowStale(){return this[EI]}set maxAge(e){if(typeof e!=\"number\")throw new TypeError(\"maxAge must be a non-negative number\");this[cd]=e,yI(this)}get maxAge(){return this[cd]}set lengthCalculator(e){typeof e!=\"function\"&&(e=$T),e!==this[Py]&&(this[Py]=e,this[Bf]=0,this[xs].forEach(r=>{r.length=this[Py](r.value,r.key),this[Bf]+=r.length})),yI(this)}get lengthCalculator(){return this[Py]}get length(){return this[Bf]}get itemCount(){return this[xs].length}rforEach(e,r){r=r||this;for(let o=this[xs].tail;o!==null;){let a=o.prev;iJ(this,e,o,r),o=a}}forEach(e,r){r=r||this;for(let o=this[xs].head;o!==null;){let a=o.next;iJ(this,e,o,r),o=a}}keys(){return this[xs].toArray().map(e=>e.key)}values(){return this[xs].toArray().map(e=>e.value)}reset(){this[If]&&this[xs]&&this[xs].length&&this[xs].forEach(e=>this[If](e.key,e.value)),this[Uc]=new Map,this[xs]=new Fje,this[Bf]=0}dump(){return this[xs].map(e=>BP(this,e)?!1:{k:e.key,v:e.value,e:e.now+(e.maxAge||0)}).toArray().filter(e=>e)}dumpLru(){return this[xs]}set(e,r,o){if(o=o||this[cd],o&&typeof o!=\"number\")throw new TypeError(\"maxAge must be a number\");let a=o?Date.now():0,n=this[Py](r,e);if(this[Uc].has(e)){if(n>this[ld])return Sy(this,this[Uc].get(e)),!1;let p=this[Uc].get(e).value;return this[If]&&(this[nJ]||this[If](e,p.value)),p.now=a,p.maxAge=o,p.value=r,this[Bf]+=n-p.length,p.length=n,this.get(e),yI(this),!0}let u=new rL(e,r,n,a,o);return u.length>this[ld]?(this[If]&&this[If](e,r),!1):(this[Bf]+=u.length,this[xs].unshift(u),this[Uc].set(e,this[xs].head),yI(this),!0)}has(e){if(!this[Uc].has(e))return!1;let r=this[Uc].get(e).value;return!BP(this,r)}get(e){return eL(this,e,!0)}peek(e){return eL(this,e,!1)}pop(){let e=this[xs].tail;return e?(Sy(this,e),e.value):null}del(e){Sy(this,this[Uc].get(e))}load(e){this.reset();let r=Date.now();for(let o=e.length-1;o>=0;o--){let a=e[o],n=a.e||0;if(n===0)this.set(a.k,a.v);else{let u=n-r;u>0&&this.set(a.k,a.v,u)}}}prune(){this[Uc].forEach((e,r)=>eL(this,r,!1))}},eL=(t,e,r)=>{let o=t[Uc].get(e);if(o){let a=o.value;if(BP(t,a)){if(Sy(t,o),!t[EI])return}else r&&(t[sJ]&&(o.value.now=Date.now()),t[xs].unshiftNode(o));return a.value}},BP=(t,e)=>{if(!e||!e.maxAge&&!t[cd])return!1;let r=Date.now()-e.now;return e.maxAge?r>e.maxAge:t[cd]&&r>t[cd]},yI=t=>{if(t[Bf]>t[ld])for(let e=t[xs].tail;t[Bf]>t[ld]&&e!==null;){let r=e.prev;Sy(t,e),e=r}},Sy=(t,e)=>{if(e){let r=e.value;t[If]&&t[If](r.key,r.value),t[Bf]-=r.length,t[Uc].delete(r.key),t[xs].removeNode(e)}},rL=class{constructor(e,r,o,a,n){this.key=e,this.value=r,this.length=o,this.now=a,this.maxAge=n||0}},iJ=(t,e,r,o)=>{let a=r.value;BP(t,a)&&(Sy(t,r),t[EI]||(a=void 0)),a&&e.call(o,a.value,a.key,t)};oJ.exports=tL});var Ml=_((uQt,AJ)=>{var ud=class{constructor(e,r){if(r=Tje(r),e instanceof ud)return e.loose===!!r.loose&&e.includePrerelease===!!r.includePrerelease?e:new ud(e.raw,r);if(e instanceof nL)return this.raw=e.value,this.set=[[e]],this.format(),this;if(this.options=r,this.loose=!!r.loose,this.includePrerelease=!!r.includePrerelease,this.raw=e.trim().split(/\\s+/).join(\" \"),this.set=this.raw.split(\"||\").map(o=>this.parseRange(o.trim())).filter(o=>o.length),!this.set.length)throw new TypeError(`Invalid SemVer Range: ${this.raw}`);if(this.set.length>1){let o=this.set[0];if(this.set=this.set.filter(a=>!cJ(a[0])),this.set.length===0)this.set=[o];else if(this.set.length>1){for(let a of this.set)if(a.length===1&&Hje(a[0])){this.set=[a];break}}}this.format()}format(){return this.range=this.set.map(e=>e.join(\" \").trim()).join(\"||\").trim(),this.range}toString(){return this.range}parseRange(e){let o=((this.options.includePrerelease&&Uje)|(this.options.loose&&_je))+\":\"+e,a=lJ.get(o);if(a)return a;let n=this.options.loose,u=n?Da[Jo.HYPHENRANGELOOSE]:Da[Jo.HYPHENRANGE];e=e.replace(u,Xje(this.options.includePrerelease)),ci(\"hyphen replace\",e),e=e.replace(Da[Jo.COMPARATORTRIM],Nje),ci(\"comparator trim\",e),e=e.replace(Da[Jo.TILDETRIM],Oje),ci(\"tilde trim\",e),e=e.replace(Da[Jo.CARETTRIM],Mje),ci(\"caret trim\",e);let A=e.split(\" \").map(I=>qje(I,this.options)).join(\" \").split(/\\s+/).map(I=>Jje(I,this.options));n&&(A=A.filter(I=>(ci(\"loose invalid filter\",I,this.options),!!I.match(Da[Jo.COMPARATORLOOSE])))),ci(\"range list\",A);let p=new Map,h=A.map(I=>new nL(I,this.options));for(let I of h){if(cJ(I))return[I];p.set(I.value,I)}p.size>1&&p.has(\"\")&&p.delete(\"\");let E=[...p.values()];return lJ.set(o,E),E}intersects(e,r){if(!(e instanceof ud))throw new TypeError(\"a Range is required\");return this.set.some(o=>uJ(o,r)&&e.set.some(a=>uJ(a,r)&&o.every(n=>a.every(u=>n.intersects(u,r)))))}test(e){if(!e)return!1;if(typeof e==\"string\")try{e=new Lje(e,this.options)}catch{return!1}for(let r=0;r<this.set.length;r++)if(Zje(this.set[r],e,this.options))return!0;return!1}};AJ.exports=ud;var Rje=aJ(),lJ=new Rje({max:1e3}),Tje=pP(),nL=CI(),ci=dI(),Lje=Po(),{safeRe:Da,t:Jo,comparatorTrimReplace:Nje,tildeTrimReplace:Oje,caretTrimReplace:Mje}=vy(),{FLAG_INCLUDE_PRERELEASE:Uje,FLAG_LOOSE:_je}=gI(),cJ=t=>t.value===\"<0.0.0-0\",Hje=t=>t.value===\"\",uJ=(t,e)=>{let r=!0,o=t.slice(),a=o.pop();for(;r&&o.length;)r=o.every(n=>a.intersects(n,e)),a=o.pop();return r},qje=(t,e)=>(ci(\"comp\",t,e),t=Yje(t,e),ci(\"caret\",t),t=Gje(t,e),ci(\"tildes\",t),t=Kje(t,e),ci(\"xrange\",t),t=Vje(t,e),ci(\"stars\",t),t),Xo=t=>!t||t.toLowerCase()===\"x\"||t===\"*\",Gje=(t,e)=>t.trim().split(/\\s+/).map(r=>jje(r,e)).join(\" \"),jje=(t,e)=>{let r=e.loose?Da[Jo.TILDELOOSE]:Da[Jo.TILDE];return t.replace(r,(o,a,n,u,A)=>{ci(\"tilde\",t,o,a,n,u,A);let p;return Xo(a)?p=\"\":Xo(n)?p=`>=${a}.0.0 <${+a+1}.0.0-0`:Xo(u)?p=`>=${a}.${n}.0 <${a}.${+n+1}.0-0`:A?(ci(\"replaceTilde pr\",A),p=`>=${a}.${n}.${u}-${A} <${a}.${+n+1}.0-0`):p=`>=${a}.${n}.${u} <${a}.${+n+1}.0-0`,ci(\"tilde return\",p),p})},Yje=(t,e)=>t.trim().split(/\\s+/).map(r=>Wje(r,e)).join(\" \"),Wje=(t,e)=>{ci(\"caret\",t,e);let r=e.loose?Da[Jo.CARETLOOSE]:Da[Jo.CARET],o=e.includePrerelease?\"-0\":\"\";return t.replace(r,(a,n,u,A,p)=>{ci(\"caret\",t,a,n,u,A,p);let h;return Xo(n)?h=\"\":Xo(u)?h=`>=${n}.0.0${o} <${+n+1}.0.0-0`:Xo(A)?n===\"0\"?h=`>=${n}.${u}.0${o} <${n}.${+u+1}.0-0`:h=`>=${n}.${u}.0${o} <${+n+1}.0.0-0`:p?(ci(\"replaceCaret pr\",p),n===\"0\"?u===\"0\"?h=`>=${n}.${u}.${A}-${p} <${n}.${u}.${+A+1}-0`:h=`>=${n}.${u}.${A}-${p} <${n}.${+u+1}.0-0`:h=`>=${n}.${u}.${A}-${p} <${+n+1}.0.0-0`):(ci(\"no pr\"),n===\"0\"?u===\"0\"?h=`>=${n}.${u}.${A}${o} <${n}.${u}.${+A+1}-0`:h=`>=${n}.${u}.${A}${o} <${n}.${+u+1}.0-0`:h=`>=${n}.${u}.${A} <${+n+1}.0.0-0`),ci(\"caret return\",h),h})},Kje=(t,e)=>(ci(\"replaceXRanges\",t,e),t.split(/\\s+/).map(r=>zje(r,e)).join(\" \")),zje=(t,e)=>{t=t.trim();let r=e.loose?Da[Jo.XRANGELOOSE]:Da[Jo.XRANGE];return t.replace(r,(o,a,n,u,A,p)=>{ci(\"xRange\",t,o,a,n,u,A,p);let h=Xo(n),E=h||Xo(u),I=E||Xo(A),v=I;return a===\"=\"&&v&&(a=\"\"),p=e.includePrerelease?\"-0\":\"\",h?a===\">\"||a===\"<\"?o=\"<0.0.0-0\":o=\"*\":a&&v?(E&&(u=0),A=0,a===\">\"?(a=\">=\",E?(n=+n+1,u=0,A=0):(u=+u+1,A=0)):a===\"<=\"&&(a=\"<\",E?n=+n+1:u=+u+1),a===\"<\"&&(p=\"-0\"),o=`${a+n}.${u}.${A}${p}`):E?o=`>=${n}.0.0${p} <${+n+1}.0.0-0`:I&&(o=`>=${n}.${u}.0${p} <${n}.${+u+1}.0-0`),ci(\"xRange return\",o),o})},Vje=(t,e)=>(ci(\"replaceStars\",t,e),t.trim().replace(Da[Jo.STAR],\"\")),Jje=(t,e)=>(ci(\"replaceGTE0\",t,e),t.trim().replace(Da[e.includePrerelease?Jo.GTE0PRE:Jo.GTE0],\"\")),Xje=t=>(e,r,o,a,n,u,A,p,h,E,I,v,x)=>(Xo(o)?r=\"\":Xo(a)?r=`>=${o}.0.0${t?\"-0\":\"\"}`:Xo(n)?r=`>=${o}.${a}.0${t?\"-0\":\"\"}`:u?r=`>=${r}`:r=`>=${r}${t?\"-0\":\"\"}`,Xo(h)?p=\"\":Xo(E)?p=`<${+h+1}.0.0-0`:Xo(I)?p=`<${h}.${+E+1}.0-0`:v?p=`<=${h}.${E}.${I}-${v}`:t?p=`<${h}.${E}.${+I+1}-0`:p=`<=${p}`,`${r} ${p}`.trim()),Zje=(t,e,r)=>{for(let o=0;o<t.length;o++)if(!t[o].test(e))return!1;if(e.prerelease.length&&!r.includePrerelease){for(let o=0;o<t.length;o++)if(ci(t[o].semver),t[o].semver!==nL.ANY&&t[o].semver.prerelease.length>0){let a=t[o].semver;if(a.major===e.major&&a.minor===e.minor&&a.patch===e.patch)return!0}return!1}return!0}});var CI=_((AQt,mJ)=>{var wI=Symbol(\"SemVer ANY\"),by=class{static get ANY(){return wI}constructor(e,r){if(r=fJ(r),e instanceof by){if(e.loose===!!r.loose)return e;e=e.value}e=e.trim().split(/\\s+/).join(\" \"),sL(\"comparator\",e,r),this.options=r,this.loose=!!r.loose,this.parse(e),this.semver===wI?this.value=\"\":this.value=this.operator+this.semver.version,sL(\"comp\",this)}parse(e){let r=this.options.loose?pJ[hJ.COMPARATORLOOSE]:pJ[hJ.COMPARATOR],o=e.match(r);if(!o)throw new TypeError(`Invalid comparator: ${e}`);this.operator=o[1]!==void 0?o[1]:\"\",this.operator===\"=\"&&(this.operator=\"\"),o[2]?this.semver=new gJ(o[2],this.options.loose):this.semver=wI}toString(){return this.value}test(e){if(sL(\"Comparator.test\",e,this.options.loose),this.semver===wI||e===wI)return!0;if(typeof e==\"string\")try{e=new gJ(e,this.options)}catch{return!1}return iL(e,this.operator,this.semver,this.options)}intersects(e,r){if(!(e instanceof by))throw new TypeError(\"a Comparator is required\");return this.operator===\"\"?this.value===\"\"?!0:new dJ(e.value,r).test(this.value):e.operator===\"\"?e.value===\"\"?!0:new dJ(this.value,r).test(e.semver):(r=fJ(r),r.includePrerelease&&(this.value===\"<0.0.0-0\"||e.value===\"<0.0.0-0\")||!r.includePrerelease&&(this.value.startsWith(\"<0.0.0\")||e.value.startsWith(\"<0.0.0\"))?!1:!!(this.operator.startsWith(\">\")&&e.operator.startsWith(\">\")||this.operator.startsWith(\"<\")&&e.operator.startsWith(\"<\")||this.semver.version===e.semver.version&&this.operator.includes(\"=\")&&e.operator.includes(\"=\")||iL(this.semver,\"<\",e.semver,r)&&this.operator.startsWith(\">\")&&e.operator.startsWith(\"<\")||iL(this.semver,\">\",e.semver,r)&&this.operator.startsWith(\"<\")&&e.operator.startsWith(\">\")))}};mJ.exports=by;var fJ=pP(),{safeRe:pJ,t:hJ}=vy(),iL=ZT(),sL=dI(),gJ=Po(),dJ=Ml()});var II=_((fQt,yJ)=>{var $je=Ml(),e9e=(t,e,r)=>{try{e=new $je(e,r)}catch{return!1}return e.test(t)};yJ.exports=e9e});var CJ=_((pQt,EJ)=>{var t9e=Ml(),r9e=(t,e)=>new t9e(t,e).set.map(r=>r.map(o=>o.value).join(\" \").trim().split(\" \"));EJ.exports=r9e});var IJ=_((hQt,wJ)=>{var n9e=Po(),i9e=Ml(),s9e=(t,e,r)=>{let o=null,a=null,n=null;try{n=new i9e(e,r)}catch{return null}return t.forEach(u=>{n.test(u)&&(!o||a.compare(u)===-1)&&(o=u,a=new n9e(o,r))}),o};wJ.exports=s9e});var vJ=_((gQt,BJ)=>{var o9e=Po(),a9e=Ml(),l9e=(t,e,r)=>{let o=null,a=null,n=null;try{n=new a9e(e,r)}catch{return null}return t.forEach(u=>{n.test(u)&&(!o||a.compare(u)===1)&&(o=u,a=new o9e(o,r))}),o};BJ.exports=l9e});var SJ=_((dQt,PJ)=>{var oL=Po(),c9e=Ml(),DJ=mI(),u9e=(t,e)=>{t=new c9e(t,e);let r=new oL(\"0.0.0\");if(t.test(r)||(r=new oL(\"0.0.0-0\"),t.test(r)))return r;r=null;for(let o=0;o<t.set.length;++o){let a=t.set[o],n=null;a.forEach(u=>{let A=new oL(u.semver.version);switch(u.operator){case\">\":A.prerelease.length===0?A.patch++:A.prerelease.push(0),A.raw=A.format();case\"\":case\">=\":(!n||DJ(A,n))&&(n=A);break;case\"<\":case\"<=\":break;default:throw new Error(`Unexpected operation: ${u.operator}`)}}),n&&(!r||DJ(r,n))&&(r=n)}return r&&t.test(r)?r:null};PJ.exports=u9e});var xJ=_((mQt,bJ)=>{var A9e=Ml(),f9e=(t,e)=>{try{return new A9e(t,e).range||\"*\"}catch{return null}};bJ.exports=f9e});var vP=_((yQt,RJ)=>{var p9e=Po(),FJ=CI(),{ANY:h9e}=FJ,g9e=Ml(),d9e=II(),kJ=mI(),QJ=mP(),m9e=EP(),y9e=yP(),E9e=(t,e,r,o)=>{t=new p9e(t,o),e=new g9e(e,o);let a,n,u,A,p;switch(r){case\">\":a=kJ,n=m9e,u=QJ,A=\">\",p=\">=\";break;case\"<\":a=QJ,n=y9e,u=kJ,A=\"<\",p=\"<=\";break;default:throw new TypeError('Must provide a hilo val of \"<\" or \">\"')}if(d9e(t,e,o))return!1;for(let h=0;h<e.set.length;++h){let E=e.set[h],I=null,v=null;if(E.forEach(x=>{x.semver===h9e&&(x=new FJ(\">=0.0.0\")),I=I||x,v=v||x,a(x.semver,I.semver,o)?I=x:u(x.semver,v.semver,o)&&(v=x)}),I.operator===A||I.operator===p||(!v.operator||v.operator===A)&&n(t,v.semver))return!1;if(v.operator===p&&u(t,v.semver))return!1}return!0};RJ.exports=E9e});var LJ=_((EQt,TJ)=>{var C9e=vP(),w9e=(t,e,r)=>C9e(t,e,\">\",r);TJ.exports=w9e});var OJ=_((CQt,NJ)=>{var I9e=vP(),B9e=(t,e,r)=>I9e(t,e,\"<\",r);NJ.exports=B9e});var _J=_((wQt,UJ)=>{var MJ=Ml(),v9e=(t,e,r)=>(t=new MJ(t,r),e=new MJ(e,r),t.intersects(e,r));UJ.exports=v9e});var qJ=_((IQt,HJ)=>{var D9e=II(),P9e=Ol();HJ.exports=(t,e,r)=>{let o=[],a=null,n=null,u=t.sort((E,I)=>P9e(E,I,r));for(let E of u)D9e(E,e,r)?(n=E,a||(a=E)):(n&&o.push([a,n]),n=null,a=null);a&&o.push([a,null]);let A=[];for(let[E,I]of o)E===I?A.push(E):!I&&E===u[0]?A.push(\"*\"):I?E===u[0]?A.push(`<=${I}`):A.push(`${E} - ${I}`):A.push(`>=${E}`);let p=A.join(\" || \"),h=typeof e.raw==\"string\"?e.raw:String(e);return p.length<h.length?p:e}});var zJ=_((BQt,KJ)=>{var GJ=Ml(),lL=CI(),{ANY:aL}=lL,BI=II(),cL=Ol(),S9e=(t,e,r={})=>{if(t===e)return!0;t=new GJ(t,r),e=new GJ(e,r);let o=!1;e:for(let a of t.set){for(let n of e.set){let u=x9e(a,n,r);if(o=o||u!==null,u)continue e}if(o)return!1}return!0},b9e=[new lL(\">=0.0.0-0\")],jJ=[new lL(\">=0.0.0\")],x9e=(t,e,r)=>{if(t===e)return!0;if(t.length===1&&t[0].semver===aL){if(e.length===1&&e[0].semver===aL)return!0;r.includePrerelease?t=b9e:t=jJ}if(e.length===1&&e[0].semver===aL){if(r.includePrerelease)return!0;e=jJ}let o=new Set,a,n;for(let x of t)x.operator===\">\"||x.operator===\">=\"?a=YJ(a,x,r):x.operator===\"<\"||x.operator===\"<=\"?n=WJ(n,x,r):o.add(x.semver);if(o.size>1)return null;let u;if(a&&n){if(u=cL(a.semver,n.semver,r),u>0)return null;if(u===0&&(a.operator!==\">=\"||n.operator!==\"<=\"))return null}for(let x of o){if(a&&!BI(x,String(a),r)||n&&!BI(x,String(n),r))return null;for(let C of e)if(!BI(x,String(C),r))return!1;return!0}let A,p,h,E,I=n&&!r.includePrerelease&&n.semver.prerelease.length?n.semver:!1,v=a&&!r.includePrerelease&&a.semver.prerelease.length?a.semver:!1;I&&I.prerelease.length===1&&n.operator===\"<\"&&I.prerelease[0]===0&&(I=!1);for(let x of e){if(E=E||x.operator===\">\"||x.operator===\">=\",h=h||x.operator===\"<\"||x.operator===\"<=\",a){if(v&&x.semver.prerelease&&x.semver.prerelease.length&&x.semver.major===v.major&&x.semver.minor===v.minor&&x.semver.patch===v.patch&&(v=!1),x.operator===\">\"||x.operator===\">=\"){if(A=YJ(a,x,r),A===x&&A!==a)return!1}else if(a.operator===\">=\"&&!BI(a.semver,String(x),r))return!1}if(n){if(I&&x.semver.prerelease&&x.semver.prerelease.length&&x.semver.major===I.major&&x.semver.minor===I.minor&&x.semver.patch===I.patch&&(I=!1),x.operator===\"<\"||x.operator===\"<=\"){if(p=WJ(n,x,r),p===x&&p!==n)return!1}else if(n.operator===\"<=\"&&!BI(n.semver,String(x),r))return!1}if(!x.operator&&(n||a)&&u!==0)return!1}return!(a&&h&&!n&&u!==0||n&&E&&!a&&u!==0||v||I)},YJ=(t,e,r)=>{if(!t)return e;let o=cL(t.semver,e.semver,r);return o>0?t:o<0||e.operator===\">\"&&t.operator===\">=\"?e:t},WJ=(t,e,r)=>{if(!t)return e;let o=cL(t.semver,e.semver,r);return o<0?t:o>0||e.operator===\"<\"&&t.operator===\"<=\"?e:t};KJ.exports=S9e});var Jn=_((vQt,XJ)=>{var uL=vy(),VJ=gI(),k9e=Po(),JJ=VT(),Q9e=od(),F9e=dV(),R9e=yV(),T9e=wV(),L9e=vV(),N9e=PV(),O9e=bV(),M9e=kV(),U9e=FV(),_9e=Ol(),H9e=NV(),q9e=MV(),G9e=dP(),j9e=qV(),Y9e=jV(),W9e=mI(),K9e=mP(),z9e=JT(),V9e=XT(),J9e=yP(),X9e=EP(),Z9e=ZT(),$9e=$V(),e5e=CI(),t5e=Ml(),r5e=II(),n5e=CJ(),i5e=IJ(),s5e=vJ(),o5e=SJ(),a5e=xJ(),l5e=vP(),c5e=LJ(),u5e=OJ(),A5e=_J(),f5e=qJ(),p5e=zJ();XJ.exports={parse:Q9e,valid:F9e,clean:R9e,inc:T9e,diff:L9e,major:N9e,minor:O9e,patch:M9e,prerelease:U9e,compare:_9e,rcompare:H9e,compareLoose:q9e,compareBuild:G9e,sort:j9e,rsort:Y9e,gt:W9e,lt:K9e,eq:z9e,neq:V9e,gte:J9e,lte:X9e,cmp:Z9e,coerce:$9e,Comparator:e5e,Range:t5e,satisfies:r5e,toComparators:n5e,maxSatisfying:i5e,minSatisfying:s5e,minVersion:o5e,validRange:a5e,outside:l5e,gtr:c5e,ltr:u5e,intersects:A5e,simplifyRange:f5e,subset:p5e,SemVer:k9e,re:uL.re,src:uL.src,tokens:uL.t,SEMVER_SPEC_VERSION:VJ.SEMVER_SPEC_VERSION,RELEASE_TYPES:VJ.RELEASE_TYPES,compareIdentifiers:JJ.compareIdentifiers,rcompareIdentifiers:JJ.rcompareIdentifiers}});var $J=_((DQt,ZJ)=>{\"use strict\";function h5e(t,e){function r(){this.constructor=t}r.prototype=e.prototype,t.prototype=new r}function Ad(t,e,r,o){this.message=t,this.expected=e,this.found=r,this.location=o,this.name=\"SyntaxError\",typeof Error.captureStackTrace==\"function\"&&Error.captureStackTrace(this,Ad)}h5e(Ad,Error);Ad.buildMessage=function(t,e){var r={literal:function(h){return'\"'+a(h.text)+'\"'},class:function(h){var E=\"\",I;for(I=0;I<h.parts.length;I++)E+=h.parts[I]instanceof Array?n(h.parts[I][0])+\"-\"+n(h.parts[I][1]):n(h.parts[I]);return\"[\"+(h.inverted?\"^\":\"\")+E+\"]\"},any:function(h){return\"any character\"},end:function(h){return\"end of input\"},other:function(h){return h.description}};function o(h){return h.charCodeAt(0).toString(16).toUpperCase()}function a(h){return h.replace(/\\\\/g,\"\\\\\\\\\").replace(/\"/g,'\\\\\"').replace(/\\0/g,\"\\\\0\").replace(/\\t/g,\"\\\\t\").replace(/\\n/g,\"\\\\n\").replace(/\\r/g,\"\\\\r\").replace(/[\\x00-\\x0F]/g,function(E){return\"\\\\x0\"+o(E)}).replace(/[\\x10-\\x1F\\x7F-\\x9F]/g,function(E){return\"\\\\x\"+o(E)})}function n(h){return h.replace(/\\\\/g,\"\\\\\\\\\").replace(/\\]/g,\"\\\\]\").replace(/\\^/g,\"\\\\^\").replace(/-/g,\"\\\\-\").replace(/\\0/g,\"\\\\0\").replace(/\\t/g,\"\\\\t\").replace(/\\n/g,\"\\\\n\").replace(/\\r/g,\"\\\\r\").replace(/[\\x00-\\x0F]/g,function(E){return\"\\\\x0\"+o(E)}).replace(/[\\x10-\\x1F\\x7F-\\x9F]/g,function(E){return\"\\\\x\"+o(E)})}function u(h){return r[h.type](h)}function A(h){var E=new Array(h.length),I,v;for(I=0;I<h.length;I++)E[I]=u(h[I]);if(E.sort(),E.length>0){for(I=1,v=1;I<E.length;I++)E[I-1]!==E[I]&&(E[v]=E[I],v++);E.length=v}switch(E.length){case 1:return E[0];case 2:return E[0]+\" or \"+E[1];default:return E.slice(0,-1).join(\", \")+\", or \"+E[E.length-1]}}function p(h){return h?'\"'+a(h)+'\"':\"end of input\"}return\"Expected \"+A(t)+\" but \"+p(e)+\" found.\"};function g5e(t,e){e=e!==void 0?e:{};var r={},o={Expression:y},a=y,n=\"|\",u=Re(\"|\",!1),A=\"&\",p=Re(\"&\",!1),h=\"^\",E=Re(\"^\",!1),I=function(Z,ie){return!!ie.reduce((be,Le)=>{switch(Le[1]){case\"|\":return be|Le[3];case\"&\":return be&Le[3];case\"^\":return be^Le[3]}},Z)},v=\"!\",x=Re(\"!\",!1),C=function(Z){return!Z},R=\"(\",N=Re(\"(\",!1),U=\")\",V=Re(\")\",!1),te=function(Z){return Z},ae=/^[^ \\t\\n\\r()!|&\\^]/,fe=ke([\" \",\"\t\",`\n`,\"\\r\",\"(\",\")\",\"!\",\"|\",\"&\",\"^\"],!0,!1),ue=function(Z){return e.queryPattern.test(Z)},me=function(Z){return e.checkFn(Z)},he=Te(\"whitespace\"),Be=/^[ \\t\\n\\r]/,we=ke([\" \",\"\t\",`\n`,\"\\r\"],!1,!1),g=0,Ee=0,Pe=[{line:1,column:1}],ce=0,ne=[],ee=0,Ie;if(\"startRule\"in e){if(!(e.startRule in o))throw new Error(`Can't start parsing from rule \"`+e.startRule+'\".');a=o[e.startRule]}function Fe(){return t.substring(Ee,g)}function At(){return qe(Ee,g)}function H(Z,ie){throw ie=ie!==void 0?ie:qe(Ee,g),S([Te(Z)],t.substring(Ee,g),ie)}function at(Z,ie){throw ie=ie!==void 0?ie:qe(Ee,g),w(Z,ie)}function Re(Z,ie){return{type:\"literal\",text:Z,ignoreCase:ie}}function ke(Z,ie,be){return{type:\"class\",parts:Z,inverted:ie,ignoreCase:be}}function xe(){return{type:\"any\"}}function He(){return{type:\"end\"}}function Te(Z){return{type:\"other\",description:Z}}function Ve(Z){var ie=Pe[Z],be;if(ie)return ie;for(be=Z-1;!Pe[be];)be--;for(ie=Pe[be],ie={line:ie.line,column:ie.column};be<Z;)t.charCodeAt(be)===10?(ie.line++,ie.column=1):ie.column++,be++;return Pe[Z]=ie,ie}function qe(Z,ie){var be=Ve(Z),Le=Ve(ie);return{start:{offset:Z,line:be.line,column:be.column},end:{offset:ie,line:Le.line,column:Le.column}}}function b(Z){g<ce||(g>ce&&(ce=g,ne=[]),ne.push(Z))}function w(Z,ie){return new Ad(Z,null,null,ie)}function S(Z,ie,be){return new Ad(Ad.buildMessage(Z,ie),Z,ie,be)}function y(){var Z,ie,be,Le,ot,dt,Gt,$t;if(Z=g,ie=F(),ie!==r){for(be=[],Le=g,ot=X(),ot!==r?(t.charCodeAt(g)===124?(dt=n,g++):(dt=r,ee===0&&b(u)),dt===r&&(t.charCodeAt(g)===38?(dt=A,g++):(dt=r,ee===0&&b(p)),dt===r&&(t.charCodeAt(g)===94?(dt=h,g++):(dt=r,ee===0&&b(E)))),dt!==r?(Gt=X(),Gt!==r?($t=F(),$t!==r?(ot=[ot,dt,Gt,$t],Le=ot):(g=Le,Le=r)):(g=Le,Le=r)):(g=Le,Le=r)):(g=Le,Le=r);Le!==r;)be.push(Le),Le=g,ot=X(),ot!==r?(t.charCodeAt(g)===124?(dt=n,g++):(dt=r,ee===0&&b(u)),dt===r&&(t.charCodeAt(g)===38?(dt=A,g++):(dt=r,ee===0&&b(p)),dt===r&&(t.charCodeAt(g)===94?(dt=h,g++):(dt=r,ee===0&&b(E)))),dt!==r?(Gt=X(),Gt!==r?($t=F(),$t!==r?(ot=[ot,dt,Gt,$t],Le=ot):(g=Le,Le=r)):(g=Le,Le=r)):(g=Le,Le=r)):(g=Le,Le=r);be!==r?(Ee=Z,ie=I(ie,be),Z=ie):(g=Z,Z=r)}else g=Z,Z=r;return Z}function F(){var Z,ie,be,Le,ot,dt;return Z=g,t.charCodeAt(g)===33?(ie=v,g++):(ie=r,ee===0&&b(x)),ie!==r?(be=F(),be!==r?(Ee=Z,ie=C(be),Z=ie):(g=Z,Z=r)):(g=Z,Z=r),Z===r&&(Z=g,t.charCodeAt(g)===40?(ie=R,g++):(ie=r,ee===0&&b(N)),ie!==r?(be=X(),be!==r?(Le=y(),Le!==r?(ot=X(),ot!==r?(t.charCodeAt(g)===41?(dt=U,g++):(dt=r,ee===0&&b(V)),dt!==r?(Ee=Z,ie=te(Le),Z=ie):(g=Z,Z=r)):(g=Z,Z=r)):(g=Z,Z=r)):(g=Z,Z=r)):(g=Z,Z=r),Z===r&&(Z=J())),Z}function J(){var Z,ie,be,Le,ot;if(Z=g,ie=X(),ie!==r){if(be=g,Le=[],ae.test(t.charAt(g))?(ot=t.charAt(g),g++):(ot=r,ee===0&&b(fe)),ot!==r)for(;ot!==r;)Le.push(ot),ae.test(t.charAt(g))?(ot=t.charAt(g),g++):(ot=r,ee===0&&b(fe));else Le=r;Le!==r?be=t.substring(be,g):be=Le,be!==r?(Ee=g,Le=ue(be),Le?Le=void 0:Le=r,Le!==r?(Ee=Z,ie=me(be),Z=ie):(g=Z,Z=r)):(g=Z,Z=r)}else g=Z,Z=r;return Z}function X(){var Z,ie;for(ee++,Z=[],Be.test(t.charAt(g))?(ie=t.charAt(g),g++):(ie=r,ee===0&&b(we));ie!==r;)Z.push(ie),Be.test(t.charAt(g))?(ie=t.charAt(g),g++):(ie=r,ee===0&&b(we));return ee--,Z===r&&(ie=r,ee===0&&b(he)),Z}if(Ie=a(),Ie!==r&&g===t.length)return Ie;throw Ie!==r&&g<t.length&&b(He()),S(ne,ce<t.length?t.charAt(ce):null,ce<t.length?qe(ce,ce+1):qe(ce,ce))}ZJ.exports={SyntaxError:Ad,parse:g5e}});var eX=_(DP=>{var{parse:d5e}=$J();DP.makeParser=(t=/[a-z]+/)=>(e,r)=>d5e(e,{queryPattern:t,checkFn:r});DP.parse=DP.makeParser()});var rX=_((SQt,tX)=>{\"use strict\";tX.exports={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]}});var AL=_((bQt,iX)=>{var vI=rX(),nX={};for(let t of Object.keys(vI))nX[vI[t]]=t;var Ar={rgb:{channels:3,labels:\"rgb\"},hsl:{channels:3,labels:\"hsl\"},hsv:{channels:3,labels:\"hsv\"},hwb:{channels:3,labels:\"hwb\"},cmyk:{channels:4,labels:\"cmyk\"},xyz:{channels:3,labels:\"xyz\"},lab:{channels:3,labels:\"lab\"},lch:{channels:3,labels:\"lch\"},hex:{channels:1,labels:[\"hex\"]},keyword:{channels:1,labels:[\"keyword\"]},ansi16:{channels:1,labels:[\"ansi16\"]},ansi256:{channels:1,labels:[\"ansi256\"]},hcg:{channels:3,labels:[\"h\",\"c\",\"g\"]},apple:{channels:3,labels:[\"r16\",\"g16\",\"b16\"]},gray:{channels:1,labels:[\"gray\"]}};iX.exports=Ar;for(let t of Object.keys(Ar)){if(!(\"channels\"in Ar[t]))throw new Error(\"missing channels property: \"+t);if(!(\"labels\"in Ar[t]))throw new Error(\"missing channel labels property: \"+t);if(Ar[t].labels.length!==Ar[t].channels)throw new Error(\"channel and label counts mismatch: \"+t);let{channels:e,labels:r}=Ar[t];delete Ar[t].channels,delete Ar[t].labels,Object.defineProperty(Ar[t],\"channels\",{value:e}),Object.defineProperty(Ar[t],\"labels\",{value:r})}Ar.rgb.hsl=function(t){let e=t[0]/255,r=t[1]/255,o=t[2]/255,a=Math.min(e,r,o),n=Math.max(e,r,o),u=n-a,A,p;n===a?A=0:e===n?A=(r-o)/u:r===n?A=2+(o-e)/u:o===n&&(A=4+(e-r)/u),A=Math.min(A*60,360),A<0&&(A+=360);let h=(a+n)/2;return n===a?p=0:h<=.5?p=u/(n+a):p=u/(2-n-a),[A,p*100,h*100]};Ar.rgb.hsv=function(t){let e,r,o,a,n,u=t[0]/255,A=t[1]/255,p=t[2]/255,h=Math.max(u,A,p),E=h-Math.min(u,A,p),I=function(v){return(h-v)/6/E+1/2};return E===0?(a=0,n=0):(n=E/h,e=I(u),r=I(A),o=I(p),u===h?a=o-r:A===h?a=1/3+e-o:p===h&&(a=2/3+r-e),a<0?a+=1:a>1&&(a-=1)),[a*360,n*100,h*100]};Ar.rgb.hwb=function(t){let e=t[0],r=t[1],o=t[2],a=Ar.rgb.hsl(t)[0],n=1/255*Math.min(e,Math.min(r,o));return o=1-1/255*Math.max(e,Math.max(r,o)),[a,n*100,o*100]};Ar.rgb.cmyk=function(t){let e=t[0]/255,r=t[1]/255,o=t[2]/255,a=Math.min(1-e,1-r,1-o),n=(1-e-a)/(1-a)||0,u=(1-r-a)/(1-a)||0,A=(1-o-a)/(1-a)||0;return[n*100,u*100,A*100,a*100]};function m5e(t,e){return(t[0]-e[0])**2+(t[1]-e[1])**2+(t[2]-e[2])**2}Ar.rgb.keyword=function(t){let e=nX[t];if(e)return e;let r=1/0,o;for(let a of Object.keys(vI)){let n=vI[a],u=m5e(t,n);u<r&&(r=u,o=a)}return o};Ar.keyword.rgb=function(t){return vI[t]};Ar.rgb.xyz=function(t){let e=t[0]/255,r=t[1]/255,o=t[2]/255;e=e>.04045?((e+.055)/1.055)**2.4:e/12.92,r=r>.04045?((r+.055)/1.055)**2.4:r/12.92,o=o>.04045?((o+.055)/1.055)**2.4:o/12.92;let a=e*.4124+r*.3576+o*.1805,n=e*.2126+r*.7152+o*.0722,u=e*.0193+r*.1192+o*.9505;return[a*100,n*100,u*100]};Ar.rgb.lab=function(t){let e=Ar.rgb.xyz(t),r=e[0],o=e[1],a=e[2];r/=95.047,o/=100,a/=108.883,r=r>.008856?r**(1/3):7.787*r+16/116,o=o>.008856?o**(1/3):7.787*o+16/116,a=a>.008856?a**(1/3):7.787*a+16/116;let n=116*o-16,u=500*(r-o),A=200*(o-a);return[n,u,A]};Ar.hsl.rgb=function(t){let e=t[0]/360,r=t[1]/100,o=t[2]/100,a,n,u;if(r===0)return u=o*255,[u,u,u];o<.5?a=o*(1+r):a=o+r-o*r;let A=2*o-a,p=[0,0,0];for(let h=0;h<3;h++)n=e+1/3*-(h-1),n<0&&n++,n>1&&n--,6*n<1?u=A+(a-A)*6*n:2*n<1?u=a:3*n<2?u=A+(a-A)*(2/3-n)*6:u=A,p[h]=u*255;return p};Ar.hsl.hsv=function(t){let e=t[0],r=t[1]/100,o=t[2]/100,a=r,n=Math.max(o,.01);o*=2,r*=o<=1?o:2-o,a*=n<=1?n:2-n;let u=(o+r)/2,A=o===0?2*a/(n+a):2*r/(o+r);return[e,A*100,u*100]};Ar.hsv.rgb=function(t){let e=t[0]/60,r=t[1]/100,o=t[2]/100,a=Math.floor(e)%6,n=e-Math.floor(e),u=255*o*(1-r),A=255*o*(1-r*n),p=255*o*(1-r*(1-n));switch(o*=255,a){case 0:return[o,p,u];case 1:return[A,o,u];case 2:return[u,o,p];case 3:return[u,A,o];case 4:return[p,u,o];case 5:return[o,u,A]}};Ar.hsv.hsl=function(t){let e=t[0],r=t[1]/100,o=t[2]/100,a=Math.max(o,.01),n,u;u=(2-r)*o;let A=(2-r)*a;return n=r*a,n/=A<=1?A:2-A,n=n||0,u/=2,[e,n*100,u*100]};Ar.hwb.rgb=function(t){let e=t[0]/360,r=t[1]/100,o=t[2]/100,a=r+o,n;a>1&&(r/=a,o/=a);let u=Math.floor(6*e),A=1-o;n=6*e-u,(u&1)!==0&&(n=1-n);let p=r+n*(A-r),h,E,I;switch(u){default:case 6:case 0:h=A,E=p,I=r;break;case 1:h=p,E=A,I=r;break;case 2:h=r,E=A,I=p;break;case 3:h=r,E=p,I=A;break;case 4:h=p,E=r,I=A;break;case 5:h=A,E=r,I=p;break}return[h*255,E*255,I*255]};Ar.cmyk.rgb=function(t){let e=t[0]/100,r=t[1]/100,o=t[2]/100,a=t[3]/100,n=1-Math.min(1,e*(1-a)+a),u=1-Math.min(1,r*(1-a)+a),A=1-Math.min(1,o*(1-a)+a);return[n*255,u*255,A*255]};Ar.xyz.rgb=function(t){let e=t[0]/100,r=t[1]/100,o=t[2]/100,a,n,u;return a=e*3.2406+r*-1.5372+o*-.4986,n=e*-.9689+r*1.8758+o*.0415,u=e*.0557+r*-.204+o*1.057,a=a>.0031308?1.055*a**(1/2.4)-.055:a*12.92,n=n>.0031308?1.055*n**(1/2.4)-.055:n*12.92,u=u>.0031308?1.055*u**(1/2.4)-.055:u*12.92,a=Math.min(Math.max(0,a),1),n=Math.min(Math.max(0,n),1),u=Math.min(Math.max(0,u),1),[a*255,n*255,u*255]};Ar.xyz.lab=function(t){let e=t[0],r=t[1],o=t[2];e/=95.047,r/=100,o/=108.883,e=e>.008856?e**(1/3):7.787*e+16/116,r=r>.008856?r**(1/3):7.787*r+16/116,o=o>.008856?o**(1/3):7.787*o+16/116;let a=116*r-16,n=500*(e-r),u=200*(r-o);return[a,n,u]};Ar.lab.xyz=function(t){let e=t[0],r=t[1],o=t[2],a,n,u;n=(e+16)/116,a=r/500+n,u=n-o/200;let A=n**3,p=a**3,h=u**3;return n=A>.008856?A:(n-16/116)/7.787,a=p>.008856?p:(a-16/116)/7.787,u=h>.008856?h:(u-16/116)/7.787,a*=95.047,n*=100,u*=108.883,[a,n,u]};Ar.lab.lch=function(t){let e=t[0],r=t[1],o=t[2],a;a=Math.atan2(o,r)*360/2/Math.PI,a<0&&(a+=360);let u=Math.sqrt(r*r+o*o);return[e,u,a]};Ar.lch.lab=function(t){let e=t[0],r=t[1],a=t[2]/360*2*Math.PI,n=r*Math.cos(a),u=r*Math.sin(a);return[e,n,u]};Ar.rgb.ansi16=function(t,e=null){let[r,o,a]=t,n=e===null?Ar.rgb.hsv(t)[2]:e;if(n=Math.round(n/50),n===0)return 30;let u=30+(Math.round(a/255)<<2|Math.round(o/255)<<1|Math.round(r/255));return n===2&&(u+=60),u};Ar.hsv.ansi16=function(t){return Ar.rgb.ansi16(Ar.hsv.rgb(t),t[2])};Ar.rgb.ansi256=function(t){let e=t[0],r=t[1],o=t[2];return e===r&&r===o?e<8?16:e>248?231:Math.round((e-8)/247*24)+232:16+36*Math.round(e/255*5)+6*Math.round(r/255*5)+Math.round(o/255*5)};Ar.ansi16.rgb=function(t){let e=t%10;if(e===0||e===7)return t>50&&(e+=3.5),e=e/10.5*255,[e,e,e];let r=(~~(t>50)+1)*.5,o=(e&1)*r*255,a=(e>>1&1)*r*255,n=(e>>2&1)*r*255;return[o,a,n]};Ar.ansi256.rgb=function(t){if(t>=232){let n=(t-232)*10+8;return[n,n,n]}t-=16;let e,r=Math.floor(t/36)/5*255,o=Math.floor((e=t%36)/6)/5*255,a=e%6/5*255;return[r,o,a]};Ar.rgb.hex=function(t){let r=(((Math.round(t[0])&255)<<16)+((Math.round(t[1])&255)<<8)+(Math.round(t[2])&255)).toString(16).toUpperCase();return\"000000\".substring(r.length)+r};Ar.hex.rgb=function(t){let e=t.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);if(!e)return[0,0,0];let r=e[0];e[0].length===3&&(r=r.split(\"\").map(A=>A+A).join(\"\"));let o=parseInt(r,16),a=o>>16&255,n=o>>8&255,u=o&255;return[a,n,u]};Ar.rgb.hcg=function(t){let e=t[0]/255,r=t[1]/255,o=t[2]/255,a=Math.max(Math.max(e,r),o),n=Math.min(Math.min(e,r),o),u=a-n,A,p;return u<1?A=n/(1-u):A=0,u<=0?p=0:a===e?p=(r-o)/u%6:a===r?p=2+(o-e)/u:p=4+(e-r)/u,p/=6,p%=1,[p*360,u*100,A*100]};Ar.hsl.hcg=function(t){let e=t[1]/100,r=t[2]/100,o=r<.5?2*e*r:2*e*(1-r),a=0;return o<1&&(a=(r-.5*o)/(1-o)),[t[0],o*100,a*100]};Ar.hsv.hcg=function(t){let e=t[1]/100,r=t[2]/100,o=e*r,a=0;return o<1&&(a=(r-o)/(1-o)),[t[0],o*100,a*100]};Ar.hcg.rgb=function(t){let e=t[0]/360,r=t[1]/100,o=t[2]/100;if(r===0)return[o*255,o*255,o*255];let a=[0,0,0],n=e%1*6,u=n%1,A=1-u,p=0;switch(Math.floor(n)){case 0:a[0]=1,a[1]=u,a[2]=0;break;case 1:a[0]=A,a[1]=1,a[2]=0;break;case 2:a[0]=0,a[1]=1,a[2]=u;break;case 3:a[0]=0,a[1]=A,a[2]=1;break;case 4:a[0]=u,a[1]=0,a[2]=1;break;default:a[0]=1,a[1]=0,a[2]=A}return p=(1-r)*o,[(r*a[0]+p)*255,(r*a[1]+p)*255,(r*a[2]+p)*255]};Ar.hcg.hsv=function(t){let e=t[1]/100,r=t[2]/100,o=e+r*(1-e),a=0;return o>0&&(a=e/o),[t[0],a*100,o*100]};Ar.hcg.hsl=function(t){let e=t[1]/100,o=t[2]/100*(1-e)+.5*e,a=0;return o>0&&o<.5?a=e/(2*o):o>=.5&&o<1&&(a=e/(2*(1-o))),[t[0],a*100,o*100]};Ar.hcg.hwb=function(t){let e=t[1]/100,r=t[2]/100,o=e+r*(1-e);return[t[0],(o-e)*100,(1-o)*100]};Ar.hwb.hcg=function(t){let e=t[1]/100,o=1-t[2]/100,a=o-e,n=0;return a<1&&(n=(o-a)/(1-a)),[t[0],a*100,n*100]};Ar.apple.rgb=function(t){return[t[0]/65535*255,t[1]/65535*255,t[2]/65535*255]};Ar.rgb.apple=function(t){return[t[0]/255*65535,t[1]/255*65535,t[2]/255*65535]};Ar.gray.rgb=function(t){return[t[0]/100*255,t[0]/100*255,t[0]/100*255]};Ar.gray.hsl=function(t){return[0,0,t[0]]};Ar.gray.hsv=Ar.gray.hsl;Ar.gray.hwb=function(t){return[0,100,t[0]]};Ar.gray.cmyk=function(t){return[0,0,0,t[0]]};Ar.gray.lab=function(t){return[t[0],0,0]};Ar.gray.hex=function(t){let e=Math.round(t[0]/100*255)&255,o=((e<<16)+(e<<8)+e).toString(16).toUpperCase();return\"000000\".substring(o.length)+o};Ar.rgb.gray=function(t){return[(t[0]+t[1]+t[2])/3/255*100]}});var oX=_((xQt,sX)=>{var PP=AL();function y5e(){let t={},e=Object.keys(PP);for(let r=e.length,o=0;o<r;o++)t[e[o]]={distance:-1,parent:null};return t}function E5e(t){let e=y5e(),r=[t];for(e[t].distance=0;r.length;){let o=r.pop(),a=Object.keys(PP[o]);for(let n=a.length,u=0;u<n;u++){let A=a[u],p=e[A];p.distance===-1&&(p.distance=e[o].distance+1,p.parent=o,r.unshift(A))}}return e}function C5e(t,e){return function(r){return e(t(r))}}function w5e(t,e){let r=[e[t].parent,t],o=PP[e[t].parent][t],a=e[t].parent;for(;e[a].parent;)r.unshift(e[a].parent),o=C5e(PP[e[a].parent][a],o),a=e[a].parent;return o.conversion=r,o}sX.exports=function(t){let e=E5e(t),r={},o=Object.keys(e);for(let a=o.length,n=0;n<a;n++){let u=o[n];e[u].parent!==null&&(r[u]=w5e(u,e))}return r}});var lX=_((kQt,aX)=>{var fL=AL(),I5e=oX(),xy={},B5e=Object.keys(fL);function v5e(t){let e=function(...r){let o=r[0];return o==null?o:(o.length>1&&(r=o),t(r))};return\"conversion\"in t&&(e.conversion=t.conversion),e}function D5e(t){let e=function(...r){let o=r[0];if(o==null)return o;o.length>1&&(r=o);let a=t(r);if(typeof a==\"object\")for(let n=a.length,u=0;u<n;u++)a[u]=Math.round(a[u]);return a};return\"conversion\"in t&&(e.conversion=t.conversion),e}B5e.forEach(t=>{xy[t]={},Object.defineProperty(xy[t],\"channels\",{value:fL[t].channels}),Object.defineProperty(xy[t],\"labels\",{value:fL[t].labels});let e=I5e(t);Object.keys(e).forEach(o=>{let a=e[o];xy[t][o]=D5e(a),xy[t][o].raw=v5e(a)})});aX.exports=xy});var DI=_((QQt,pX)=>{\"use strict\";var cX=(t,e)=>(...r)=>`\\x1B[${t(...r)+e}m`,uX=(t,e)=>(...r)=>{let o=t(...r);return`\\x1B[${38+e};5;${o}m`},AX=(t,e)=>(...r)=>{let o=t(...r);return`\\x1B[${38+e};2;${o[0]};${o[1]};${o[2]}m`},SP=t=>t,fX=(t,e,r)=>[t,e,r],ky=(t,e,r)=>{Object.defineProperty(t,e,{get:()=>{let o=r();return Object.defineProperty(t,e,{value:o,enumerable:!0,configurable:!0}),o},enumerable:!0,configurable:!0})},pL,Qy=(t,e,r,o)=>{pL===void 0&&(pL=lX());let a=o?10:0,n={};for(let[u,A]of Object.entries(pL)){let p=u===\"ansi16\"?\"ansi\":u;u===e?n[p]=t(r,a):typeof A==\"object\"&&(n[p]=t(A[e],a))}return n};function P5e(){let t=new Map,e={modifier:{reset:[0,0],bold:[1,22],dim:[2,22],italic:[3,23],underline:[4,24],inverse:[7,27],hidden:[8,28],strikethrough:[9,29]},color:{black:[30,39],red:[31,39],green:[32,39],yellow:[33,39],blue:[34,39],magenta:[35,39],cyan:[36,39],white:[37,39],blackBright:[90,39],redBright:[91,39],greenBright:[92,39],yellowBright:[93,39],blueBright:[94,39],magentaBright:[95,39],cyanBright:[96,39],whiteBright:[97,39]},bgColor:{bgBlack:[40,49],bgRed:[41,49],bgGreen:[42,49],bgYellow:[43,49],bgBlue:[44,49],bgMagenta:[45,49],bgCyan:[46,49],bgWhite:[47,49],bgBlackBright:[100,49],bgRedBright:[101,49],bgGreenBright:[102,49],bgYellowBright:[103,49],bgBlueBright:[104,49],bgMagentaBright:[105,49],bgCyanBright:[106,49],bgWhiteBright:[107,49]}};e.color.gray=e.color.blackBright,e.bgColor.bgGray=e.bgColor.bgBlackBright,e.color.grey=e.color.blackBright,e.bgColor.bgGrey=e.bgColor.bgBlackBright;for(let[r,o]of Object.entries(e)){for(let[a,n]of Object.entries(o))e[a]={open:`\\x1B[${n[0]}m`,close:`\\x1B[${n[1]}m`},o[a]=e[a],t.set(n[0],n[1]);Object.defineProperty(e,r,{value:o,enumerable:!1})}return Object.defineProperty(e,\"codes\",{value:t,enumerable:!1}),e.color.close=\"\\x1B[39m\",e.bgColor.close=\"\\x1B[49m\",ky(e.color,\"ansi\",()=>Qy(cX,\"ansi16\",SP,!1)),ky(e.color,\"ansi256\",()=>Qy(uX,\"ansi256\",SP,!1)),ky(e.color,\"ansi16m\",()=>Qy(AX,\"rgb\",fX,!1)),ky(e.bgColor,\"ansi\",()=>Qy(cX,\"ansi16\",SP,!0)),ky(e.bgColor,\"ansi256\",()=>Qy(uX,\"ansi256\",SP,!0)),ky(e.bgColor,\"ansi16m\",()=>Qy(AX,\"rgb\",fX,!0)),e}Object.defineProperty(pX,\"exports\",{enumerable:!0,get:P5e})});var gX=_((FQt,hX)=>{\"use strict\";hX.exports=(t,e=process.argv)=>{let r=t.startsWith(\"-\")?\"\":t.length===1?\"-\":\"--\",o=e.indexOf(r+t),a=e.indexOf(\"--\");return o!==-1&&(a===-1||o<a)}});var dL=_((RQt,mX)=>{\"use strict\";var S5e=ve(\"os\"),dX=ve(\"tty\"),Ul=gX(),{env:ls}=process,Jp;Ul(\"no-color\")||Ul(\"no-colors\")||Ul(\"color=false\")||Ul(\"color=never\")?Jp=0:(Ul(\"color\")||Ul(\"colors\")||Ul(\"color=true\")||Ul(\"color=always\"))&&(Jp=1);\"FORCE_COLOR\"in ls&&(ls.FORCE_COLOR===\"true\"?Jp=1:ls.FORCE_COLOR===\"false\"?Jp=0:Jp=ls.FORCE_COLOR.length===0?1:Math.min(parseInt(ls.FORCE_COLOR,10),3));function hL(t){return t===0?!1:{level:t,hasBasic:!0,has256:t>=2,has16m:t>=3}}function gL(t,e){if(Jp===0)return 0;if(Ul(\"color=16m\")||Ul(\"color=full\")||Ul(\"color=truecolor\"))return 3;if(Ul(\"color=256\"))return 2;if(t&&!e&&Jp===void 0)return 0;let r=Jp||0;if(ls.TERM===\"dumb\")return r;if(process.platform===\"win32\"){let o=S5e.release().split(\".\");return Number(o[0])>=10&&Number(o[2])>=10586?Number(o[2])>=14931?3:2:1}if(\"CI\"in ls)return[\"TRAVIS\",\"CIRCLECI\",\"APPVEYOR\",\"GITLAB_CI\"].some(o=>o in ls)||ls.CI_NAME===\"codeship\"?1:r;if(\"TEAMCITY_VERSION\"in ls)return/^(9\\.(0*[1-9]\\d*)\\.|\\d{2,}\\.)/.test(ls.TEAMCITY_VERSION)?1:0;if(\"GITHUB_ACTIONS\"in ls)return 1;if(ls.COLORTERM===\"truecolor\")return 3;if(\"TERM_PROGRAM\"in ls){let o=parseInt((ls.TERM_PROGRAM_VERSION||\"\").split(\".\")[0],10);switch(ls.TERM_PROGRAM){case\"iTerm.app\":return o>=3?3:2;case\"Apple_Terminal\":return 2}}return/-256(color)?$/i.test(ls.TERM)?2:/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(ls.TERM)||\"COLORTERM\"in ls?1:r}function b5e(t){let e=gL(t,t&&t.isTTY);return hL(e)}mX.exports={supportsColor:b5e,stdout:hL(gL(!0,dX.isatty(1))),stderr:hL(gL(!0,dX.isatty(2)))}});var EX=_((TQt,yX)=>{\"use strict\";var x5e=(t,e,r)=>{let o=t.indexOf(e);if(o===-1)return t;let a=e.length,n=0,u=\"\";do u+=t.substr(n,o-n)+e+r,n=o+a,o=t.indexOf(e,n);while(o!==-1);return u+=t.substr(n),u},k5e=(t,e,r,o)=>{let a=0,n=\"\";do{let u=t[o-1]===\"\\r\";n+=t.substr(a,(u?o-1:o)-a)+e+(u?`\\r\n`:`\n`)+r,a=o+1,o=t.indexOf(`\n`,a)}while(o!==-1);return n+=t.substr(a),n};yX.exports={stringReplaceAll:x5e,stringEncaseCRLFWithFirstIndex:k5e}});var vX=_((LQt,BX)=>{\"use strict\";var Q5e=/(?:\\\\(u(?:[a-f\\d]{4}|\\{[a-f\\d]{1,6}\\})|x[a-f\\d]{2}|.))|(?:\\{(~)?(\\w+(?:\\([^)]*\\))?(?:\\.\\w+(?:\\([^)]*\\))?)*)(?:[ \\t]|(?=\\r?\\n)))|(\\})|((?:.|[\\r\\n\\f])+?)/gi,CX=/(?:^|\\.)(\\w+)(?:\\(([^)]*)\\))?/g,F5e=/^(['\"])((?:\\\\.|(?!\\1)[^\\\\])*)\\1$/,R5e=/\\\\(u(?:[a-f\\d]{4}|\\{[a-f\\d]{1,6}\\})|x[a-f\\d]{2}|.)|([^\\\\])/gi,T5e=new Map([[\"n\",`\n`],[\"r\",\"\\r\"],[\"t\",\"\t\"],[\"b\",\"\\b\"],[\"f\",\"\\f\"],[\"v\",\"\\v\"],[\"0\",\"\\0\"],[\"\\\\\",\"\\\\\"],[\"e\",\"\\x1B\"],[\"a\",\"\\x07\"]]);function IX(t){let e=t[0]===\"u\",r=t[1]===\"{\";return e&&!r&&t.length===5||t[0]===\"x\"&&t.length===3?String.fromCharCode(parseInt(t.slice(1),16)):e&&r?String.fromCodePoint(parseInt(t.slice(2,-1),16)):T5e.get(t)||t}function L5e(t,e){let r=[],o=e.trim().split(/\\s*,\\s*/g),a;for(let n of o){let u=Number(n);if(!Number.isNaN(u))r.push(u);else if(a=n.match(F5e))r.push(a[2].replace(R5e,(A,p,h)=>p?IX(p):h));else throw new Error(`Invalid Chalk template style argument: ${n} (in style '${t}')`)}return r}function N5e(t){CX.lastIndex=0;let e=[],r;for(;(r=CX.exec(t))!==null;){let o=r[1];if(r[2]){let a=L5e(o,r[2]);e.push([o].concat(a))}else e.push([o])}return e}function wX(t,e){let r={};for(let a of e)for(let n of a.styles)r[n[0]]=a.inverse?null:n.slice(1);let o=t;for(let[a,n]of Object.entries(r))if(!!Array.isArray(n)){if(!(a in o))throw new Error(`Unknown Chalk style: ${a}`);o=n.length>0?o[a](...n):o[a]}return o}BX.exports=(t,e)=>{let r=[],o=[],a=[];if(e.replace(Q5e,(n,u,A,p,h,E)=>{if(u)a.push(IX(u));else if(p){let I=a.join(\"\");a=[],o.push(r.length===0?I:wX(t,r)(I)),r.push({inverse:A,styles:N5e(p)})}else if(h){if(r.length===0)throw new Error(\"Found extraneous } in Chalk template literal\");o.push(wX(t,r)(a.join(\"\"))),a=[],r.pop()}else a.push(E)}),o.push(a.join(\"\")),r.length>0){let n=`Chalk template literal is missing ${r.length} closing bracket${r.length===1?\"\":\"s\"} (\\`}\\`)`;throw new Error(n)}return o.join(\"\")}});var IL=_((NQt,bX)=>{\"use strict\";var PI=DI(),{stdout:yL,stderr:EL}=dL(),{stringReplaceAll:O5e,stringEncaseCRLFWithFirstIndex:M5e}=EX(),DX=[\"ansi\",\"ansi\",\"ansi256\",\"ansi16m\"],Fy=Object.create(null),U5e=(t,e={})=>{if(e.level>3||e.level<0)throw new Error(\"The `level` option should be an integer from 0 to 3\");let r=yL?yL.level:0;t.level=e.level===void 0?r:e.level},CL=class{constructor(e){return PX(e)}},PX=t=>{let e={};return U5e(e,t),e.template=(...r)=>q5e(e.template,...r),Object.setPrototypeOf(e,bP.prototype),Object.setPrototypeOf(e.template,e),e.template.constructor=()=>{throw new Error(\"`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.\")},e.template.Instance=CL,e.template};function bP(t){return PX(t)}for(let[t,e]of Object.entries(PI))Fy[t]={get(){let r=xP(this,wL(e.open,e.close,this._styler),this._isEmpty);return Object.defineProperty(this,t,{value:r}),r}};Fy.visible={get(){let t=xP(this,this._styler,!0);return Object.defineProperty(this,\"visible\",{value:t}),t}};var SX=[\"rgb\",\"hex\",\"keyword\",\"hsl\",\"hsv\",\"hwb\",\"ansi\",\"ansi256\"];for(let t of SX)Fy[t]={get(){let{level:e}=this;return function(...r){let o=wL(PI.color[DX[e]][t](...r),PI.color.close,this._styler);return xP(this,o,this._isEmpty)}}};for(let t of SX){let e=\"bg\"+t[0].toUpperCase()+t.slice(1);Fy[e]={get(){let{level:r}=this;return function(...o){let a=wL(PI.bgColor[DX[r]][t](...o),PI.bgColor.close,this._styler);return xP(this,a,this._isEmpty)}}}}var _5e=Object.defineProperties(()=>{},{...Fy,level:{enumerable:!0,get(){return this._generator.level},set(t){this._generator.level=t}}}),wL=(t,e,r)=>{let o,a;return r===void 0?(o=t,a=e):(o=r.openAll+t,a=e+r.closeAll),{open:t,close:e,openAll:o,closeAll:a,parent:r}},xP=(t,e,r)=>{let o=(...a)=>H5e(o,a.length===1?\"\"+a[0]:a.join(\" \"));return o.__proto__=_5e,o._generator=t,o._styler=e,o._isEmpty=r,o},H5e=(t,e)=>{if(t.level<=0||!e)return t._isEmpty?\"\":e;let r=t._styler;if(r===void 0)return e;let{openAll:o,closeAll:a}=r;if(e.indexOf(\"\\x1B\")!==-1)for(;r!==void 0;)e=O5e(e,r.close,r.open),r=r.parent;let n=e.indexOf(`\n`);return n!==-1&&(e=M5e(e,a,o,n)),o+e+a},mL,q5e=(t,...e)=>{let[r]=e;if(!Array.isArray(r))return e.join(\" \");let o=e.slice(1),a=[r.raw[0]];for(let n=1;n<r.length;n++)a.push(String(o[n-1]).replace(/[{}\\\\]/g,\"\\\\$&\"),String(r.raw[n]));return mL===void 0&&(mL=vX()),mL(t,a.join(\"\"))};Object.defineProperties(bP.prototype,Fy);var SI=bP();SI.supportsColor=yL;SI.stderr=bP({level:EL?EL.level:0});SI.stderr.supportsColor=EL;SI.Level={None:0,Basic:1,Ansi256:2,TrueColor:3,0:\"None\",1:\"Basic\",2:\"Ansi256\",3:\"TrueColor\"};bX.exports=SI});var kP=_(_l=>{\"use strict\";_l.isInteger=t=>typeof t==\"number\"?Number.isInteger(t):typeof t==\"string\"&&t.trim()!==\"\"?Number.isInteger(Number(t)):!1;_l.find=(t,e)=>t.nodes.find(r=>r.type===e);_l.exceedsLimit=(t,e,r=1,o)=>o===!1||!_l.isInteger(t)||!_l.isInteger(e)?!1:(Number(e)-Number(t))/Number(r)>=o;_l.escapeNode=(t,e=0,r)=>{let o=t.nodes[e];!o||(r&&o.type===r||o.type===\"open\"||o.type===\"close\")&&o.escaped!==!0&&(o.value=\"\\\\\"+o.value,o.escaped=!0)};_l.encloseBrace=t=>t.type!==\"brace\"?!1:t.commas>>0+t.ranges>>0===0?(t.invalid=!0,!0):!1;_l.isInvalidBrace=t=>t.type!==\"brace\"?!1:t.invalid===!0||t.dollar?!0:t.commas>>0+t.ranges>>0===0||t.open!==!0||t.close!==!0?(t.invalid=!0,!0):!1;_l.isOpenOrClose=t=>t.type===\"open\"||t.type===\"close\"?!0:t.open===!0||t.close===!0;_l.reduce=t=>t.reduce((e,r)=>(r.type===\"text\"&&e.push(r.value),r.type===\"range\"&&(r.type=\"text\"),e),[]);_l.flatten=(...t)=>{let e=[],r=o=>{for(let a=0;a<o.length;a++){let n=o[a];Array.isArray(n)?r(n,e):n!==void 0&&e.push(n)}return e};return r(t),e}});var QP=_((MQt,kX)=>{\"use strict\";var xX=kP();kX.exports=(t,e={})=>{let r=(o,a={})=>{let n=e.escapeInvalid&&xX.isInvalidBrace(a),u=o.invalid===!0&&e.escapeInvalid===!0,A=\"\";if(o.value)return(n||u)&&xX.isOpenOrClose(o)?\"\\\\\"+o.value:o.value;if(o.value)return o.value;if(o.nodes)for(let p of o.nodes)A+=r(p);return A};return r(t)}});var FX=_((UQt,QX)=>{\"use strict\";QX.exports=function(t){return typeof t==\"number\"?t-t===0:typeof t==\"string\"&&t.trim()!==\"\"?Number.isFinite?Number.isFinite(+t):isFinite(+t):!1}});var HX=_((_Qt,_X)=>{\"use strict\";var RX=FX(),fd=(t,e,r)=>{if(RX(t)===!1)throw new TypeError(\"toRegexRange: expected the first argument to be a number\");if(e===void 0||t===e)return String(t);if(RX(e)===!1)throw new TypeError(\"toRegexRange: expected the second argument to be a number.\");let o={relaxZeros:!0,...r};typeof o.strictZeros==\"boolean\"&&(o.relaxZeros=o.strictZeros===!1);let a=String(o.relaxZeros),n=String(o.shorthand),u=String(o.capture),A=String(o.wrap),p=t+\":\"+e+\"=\"+a+n+u+A;if(fd.cache.hasOwnProperty(p))return fd.cache[p].result;let h=Math.min(t,e),E=Math.max(t,e);if(Math.abs(h-E)===1){let R=t+\"|\"+e;return o.capture?`(${R})`:o.wrap===!1?R:`(?:${R})`}let I=UX(t)||UX(e),v={min:t,max:e,a:h,b:E},x=[],C=[];if(I&&(v.isPadded=I,v.maxLen=String(v.max).length),h<0){let R=E<0?Math.abs(E):1;C=TX(R,Math.abs(h),v,o),h=v.a=0}return E>=0&&(x=TX(h,E,v,o)),v.negatives=C,v.positives=x,v.result=G5e(C,x,o),o.capture===!0?v.result=`(${v.result})`:o.wrap!==!1&&x.length+C.length>1&&(v.result=`(?:${v.result})`),fd.cache[p]=v,v.result};function G5e(t,e,r){let o=BL(t,e,\"-\",!1,r)||[],a=BL(e,t,\"\",!1,r)||[],n=BL(t,e,\"-?\",!0,r)||[];return o.concat(n).concat(a).join(\"|\")}function j5e(t,e){let r=1,o=1,a=NX(t,r),n=new Set([e]);for(;t<=a&&a<=e;)n.add(a),r+=1,a=NX(t,r);for(a=OX(e+1,o)-1;t<a&&a<=e;)n.add(a),o+=1,a=OX(e+1,o)-1;return n=[...n],n.sort(K5e),n}function Y5e(t,e,r){if(t===e)return{pattern:t,count:[],digits:0};let o=W5e(t,e),a=o.length,n=\"\",u=0;for(let A=0;A<a;A++){let[p,h]=o[A];p===h?n+=p:p!==\"0\"||h!==\"9\"?n+=z5e(p,h,r):u++}return u&&(n+=r.shorthand===!0?\"\\\\d\":\"[0-9]\"),{pattern:n,count:[u],digits:a}}function TX(t,e,r,o){let a=j5e(t,e),n=[],u=t,A;for(let p=0;p<a.length;p++){let h=a[p],E=Y5e(String(u),String(h),o),I=\"\";if(!r.isPadded&&A&&A.pattern===E.pattern){A.count.length>1&&A.count.pop(),A.count.push(E.count[0]),A.string=A.pattern+MX(A.count),u=h+1;continue}r.isPadded&&(I=V5e(h,r,o)),E.string=I+E.pattern+MX(E.count),n.push(E),u=h+1,A=E}return n}function BL(t,e,r,o,a){let n=[];for(let u of t){let{string:A}=u;!o&&!LX(e,\"string\",A)&&n.push(r+A),o&&LX(e,\"string\",A)&&n.push(r+A)}return n}function W5e(t,e){let r=[];for(let o=0;o<t.length;o++)r.push([t[o],e[o]]);return r}function K5e(t,e){return t>e?1:e>t?-1:0}function LX(t,e,r){return t.some(o=>o[e]===r)}function NX(t,e){return Number(String(t).slice(0,-e)+\"9\".repeat(e))}function OX(t,e){return t-t%Math.pow(10,e)}function MX(t){let[e=0,r=\"\"]=t;return r||e>1?`{${e+(r?\",\"+r:\"\")}}`:\"\"}function z5e(t,e,r){return`[${t}${e-t===1?\"\":\"-\"}${e}]`}function UX(t){return/^-?(0+)\\d/.test(t)}function V5e(t,e,r){if(!e.isPadded)return t;let o=Math.abs(e.maxLen-String(t).length),a=r.relaxZeros!==!1;switch(o){case 0:return\"\";case 1:return a?\"0?\":\"0\";case 2:return a?\"0{0,2}\":\"00\";default:return a?`0{0,${o}}`:`0{${o}}`}}fd.cache={};fd.clearCache=()=>fd.cache={};_X.exports=fd});var PL=_((HQt,VX)=>{\"use strict\";var J5e=ve(\"util\"),jX=HX(),qX=t=>t!==null&&typeof t==\"object\"&&!Array.isArray(t),X5e=t=>e=>t===!0?Number(e):String(e),vL=t=>typeof t==\"number\"||typeof t==\"string\"&&t!==\"\",bI=t=>Number.isInteger(+t),DL=t=>{let e=`${t}`,r=-1;if(e[0]===\"-\"&&(e=e.slice(1)),e===\"0\")return!1;for(;e[++r]===\"0\";);return r>0},Z5e=(t,e,r)=>typeof t==\"string\"||typeof e==\"string\"?!0:r.stringify===!0,$5e=(t,e,r)=>{if(e>0){let o=t[0]===\"-\"?\"-\":\"\";o&&(t=t.slice(1)),t=o+t.padStart(o?e-1:e,\"0\")}return r===!1?String(t):t},GX=(t,e)=>{let r=t[0]===\"-\"?\"-\":\"\";for(r&&(t=t.slice(1),e--);t.length<e;)t=\"0\"+t;return r?\"-\"+t:t},e7e=(t,e)=>{t.negatives.sort((u,A)=>u<A?-1:u>A?1:0),t.positives.sort((u,A)=>u<A?-1:u>A?1:0);let r=e.capture?\"\":\"?:\",o=\"\",a=\"\",n;return t.positives.length&&(o=t.positives.join(\"|\")),t.negatives.length&&(a=`-(${r}${t.negatives.join(\"|\")})`),o&&a?n=`${o}|${a}`:n=o||a,e.wrap?`(${r}${n})`:n},YX=(t,e,r,o)=>{if(r)return jX(t,e,{wrap:!1,...o});let a=String.fromCharCode(t);if(t===e)return a;let n=String.fromCharCode(e);return`[${a}-${n}]`},WX=(t,e,r)=>{if(Array.isArray(t)){let o=r.wrap===!0,a=r.capture?\"\":\"?:\";return o?`(${a}${t.join(\"|\")})`:t.join(\"|\")}return jX(t,e,r)},KX=(...t)=>new RangeError(\"Invalid range arguments: \"+J5e.inspect(...t)),zX=(t,e,r)=>{if(r.strictRanges===!0)throw KX([t,e]);return[]},t7e=(t,e)=>{if(e.strictRanges===!0)throw new TypeError(`Expected step \"${t}\" to be a number`);return[]},r7e=(t,e,r=1,o={})=>{let a=Number(t),n=Number(e);if(!Number.isInteger(a)||!Number.isInteger(n)){if(o.strictRanges===!0)throw KX([t,e]);return[]}a===0&&(a=0),n===0&&(n=0);let u=a>n,A=String(t),p=String(e),h=String(r);r=Math.max(Math.abs(r),1);let E=DL(A)||DL(p)||DL(h),I=E?Math.max(A.length,p.length,h.length):0,v=E===!1&&Z5e(t,e,o)===!1,x=o.transform||X5e(v);if(o.toRegex&&r===1)return YX(GX(t,I),GX(e,I),!0,o);let C={negatives:[],positives:[]},R=V=>C[V<0?\"negatives\":\"positives\"].push(Math.abs(V)),N=[],U=0;for(;u?a>=n:a<=n;)o.toRegex===!0&&r>1?R(a):N.push($5e(x(a,U),I,v)),a=u?a-r:a+r,U++;return o.toRegex===!0?r>1?e7e(C,o):WX(N,null,{wrap:!1,...o}):N},n7e=(t,e,r=1,o={})=>{if(!bI(t)&&t.length>1||!bI(e)&&e.length>1)return zX(t,e,o);let a=o.transform||(v=>String.fromCharCode(v)),n=`${t}`.charCodeAt(0),u=`${e}`.charCodeAt(0),A=n>u,p=Math.min(n,u),h=Math.max(n,u);if(o.toRegex&&r===1)return YX(p,h,!1,o);let E=[],I=0;for(;A?n>=u:n<=u;)E.push(a(n,I)),n=A?n-r:n+r,I++;return o.toRegex===!0?WX(E,null,{wrap:!1,options:o}):E},FP=(t,e,r,o={})=>{if(e==null&&vL(t))return[t];if(!vL(t)||!vL(e))return zX(t,e,o);if(typeof r==\"function\")return FP(t,e,1,{transform:r});if(qX(r))return FP(t,e,0,r);let a={...o};return a.capture===!0&&(a.wrap=!0),r=r||a.step||1,bI(r)?bI(t)&&bI(e)?r7e(t,e,r,a):n7e(t,e,Math.max(Math.abs(r),1),a):r!=null&&!qX(r)?t7e(r,a):FP(t,e,1,r)};VX.exports=FP});var ZX=_((qQt,XX)=>{\"use strict\";var i7e=PL(),JX=kP(),s7e=(t,e={})=>{let r=(o,a={})=>{let n=JX.isInvalidBrace(a),u=o.invalid===!0&&e.escapeInvalid===!0,A=n===!0||u===!0,p=e.escapeInvalid===!0?\"\\\\\":\"\",h=\"\";if(o.isOpen===!0||o.isClose===!0)return p+o.value;if(o.type===\"open\")return A?p+o.value:\"(\";if(o.type===\"close\")return A?p+o.value:\")\";if(o.type===\"comma\")return o.prev.type===\"comma\"?\"\":A?o.value:\"|\";if(o.value)return o.value;if(o.nodes&&o.ranges>0){let E=JX.reduce(o.nodes),I=i7e(...E,{...e,wrap:!1,toRegex:!0});if(I.length!==0)return E.length>1&&I.length>1?`(${I})`:I}if(o.nodes)for(let E of o.nodes)h+=r(E,o);return h};return r(t)};XX.exports=s7e});var tZ=_((GQt,eZ)=>{\"use strict\";var o7e=PL(),$X=QP(),Ry=kP(),pd=(t=\"\",e=\"\",r=!1)=>{let o=[];if(t=[].concat(t),e=[].concat(e),!e.length)return t;if(!t.length)return r?Ry.flatten(e).map(a=>`{${a}}`):e;for(let a of t)if(Array.isArray(a))for(let n of a)o.push(pd(n,e,r));else for(let n of e)r===!0&&typeof n==\"string\"&&(n=`{${n}}`),o.push(Array.isArray(n)?pd(a,n,r):a+n);return Ry.flatten(o)},a7e=(t,e={})=>{let r=e.rangeLimit===void 0?1e3:e.rangeLimit,o=(a,n={})=>{a.queue=[];let u=n,A=n.queue;for(;u.type!==\"brace\"&&u.type!==\"root\"&&u.parent;)u=u.parent,A=u.queue;if(a.invalid||a.dollar){A.push(pd(A.pop(),$X(a,e)));return}if(a.type===\"brace\"&&a.invalid!==!0&&a.nodes.length===2){A.push(pd(A.pop(),[\"{}\"]));return}if(a.nodes&&a.ranges>0){let I=Ry.reduce(a.nodes);if(Ry.exceedsLimit(...I,e.step,r))throw new RangeError(\"expanded array length exceeds range limit. Use options.rangeLimit to increase or disable the limit.\");let v=o7e(...I,e);v.length===0&&(v=$X(a,e)),A.push(pd(A.pop(),v)),a.nodes=[];return}let p=Ry.encloseBrace(a),h=a.queue,E=a;for(;E.type!==\"brace\"&&E.type!==\"root\"&&E.parent;)E=E.parent,h=E.queue;for(let I=0;I<a.nodes.length;I++){let v=a.nodes[I];if(v.type===\"comma\"&&a.type===\"brace\"){I===1&&h.push(\"\"),h.push(\"\");continue}if(v.type===\"close\"){A.push(pd(A.pop(),h,p));continue}if(v.value&&v.type!==\"open\"){h.push(pd(h.pop(),v.value));continue}v.nodes&&o(v,a)}return h};return Ry.flatten(o(t))};eZ.exports=a7e});var nZ=_((jQt,rZ)=>{\"use strict\";rZ.exports={MAX_LENGTH:1024*64,CHAR_0:\"0\",CHAR_9:\"9\",CHAR_UPPERCASE_A:\"A\",CHAR_LOWERCASE_A:\"a\",CHAR_UPPERCASE_Z:\"Z\",CHAR_LOWERCASE_Z:\"z\",CHAR_LEFT_PARENTHESES:\"(\",CHAR_RIGHT_PARENTHESES:\")\",CHAR_ASTERISK:\"*\",CHAR_AMPERSAND:\"&\",CHAR_AT:\"@\",CHAR_BACKSLASH:\"\\\\\",CHAR_BACKTICK:\"`\",CHAR_CARRIAGE_RETURN:\"\\r\",CHAR_CIRCUMFLEX_ACCENT:\"^\",CHAR_COLON:\":\",CHAR_COMMA:\",\",CHAR_DOLLAR:\"$\",CHAR_DOT:\".\",CHAR_DOUBLE_QUOTE:'\"',CHAR_EQUAL:\"=\",CHAR_EXCLAMATION_MARK:\"!\",CHAR_FORM_FEED:\"\\f\",CHAR_FORWARD_SLASH:\"/\",CHAR_HASH:\"#\",CHAR_HYPHEN_MINUS:\"-\",CHAR_LEFT_ANGLE_BRACKET:\"<\",CHAR_LEFT_CURLY_BRACE:\"{\",CHAR_LEFT_SQUARE_BRACKET:\"[\",CHAR_LINE_FEED:`\n`,CHAR_NO_BREAK_SPACE:\"\\xA0\",CHAR_PERCENT:\"%\",CHAR_PLUS:\"+\",CHAR_QUESTION_MARK:\"?\",CHAR_RIGHT_ANGLE_BRACKET:\">\",CHAR_RIGHT_CURLY_BRACE:\"}\",CHAR_RIGHT_SQUARE_BRACKET:\"]\",CHAR_SEMICOLON:\";\",CHAR_SINGLE_QUOTE:\"'\",CHAR_SPACE:\" \",CHAR_TAB:\"\t\",CHAR_UNDERSCORE:\"_\",CHAR_VERTICAL_LINE:\"|\",CHAR_ZERO_WIDTH_NOBREAK_SPACE:\"\\uFEFF\"}});var lZ=_((YQt,aZ)=>{\"use strict\";var l7e=QP(),{MAX_LENGTH:iZ,CHAR_BACKSLASH:SL,CHAR_BACKTICK:c7e,CHAR_COMMA:u7e,CHAR_DOT:A7e,CHAR_LEFT_PARENTHESES:f7e,CHAR_RIGHT_PARENTHESES:p7e,CHAR_LEFT_CURLY_BRACE:h7e,CHAR_RIGHT_CURLY_BRACE:g7e,CHAR_LEFT_SQUARE_BRACKET:sZ,CHAR_RIGHT_SQUARE_BRACKET:oZ,CHAR_DOUBLE_QUOTE:d7e,CHAR_SINGLE_QUOTE:m7e,CHAR_NO_BREAK_SPACE:y7e,CHAR_ZERO_WIDTH_NOBREAK_SPACE:E7e}=nZ(),C7e=(t,e={})=>{if(typeof t!=\"string\")throw new TypeError(\"Expected a string\");let r=e||{},o=typeof r.maxLength==\"number\"?Math.min(iZ,r.maxLength):iZ;if(t.length>o)throw new SyntaxError(`Input length (${t.length}), exceeds max characters (${o})`);let a={type:\"root\",input:t,nodes:[]},n=[a],u=a,A=a,p=0,h=t.length,E=0,I=0,v,x={},C=()=>t[E++],R=N=>{if(N.type===\"text\"&&A.type===\"dot\"&&(A.type=\"text\"),A&&A.type===\"text\"&&N.type===\"text\"){A.value+=N.value;return}return u.nodes.push(N),N.parent=u,N.prev=A,A=N,N};for(R({type:\"bos\"});E<h;)if(u=n[n.length-1],v=C(),!(v===E7e||v===y7e)){if(v===SL){R({type:\"text\",value:(e.keepEscaping?v:\"\")+C()});continue}if(v===oZ){R({type:\"text\",value:\"\\\\\"+v});continue}if(v===sZ){p++;let N=!0,U;for(;E<h&&(U=C());){if(v+=U,U===sZ){p++;continue}if(U===SL){v+=C();continue}if(U===oZ&&(p--,p===0))break}R({type:\"text\",value:v});continue}if(v===f7e){u=R({type:\"paren\",nodes:[]}),n.push(u),R({type:\"text\",value:v});continue}if(v===p7e){if(u.type!==\"paren\"){R({type:\"text\",value:v});continue}u=n.pop(),R({type:\"text\",value:v}),u=n[n.length-1];continue}if(v===d7e||v===m7e||v===c7e){let N=v,U;for(e.keepQuotes!==!0&&(v=\"\");E<h&&(U=C());){if(U===SL){v+=U+C();continue}if(U===N){e.keepQuotes===!0&&(v+=U);break}v+=U}R({type:\"text\",value:v});continue}if(v===h7e){I++;let U={type:\"brace\",open:!0,close:!1,dollar:A.value&&A.value.slice(-1)===\"$\"||u.dollar===!0,depth:I,commas:0,ranges:0,nodes:[]};u=R(U),n.push(u),R({type:\"open\",value:v});continue}if(v===g7e){if(u.type!==\"brace\"){R({type:\"text\",value:v});continue}let N=\"close\";u=n.pop(),u.close=!0,R({type:N,value:v}),I--,u=n[n.length-1];continue}if(v===u7e&&I>0){if(u.ranges>0){u.ranges=0;let N=u.nodes.shift();u.nodes=[N,{type:\"text\",value:l7e(u)}]}R({type:\"comma\",value:v}),u.commas++;continue}if(v===A7e&&I>0&&u.commas===0){let N=u.nodes;if(I===0||N.length===0){R({type:\"text\",value:v});continue}if(A.type===\"dot\"){if(u.range=[],A.value+=v,A.type=\"range\",u.nodes.length!==3&&u.nodes.length!==5){u.invalid=!0,u.ranges=0,A.type=\"text\";continue}u.ranges++,u.args=[];continue}if(A.type===\"range\"){N.pop();let U=N[N.length-1];U.value+=A.value+v,A=U,u.ranges--;continue}R({type:\"dot\",value:v});continue}R({type:\"text\",value:v})}do if(u=n.pop(),u.type!==\"root\"){u.nodes.forEach(V=>{V.nodes||(V.type===\"open\"&&(V.isOpen=!0),V.type===\"close\"&&(V.isClose=!0),V.nodes||(V.type=\"text\"),V.invalid=!0)});let N=n[n.length-1],U=N.nodes.indexOf(u);N.nodes.splice(U,1,...u.nodes)}while(n.length>0);return R({type:\"eos\"}),a};aZ.exports=C7e});var AZ=_((WQt,uZ)=>{\"use strict\";var cZ=QP(),w7e=ZX(),I7e=tZ(),B7e=lZ(),nl=(t,e={})=>{let r=[];if(Array.isArray(t))for(let o of t){let a=nl.create(o,e);Array.isArray(a)?r.push(...a):r.push(a)}else r=[].concat(nl.create(t,e));return e&&e.expand===!0&&e.nodupes===!0&&(r=[...new Set(r)]),r};nl.parse=(t,e={})=>B7e(t,e);nl.stringify=(t,e={})=>cZ(typeof t==\"string\"?nl.parse(t,e):t,e);nl.compile=(t,e={})=>(typeof t==\"string\"&&(t=nl.parse(t,e)),w7e(t,e));nl.expand=(t,e={})=>{typeof t==\"string\"&&(t=nl.parse(t,e));let r=I7e(t,e);return e.noempty===!0&&(r=r.filter(Boolean)),e.nodupes===!0&&(r=[...new Set(r)]),r};nl.create=(t,e={})=>t===\"\"||t.length<3?[t]:e.expand!==!0?nl.compile(t,e):nl.expand(t,e);uZ.exports=nl});var xI=_((KQt,dZ)=>{\"use strict\";var v7e=ve(\"path\"),zu=\"\\\\\\\\/\",fZ=`[^${zu}]`,vf=\"\\\\.\",D7e=\"\\\\+\",P7e=\"\\\\?\",RP=\"\\\\/\",S7e=\"(?=.)\",pZ=\"[^/]\",bL=`(?:${RP}|$)`,hZ=`(?:^|${RP})`,xL=`${vf}{1,2}${bL}`,b7e=`(?!${vf})`,x7e=`(?!${hZ}${xL})`,k7e=`(?!${vf}{0,1}${bL})`,Q7e=`(?!${xL})`,F7e=`[^.${RP}]`,R7e=`${pZ}*?`,gZ={DOT_LITERAL:vf,PLUS_LITERAL:D7e,QMARK_LITERAL:P7e,SLASH_LITERAL:RP,ONE_CHAR:S7e,QMARK:pZ,END_ANCHOR:bL,DOTS_SLASH:xL,NO_DOT:b7e,NO_DOTS:x7e,NO_DOT_SLASH:k7e,NO_DOTS_SLASH:Q7e,QMARK_NO_DOT:F7e,STAR:R7e,START_ANCHOR:hZ},T7e={...gZ,SLASH_LITERAL:`[${zu}]`,QMARK:fZ,STAR:`${fZ}*?`,DOTS_SLASH:`${vf}{1,2}(?:[${zu}]|$)`,NO_DOT:`(?!${vf})`,NO_DOTS:`(?!(?:^|[${zu}])${vf}{1,2}(?:[${zu}]|$))`,NO_DOT_SLASH:`(?!${vf}{0,1}(?:[${zu}]|$))`,NO_DOTS_SLASH:`(?!${vf}{1,2}(?:[${zu}]|$))`,QMARK_NO_DOT:`[^.${zu}]`,START_ANCHOR:`(?:^|[${zu}])`,END_ANCHOR:`(?:[${zu}]|$)`},L7e={alnum:\"a-zA-Z0-9\",alpha:\"a-zA-Z\",ascii:\"\\\\x00-\\\\x7F\",blank:\" \\\\t\",cntrl:\"\\\\x00-\\\\x1F\\\\x7F\",digit:\"0-9\",graph:\"\\\\x21-\\\\x7E\",lower:\"a-z\",print:\"\\\\x20-\\\\x7E \",punct:\"\\\\-!\\\"#$%&'()\\\\*+,./:;<=>?@[\\\\]^_`{|}~\",space:\" \\\\t\\\\r\\\\n\\\\v\\\\f\",upper:\"A-Z\",word:\"A-Za-z0-9_\",xdigit:\"A-Fa-f0-9\"};dZ.exports={MAX_LENGTH:1024*64,POSIX_REGEX_SOURCE:L7e,REGEX_BACKSLASH:/\\\\(?![*+?^${}(|)[\\]])/g,REGEX_NON_SPECIAL_CHARS:/^[^@![\\].,$*+?^{}()|\\\\/]+/,REGEX_SPECIAL_CHARS:/[-*+?.^${}(|)[\\]]/,REGEX_SPECIAL_CHARS_BACKREF:/(\\\\?)((\\W)(\\3*))/g,REGEX_SPECIAL_CHARS_GLOBAL:/([-*+?.^${}(|)[\\]])/g,REGEX_REMOVE_BACKSLASH:/(?:\\[.*?[^\\\\]\\]|\\\\(?=.))/g,REPLACEMENTS:{\"***\":\"*\",\"**/**\":\"**\",\"**/**/**\":\"**\"},CHAR_0:48,CHAR_9:57,CHAR_UPPERCASE_A:65,CHAR_LOWERCASE_A:97,CHAR_UPPERCASE_Z:90,CHAR_LOWERCASE_Z:122,CHAR_LEFT_PARENTHESES:40,CHAR_RIGHT_PARENTHESES:41,CHAR_ASTERISK:42,CHAR_AMPERSAND:38,CHAR_AT:64,CHAR_BACKWARD_SLASH:92,CHAR_CARRIAGE_RETURN:13,CHAR_CIRCUMFLEX_ACCENT:94,CHAR_COLON:58,CHAR_COMMA:44,CHAR_DOT:46,CHAR_DOUBLE_QUOTE:34,CHAR_EQUAL:61,CHAR_EXCLAMATION_MARK:33,CHAR_FORM_FEED:12,CHAR_FORWARD_SLASH:47,CHAR_GRAVE_ACCENT:96,CHAR_HASH:35,CHAR_HYPHEN_MINUS:45,CHAR_LEFT_ANGLE_BRACKET:60,CHAR_LEFT_CURLY_BRACE:123,CHAR_LEFT_SQUARE_BRACKET:91,CHAR_LINE_FEED:10,CHAR_NO_BREAK_SPACE:160,CHAR_PERCENT:37,CHAR_PLUS:43,CHAR_QUESTION_MARK:63,CHAR_RIGHT_ANGLE_BRACKET:62,CHAR_RIGHT_CURLY_BRACE:125,CHAR_RIGHT_SQUARE_BRACKET:93,CHAR_SEMICOLON:59,CHAR_SINGLE_QUOTE:39,CHAR_SPACE:32,CHAR_TAB:9,CHAR_UNDERSCORE:95,CHAR_VERTICAL_LINE:124,CHAR_ZERO_WIDTH_NOBREAK_SPACE:65279,SEP:v7e.sep,extglobChars(t){return{\"!\":{type:\"negate\",open:\"(?:(?!(?:\",close:`))${t.STAR})`},\"?\":{type:\"qmark\",open:\"(?:\",close:\")?\"},\"+\":{type:\"plus\",open:\"(?:\",close:\")+\"},\"*\":{type:\"star\",open:\"(?:\",close:\")*\"},\"@\":{type:\"at\",open:\"(?:\",close:\")\"}}},globChars(t){return t===!0?T7e:gZ}}});var kI=_(Pa=>{\"use strict\";var N7e=ve(\"path\"),O7e=process.platform===\"win32\",{REGEX_BACKSLASH:M7e,REGEX_REMOVE_BACKSLASH:U7e,REGEX_SPECIAL_CHARS:_7e,REGEX_SPECIAL_CHARS_GLOBAL:H7e}=xI();Pa.isObject=t=>t!==null&&typeof t==\"object\"&&!Array.isArray(t);Pa.hasRegexChars=t=>_7e.test(t);Pa.isRegexChar=t=>t.length===1&&Pa.hasRegexChars(t);Pa.escapeRegex=t=>t.replace(H7e,\"\\\\$1\");Pa.toPosixSlashes=t=>t.replace(M7e,\"/\");Pa.removeBackslashes=t=>t.replace(U7e,e=>e===\"\\\\\"?\"\":e);Pa.supportsLookbehinds=()=>{let t=process.version.slice(1).split(\".\").map(Number);return t.length===3&&t[0]>=9||t[0]===8&&t[1]>=10};Pa.isWindows=t=>t&&typeof t.windows==\"boolean\"?t.windows:O7e===!0||N7e.sep===\"\\\\\";Pa.escapeLast=(t,e,r)=>{let o=t.lastIndexOf(e,r);return o===-1?t:t[o-1]===\"\\\\\"?Pa.escapeLast(t,e,o-1):`${t.slice(0,o)}\\\\${t.slice(o)}`};Pa.removePrefix=(t,e={})=>{let r=t;return r.startsWith(\"./\")&&(r=r.slice(2),e.prefix=\"./\"),r};Pa.wrapOutput=(t,e={},r={})=>{let o=r.contains?\"\":\"^\",a=r.contains?\"\":\"$\",n=`${o}(?:${t})${a}`;return e.negated===!0&&(n=`(?:^(?!${n}).*$)`),n}});var vZ=_((VQt,BZ)=>{\"use strict\";var mZ=kI(),{CHAR_ASTERISK:kL,CHAR_AT:q7e,CHAR_BACKWARD_SLASH:QI,CHAR_COMMA:G7e,CHAR_DOT:QL,CHAR_EXCLAMATION_MARK:FL,CHAR_FORWARD_SLASH:IZ,CHAR_LEFT_CURLY_BRACE:RL,CHAR_LEFT_PARENTHESES:TL,CHAR_LEFT_SQUARE_BRACKET:j7e,CHAR_PLUS:Y7e,CHAR_QUESTION_MARK:yZ,CHAR_RIGHT_CURLY_BRACE:W7e,CHAR_RIGHT_PARENTHESES:EZ,CHAR_RIGHT_SQUARE_BRACKET:K7e}=xI(),CZ=t=>t===IZ||t===QI,wZ=t=>{t.isPrefix!==!0&&(t.depth=t.isGlobstar?1/0:1)},z7e=(t,e)=>{let r=e||{},o=t.length-1,a=r.parts===!0||r.scanToEnd===!0,n=[],u=[],A=[],p=t,h=-1,E=0,I=0,v=!1,x=!1,C=!1,R=!1,N=!1,U=!1,V=!1,te=!1,ae=!1,fe=!1,ue=0,me,he,Be={value:\"\",depth:0,isGlob:!1},we=()=>h>=o,g=()=>p.charCodeAt(h+1),Ee=()=>(me=he,p.charCodeAt(++h));for(;h<o;){he=Ee();let Ie;if(he===QI){V=Be.backslashes=!0,he=Ee(),he===RL&&(U=!0);continue}if(U===!0||he===RL){for(ue++;we()!==!0&&(he=Ee());){if(he===QI){V=Be.backslashes=!0,Ee();continue}if(he===RL){ue++;continue}if(U!==!0&&he===QL&&(he=Ee())===QL){if(v=Be.isBrace=!0,C=Be.isGlob=!0,fe=!0,a===!0)continue;break}if(U!==!0&&he===G7e){if(v=Be.isBrace=!0,C=Be.isGlob=!0,fe=!0,a===!0)continue;break}if(he===W7e&&(ue--,ue===0)){U=!1,v=Be.isBrace=!0,fe=!0;break}}if(a===!0)continue;break}if(he===IZ){if(n.push(h),u.push(Be),Be={value:\"\",depth:0,isGlob:!1},fe===!0)continue;if(me===QL&&h===E+1){E+=2;continue}I=h+1;continue}if(r.noext!==!0&&(he===Y7e||he===q7e||he===kL||he===yZ||he===FL)===!0&&g()===TL){if(C=Be.isGlob=!0,R=Be.isExtglob=!0,fe=!0,he===FL&&h===E&&(ae=!0),a===!0){for(;we()!==!0&&(he=Ee());){if(he===QI){V=Be.backslashes=!0,he=Ee();continue}if(he===EZ){C=Be.isGlob=!0,fe=!0;break}}continue}break}if(he===kL){if(me===kL&&(N=Be.isGlobstar=!0),C=Be.isGlob=!0,fe=!0,a===!0)continue;break}if(he===yZ){if(C=Be.isGlob=!0,fe=!0,a===!0)continue;break}if(he===j7e){for(;we()!==!0&&(Ie=Ee());){if(Ie===QI){V=Be.backslashes=!0,Ee();continue}if(Ie===K7e){x=Be.isBracket=!0,C=Be.isGlob=!0,fe=!0;break}}if(a===!0)continue;break}if(r.nonegate!==!0&&he===FL&&h===E){te=Be.negated=!0,E++;continue}if(r.noparen!==!0&&he===TL){if(C=Be.isGlob=!0,a===!0){for(;we()!==!0&&(he=Ee());){if(he===TL){V=Be.backslashes=!0,he=Ee();continue}if(he===EZ){fe=!0;break}}continue}break}if(C===!0){if(fe=!0,a===!0)continue;break}}r.noext===!0&&(R=!1,C=!1);let Pe=p,ce=\"\",ne=\"\";E>0&&(ce=p.slice(0,E),p=p.slice(E),I-=E),Pe&&C===!0&&I>0?(Pe=p.slice(0,I),ne=p.slice(I)):C===!0?(Pe=\"\",ne=p):Pe=p,Pe&&Pe!==\"\"&&Pe!==\"/\"&&Pe!==p&&CZ(Pe.charCodeAt(Pe.length-1))&&(Pe=Pe.slice(0,-1)),r.unescape===!0&&(ne&&(ne=mZ.removeBackslashes(ne)),Pe&&V===!0&&(Pe=mZ.removeBackslashes(Pe)));let ee={prefix:ce,input:t,start:E,base:Pe,glob:ne,isBrace:v,isBracket:x,isGlob:C,isExtglob:R,isGlobstar:N,negated:te,negatedExtglob:ae};if(r.tokens===!0&&(ee.maxDepth=0,CZ(he)||u.push(Be),ee.tokens=u),r.parts===!0||r.tokens===!0){let Ie;for(let Fe=0;Fe<n.length;Fe++){let At=Ie?Ie+1:E,H=n[Fe],at=t.slice(At,H);r.tokens&&(Fe===0&&E!==0?(u[Fe].isPrefix=!0,u[Fe].value=ce):u[Fe].value=at,wZ(u[Fe]),ee.maxDepth+=u[Fe].depth),(Fe!==0||at!==\"\")&&A.push(at),Ie=H}if(Ie&&Ie+1<t.length){let Fe=t.slice(Ie+1);A.push(Fe),r.tokens&&(u[u.length-1].value=Fe,wZ(u[u.length-1]),ee.maxDepth+=u[u.length-1].depth)}ee.slashes=n,ee.parts=A}return ee};BZ.exports=z7e});var SZ=_((JQt,PZ)=>{\"use strict\";var TP=xI(),il=kI(),{MAX_LENGTH:LP,POSIX_REGEX_SOURCE:V7e,REGEX_NON_SPECIAL_CHARS:J7e,REGEX_SPECIAL_CHARS_BACKREF:X7e,REPLACEMENTS:DZ}=TP,Z7e=(t,e)=>{if(typeof e.expandRange==\"function\")return e.expandRange(...t,e);t.sort();let r=`[${t.join(\"-\")}]`;try{new RegExp(r)}catch{return t.map(a=>il.escapeRegex(a)).join(\"..\")}return r},Ty=(t,e)=>`Missing ${t}: \"${e}\" - use \"\\\\\\\\${e}\" to match literal characters`,LL=(t,e)=>{if(typeof t!=\"string\")throw new TypeError(\"Expected a string\");t=DZ[t]||t;let r={...e},o=typeof r.maxLength==\"number\"?Math.min(LP,r.maxLength):LP,a=t.length;if(a>o)throw new SyntaxError(`Input length: ${a}, exceeds maximum allowed length: ${o}`);let n={type:\"bos\",value:\"\",output:r.prepend||\"\"},u=[n],A=r.capture?\"\":\"?:\",p=il.isWindows(e),h=TP.globChars(p),E=TP.extglobChars(h),{DOT_LITERAL:I,PLUS_LITERAL:v,SLASH_LITERAL:x,ONE_CHAR:C,DOTS_SLASH:R,NO_DOT:N,NO_DOT_SLASH:U,NO_DOTS_SLASH:V,QMARK:te,QMARK_NO_DOT:ae,STAR:fe,START_ANCHOR:ue}=h,me=b=>`(${A}(?:(?!${ue}${b.dot?R:I}).)*?)`,he=r.dot?\"\":N,Be=r.dot?te:ae,we=r.bash===!0?me(r):fe;r.capture&&(we=`(${we})`),typeof r.noext==\"boolean\"&&(r.noextglob=r.noext);let g={input:t,index:-1,start:0,dot:r.dot===!0,consumed:\"\",output:\"\",prefix:\"\",backtrack:!1,negated:!1,brackets:0,braces:0,parens:0,quotes:0,globstar:!1,tokens:u};t=il.removePrefix(t,g),a=t.length;let Ee=[],Pe=[],ce=[],ne=n,ee,Ie=()=>g.index===a-1,Fe=g.peek=(b=1)=>t[g.index+b],At=g.advance=()=>t[++g.index]||\"\",H=()=>t.slice(g.index+1),at=(b=\"\",w=0)=>{g.consumed+=b,g.index+=w},Re=b=>{g.output+=b.output!=null?b.output:b.value,at(b.value)},ke=()=>{let b=1;for(;Fe()===\"!\"&&(Fe(2)!==\"(\"||Fe(3)===\"?\");)At(),g.start++,b++;return b%2===0?!1:(g.negated=!0,g.start++,!0)},xe=b=>{g[b]++,ce.push(b)},He=b=>{g[b]--,ce.pop()},Te=b=>{if(ne.type===\"globstar\"){let w=g.braces>0&&(b.type===\"comma\"||b.type===\"brace\"),S=b.extglob===!0||Ee.length&&(b.type===\"pipe\"||b.type===\"paren\");b.type!==\"slash\"&&b.type!==\"paren\"&&!w&&!S&&(g.output=g.output.slice(0,-ne.output.length),ne.type=\"star\",ne.value=\"*\",ne.output=we,g.output+=ne.output)}if(Ee.length&&b.type!==\"paren\"&&(Ee[Ee.length-1].inner+=b.value),(b.value||b.output)&&Re(b),ne&&ne.type===\"text\"&&b.type===\"text\"){ne.value+=b.value,ne.output=(ne.output||\"\")+b.value;return}b.prev=ne,u.push(b),ne=b},Ve=(b,w)=>{let S={...E[w],conditions:1,inner:\"\"};S.prev=ne,S.parens=g.parens,S.output=g.output;let y=(r.capture?\"(\":\"\")+S.open;xe(\"parens\"),Te({type:b,value:w,output:g.output?\"\":C}),Te({type:\"paren\",extglob:!0,value:At(),output:y}),Ee.push(S)},qe=b=>{let w=b.close+(r.capture?\")\":\"\"),S;if(b.type===\"negate\"){let y=we;if(b.inner&&b.inner.length>1&&b.inner.includes(\"/\")&&(y=me(r)),(y!==we||Ie()||/^\\)+$/.test(H()))&&(w=b.close=`)$))${y}`),b.inner.includes(\"*\")&&(S=H())&&/^\\.[^\\\\/.]+$/.test(S)){let F=LL(S,{...e,fastpaths:!1}).output;w=b.close=`)${F})${y})`}b.prev.type===\"bos\"&&(g.negatedExtglob=!0)}Te({type:\"paren\",extglob:!0,value:ee,output:w}),He(\"parens\")};if(r.fastpaths!==!1&&!/(^[*!]|[/()[\\]{}\"])/.test(t)){let b=!1,w=t.replace(X7e,(S,y,F,J,X,Z)=>J===\"\\\\\"?(b=!0,S):J===\"?\"?y?y+J+(X?te.repeat(X.length):\"\"):Z===0?Be+(X?te.repeat(X.length):\"\"):te.repeat(F.length):J===\".\"?I.repeat(F.length):J===\"*\"?y?y+J+(X?we:\"\"):we:y?S:`\\\\${S}`);return b===!0&&(r.unescape===!0?w=w.replace(/\\\\/g,\"\"):w=w.replace(/\\\\+/g,S=>S.length%2===0?\"\\\\\\\\\":S?\"\\\\\":\"\")),w===t&&r.contains===!0?(g.output=t,g):(g.output=il.wrapOutput(w,g,e),g)}for(;!Ie();){if(ee=At(),ee===\"\\0\")continue;if(ee===\"\\\\\"){let S=Fe();if(S===\"/\"&&r.bash!==!0||S===\".\"||S===\";\")continue;if(!S){ee+=\"\\\\\",Te({type:\"text\",value:ee});continue}let y=/^\\\\+/.exec(H()),F=0;if(y&&y[0].length>2&&(F=y[0].length,g.index+=F,F%2!==0&&(ee+=\"\\\\\")),r.unescape===!0?ee=At():ee+=At(),g.brackets===0){Te({type:\"text\",value:ee});continue}}if(g.brackets>0&&(ee!==\"]\"||ne.value===\"[\"||ne.value===\"[^\")){if(r.posix!==!1&&ee===\":\"){let S=ne.value.slice(1);if(S.includes(\"[\")&&(ne.posix=!0,S.includes(\":\"))){let y=ne.value.lastIndexOf(\"[\"),F=ne.value.slice(0,y),J=ne.value.slice(y+2),X=V7e[J];if(X){ne.value=F+X,g.backtrack=!0,At(),!n.output&&u.indexOf(ne)===1&&(n.output=C);continue}}}(ee===\"[\"&&Fe()!==\":\"||ee===\"-\"&&Fe()===\"]\")&&(ee=`\\\\${ee}`),ee===\"]\"&&(ne.value===\"[\"||ne.value===\"[^\")&&(ee=`\\\\${ee}`),r.posix===!0&&ee===\"!\"&&ne.value===\"[\"&&(ee=\"^\"),ne.value+=ee,Re({value:ee});continue}if(g.quotes===1&&ee!=='\"'){ee=il.escapeRegex(ee),ne.value+=ee,Re({value:ee});continue}if(ee==='\"'){g.quotes=g.quotes===1?0:1,r.keepQuotes===!0&&Te({type:\"text\",value:ee});continue}if(ee===\"(\"){xe(\"parens\"),Te({type:\"paren\",value:ee});continue}if(ee===\")\"){if(g.parens===0&&r.strictBrackets===!0)throw new SyntaxError(Ty(\"opening\",\"(\"));let S=Ee[Ee.length-1];if(S&&g.parens===S.parens+1){qe(Ee.pop());continue}Te({type:\"paren\",value:ee,output:g.parens?\")\":\"\\\\)\"}),He(\"parens\");continue}if(ee===\"[\"){if(r.nobracket===!0||!H().includes(\"]\")){if(r.nobracket!==!0&&r.strictBrackets===!0)throw new SyntaxError(Ty(\"closing\",\"]\"));ee=`\\\\${ee}`}else xe(\"brackets\");Te({type:\"bracket\",value:ee});continue}if(ee===\"]\"){if(r.nobracket===!0||ne&&ne.type===\"bracket\"&&ne.value.length===1){Te({type:\"text\",value:ee,output:`\\\\${ee}`});continue}if(g.brackets===0){if(r.strictBrackets===!0)throw new SyntaxError(Ty(\"opening\",\"[\"));Te({type:\"text\",value:ee,output:`\\\\${ee}`});continue}He(\"brackets\");let S=ne.value.slice(1);if(ne.posix!==!0&&S[0]===\"^\"&&!S.includes(\"/\")&&(ee=`/${ee}`),ne.value+=ee,Re({value:ee}),r.literalBrackets===!1||il.hasRegexChars(S))continue;let y=il.escapeRegex(ne.value);if(g.output=g.output.slice(0,-ne.value.length),r.literalBrackets===!0){g.output+=y,ne.value=y;continue}ne.value=`(${A}${y}|${ne.value})`,g.output+=ne.value;continue}if(ee===\"{\"&&r.nobrace!==!0){xe(\"braces\");let S={type:\"brace\",value:ee,output:\"(\",outputIndex:g.output.length,tokensIndex:g.tokens.length};Pe.push(S),Te(S);continue}if(ee===\"}\"){let S=Pe[Pe.length-1];if(r.nobrace===!0||!S){Te({type:\"text\",value:ee,output:ee});continue}let y=\")\";if(S.dots===!0){let F=u.slice(),J=[];for(let X=F.length-1;X>=0&&(u.pop(),F[X].type!==\"brace\");X--)F[X].type!==\"dots\"&&J.unshift(F[X].value);y=Z7e(J,r),g.backtrack=!0}if(S.comma!==!0&&S.dots!==!0){let F=g.output.slice(0,S.outputIndex),J=g.tokens.slice(S.tokensIndex);S.value=S.output=\"\\\\{\",ee=y=\"\\\\}\",g.output=F;for(let X of J)g.output+=X.output||X.value}Te({type:\"brace\",value:ee,output:y}),He(\"braces\"),Pe.pop();continue}if(ee===\"|\"){Ee.length>0&&Ee[Ee.length-1].conditions++,Te({type:\"text\",value:ee});continue}if(ee===\",\"){let S=ee,y=Pe[Pe.length-1];y&&ce[ce.length-1]===\"braces\"&&(y.comma=!0,S=\"|\"),Te({type:\"comma\",value:ee,output:S});continue}if(ee===\"/\"){if(ne.type===\"dot\"&&g.index===g.start+1){g.start=g.index+1,g.consumed=\"\",g.output=\"\",u.pop(),ne=n;continue}Te({type:\"slash\",value:ee,output:x});continue}if(ee===\".\"){if(g.braces>0&&ne.type===\"dot\"){ne.value===\".\"&&(ne.output=I);let S=Pe[Pe.length-1];ne.type=\"dots\",ne.output+=ee,ne.value+=ee,S.dots=!0;continue}if(g.braces+g.parens===0&&ne.type!==\"bos\"&&ne.type!==\"slash\"){Te({type:\"text\",value:ee,output:I});continue}Te({type:\"dot\",value:ee,output:I});continue}if(ee===\"?\"){if(!(ne&&ne.value===\"(\")&&r.noextglob!==!0&&Fe()===\"(\"&&Fe(2)!==\"?\"){Ve(\"qmark\",ee);continue}if(ne&&ne.type===\"paren\"){let y=Fe(),F=ee;if(y===\"<\"&&!il.supportsLookbehinds())throw new Error(\"Node.js v10 or higher is required for regex lookbehinds\");(ne.value===\"(\"&&!/[!=<:]/.test(y)||y===\"<\"&&!/<([!=]|\\w+>)/.test(H()))&&(F=`\\\\${ee}`),Te({type:\"text\",value:ee,output:F});continue}if(r.dot!==!0&&(ne.type===\"slash\"||ne.type===\"bos\")){Te({type:\"qmark\",value:ee,output:ae});continue}Te({type:\"qmark\",value:ee,output:te});continue}if(ee===\"!\"){if(r.noextglob!==!0&&Fe()===\"(\"&&(Fe(2)!==\"?\"||!/[!=<:]/.test(Fe(3)))){Ve(\"negate\",ee);continue}if(r.nonegate!==!0&&g.index===0){ke();continue}}if(ee===\"+\"){if(r.noextglob!==!0&&Fe()===\"(\"&&Fe(2)!==\"?\"){Ve(\"plus\",ee);continue}if(ne&&ne.value===\"(\"||r.regex===!1){Te({type:\"plus\",value:ee,output:v});continue}if(ne&&(ne.type===\"bracket\"||ne.type===\"paren\"||ne.type===\"brace\")||g.parens>0){Te({type:\"plus\",value:ee});continue}Te({type:\"plus\",value:v});continue}if(ee===\"@\"){if(r.noextglob!==!0&&Fe()===\"(\"&&Fe(2)!==\"?\"){Te({type:\"at\",extglob:!0,value:ee,output:\"\"});continue}Te({type:\"text\",value:ee});continue}if(ee!==\"*\"){(ee===\"$\"||ee===\"^\")&&(ee=`\\\\${ee}`);let S=J7e.exec(H());S&&(ee+=S[0],g.index+=S[0].length),Te({type:\"text\",value:ee});continue}if(ne&&(ne.type===\"globstar\"||ne.star===!0)){ne.type=\"star\",ne.star=!0,ne.value+=ee,ne.output=we,g.backtrack=!0,g.globstar=!0,at(ee);continue}let b=H();if(r.noextglob!==!0&&/^\\([^?]/.test(b)){Ve(\"star\",ee);continue}if(ne.type===\"star\"){if(r.noglobstar===!0){at(ee);continue}let S=ne.prev,y=S.prev,F=S.type===\"slash\"||S.type===\"bos\",J=y&&(y.type===\"star\"||y.type===\"globstar\");if(r.bash===!0&&(!F||b[0]&&b[0]!==\"/\")){Te({type:\"star\",value:ee,output:\"\"});continue}let X=g.braces>0&&(S.type===\"comma\"||S.type===\"brace\"),Z=Ee.length&&(S.type===\"pipe\"||S.type===\"paren\");if(!F&&S.type!==\"paren\"&&!X&&!Z){Te({type:\"star\",value:ee,output:\"\"});continue}for(;b.slice(0,3)===\"/**\";){let ie=t[g.index+4];if(ie&&ie!==\"/\")break;b=b.slice(3),at(\"/**\",3)}if(S.type===\"bos\"&&Ie()){ne.type=\"globstar\",ne.value+=ee,ne.output=me(r),g.output=ne.output,g.globstar=!0,at(ee);continue}if(S.type===\"slash\"&&S.prev.type!==\"bos\"&&!J&&Ie()){g.output=g.output.slice(0,-(S.output+ne.output).length),S.output=`(?:${S.output}`,ne.type=\"globstar\",ne.output=me(r)+(r.strictSlashes?\")\":\"|$)\"),ne.value+=ee,g.globstar=!0,g.output+=S.output+ne.output,at(ee);continue}if(S.type===\"slash\"&&S.prev.type!==\"bos\"&&b[0]===\"/\"){let ie=b[1]!==void 0?\"|$\":\"\";g.output=g.output.slice(0,-(S.output+ne.output).length),S.output=`(?:${S.output}`,ne.type=\"globstar\",ne.output=`${me(r)}${x}|${x}${ie})`,ne.value+=ee,g.output+=S.output+ne.output,g.globstar=!0,at(ee+At()),Te({type:\"slash\",value:\"/\",output:\"\"});continue}if(S.type===\"bos\"&&b[0]===\"/\"){ne.type=\"globstar\",ne.value+=ee,ne.output=`(?:^|${x}|${me(r)}${x})`,g.output=ne.output,g.globstar=!0,at(ee+At()),Te({type:\"slash\",value:\"/\",output:\"\"});continue}g.output=g.output.slice(0,-ne.output.length),ne.type=\"globstar\",ne.output=me(r),ne.value+=ee,g.output+=ne.output,g.globstar=!0,at(ee);continue}let w={type:\"star\",value:ee,output:we};if(r.bash===!0){w.output=\".*?\",(ne.type===\"bos\"||ne.type===\"slash\")&&(w.output=he+w.output),Te(w);continue}if(ne&&(ne.type===\"bracket\"||ne.type===\"paren\")&&r.regex===!0){w.output=ee,Te(w);continue}(g.index===g.start||ne.type===\"slash\"||ne.type===\"dot\")&&(ne.type===\"dot\"?(g.output+=U,ne.output+=U):r.dot===!0?(g.output+=V,ne.output+=V):(g.output+=he,ne.output+=he),Fe()!==\"*\"&&(g.output+=C,ne.output+=C)),Te(w)}for(;g.brackets>0;){if(r.strictBrackets===!0)throw new SyntaxError(Ty(\"closing\",\"]\"));g.output=il.escapeLast(g.output,\"[\"),He(\"brackets\")}for(;g.parens>0;){if(r.strictBrackets===!0)throw new SyntaxError(Ty(\"closing\",\")\"));g.output=il.escapeLast(g.output,\"(\"),He(\"parens\")}for(;g.braces>0;){if(r.strictBrackets===!0)throw new SyntaxError(Ty(\"closing\",\"}\"));g.output=il.escapeLast(g.output,\"{\"),He(\"braces\")}if(r.strictSlashes!==!0&&(ne.type===\"star\"||ne.type===\"bracket\")&&Te({type:\"maybe_slash\",value:\"\",output:`${x}?`}),g.backtrack===!0){g.output=\"\";for(let b of g.tokens)g.output+=b.output!=null?b.output:b.value,b.suffix&&(g.output+=b.suffix)}return g};LL.fastpaths=(t,e)=>{let r={...e},o=typeof r.maxLength==\"number\"?Math.min(LP,r.maxLength):LP,a=t.length;if(a>o)throw new SyntaxError(`Input length: ${a}, exceeds maximum allowed length: ${o}`);t=DZ[t]||t;let n=il.isWindows(e),{DOT_LITERAL:u,SLASH_LITERAL:A,ONE_CHAR:p,DOTS_SLASH:h,NO_DOT:E,NO_DOTS:I,NO_DOTS_SLASH:v,STAR:x,START_ANCHOR:C}=TP.globChars(n),R=r.dot?I:E,N=r.dot?v:E,U=r.capture?\"\":\"?:\",V={negated:!1,prefix:\"\"},te=r.bash===!0?\".*?\":x;r.capture&&(te=`(${te})`);let ae=he=>he.noglobstar===!0?te:`(${U}(?:(?!${C}${he.dot?h:u}).)*?)`,fe=he=>{switch(he){case\"*\":return`${R}${p}${te}`;case\".*\":return`${u}${p}${te}`;case\"*.*\":return`${R}${te}${u}${p}${te}`;case\"*/*\":return`${R}${te}${A}${p}${N}${te}`;case\"**\":return R+ae(r);case\"**/*\":return`(?:${R}${ae(r)}${A})?${N}${p}${te}`;case\"**/*.*\":return`(?:${R}${ae(r)}${A})?${N}${te}${u}${p}${te}`;case\"**/.*\":return`(?:${R}${ae(r)}${A})?${u}${p}${te}`;default:{let Be=/^(.*?)\\.(\\w+)$/.exec(he);if(!Be)return;let we=fe(Be[1]);return we?we+u+Be[2]:void 0}}},ue=il.removePrefix(t,V),me=fe(ue);return me&&r.strictSlashes!==!0&&(me+=`${A}?`),me};PZ.exports=LL});var xZ=_((XQt,bZ)=>{\"use strict\";var $7e=ve(\"path\"),eYe=vZ(),NL=SZ(),OL=kI(),tYe=xI(),rYe=t=>t&&typeof t==\"object\"&&!Array.isArray(t),Mi=(t,e,r=!1)=>{if(Array.isArray(t)){let E=t.map(v=>Mi(v,e,r));return v=>{for(let x of E){let C=x(v);if(C)return C}return!1}}let o=rYe(t)&&t.tokens&&t.input;if(t===\"\"||typeof t!=\"string\"&&!o)throw new TypeError(\"Expected pattern to be a non-empty string\");let a=e||{},n=OL.isWindows(e),u=o?Mi.compileRe(t,e):Mi.makeRe(t,e,!1,!0),A=u.state;delete u.state;let p=()=>!1;if(a.ignore){let E={...e,ignore:null,onMatch:null,onResult:null};p=Mi(a.ignore,E,r)}let h=(E,I=!1)=>{let{isMatch:v,match:x,output:C}=Mi.test(E,u,e,{glob:t,posix:n}),R={glob:t,state:A,regex:u,posix:n,input:E,output:C,match:x,isMatch:v};return typeof a.onResult==\"function\"&&a.onResult(R),v===!1?(R.isMatch=!1,I?R:!1):p(E)?(typeof a.onIgnore==\"function\"&&a.onIgnore(R),R.isMatch=!1,I?R:!1):(typeof a.onMatch==\"function\"&&a.onMatch(R),I?R:!0)};return r&&(h.state=A),h};Mi.test=(t,e,r,{glob:o,posix:a}={})=>{if(typeof t!=\"string\")throw new TypeError(\"Expected input to be a string\");if(t===\"\")return{isMatch:!1,output:\"\"};let n=r||{},u=n.format||(a?OL.toPosixSlashes:null),A=t===o,p=A&&u?u(t):t;return A===!1&&(p=u?u(t):t,A=p===o),(A===!1||n.capture===!0)&&(n.matchBase===!0||n.basename===!0?A=Mi.matchBase(t,e,r,a):A=e.exec(p)),{isMatch:Boolean(A),match:A,output:p}};Mi.matchBase=(t,e,r,o=OL.isWindows(r))=>(e instanceof RegExp?e:Mi.makeRe(e,r)).test($7e.basename(t));Mi.isMatch=(t,e,r)=>Mi(e,r)(t);Mi.parse=(t,e)=>Array.isArray(t)?t.map(r=>Mi.parse(r,e)):NL(t,{...e,fastpaths:!1});Mi.scan=(t,e)=>eYe(t,e);Mi.compileRe=(t,e,r=!1,o=!1)=>{if(r===!0)return t.output;let a=e||{},n=a.contains?\"\":\"^\",u=a.contains?\"\":\"$\",A=`${n}(?:${t.output})${u}`;t&&t.negated===!0&&(A=`^(?!${A}).*$`);let p=Mi.toRegex(A,e);return o===!0&&(p.state=t),p};Mi.makeRe=(t,e={},r=!1,o=!1)=>{if(!t||typeof t!=\"string\")throw new TypeError(\"Expected a non-empty string\");let a={negated:!1,fastpaths:!0};return e.fastpaths!==!1&&(t[0]===\".\"||t[0]===\"*\")&&(a.output=NL.fastpaths(t,e)),a.output||(a=NL(t,e)),Mi.compileRe(a,e,r,o)};Mi.toRegex=(t,e)=>{try{let r=e||{};return new RegExp(t,r.flags||(r.nocase?\"i\":\"\"))}catch(r){if(e&&e.debug===!0)throw r;return/$^/}};Mi.constants=tYe;bZ.exports=Mi});var QZ=_((ZQt,kZ)=>{\"use strict\";kZ.exports=xZ()});var Zo=_(($Qt,LZ)=>{\"use strict\";var RZ=ve(\"util\"),TZ=AZ(),Vu=QZ(),ML=kI(),FZ=t=>t===\"\"||t===\"./\",yi=(t,e,r)=>{e=[].concat(e),t=[].concat(t);let o=new Set,a=new Set,n=new Set,u=0,A=E=>{n.add(E.output),r&&r.onResult&&r.onResult(E)};for(let E=0;E<e.length;E++){let I=Vu(String(e[E]),{...r,onResult:A},!0),v=I.state.negated||I.state.negatedExtglob;v&&u++;for(let x of t){let C=I(x,!0);!(v?!C.isMatch:C.isMatch)||(v?o.add(C.output):(o.delete(C.output),a.add(C.output)))}}let h=(u===e.length?[...n]:[...a]).filter(E=>!o.has(E));if(r&&h.length===0){if(r.failglob===!0)throw new Error(`No matches found for \"${e.join(\", \")}\"`);if(r.nonull===!0||r.nullglob===!0)return r.unescape?e.map(E=>E.replace(/\\\\/g,\"\")):e}return h};yi.match=yi;yi.matcher=(t,e)=>Vu(t,e);yi.isMatch=(t,e,r)=>Vu(e,r)(t);yi.any=yi.isMatch;yi.not=(t,e,r={})=>{e=[].concat(e).map(String);let o=new Set,a=[],n=A=>{r.onResult&&r.onResult(A),a.push(A.output)},u=new Set(yi(t,e,{...r,onResult:n}));for(let A of a)u.has(A)||o.add(A);return[...o]};yi.contains=(t,e,r)=>{if(typeof t!=\"string\")throw new TypeError(`Expected a string: \"${RZ.inspect(t)}\"`);if(Array.isArray(e))return e.some(o=>yi.contains(t,o,r));if(typeof e==\"string\"){if(FZ(t)||FZ(e))return!1;if(t.includes(e)||t.startsWith(\"./\")&&t.slice(2).includes(e))return!0}return yi.isMatch(t,e,{...r,contains:!0})};yi.matchKeys=(t,e,r)=>{if(!ML.isObject(t))throw new TypeError(\"Expected the first argument to be an object\");let o=yi(Object.keys(t),e,r),a={};for(let n of o)a[n]=t[n];return a};yi.some=(t,e,r)=>{let o=[].concat(t);for(let a of[].concat(e)){let n=Vu(String(a),r);if(o.some(u=>n(u)))return!0}return!1};yi.every=(t,e,r)=>{let o=[].concat(t);for(let a of[].concat(e)){let n=Vu(String(a),r);if(!o.every(u=>n(u)))return!1}return!0};yi.all=(t,e,r)=>{if(typeof t!=\"string\")throw new TypeError(`Expected a string: \"${RZ.inspect(t)}\"`);return[].concat(e).every(o=>Vu(o,r)(t))};yi.capture=(t,e,r)=>{let o=ML.isWindows(r),n=Vu.makeRe(String(t),{...r,capture:!0}).exec(o?ML.toPosixSlashes(e):e);if(n)return n.slice(1).map(u=>u===void 0?\"\":u)};yi.makeRe=(...t)=>Vu.makeRe(...t);yi.scan=(...t)=>Vu.scan(...t);yi.parse=(t,e)=>{let r=[];for(let o of[].concat(t||[]))for(let a of TZ(String(o),e))r.push(Vu.parse(a,e));return r};yi.braces=(t,e)=>{if(typeof t!=\"string\")throw new TypeError(\"Expected a string\");return e&&e.nobrace===!0||!/\\{.*\\}/.test(t)?[t]:TZ(t,e)};yi.braceExpand=(t,e)=>{if(typeof t!=\"string\")throw new TypeError(\"Expected a string\");return yi.braces(t,{...e,expand:!0})};LZ.exports=yi});var OZ=_((eFt,NZ)=>{\"use strict\";NZ.exports=({onlyFirst:t=!1}={})=>{let e=[\"[\\\\u001B\\\\u009B][[\\\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\\\d\\\\/#&.:=?%@~_]+)*|[a-zA-Z\\\\d]+(?:;[-a-zA-Z\\\\d\\\\/#&.:=?%@~_]*)*)?\\\\u0007)\",\"(?:(?:\\\\d{1,4}(?:;\\\\d{0,4})*)?[\\\\dA-PR-TZcf-ntqry=><~]))\"].join(\"|\");return new RegExp(e,t?void 0:\"g\")}});var NP=_((tFt,MZ)=>{\"use strict\";var nYe=OZ();MZ.exports=t=>typeof t==\"string\"?t.replace(nYe(),\"\"):t});var _Z=_((rFt,UZ)=>{function iYe(){this.__data__=[],this.size=0}UZ.exports=iYe});var Ly=_((nFt,HZ)=>{function sYe(t,e){return t===e||t!==t&&e!==e}HZ.exports=sYe});var FI=_((iFt,qZ)=>{var oYe=Ly();function aYe(t,e){for(var r=t.length;r--;)if(oYe(t[r][0],e))return r;return-1}qZ.exports=aYe});var jZ=_((sFt,GZ)=>{var lYe=FI(),cYe=Array.prototype,uYe=cYe.splice;function AYe(t){var e=this.__data__,r=lYe(e,t);if(r<0)return!1;var o=e.length-1;return r==o?e.pop():uYe.call(e,r,1),--this.size,!0}GZ.exports=AYe});var WZ=_((oFt,YZ)=>{var fYe=FI();function pYe(t){var e=this.__data__,r=fYe(e,t);return r<0?void 0:e[r][1]}YZ.exports=pYe});var zZ=_((aFt,KZ)=>{var hYe=FI();function gYe(t){return hYe(this.__data__,t)>-1}KZ.exports=gYe});var JZ=_((lFt,VZ)=>{var dYe=FI();function mYe(t,e){var r=this.__data__,o=dYe(r,t);return o<0?(++this.size,r.push([t,e])):r[o][1]=e,this}VZ.exports=mYe});var RI=_((cFt,XZ)=>{var yYe=_Z(),EYe=jZ(),CYe=WZ(),wYe=zZ(),IYe=JZ();function Ny(t){var e=-1,r=t==null?0:t.length;for(this.clear();++e<r;){var o=t[e];this.set(o[0],o[1])}}Ny.prototype.clear=yYe;Ny.prototype.delete=EYe;Ny.prototype.get=CYe;Ny.prototype.has=wYe;Ny.prototype.set=IYe;XZ.exports=Ny});var $Z=_((uFt,ZZ)=>{var BYe=RI();function vYe(){this.__data__=new BYe,this.size=0}ZZ.exports=vYe});var t$=_((AFt,e$)=>{function DYe(t){var e=this.__data__,r=e.delete(t);return this.size=e.size,r}e$.exports=DYe});var n$=_((fFt,r$)=>{function PYe(t){return this.__data__.get(t)}r$.exports=PYe});var s$=_((pFt,i$)=>{function SYe(t){return this.__data__.has(t)}i$.exports=SYe});var UL=_((hFt,o$)=>{var bYe=typeof global==\"object\"&&global&&global.Object===Object&&global;o$.exports=bYe});var Hl=_((gFt,a$)=>{var xYe=UL(),kYe=typeof self==\"object\"&&self&&self.Object===Object&&self,QYe=xYe||kYe||Function(\"return this\")();a$.exports=QYe});var hd=_((dFt,l$)=>{var FYe=Hl(),RYe=FYe.Symbol;l$.exports=RYe});var f$=_((mFt,A$)=>{var c$=hd(),u$=Object.prototype,TYe=u$.hasOwnProperty,LYe=u$.toString,TI=c$?c$.toStringTag:void 0;function NYe(t){var e=TYe.call(t,TI),r=t[TI];try{t[TI]=void 0;var o=!0}catch{}var a=LYe.call(t);return o&&(e?t[TI]=r:delete t[TI]),a}A$.exports=NYe});var h$=_((yFt,p$)=>{var OYe=Object.prototype,MYe=OYe.toString;function UYe(t){return MYe.call(t)}p$.exports=UYe});var gd=_((EFt,m$)=>{var g$=hd(),_Ye=f$(),HYe=h$(),qYe=\"[object Null]\",GYe=\"[object Undefined]\",d$=g$?g$.toStringTag:void 0;function jYe(t){return t==null?t===void 0?GYe:qYe:d$&&d$ in Object(t)?_Ye(t):HYe(t)}m$.exports=jYe});var sl=_((CFt,y$)=>{function YYe(t){var e=typeof t;return t!=null&&(e==\"object\"||e==\"function\")}y$.exports=YYe});var OP=_((wFt,E$)=>{var WYe=gd(),KYe=sl(),zYe=\"[object AsyncFunction]\",VYe=\"[object Function]\",JYe=\"[object GeneratorFunction]\",XYe=\"[object Proxy]\";function ZYe(t){if(!KYe(t))return!1;var e=WYe(t);return e==VYe||e==JYe||e==zYe||e==XYe}E$.exports=ZYe});var w$=_((IFt,C$)=>{var $Ye=Hl(),eWe=$Ye[\"__core-js_shared__\"];C$.exports=eWe});var v$=_((BFt,B$)=>{var _L=w$(),I$=function(){var t=/[^.]+$/.exec(_L&&_L.keys&&_L.keys.IE_PROTO||\"\");return t?\"Symbol(src)_1.\"+t:\"\"}();function tWe(t){return!!I$&&I$ in t}B$.exports=tWe});var HL=_((vFt,D$)=>{var rWe=Function.prototype,nWe=rWe.toString;function iWe(t){if(t!=null){try{return nWe.call(t)}catch{}try{return t+\"\"}catch{}}return\"\"}D$.exports=iWe});var S$=_((DFt,P$)=>{var sWe=OP(),oWe=v$(),aWe=sl(),lWe=HL(),cWe=/[\\\\^$.*+?()[\\]{}|]/g,uWe=/^\\[object .+?Constructor\\]$/,AWe=Function.prototype,fWe=Object.prototype,pWe=AWe.toString,hWe=fWe.hasOwnProperty,gWe=RegExp(\"^\"+pWe.call(hWe).replace(cWe,\"\\\\$&\").replace(/hasOwnProperty|(function).*?(?=\\\\\\()| for .+?(?=\\\\\\])/g,\"$1.*?\")+\"$\");function dWe(t){if(!aWe(t)||oWe(t))return!1;var e=sWe(t)?gWe:uWe;return e.test(lWe(t))}P$.exports=dWe});var x$=_((PFt,b$)=>{function mWe(t,e){return t?.[e]}b$.exports=mWe});var Xp=_((SFt,k$)=>{var yWe=S$(),EWe=x$();function CWe(t,e){var r=EWe(t,e);return yWe(r)?r:void 0}k$.exports=CWe});var MP=_((bFt,Q$)=>{var wWe=Xp(),IWe=Hl(),BWe=wWe(IWe,\"Map\");Q$.exports=BWe});var LI=_((xFt,F$)=>{var vWe=Xp(),DWe=vWe(Object,\"create\");F$.exports=DWe});var L$=_((kFt,T$)=>{var R$=LI();function PWe(){this.__data__=R$?R$(null):{},this.size=0}T$.exports=PWe});var O$=_((QFt,N$)=>{function SWe(t){var e=this.has(t)&&delete this.__data__[t];return this.size-=e?1:0,e}N$.exports=SWe});var U$=_((FFt,M$)=>{var bWe=LI(),xWe=\"__lodash_hash_undefined__\",kWe=Object.prototype,QWe=kWe.hasOwnProperty;function FWe(t){var e=this.__data__;if(bWe){var r=e[t];return r===xWe?void 0:r}return QWe.call(e,t)?e[t]:void 0}M$.exports=FWe});var H$=_((RFt,_$)=>{var RWe=LI(),TWe=Object.prototype,LWe=TWe.hasOwnProperty;function NWe(t){var e=this.__data__;return RWe?e[t]!==void 0:LWe.call(e,t)}_$.exports=NWe});var G$=_((TFt,q$)=>{var OWe=LI(),MWe=\"__lodash_hash_undefined__\";function UWe(t,e){var r=this.__data__;return this.size+=this.has(t)?0:1,r[t]=OWe&&e===void 0?MWe:e,this}q$.exports=UWe});var Y$=_((LFt,j$)=>{var _We=L$(),HWe=O$(),qWe=U$(),GWe=H$(),jWe=G$();function Oy(t){var e=-1,r=t==null?0:t.length;for(this.clear();++e<r;){var o=t[e];this.set(o[0],o[1])}}Oy.prototype.clear=_We;Oy.prototype.delete=HWe;Oy.prototype.get=qWe;Oy.prototype.has=GWe;Oy.prototype.set=jWe;j$.exports=Oy});var z$=_((NFt,K$)=>{var W$=Y$(),YWe=RI(),WWe=MP();function KWe(){this.size=0,this.__data__={hash:new W$,map:new(WWe||YWe),string:new W$}}K$.exports=KWe});var J$=_((OFt,V$)=>{function zWe(t){var e=typeof t;return e==\"string\"||e==\"number\"||e==\"symbol\"||e==\"boolean\"?t!==\"__proto__\":t===null}V$.exports=zWe});var NI=_((MFt,X$)=>{var VWe=J$();function JWe(t,e){var r=t.__data__;return VWe(e)?r[typeof e==\"string\"?\"string\":\"hash\"]:r.map}X$.exports=JWe});var $$=_((UFt,Z$)=>{var XWe=NI();function ZWe(t){var e=XWe(this,t).delete(t);return this.size-=e?1:0,e}Z$.exports=ZWe});var tee=_((_Ft,eee)=>{var $We=NI();function eKe(t){return $We(this,t).get(t)}eee.exports=eKe});var nee=_((HFt,ree)=>{var tKe=NI();function rKe(t){return tKe(this,t).has(t)}ree.exports=rKe});var see=_((qFt,iee)=>{var nKe=NI();function iKe(t,e){var r=nKe(this,t),o=r.size;return r.set(t,e),this.size+=r.size==o?0:1,this}iee.exports=iKe});var UP=_((GFt,oee)=>{var sKe=z$(),oKe=$$(),aKe=tee(),lKe=nee(),cKe=see();function My(t){var e=-1,r=t==null?0:t.length;for(this.clear();++e<r;){var o=t[e];this.set(o[0],o[1])}}My.prototype.clear=sKe;My.prototype.delete=oKe;My.prototype.get=aKe;My.prototype.has=lKe;My.prototype.set=cKe;oee.exports=My});var lee=_((jFt,aee)=>{var uKe=RI(),AKe=MP(),fKe=UP(),pKe=200;function hKe(t,e){var r=this.__data__;if(r instanceof uKe){var o=r.__data__;if(!AKe||o.length<pKe-1)return o.push([t,e]),this.size=++r.size,this;r=this.__data__=new fKe(o)}return r.set(t,e),this.size=r.size,this}aee.exports=hKe});var _P=_((YFt,cee)=>{var gKe=RI(),dKe=$Z(),mKe=t$(),yKe=n$(),EKe=s$(),CKe=lee();function Uy(t){var e=this.__data__=new gKe(t);this.size=e.size}Uy.prototype.clear=dKe;Uy.prototype.delete=mKe;Uy.prototype.get=yKe;Uy.prototype.has=EKe;Uy.prototype.set=CKe;cee.exports=Uy});var Aee=_((WFt,uee)=>{var wKe=\"__lodash_hash_undefined__\";function IKe(t){return this.__data__.set(t,wKe),this}uee.exports=IKe});var pee=_((KFt,fee)=>{function BKe(t){return this.__data__.has(t)}fee.exports=BKe});var gee=_((zFt,hee)=>{var vKe=UP(),DKe=Aee(),PKe=pee();function HP(t){var e=-1,r=t==null?0:t.length;for(this.__data__=new vKe;++e<r;)this.add(t[e])}HP.prototype.add=HP.prototype.push=DKe;HP.prototype.has=PKe;hee.exports=HP});var mee=_((VFt,dee)=>{function SKe(t,e){for(var r=-1,o=t==null?0:t.length;++r<o;)if(e(t[r],r,t))return!0;return!1}dee.exports=SKe});var Eee=_((JFt,yee)=>{function bKe(t,e){return t.has(e)}yee.exports=bKe});var qL=_((XFt,Cee)=>{var xKe=gee(),kKe=mee(),QKe=Eee(),FKe=1,RKe=2;function TKe(t,e,r,o,a,n){var u=r&FKe,A=t.length,p=e.length;if(A!=p&&!(u&&p>A))return!1;var h=n.get(t),E=n.get(e);if(h&&E)return h==e&&E==t;var I=-1,v=!0,x=r&RKe?new xKe:void 0;for(n.set(t,e),n.set(e,t);++I<A;){var C=t[I],R=e[I];if(o)var N=u?o(R,C,I,e,t,n):o(C,R,I,t,e,n);if(N!==void 0){if(N)continue;v=!1;break}if(x){if(!kKe(e,function(U,V){if(!QKe(x,V)&&(C===U||a(C,U,r,o,n)))return x.push(V)})){v=!1;break}}else if(!(C===R||a(C,R,r,o,n))){v=!1;break}}return n.delete(t),n.delete(e),v}Cee.exports=TKe});var jL=_((ZFt,wee)=>{var LKe=Hl(),NKe=LKe.Uint8Array;wee.exports=NKe});var Bee=_(($Ft,Iee)=>{function OKe(t){var e=-1,r=Array(t.size);return t.forEach(function(o,a){r[++e]=[a,o]}),r}Iee.exports=OKe});var Dee=_((eRt,vee)=>{function MKe(t){var e=-1,r=Array(t.size);return t.forEach(function(o){r[++e]=o}),r}vee.exports=MKe});var kee=_((tRt,xee)=>{var Pee=hd(),See=jL(),UKe=Ly(),_Ke=qL(),HKe=Bee(),qKe=Dee(),GKe=1,jKe=2,YKe=\"[object Boolean]\",WKe=\"[object Date]\",KKe=\"[object Error]\",zKe=\"[object Map]\",VKe=\"[object Number]\",JKe=\"[object RegExp]\",XKe=\"[object Set]\",ZKe=\"[object String]\",$Ke=\"[object Symbol]\",eze=\"[object ArrayBuffer]\",tze=\"[object DataView]\",bee=Pee?Pee.prototype:void 0,YL=bee?bee.valueOf:void 0;function rze(t,e,r,o,a,n,u){switch(r){case tze:if(t.byteLength!=e.byteLength||t.byteOffset!=e.byteOffset)return!1;t=t.buffer,e=e.buffer;case eze:return!(t.byteLength!=e.byteLength||!n(new See(t),new See(e)));case YKe:case WKe:case VKe:return UKe(+t,+e);case KKe:return t.name==e.name&&t.message==e.message;case JKe:case ZKe:return t==e+\"\";case zKe:var A=HKe;case XKe:var p=o&GKe;if(A||(A=qKe),t.size!=e.size&&!p)return!1;var h=u.get(t);if(h)return h==e;o|=jKe,u.set(t,e);var E=_Ke(A(t),A(e),o,a,n,u);return u.delete(t),E;case $Ke:if(YL)return YL.call(t)==YL.call(e)}return!1}xee.exports=rze});var qP=_((rRt,Qee)=>{function nze(t,e){for(var r=-1,o=e.length,a=t.length;++r<o;)t[a+r]=e[r];return t}Qee.exports=nze});var ql=_((nRt,Fee)=>{var ize=Array.isArray;Fee.exports=ize});var WL=_((iRt,Ree)=>{var sze=qP(),oze=ql();function aze(t,e,r){var o=e(t);return oze(t)?o:sze(o,r(t))}Ree.exports=aze});var Lee=_((sRt,Tee)=>{function lze(t,e){for(var r=-1,o=t==null?0:t.length,a=0,n=[];++r<o;){var u=t[r];e(u,r,t)&&(n[a++]=u)}return n}Tee.exports=lze});var KL=_((oRt,Nee)=>{function cze(){return[]}Nee.exports=cze});var GP=_((aRt,Mee)=>{var uze=Lee(),Aze=KL(),fze=Object.prototype,pze=fze.propertyIsEnumerable,Oee=Object.getOwnPropertySymbols,hze=Oee?function(t){return t==null?[]:(t=Object(t),uze(Oee(t),function(e){return pze.call(t,e)}))}:Aze;Mee.exports=hze});var _ee=_((lRt,Uee)=>{function gze(t,e){for(var r=-1,o=Array(t);++r<t;)o[r]=e(r);return o}Uee.exports=gze});var Ju=_((cRt,Hee)=>{function dze(t){return t!=null&&typeof t==\"object\"}Hee.exports=dze});var Gee=_((uRt,qee)=>{var mze=gd(),yze=Ju(),Eze=\"[object Arguments]\";function Cze(t){return yze(t)&&mze(t)==Eze}qee.exports=Cze});var OI=_((ARt,Wee)=>{var jee=Gee(),wze=Ju(),Yee=Object.prototype,Ize=Yee.hasOwnProperty,Bze=Yee.propertyIsEnumerable,vze=jee(function(){return arguments}())?jee:function(t){return wze(t)&&Ize.call(t,\"callee\")&&!Bze.call(t,\"callee\")};Wee.exports=vze});var zee=_((fRt,Kee)=>{function Dze(){return!1}Kee.exports=Dze});var UI=_((MI,_y)=>{var Pze=Hl(),Sze=zee(),Xee=typeof MI==\"object\"&&MI&&!MI.nodeType&&MI,Vee=Xee&&typeof _y==\"object\"&&_y&&!_y.nodeType&&_y,bze=Vee&&Vee.exports===Xee,Jee=bze?Pze.Buffer:void 0,xze=Jee?Jee.isBuffer:void 0,kze=xze||Sze;_y.exports=kze});var _I=_((pRt,Zee)=>{var Qze=9007199254740991,Fze=/^(?:0|[1-9]\\d*)$/;function Rze(t,e){var r=typeof t;return e=e??Qze,!!e&&(r==\"number\"||r!=\"symbol\"&&Fze.test(t))&&t>-1&&t%1==0&&t<e}Zee.exports=Rze});var jP=_((hRt,$ee)=>{var Tze=9007199254740991;function Lze(t){return typeof t==\"number\"&&t>-1&&t%1==0&&t<=Tze}$ee.exports=Lze});var tte=_((gRt,ete)=>{var Nze=gd(),Oze=jP(),Mze=Ju(),Uze=\"[object Arguments]\",_ze=\"[object Array]\",Hze=\"[object Boolean]\",qze=\"[object Date]\",Gze=\"[object Error]\",jze=\"[object Function]\",Yze=\"[object Map]\",Wze=\"[object Number]\",Kze=\"[object Object]\",zze=\"[object RegExp]\",Vze=\"[object Set]\",Jze=\"[object String]\",Xze=\"[object WeakMap]\",Zze=\"[object ArrayBuffer]\",$ze=\"[object DataView]\",eVe=\"[object Float32Array]\",tVe=\"[object Float64Array]\",rVe=\"[object Int8Array]\",nVe=\"[object Int16Array]\",iVe=\"[object Int32Array]\",sVe=\"[object Uint8Array]\",oVe=\"[object Uint8ClampedArray]\",aVe=\"[object Uint16Array]\",lVe=\"[object Uint32Array]\",ui={};ui[eVe]=ui[tVe]=ui[rVe]=ui[nVe]=ui[iVe]=ui[sVe]=ui[oVe]=ui[aVe]=ui[lVe]=!0;ui[Uze]=ui[_ze]=ui[Zze]=ui[Hze]=ui[$ze]=ui[qze]=ui[Gze]=ui[jze]=ui[Yze]=ui[Wze]=ui[Kze]=ui[zze]=ui[Vze]=ui[Jze]=ui[Xze]=!1;function cVe(t){return Mze(t)&&Oze(t.length)&&!!ui[Nze(t)]}ete.exports=cVe});var YP=_((dRt,rte)=>{function uVe(t){return function(e){return t(e)}}rte.exports=uVe});var WP=_((HI,Hy)=>{var AVe=UL(),nte=typeof HI==\"object\"&&HI&&!HI.nodeType&&HI,qI=nte&&typeof Hy==\"object\"&&Hy&&!Hy.nodeType&&Hy,fVe=qI&&qI.exports===nte,zL=fVe&&AVe.process,pVe=function(){try{var t=qI&&qI.require&&qI.require(\"util\").types;return t||zL&&zL.binding&&zL.binding(\"util\")}catch{}}();Hy.exports=pVe});var KP=_((mRt,ote)=>{var hVe=tte(),gVe=YP(),ite=WP(),ste=ite&&ite.isTypedArray,dVe=ste?gVe(ste):hVe;ote.exports=dVe});var VL=_((yRt,ate)=>{var mVe=_ee(),yVe=OI(),EVe=ql(),CVe=UI(),wVe=_I(),IVe=KP(),BVe=Object.prototype,vVe=BVe.hasOwnProperty;function DVe(t,e){var r=EVe(t),o=!r&&yVe(t),a=!r&&!o&&CVe(t),n=!r&&!o&&!a&&IVe(t),u=r||o||a||n,A=u?mVe(t.length,String):[],p=A.length;for(var h in t)(e||vVe.call(t,h))&&!(u&&(h==\"length\"||a&&(h==\"offset\"||h==\"parent\")||n&&(h==\"buffer\"||h==\"byteLength\"||h==\"byteOffset\")||wVe(h,p)))&&A.push(h);return A}ate.exports=DVe});var zP=_((ERt,lte)=>{var PVe=Object.prototype;function SVe(t){var e=t&&t.constructor,r=typeof e==\"function\"&&e.prototype||PVe;return t===r}lte.exports=SVe});var JL=_((CRt,cte)=>{function bVe(t,e){return function(r){return t(e(r))}}cte.exports=bVe});var Ate=_((wRt,ute)=>{var xVe=JL(),kVe=xVe(Object.keys,Object);ute.exports=kVe});var pte=_((IRt,fte)=>{var QVe=zP(),FVe=Ate(),RVe=Object.prototype,TVe=RVe.hasOwnProperty;function LVe(t){if(!QVe(t))return FVe(t);var e=[];for(var r in Object(t))TVe.call(t,r)&&r!=\"constructor\"&&e.push(r);return e}fte.exports=LVe});var GI=_((BRt,hte)=>{var NVe=OP(),OVe=jP();function MVe(t){return t!=null&&OVe(t.length)&&!NVe(t)}hte.exports=MVe});var VP=_((vRt,gte)=>{var UVe=VL(),_Ve=pte(),HVe=GI();function qVe(t){return HVe(t)?UVe(t):_Ve(t)}gte.exports=qVe});var XL=_((DRt,dte)=>{var GVe=WL(),jVe=GP(),YVe=VP();function WVe(t){return GVe(t,YVe,jVe)}dte.exports=WVe});var Ete=_((PRt,yte)=>{var mte=XL(),KVe=1,zVe=Object.prototype,VVe=zVe.hasOwnProperty;function JVe(t,e,r,o,a,n){var u=r&KVe,A=mte(t),p=A.length,h=mte(e),E=h.length;if(p!=E&&!u)return!1;for(var I=p;I--;){var v=A[I];if(!(u?v in e:VVe.call(e,v)))return!1}var x=n.get(t),C=n.get(e);if(x&&C)return x==e&&C==t;var R=!0;n.set(t,e),n.set(e,t);for(var N=u;++I<p;){v=A[I];var U=t[v],V=e[v];if(o)var te=u?o(V,U,v,e,t,n):o(U,V,v,t,e,n);if(!(te===void 0?U===V||a(U,V,r,o,n):te)){R=!1;break}N||(N=v==\"constructor\")}if(R&&!N){var ae=t.constructor,fe=e.constructor;ae!=fe&&\"constructor\"in t&&\"constructor\"in e&&!(typeof ae==\"function\"&&ae instanceof ae&&typeof fe==\"function\"&&fe instanceof fe)&&(R=!1)}return n.delete(t),n.delete(e),R}yte.exports=JVe});var wte=_((SRt,Cte)=>{var XVe=Xp(),ZVe=Hl(),$Ve=XVe(ZVe,\"DataView\");Cte.exports=$Ve});var Bte=_((bRt,Ite)=>{var eJe=Xp(),tJe=Hl(),rJe=eJe(tJe,\"Promise\");Ite.exports=rJe});var Dte=_((xRt,vte)=>{var nJe=Xp(),iJe=Hl(),sJe=nJe(iJe,\"Set\");vte.exports=sJe});var Ste=_((kRt,Pte)=>{var oJe=Xp(),aJe=Hl(),lJe=oJe(aJe,\"WeakMap\");Pte.exports=lJe});var jI=_((QRt,Tte)=>{var ZL=wte(),$L=MP(),eN=Bte(),tN=Dte(),rN=Ste(),Rte=gd(),qy=HL(),bte=\"[object Map]\",cJe=\"[object Object]\",xte=\"[object Promise]\",kte=\"[object Set]\",Qte=\"[object WeakMap]\",Fte=\"[object DataView]\",uJe=qy(ZL),AJe=qy($L),fJe=qy(eN),pJe=qy(tN),hJe=qy(rN),dd=Rte;(ZL&&dd(new ZL(new ArrayBuffer(1)))!=Fte||$L&&dd(new $L)!=bte||eN&&dd(eN.resolve())!=xte||tN&&dd(new tN)!=kte||rN&&dd(new rN)!=Qte)&&(dd=function(t){var e=Rte(t),r=e==cJe?t.constructor:void 0,o=r?qy(r):\"\";if(o)switch(o){case uJe:return Fte;case AJe:return bte;case fJe:return xte;case pJe:return kte;case hJe:return Qte}return e});Tte.exports=dd});var qte=_((FRt,Hte)=>{var nN=_P(),gJe=qL(),dJe=kee(),mJe=Ete(),Lte=jI(),Nte=ql(),Ote=UI(),yJe=KP(),EJe=1,Mte=\"[object Arguments]\",Ute=\"[object Array]\",JP=\"[object Object]\",CJe=Object.prototype,_te=CJe.hasOwnProperty;function wJe(t,e,r,o,a,n){var u=Nte(t),A=Nte(e),p=u?Ute:Lte(t),h=A?Ute:Lte(e);p=p==Mte?JP:p,h=h==Mte?JP:h;var E=p==JP,I=h==JP,v=p==h;if(v&&Ote(t)){if(!Ote(e))return!1;u=!0,E=!1}if(v&&!E)return n||(n=new nN),u||yJe(t)?gJe(t,e,r,o,a,n):dJe(t,e,p,r,o,a,n);if(!(r&EJe)){var x=E&&_te.call(t,\"__wrapped__\"),C=I&&_te.call(e,\"__wrapped__\");if(x||C){var R=x?t.value():t,N=C?e.value():e;return n||(n=new nN),a(R,N,r,o,n)}}return v?(n||(n=new nN),mJe(t,e,r,o,a,n)):!1}Hte.exports=wJe});var Wte=_((RRt,Yte)=>{var IJe=qte(),Gte=Ju();function jte(t,e,r,o,a){return t===e?!0:t==null||e==null||!Gte(t)&&!Gte(e)?t!==t&&e!==e:IJe(t,e,r,o,jte,a)}Yte.exports=jte});var zte=_((TRt,Kte)=>{var BJe=Wte();function vJe(t,e){return BJe(t,e)}Kte.exports=vJe});var iN=_((LRt,Vte)=>{var DJe=Xp(),PJe=function(){try{var t=DJe(Object,\"defineProperty\");return t({},\"\",{}),t}catch{}}();Vte.exports=PJe});var XP=_((NRt,Xte)=>{var Jte=iN();function SJe(t,e,r){e==\"__proto__\"&&Jte?Jte(t,e,{configurable:!0,enumerable:!0,value:r,writable:!0}):t[e]=r}Xte.exports=SJe});var sN=_((ORt,Zte)=>{var bJe=XP(),xJe=Ly();function kJe(t,e,r){(r!==void 0&&!xJe(t[e],r)||r===void 0&&!(e in t))&&bJe(t,e,r)}Zte.exports=kJe});var ere=_((MRt,$te)=>{function QJe(t){return function(e,r,o){for(var a=-1,n=Object(e),u=o(e),A=u.length;A--;){var p=u[t?A:++a];if(r(n[p],p,n)===!1)break}return e}}$te.exports=QJe});var rre=_((URt,tre)=>{var FJe=ere(),RJe=FJe();tre.exports=RJe});var oN=_((YI,Gy)=>{var TJe=Hl(),ore=typeof YI==\"object\"&&YI&&!YI.nodeType&&YI,nre=ore&&typeof Gy==\"object\"&&Gy&&!Gy.nodeType&&Gy,LJe=nre&&nre.exports===ore,ire=LJe?TJe.Buffer:void 0,sre=ire?ire.allocUnsafe:void 0;function NJe(t,e){if(e)return t.slice();var r=t.length,o=sre?sre(r):new t.constructor(r);return t.copy(o),o}Gy.exports=NJe});var ZP=_((_Rt,lre)=>{var are=jL();function OJe(t){var e=new t.constructor(t.byteLength);return new are(e).set(new are(t)),e}lre.exports=OJe});var aN=_((HRt,cre)=>{var MJe=ZP();function UJe(t,e){var r=e?MJe(t.buffer):t.buffer;return new t.constructor(r,t.byteOffset,t.length)}cre.exports=UJe});var $P=_((qRt,ure)=>{function _Je(t,e){var r=-1,o=t.length;for(e||(e=Array(o));++r<o;)e[r]=t[r];return e}ure.exports=_Je});var pre=_((GRt,fre)=>{var HJe=sl(),Are=Object.create,qJe=function(){function t(){}return function(e){if(!HJe(e))return{};if(Are)return Are(e);t.prototype=e;var r=new t;return t.prototype=void 0,r}}();fre.exports=qJe});var eS=_((jRt,hre)=>{var GJe=JL(),jJe=GJe(Object.getPrototypeOf,Object);hre.exports=jJe});var lN=_((YRt,gre)=>{var YJe=pre(),WJe=eS(),KJe=zP();function zJe(t){return typeof t.constructor==\"function\"&&!KJe(t)?YJe(WJe(t)):{}}gre.exports=zJe});var mre=_((WRt,dre)=>{var VJe=GI(),JJe=Ju();function XJe(t){return JJe(t)&&VJe(t)}dre.exports=XJe});var cN=_((KRt,Ere)=>{var ZJe=gd(),$Je=eS(),eXe=Ju(),tXe=\"[object Object]\",rXe=Function.prototype,nXe=Object.prototype,yre=rXe.toString,iXe=nXe.hasOwnProperty,sXe=yre.call(Object);function oXe(t){if(!eXe(t)||ZJe(t)!=tXe)return!1;var e=$Je(t);if(e===null)return!0;var r=iXe.call(e,\"constructor\")&&e.constructor;return typeof r==\"function\"&&r instanceof r&&yre.call(r)==sXe}Ere.exports=oXe});var uN=_((zRt,Cre)=>{function aXe(t,e){if(!(e===\"constructor\"&&typeof t[e]==\"function\")&&e!=\"__proto__\")return t[e]}Cre.exports=aXe});var tS=_((VRt,wre)=>{var lXe=XP(),cXe=Ly(),uXe=Object.prototype,AXe=uXe.hasOwnProperty;function fXe(t,e,r){var o=t[e];(!(AXe.call(t,e)&&cXe(o,r))||r===void 0&&!(e in t))&&lXe(t,e,r)}wre.exports=fXe});var md=_((JRt,Ire)=>{var pXe=tS(),hXe=XP();function gXe(t,e,r,o){var a=!r;r||(r={});for(var n=-1,u=e.length;++n<u;){var A=e[n],p=o?o(r[A],t[A],A,r,t):void 0;p===void 0&&(p=t[A]),a?hXe(r,A,p):pXe(r,A,p)}return r}Ire.exports=gXe});var vre=_((XRt,Bre)=>{function dXe(t){var e=[];if(t!=null)for(var r in Object(t))e.push(r);return e}Bre.exports=dXe});var Pre=_((ZRt,Dre)=>{var mXe=sl(),yXe=zP(),EXe=vre(),CXe=Object.prototype,wXe=CXe.hasOwnProperty;function IXe(t){if(!mXe(t))return EXe(t);var e=yXe(t),r=[];for(var o in t)o==\"constructor\"&&(e||!wXe.call(t,o))||r.push(o);return r}Dre.exports=IXe});var jy=_(($Rt,Sre)=>{var BXe=VL(),vXe=Pre(),DXe=GI();function PXe(t){return DXe(t)?BXe(t,!0):vXe(t)}Sre.exports=PXe});var xre=_((eTt,bre)=>{var SXe=md(),bXe=jy();function xXe(t){return SXe(t,bXe(t))}bre.exports=xXe});var Lre=_((tTt,Tre)=>{var kre=sN(),kXe=oN(),QXe=aN(),FXe=$P(),RXe=lN(),Qre=OI(),Fre=ql(),TXe=mre(),LXe=UI(),NXe=OP(),OXe=sl(),MXe=cN(),UXe=KP(),Rre=uN(),_Xe=xre();function HXe(t,e,r,o,a,n,u){var A=Rre(t,r),p=Rre(e,r),h=u.get(p);if(h){kre(t,r,h);return}var E=n?n(A,p,r+\"\",t,e,u):void 0,I=E===void 0;if(I){var v=Fre(p),x=!v&&LXe(p),C=!v&&!x&&UXe(p);E=p,v||x||C?Fre(A)?E=A:TXe(A)?E=FXe(A):x?(I=!1,E=kXe(p,!0)):C?(I=!1,E=QXe(p,!0)):E=[]:MXe(p)||Qre(p)?(E=A,Qre(A)?E=_Xe(A):(!OXe(A)||NXe(A))&&(E=RXe(p))):I=!1}I&&(u.set(p,E),a(E,p,o,n,u),u.delete(p)),kre(t,r,E)}Tre.exports=HXe});var Mre=_((rTt,Ore)=>{var qXe=_P(),GXe=sN(),jXe=rre(),YXe=Lre(),WXe=sl(),KXe=jy(),zXe=uN();function Nre(t,e,r,o,a){t!==e&&jXe(e,function(n,u){if(a||(a=new qXe),WXe(n))YXe(t,e,u,r,Nre,o,a);else{var A=o?o(zXe(t,u),n,u+\"\",t,e,a):void 0;A===void 0&&(A=n),GXe(t,u,A)}},KXe)}Ore.exports=Nre});var AN=_((nTt,Ure)=>{function VXe(t){return t}Ure.exports=VXe});var Hre=_((iTt,_re)=>{function JXe(t,e,r){switch(r.length){case 0:return t.call(e);case 1:return t.call(e,r[0]);case 2:return t.call(e,r[0],r[1]);case 3:return t.call(e,r[0],r[1],r[2])}return t.apply(e,r)}_re.exports=JXe});var fN=_((sTt,Gre)=>{var XXe=Hre(),qre=Math.max;function ZXe(t,e,r){return e=qre(e===void 0?t.length-1:e,0),function(){for(var o=arguments,a=-1,n=qre(o.length-e,0),u=Array(n);++a<n;)u[a]=o[e+a];a=-1;for(var A=Array(e+1);++a<e;)A[a]=o[a];return A[e]=r(u),XXe(t,this,A)}}Gre.exports=ZXe});var Yre=_((oTt,jre)=>{function $Xe(t){return function(){return t}}jre.exports=$Xe});var zre=_((aTt,Kre)=>{var eZe=Yre(),Wre=iN(),tZe=AN(),rZe=Wre?function(t,e){return Wre(t,\"toString\",{configurable:!0,enumerable:!1,value:eZe(e),writable:!0})}:tZe;Kre.exports=rZe});var Jre=_((lTt,Vre)=>{var nZe=800,iZe=16,sZe=Date.now;function oZe(t){var e=0,r=0;return function(){var o=sZe(),a=iZe-(o-r);if(r=o,a>0){if(++e>=nZe)return arguments[0]}else e=0;return t.apply(void 0,arguments)}}Vre.exports=oZe});var pN=_((cTt,Xre)=>{var aZe=zre(),lZe=Jre(),cZe=lZe(aZe);Xre.exports=cZe});var $re=_((uTt,Zre)=>{var uZe=AN(),AZe=fN(),fZe=pN();function pZe(t,e){return fZe(AZe(t,e,uZe),t+\"\")}Zre.exports=pZe});var tne=_((ATt,ene)=>{var hZe=Ly(),gZe=GI(),dZe=_I(),mZe=sl();function yZe(t,e,r){if(!mZe(r))return!1;var o=typeof e;return(o==\"number\"?gZe(r)&&dZe(e,r.length):o==\"string\"&&e in r)?hZe(r[e],t):!1}ene.exports=yZe});var nne=_((fTt,rne)=>{var EZe=$re(),CZe=tne();function wZe(t){return EZe(function(e,r){var o=-1,a=r.length,n=a>1?r[a-1]:void 0,u=a>2?r[2]:void 0;for(n=t.length>3&&typeof n==\"function\"?(a--,n):void 0,u&&CZe(r[0],r[1],u)&&(n=a<3?void 0:n,a=1),e=Object(e);++o<a;){var A=r[o];A&&t(e,A,o,n)}return e})}rne.exports=wZe});var sne=_((pTt,ine)=>{var IZe=Mre(),BZe=nne(),vZe=BZe(function(t,e,r,o){IZe(t,e,r,o)});ine.exports=vZe});var _e={};zt(_e,{AsyncActions:()=>dN,BufferStream:()=>gN,CachingStrategy:()=>mne,DefaultStream:()=>mN,allSettledSafe:()=>_c,assertNever:()=>EN,bufferStream:()=>zy,buildIgnorePattern:()=>QZe,convertMapsToIndexableObjects:()=>nS,dynamicRequire:()=>Df,escapeRegExp:()=>PZe,getArrayWithDefault:()=>Yy,getFactoryWithDefault:()=>al,getMapWithDefault:()=>Wy,getSetWithDefault:()=>yd,groupBy:()=>IN,isIndexableObject:()=>hN,isPathLike:()=>FZe,isTaggedYarnVersion:()=>DZe,makeDeferred:()=>hne,mapAndFilter:()=>ol,mapAndFind:()=>KI,mergeIntoTarget:()=>Ene,overrideType:()=>SZe,parseBoolean:()=>zI,parseInt:()=>Vy,parseOptionalBoolean:()=>yne,plural:()=>rS,prettifyAsyncErrors:()=>Ky,prettifySyncErrors:()=>CN,releaseAfterUseAsync:()=>xZe,replaceEnvVariables:()=>iS,sortMap:()=>ks,toMerged:()=>RZe,tryParseOptionalBoolean:()=>wN,validateEnum:()=>bZe});function DZe(t){return!!(Ane.default.valid(t)&&t.match(/^[^-]+(-rc\\.[0-9]+)?$/))}function rS(t,{one:e,more:r,zero:o=r}){return t===0?o:t===1?e:r}function PZe(t){return t.replace(/[.*+?^${}()|[\\]\\\\]/g,\"\\\\$&\")}function SZe(t){}function EN(t){throw new Error(`Assertion failed: Unexpected object '${t}'`)}function bZe(t,e){let r=Object.values(t);if(!r.includes(e))throw new it(`Invalid value for enumeration: ${JSON.stringify(e)} (expected one of ${r.map(o=>JSON.stringify(o)).join(\", \")})`);return e}function ol(t,e){let r=[];for(let o of t){let a=e(o);a!==fne&&r.push(a)}return r}function KI(t,e){for(let r of t){let o=e(r);if(o!==pne)return o}}function hN(t){return typeof t==\"object\"&&t!==null}async function _c(t){let e=await Promise.allSettled(t),r=[];for(let o of e){if(o.status===\"rejected\")throw o.reason;r.push(o.value)}return r}function nS(t){if(t instanceof Map&&(t=Object.fromEntries(t)),hN(t))for(let e of Object.keys(t)){let r=t[e];hN(r)&&(t[e]=nS(r))}return t}function al(t,e,r){let o=t.get(e);return typeof o>\"u\"&&t.set(e,o=r()),o}function Yy(t,e){let r=t.get(e);return typeof r>\"u\"&&t.set(e,r=[]),r}function yd(t,e){let r=t.get(e);return typeof r>\"u\"&&t.set(e,r=new Set),r}function Wy(t,e){let r=t.get(e);return typeof r>\"u\"&&t.set(e,r=new Map),r}async function xZe(t,e){if(e==null)return await t();try{return await t()}finally{await e()}}async function Ky(t,e){try{return await t()}catch(r){throw r.message=e(r.message),r}}function CN(t,e){try{return t()}catch(r){throw r.message=e(r.message),r}}async function zy(t){return await new Promise((e,r)=>{let o=[];t.on(\"error\",a=>{r(a)}),t.on(\"data\",a=>{o.push(a)}),t.on(\"end\",()=>{e(Buffer.concat(o))})})}function hne(){let t,e;return{promise:new Promise((o,a)=>{t=o,e=a}),resolve:t,reject:e}}function gne(t){return WI(le.fromPortablePath(t))}function dne(path){let physicalPath=le.fromPortablePath(path),currentCacheEntry=WI.cache[physicalPath];delete WI.cache[physicalPath];let result;try{result=gne(physicalPath);let freshCacheEntry=WI.cache[physicalPath],dynamicModule=eval(\"module\"),freshCacheIndex=dynamicModule.children.indexOf(freshCacheEntry);freshCacheIndex!==-1&&dynamicModule.children.splice(freshCacheIndex,1)}finally{WI.cache[physicalPath]=currentCacheEntry}return result}function kZe(t){let e=one.get(t),r=oe.statSync(t);if(e?.mtime===r.mtimeMs)return e.instance;let o=dne(t);return one.set(t,{mtime:r.mtimeMs,instance:o}),o}function Df(t,{cachingStrategy:e=2}={}){switch(e){case 0:return dne(t);case 1:return kZe(t);case 2:return gne(t);default:throw new Error(\"Unsupported caching strategy\")}}function ks(t,e){let r=Array.from(t);Array.isArray(e)||(e=[e]);let o=[];for(let n of e)o.push(r.map(u=>n(u)));let a=r.map((n,u)=>u);return a.sort((n,u)=>{for(let A of o){let p=A[n]<A[u]?-1:A[n]>A[u]?1:0;if(p!==0)return p}return 0}),a.map(n=>r[n])}function QZe(t){return t.length===0?null:t.map(e=>`(${cne.default.makeRe(e,{windows:!1,dot:!0}).source})`).join(\"|\")}function iS(t,{env:e}){let r=/\\${(?<variableName>[\\d\\w_]+)(?<colon>:)?(?:-(?<fallback>[^}]*))?}/g;return t.replace(r,(...o)=>{let{variableName:a,colon:n,fallback:u}=o[o.length-1],A=Object.hasOwn(e,a),p=e[a];if(p||A&&!n)return p;if(u!=null)return u;throw new it(`Environment variable not found (${a})`)})}function zI(t){switch(t){case\"true\":case\"1\":case 1:case!0:return!0;case\"false\":case\"0\":case 0:case!1:return!1;default:throw new Error(`Couldn't parse \"${t}\" as a boolean`)}}function yne(t){return typeof t>\"u\"?t:zI(t)}function wN(t){try{return yne(t)}catch{return null}}function FZe(t){return!!(le.isAbsolute(t)||t.match(/^(\\.{1,2}|~)\\//))}function Ene(t,...e){let r=u=>({value:u}),o=r(t),a=e.map(u=>r(u)),{value:n}=(0,lne.default)(o,...a,(u,A)=>{if(Array.isArray(u)&&Array.isArray(A)){for(let p of A)u.find(h=>(0,ane.default)(h,p))||u.push(p);return u}});return n}function RZe(...t){return Ene({},...t)}function IN(t,e){let r=Object.create(null);for(let o of t){let a=o[e];r[a]??=[],r[a].push(o)}return r}function Vy(t){return typeof t==\"string\"?Number.parseInt(t,10):t}var ane,lne,cne,une,Ane,yN,fne,pne,gN,dN,mN,WI,one,mne,Gl=Et(()=>{Pt();qt();ane=$e(zte()),lne=$e(sne()),cne=$e(Zo()),une=$e(sd()),Ane=$e(Jn()),yN=ve(\"stream\");fne=Symbol();ol.skip=fne;pne=Symbol();KI.skip=pne;gN=class extends yN.Transform{constructor(){super(...arguments);this.chunks=[]}_transform(r,o,a){if(o!==\"buffer\"||!Buffer.isBuffer(r))throw new Error(\"Assertion failed: BufferStream only accept buffers\");this.chunks.push(r),a(null,null)}_flush(r){r(null,Buffer.concat(this.chunks))}};dN=class{constructor(e){this.deferred=new Map;this.promises=new Map;this.limit=(0,une.default)(e)}set(e,r){let o=this.deferred.get(e);typeof o>\"u\"&&this.deferred.set(e,o=hne());let a=this.limit(()=>r());return this.promises.set(e,a),a.then(()=>{this.promises.get(e)===a&&o.resolve()},n=>{this.promises.get(e)===a&&o.reject(n)}),o.promise}reduce(e,r){let o=this.promises.get(e)??Promise.resolve();this.set(e,()=>r(o))}async wait(){await Promise.all(this.promises.values())}},mN=class extends yN.Transform{constructor(r=Buffer.alloc(0)){super();this.active=!0;this.ifEmpty=r}_transform(r,o,a){if(o!==\"buffer\"||!Buffer.isBuffer(r))throw new Error(\"Assertion failed: DefaultStream only accept buffers\");this.active=!1,a(null,r)}_flush(r){this.active&&this.ifEmpty.length>0?r(null,this.ifEmpty):r(null)}},WI=eval(\"require\");one=new Map;mne=(o=>(o[o.NoCache=0]=\"NoCache\",o[o.FsTime=1]=\"FsTime\",o[o.Node=2]=\"Node\",o))(mne||{})});var Jy,BN,vN,Cne=Et(()=>{Jy=(r=>(r.HARD=\"HARD\",r.SOFT=\"SOFT\",r))(Jy||{}),BN=(o=>(o.Dependency=\"Dependency\",o.PeerDependency=\"PeerDependency\",o.PeerDependencyMeta=\"PeerDependencyMeta\",o))(BN||{}),vN=(o=>(o.Inactive=\"inactive\",o.Redundant=\"redundant\",o.Active=\"active\",o))(vN||{})});var de={};zt(de,{LogLevel:()=>cS,Style:()=>oS,Type:()=>yt,addLogFilterSupport:()=>XI,applyColor:()=>zs,applyHyperlink:()=>Zy,applyStyle:()=>Ed,json:()=>Cd,jsonOrPretty:()=>NZe,mark:()=>xN,pretty:()=>Ut,prettyField:()=>Xu,prettyList:()=>bN,prettyTruncatedLocatorList:()=>lS,stripAnsi:()=>Xy.default,supportsColor:()=>aS,supportsHyperlinks:()=>SN,tuple:()=>Hc});function wne(t){let e=[\"KiB\",\"MiB\",\"GiB\",\"TiB\"],r=e.length;for(;r>1&&t<1024**r;)r-=1;let o=1024**r;return`${Math.floor(t*100/o)/100} ${e[r-1]}`}function Hc(t,e){return[e,t]}function Ed(t,e,r){return t.get(\"enableColors\")&&r&2&&(e=JI.default.bold(e)),e}function zs(t,e,r){if(!t.get(\"enableColors\"))return e;let o=TZe.get(r);if(o===null)return e;let a=typeof o>\"u\"?r:PN.level>=3?o[0]:o[1],n=typeof a==\"number\"?DN.ansi256(a):a.startsWith(\"#\")?DN.hex(a):DN[a];if(typeof n!=\"function\")throw new Error(`Invalid format type ${a}`);return n(e)}function Zy(t,e,r){return t.get(\"enableHyperlinks\")?LZe?`\\x1B]8;;${r}\\x1B\\\\${e}\\x1B]8;;\\x1B\\\\`:`\\x1B]8;;${r}\\x07${e}\\x1B]8;;\\x07`:e}function Ut(t,e,r){if(e===null)return zs(t,\"null\",yt.NULL);if(Object.hasOwn(sS,r))return sS[r].pretty(t,e);if(typeof e!=\"string\")throw new Error(`Assertion failed: Expected the value to be a string, got ${typeof e}`);return zs(t,e,r)}function bN(t,e,r,{separator:o=\", \"}={}){return[...e].map(a=>Ut(t,a,r)).join(o)}function Cd(t,e){if(t===null)return null;if(Object.hasOwn(sS,e))return sS[e].json(t);if(typeof t!=\"string\")throw new Error(`Assertion failed: Expected the value to be a string, got ${typeof t}`);return t}function NZe(t,e,[r,o]){return t?Cd(r,o):Ut(e,r,o)}function xN(t){return{Check:zs(t,\"\\u2713\",\"green\"),Cross:zs(t,\"\\u2718\",\"red\"),Question:zs(t,\"?\",\"cyan\")}}function Xu(t,{label:e,value:[r,o]}){return`${Ut(t,e,yt.CODE)}: ${Ut(t,r,o)}`}function lS(t,e,r){let o=[],a=[...e],n=r;for(;a.length>0;){let h=a[0],E=`${qr(t,h)}, `,I=kN(h).length+2;if(o.length>0&&n<I)break;o.push([E,I]),n-=I,a.shift()}if(a.length===0)return o.map(([h])=>h).join(\"\").slice(0,-2);let u=\"X\".repeat(a.length.toString().length),A=`and ${u} more.`,p=a.length;for(;o.length>1&&n<A.length;)n+=o[o.length-1][1],p+=1,o.pop();return[o.map(([h])=>h).join(\"\"),A.replace(u,Ut(t,p,yt.NUMBER))].join(\"\")}function XI(t,{configuration:e}){let r=e.get(\"logFilters\"),o=new Map,a=new Map,n=[];for(let I of r){let v=I.get(\"level\");if(typeof v>\"u\")continue;let x=I.get(\"code\");typeof x<\"u\"&&o.set(x,v);let C=I.get(\"text\");typeof C<\"u\"&&a.set(C,v);let R=I.get(\"pattern\");typeof R<\"u\"&&n.push([Ine.default.matcher(R,{contains:!0}),v])}n.reverse();let u=(I,v,x)=>{if(I===null||I===0)return x;let C=a.size>0||n.length>0?(0,Xy.default)(v):v;if(a.size>0){let R=a.get(C);if(typeof R<\"u\")return R??x}if(n.length>0){for(let[R,N]of n)if(R(C))return N??x}if(o.size>0){let R=o.get(Ku(I));if(typeof R<\"u\")return R??x}return x},A=t.reportInfo,p=t.reportWarning,h=t.reportError,E=function(I,v,x,C){switch(u(v,x,C)){case\"info\":A.call(I,v,x);break;case\"warning\":p.call(I,v??0,x);break;case\"error\":h.call(I,v??0,x);break}};t.reportInfo=function(...I){return E(this,...I,\"info\")},t.reportWarning=function(...I){return E(this,...I,\"warning\")},t.reportError=function(...I){return E(this,...I,\"error\")}}var JI,VI,Ine,Xy,Bne,yt,oS,PN,aS,SN,DN,TZe,So,sS,LZe,cS,jl=Et(()=>{Pt();JI=$e(IL()),VI=$e(rd());qt();Ine=$e(Zo()),Xy=$e(NP()),Bne=ve(\"util\");fP();bo();yt={NO_HINT:\"NO_HINT\",ID:\"ID\",NULL:\"NULL\",SCOPE:\"SCOPE\",NAME:\"NAME\",RANGE:\"RANGE\",REFERENCE:\"REFERENCE\",NUMBER:\"NUMBER\",PATH:\"PATH\",URL:\"URL\",ADDED:\"ADDED\",REMOVED:\"REMOVED\",CODE:\"CODE\",INSPECT:\"INSPECT\",DURATION:\"DURATION\",SIZE:\"SIZE\",SIZE_DIFF:\"SIZE_DIFF\",IDENT:\"IDENT\",DESCRIPTOR:\"DESCRIPTOR\",LOCATOR:\"LOCATOR\",RESOLUTION:\"RESOLUTION\",DEPENDENT:\"DEPENDENT\",PACKAGE_EXTENSION:\"PACKAGE_EXTENSION\",SETTING:\"SETTING\",MARKDOWN:\"MARKDOWN\",MARKDOWN_INLINE:\"MARKDOWN_INLINE\"},oS=(e=>(e[e.BOLD=2]=\"BOLD\",e))(oS||{}),PN=VI.default.GITHUB_ACTIONS?{level:2}:JI.default.supportsColor?{level:JI.default.supportsColor.level}:{level:0},aS=PN.level!==0,SN=aS&&!VI.default.GITHUB_ACTIONS&&!VI.default.CIRCLE&&!VI.default.GITLAB,DN=new JI.default.Instance(PN),TZe=new Map([[yt.NO_HINT,null],[yt.NULL,[\"#a853b5\",129]],[yt.SCOPE,[\"#d75f00\",166]],[yt.NAME,[\"#d7875f\",173]],[yt.RANGE,[\"#00afaf\",37]],[yt.REFERENCE,[\"#87afff\",111]],[yt.NUMBER,[\"#ffd700\",220]],[yt.PATH,[\"#d75fd7\",170]],[yt.URL,[\"#d75fd7\",170]],[yt.ADDED,[\"#5faf00\",70]],[yt.REMOVED,[\"#ff3131\",160]],[yt.CODE,[\"#87afff\",111]],[yt.SIZE,[\"#ffd700\",220]]]),So=t=>t;sS={[yt.ID]:So({pretty:(t,e)=>typeof e==\"number\"?zs(t,`${e}`,yt.NUMBER):zs(t,e,yt.CODE),json:t=>t}),[yt.INSPECT]:So({pretty:(t,e)=>(0,Bne.inspect)(e,{depth:1/0,colors:t.get(\"enableColors\"),compact:!0,breakLength:1/0}),json:t=>t}),[yt.NUMBER]:So({pretty:(t,e)=>zs(t,`${e}`,yt.NUMBER),json:t=>t}),[yt.IDENT]:So({pretty:(t,e)=>cs(t,e),json:t=>fn(t)}),[yt.LOCATOR]:So({pretty:(t,e)=>qr(t,e),json:t=>ba(t)}),[yt.DESCRIPTOR]:So({pretty:(t,e)=>Gn(t,e),json:t=>Sa(t)}),[yt.RESOLUTION]:So({pretty:(t,{descriptor:e,locator:r})=>ZI(t,e,r),json:({descriptor:t,locator:e})=>({descriptor:Sa(t),locator:e!==null?ba(e):null})}),[yt.DEPENDENT]:So({pretty:(t,{locator:e,descriptor:r})=>QN(t,e,r),json:({locator:t,descriptor:e})=>({locator:ba(t),descriptor:Sa(e)})}),[yt.PACKAGE_EXTENSION]:So({pretty:(t,e)=>{switch(e.type){case\"Dependency\":return`${cs(t,e.parentDescriptor)} \\u27A4 ${zs(t,\"dependencies\",yt.CODE)} \\u27A4 ${cs(t,e.descriptor)}`;case\"PeerDependency\":return`${cs(t,e.parentDescriptor)} \\u27A4 ${zs(t,\"peerDependencies\",yt.CODE)} \\u27A4 ${cs(t,e.descriptor)}`;case\"PeerDependencyMeta\":return`${cs(t,e.parentDescriptor)} \\u27A4 ${zs(t,\"peerDependenciesMeta\",yt.CODE)} \\u27A4 ${cs(t,Vs(e.selector))} \\u27A4 ${zs(t,e.key,yt.CODE)}`;default:throw new Error(`Assertion failed: Unsupported package extension type: ${e.type}`)}},json:t=>{switch(t.type){case\"Dependency\":return`${fn(t.parentDescriptor)} > ${fn(t.descriptor)}`;case\"PeerDependency\":return`${fn(t.parentDescriptor)} >> ${fn(t.descriptor)}`;case\"PeerDependencyMeta\":return`${fn(t.parentDescriptor)} >> ${t.selector} / ${t.key}`;default:throw new Error(`Assertion failed: Unsupported package extension type: ${t.type}`)}}}),[yt.SETTING]:So({pretty:(t,e)=>(t.get(e),Zy(t,zs(t,e,yt.CODE),`https://yarnpkg.com/configuration/yarnrc#${e}`)),json:t=>t}),[yt.DURATION]:So({pretty:(t,e)=>{if(e>1e3*60){let r=Math.floor(e/1e3/60),o=Math.ceil((e-r*60*1e3)/1e3);return o===0?`${r}m`:`${r}m ${o}s`}else{let r=Math.floor(e/1e3),o=e-r*1e3;return o===0?`${r}s`:`${r}s ${o}ms`}},json:t=>t}),[yt.SIZE]:So({pretty:(t,e)=>zs(t,wne(e),yt.NUMBER),json:t=>t}),[yt.SIZE_DIFF]:So({pretty:(t,e)=>{let r=e>=0?\"+\":\"-\",o=r===\"+\"?yt.REMOVED:yt.ADDED;return zs(t,`${r} ${wne(Math.max(Math.abs(e),1))}`,o)},json:t=>t}),[yt.PATH]:So({pretty:(t,e)=>zs(t,le.fromPortablePath(e),yt.PATH),json:t=>le.fromPortablePath(t)}),[yt.MARKDOWN]:So({pretty:(t,{text:e,format:r,paragraphs:o})=>Do(e,{format:r,paragraphs:o}),json:({text:t})=>t}),[yt.MARKDOWN_INLINE]:So({pretty:(t,e)=>(e=e.replace(/(`+)((?:.|[\\n])*?)\\1/g,(r,o,a)=>Ut(t,o+a+o,yt.CODE)),e=e.replace(/(\\*\\*)((?:.|[\\n])*?)\\1/g,(r,o,a)=>Ed(t,a,2)),e),json:t=>t})};LZe=!!process.env.KONSOLE_VERSION;cS=(a=>(a.Error=\"error\",a.Warning=\"warning\",a.Info=\"info\",a.Discard=\"discard\",a))(cS||{})});var vne=_($y=>{\"use strict\";Object.defineProperty($y,\"__esModule\",{value:!0});$y.splitWhen=$y.flatten=void 0;function OZe(t){return t.reduce((e,r)=>[].concat(e,r),[])}$y.flatten=OZe;function MZe(t,e){let r=[[]],o=0;for(let a of t)e(a)?(o++,r[o]=[]):r[o].push(a);return r}$y.splitWhen=MZe});var Dne=_(uS=>{\"use strict\";Object.defineProperty(uS,\"__esModule\",{value:!0});uS.isEnoentCodeError=void 0;function UZe(t){return t.code===\"ENOENT\"}uS.isEnoentCodeError=UZe});var Pne=_(AS=>{\"use strict\";Object.defineProperty(AS,\"__esModule\",{value:!0});AS.createDirentFromStats=void 0;var FN=class{constructor(e,r){this.name=e,this.isBlockDevice=r.isBlockDevice.bind(r),this.isCharacterDevice=r.isCharacterDevice.bind(r),this.isDirectory=r.isDirectory.bind(r),this.isFIFO=r.isFIFO.bind(r),this.isFile=r.isFile.bind(r),this.isSocket=r.isSocket.bind(r),this.isSymbolicLink=r.isSymbolicLink.bind(r)}};function _Ze(t,e){return new FN(t,e)}AS.createDirentFromStats=_Ze});var Sne=_(Zu=>{\"use strict\";Object.defineProperty(Zu,\"__esModule\",{value:!0});Zu.removeLeadingDotSegment=Zu.escape=Zu.makeAbsolute=Zu.unixify=void 0;var HZe=ve(\"path\"),qZe=2,GZe=/(\\\\?)([()*?[\\]{|}]|^!|[!+@](?=\\())/g;function jZe(t){return t.replace(/\\\\/g,\"/\")}Zu.unixify=jZe;function YZe(t,e){return HZe.resolve(t,e)}Zu.makeAbsolute=YZe;function WZe(t){return t.replace(GZe,\"\\\\$2\")}Zu.escape=WZe;function KZe(t){if(t.charAt(0)===\".\"){let e=t.charAt(1);if(e===\"/\"||e===\"\\\\\")return t.slice(qZe)}return t}Zu.removeLeadingDotSegment=KZe});var xne=_((bTt,bne)=>{bne.exports=function(e){if(typeof e!=\"string\"||e===\"\")return!1;for(var r;r=/(\\\\).|([@?!+*]\\(.*\\))/g.exec(e);){if(r[2])return!0;e=e.slice(r.index+r[0].length)}return!1}});var Fne=_((xTt,Qne)=>{var zZe=xne(),kne={\"{\":\"}\",\"(\":\")\",\"[\":\"]\"},VZe=function(t){if(t[0]===\"!\")return!0;for(var e=0,r=-2,o=-2,a=-2,n=-2,u=-2;e<t.length;){if(t[e]===\"*\"||t[e+1]===\"?\"&&/[\\].+)]/.test(t[e])||o!==-1&&t[e]===\"[\"&&t[e+1]!==\"]\"&&(o<e&&(o=t.indexOf(\"]\",e)),o>e&&(u===-1||u>o||(u=t.indexOf(\"\\\\\",e),u===-1||u>o)))||a!==-1&&t[e]===\"{\"&&t[e+1]!==\"}\"&&(a=t.indexOf(\"}\",e),a>e&&(u=t.indexOf(\"\\\\\",e),u===-1||u>a))||n!==-1&&t[e]===\"(\"&&t[e+1]===\"?\"&&/[:!=]/.test(t[e+2])&&t[e+3]!==\")\"&&(n=t.indexOf(\")\",e),n>e&&(u=t.indexOf(\"\\\\\",e),u===-1||u>n))||r!==-1&&t[e]===\"(\"&&t[e+1]!==\"|\"&&(r<e&&(r=t.indexOf(\"|\",e)),r!==-1&&t[r+1]!==\")\"&&(n=t.indexOf(\")\",r),n>r&&(u=t.indexOf(\"\\\\\",r),u===-1||u>n))))return!0;if(t[e]===\"\\\\\"){var A=t[e+1];e+=2;var p=kne[A];if(p){var h=t.indexOf(p,e);h!==-1&&(e=h+1)}if(t[e]===\"!\")return!0}else e++}return!1},JZe=function(t){if(t[0]===\"!\")return!0;for(var e=0;e<t.length;){if(/[*?{}()[\\]]/.test(t[e]))return!0;if(t[e]===\"\\\\\"){var r=t[e+1];e+=2;var o=kne[r];if(o){var a=t.indexOf(o,e);a!==-1&&(e=a+1)}if(t[e]===\"!\")return!0}else e++}return!1};Qne.exports=function(e,r){if(typeof e!=\"string\"||e===\"\")return!1;if(zZe(e))return!0;var o=VZe;return r&&r.strict===!1&&(o=JZe),o(e)}});var Tne=_((kTt,Rne)=>{\"use strict\";var XZe=Fne(),ZZe=ve(\"path\").posix.dirname,$Ze=ve(\"os\").platform()===\"win32\",RN=\"/\",e$e=/\\\\/g,t$e=/[\\{\\[].*[\\}\\]]$/,r$e=/(^|[^\\\\])([\\{\\[]|\\([^\\)]+$)/,n$e=/\\\\([\\!\\*\\?\\|\\[\\]\\(\\)\\{\\}])/g;Rne.exports=function(e,r){var o=Object.assign({flipBackslashes:!0},r);o.flipBackslashes&&$Ze&&e.indexOf(RN)<0&&(e=e.replace(e$e,RN)),t$e.test(e)&&(e+=RN),e+=\"a\";do e=ZZe(e);while(XZe(e)||r$e.test(e));return e.replace(n$e,\"$1\")}});var qne=_(Gr=>{\"use strict\";Object.defineProperty(Gr,\"__esModule\",{value:!0});Gr.matchAny=Gr.convertPatternsToRe=Gr.makeRe=Gr.getPatternParts=Gr.expandBraceExpansion=Gr.expandPatternsWithBraceExpansion=Gr.isAffectDepthOfReadingPattern=Gr.endsWithSlashGlobStar=Gr.hasGlobStar=Gr.getBaseDirectory=Gr.isPatternRelatedToParentDirectory=Gr.getPatternsOutsideCurrentDirectory=Gr.getPatternsInsideCurrentDirectory=Gr.getPositivePatterns=Gr.getNegativePatterns=Gr.isPositivePattern=Gr.isNegativePattern=Gr.convertToNegativePattern=Gr.convertToPositivePattern=Gr.isDynamicPattern=Gr.isStaticPattern=void 0;var i$e=ve(\"path\"),s$e=Tne(),TN=Zo(),Lne=\"**\",o$e=\"\\\\\",a$e=/[*?]|^!/,l$e=/\\[[^[]*]/,c$e=/(?:^|[^!*+?@])\\([^(]*\\|[^|]*\\)/,u$e=/[!*+?@]\\([^(]*\\)/,A$e=/,|\\.\\./;function Nne(t,e={}){return!One(t,e)}Gr.isStaticPattern=Nne;function One(t,e={}){return t===\"\"?!1:!!(e.caseSensitiveMatch===!1||t.includes(o$e)||a$e.test(t)||l$e.test(t)||c$e.test(t)||e.extglob!==!1&&u$e.test(t)||e.braceExpansion!==!1&&f$e(t))}Gr.isDynamicPattern=One;function f$e(t){let e=t.indexOf(\"{\");if(e===-1)return!1;let r=t.indexOf(\"}\",e+1);if(r===-1)return!1;let o=t.slice(e,r);return A$e.test(o)}function p$e(t){return fS(t)?t.slice(1):t}Gr.convertToPositivePattern=p$e;function h$e(t){return\"!\"+t}Gr.convertToNegativePattern=h$e;function fS(t){return t.startsWith(\"!\")&&t[1]!==\"(\"}Gr.isNegativePattern=fS;function Mne(t){return!fS(t)}Gr.isPositivePattern=Mne;function g$e(t){return t.filter(fS)}Gr.getNegativePatterns=g$e;function d$e(t){return t.filter(Mne)}Gr.getPositivePatterns=d$e;function m$e(t){return t.filter(e=>!LN(e))}Gr.getPatternsInsideCurrentDirectory=m$e;function y$e(t){return t.filter(LN)}Gr.getPatternsOutsideCurrentDirectory=y$e;function LN(t){return t.startsWith(\"..\")||t.startsWith(\"./..\")}Gr.isPatternRelatedToParentDirectory=LN;function E$e(t){return s$e(t,{flipBackslashes:!1})}Gr.getBaseDirectory=E$e;function C$e(t){return t.includes(Lne)}Gr.hasGlobStar=C$e;function Une(t){return t.endsWith(\"/\"+Lne)}Gr.endsWithSlashGlobStar=Une;function w$e(t){let e=i$e.basename(t);return Une(t)||Nne(e)}Gr.isAffectDepthOfReadingPattern=w$e;function I$e(t){return t.reduce((e,r)=>e.concat(_ne(r)),[])}Gr.expandPatternsWithBraceExpansion=I$e;function _ne(t){return TN.braces(t,{expand:!0,nodupes:!0})}Gr.expandBraceExpansion=_ne;function B$e(t,e){let{parts:r}=TN.scan(t,Object.assign(Object.assign({},e),{parts:!0}));return r.length===0&&(r=[t]),r[0].startsWith(\"/\")&&(r[0]=r[0].slice(1),r.unshift(\"\")),r}Gr.getPatternParts=B$e;function Hne(t,e){return TN.makeRe(t,e)}Gr.makeRe=Hne;function v$e(t,e){return t.map(r=>Hne(r,e))}Gr.convertPatternsToRe=v$e;function D$e(t,e){return e.some(r=>r.test(t))}Gr.matchAny=D$e});var Wne=_((FTt,Yne)=>{\"use strict\";var P$e=ve(\"stream\"),Gne=P$e.PassThrough,S$e=Array.prototype.slice;Yne.exports=b$e;function b$e(){let t=[],e=S$e.call(arguments),r=!1,o=e[e.length-1];o&&!Array.isArray(o)&&o.pipe==null?e.pop():o={};let a=o.end!==!1,n=o.pipeError===!0;o.objectMode==null&&(o.objectMode=!0),o.highWaterMark==null&&(o.highWaterMark=64*1024);let u=Gne(o);function A(){for(let E=0,I=arguments.length;E<I;E++)t.push(jne(arguments[E],o));return p(),this}function p(){if(r)return;r=!0;let E=t.shift();if(!E){process.nextTick(h);return}Array.isArray(E)||(E=[E]);let I=E.length+1;function v(){--I>0||(r=!1,p())}function x(C){function R(){C.removeListener(\"merge2UnpipeEnd\",R),C.removeListener(\"end\",R),n&&C.removeListener(\"error\",N),v()}function N(U){u.emit(\"error\",U)}if(C._readableState.endEmitted)return v();C.on(\"merge2UnpipeEnd\",R),C.on(\"end\",R),n&&C.on(\"error\",N),C.pipe(u,{end:!1}),C.resume()}for(let C=0;C<E.length;C++)x(E[C]);v()}function h(){r=!1,u.emit(\"queueDrain\"),a&&u.end()}return u.setMaxListeners(0),u.add=A,u.on(\"unpipe\",function(E){E.emit(\"merge2UnpipeEnd\")}),e.length&&A.apply(null,e),u}function jne(t,e){if(Array.isArray(t))for(let r=0,o=t.length;r<o;r++)t[r]=jne(t[r],e);else{if(!t._readableState&&t.pipe&&(t=t.pipe(Gne(e))),!t._readableState||!t.pause||!t.pipe)throw new Error(\"Only readable stream can be merged.\");t.pause()}return t}});var zne=_(pS=>{\"use strict\";Object.defineProperty(pS,\"__esModule\",{value:!0});pS.merge=void 0;var x$e=Wne();function k$e(t){let e=x$e(t);return t.forEach(r=>{r.once(\"error\",o=>e.emit(\"error\",o))}),e.once(\"close\",()=>Kne(t)),e.once(\"end\",()=>Kne(t)),e}pS.merge=k$e;function Kne(t){t.forEach(e=>e.emit(\"close\"))}});var Vne=_(eE=>{\"use strict\";Object.defineProperty(eE,\"__esModule\",{value:!0});eE.isEmpty=eE.isString=void 0;function Q$e(t){return typeof t==\"string\"}eE.isString=Q$e;function F$e(t){return t===\"\"}eE.isEmpty=F$e});var Pf=_(xo=>{\"use strict\";Object.defineProperty(xo,\"__esModule\",{value:!0});xo.string=xo.stream=xo.pattern=xo.path=xo.fs=xo.errno=xo.array=void 0;var R$e=vne();xo.array=R$e;var T$e=Dne();xo.errno=T$e;var L$e=Pne();xo.fs=L$e;var N$e=Sne();xo.path=N$e;var O$e=qne();xo.pattern=O$e;var M$e=zne();xo.stream=M$e;var U$e=Vne();xo.string=U$e});var Zne=_(ko=>{\"use strict\";Object.defineProperty(ko,\"__esModule\",{value:!0});ko.convertPatternGroupToTask=ko.convertPatternGroupsToTasks=ko.groupPatternsByBaseDirectory=ko.getNegativePatternsAsPositive=ko.getPositivePatterns=ko.convertPatternsToTasks=ko.generate=void 0;var Sf=Pf();function _$e(t,e){let r=Jne(t),o=Xne(t,e.ignore),a=r.filter(p=>Sf.pattern.isStaticPattern(p,e)),n=r.filter(p=>Sf.pattern.isDynamicPattern(p,e)),u=NN(a,o,!1),A=NN(n,o,!0);return u.concat(A)}ko.generate=_$e;function NN(t,e,r){let o=[],a=Sf.pattern.getPatternsOutsideCurrentDirectory(t),n=Sf.pattern.getPatternsInsideCurrentDirectory(t),u=ON(a),A=ON(n);return o.push(...MN(u,e,r)),\".\"in A?o.push(UN(\".\",n,e,r)):o.push(...MN(A,e,r)),o}ko.convertPatternsToTasks=NN;function Jne(t){return Sf.pattern.getPositivePatterns(t)}ko.getPositivePatterns=Jne;function Xne(t,e){return Sf.pattern.getNegativePatterns(t).concat(e).map(Sf.pattern.convertToPositivePattern)}ko.getNegativePatternsAsPositive=Xne;function ON(t){let e={};return t.reduce((r,o)=>{let a=Sf.pattern.getBaseDirectory(o);return a in r?r[a].push(o):r[a]=[o],r},e)}ko.groupPatternsByBaseDirectory=ON;function MN(t,e,r){return Object.keys(t).map(o=>UN(o,t[o],e,r))}ko.convertPatternGroupsToTasks=MN;function UN(t,e,r,o){return{dynamic:o,positive:e,negative:r,base:t,patterns:[].concat(e,r.map(Sf.pattern.convertToNegativePattern))}}ko.convertPatternGroupToTask=UN});var eie=_(tE=>{\"use strict\";Object.defineProperty(tE,\"__esModule\",{value:!0});tE.removeDuplicateSlashes=tE.transform=void 0;var H$e=/(?!^)\\/{2,}/g;function q$e(t){return t.map(e=>$ne(e))}tE.transform=q$e;function $ne(t){return t.replace(H$e,\"/\")}tE.removeDuplicateSlashes=$ne});var rie=_(hS=>{\"use strict\";Object.defineProperty(hS,\"__esModule\",{value:!0});hS.read=void 0;function G$e(t,e,r){e.fs.lstat(t,(o,a)=>{if(o!==null){tie(r,o);return}if(!a.isSymbolicLink()||!e.followSymbolicLink){_N(r,a);return}e.fs.stat(t,(n,u)=>{if(n!==null){if(e.throwErrorOnBrokenSymbolicLink){tie(r,n);return}_N(r,a);return}e.markSymbolicLink&&(u.isSymbolicLink=()=>!0),_N(r,u)})})}hS.read=G$e;function tie(t,e){t(e)}function _N(t,e){t(null,e)}});var nie=_(gS=>{\"use strict\";Object.defineProperty(gS,\"__esModule\",{value:!0});gS.read=void 0;function j$e(t,e){let r=e.fs.lstatSync(t);if(!r.isSymbolicLink()||!e.followSymbolicLink)return r;try{let o=e.fs.statSync(t);return e.markSymbolicLink&&(o.isSymbolicLink=()=>!0),o}catch(o){if(!e.throwErrorOnBrokenSymbolicLink)return r;throw o}}gS.read=j$e});var iie=_(Zp=>{\"use strict\";Object.defineProperty(Zp,\"__esModule\",{value:!0});Zp.createFileSystemAdapter=Zp.FILE_SYSTEM_ADAPTER=void 0;var dS=ve(\"fs\");Zp.FILE_SYSTEM_ADAPTER={lstat:dS.lstat,stat:dS.stat,lstatSync:dS.lstatSync,statSync:dS.statSync};function Y$e(t){return t===void 0?Zp.FILE_SYSTEM_ADAPTER:Object.assign(Object.assign({},Zp.FILE_SYSTEM_ADAPTER),t)}Zp.createFileSystemAdapter=Y$e});var sie=_(qN=>{\"use strict\";Object.defineProperty(qN,\"__esModule\",{value:!0});var W$e=iie(),HN=class{constructor(e={}){this._options=e,this.followSymbolicLink=this._getValue(this._options.followSymbolicLink,!0),this.fs=W$e.createFileSystemAdapter(this._options.fs),this.markSymbolicLink=this._getValue(this._options.markSymbolicLink,!1),this.throwErrorOnBrokenSymbolicLink=this._getValue(this._options.throwErrorOnBrokenSymbolicLink,!0)}_getValue(e,r){return e??r}};qN.default=HN});var wd=_($p=>{\"use strict\";Object.defineProperty($p,\"__esModule\",{value:!0});$p.statSync=$p.stat=$p.Settings=void 0;var oie=rie(),K$e=nie(),GN=sie();$p.Settings=GN.default;function z$e(t,e,r){if(typeof e==\"function\"){oie.read(t,jN(),e);return}oie.read(t,jN(e),r)}$p.stat=z$e;function V$e(t,e){let r=jN(e);return K$e.read(t,r)}$p.statSync=V$e;function jN(t={}){return t instanceof GN.default?t:new GN.default(t)}});var lie=_((GTt,aie)=>{aie.exports=J$e;function J$e(t,e){var r,o,a,n=!0;Array.isArray(t)?(r=[],o=t.length):(a=Object.keys(t),r={},o=a.length);function u(p){function h(){e&&e(p,r),e=null}n?process.nextTick(h):h()}function A(p,h,E){r[p]=E,(--o===0||h)&&u(h)}o?a?a.forEach(function(p){t[p](function(h,E){A(p,h,E)})}):t.forEach(function(p,h){p(function(E,I){A(h,E,I)})}):u(null),n=!1}});var YN=_(yS=>{\"use strict\";Object.defineProperty(yS,\"__esModule\",{value:!0});yS.IS_SUPPORT_READDIR_WITH_FILE_TYPES=void 0;var mS=process.versions.node.split(\".\");if(mS[0]===void 0||mS[1]===void 0)throw new Error(`Unexpected behavior. The 'process.versions.node' variable has invalid value: ${process.versions.node}`);var cie=Number.parseInt(mS[0],10),X$e=Number.parseInt(mS[1],10),uie=10,Z$e=10,$$e=cie>uie,eet=cie===uie&&X$e>=Z$e;yS.IS_SUPPORT_READDIR_WITH_FILE_TYPES=$$e||eet});var Aie=_(ES=>{\"use strict\";Object.defineProperty(ES,\"__esModule\",{value:!0});ES.createDirentFromStats=void 0;var WN=class{constructor(e,r){this.name=e,this.isBlockDevice=r.isBlockDevice.bind(r),this.isCharacterDevice=r.isCharacterDevice.bind(r),this.isDirectory=r.isDirectory.bind(r),this.isFIFO=r.isFIFO.bind(r),this.isFile=r.isFile.bind(r),this.isSocket=r.isSocket.bind(r),this.isSymbolicLink=r.isSymbolicLink.bind(r)}};function tet(t,e){return new WN(t,e)}ES.createDirentFromStats=tet});var KN=_(CS=>{\"use strict\";Object.defineProperty(CS,\"__esModule\",{value:!0});CS.fs=void 0;var ret=Aie();CS.fs=ret});var zN=_(wS=>{\"use strict\";Object.defineProperty(wS,\"__esModule\",{value:!0});wS.joinPathSegments=void 0;function net(t,e,r){return t.endsWith(r)?t+e:t+r+e}wS.joinPathSegments=net});var mie=_(eh=>{\"use strict\";Object.defineProperty(eh,\"__esModule\",{value:!0});eh.readdir=eh.readdirWithFileTypes=eh.read=void 0;var iet=wd(),fie=lie(),set=YN(),pie=KN(),hie=zN();function oet(t,e,r){if(!e.stats&&set.IS_SUPPORT_READDIR_WITH_FILE_TYPES){gie(t,e,r);return}die(t,e,r)}eh.read=oet;function gie(t,e,r){e.fs.readdir(t,{withFileTypes:!0},(o,a)=>{if(o!==null){IS(r,o);return}let n=a.map(A=>({dirent:A,name:A.name,path:hie.joinPathSegments(t,A.name,e.pathSegmentSeparator)}));if(!e.followSymbolicLinks){VN(r,n);return}let u=n.map(A=>aet(A,e));fie(u,(A,p)=>{if(A!==null){IS(r,A);return}VN(r,p)})})}eh.readdirWithFileTypes=gie;function aet(t,e){return r=>{if(!t.dirent.isSymbolicLink()){r(null,t);return}e.fs.stat(t.path,(o,a)=>{if(o!==null){if(e.throwErrorOnBrokenSymbolicLink){r(o);return}r(null,t);return}t.dirent=pie.fs.createDirentFromStats(t.name,a),r(null,t)})}}function die(t,e,r){e.fs.readdir(t,(o,a)=>{if(o!==null){IS(r,o);return}let n=a.map(u=>{let A=hie.joinPathSegments(t,u,e.pathSegmentSeparator);return p=>{iet.stat(A,e.fsStatSettings,(h,E)=>{if(h!==null){p(h);return}let I={name:u,path:A,dirent:pie.fs.createDirentFromStats(u,E)};e.stats&&(I.stats=E),p(null,I)})}});fie(n,(u,A)=>{if(u!==null){IS(r,u);return}VN(r,A)})})}eh.readdir=die;function IS(t,e){t(e)}function VN(t,e){t(null,e)}});var Iie=_(th=>{\"use strict\";Object.defineProperty(th,\"__esModule\",{value:!0});th.readdir=th.readdirWithFileTypes=th.read=void 0;var cet=wd(),uet=YN(),yie=KN(),Eie=zN();function Aet(t,e){return!e.stats&&uet.IS_SUPPORT_READDIR_WITH_FILE_TYPES?Cie(t,e):wie(t,e)}th.read=Aet;function Cie(t,e){return e.fs.readdirSync(t,{withFileTypes:!0}).map(o=>{let a={dirent:o,name:o.name,path:Eie.joinPathSegments(t,o.name,e.pathSegmentSeparator)};if(a.dirent.isSymbolicLink()&&e.followSymbolicLinks)try{let n=e.fs.statSync(a.path);a.dirent=yie.fs.createDirentFromStats(a.name,n)}catch(n){if(e.throwErrorOnBrokenSymbolicLink)throw n}return a})}th.readdirWithFileTypes=Cie;function wie(t,e){return e.fs.readdirSync(t).map(o=>{let a=Eie.joinPathSegments(t,o,e.pathSegmentSeparator),n=cet.statSync(a,e.fsStatSettings),u={name:o,path:a,dirent:yie.fs.createDirentFromStats(o,n)};return e.stats&&(u.stats=n),u})}th.readdir=wie});var Bie=_(rh=>{\"use strict\";Object.defineProperty(rh,\"__esModule\",{value:!0});rh.createFileSystemAdapter=rh.FILE_SYSTEM_ADAPTER=void 0;var rE=ve(\"fs\");rh.FILE_SYSTEM_ADAPTER={lstat:rE.lstat,stat:rE.stat,lstatSync:rE.lstatSync,statSync:rE.statSync,readdir:rE.readdir,readdirSync:rE.readdirSync};function fet(t){return t===void 0?rh.FILE_SYSTEM_ADAPTER:Object.assign(Object.assign({},rh.FILE_SYSTEM_ADAPTER),t)}rh.createFileSystemAdapter=fet});var vie=_(XN=>{\"use strict\";Object.defineProperty(XN,\"__esModule\",{value:!0});var pet=ve(\"path\"),het=wd(),get=Bie(),JN=class{constructor(e={}){this._options=e,this.followSymbolicLinks=this._getValue(this._options.followSymbolicLinks,!1),this.fs=get.createFileSystemAdapter(this._options.fs),this.pathSegmentSeparator=this._getValue(this._options.pathSegmentSeparator,pet.sep),this.stats=this._getValue(this._options.stats,!1),this.throwErrorOnBrokenSymbolicLink=this._getValue(this._options.throwErrorOnBrokenSymbolicLink,!0),this.fsStatSettings=new het.Settings({followSymbolicLink:this.followSymbolicLinks,fs:this.fs,throwErrorOnBrokenSymbolicLink:this.throwErrorOnBrokenSymbolicLink})}_getValue(e,r){return e??r}};XN.default=JN});var BS=_(nh=>{\"use strict\";Object.defineProperty(nh,\"__esModule\",{value:!0});nh.Settings=nh.scandirSync=nh.scandir=void 0;var Die=mie(),det=Iie(),ZN=vie();nh.Settings=ZN.default;function met(t,e,r){if(typeof e==\"function\"){Die.read(t,$N(),e);return}Die.read(t,$N(e),r)}nh.scandir=met;function yet(t,e){let r=$N(e);return det.read(t,r)}nh.scandirSync=yet;function $N(t={}){return t instanceof ZN.default?t:new ZN.default(t)}});var Sie=_(($Tt,Pie)=>{\"use strict\";function Eet(t){var e=new t,r=e;function o(){var n=e;return n.next?e=n.next:(e=new t,r=e),n.next=null,n}function a(n){r.next=n,r=n}return{get:o,release:a}}Pie.exports=Eet});var xie=_((eLt,eO)=>{\"use strict\";var Cet=Sie();function bie(t,e,r){if(typeof t==\"function\"&&(r=e,e=t,t=null),r<1)throw new Error(\"fastqueue concurrency must be greater than 1\");var o=Cet(wet),a=null,n=null,u=0,A=null,p={push:R,drain:Yl,saturated:Yl,pause:E,paused:!1,concurrency:r,running:h,resume:x,idle:C,length:I,getQueue:v,unshift:N,empty:Yl,kill:V,killAndDrain:te,error:ae};return p;function h(){return u}function E(){p.paused=!0}function I(){for(var fe=a,ue=0;fe;)fe=fe.next,ue++;return ue}function v(){for(var fe=a,ue=[];fe;)ue.push(fe.value),fe=fe.next;return ue}function x(){if(!!p.paused){p.paused=!1;for(var fe=0;fe<p.concurrency;fe++)u++,U()}}function C(){return u===0&&p.length()===0}function R(fe,ue){var me=o.get();me.context=t,me.release=U,me.value=fe,me.callback=ue||Yl,me.errorHandler=A,u===p.concurrency||p.paused?n?(n.next=me,n=me):(a=me,n=me,p.saturated()):(u++,e.call(t,me.value,me.worked))}function N(fe,ue){var me=o.get();me.context=t,me.release=U,me.value=fe,me.callback=ue||Yl,u===p.concurrency||p.paused?a?(me.next=a,a=me):(a=me,n=me,p.saturated()):(u++,e.call(t,me.value,me.worked))}function U(fe){fe&&o.release(fe);var ue=a;ue?p.paused?u--:(n===a&&(n=null),a=ue.next,ue.next=null,e.call(t,ue.value,ue.worked),n===null&&p.empty()):--u===0&&p.drain()}function V(){a=null,n=null,p.drain=Yl}function te(){a=null,n=null,p.drain(),p.drain=Yl}function ae(fe){A=fe}}function Yl(){}function wet(){this.value=null,this.callback=Yl,this.next=null,this.release=Yl,this.context=null,this.errorHandler=null;var t=this;this.worked=function(r,o){var a=t.callback,n=t.errorHandler,u=t.value;t.value=null,t.callback=Yl,t.errorHandler&&n(r,u),a.call(t.context,r,o),t.release(t)}}function Iet(t,e,r){typeof t==\"function\"&&(r=e,e=t,t=null);function o(E,I){e.call(this,E).then(function(v){I(null,v)},I)}var a=bie(t,o,r),n=a.push,u=a.unshift;return a.push=A,a.unshift=p,a.drained=h,a;function A(E){var I=new Promise(function(v,x){n(E,function(C,R){if(C){x(C);return}v(R)})});return I.catch(Yl),I}function p(E){var I=new Promise(function(v,x){u(E,function(C,R){if(C){x(C);return}v(R)})});return I.catch(Yl),I}function h(){var E=a.drain,I=new Promise(function(v){a.drain=function(){E(),v()}});return I}}eO.exports=bie;eO.exports.promise=Iet});var vS=_($u=>{\"use strict\";Object.defineProperty($u,\"__esModule\",{value:!0});$u.joinPathSegments=$u.replacePathSegmentSeparator=$u.isAppliedFilter=$u.isFatalError=void 0;function Bet(t,e){return t.errorFilter===null?!0:!t.errorFilter(e)}$u.isFatalError=Bet;function vet(t,e){return t===null||t(e)}$u.isAppliedFilter=vet;function Det(t,e){return t.split(/[/\\\\]/).join(e)}$u.replacePathSegmentSeparator=Det;function Pet(t,e,r){return t===\"\"?e:t.endsWith(r)?t+e:t+r+e}$u.joinPathSegments=Pet});var nO=_(rO=>{\"use strict\";Object.defineProperty(rO,\"__esModule\",{value:!0});var bet=vS(),tO=class{constructor(e,r){this._root=e,this._settings=r,this._root=bet.replacePathSegmentSeparator(e,r.pathSegmentSeparator)}};rO.default=tO});var oO=_(sO=>{\"use strict\";Object.defineProperty(sO,\"__esModule\",{value:!0});var xet=ve(\"events\"),ket=BS(),Qet=xie(),DS=vS(),Fet=nO(),iO=class extends Fet.default{constructor(e,r){super(e,r),this._settings=r,this._scandir=ket.scandir,this._emitter=new xet.EventEmitter,this._queue=Qet(this._worker.bind(this),this._settings.concurrency),this._isFatalError=!1,this._isDestroyed=!1,this._queue.drain=()=>{this._isFatalError||this._emitter.emit(\"end\")}}read(){return this._isFatalError=!1,this._isDestroyed=!1,setImmediate(()=>{this._pushToQueue(this._root,this._settings.basePath)}),this._emitter}get isDestroyed(){return this._isDestroyed}destroy(){if(this._isDestroyed)throw new Error(\"The reader is already destroyed\");this._isDestroyed=!0,this._queue.killAndDrain()}onEntry(e){this._emitter.on(\"entry\",e)}onError(e){this._emitter.once(\"error\",e)}onEnd(e){this._emitter.once(\"end\",e)}_pushToQueue(e,r){let o={directory:e,base:r};this._queue.push(o,a=>{a!==null&&this._handleError(a)})}_worker(e,r){this._scandir(e.directory,this._settings.fsScandirSettings,(o,a)=>{if(o!==null){r(o,void 0);return}for(let n of a)this._handleEntry(n,e.base);r(null,void 0)})}_handleError(e){this._isDestroyed||!DS.isFatalError(this._settings,e)||(this._isFatalError=!0,this._isDestroyed=!0,this._emitter.emit(\"error\",e))}_handleEntry(e,r){if(this._isDestroyed||this._isFatalError)return;let o=e.path;r!==void 0&&(e.path=DS.joinPathSegments(r,e.name,this._settings.pathSegmentSeparator)),DS.isAppliedFilter(this._settings.entryFilter,e)&&this._emitEntry(e),e.dirent.isDirectory()&&DS.isAppliedFilter(this._settings.deepFilter,e)&&this._pushToQueue(o,r===void 0?void 0:e.path)}_emitEntry(e){this._emitter.emit(\"entry\",e)}};sO.default=iO});var kie=_(lO=>{\"use strict\";Object.defineProperty(lO,\"__esModule\",{value:!0});var Ret=oO(),aO=class{constructor(e,r){this._root=e,this._settings=r,this._reader=new Ret.default(this._root,this._settings),this._storage=[]}read(e){this._reader.onError(r=>{Tet(e,r)}),this._reader.onEntry(r=>{this._storage.push(r)}),this._reader.onEnd(()=>{Let(e,this._storage)}),this._reader.read()}};lO.default=aO;function Tet(t,e){t(e)}function Let(t,e){t(null,e)}});var Qie=_(uO=>{\"use strict\";Object.defineProperty(uO,\"__esModule\",{value:!0});var Net=ve(\"stream\"),Oet=oO(),cO=class{constructor(e,r){this._root=e,this._settings=r,this._reader=new Oet.default(this._root,this._settings),this._stream=new Net.Readable({objectMode:!0,read:()=>{},destroy:()=>{this._reader.isDestroyed||this._reader.destroy()}})}read(){return this._reader.onError(e=>{this._stream.emit(\"error\",e)}),this._reader.onEntry(e=>{this._stream.push(e)}),this._reader.onEnd(()=>{this._stream.push(null)}),this._reader.read(),this._stream}};uO.default=cO});var Fie=_(fO=>{\"use strict\";Object.defineProperty(fO,\"__esModule\",{value:!0});var Met=BS(),PS=vS(),Uet=nO(),AO=class extends Uet.default{constructor(){super(...arguments),this._scandir=Met.scandirSync,this._storage=[],this._queue=new Set}read(){return this._pushToQueue(this._root,this._settings.basePath),this._handleQueue(),this._storage}_pushToQueue(e,r){this._queue.add({directory:e,base:r})}_handleQueue(){for(let e of this._queue.values())this._handleDirectory(e.directory,e.base)}_handleDirectory(e,r){try{let o=this._scandir(e,this._settings.fsScandirSettings);for(let a of o)this._handleEntry(a,r)}catch(o){this._handleError(o)}}_handleError(e){if(!!PS.isFatalError(this._settings,e))throw e}_handleEntry(e,r){let o=e.path;r!==void 0&&(e.path=PS.joinPathSegments(r,e.name,this._settings.pathSegmentSeparator)),PS.isAppliedFilter(this._settings.entryFilter,e)&&this._pushToStorage(e),e.dirent.isDirectory()&&PS.isAppliedFilter(this._settings.deepFilter,e)&&this._pushToQueue(o,r===void 0?void 0:e.path)}_pushToStorage(e){this._storage.push(e)}};fO.default=AO});var Rie=_(hO=>{\"use strict\";Object.defineProperty(hO,\"__esModule\",{value:!0});var _et=Fie(),pO=class{constructor(e,r){this._root=e,this._settings=r,this._reader=new _et.default(this._root,this._settings)}read(){return this._reader.read()}};hO.default=pO});var Tie=_(dO=>{\"use strict\";Object.defineProperty(dO,\"__esModule\",{value:!0});var Het=ve(\"path\"),qet=BS(),gO=class{constructor(e={}){this._options=e,this.basePath=this._getValue(this._options.basePath,void 0),this.concurrency=this._getValue(this._options.concurrency,Number.POSITIVE_INFINITY),this.deepFilter=this._getValue(this._options.deepFilter,null),this.entryFilter=this._getValue(this._options.entryFilter,null),this.errorFilter=this._getValue(this._options.errorFilter,null),this.pathSegmentSeparator=this._getValue(this._options.pathSegmentSeparator,Het.sep),this.fsScandirSettings=new qet.Settings({followSymbolicLinks:this._options.followSymbolicLinks,fs:this._options.fs,pathSegmentSeparator:this._options.pathSegmentSeparator,stats:this._options.stats,throwErrorOnBrokenSymbolicLink:this._options.throwErrorOnBrokenSymbolicLink})}_getValue(e,r){return e??r}};dO.default=gO});var bS=_(eA=>{\"use strict\";Object.defineProperty(eA,\"__esModule\",{value:!0});eA.Settings=eA.walkStream=eA.walkSync=eA.walk=void 0;var Lie=kie(),Get=Qie(),jet=Rie(),mO=Tie();eA.Settings=mO.default;function Yet(t,e,r){if(typeof e==\"function\"){new Lie.default(t,SS()).read(e);return}new Lie.default(t,SS(e)).read(r)}eA.walk=Yet;function Wet(t,e){let r=SS(e);return new jet.default(t,r).read()}eA.walkSync=Wet;function Ket(t,e){let r=SS(e);return new Get.default(t,r).read()}eA.walkStream=Ket;function SS(t={}){return t instanceof mO.default?t:new mO.default(t)}});var xS=_(EO=>{\"use strict\";Object.defineProperty(EO,\"__esModule\",{value:!0});var zet=ve(\"path\"),Vet=wd(),Nie=Pf(),yO=class{constructor(e){this._settings=e,this._fsStatSettings=new Vet.Settings({followSymbolicLink:this._settings.followSymbolicLinks,fs:this._settings.fs,throwErrorOnBrokenSymbolicLink:this._settings.followSymbolicLinks})}_getFullEntryPath(e){return zet.resolve(this._settings.cwd,e)}_makeEntry(e,r){let o={name:r,path:r,dirent:Nie.fs.createDirentFromStats(r,e)};return this._settings.stats&&(o.stats=e),o}_isFatalError(e){return!Nie.errno.isEnoentCodeError(e)&&!this._settings.suppressErrors}};EO.default=yO});var IO=_(wO=>{\"use strict\";Object.defineProperty(wO,\"__esModule\",{value:!0});var Jet=ve(\"stream\"),Xet=wd(),Zet=bS(),$et=xS(),CO=class extends $et.default{constructor(){super(...arguments),this._walkStream=Zet.walkStream,this._stat=Xet.stat}dynamic(e,r){return this._walkStream(e,r)}static(e,r){let o=e.map(this._getFullEntryPath,this),a=new Jet.PassThrough({objectMode:!0});a._write=(n,u,A)=>this._getEntry(o[n],e[n],r).then(p=>{p!==null&&r.entryFilter(p)&&a.push(p),n===o.length-1&&a.end(),A()}).catch(A);for(let n=0;n<o.length;n++)a.write(n);return a}_getEntry(e,r,o){return this._getStat(e).then(a=>this._makeEntry(a,r)).catch(a=>{if(o.errorFilter(a))return null;throw a})}_getStat(e){return new Promise((r,o)=>{this._stat(e,this._fsStatSettings,(a,n)=>a===null?r(n):o(a))})}};wO.default=CO});var Oie=_(vO=>{\"use strict\";Object.defineProperty(vO,\"__esModule\",{value:!0});var ett=bS(),ttt=xS(),rtt=IO(),BO=class extends ttt.default{constructor(){super(...arguments),this._walkAsync=ett.walk,this._readerStream=new rtt.default(this._settings)}dynamic(e,r){return new Promise((o,a)=>{this._walkAsync(e,r,(n,u)=>{n===null?o(u):a(n)})})}async static(e,r){let o=[],a=this._readerStream.static(e,r);return new Promise((n,u)=>{a.once(\"error\",u),a.on(\"data\",A=>o.push(A)),a.once(\"end\",()=>n(o))})}};vO.default=BO});var Mie=_(PO=>{\"use strict\";Object.defineProperty(PO,\"__esModule\",{value:!0});var nE=Pf(),DO=class{constructor(e,r,o){this._patterns=e,this._settings=r,this._micromatchOptions=o,this._storage=[],this._fillStorage()}_fillStorage(){let e=nE.pattern.expandPatternsWithBraceExpansion(this._patterns);for(let r of e){let o=this._getPatternSegments(r),a=this._splitSegmentsIntoSections(o);this._storage.push({complete:a.length<=1,pattern:r,segments:o,sections:a})}}_getPatternSegments(e){return nE.pattern.getPatternParts(e,this._micromatchOptions).map(o=>nE.pattern.isDynamicPattern(o,this._settings)?{dynamic:!0,pattern:o,patternRe:nE.pattern.makeRe(o,this._micromatchOptions)}:{dynamic:!1,pattern:o})}_splitSegmentsIntoSections(e){return nE.array.splitWhen(e,r=>r.dynamic&&nE.pattern.hasGlobStar(r.pattern))}};PO.default=DO});var Uie=_(bO=>{\"use strict\";Object.defineProperty(bO,\"__esModule\",{value:!0});var ntt=Mie(),SO=class extends ntt.default{match(e){let r=e.split(\"/\"),o=r.length,a=this._storage.filter(n=>!n.complete||n.segments.length>o);for(let n of a){let u=n.sections[0];if(!n.complete&&o>u.length||r.every((p,h)=>{let E=n.segments[h];return!!(E.dynamic&&E.patternRe.test(p)||!E.dynamic&&E.pattern===p)}))return!0}return!1}};bO.default=SO});var _ie=_(kO=>{\"use strict\";Object.defineProperty(kO,\"__esModule\",{value:!0});var kS=Pf(),itt=Uie(),xO=class{constructor(e,r){this._settings=e,this._micromatchOptions=r}getFilter(e,r,o){let a=this._getMatcher(r),n=this._getNegativePatternsRe(o);return u=>this._filter(e,u,a,n)}_getMatcher(e){return new itt.default(e,this._settings,this._micromatchOptions)}_getNegativePatternsRe(e){let r=e.filter(kS.pattern.isAffectDepthOfReadingPattern);return kS.pattern.convertPatternsToRe(r,this._micromatchOptions)}_filter(e,r,o,a){if(this._isSkippedByDeep(e,r.path)||this._isSkippedSymbolicLink(r))return!1;let n=kS.path.removeLeadingDotSegment(r.path);return this._isSkippedByPositivePatterns(n,o)?!1:this._isSkippedByNegativePatterns(n,a)}_isSkippedByDeep(e,r){return this._settings.deep===1/0?!1:this._getEntryLevel(e,r)>=this._settings.deep}_getEntryLevel(e,r){let o=r.split(\"/\").length;if(e===\"\")return o;let a=e.split(\"/\").length;return o-a}_isSkippedSymbolicLink(e){return!this._settings.followSymbolicLinks&&e.dirent.isSymbolicLink()}_isSkippedByPositivePatterns(e,r){return!this._settings.baseNameMatch&&!r.match(e)}_isSkippedByNegativePatterns(e,r){return!kS.pattern.matchAny(e,r)}};kO.default=xO});var Hie=_(FO=>{\"use strict\";Object.defineProperty(FO,\"__esModule\",{value:!0});var Id=Pf(),QO=class{constructor(e,r){this._settings=e,this._micromatchOptions=r,this.index=new Map}getFilter(e,r){let o=Id.pattern.convertPatternsToRe(e,this._micromatchOptions),a=Id.pattern.convertPatternsToRe(r,this._micromatchOptions);return n=>this._filter(n,o,a)}_filter(e,r,o){if(this._settings.unique&&this._isDuplicateEntry(e)||this._onlyFileFilter(e)||this._onlyDirectoryFilter(e)||this._isSkippedByAbsoluteNegativePatterns(e.path,o))return!1;let a=this._settings.baseNameMatch?e.name:e.path,n=e.dirent.isDirectory(),u=this._isMatchToPatterns(a,r,n)&&!this._isMatchToPatterns(e.path,o,n);return this._settings.unique&&u&&this._createIndexRecord(e),u}_isDuplicateEntry(e){return this.index.has(e.path)}_createIndexRecord(e){this.index.set(e.path,void 0)}_onlyFileFilter(e){return this._settings.onlyFiles&&!e.dirent.isFile()}_onlyDirectoryFilter(e){return this._settings.onlyDirectories&&!e.dirent.isDirectory()}_isSkippedByAbsoluteNegativePatterns(e,r){if(!this._settings.absolute)return!1;let o=Id.path.makeAbsolute(this._settings.cwd,e);return Id.pattern.matchAny(o,r)}_isMatchToPatterns(e,r,o){let a=Id.path.removeLeadingDotSegment(e),n=Id.pattern.matchAny(a,r);return!n&&o?Id.pattern.matchAny(a+\"/\",r):n}};FO.default=QO});var qie=_(TO=>{\"use strict\";Object.defineProperty(TO,\"__esModule\",{value:!0});var stt=Pf(),RO=class{constructor(e){this._settings=e}getFilter(){return e=>this._isNonFatalError(e)}_isNonFatalError(e){return stt.errno.isEnoentCodeError(e)||this._settings.suppressErrors}};TO.default=RO});var jie=_(NO=>{\"use strict\";Object.defineProperty(NO,\"__esModule\",{value:!0});var Gie=Pf(),LO=class{constructor(e){this._settings=e}getTransformer(){return e=>this._transform(e)}_transform(e){let r=e.path;return this._settings.absolute&&(r=Gie.path.makeAbsolute(this._settings.cwd,r),r=Gie.path.unixify(r)),this._settings.markDirectories&&e.dirent.isDirectory()&&(r+=\"/\"),this._settings.objectMode?Object.assign(Object.assign({},e),{path:r}):r}};NO.default=LO});var QS=_(MO=>{\"use strict\";Object.defineProperty(MO,\"__esModule\",{value:!0});var ott=ve(\"path\"),att=_ie(),ltt=Hie(),ctt=qie(),utt=jie(),OO=class{constructor(e){this._settings=e,this.errorFilter=new ctt.default(this._settings),this.entryFilter=new ltt.default(this._settings,this._getMicromatchOptions()),this.deepFilter=new att.default(this._settings,this._getMicromatchOptions()),this.entryTransformer=new utt.default(this._settings)}_getRootDirectory(e){return ott.resolve(this._settings.cwd,e.base)}_getReaderOptions(e){let r=e.base===\".\"?\"\":e.base;return{basePath:r,pathSegmentSeparator:\"/\",concurrency:this._settings.concurrency,deepFilter:this.deepFilter.getFilter(r,e.positive,e.negative),entryFilter:this.entryFilter.getFilter(e.positive,e.negative),errorFilter:this.errorFilter.getFilter(),followSymbolicLinks:this._settings.followSymbolicLinks,fs:this._settings.fs,stats:this._settings.stats,throwErrorOnBrokenSymbolicLink:this._settings.throwErrorOnBrokenSymbolicLink,transform:this.entryTransformer.getTransformer()}}_getMicromatchOptions(){return{dot:this._settings.dot,matchBase:this._settings.baseNameMatch,nobrace:!this._settings.braceExpansion,nocase:!this._settings.caseSensitiveMatch,noext:!this._settings.extglob,noglobstar:!this._settings.globstar,posix:!0,strictSlashes:!1}}};MO.default=OO});var Yie=_(_O=>{\"use strict\";Object.defineProperty(_O,\"__esModule\",{value:!0});var Att=Oie(),ftt=QS(),UO=class extends ftt.default{constructor(){super(...arguments),this._reader=new Att.default(this._settings)}async read(e){let r=this._getRootDirectory(e),o=this._getReaderOptions(e);return(await this.api(r,e,o)).map(n=>o.transform(n))}api(e,r,o){return r.dynamic?this._reader.dynamic(e,o):this._reader.static(r.patterns,o)}};_O.default=UO});var Wie=_(qO=>{\"use strict\";Object.defineProperty(qO,\"__esModule\",{value:!0});var ptt=ve(\"stream\"),htt=IO(),gtt=QS(),HO=class extends gtt.default{constructor(){super(...arguments),this._reader=new htt.default(this._settings)}read(e){let r=this._getRootDirectory(e),o=this._getReaderOptions(e),a=this.api(r,e,o),n=new ptt.Readable({objectMode:!0,read:()=>{}});return a.once(\"error\",u=>n.emit(\"error\",u)).on(\"data\",u=>n.emit(\"data\",o.transform(u))).once(\"end\",()=>n.emit(\"end\")),n.once(\"close\",()=>a.destroy()),n}api(e,r,o){return r.dynamic?this._reader.dynamic(e,o):this._reader.static(r.patterns,o)}};qO.default=HO});var Kie=_(jO=>{\"use strict\";Object.defineProperty(jO,\"__esModule\",{value:!0});var dtt=wd(),mtt=bS(),ytt=xS(),GO=class extends ytt.default{constructor(){super(...arguments),this._walkSync=mtt.walkSync,this._statSync=dtt.statSync}dynamic(e,r){return this._walkSync(e,r)}static(e,r){let o=[];for(let a of e){let n=this._getFullEntryPath(a),u=this._getEntry(n,a,r);u===null||!r.entryFilter(u)||o.push(u)}return o}_getEntry(e,r,o){try{let a=this._getStat(e);return this._makeEntry(a,r)}catch(a){if(o.errorFilter(a))return null;throw a}}_getStat(e){return this._statSync(e,this._fsStatSettings)}};jO.default=GO});var zie=_(WO=>{\"use strict\";Object.defineProperty(WO,\"__esModule\",{value:!0});var Ett=Kie(),Ctt=QS(),YO=class extends Ctt.default{constructor(){super(...arguments),this._reader=new Ett.default(this._settings)}read(e){let r=this._getRootDirectory(e),o=this._getReaderOptions(e);return this.api(r,e,o).map(o.transform)}api(e,r,o){return r.dynamic?this._reader.dynamic(e,o):this._reader.static(r.patterns,o)}};WO.default=YO});var Vie=_(sE=>{\"use strict\";Object.defineProperty(sE,\"__esModule\",{value:!0});sE.DEFAULT_FILE_SYSTEM_ADAPTER=void 0;var iE=ve(\"fs\"),wtt=ve(\"os\"),Itt=Math.max(wtt.cpus().length,1);sE.DEFAULT_FILE_SYSTEM_ADAPTER={lstat:iE.lstat,lstatSync:iE.lstatSync,stat:iE.stat,statSync:iE.statSync,readdir:iE.readdir,readdirSync:iE.readdirSync};var KO=class{constructor(e={}){this._options=e,this.absolute=this._getValue(this._options.absolute,!1),this.baseNameMatch=this._getValue(this._options.baseNameMatch,!1),this.braceExpansion=this._getValue(this._options.braceExpansion,!0),this.caseSensitiveMatch=this._getValue(this._options.caseSensitiveMatch,!0),this.concurrency=this._getValue(this._options.concurrency,Itt),this.cwd=this._getValue(this._options.cwd,process.cwd()),this.deep=this._getValue(this._options.deep,1/0),this.dot=this._getValue(this._options.dot,!1),this.extglob=this._getValue(this._options.extglob,!0),this.followSymbolicLinks=this._getValue(this._options.followSymbolicLinks,!0),this.fs=this._getFileSystemMethods(this._options.fs),this.globstar=this._getValue(this._options.globstar,!0),this.ignore=this._getValue(this._options.ignore,[]),this.markDirectories=this._getValue(this._options.markDirectories,!1),this.objectMode=this._getValue(this._options.objectMode,!1),this.onlyDirectories=this._getValue(this._options.onlyDirectories,!1),this.onlyFiles=this._getValue(this._options.onlyFiles,!0),this.stats=this._getValue(this._options.stats,!1),this.suppressErrors=this._getValue(this._options.suppressErrors,!1),this.throwErrorOnBrokenSymbolicLink=this._getValue(this._options.throwErrorOnBrokenSymbolicLink,!1),this.unique=this._getValue(this._options.unique,!0),this.onlyDirectories&&(this.onlyFiles=!1),this.stats&&(this.objectMode=!0)}_getValue(e,r){return e===void 0?r:e}_getFileSystemMethods(e={}){return Object.assign(Object.assign({},sE.DEFAULT_FILE_SYSTEM_ADAPTER),e)}};sE.default=KO});var RS=_((DLt,Zie)=>{\"use strict\";var Jie=Zne(),Xie=eie(),Btt=Yie(),vtt=Wie(),Dtt=zie(),zO=Vie(),Bd=Pf();async function VO(t,e){oE(t);let r=JO(t,Btt.default,e),o=await Promise.all(r);return Bd.array.flatten(o)}(function(t){function e(u,A){oE(u);let p=JO(u,Dtt.default,A);return Bd.array.flatten(p)}t.sync=e;function r(u,A){oE(u);let p=JO(u,vtt.default,A);return Bd.stream.merge(p)}t.stream=r;function o(u,A){oE(u);let p=Xie.transform([].concat(u)),h=new zO.default(A);return Jie.generate(p,h)}t.generateTasks=o;function a(u,A){oE(u);let p=new zO.default(A);return Bd.pattern.isDynamicPattern(u,p)}t.isDynamicPattern=a;function n(u){return oE(u),Bd.path.escape(u)}t.escapePath=n})(VO||(VO={}));function JO(t,e,r){let o=Xie.transform([].concat(t)),a=new zO.default(r),n=Jie.generate(o,a),u=new e(a);return n.map(u.read,u)}function oE(t){if(![].concat(t).every(o=>Bd.string.isString(o)&&!Bd.string.isEmpty(o)))throw new TypeError(\"Patterns must be a string (non empty) or an array of strings\")}Zie.exports=VO});var wn={};zt(wn,{checksumFile:()=>LS,checksumPattern:()=>NS,makeHash:()=>Js});function Js(...t){let e=(0,TS.createHash)(\"sha512\"),r=\"\";for(let o of t)typeof o==\"string\"?r+=o:o&&(r&&(e.update(r),r=\"\"),e.update(o));return r&&e.update(r),e.digest(\"hex\")}async function LS(t,{baseFs:e,algorithm:r}={baseFs:oe,algorithm:\"sha512\"}){let o=await e.openPromise(t,\"r\");try{let n=Buffer.allocUnsafeSlow(65536),u=(0,TS.createHash)(r),A=0;for(;(A=await e.readPromise(o,n,0,65536))!==0;)u.update(A===65536?n:n.slice(0,A));return u.digest(\"hex\")}finally{await e.closePromise(o)}}async function NS(t,{cwd:e}){let o=(await(0,XO.default)(t,{cwd:le.fromPortablePath(e),onlyDirectories:!0})).map(A=>`${A}/**/*`),a=await(0,XO.default)([t,...o],{cwd:le.fromPortablePath(e),onlyFiles:!1});a.sort();let n=await Promise.all(a.map(async A=>{let p=[Buffer.from(A)],h=le.toPortablePath(A),E=await oe.lstatPromise(h);return E.isSymbolicLink()?p.push(Buffer.from(await oe.readlinkPromise(h))):E.isFile()&&p.push(await oe.readFilePromise(h)),p.join(\"\\0\")})),u=(0,TS.createHash)(\"sha512\");for(let A of n)u.update(A);return u.digest(\"hex\")}var TS,XO,ih=Et(()=>{Pt();TS=ve(\"crypto\"),XO=$e(RS())});var W={};zt(W,{areDescriptorsEqual:()=>nse,areIdentsEqual:()=>n1,areLocatorsEqual:()=>i1,areVirtualPackagesEquivalent:()=>Ttt,bindDescriptor:()=>Ftt,bindLocator:()=>Rtt,convertDescriptorToLocator:()=>OS,convertLocatorToDescriptor:()=>$O,convertPackageToLocator:()=>xtt,convertToIdent:()=>btt,convertToManifestRange:()=>jtt,copyPackage:()=>e1,devirtualizeDescriptor:()=>t1,devirtualizeLocator:()=>r1,ensureDevirtualizedDescriptor:()=>ktt,ensureDevirtualizedLocator:()=>Qtt,getIdentVendorPath:()=>nM,isPackageCompatible:()=>qS,isVirtualDescriptor:()=>bf,isVirtualLocator:()=>qc,makeDescriptor:()=>In,makeIdent:()=>tA,makeLocator:()=>Qs,makeRange:()=>_S,parseDescriptor:()=>sh,parseFileStyleRange:()=>qtt,parseIdent:()=>Vs,parseLocator:()=>xf,parseRange:()=>vd,prettyDependent:()=>QN,prettyDescriptor:()=>Gn,prettyIdent:()=>cs,prettyLocator:()=>qr,prettyLocatorNoColors:()=>kN,prettyRange:()=>cE,prettyReference:()=>o1,prettyResolution:()=>ZI,prettyWorkspace:()=>a1,renamePackage:()=>eM,slugifyIdent:()=>ZO,slugifyLocator:()=>lE,sortDescriptors:()=>uE,stringifyDescriptor:()=>Sa,stringifyIdent:()=>fn,stringifyLocator:()=>ba,tryParseDescriptor:()=>s1,tryParseIdent:()=>ise,tryParseLocator:()=>US,tryParseRange:()=>Htt,virtualizeDescriptor:()=>tM,virtualizePackage:()=>rM});function tA(t,e){if(t?.startsWith(\"@\"))throw new Error(\"Invalid scope: don't prefix it with '@'\");return{identHash:Js(t,e),scope:t,name:e}}function In(t,e){return{identHash:t.identHash,scope:t.scope,name:t.name,descriptorHash:Js(t.identHash,e),range:e}}function Qs(t,e){return{identHash:t.identHash,scope:t.scope,name:t.name,locatorHash:Js(t.identHash,e),reference:e}}function btt(t){return{identHash:t.identHash,scope:t.scope,name:t.name}}function OS(t){return{identHash:t.identHash,scope:t.scope,name:t.name,locatorHash:t.descriptorHash,reference:t.range}}function $O(t){return{identHash:t.identHash,scope:t.scope,name:t.name,descriptorHash:t.locatorHash,range:t.reference}}function xtt(t){return{identHash:t.identHash,scope:t.scope,name:t.name,locatorHash:t.locatorHash,reference:t.reference}}function eM(t,e){return{identHash:e.identHash,scope:e.scope,name:e.name,locatorHash:e.locatorHash,reference:e.reference,version:t.version,languageName:t.languageName,linkType:t.linkType,conditions:t.conditions,dependencies:new Map(t.dependencies),peerDependencies:new Map(t.peerDependencies),dependenciesMeta:new Map(t.dependenciesMeta),peerDependenciesMeta:new Map(t.peerDependenciesMeta),bin:new Map(t.bin)}}function e1(t){return eM(t,t)}function tM(t,e){if(e.includes(\"#\"))throw new Error(\"Invalid entropy\");return In(t,`virtual:${e}#${t.range}`)}function rM(t,e){if(e.includes(\"#\"))throw new Error(\"Invalid entropy\");return eM(t,Qs(t,`virtual:${e}#${t.reference}`))}function bf(t){return t.range.startsWith($I)}function qc(t){return t.reference.startsWith($I)}function t1(t){if(!bf(t))throw new Error(\"Not a virtual descriptor\");return In(t,t.range.replace(MS,\"\"))}function r1(t){if(!qc(t))throw new Error(\"Not a virtual descriptor\");return Qs(t,t.reference.replace(MS,\"\"))}function ktt(t){return bf(t)?In(t,t.range.replace(MS,\"\")):t}function Qtt(t){return qc(t)?Qs(t,t.reference.replace(MS,\"\")):t}function Ftt(t,e){return t.range.includes(\"::\")?t:In(t,`${t.range}::${aE.default.stringify(e)}`)}function Rtt(t,e){return t.reference.includes(\"::\")?t:Qs(t,`${t.reference}::${aE.default.stringify(e)}`)}function n1(t,e){return t.identHash===e.identHash}function nse(t,e){return t.descriptorHash===e.descriptorHash}function i1(t,e){return t.locatorHash===e.locatorHash}function Ttt(t,e){if(!qc(t))throw new Error(\"Invalid package type\");if(!qc(e))throw new Error(\"Invalid package type\");if(!n1(t,e)||t.dependencies.size!==e.dependencies.size)return!1;for(let r of t.dependencies.values()){let o=e.dependencies.get(r.identHash);if(!o||!nse(r,o))return!1}return!0}function Vs(t){let e=ise(t);if(!e)throw new Error(`Invalid ident (${t})`);return e}function ise(t){let e=t.match(Ltt);if(!e)return null;let[,r,o]=e;return tA(typeof r<\"u\"?r:null,o)}function sh(t,e=!1){let r=s1(t,e);if(!r)throw new Error(`Invalid descriptor (${t})`);return r}function s1(t,e=!1){let r=e?t.match(Ntt):t.match(Ott);if(!r)return null;let[,o,a,n]=r;if(n===\"unknown\")throw new Error(`Invalid range (${t})`);let u=typeof o<\"u\"?o:null,A=typeof n<\"u\"?n:\"unknown\";return In(tA(u,a),A)}function xf(t,e=!1){let r=US(t,e);if(!r)throw new Error(`Invalid locator (${t})`);return r}function US(t,e=!1){let r=e?t.match(Mtt):t.match(Utt);if(!r)return null;let[,o,a,n]=r;if(n===\"unknown\")throw new Error(`Invalid reference (${t})`);let u=typeof o<\"u\"?o:null,A=typeof n<\"u\"?n:\"unknown\";return Qs(tA(u,a),A)}function vd(t,e){let r=t.match(_tt);if(r===null)throw new Error(`Invalid range (${t})`);let o=typeof r[1]<\"u\"?r[1]:null;if(typeof e?.requireProtocol==\"string\"&&o!==e.requireProtocol)throw new Error(`Invalid protocol (${o})`);if(e?.requireProtocol&&o===null)throw new Error(`Missing protocol (${o})`);let a=typeof r[3]<\"u\"?decodeURIComponent(r[2]):null;if(e?.requireSource&&a===null)throw new Error(`Missing source (${t})`);let n=typeof r[3]<\"u\"?decodeURIComponent(r[3]):decodeURIComponent(r[2]),u=e?.parseSelector?aE.default.parse(n):n,A=typeof r[4]<\"u\"?aE.default.parse(r[4]):null;return{protocol:o,source:a,selector:u,params:A}}function Htt(t,e){try{return vd(t,e)}catch{return null}}function qtt(t,{protocol:e}){let{selector:r,params:o}=vd(t,{requireProtocol:e,requireBindings:!0});if(typeof o.locator!=\"string\")throw new Error(`Assertion failed: Invalid bindings for ${t}`);return{parentLocator:xf(o.locator,!0),path:r}}function $ie(t){return t=t.replaceAll(\"%\",\"%25\"),t=t.replaceAll(\":\",\"%3A\"),t=t.replaceAll(\"#\",\"%23\"),t}function Gtt(t){return t===null?!1:Object.entries(t).length>0}function _S({protocol:t,source:e,selector:r,params:o}){let a=\"\";return t!==null&&(a+=`${t}`),e!==null&&(a+=`${$ie(e)}#`),a+=$ie(r),Gtt(o)&&(a+=`::${aE.default.stringify(o)}`),a}function jtt(t){let{params:e,protocol:r,source:o,selector:a}=vd(t);for(let n in e)n.startsWith(\"__\")&&delete e[n];return _S({protocol:r,source:o,params:e,selector:a})}function fn(t){return t.scope?`@${t.scope}/${t.name}`:`${t.name}`}function Sa(t){return t.scope?`@${t.scope}/${t.name}@${t.range}`:`${t.name}@${t.range}`}function ba(t){return t.scope?`@${t.scope}/${t.name}@${t.reference}`:`${t.name}@${t.reference}`}function ZO(t){return t.scope!==null?`@${t.scope}-${t.name}`:t.name}function lE(t){let{protocol:e,selector:r}=vd(t.reference),o=e!==null?e.replace(Ytt,\"\"):\"exotic\",a=ese.default.valid(r),n=a!==null?`${o}-${a}`:`${o}`,u=10;return t.scope?`${ZO(t)}-${n}-${t.locatorHash.slice(0,u)}`:`${ZO(t)}-${n}-${t.locatorHash.slice(0,u)}`}function cs(t,e){return e.scope?`${Ut(t,`@${e.scope}/`,yt.SCOPE)}${Ut(t,e.name,yt.NAME)}`:`${Ut(t,e.name,yt.NAME)}`}function HS(t){if(t.startsWith($I)){let e=HS(t.substring(t.indexOf(\"#\")+1)),r=t.substring($I.length,$I.length+Ptt);return`${e} [${r}]`}else return t.replace(Wtt,\"?[...]\")}function cE(t,e){return`${Ut(t,HS(e),yt.RANGE)}`}function Gn(t,e){return`${cs(t,e)}${Ut(t,\"@\",yt.RANGE)}${cE(t,e.range)}`}function o1(t,e){return`${Ut(t,HS(e),yt.REFERENCE)}`}function qr(t,e){return`${cs(t,e)}${Ut(t,\"@\",yt.REFERENCE)}${o1(t,e.reference)}`}function kN(t){return`${fn(t)}@${HS(t.reference)}`}function uE(t){return ks(t,[e=>fn(e),e=>e.range])}function a1(t,e){return cs(t,e.anchoredLocator)}function ZI(t,e,r){let o=bf(e)?t1(e):e;return r===null?`${Gn(t,o)} \\u2192 ${xN(t).Cross}`:o.identHash===r.identHash?`${Gn(t,o)} \\u2192 ${o1(t,r.reference)}`:`${Gn(t,o)} \\u2192 ${qr(t,r)}`}function QN(t,e,r){return r===null?`${qr(t,e)}`:`${qr(t,e)} (via ${cE(t,r.range)})`}function nM(t){return`node_modules/${fn(t)}`}function qS(t,e){return t.conditions?Stt(t.conditions,r=>{let[,o,a]=r.match(rse),n=e[o];return n?n.includes(a):!0}):!0}var aE,ese,tse,$I,Ptt,rse,Stt,MS,Ltt,Ntt,Ott,Mtt,Utt,_tt,Ytt,Wtt,bo=Et(()=>{aE=$e(ve(\"querystring\")),ese=$e(Jn()),tse=$e(eX());jl();ih();Gl();bo();$I=\"virtual:\",Ptt=5,rse=/(os|cpu|libc)=([a-z0-9_-]+)/,Stt=(0,tse.makeParser)(rse);MS=/^[^#]*#/;Ltt=/^(?:@([^/]+?)\\/)?([^@/]+)$/;Ntt=/^(?:@([^/]+?)\\/)?([^@/]+?)(?:@(.+))$/,Ott=/^(?:@([^/]+?)\\/)?([^@/]+?)(?:@(.+))?$/;Mtt=/^(?:@([^/]+?)\\/)?([^@/]+?)(?:@(.+))$/,Utt=/^(?:@([^/]+?)\\/)?([^@/]+?)(?:@(.+))?$/;_tt=/^([^#:]*:)?((?:(?!::)[^#])*)(?:#((?:(?!::).)*))?(?:::(.*))?$/;Ytt=/:$/;Wtt=/\\?.*/});var sse,ose=Et(()=>{bo();sse={hooks:{reduceDependency:(t,e,r,o,{resolver:a,resolveOptions:n})=>{for(let{pattern:u,reference:A}of e.topLevelWorkspace.manifest.resolutions){if(u.from&&(u.from.fullName!==fn(r)||e.configuration.normalizeLocator(Qs(Vs(u.from.fullName),u.from.description??r.reference)).locatorHash!==r.locatorHash)||u.descriptor.fullName!==fn(t)||e.configuration.normalizeDependency(In(xf(u.descriptor.fullName),u.descriptor.description??t.range)).descriptorHash!==t.descriptorHash)continue;return a.bindDescriptor(e.configuration.normalizeDependency(In(t,A)),e.topLevelWorkspace.anchoredLocator,n)}return t},validateProject:async(t,e)=>{for(let r of t.workspaces){let o=a1(t.configuration,r);await t.configuration.triggerHook(a=>a.validateWorkspace,r,{reportWarning:(a,n)=>e.reportWarning(a,`${o}: ${n}`),reportError:(a,n)=>e.reportError(a,`${o}: ${n}`)})}},validateWorkspace:async(t,e)=>{let{manifest:r}=t;r.resolutions.length&&t.cwd!==t.project.cwd&&r.errors.push(new Error(\"Resolutions field will be ignored\"));for(let o of r.errors)e.reportWarning(57,o.message)}}}});var l1,Xn,Dd=Et(()=>{l1=class{supportsDescriptor(e,r){return!!(e.range.startsWith(l1.protocol)||r.project.tryWorkspaceByDescriptor(e)!==null)}supportsLocator(e,r){return!!e.reference.startsWith(l1.protocol)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,o){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){return[o.project.getWorkspaceByDescriptor(e).anchoredLocator]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){let o=r.project.getWorkspaceByCwd(e.reference.slice(l1.protocol.length));return{...e,version:o.manifest.version||\"0.0.0\",languageName:\"unknown\",linkType:\"SOFT\",conditions:null,dependencies:r.project.configuration.normalizeDependencyMap(new Map([...o.manifest.dependencies,...o.manifest.devDependencies])),peerDependencies:new Map([...o.manifest.peerDependencies]),dependenciesMeta:o.manifest.dependenciesMeta,peerDependenciesMeta:o.manifest.peerDependenciesMeta,bin:o.manifest.bin}}},Xn=l1;Xn.protocol=\"workspace:\"});var kr={};zt(kr,{SemVer:()=>Ase.SemVer,clean:()=>ztt,getComparator:()=>cse,mergeComparators:()=>iM,satisfiesWithPrereleases:()=>kf,simplifyRanges:()=>sM,stringifyComparator:()=>use,validRange:()=>xa});function kf(t,e,r=!1){if(!t)return!1;let o=`${e}${r}`,a=ase.get(o);if(typeof a>\"u\")try{a=new oh.default.Range(e,{includePrerelease:!0,loose:r})}catch{return!1}finally{ase.set(o,a||null)}else if(a===null)return!1;let n;try{n=new oh.default.SemVer(t,a)}catch{return!1}return a.test(n)?!0:(n.prerelease&&(n.prerelease=[]),a.set.some(u=>{for(let A of u)A.semver.prerelease&&(A.semver.prerelease=[]);return u.every(A=>A.test(n))}))}function xa(t){if(t.indexOf(\":\")!==-1)return null;let e=lse.get(t);if(typeof e<\"u\")return e;try{e=new oh.default.Range(t)}catch{e=null}return lse.set(t,e),e}function ztt(t){let e=Ktt.exec(t);return e?e[1]:null}function cse(t){if(t.semver===oh.default.Comparator.ANY)return{gt:null,lt:null};switch(t.operator){case\"\":return{gt:[\">=\",t.semver],lt:[\"<=\",t.semver]};case\">\":case\">=\":return{gt:[t.operator,t.semver],lt:null};case\"<\":case\"<=\":return{gt:null,lt:[t.operator,t.semver]};default:throw new Error(`Assertion failed: Unexpected comparator operator (${t.operator})`)}}function iM(t){if(t.length===0)return null;let e=null,r=null;for(let o of t){if(o.gt){let a=e!==null?oh.default.compare(o.gt[1],e[1]):null;(a===null||a>0||a===0&&o.gt[0]===\">\")&&(e=o.gt)}if(o.lt){let a=r!==null?oh.default.compare(o.lt[1],r[1]):null;(a===null||a<0||a===0&&o.lt[0]===\"<\")&&(r=o.lt)}}if(e&&r){let o=oh.default.compare(e[1],r[1]);if(o===0&&(e[0]===\">\"||r[0]===\"<\")||o>0)return null}return{gt:e,lt:r}}function use(t){if(t.gt&&t.lt){if(t.gt[0]===\">=\"&&t.lt[0]===\"<=\"&&t.gt[1].version===t.lt[1].version)return t.gt[1].version;if(t.gt[0]===\">=\"&&t.lt[0]===\"<\"){if(t.lt[1].version===`${t.gt[1].major+1}.0.0-0`)return`^${t.gt[1].version}`;if(t.lt[1].version===`${t.gt[1].major}.${t.gt[1].minor+1}.0-0`)return`~${t.gt[1].version}`}}let e=[];return t.gt&&e.push(t.gt[0]+t.gt[1].version),t.lt&&e.push(t.lt[0]+t.lt[1].version),e.length?e.join(\" \"):\"*\"}function sM(t){let e=t.map(o=>xa(o).set.map(a=>a.map(n=>cse(n)))),r=e.shift().map(o=>iM(o)).filter(o=>o!==null);for(let o of e){let a=[];for(let n of r)for(let u of o){let A=iM([n,...u]);A!==null&&a.push(A)}r=a}return r.length===0?null:r.map(o=>use(o)).join(\" || \")}var oh,Ase,ase,lse,Ktt,Qf=Et(()=>{oh=$e(Jn()),Ase=$e(Jn()),ase=new Map;lse=new Map;Ktt=/^(?:[\\sv=]*?)((0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?)(?:\\s*)$/});function fse(t){let e=t.match(/^[ \\t]+/m);return e?e[0]:\"  \"}function pse(t){return t.charCodeAt(0)===65279?t.slice(1):t}function $o(t){return t.replace(/\\\\/g,\"/\")}function GS(t,{yamlCompatibilityMode:e}){return e?wN(t):typeof t>\"u\"||typeof t==\"boolean\"?t:null}function hse(t,e){let r=e.search(/[^!]/);if(r===-1)return\"invalid\";let o=r%2===0?\"\":\"!\",a=e.slice(r);return`${o}${t}=${a}`}function oM(t,e){return e.length===1?hse(t,e[0]):`(${e.map(r=>hse(t,r)).join(\" | \")})`}var gse,AE,Ot,fE=Et(()=>{Pt();Nl();gse=$e(Jn());Dd();Gl();Qf();bo();AE=class{constructor(){this.indent=\"  \";this.name=null;this.version=null;this.os=null;this.cpu=null;this.libc=null;this.type=null;this.packageManager=null;this.private=!1;this.license=null;this.main=null;this.module=null;this.browser=null;this.languageName=null;this.bin=new Map;this.scripts=new Map;this.dependencies=new Map;this.devDependencies=new Map;this.peerDependencies=new Map;this.workspaceDefinitions=[];this.dependenciesMeta=new Map;this.peerDependenciesMeta=new Map;this.resolutions=[];this.files=null;this.publishConfig=null;this.installConfig=null;this.preferUnplugged=null;this.raw={};this.errors=[]}static async tryFind(e,{baseFs:r=new Tn}={}){let o=z.join(e,\"package.json\");try{return await AE.fromFile(o,{baseFs:r})}catch(a){if(a.code===\"ENOENT\")return null;throw a}}static async find(e,{baseFs:r}={}){let o=await AE.tryFind(e,{baseFs:r});if(o===null)throw new Error(\"Manifest not found\");return o}static async fromFile(e,{baseFs:r=new Tn}={}){let o=new AE;return await o.loadFile(e,{baseFs:r}),o}static fromText(e){let r=new AE;return r.loadFromText(e),r}loadFromText(e){let r;try{r=JSON.parse(pse(e)||\"{}\")}catch(o){throw o.message+=` (when parsing ${e})`,o}this.load(r),this.indent=fse(e)}async loadFile(e,{baseFs:r=new Tn}){let o=await r.readFilePromise(e,\"utf8\"),a;try{a=JSON.parse(pse(o)||\"{}\")}catch(n){throw n.message+=` (when parsing ${e})`,n}this.load(a),this.indent=fse(o)}load(e,{yamlCompatibilityMode:r=!1}={}){if(typeof e!=\"object\"||e===null)throw new Error(`Utterly invalid manifest data (${e})`);this.raw=e;let o=[];if(this.name=null,typeof e.name==\"string\")try{this.name=Vs(e.name)}catch{o.push(new Error(\"Parsing failed for the 'name' field\"))}if(typeof e.version==\"string\"?this.version=e.version:this.version=null,Array.isArray(e.os)){let n=[];this.os=n;for(let u of e.os)typeof u!=\"string\"?o.push(new Error(\"Parsing failed for the 'os' field\")):n.push(u)}else this.os=null;if(Array.isArray(e.cpu)){let n=[];this.cpu=n;for(let u of e.cpu)typeof u!=\"string\"?o.push(new Error(\"Parsing failed for the 'cpu' field\")):n.push(u)}else this.cpu=null;if(Array.isArray(e.libc)){let n=[];this.libc=n;for(let u of e.libc)typeof u!=\"string\"?o.push(new Error(\"Parsing failed for the 'libc' field\")):n.push(u)}else this.libc=null;if(typeof e.type==\"string\"?this.type=e.type:this.type=null,typeof e.packageManager==\"string\"?this.packageManager=e.packageManager:this.packageManager=null,typeof e.private==\"boolean\"?this.private=e.private:this.private=!1,typeof e.license==\"string\"?this.license=e.license:this.license=null,typeof e.languageName==\"string\"?this.languageName=e.languageName:this.languageName=null,typeof e.main==\"string\"?this.main=$o(e.main):this.main=null,typeof e.module==\"string\"?this.module=$o(e.module):this.module=null,e.browser!=null)if(typeof e.browser==\"string\")this.browser=$o(e.browser);else{this.browser=new Map;for(let[n,u]of Object.entries(e.browser))this.browser.set($o(n),typeof u==\"string\"?$o(u):u)}else this.browser=null;if(this.bin=new Map,typeof e.bin==\"string\")e.bin.trim()===\"\"?o.push(new Error(\"Invalid bin field\")):this.name!==null?this.bin.set(this.name.name,$o(e.bin)):o.push(new Error(\"String bin field, but no attached package name\"));else if(typeof e.bin==\"object\"&&e.bin!==null)for(let[n,u]of Object.entries(e.bin)){if(typeof u!=\"string\"||u.trim()===\"\"){o.push(new Error(`Invalid bin definition for '${n}'`));continue}let A=Vs(n);this.bin.set(A.name,$o(u))}if(this.scripts=new Map,typeof e.scripts==\"object\"&&e.scripts!==null)for(let[n,u]of Object.entries(e.scripts)){if(typeof u!=\"string\"){o.push(new Error(`Invalid script definition for '${n}'`));continue}this.scripts.set(n,u)}if(this.dependencies=new Map,typeof e.dependencies==\"object\"&&e.dependencies!==null)for(let[n,u]of Object.entries(e.dependencies)){if(typeof u!=\"string\"){o.push(new Error(`Invalid dependency range for '${n}'`));continue}let A;try{A=Vs(n)}catch{o.push(new Error(`Parsing failed for the dependency name '${n}'`));continue}let p=In(A,u);this.dependencies.set(p.identHash,p)}if(this.devDependencies=new Map,typeof e.devDependencies==\"object\"&&e.devDependencies!==null)for(let[n,u]of Object.entries(e.devDependencies)){if(typeof u!=\"string\"){o.push(new Error(`Invalid dependency range for '${n}'`));continue}let A;try{A=Vs(n)}catch{o.push(new Error(`Parsing failed for the dependency name '${n}'`));continue}let p=In(A,u);this.devDependencies.set(p.identHash,p)}if(this.peerDependencies=new Map,typeof e.peerDependencies==\"object\"&&e.peerDependencies!==null)for(let[n,u]of Object.entries(e.peerDependencies)){let A;try{A=Vs(n)}catch{o.push(new Error(`Parsing failed for the dependency name '${n}'`));continue}(typeof u!=\"string\"||!u.startsWith(Xn.protocol)&&!xa(u))&&(o.push(new Error(`Invalid dependency range for '${n}'`)),u=\"*\");let p=In(A,u);this.peerDependencies.set(p.identHash,p)}typeof e.workspaces==\"object\"&&e.workspaces!==null&&e.workspaces.nohoist&&o.push(new Error(\"'nohoist' is deprecated, please use 'installConfig.hoistingLimits' instead\"));let a=Array.isArray(e.workspaces)?e.workspaces:typeof e.workspaces==\"object\"&&e.workspaces!==null&&Array.isArray(e.workspaces.packages)?e.workspaces.packages:[];this.workspaceDefinitions=[];for(let n of a){if(typeof n!=\"string\"){o.push(new Error(`Invalid workspace definition for '${n}'`));continue}this.workspaceDefinitions.push({pattern:n})}if(this.dependenciesMeta=new Map,typeof e.dependenciesMeta==\"object\"&&e.dependenciesMeta!==null)for(let[n,u]of Object.entries(e.dependenciesMeta)){if(typeof u!=\"object\"||u===null){o.push(new Error(`Invalid meta field for '${n}`));continue}let A=sh(n),p=this.ensureDependencyMeta(A),h=GS(u.built,{yamlCompatibilityMode:r});if(h===null){o.push(new Error(`Invalid built meta field for '${n}'`));continue}let E=GS(u.optional,{yamlCompatibilityMode:r});if(E===null){o.push(new Error(`Invalid optional meta field for '${n}'`));continue}let I=GS(u.unplugged,{yamlCompatibilityMode:r});if(I===null){o.push(new Error(`Invalid unplugged meta field for '${n}'`));continue}Object.assign(p,{built:h,optional:E,unplugged:I})}if(this.peerDependenciesMeta=new Map,typeof e.peerDependenciesMeta==\"object\"&&e.peerDependenciesMeta!==null)for(let[n,u]of Object.entries(e.peerDependenciesMeta)){if(typeof u!=\"object\"||u===null){o.push(new Error(`Invalid meta field for '${n}'`));continue}let A=sh(n),p=this.ensurePeerDependencyMeta(A),h=GS(u.optional,{yamlCompatibilityMode:r});if(h===null){o.push(new Error(`Invalid optional meta field for '${n}'`));continue}Object.assign(p,{optional:h})}if(this.resolutions=[],typeof e.resolutions==\"object\"&&e.resolutions!==null)for(let[n,u]of Object.entries(e.resolutions)){if(typeof u!=\"string\"){o.push(new Error(`Invalid resolution entry for '${n}'`));continue}try{this.resolutions.push({pattern:MD(n),reference:u})}catch(A){o.push(A);continue}}if(Array.isArray(e.files)){this.files=new Set;for(let n of e.files){if(typeof n!=\"string\"){o.push(new Error(`Invalid files entry for '${n}'`));continue}this.files.add(n)}}else this.files=null;if(typeof e.publishConfig==\"object\"&&e.publishConfig!==null){if(this.publishConfig={},typeof e.publishConfig.access==\"string\"&&(this.publishConfig.access=e.publishConfig.access),typeof e.publishConfig.main==\"string\"&&(this.publishConfig.main=$o(e.publishConfig.main)),typeof e.publishConfig.module==\"string\"&&(this.publishConfig.module=$o(e.publishConfig.module)),e.publishConfig.browser!=null)if(typeof e.publishConfig.browser==\"string\")this.publishConfig.browser=$o(e.publishConfig.browser);else{this.publishConfig.browser=new Map;for(let[n,u]of Object.entries(e.publishConfig.browser))this.publishConfig.browser.set($o(n),typeof u==\"string\"?$o(u):u)}if(typeof e.publishConfig.registry==\"string\"&&(this.publishConfig.registry=e.publishConfig.registry),typeof e.publishConfig.bin==\"string\")this.name!==null?this.publishConfig.bin=new Map([[this.name.name,$o(e.publishConfig.bin)]]):o.push(new Error(\"String bin field, but no attached package name\"));else if(typeof e.publishConfig.bin==\"object\"&&e.publishConfig.bin!==null){this.publishConfig.bin=new Map;for(let[n,u]of Object.entries(e.publishConfig.bin)){if(typeof u!=\"string\"){o.push(new Error(`Invalid bin definition for '${n}'`));continue}this.publishConfig.bin.set(n,$o(u))}}if(Array.isArray(e.publishConfig.executableFiles)){this.publishConfig.executableFiles=new Set;for(let n of e.publishConfig.executableFiles){if(typeof n!=\"string\"){o.push(new Error(\"Invalid executable file definition\"));continue}this.publishConfig.executableFiles.add($o(n))}}}else this.publishConfig=null;if(typeof e.installConfig==\"object\"&&e.installConfig!==null){this.installConfig={};for(let n of Object.keys(e.installConfig))n===\"hoistingLimits\"?typeof e.installConfig.hoistingLimits==\"string\"?this.installConfig.hoistingLimits=e.installConfig.hoistingLimits:o.push(new Error(\"Invalid hoisting limits definition\")):n==\"selfReferences\"?typeof e.installConfig.selfReferences==\"boolean\"?this.installConfig.selfReferences=e.installConfig.selfReferences:o.push(new Error(\"Invalid selfReferences definition, must be a boolean value\")):o.push(new Error(`Unrecognized installConfig key: ${n}`))}else this.installConfig=null;if(typeof e.optionalDependencies==\"object\"&&e.optionalDependencies!==null)for(let[n,u]of Object.entries(e.optionalDependencies)){if(typeof u!=\"string\"){o.push(new Error(`Invalid dependency range for '${n}'`));continue}let A;try{A=Vs(n)}catch{o.push(new Error(`Parsing failed for the dependency name '${n}'`));continue}let p=In(A,u);this.dependencies.set(p.identHash,p);let h=In(A,\"unknown\"),E=this.ensureDependencyMeta(h);Object.assign(E,{optional:!0})}typeof e.preferUnplugged==\"boolean\"?this.preferUnplugged=e.preferUnplugged:this.preferUnplugged=null,this.errors=o}getForScope(e){switch(e){case\"dependencies\":return this.dependencies;case\"devDependencies\":return this.devDependencies;case\"peerDependencies\":return this.peerDependencies;default:throw new Error(`Unsupported value (\"${e}\")`)}}hasConsumerDependency(e){return!!(this.dependencies.has(e.identHash)||this.peerDependencies.has(e.identHash))}hasHardDependency(e){return!!(this.dependencies.has(e.identHash)||this.devDependencies.has(e.identHash))}hasSoftDependency(e){return!!this.peerDependencies.has(e.identHash)}hasDependency(e){return!!(this.hasHardDependency(e)||this.hasSoftDependency(e))}getConditions(){let e=[];return this.os&&this.os.length>0&&e.push(oM(\"os\",this.os)),this.cpu&&this.cpu.length>0&&e.push(oM(\"cpu\",this.cpu)),this.libc&&this.libc.length>0&&e.push(oM(\"libc\",this.libc)),e.length>0?e.join(\" & \"):null}ensureDependencyMeta(e){if(e.range!==\"unknown\"&&!gse.default.valid(e.range))throw new Error(`Invalid meta field range for '${Sa(e)}'`);let r=fn(e),o=e.range!==\"unknown\"?e.range:null,a=this.dependenciesMeta.get(r);a||this.dependenciesMeta.set(r,a=new Map);let n=a.get(o);return n||a.set(o,n={}),n}ensurePeerDependencyMeta(e){if(e.range!==\"unknown\")throw new Error(`Invalid meta field range for '${Sa(e)}'`);let r=fn(e),o=this.peerDependenciesMeta.get(r);return o||this.peerDependenciesMeta.set(r,o={}),o}setRawField(e,r,{after:o=[]}={}){let a=new Set(o.filter(n=>Object.hasOwn(this.raw,n)));if(a.size===0||Object.hasOwn(this.raw,e))this.raw[e]=r;else{let n=this.raw,u=this.raw={},A=!1;for(let p of Object.keys(n))u[p]=n[p],A||(a.delete(p),a.size===0&&(u[e]=r,A=!0))}}exportTo(e,{compatibilityMode:r=!0}={}){if(Object.assign(e,this.raw),this.name!==null?e.name=fn(this.name):delete e.name,this.version!==null?e.version=this.version:delete e.version,this.os!==null?e.os=this.os:delete e.os,this.cpu!==null?e.cpu=this.cpu:delete e.cpu,this.type!==null?e.type=this.type:delete e.type,this.packageManager!==null?e.packageManager=this.packageManager:delete e.packageManager,this.private?e.private=!0:delete e.private,this.license!==null?e.license=this.license:delete e.license,this.languageName!==null?e.languageName=this.languageName:delete e.languageName,this.main!==null?e.main=this.main:delete e.main,this.module!==null?e.module=this.module:delete e.module,this.browser!==null){let n=this.browser;typeof n==\"string\"?e.browser=n:n instanceof Map&&(e.browser=Object.assign({},...Array.from(n.keys()).sort().map(u=>({[u]:n.get(u)}))))}else delete e.browser;this.bin.size===1&&this.name!==null&&this.bin.has(this.name.name)?e.bin=this.bin.get(this.name.name):this.bin.size>0?e.bin=Object.assign({},...Array.from(this.bin.keys()).sort().map(n=>({[n]:this.bin.get(n)}))):delete e.bin,this.workspaceDefinitions.length>0?this.raw.workspaces&&!Array.isArray(this.raw.workspaces)?e.workspaces={...this.raw.workspaces,packages:this.workspaceDefinitions.map(({pattern:n})=>n)}:e.workspaces=this.workspaceDefinitions.map(({pattern:n})=>n):this.raw.workspaces&&!Array.isArray(this.raw.workspaces)&&Object.keys(this.raw.workspaces).length>0?e.workspaces=this.raw.workspaces:delete e.workspaces;let o=[],a=[];for(let n of this.dependencies.values()){let u=this.dependenciesMeta.get(fn(n)),A=!1;if(r&&u){let p=u.get(null);p&&p.optional&&(A=!0)}A?a.push(n):o.push(n)}o.length>0?e.dependencies=Object.assign({},...uE(o).map(n=>({[fn(n)]:n.range}))):delete e.dependencies,a.length>0?e.optionalDependencies=Object.assign({},...uE(a).map(n=>({[fn(n)]:n.range}))):delete e.optionalDependencies,this.devDependencies.size>0?e.devDependencies=Object.assign({},...uE(this.devDependencies.values()).map(n=>({[fn(n)]:n.range}))):delete e.devDependencies,this.peerDependencies.size>0?e.peerDependencies=Object.assign({},...uE(this.peerDependencies.values()).map(n=>({[fn(n)]:n.range}))):delete e.peerDependencies,e.dependenciesMeta={};for(let[n,u]of ks(this.dependenciesMeta.entries(),([A,p])=>A))for(let[A,p]of ks(u.entries(),([h,E])=>h!==null?`0${h}`:\"1\")){let h=A!==null?Sa(In(Vs(n),A)):n,E={...p};r&&A===null&&delete E.optional,Object.keys(E).length!==0&&(e.dependenciesMeta[h]=E)}if(Object.keys(e.dependenciesMeta).length===0&&delete e.dependenciesMeta,this.peerDependenciesMeta.size>0?e.peerDependenciesMeta=Object.assign({},...ks(this.peerDependenciesMeta.entries(),([n,u])=>n).map(([n,u])=>({[n]:u}))):delete e.peerDependenciesMeta,this.resolutions.length>0?e.resolutions=Object.assign({},...this.resolutions.map(({pattern:n,reference:u})=>({[UD(n)]:u}))):delete e.resolutions,this.files!==null?e.files=Array.from(this.files):delete e.files,this.preferUnplugged!==null?e.preferUnplugged=this.preferUnplugged:delete e.preferUnplugged,this.scripts!==null&&this.scripts.size>0){e.scripts??={};for(let n of Object.keys(e.scripts))this.scripts.has(n)||delete e.scripts[n];for(let[n,u]of this.scripts.entries())e.scripts[n]=u}else delete e.scripts;return e}},Ot=AE;Ot.fileName=\"package.json\",Ot.allDependencies=[\"dependencies\",\"devDependencies\",\"peerDependencies\"],Ot.hardDependencies=[\"dependencies\",\"devDependencies\"]});var mse=_((_Lt,dse)=>{var Vtt=Hl(),Jtt=function(){return Vtt.Date.now()};dse.exports=Jtt});var Ese=_((HLt,yse)=>{var Xtt=/\\s/;function Ztt(t){for(var e=t.length;e--&&Xtt.test(t.charAt(e)););return e}yse.exports=Ztt});var wse=_((qLt,Cse)=>{var $tt=Ese(),ert=/^\\s+/;function trt(t){return t&&t.slice(0,$tt(t)+1).replace(ert,\"\")}Cse.exports=trt});var pE=_((GLt,Ise)=>{var rrt=gd(),nrt=Ju(),irt=\"[object Symbol]\";function srt(t){return typeof t==\"symbol\"||nrt(t)&&rrt(t)==irt}Ise.exports=srt});var Pse=_((jLt,Dse)=>{var ort=wse(),Bse=sl(),art=pE(),vse=0/0,lrt=/^[-+]0x[0-9a-f]+$/i,crt=/^0b[01]+$/i,urt=/^0o[0-7]+$/i,Art=parseInt;function frt(t){if(typeof t==\"number\")return t;if(art(t))return vse;if(Bse(t)){var e=typeof t.valueOf==\"function\"?t.valueOf():t;t=Bse(e)?e+\"\":e}if(typeof t!=\"string\")return t===0?t:+t;t=ort(t);var r=crt.test(t);return r||urt.test(t)?Art(t.slice(2),r?2:8):lrt.test(t)?vse:+t}Dse.exports=frt});var xse=_((YLt,bse)=>{var prt=sl(),aM=mse(),Sse=Pse(),hrt=\"Expected a function\",grt=Math.max,drt=Math.min;function mrt(t,e,r){var o,a,n,u,A,p,h=0,E=!1,I=!1,v=!0;if(typeof t!=\"function\")throw new TypeError(hrt);e=Sse(e)||0,prt(r)&&(E=!!r.leading,I=\"maxWait\"in r,n=I?grt(Sse(r.maxWait)||0,e):n,v=\"trailing\"in r?!!r.trailing:v);function x(ue){var me=o,he=a;return o=a=void 0,h=ue,u=t.apply(he,me),u}function C(ue){return h=ue,A=setTimeout(U,e),E?x(ue):u}function R(ue){var me=ue-p,he=ue-h,Be=e-me;return I?drt(Be,n-he):Be}function N(ue){var me=ue-p,he=ue-h;return p===void 0||me>=e||me<0||I&&he>=n}function U(){var ue=aM();if(N(ue))return V(ue);A=setTimeout(U,R(ue))}function V(ue){return A=void 0,v&&o?x(ue):(o=a=void 0,u)}function te(){A!==void 0&&clearTimeout(A),h=0,o=p=a=A=void 0}function ae(){return A===void 0?u:V(aM())}function fe(){var ue=aM(),me=N(ue);if(o=arguments,a=this,p=ue,me){if(A===void 0)return C(p);if(I)return clearTimeout(A),A=setTimeout(U,e),x(p)}return A===void 0&&(A=setTimeout(U,e)),u}return fe.cancel=te,fe.flush=ae,fe}bse.exports=mrt});var lM=_((WLt,kse)=>{var yrt=xse(),Ert=sl(),Crt=\"Expected a function\";function wrt(t,e,r){var o=!0,a=!0;if(typeof t!=\"function\")throw new TypeError(Crt);return Ert(r)&&(o=\"leading\"in r?!!r.leading:o,a=\"trailing\"in r?!!r.trailing:a),yrt(t,e,{leading:o,maxWait:e,trailing:a})}kse.exports=wrt});function Brt(t){return typeof t.reportCode<\"u\"}var Qse,Fse,Rse,Irt,Jt,Xs,Wl=Et(()=>{Qse=$e(lM()),Fse=ve(\"stream\"),Rse=ve(\"string_decoder\"),Irt=15,Jt=class extends Error{constructor(r,o,a){super(o);this.reportExtra=a;this.reportCode=r}};Xs=class{constructor(){this.cacheHits=new Set;this.cacheMisses=new Set;this.reportedInfos=new Set;this.reportedWarnings=new Set;this.reportedErrors=new Set}getRecommendedLength(){return 180}reportCacheHit(e){this.cacheHits.add(e.locatorHash)}reportCacheMiss(e,r){this.cacheMisses.add(e.locatorHash)}static progressViaCounter(e){let r=0,o,a=new Promise(p=>{o=p}),n=p=>{let h=o;a=new Promise(E=>{o=E}),r=p,h()},u=(p=0)=>{n(r+1)},A=async function*(){for(;r<e;)await a,yield{progress:r/e}}();return{[Symbol.asyncIterator](){return A},hasProgress:!0,hasTitle:!1,set:n,tick:u}}static progressViaTitle(){let e,r,o=new Promise(u=>{r=u}),a=(0,Qse.default)(u=>{let A=r;o=new Promise(p=>{r=p}),e=u,A()},1e3/Irt),n=async function*(){for(;;)await o,yield{title:e}}();return{[Symbol.asyncIterator](){return n},hasProgress:!1,hasTitle:!0,setTitle:a}}async startProgressPromise(e,r){let o=this.reportProgress(e);try{return await r(e)}finally{o.stop()}}startProgressSync(e,r){let o=this.reportProgress(e);try{return r(e)}finally{o.stop()}}reportInfoOnce(e,r,o){let a=o&&o.key?o.key:r;this.reportedInfos.has(a)||(this.reportedInfos.add(a),this.reportInfo(e,r),o?.reportExtra?.(this))}reportWarningOnce(e,r,o){let a=o&&o.key?o.key:r;this.reportedWarnings.has(a)||(this.reportedWarnings.add(a),this.reportWarning(e,r),o?.reportExtra?.(this))}reportErrorOnce(e,r,o){let a=o&&o.key?o.key:r;this.reportedErrors.has(a)||(this.reportedErrors.add(a),this.reportError(e,r),o?.reportExtra?.(this))}reportExceptionOnce(e){Brt(e)?this.reportErrorOnce(e.reportCode,e.message,{key:e,reportExtra:e.reportExtra}):this.reportErrorOnce(1,e.stack||e.message,{key:e})}createStreamReporter(e=null){let r=new Fse.PassThrough,o=new Rse.StringDecoder,a=\"\";return r.on(\"data\",n=>{let u=o.write(n),A;do if(A=u.indexOf(`\n`),A!==-1){let p=a+u.substring(0,A);u=u.substring(A+1),a=\"\",e!==null?this.reportInfo(null,`${e} ${p}`):this.reportInfo(null,p)}while(A!==-1);a+=u}),r.on(\"end\",()=>{let n=o.end();n!==\"\"&&(e!==null?this.reportInfo(null,`${e} ${n}`):this.reportInfo(null,n))}),r}}});var hE,cM=Et(()=>{Wl();bo();hE=class{constructor(e){this.fetchers=e}supports(e,r){return!!this.tryFetcher(e,r)}getLocalPath(e,r){return this.getFetcher(e,r).getLocalPath(e,r)}async fetch(e,r){return await this.getFetcher(e,r).fetch(e,r)}tryFetcher(e,r){let o=this.fetchers.find(a=>a.supports(e,r));return o||null}getFetcher(e,r){let o=this.fetchers.find(a=>a.supports(e,r));if(!o)throw new Jt(11,`${qr(r.project.configuration,e)} isn't supported by any available fetcher`);return o}}});var Pd,uM=Et(()=>{bo();Pd=class{constructor(e){this.resolvers=e.filter(r=>r)}supportsDescriptor(e,r){return!!this.tryResolverByDescriptor(e,r)}supportsLocator(e,r){return!!this.tryResolverByLocator(e,r)}shouldPersistResolution(e,r){return this.getResolverByLocator(e,r).shouldPersistResolution(e,r)}bindDescriptor(e,r,o){return this.getResolverByDescriptor(e,o).bindDescriptor(e,r,o)}getResolutionDependencies(e,r){return this.getResolverByDescriptor(e,r).getResolutionDependencies(e,r)}async getCandidates(e,r,o){return await this.getResolverByDescriptor(e,o).getCandidates(e,r,o)}async getSatisfying(e,r,o,a){return this.getResolverByDescriptor(e,a).getSatisfying(e,r,o,a)}async resolve(e,r){return await this.getResolverByLocator(e,r).resolve(e,r)}tryResolverByDescriptor(e,r){let o=this.resolvers.find(a=>a.supportsDescriptor(e,r));return o||null}getResolverByDescriptor(e,r){let o=this.resolvers.find(a=>a.supportsDescriptor(e,r));if(!o)throw new Error(`${Gn(r.project.configuration,e)} isn't supported by any available resolver`);return o}tryResolverByLocator(e,r){let o=this.resolvers.find(a=>a.supportsLocator(e,r));return o||null}getResolverByLocator(e,r){let o=this.resolvers.find(a=>a.supportsLocator(e,r));if(!o)throw new Error(`${qr(r.project.configuration,e)} isn't supported by any available resolver`);return o}}});var gE,AM=Et(()=>{Pt();bo();gE=class{supports(e){return!!e.reference.startsWith(\"virtual:\")}getLocalPath(e,r){let o=e.reference.indexOf(\"#\");if(o===-1)throw new Error(\"Invalid virtual package reference\");let a=e.reference.slice(o+1),n=Qs(e,a);return r.fetcher.getLocalPath(n,r)}async fetch(e,r){let o=e.reference.indexOf(\"#\");if(o===-1)throw new Error(\"Invalid virtual package reference\");let a=e.reference.slice(o+1),n=Qs(e,a),u=await r.fetcher.fetch(n,r);return await this.ensureVirtualLink(e,u,r)}getLocatorFilename(e){return lE(e)}async ensureVirtualLink(e,r,o){let a=r.packageFs.getRealPath(),n=o.project.configuration.get(\"virtualFolder\"),u=this.getLocatorFilename(e),A=mi.makeVirtualPath(n,u,a),p=new _u(A,{baseFs:r.packageFs,pathUtils:z});return{...r,packageFs:p}}}});var dE,c1,Tse=Et(()=>{dE=class{static isVirtualDescriptor(e){return!!e.range.startsWith(dE.protocol)}static isVirtualLocator(e){return!!e.reference.startsWith(dE.protocol)}supportsDescriptor(e,r){return dE.isVirtualDescriptor(e)}supportsLocator(e,r){return dE.isVirtualLocator(e)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,o){throw new Error('Assertion failed: calling \"bindDescriptor\" on a virtual descriptor is unsupported')}getResolutionDependencies(e,r){throw new Error('Assertion failed: calling \"getResolutionDependencies\" on a virtual descriptor is unsupported')}async getCandidates(e,r,o){throw new Error('Assertion failed: calling \"getCandidates\" on a virtual descriptor is unsupported')}async getSatisfying(e,r,o,a){throw new Error('Assertion failed: calling \"getSatisfying\" on a virtual descriptor is unsupported')}async resolve(e,r){throw new Error('Assertion failed: calling \"resolve\" on a virtual locator is unsupported')}},c1=dE;c1.protocol=\"virtual:\"});var mE,fM=Et(()=>{Pt();Dd();mE=class{supports(e){return!!e.reference.startsWith(Xn.protocol)}getLocalPath(e,r){return this.getWorkspace(e,r).cwd}async fetch(e,r){let o=this.getWorkspace(e,r).cwd;return{packageFs:new gn(o),prefixPath:Bt.dot,localPath:o}}getWorkspace(e,r){return r.project.getWorkspaceByCwd(e.reference.slice(Xn.protocol.length))}}});function u1(t){return typeof t==\"object\"&&t!==null&&!Array.isArray(t)}function Lse(t){return typeof t>\"u\"?3:u1(t)?0:Array.isArray(t)?1:2}function gM(t,e){return Object.hasOwn(t,e)}function Drt(t){return u1(t)&&gM(t,\"onConflict\")&&typeof t.onConflict==\"string\"}function Prt(t){if(typeof t>\"u\")return{onConflict:\"default\",value:t};if(!Drt(t))return{onConflict:\"default\",value:t};if(gM(t,\"value\"))return t;let{onConflict:e,...r}=t;return{onConflict:e,value:r}}function Nse(t,e){let r=u1(t)&&gM(t,e)?t[e]:void 0;return Prt(r)}function yE(t,e){return[t,e,Ose]}function dM(t){return Array.isArray(t)?t[2]===Ose:!1}function pM(t,e){if(u1(t)){let r={};for(let o of Object.keys(t))r[o]=pM(t[o],e);return yE(e,r)}return Array.isArray(t)?yE(e,t.map(r=>pM(r,e))):yE(e,t)}function hM(t,e,r,o,a){let n,u=[],A=a,p=0;for(let E=a-1;E>=o;--E){let[I,v]=t[E],{onConflict:x,value:C}=Nse(v,r),R=Lse(C);if(R!==3){if(n??=R,R!==n||x===\"hardReset\"){p=A;break}if(R===2)return yE(I,C);if(u.unshift([I,C]),x===\"reset\"){p=E;break}x===\"extend\"&&E===o&&(o=0),A=E}}if(typeof n>\"u\")return null;let h=u.map(([E])=>E).join(\", \");switch(n){case 1:return yE(h,new Array().concat(...u.map(([E,I])=>I.map(v=>pM(v,E)))));case 0:{let E=Object.assign({},...u.map(([,R])=>R)),I=Object.keys(E),v={},x=t.map(([R,N])=>[R,Nse(N,r).value]),C=vrt(x,([R,N])=>{let U=Lse(N);return U!==0&&U!==3});if(C!==-1){let R=x.slice(C+1);for(let N of I)v[N]=hM(R,e,N,0,R.length)}else for(let R of I)v[R]=hM(x,e,R,p,x.length);return yE(h,v)}default:throw new Error(\"Assertion failed: Non-extendable value type\")}}function Mse(t){return hM(t.map(([e,r])=>[e,{[\".\"]:r}]),[],\".\",0,t.length)}function A1(t){return dM(t)?t[1]:t}function jS(t){let e=dM(t)?t[1]:t;if(Array.isArray(e))return e.map(r=>jS(r));if(u1(e)){let r={};for(let[o,a]of Object.entries(e))r[o]=jS(a);return r}return e}function mM(t){return dM(t)?t[0]:null}var vrt,Ose,Use=Et(()=>{vrt=(t,e,r)=>{let o=[...t];return o.reverse(),o.findIndex(e,r)};Ose=Symbol()});var YS={};zt(YS,{getDefaultGlobalFolder:()=>EM,getHomeFolder:()=>EE,isFolderInside:()=>CM});function EM(){if(process.platform===\"win32\"){let t=le.toPortablePath(process.env.LOCALAPPDATA||le.join((0,yM.homedir)(),\"AppData\",\"Local\"));return z.resolve(t,\"Yarn/Berry\")}if(process.env.XDG_DATA_HOME){let t=le.toPortablePath(process.env.XDG_DATA_HOME);return z.resolve(t,\"yarn/berry\")}return z.resolve(EE(),\".yarn/berry\")}function EE(){return le.toPortablePath((0,yM.homedir)()||\"/usr/local/share\")}function CM(t,e){let r=z.relative(e,t);return r&&!r.startsWith(\"..\")&&!z.isAbsolute(r)}var yM,WS=Et(()=>{Pt();yM=ve(\"os\")});var Gse=_(CE=>{\"use strict\";var sNt=ve(\"net\"),brt=ve(\"tls\"),wM=ve(\"http\"),_se=ve(\"https\"),xrt=ve(\"events\"),oNt=ve(\"assert\"),krt=ve(\"util\");CE.httpOverHttp=Qrt;CE.httpsOverHttp=Frt;CE.httpOverHttps=Rrt;CE.httpsOverHttps=Trt;function Qrt(t){var e=new Ff(t);return e.request=wM.request,e}function Frt(t){var e=new Ff(t);return e.request=wM.request,e.createSocket=Hse,e.defaultPort=443,e}function Rrt(t){var e=new Ff(t);return e.request=_se.request,e}function Trt(t){var e=new Ff(t);return e.request=_se.request,e.createSocket=Hse,e.defaultPort=443,e}function Ff(t){var e=this;e.options=t||{},e.proxyOptions=e.options.proxy||{},e.maxSockets=e.options.maxSockets||wM.Agent.defaultMaxSockets,e.requests=[],e.sockets=[],e.on(\"free\",function(o,a,n,u){for(var A=qse(a,n,u),p=0,h=e.requests.length;p<h;++p){var E=e.requests[p];if(E.host===A.host&&E.port===A.port){e.requests.splice(p,1),E.request.onSocket(o);return}}o.destroy(),e.removeSocket(o)})}krt.inherits(Ff,xrt.EventEmitter);Ff.prototype.addRequest=function(e,r,o,a){var n=this,u=IM({request:e},n.options,qse(r,o,a));if(n.sockets.length>=this.maxSockets){n.requests.push(u);return}n.createSocket(u,function(A){A.on(\"free\",p),A.on(\"close\",h),A.on(\"agentRemove\",h),e.onSocket(A);function p(){n.emit(\"free\",A,u)}function h(E){n.removeSocket(A),A.removeListener(\"free\",p),A.removeListener(\"close\",h),A.removeListener(\"agentRemove\",h)}})};Ff.prototype.createSocket=function(e,r){var o=this,a={};o.sockets.push(a);var n=IM({},o.proxyOptions,{method:\"CONNECT\",path:e.host+\":\"+e.port,agent:!1,headers:{host:e.host+\":\"+e.port}});e.localAddress&&(n.localAddress=e.localAddress),n.proxyAuth&&(n.headers=n.headers||{},n.headers[\"Proxy-Authorization\"]=\"Basic \"+new Buffer(n.proxyAuth).toString(\"base64\")),ah(\"making CONNECT request\");var u=o.request(n);u.useChunkedEncodingByDefault=!1,u.once(\"response\",A),u.once(\"upgrade\",p),u.once(\"connect\",h),u.once(\"error\",E),u.end();function A(I){I.upgrade=!0}function p(I,v,x){process.nextTick(function(){h(I,v,x)})}function h(I,v,x){if(u.removeAllListeners(),v.removeAllListeners(),I.statusCode!==200){ah(\"tunneling socket could not be established, statusCode=%d\",I.statusCode),v.destroy();var C=new Error(\"tunneling socket could not be established, statusCode=\"+I.statusCode);C.code=\"ECONNRESET\",e.request.emit(\"error\",C),o.removeSocket(a);return}if(x.length>0){ah(\"got illegal response body from proxy\"),v.destroy();var C=new Error(\"got illegal response body from proxy\");C.code=\"ECONNRESET\",e.request.emit(\"error\",C),o.removeSocket(a);return}return ah(\"tunneling connection has established\"),o.sockets[o.sockets.indexOf(a)]=v,r(v)}function E(I){u.removeAllListeners(),ah(`tunneling socket could not be established, cause=%s\n`,I.message,I.stack);var v=new Error(\"tunneling socket could not be established, cause=\"+I.message);v.code=\"ECONNRESET\",e.request.emit(\"error\",v),o.removeSocket(a)}};Ff.prototype.removeSocket=function(e){var r=this.sockets.indexOf(e);if(r!==-1){this.sockets.splice(r,1);var o=this.requests.shift();o&&this.createSocket(o,function(a){o.request.onSocket(a)})}};function Hse(t,e){var r=this;Ff.prototype.createSocket.call(r,t,function(o){var a=t.request.getHeader(\"host\"),n=IM({},r.options,{socket:o,servername:a?a.replace(/:.*$/,\"\"):t.host}),u=brt.connect(0,n);r.sockets[r.sockets.indexOf(o)]=u,e(u)})}function qse(t,e,r){return typeof t==\"string\"?{host:t,port:e,localAddress:r}:t}function IM(t){for(var e=1,r=arguments.length;e<r;++e){var o=arguments[e];if(typeof o==\"object\")for(var a=Object.keys(o),n=0,u=a.length;n<u;++n){var A=a[n];o[A]!==void 0&&(t[A]=o[A])}}return t}var ah;process.env.NODE_DEBUG&&/\\btunnel\\b/.test(process.env.NODE_DEBUG)?ah=function(){var t=Array.prototype.slice.call(arguments);typeof t[0]==\"string\"?t[0]=\"TUNNEL: \"+t[0]:t.unshift(\"TUNNEL:\"),console.error.apply(console,t)}:ah=function(){};CE.debug=ah});var Yse=_((lNt,jse)=>{jse.exports=Gse()});var Tf=_((Rf,KS)=>{\"use strict\";Object.defineProperty(Rf,\"__esModule\",{value:!0});var Wse=[\"Int8Array\",\"Uint8Array\",\"Uint8ClampedArray\",\"Int16Array\",\"Uint16Array\",\"Int32Array\",\"Uint32Array\",\"Float32Array\",\"Float64Array\",\"BigInt64Array\",\"BigUint64Array\"];function Lrt(t){return Wse.includes(t)}var Nrt=[\"Function\",\"Generator\",\"AsyncGenerator\",\"GeneratorFunction\",\"AsyncGeneratorFunction\",\"AsyncFunction\",\"Observable\",\"Array\",\"Buffer\",\"Blob\",\"Object\",\"RegExp\",\"Date\",\"Error\",\"Map\",\"Set\",\"WeakMap\",\"WeakSet\",\"ArrayBuffer\",\"SharedArrayBuffer\",\"DataView\",\"Promise\",\"URL\",\"FormData\",\"URLSearchParams\",\"HTMLElement\",...Wse];function Ort(t){return Nrt.includes(t)}var Mrt=[\"null\",\"undefined\",\"string\",\"number\",\"bigint\",\"boolean\",\"symbol\"];function Urt(t){return Mrt.includes(t)}function wE(t){return e=>typeof e===t}var{toString:Kse}=Object.prototype,f1=t=>{let e=Kse.call(t).slice(8,-1);if(/HTML\\w+Element/.test(e)&&Se.domElement(t))return\"HTMLElement\";if(Ort(e))return e},Zn=t=>e=>f1(e)===t;function Se(t){if(t===null)return\"null\";switch(typeof t){case\"undefined\":return\"undefined\";case\"string\":return\"string\";case\"number\":return\"number\";case\"boolean\":return\"boolean\";case\"function\":return\"Function\";case\"bigint\":return\"bigint\";case\"symbol\":return\"symbol\";default:}if(Se.observable(t))return\"Observable\";if(Se.array(t))return\"Array\";if(Se.buffer(t))return\"Buffer\";let e=f1(t);if(e)return e;if(t instanceof String||t instanceof Boolean||t instanceof Number)throw new TypeError(\"Please don't use object wrappers for primitive types\");return\"Object\"}Se.undefined=wE(\"undefined\");Se.string=wE(\"string\");var _rt=wE(\"number\");Se.number=t=>_rt(t)&&!Se.nan(t);Se.bigint=wE(\"bigint\");Se.function_=wE(\"function\");Se.null_=t=>t===null;Se.class_=t=>Se.function_(t)&&t.toString().startsWith(\"class \");Se.boolean=t=>t===!0||t===!1;Se.symbol=wE(\"symbol\");Se.numericString=t=>Se.string(t)&&!Se.emptyStringOrWhitespace(t)&&!Number.isNaN(Number(t));Se.array=(t,e)=>Array.isArray(t)?Se.function_(e)?t.every(e):!0:!1;Se.buffer=t=>{var e,r,o,a;return(a=(o=(r=(e=t)===null||e===void 0?void 0:e.constructor)===null||r===void 0?void 0:r.isBuffer)===null||o===void 0?void 0:o.call(r,t))!==null&&a!==void 0?a:!1};Se.blob=t=>Zn(\"Blob\")(t);Se.nullOrUndefined=t=>Se.null_(t)||Se.undefined(t);Se.object=t=>!Se.null_(t)&&(typeof t==\"object\"||Se.function_(t));Se.iterable=t=>{var e;return Se.function_((e=t)===null||e===void 0?void 0:e[Symbol.iterator])};Se.asyncIterable=t=>{var e;return Se.function_((e=t)===null||e===void 0?void 0:e[Symbol.asyncIterator])};Se.generator=t=>{var e,r;return Se.iterable(t)&&Se.function_((e=t)===null||e===void 0?void 0:e.next)&&Se.function_((r=t)===null||r===void 0?void 0:r.throw)};Se.asyncGenerator=t=>Se.asyncIterable(t)&&Se.function_(t.next)&&Se.function_(t.throw);Se.nativePromise=t=>Zn(\"Promise\")(t);var Hrt=t=>{var e,r;return Se.function_((e=t)===null||e===void 0?void 0:e.then)&&Se.function_((r=t)===null||r===void 0?void 0:r.catch)};Se.promise=t=>Se.nativePromise(t)||Hrt(t);Se.generatorFunction=Zn(\"GeneratorFunction\");Se.asyncGeneratorFunction=t=>f1(t)===\"AsyncGeneratorFunction\";Se.asyncFunction=t=>f1(t)===\"AsyncFunction\";Se.boundFunction=t=>Se.function_(t)&&!t.hasOwnProperty(\"prototype\");Se.regExp=Zn(\"RegExp\");Se.date=Zn(\"Date\");Se.error=Zn(\"Error\");Se.map=t=>Zn(\"Map\")(t);Se.set=t=>Zn(\"Set\")(t);Se.weakMap=t=>Zn(\"WeakMap\")(t);Se.weakSet=t=>Zn(\"WeakSet\")(t);Se.int8Array=Zn(\"Int8Array\");Se.uint8Array=Zn(\"Uint8Array\");Se.uint8ClampedArray=Zn(\"Uint8ClampedArray\");Se.int16Array=Zn(\"Int16Array\");Se.uint16Array=Zn(\"Uint16Array\");Se.int32Array=Zn(\"Int32Array\");Se.uint32Array=Zn(\"Uint32Array\");Se.float32Array=Zn(\"Float32Array\");Se.float64Array=Zn(\"Float64Array\");Se.bigInt64Array=Zn(\"BigInt64Array\");Se.bigUint64Array=Zn(\"BigUint64Array\");Se.arrayBuffer=Zn(\"ArrayBuffer\");Se.sharedArrayBuffer=Zn(\"SharedArrayBuffer\");Se.dataView=Zn(\"DataView\");Se.enumCase=(t,e)=>Object.values(e).includes(t);Se.directInstanceOf=(t,e)=>Object.getPrototypeOf(t)===e.prototype;Se.urlInstance=t=>Zn(\"URL\")(t);Se.urlString=t=>{if(!Se.string(t))return!1;try{return new URL(t),!0}catch{return!1}};Se.truthy=t=>Boolean(t);Se.falsy=t=>!t;Se.nan=t=>Number.isNaN(t);Se.primitive=t=>Se.null_(t)||Urt(typeof t);Se.integer=t=>Number.isInteger(t);Se.safeInteger=t=>Number.isSafeInteger(t);Se.plainObject=t=>{if(Kse.call(t)!==\"[object Object]\")return!1;let e=Object.getPrototypeOf(t);return e===null||e===Object.getPrototypeOf({})};Se.typedArray=t=>Lrt(f1(t));var qrt=t=>Se.safeInteger(t)&&t>=0;Se.arrayLike=t=>!Se.nullOrUndefined(t)&&!Se.function_(t)&&qrt(t.length);Se.inRange=(t,e)=>{if(Se.number(e))return t>=Math.min(0,e)&&t<=Math.max(e,0);if(Se.array(e)&&e.length===2)return t>=Math.min(...e)&&t<=Math.max(...e);throw new TypeError(`Invalid range: ${JSON.stringify(e)}`)};var Grt=1,jrt=[\"innerHTML\",\"ownerDocument\",\"style\",\"attributes\",\"nodeValue\"];Se.domElement=t=>Se.object(t)&&t.nodeType===Grt&&Se.string(t.nodeName)&&!Se.plainObject(t)&&jrt.every(e=>e in t);Se.observable=t=>{var e,r,o,a;return t?t===((r=(e=t)[Symbol.observable])===null||r===void 0?void 0:r.call(e))||t===((a=(o=t)[\"@@observable\"])===null||a===void 0?void 0:a.call(o)):!1};Se.nodeStream=t=>Se.object(t)&&Se.function_(t.pipe)&&!Se.observable(t);Se.infinite=t=>t===1/0||t===-1/0;var zse=t=>e=>Se.integer(e)&&Math.abs(e%2)===t;Se.evenInteger=zse(0);Se.oddInteger=zse(1);Se.emptyArray=t=>Se.array(t)&&t.length===0;Se.nonEmptyArray=t=>Se.array(t)&&t.length>0;Se.emptyString=t=>Se.string(t)&&t.length===0;var Yrt=t=>Se.string(t)&&!/\\S/.test(t);Se.emptyStringOrWhitespace=t=>Se.emptyString(t)||Yrt(t);Se.nonEmptyString=t=>Se.string(t)&&t.length>0;Se.nonEmptyStringAndNotWhitespace=t=>Se.string(t)&&!Se.emptyStringOrWhitespace(t);Se.emptyObject=t=>Se.object(t)&&!Se.map(t)&&!Se.set(t)&&Object.keys(t).length===0;Se.nonEmptyObject=t=>Se.object(t)&&!Se.map(t)&&!Se.set(t)&&Object.keys(t).length>0;Se.emptySet=t=>Se.set(t)&&t.size===0;Se.nonEmptySet=t=>Se.set(t)&&t.size>0;Se.emptyMap=t=>Se.map(t)&&t.size===0;Se.nonEmptyMap=t=>Se.map(t)&&t.size>0;Se.propertyKey=t=>Se.any([Se.string,Se.number,Se.symbol],t);Se.formData=t=>Zn(\"FormData\")(t);Se.urlSearchParams=t=>Zn(\"URLSearchParams\")(t);var Vse=(t,e,r)=>{if(!Se.function_(e))throw new TypeError(`Invalid predicate: ${JSON.stringify(e)}`);if(r.length===0)throw new TypeError(\"Invalid number of values\");return t.call(r,e)};Se.any=(t,...e)=>(Se.array(t)?t:[t]).some(o=>Vse(Array.prototype.some,o,e));Se.all=(t,...e)=>Vse(Array.prototype.every,t,e);var Mt=(t,e,r,o={})=>{if(!t){let{multipleValues:a}=o,n=a?`received values of types ${[...new Set(r.map(u=>`\\`${Se(u)}\\``))].join(\", \")}`:`received value of type \\`${Se(r)}\\``;throw new TypeError(`Expected value which is \\`${e}\\`, ${n}.`)}};Rf.assert={undefined:t=>Mt(Se.undefined(t),\"undefined\",t),string:t=>Mt(Se.string(t),\"string\",t),number:t=>Mt(Se.number(t),\"number\",t),bigint:t=>Mt(Se.bigint(t),\"bigint\",t),function_:t=>Mt(Se.function_(t),\"Function\",t),null_:t=>Mt(Se.null_(t),\"null\",t),class_:t=>Mt(Se.class_(t),\"Class\",t),boolean:t=>Mt(Se.boolean(t),\"boolean\",t),symbol:t=>Mt(Se.symbol(t),\"symbol\",t),numericString:t=>Mt(Se.numericString(t),\"string with a number\",t),array:(t,e)=>{Mt(Se.array(t),\"Array\",t),e&&t.forEach(e)},buffer:t=>Mt(Se.buffer(t),\"Buffer\",t),blob:t=>Mt(Se.blob(t),\"Blob\",t),nullOrUndefined:t=>Mt(Se.nullOrUndefined(t),\"null or undefined\",t),object:t=>Mt(Se.object(t),\"Object\",t),iterable:t=>Mt(Se.iterable(t),\"Iterable\",t),asyncIterable:t=>Mt(Se.asyncIterable(t),\"AsyncIterable\",t),generator:t=>Mt(Se.generator(t),\"Generator\",t),asyncGenerator:t=>Mt(Se.asyncGenerator(t),\"AsyncGenerator\",t),nativePromise:t=>Mt(Se.nativePromise(t),\"native Promise\",t),promise:t=>Mt(Se.promise(t),\"Promise\",t),generatorFunction:t=>Mt(Se.generatorFunction(t),\"GeneratorFunction\",t),asyncGeneratorFunction:t=>Mt(Se.asyncGeneratorFunction(t),\"AsyncGeneratorFunction\",t),asyncFunction:t=>Mt(Se.asyncFunction(t),\"AsyncFunction\",t),boundFunction:t=>Mt(Se.boundFunction(t),\"Function\",t),regExp:t=>Mt(Se.regExp(t),\"RegExp\",t),date:t=>Mt(Se.date(t),\"Date\",t),error:t=>Mt(Se.error(t),\"Error\",t),map:t=>Mt(Se.map(t),\"Map\",t),set:t=>Mt(Se.set(t),\"Set\",t),weakMap:t=>Mt(Se.weakMap(t),\"WeakMap\",t),weakSet:t=>Mt(Se.weakSet(t),\"WeakSet\",t),int8Array:t=>Mt(Se.int8Array(t),\"Int8Array\",t),uint8Array:t=>Mt(Se.uint8Array(t),\"Uint8Array\",t),uint8ClampedArray:t=>Mt(Se.uint8ClampedArray(t),\"Uint8ClampedArray\",t),int16Array:t=>Mt(Se.int16Array(t),\"Int16Array\",t),uint16Array:t=>Mt(Se.uint16Array(t),\"Uint16Array\",t),int32Array:t=>Mt(Se.int32Array(t),\"Int32Array\",t),uint32Array:t=>Mt(Se.uint32Array(t),\"Uint32Array\",t),float32Array:t=>Mt(Se.float32Array(t),\"Float32Array\",t),float64Array:t=>Mt(Se.float64Array(t),\"Float64Array\",t),bigInt64Array:t=>Mt(Se.bigInt64Array(t),\"BigInt64Array\",t),bigUint64Array:t=>Mt(Se.bigUint64Array(t),\"BigUint64Array\",t),arrayBuffer:t=>Mt(Se.arrayBuffer(t),\"ArrayBuffer\",t),sharedArrayBuffer:t=>Mt(Se.sharedArrayBuffer(t),\"SharedArrayBuffer\",t),dataView:t=>Mt(Se.dataView(t),\"DataView\",t),enumCase:(t,e)=>Mt(Se.enumCase(t,e),\"EnumCase\",t),urlInstance:t=>Mt(Se.urlInstance(t),\"URL\",t),urlString:t=>Mt(Se.urlString(t),\"string with a URL\",t),truthy:t=>Mt(Se.truthy(t),\"truthy\",t),falsy:t=>Mt(Se.falsy(t),\"falsy\",t),nan:t=>Mt(Se.nan(t),\"NaN\",t),primitive:t=>Mt(Se.primitive(t),\"primitive\",t),integer:t=>Mt(Se.integer(t),\"integer\",t),safeInteger:t=>Mt(Se.safeInteger(t),\"integer\",t),plainObject:t=>Mt(Se.plainObject(t),\"plain object\",t),typedArray:t=>Mt(Se.typedArray(t),\"TypedArray\",t),arrayLike:t=>Mt(Se.arrayLike(t),\"array-like\",t),domElement:t=>Mt(Se.domElement(t),\"HTMLElement\",t),observable:t=>Mt(Se.observable(t),\"Observable\",t),nodeStream:t=>Mt(Se.nodeStream(t),\"Node.js Stream\",t),infinite:t=>Mt(Se.infinite(t),\"infinite number\",t),emptyArray:t=>Mt(Se.emptyArray(t),\"empty array\",t),nonEmptyArray:t=>Mt(Se.nonEmptyArray(t),\"non-empty array\",t),emptyString:t=>Mt(Se.emptyString(t),\"empty string\",t),emptyStringOrWhitespace:t=>Mt(Se.emptyStringOrWhitespace(t),\"empty string or whitespace\",t),nonEmptyString:t=>Mt(Se.nonEmptyString(t),\"non-empty string\",t),nonEmptyStringAndNotWhitespace:t=>Mt(Se.nonEmptyStringAndNotWhitespace(t),\"non-empty string and not whitespace\",t),emptyObject:t=>Mt(Se.emptyObject(t),\"empty object\",t),nonEmptyObject:t=>Mt(Se.nonEmptyObject(t),\"non-empty object\",t),emptySet:t=>Mt(Se.emptySet(t),\"empty set\",t),nonEmptySet:t=>Mt(Se.nonEmptySet(t),\"non-empty set\",t),emptyMap:t=>Mt(Se.emptyMap(t),\"empty map\",t),nonEmptyMap:t=>Mt(Se.nonEmptyMap(t),\"non-empty map\",t),propertyKey:t=>Mt(Se.propertyKey(t),\"PropertyKey\",t),formData:t=>Mt(Se.formData(t),\"FormData\",t),urlSearchParams:t=>Mt(Se.urlSearchParams(t),\"URLSearchParams\",t),evenInteger:t=>Mt(Se.evenInteger(t),\"even integer\",t),oddInteger:t=>Mt(Se.oddInteger(t),\"odd integer\",t),directInstanceOf:(t,e)=>Mt(Se.directInstanceOf(t,e),\"T\",t),inRange:(t,e)=>Mt(Se.inRange(t,e),\"in range\",t),any:(t,...e)=>Mt(Se.any(t,...e),\"predicate returns truthy for any value\",e,{multipleValues:!0}),all:(t,...e)=>Mt(Se.all(t,...e),\"predicate returns truthy for all values\",e,{multipleValues:!0})};Object.defineProperties(Se,{class:{value:Se.class_},function:{value:Se.function_},null:{value:Se.null_}});Object.defineProperties(Rf.assert,{class:{value:Rf.assert.class_},function:{value:Rf.assert.function_},null:{value:Rf.assert.null_}});Rf.default=Se;KS.exports=Se;KS.exports.default=Se;KS.exports.assert=Rf.assert});var Jse=_((cNt,BM)=>{\"use strict\";var zS=class extends Error{constructor(e){super(e||\"Promise was canceled\"),this.name=\"CancelError\"}get isCanceled(){return!0}},IE=class{static fn(e){return(...r)=>new IE((o,a,n)=>{r.push(n),e(...r).then(o,a)})}constructor(e){this._cancelHandlers=[],this._isPending=!0,this._isCanceled=!1,this._rejectOnCancel=!0,this._promise=new Promise((r,o)=>{this._reject=o;let a=A=>{this._isPending=!1,r(A)},n=A=>{this._isPending=!1,o(A)},u=A=>{if(!this._isPending)throw new Error(\"The `onCancel` handler was attached after the promise settled.\");this._cancelHandlers.push(A)};return Object.defineProperties(u,{shouldReject:{get:()=>this._rejectOnCancel,set:A=>{this._rejectOnCancel=A}}}),e(a,n,u)})}then(e,r){return this._promise.then(e,r)}catch(e){return this._promise.catch(e)}finally(e){return this._promise.finally(e)}cancel(e){if(!(!this._isPending||this._isCanceled)){if(this._cancelHandlers.length>0)try{for(let r of this._cancelHandlers)r()}catch(r){this._reject(r)}this._isCanceled=!0,this._rejectOnCancel&&this._reject(new zS(e))}}get isCanceled(){return this._isCanceled}};Object.setPrototypeOf(IE.prototype,Promise.prototype);BM.exports=IE;BM.exports.CancelError=zS});var Xse=_((DM,PM)=>{\"use strict\";Object.defineProperty(DM,\"__esModule\",{value:!0});function Wrt(t){return t.encrypted}var vM=(t,e)=>{let r;typeof e==\"function\"?r={connect:e}:r=e;let o=typeof r.connect==\"function\",a=typeof r.secureConnect==\"function\",n=typeof r.close==\"function\",u=()=>{o&&r.connect(),Wrt(t)&&a&&(t.authorized?r.secureConnect():t.authorizationError||t.once(\"secureConnect\",r.secureConnect)),n&&t.once(\"close\",r.close)};t.writable&&!t.connecting?u():t.connecting?t.once(\"connect\",u):t.destroyed&&n&&r.close(t._hadError)};DM.default=vM;PM.exports=vM;PM.exports.default=vM});var Zse=_((bM,xM)=>{\"use strict\";Object.defineProperty(bM,\"__esModule\",{value:!0});var Krt=Xse(),zrt=Number(process.versions.node.split(\".\")[0]),SM=t=>{let e={start:Date.now(),socket:void 0,lookup:void 0,connect:void 0,secureConnect:void 0,upload:void 0,response:void 0,end:void 0,error:void 0,abort:void 0,phases:{wait:void 0,dns:void 0,tcp:void 0,tls:void 0,request:void 0,firstByte:void 0,download:void 0,total:void 0}};t.timings=e;let r=u=>{let A=u.emit.bind(u);u.emit=(p,...h)=>(p===\"error\"&&(e.error=Date.now(),e.phases.total=e.error-e.start,u.emit=A),A(p,...h))};r(t),t.prependOnceListener(\"abort\",()=>{e.abort=Date.now(),(!e.response||zrt>=13)&&(e.phases.total=Date.now()-e.start)});let o=u=>{e.socket=Date.now(),e.phases.wait=e.socket-e.start;let A=()=>{e.lookup=Date.now(),e.phases.dns=e.lookup-e.socket};u.prependOnceListener(\"lookup\",A),Krt.default(u,{connect:()=>{e.connect=Date.now(),e.lookup===void 0&&(u.removeListener(\"lookup\",A),e.lookup=e.connect,e.phases.dns=e.lookup-e.socket),e.phases.tcp=e.connect-e.lookup},secureConnect:()=>{e.secureConnect=Date.now(),e.phases.tls=e.secureConnect-e.connect}})};t.socket?o(t.socket):t.prependOnceListener(\"socket\",o);let a=()=>{var u;e.upload=Date.now(),e.phases.request=e.upload-(u=e.secureConnect,u??e.connect)};return(()=>typeof t.writableFinished==\"boolean\"?t.writableFinished:t.finished&&t.outputSize===0&&(!t.socket||t.socket.writableLength===0))()?a():t.prependOnceListener(\"finish\",a),t.prependOnceListener(\"response\",u=>{e.response=Date.now(),e.phases.firstByte=e.response-e.upload,u.timings=e,r(u),u.prependOnceListener(\"end\",()=>{e.end=Date.now(),e.phases.download=e.end-e.response,e.phases.total=e.end-e.start})}),e};bM.default=SM;xM.exports=SM;xM.exports.default=SM});var soe=_((uNt,FM)=>{\"use strict\";var{V4MAPPED:Vrt,ADDRCONFIG:Jrt,ALL:ioe,promises:{Resolver:$se},lookup:Xrt}=ve(\"dns\"),{promisify:kM}=ve(\"util\"),Zrt=ve(\"os\"),BE=Symbol(\"cacheableLookupCreateConnection\"),QM=Symbol(\"cacheableLookupInstance\"),eoe=Symbol(\"expires\"),$rt=typeof ioe==\"number\",toe=t=>{if(!(t&&typeof t.createConnection==\"function\"))throw new Error(\"Expected an Agent instance as the first argument\")},ent=t=>{for(let e of t)e.family!==6&&(e.address=`::ffff:${e.address}`,e.family=6)},roe=()=>{let t=!1,e=!1;for(let r of Object.values(Zrt.networkInterfaces()))for(let o of r)if(!o.internal&&(o.family===\"IPv6\"?e=!0:t=!0,t&&e))return{has4:t,has6:e};return{has4:t,has6:e}},tnt=t=>Symbol.iterator in t,noe={ttl:!0},rnt={all:!0},VS=class{constructor({cache:e=new Map,maxTtl:r=1/0,fallbackDuration:o=3600,errorTtl:a=.15,resolver:n=new $se,lookup:u=Xrt}={}){if(this.maxTtl=r,this.errorTtl=a,this._cache=e,this._resolver=n,this._dnsLookup=kM(u),this._resolver instanceof $se?(this._resolve4=this._resolver.resolve4.bind(this._resolver),this._resolve6=this._resolver.resolve6.bind(this._resolver)):(this._resolve4=kM(this._resolver.resolve4.bind(this._resolver)),this._resolve6=kM(this._resolver.resolve6.bind(this._resolver))),this._iface=roe(),this._pending={},this._nextRemovalTime=!1,this._hostnamesToFallback=new Set,o<1)this._fallback=!1;else{this._fallback=!0;let A=setInterval(()=>{this._hostnamesToFallback.clear()},o*1e3);A.unref&&A.unref()}this.lookup=this.lookup.bind(this),this.lookupAsync=this.lookupAsync.bind(this)}set servers(e){this.clear(),this._resolver.setServers(e)}get servers(){return this._resolver.getServers()}lookup(e,r,o){if(typeof r==\"function\"?(o=r,r={}):typeof r==\"number\"&&(r={family:r}),!o)throw new Error(\"Callback must be a function.\");this.lookupAsync(e,r).then(a=>{r.all?o(null,a):o(null,a.address,a.family,a.expires,a.ttl)},o)}async lookupAsync(e,r={}){typeof r==\"number\"&&(r={family:r});let o=await this.query(e);if(r.family===6){let a=o.filter(n=>n.family===6);r.hints&Vrt&&($rt&&r.hints&ioe||a.length===0)?ent(o):o=a}else r.family===4&&(o=o.filter(a=>a.family===4));if(r.hints&Jrt){let{_iface:a}=this;o=o.filter(n=>n.family===6?a.has6:a.has4)}if(o.length===0){let a=new Error(`cacheableLookup ENOTFOUND ${e}`);throw a.code=\"ENOTFOUND\",a.hostname=e,a}return r.all?o:o[0]}async query(e){let r=await this._cache.get(e);if(!r){let o=this._pending[e];if(o)r=await o;else{let a=this.queryAndCache(e);this._pending[e]=a,r=await a}}return r=r.map(o=>({...o})),r}async _resolve(e){let r=async h=>{try{return await h}catch(E){if(E.code===\"ENODATA\"||E.code===\"ENOTFOUND\")return[];throw E}},[o,a]=await Promise.all([this._resolve4(e,noe),this._resolve6(e,noe)].map(h=>r(h))),n=0,u=0,A=0,p=Date.now();for(let h of o)h.family=4,h.expires=p+h.ttl*1e3,n=Math.max(n,h.ttl);for(let h of a)h.family=6,h.expires=p+h.ttl*1e3,u=Math.max(u,h.ttl);return o.length>0?a.length>0?A=Math.min(n,u):A=n:A=u,{entries:[...o,...a],cacheTtl:A}}async _lookup(e){try{return{entries:await this._dnsLookup(e,{all:!0}),cacheTtl:0}}catch{return{entries:[],cacheTtl:0}}}async _set(e,r,o){if(this.maxTtl>0&&o>0){o=Math.min(o,this.maxTtl)*1e3,r[eoe]=Date.now()+o;try{await this._cache.set(e,r,o)}catch(a){this.lookupAsync=async()=>{let n=new Error(\"Cache Error. Please recreate the CacheableLookup instance.\");throw n.cause=a,n}}tnt(this._cache)&&this._tick(o)}}async queryAndCache(e){if(this._hostnamesToFallback.has(e))return this._dnsLookup(e,rnt);try{let r=await this._resolve(e);r.entries.length===0&&this._fallback&&(r=await this._lookup(e),r.entries.length!==0&&this._hostnamesToFallback.add(e));let o=r.entries.length===0?this.errorTtl:r.cacheTtl;return await this._set(e,r.entries,o),delete this._pending[e],r.entries}catch(r){throw delete this._pending[e],r}}_tick(e){let r=this._nextRemovalTime;(!r||e<r)&&(clearTimeout(this._removalTimeout),this._nextRemovalTime=e,this._removalTimeout=setTimeout(()=>{this._nextRemovalTime=!1;let o=1/0,a=Date.now();for(let[n,u]of this._cache){let A=u[eoe];a>=A?this._cache.delete(n):A<o&&(o=A)}o!==1/0&&this._tick(o-a)},e),this._removalTimeout.unref&&this._removalTimeout.unref())}install(e){if(toe(e),BE in e)throw new Error(\"CacheableLookup has been already installed\");e[BE]=e.createConnection,e[QM]=this,e.createConnection=(r,o)=>(\"lookup\"in r||(r.lookup=this.lookup),e[BE](r,o))}uninstall(e){if(toe(e),e[BE]){if(e[QM]!==this)throw new Error(\"The agent is not owned by this CacheableLookup instance\");e.createConnection=e[BE],delete e[BE],delete e[QM]}}updateInterfaceInfo(){let{_iface:e}=this;this._iface=roe(),(e.has4&&!this._iface.has4||e.has6&&!this._iface.has6)&&this._cache.clear()}clear(e){if(e){this._cache.delete(e);return}this._cache.clear()}};FM.exports=VS;FM.exports.default=VS});var loe=_((ANt,RM)=>{\"use strict\";var nnt=typeof URL>\"u\"?ve(\"url\").URL:URL,int=\"text/plain\",snt=\"us-ascii\",ooe=(t,e)=>e.some(r=>r instanceof RegExp?r.test(t):r===t),ont=(t,{stripHash:e})=>{let r=t.match(/^data:([^,]*?),([^#]*?)(?:#(.*))?$/);if(!r)throw new Error(`Invalid URL: ${t}`);let o=r[1].split(\";\"),a=r[2],n=e?\"\":r[3],u=!1;o[o.length-1]===\"base64\"&&(o.pop(),u=!0);let A=(o.shift()||\"\").toLowerCase(),h=[...o.map(E=>{let[I,v=\"\"]=E.split(\"=\").map(x=>x.trim());return I===\"charset\"&&(v=v.toLowerCase(),v===snt)?\"\":`${I}${v?`=${v}`:\"\"}`}).filter(Boolean)];return u&&h.push(\"base64\"),(h.length!==0||A&&A!==int)&&h.unshift(A),`data:${h.join(\";\")},${u?a.trim():a}${n?`#${n}`:\"\"}`},aoe=(t,e)=>{if(e={defaultProtocol:\"http:\",normalizeProtocol:!0,forceHttp:!1,forceHttps:!1,stripAuthentication:!0,stripHash:!1,stripWWW:!0,removeQueryParameters:[/^utm_\\w+/i],removeTrailingSlash:!0,removeDirectoryIndex:!1,sortQueryParameters:!0,...e},Reflect.has(e,\"normalizeHttps\"))throw new Error(\"options.normalizeHttps is renamed to options.forceHttp\");if(Reflect.has(e,\"normalizeHttp\"))throw new Error(\"options.normalizeHttp is renamed to options.forceHttps\");if(Reflect.has(e,\"stripFragment\"))throw new Error(\"options.stripFragment is renamed to options.stripHash\");if(t=t.trim(),/^data:/i.test(t))return ont(t,e);let r=t.startsWith(\"//\");!r&&/^\\.*\\//.test(t)||(t=t.replace(/^(?!(?:\\w+:)?\\/\\/)|^\\/\\//,e.defaultProtocol));let a=new nnt(t);if(e.forceHttp&&e.forceHttps)throw new Error(\"The `forceHttp` and `forceHttps` options cannot be used together\");if(e.forceHttp&&a.protocol===\"https:\"&&(a.protocol=\"http:\"),e.forceHttps&&a.protocol===\"http:\"&&(a.protocol=\"https:\"),e.stripAuthentication&&(a.username=\"\",a.password=\"\"),e.stripHash&&(a.hash=\"\"),a.pathname&&(a.pathname=a.pathname.replace(/((?!:).|^)\\/{2,}/g,(n,u)=>/^(?!\\/)/g.test(u)?`${u}/`:\"/\")),a.pathname&&(a.pathname=decodeURI(a.pathname)),e.removeDirectoryIndex===!0&&(e.removeDirectoryIndex=[/^index\\.[a-z]+$/]),Array.isArray(e.removeDirectoryIndex)&&e.removeDirectoryIndex.length>0){let n=a.pathname.split(\"/\"),u=n[n.length-1];ooe(u,e.removeDirectoryIndex)&&(n=n.slice(0,n.length-1),a.pathname=n.slice(1).join(\"/\")+\"/\")}if(a.hostname&&(a.hostname=a.hostname.replace(/\\.$/,\"\"),e.stripWWW&&/^www\\.([a-z\\-\\d]{2,63})\\.([a-z.]{2,5})$/.test(a.hostname)&&(a.hostname=a.hostname.replace(/^www\\./,\"\"))),Array.isArray(e.removeQueryParameters))for(let n of[...a.searchParams.keys()])ooe(n,e.removeQueryParameters)&&a.searchParams.delete(n);return e.sortQueryParameters&&a.searchParams.sort(),e.removeTrailingSlash&&(a.pathname=a.pathname.replace(/\\/$/,\"\")),t=a.toString(),(e.removeTrailingSlash||a.pathname===\"/\")&&a.hash===\"\"&&(t=t.replace(/\\/$/,\"\")),r&&!e.normalizeProtocol&&(t=t.replace(/^http:\\/\\//,\"//\")),e.stripProtocol&&(t=t.replace(/^(?:https?:)?\\/\\//,\"\")),t};RM.exports=aoe;RM.exports.default=aoe});var Aoe=_((fNt,uoe)=>{uoe.exports=coe;function coe(t,e){if(t&&e)return coe(t)(e);if(typeof t!=\"function\")throw new TypeError(\"need wrapper function\");return Object.keys(t).forEach(function(o){r[o]=t[o]}),r;function r(){for(var o=new Array(arguments.length),a=0;a<o.length;a++)o[a]=arguments[a];var n=t.apply(this,o),u=o[o.length-1];return typeof n==\"function\"&&n!==u&&Object.keys(u).forEach(function(A){n[A]=u[A]}),n}}});var LM=_((pNt,TM)=>{var foe=Aoe();TM.exports=foe(JS);TM.exports.strict=foe(poe);JS.proto=JS(function(){Object.defineProperty(Function.prototype,\"once\",{value:function(){return JS(this)},configurable:!0}),Object.defineProperty(Function.prototype,\"onceStrict\",{value:function(){return poe(this)},configurable:!0})});function JS(t){var e=function(){return e.called?e.value:(e.called=!0,e.value=t.apply(this,arguments))};return e.called=!1,e}function poe(t){var e=function(){if(e.called)throw new Error(e.onceError);return e.called=!0,e.value=t.apply(this,arguments)},r=t.name||\"Function wrapped with `once`\";return e.onceError=r+\" shouldn't be called more than once\",e.called=!1,e}});var NM=_((hNt,goe)=>{var ant=LM(),lnt=function(){},cnt=function(t){return t.setHeader&&typeof t.abort==\"function\"},unt=function(t){return t.stdio&&Array.isArray(t.stdio)&&t.stdio.length===3},hoe=function(t,e,r){if(typeof e==\"function\")return hoe(t,null,e);e||(e={}),r=ant(r||lnt);var o=t._writableState,a=t._readableState,n=e.readable||e.readable!==!1&&t.readable,u=e.writable||e.writable!==!1&&t.writable,A=function(){t.writable||p()},p=function(){u=!1,n||r.call(t)},h=function(){n=!1,u||r.call(t)},E=function(C){r.call(t,C?new Error(\"exited with error code: \"+C):null)},I=function(C){r.call(t,C)},v=function(){if(n&&!(a&&a.ended))return r.call(t,new Error(\"premature close\"));if(u&&!(o&&o.ended))return r.call(t,new Error(\"premature close\"))},x=function(){t.req.on(\"finish\",p)};return cnt(t)?(t.on(\"complete\",p),t.on(\"abort\",v),t.req?x():t.on(\"request\",x)):u&&!o&&(t.on(\"end\",A),t.on(\"close\",A)),unt(t)&&t.on(\"exit\",E),t.on(\"end\",h),t.on(\"finish\",p),e.error!==!1&&t.on(\"error\",I),t.on(\"close\",v),function(){t.removeListener(\"complete\",p),t.removeListener(\"abort\",v),t.removeListener(\"request\",x),t.req&&t.req.removeListener(\"finish\",p),t.removeListener(\"end\",A),t.removeListener(\"close\",A),t.removeListener(\"finish\",p),t.removeListener(\"exit\",E),t.removeListener(\"end\",h),t.removeListener(\"error\",I),t.removeListener(\"close\",v)}};goe.exports=hoe});var yoe=_((gNt,moe)=>{var Ant=LM(),fnt=NM(),OM=ve(\"fs\"),p1=function(){},pnt=/^v?\\.0/.test(process.version),XS=function(t){return typeof t==\"function\"},hnt=function(t){return!pnt||!OM?!1:(t instanceof(OM.ReadStream||p1)||t instanceof(OM.WriteStream||p1))&&XS(t.close)},gnt=function(t){return t.setHeader&&XS(t.abort)},dnt=function(t,e,r,o){o=Ant(o);var a=!1;t.on(\"close\",function(){a=!0}),fnt(t,{readable:e,writable:r},function(u){if(u)return o(u);a=!0,o()});var n=!1;return function(u){if(!a&&!n){if(n=!0,hnt(t))return t.close(p1);if(gnt(t))return t.abort();if(XS(t.destroy))return t.destroy();o(u||new Error(\"stream was destroyed\"))}}},doe=function(t){t()},mnt=function(t,e){return t.pipe(e)},ynt=function(){var t=Array.prototype.slice.call(arguments),e=XS(t[t.length-1]||p1)&&t.pop()||p1;if(Array.isArray(t[0])&&(t=t[0]),t.length<2)throw new Error(\"pump requires two streams per minimum\");var r,o=t.map(function(a,n){var u=n<t.length-1,A=n>0;return dnt(a,u,A,function(p){r||(r=p),p&&o.forEach(doe),!u&&(o.forEach(doe),e(r))})});return t.reduce(mnt)};moe.exports=ynt});var Coe=_((dNt,Eoe)=>{\"use strict\";var{PassThrough:Ent}=ve(\"stream\");Eoe.exports=t=>{t={...t};let{array:e}=t,{encoding:r}=t,o=r===\"buffer\",a=!1;e?a=!(r||o):r=r||\"utf8\",o&&(r=null);let n=new Ent({objectMode:a});r&&n.setEncoding(r);let u=0,A=[];return n.on(\"data\",p=>{A.push(p),a?u=A.length:u+=p.length}),n.getBufferedValue=()=>e?A:o?Buffer.concat(A,u):A.join(\"\"),n.getBufferedLength=()=>u,n}});var woe=_((mNt,vE)=>{\"use strict\";var Cnt=yoe(),wnt=Coe(),ZS=class extends Error{constructor(){super(\"maxBuffer exceeded\"),this.name=\"MaxBufferError\"}};async function $S(t,e){if(!t)return Promise.reject(new Error(\"Expected a stream\"));e={maxBuffer:1/0,...e};let{maxBuffer:r}=e,o;return await new Promise((a,n)=>{let u=A=>{A&&(A.bufferedData=o.getBufferedValue()),n(A)};o=Cnt(t,wnt(e),A=>{if(A){u(A);return}a()}),o.on(\"data\",()=>{o.getBufferedLength()>r&&u(new ZS)})}),o.getBufferedValue()}vE.exports=$S;vE.exports.default=$S;vE.exports.buffer=(t,e)=>$S(t,{...e,encoding:\"buffer\"});vE.exports.array=(t,e)=>$S(t,{...e,array:!0});vE.exports.MaxBufferError=ZS});var Boe=_((ENt,Ioe)=>{\"use strict\";var Int=new Set([200,203,204,206,300,301,308,404,405,410,414,501]),Bnt=new Set([200,203,204,300,301,302,303,307,308,404,405,410,414,501]),vnt=new Set([500,502,503,504]),Dnt={date:!0,connection:!0,\"keep-alive\":!0,\"proxy-authenticate\":!0,\"proxy-authorization\":!0,te:!0,trailer:!0,\"transfer-encoding\":!0,upgrade:!0},Pnt={\"content-length\":!0,\"content-encoding\":!0,\"transfer-encoding\":!0,\"content-range\":!0};function Sd(t){let e=parseInt(t,10);return isFinite(e)?e:0}function Snt(t){return t?vnt.has(t.status):!0}function MM(t){let e={};if(!t)return e;let r=t.trim().split(/,/);for(let o of r){let[a,n]=o.split(/=/,2);e[a.trim()]=n===void 0?!0:n.trim().replace(/^\"|\"$/g,\"\")}return e}function bnt(t){let e=[];for(let r in t){let o=t[r];e.push(o===!0?r:r+\"=\"+o)}if(!!e.length)return e.join(\", \")}Ioe.exports=class{constructor(e,r,{shared:o,cacheHeuristic:a,immutableMinTimeToLive:n,ignoreCargoCult:u,_fromObject:A}={}){if(A){this._fromObject(A);return}if(!r||!r.headers)throw Error(\"Response headers missing\");this._assertRequestHasHeaders(e),this._responseTime=this.now(),this._isShared=o!==!1,this._cacheHeuristic=a!==void 0?a:.1,this._immutableMinTtl=n!==void 0?n:24*3600*1e3,this._status=\"status\"in r?r.status:200,this._resHeaders=r.headers,this._rescc=MM(r.headers[\"cache-control\"]),this._method=\"method\"in e?e.method:\"GET\",this._url=e.url,this._host=e.headers.host,this._noAuthorization=!e.headers.authorization,this._reqHeaders=r.headers.vary?e.headers:null,this._reqcc=MM(e.headers[\"cache-control\"]),u&&\"pre-check\"in this._rescc&&\"post-check\"in this._rescc&&(delete this._rescc[\"pre-check\"],delete this._rescc[\"post-check\"],delete this._rescc[\"no-cache\"],delete this._rescc[\"no-store\"],delete this._rescc[\"must-revalidate\"],this._resHeaders=Object.assign({},this._resHeaders,{\"cache-control\":bnt(this._rescc)}),delete this._resHeaders.expires,delete this._resHeaders.pragma),r.headers[\"cache-control\"]==null&&/no-cache/.test(r.headers.pragma)&&(this._rescc[\"no-cache\"]=!0)}now(){return Date.now()}storable(){return!!(!this._reqcc[\"no-store\"]&&(this._method===\"GET\"||this._method===\"HEAD\"||this._method===\"POST\"&&this._hasExplicitExpiration())&&Bnt.has(this._status)&&!this._rescc[\"no-store\"]&&(!this._isShared||!this._rescc.private)&&(!this._isShared||this._noAuthorization||this._allowsStoringAuthenticated())&&(this._resHeaders.expires||this._rescc[\"max-age\"]||this._isShared&&this._rescc[\"s-maxage\"]||this._rescc.public||Int.has(this._status)))}_hasExplicitExpiration(){return this._isShared&&this._rescc[\"s-maxage\"]||this._rescc[\"max-age\"]||this._resHeaders.expires}_assertRequestHasHeaders(e){if(!e||!e.headers)throw Error(\"Request headers missing\")}satisfiesWithoutRevalidation(e){this._assertRequestHasHeaders(e);let r=MM(e.headers[\"cache-control\"]);return r[\"no-cache\"]||/no-cache/.test(e.headers.pragma)||r[\"max-age\"]&&this.age()>r[\"max-age\"]||r[\"min-fresh\"]&&this.timeToLive()<1e3*r[\"min-fresh\"]||this.stale()&&!(r[\"max-stale\"]&&!this._rescc[\"must-revalidate\"]&&(r[\"max-stale\"]===!0||r[\"max-stale\"]>this.age()-this.maxAge()))?!1:this._requestMatches(e,!1)}_requestMatches(e,r){return(!this._url||this._url===e.url)&&this._host===e.headers.host&&(!e.method||this._method===e.method||r&&e.method===\"HEAD\")&&this._varyMatches(e)}_allowsStoringAuthenticated(){return this._rescc[\"must-revalidate\"]||this._rescc.public||this._rescc[\"s-maxage\"]}_varyMatches(e){if(!this._resHeaders.vary)return!0;if(this._resHeaders.vary===\"*\")return!1;let r=this._resHeaders.vary.trim().toLowerCase().split(/\\s*,\\s*/);for(let o of r)if(e.headers[o]!==this._reqHeaders[o])return!1;return!0}_copyWithoutHopByHopHeaders(e){let r={};for(let o in e)Dnt[o]||(r[o]=e[o]);if(e.connection){let o=e.connection.trim().split(/\\s*,\\s*/);for(let a of o)delete r[a]}if(r.warning){let o=r.warning.split(/,/).filter(a=>!/^\\s*1[0-9][0-9]/.test(a));o.length?r.warning=o.join(\",\").trim():delete r.warning}return r}responseHeaders(){let e=this._copyWithoutHopByHopHeaders(this._resHeaders),r=this.age();return r>3600*24&&!this._hasExplicitExpiration()&&this.maxAge()>3600*24&&(e.warning=(e.warning?`${e.warning}, `:\"\")+'113 - \"rfc7234 5.5.4\"'),e.age=`${Math.round(r)}`,e.date=new Date(this.now()).toUTCString(),e}date(){let e=Date.parse(this._resHeaders.date);return isFinite(e)?e:this._responseTime}age(){let e=this._ageValue(),r=(this.now()-this._responseTime)/1e3;return e+r}_ageValue(){return Sd(this._resHeaders.age)}maxAge(){if(!this.storable()||this._rescc[\"no-cache\"]||this._isShared&&this._resHeaders[\"set-cookie\"]&&!this._rescc.public&&!this._rescc.immutable||this._resHeaders.vary===\"*\")return 0;if(this._isShared){if(this._rescc[\"proxy-revalidate\"])return 0;if(this._rescc[\"s-maxage\"])return Sd(this._rescc[\"s-maxage\"])}if(this._rescc[\"max-age\"])return Sd(this._rescc[\"max-age\"]);let e=this._rescc.immutable?this._immutableMinTtl:0,r=this.date();if(this._resHeaders.expires){let o=Date.parse(this._resHeaders.expires);return Number.isNaN(o)||o<r?0:Math.max(e,(o-r)/1e3)}if(this._resHeaders[\"last-modified\"]){let o=Date.parse(this._resHeaders[\"last-modified\"]);if(isFinite(o)&&r>o)return Math.max(e,(r-o)/1e3*this._cacheHeuristic)}return e}timeToLive(){let e=this.maxAge()-this.age(),r=e+Sd(this._rescc[\"stale-if-error\"]),o=e+Sd(this._rescc[\"stale-while-revalidate\"]);return Math.max(0,e,r,o)*1e3}stale(){return this.maxAge()<=this.age()}_useStaleIfError(){return this.maxAge()+Sd(this._rescc[\"stale-if-error\"])>this.age()}useStaleWhileRevalidate(){return this.maxAge()+Sd(this._rescc[\"stale-while-revalidate\"])>this.age()}static fromObject(e){return new this(void 0,void 0,{_fromObject:e})}_fromObject(e){if(this._responseTime)throw Error(\"Reinitialized\");if(!e||e.v!==1)throw Error(\"Invalid serialization\");this._responseTime=e.t,this._isShared=e.sh,this._cacheHeuristic=e.ch,this._immutableMinTtl=e.imm!==void 0?e.imm:24*3600*1e3,this._status=e.st,this._resHeaders=e.resh,this._rescc=e.rescc,this._method=e.m,this._url=e.u,this._host=e.h,this._noAuthorization=e.a,this._reqHeaders=e.reqh,this._reqcc=e.reqcc}toObject(){return{v:1,t:this._responseTime,sh:this._isShared,ch:this._cacheHeuristic,imm:this._immutableMinTtl,st:this._status,resh:this._resHeaders,rescc:this._rescc,m:this._method,u:this._url,h:this._host,a:this._noAuthorization,reqh:this._reqHeaders,reqcc:this._reqcc}}revalidationHeaders(e){this._assertRequestHasHeaders(e);let r=this._copyWithoutHopByHopHeaders(e.headers);if(delete r[\"if-range\"],!this._requestMatches(e,!0)||!this.storable())return delete r[\"if-none-match\"],delete r[\"if-modified-since\"],r;if(this._resHeaders.etag&&(r[\"if-none-match\"]=r[\"if-none-match\"]?`${r[\"if-none-match\"]}, ${this._resHeaders.etag}`:this._resHeaders.etag),r[\"accept-ranges\"]||r[\"if-match\"]||r[\"if-unmodified-since\"]||this._method&&this._method!=\"GET\"){if(delete r[\"if-modified-since\"],r[\"if-none-match\"]){let a=r[\"if-none-match\"].split(/,/).filter(n=>!/^\\s*W\\//.test(n));a.length?r[\"if-none-match\"]=a.join(\",\").trim():delete r[\"if-none-match\"]}}else this._resHeaders[\"last-modified\"]&&!r[\"if-modified-since\"]&&(r[\"if-modified-since\"]=this._resHeaders[\"last-modified\"]);return r}revalidatedPolicy(e,r){if(this._assertRequestHasHeaders(e),this._useStaleIfError()&&Snt(r))return{modified:!1,matches:!1,policy:this};if(!r||!r.headers)throw Error(\"Response headers missing\");let o=!1;if(r.status!==void 0&&r.status!=304?o=!1:r.headers.etag&&!/^\\s*W\\//.test(r.headers.etag)?o=this._resHeaders.etag&&this._resHeaders.etag.replace(/^\\s*W\\//,\"\")===r.headers.etag:this._resHeaders.etag&&r.headers.etag?o=this._resHeaders.etag.replace(/^\\s*W\\//,\"\")===r.headers.etag.replace(/^\\s*W\\//,\"\"):this._resHeaders[\"last-modified\"]?o=this._resHeaders[\"last-modified\"]===r.headers[\"last-modified\"]:!this._resHeaders.etag&&!this._resHeaders[\"last-modified\"]&&!r.headers.etag&&!r.headers[\"last-modified\"]&&(o=!0),!o)return{policy:new this.constructor(e,r),modified:r.status!=304,matches:!1};let a={};for(let u in this._resHeaders)a[u]=u in r.headers&&!Pnt[u]?r.headers[u]:this._resHeaders[u];let n=Object.assign({},r,{status:this._status,method:this._method,headers:a});return{policy:new this.constructor(e,n,{shared:this._isShared,cacheHeuristic:this._cacheHeuristic,immutableMinTimeToLive:this._immutableMinTtl}),modified:!1,matches:!0}}}});var eb=_((CNt,voe)=>{\"use strict\";voe.exports=t=>{let e={};for(let[r,o]of Object.entries(t))e[r.toLowerCase()]=o;return e}});var Poe=_((wNt,Doe)=>{\"use strict\";var xnt=ve(\"stream\").Readable,knt=eb(),UM=class extends xnt{constructor(e,r,o,a){if(typeof e!=\"number\")throw new TypeError(\"Argument `statusCode` should be a number\");if(typeof r!=\"object\")throw new TypeError(\"Argument `headers` should be an object\");if(!(o instanceof Buffer))throw new TypeError(\"Argument `body` should be a buffer\");if(typeof a!=\"string\")throw new TypeError(\"Argument `url` should be a string\");super(),this.statusCode=e,this.headers=knt(r),this.body=o,this.url=a}_read(){this.push(this.body),this.push(null)}};Doe.exports=UM});var boe=_((INt,Soe)=>{\"use strict\";var Qnt=[\"destroy\",\"setTimeout\",\"socket\",\"headers\",\"trailers\",\"rawHeaders\",\"statusCode\",\"httpVersion\",\"httpVersionMinor\",\"httpVersionMajor\",\"rawTrailers\",\"statusMessage\"];Soe.exports=(t,e)=>{let r=new Set(Object.keys(t).concat(Qnt));for(let o of r)o in e||(e[o]=typeof t[o]==\"function\"?t[o].bind(t):t[o])}});var koe=_((BNt,xoe)=>{\"use strict\";var Fnt=ve(\"stream\").PassThrough,Rnt=boe(),Tnt=t=>{if(!(t&&t.pipe))throw new TypeError(\"Parameter `response` must be a response stream.\");let e=new Fnt;return Rnt(t,e),t.pipe(e)};xoe.exports=Tnt});var Qoe=_(_M=>{_M.stringify=function t(e){if(typeof e>\"u\")return e;if(e&&Buffer.isBuffer(e))return JSON.stringify(\":base64:\"+e.toString(\"base64\"));if(e&&e.toJSON&&(e=e.toJSON()),e&&typeof e==\"object\"){var r=\"\",o=Array.isArray(e);r=o?\"[\":\"{\";var a=!0;for(var n in e){var u=typeof e[n]==\"function\"||!o&&typeof e[n]>\"u\";Object.hasOwnProperty.call(e,n)&&!u&&(a||(r+=\",\"),a=!1,o?e[n]==null?r+=\"null\":r+=t(e[n]):e[n]!==void 0&&(r+=t(n)+\":\"+t(e[n])))}return r+=o?\"]\":\"}\",r}else return typeof e==\"string\"?JSON.stringify(/^:/.test(e)?\":\"+e:e):typeof e>\"u\"?\"null\":JSON.stringify(e)};_M.parse=function(t){return JSON.parse(t,function(e,r){return typeof r==\"string\"?/^:base64:/.test(r)?Buffer.from(r.substring(8),\"base64\"):/^:/.test(r)?r.substring(1):r:r})}});var Loe=_((DNt,Toe)=>{\"use strict\";var Lnt=ve(\"events\"),Foe=Qoe(),Nnt=t=>{let e={redis:\"@keyv/redis\",rediss:\"@keyv/redis\",mongodb:\"@keyv/mongo\",mongo:\"@keyv/mongo\",sqlite:\"@keyv/sqlite\",postgresql:\"@keyv/postgres\",postgres:\"@keyv/postgres\",mysql:\"@keyv/mysql\",etcd:\"@keyv/etcd\",offline:\"@keyv/offline\",tiered:\"@keyv/tiered\"};if(t.adapter||t.uri){let r=t.adapter||/^[^:+]*/.exec(t.uri)[0];return new(ve(e[r]))(t)}return new Map},Roe=[\"sqlite\",\"postgres\",\"mysql\",\"mongo\",\"redis\",\"tiered\"],HM=class extends Lnt{constructor(e,{emitErrors:r=!0,...o}={}){if(super(),this.opts={namespace:\"keyv\",serialize:Foe.stringify,deserialize:Foe.parse,...typeof e==\"string\"?{uri:e}:e,...o},!this.opts.store){let n={...this.opts};this.opts.store=Nnt(n)}if(this.opts.compression){let n=this.opts.compression;this.opts.serialize=n.serialize.bind(n),this.opts.deserialize=n.deserialize.bind(n)}typeof this.opts.store.on==\"function\"&&r&&this.opts.store.on(\"error\",n=>this.emit(\"error\",n)),this.opts.store.namespace=this.opts.namespace;let a=n=>async function*(){for await(let[u,A]of typeof n==\"function\"?n(this.opts.store.namespace):n){let p=await this.opts.deserialize(A);if(!(this.opts.store.namespace&&!u.includes(this.opts.store.namespace))){if(typeof p.expires==\"number\"&&Date.now()>p.expires){this.delete(u);continue}yield[this._getKeyUnprefix(u),p.value]}}};typeof this.opts.store[Symbol.iterator]==\"function\"&&this.opts.store instanceof Map?this.iterator=a(this.opts.store):typeof this.opts.store.iterator==\"function\"&&this.opts.store.opts&&this._checkIterableAdaptar()&&(this.iterator=a(this.opts.store.iterator.bind(this.opts.store)))}_checkIterableAdaptar(){return Roe.includes(this.opts.store.opts.dialect)||Roe.findIndex(e=>this.opts.store.opts.url.includes(e))>=0}_getKeyPrefix(e){return`${this.opts.namespace}:${e}`}_getKeyPrefixArray(e){return e.map(r=>`${this.opts.namespace}:${r}`)}_getKeyUnprefix(e){return e.split(\":\").splice(1).join(\":\")}get(e,r){let{store:o}=this.opts,a=Array.isArray(e),n=a?this._getKeyPrefixArray(e):this._getKeyPrefix(e);if(a&&o.getMany===void 0){let u=[];for(let A of n)u.push(Promise.resolve().then(()=>o.get(A)).then(p=>typeof p==\"string\"?this.opts.deserialize(p):this.opts.compression?this.opts.deserialize(p):p).then(p=>{if(p!=null)return typeof p.expires==\"number\"&&Date.now()>p.expires?this.delete(A).then(()=>{}):r&&r.raw?p:p.value}));return Promise.allSettled(u).then(A=>{let p=[];for(let h of A)p.push(h.value);return p})}return Promise.resolve().then(()=>a?o.getMany(n):o.get(n)).then(u=>typeof u==\"string\"?this.opts.deserialize(u):this.opts.compression?this.opts.deserialize(u):u).then(u=>{if(u!=null)return a?u.map((A,p)=>{if(typeof A==\"string\"&&(A=this.opts.deserialize(A)),A!=null){if(typeof A.expires==\"number\"&&Date.now()>A.expires){this.delete(e[p]).then(()=>{});return}return r&&r.raw?A:A.value}}):typeof u.expires==\"number\"&&Date.now()>u.expires?this.delete(e).then(()=>{}):r&&r.raw?u:u.value})}set(e,r,o){let a=this._getKeyPrefix(e);typeof o>\"u\"&&(o=this.opts.ttl),o===0&&(o=void 0);let{store:n}=this.opts;return Promise.resolve().then(()=>{let u=typeof o==\"number\"?Date.now()+o:null;return typeof r==\"symbol\"&&this.emit(\"error\",\"symbol cannot be serialized\"),r={value:r,expires:u},this.opts.serialize(r)}).then(u=>n.set(a,u,o)).then(()=>!0)}delete(e){let{store:r}=this.opts;if(Array.isArray(e)){let a=this._getKeyPrefixArray(e);if(r.deleteMany===void 0){let n=[];for(let u of a)n.push(r.delete(u));return Promise.allSettled(n).then(u=>u.every(A=>A.value===!0))}return Promise.resolve().then(()=>r.deleteMany(a))}let o=this._getKeyPrefix(e);return Promise.resolve().then(()=>r.delete(o))}clear(){let{store:e}=this.opts;return Promise.resolve().then(()=>e.clear())}has(e){let r=this._getKeyPrefix(e),{store:o}=this.opts;return Promise.resolve().then(async()=>typeof o.has==\"function\"?o.has(r):await o.get(r)!==void 0)}disconnect(){let{store:e}=this.opts;if(typeof e.disconnect==\"function\")return e.disconnect()}};Toe.exports=HM});var Moe=_((SNt,Ooe)=>{\"use strict\";var Ont=ve(\"events\"),tb=ve(\"url\"),Mnt=loe(),Unt=woe(),qM=Boe(),Noe=Poe(),_nt=eb(),Hnt=koe(),qnt=Loe(),Gc=class{constructor(e,r){if(typeof e!=\"function\")throw new TypeError(\"Parameter `request` must be a function\");return this.cache=new qnt({uri:typeof r==\"string\"&&r,store:typeof r!=\"string\"&&r,namespace:\"cacheable-request\"}),this.createCacheableRequest(e)}createCacheableRequest(e){return(r,o)=>{let a;if(typeof r==\"string\")a=GM(tb.parse(r)),r={};else if(r instanceof tb.URL)a=GM(tb.parse(r.toString())),r={};else{let[I,...v]=(r.path||\"\").split(\"?\"),x=v.length>0?`?${v.join(\"?\")}`:\"\";a=GM({...r,pathname:I,search:x})}r={headers:{},method:\"GET\",cache:!0,strictTtl:!1,automaticFailover:!1,...r,...Gnt(a)},r.headers=_nt(r.headers);let n=new Ont,u=Mnt(tb.format(a),{stripWWW:!1,removeTrailingSlash:!1,stripAuthentication:!1}),A=`${r.method}:${u}`,p=!1,h=!1,E=I=>{h=!0;let v=!1,x,C=new Promise(N=>{x=()=>{v||(v=!0,N())}}),R=N=>{if(p&&!I.forceRefresh){N.status=N.statusCode;let V=qM.fromObject(p.cachePolicy).revalidatedPolicy(I,N);if(!V.modified){let te=V.policy.responseHeaders();N=new Noe(p.statusCode,te,p.body,p.url),N.cachePolicy=V.policy,N.fromCache=!0}}N.fromCache||(N.cachePolicy=new qM(I,N,I),N.fromCache=!1);let U;I.cache&&N.cachePolicy.storable()?(U=Hnt(N),(async()=>{try{let V=Unt.buffer(N);if(await Promise.race([C,new Promise(ue=>N.once(\"end\",ue))]),v)return;let te=await V,ae={cachePolicy:N.cachePolicy.toObject(),url:N.url,statusCode:N.fromCache?p.statusCode:N.statusCode,body:te},fe=I.strictTtl?N.cachePolicy.timeToLive():void 0;I.maxTtl&&(fe=fe?Math.min(fe,I.maxTtl):I.maxTtl),await this.cache.set(A,ae,fe)}catch(V){n.emit(\"error\",new Gc.CacheError(V))}})()):I.cache&&p&&(async()=>{try{await this.cache.delete(A)}catch(V){n.emit(\"error\",new Gc.CacheError(V))}})(),n.emit(\"response\",U||N),typeof o==\"function\"&&o(U||N)};try{let N=e(I,R);N.once(\"error\",x),N.once(\"abort\",x),n.emit(\"request\",N)}catch(N){n.emit(\"error\",new Gc.RequestError(N))}};return(async()=>{let I=async x=>{await Promise.resolve();let C=x.cache?await this.cache.get(A):void 0;if(typeof C>\"u\")return E(x);let R=qM.fromObject(C.cachePolicy);if(R.satisfiesWithoutRevalidation(x)&&!x.forceRefresh){let N=R.responseHeaders(),U=new Noe(C.statusCode,N,C.body,C.url);U.cachePolicy=R,U.fromCache=!0,n.emit(\"response\",U),typeof o==\"function\"&&o(U)}else p=C,x.headers=R.revalidationHeaders(x),E(x)},v=x=>n.emit(\"error\",new Gc.CacheError(x));this.cache.once(\"error\",v),n.on(\"response\",()=>this.cache.removeListener(\"error\",v));try{await I(r)}catch(x){r.automaticFailover&&!h&&E(r),n.emit(\"error\",new Gc.CacheError(x))}})(),n}}};function Gnt(t){let e={...t};return e.path=`${t.pathname||\"/\"}${t.search||\"\"}`,delete e.pathname,delete e.search,e}function GM(t){return{protocol:t.protocol,auth:t.auth,hostname:t.hostname||t.host||\"localhost\",port:t.port,pathname:t.pathname,search:t.search}}Gc.RequestError=class extends Error{constructor(t){super(t.message),this.name=\"RequestError\",Object.assign(this,t)}};Gc.CacheError=class extends Error{constructor(t){super(t.message),this.name=\"CacheError\",Object.assign(this,t)}};Ooe.exports=Gc});var _oe=_((kNt,Uoe)=>{\"use strict\";var jnt=[\"aborted\",\"complete\",\"headers\",\"httpVersion\",\"httpVersionMinor\",\"httpVersionMajor\",\"method\",\"rawHeaders\",\"rawTrailers\",\"setTimeout\",\"socket\",\"statusCode\",\"statusMessage\",\"trailers\",\"url\"];Uoe.exports=(t,e)=>{if(e._readableState.autoDestroy)throw new Error(\"The second stream must have the `autoDestroy` option set to `false`\");let r=new Set(Object.keys(t).concat(jnt)),o={};for(let a of r)a in e||(o[a]={get(){let n=t[a];return typeof n==\"function\"?n.bind(t):n},set(n){t[a]=n},enumerable:!0,configurable:!1});return Object.defineProperties(e,o),t.once(\"aborted\",()=>{e.destroy(),e.emit(\"aborted\")}),t.once(\"close\",()=>{t.complete&&e.readable?e.once(\"end\",()=>{e.emit(\"close\")}):e.emit(\"close\")}),e}});var qoe=_((QNt,Hoe)=>{\"use strict\";var{Transform:Ynt,PassThrough:Wnt}=ve(\"stream\"),jM=ve(\"zlib\"),Knt=_oe();Hoe.exports=t=>{let e=(t.headers[\"content-encoding\"]||\"\").toLowerCase();if(![\"gzip\",\"deflate\",\"br\"].includes(e))return t;let r=e===\"br\";if(r&&typeof jM.createBrotliDecompress!=\"function\")return t.destroy(new Error(\"Brotli is not supported on Node.js < 12\")),t;let o=!0,a=new Ynt({transform(A,p,h){o=!1,h(null,A)},flush(A){A()}}),n=new Wnt({autoDestroy:!1,destroy(A,p){t.destroy(),p(A)}}),u=r?jM.createBrotliDecompress():jM.createUnzip();return u.once(\"error\",A=>{if(o&&!t.readable){n.end();return}n.destroy(A)}),Knt(t,n),t.pipe(a).pipe(u).pipe(n),n}});var WM=_((FNt,Goe)=>{\"use strict\";var YM=class{constructor(e={}){if(!(e.maxSize&&e.maxSize>0))throw new TypeError(\"`maxSize` must be a number greater than 0\");this.maxSize=e.maxSize,this.onEviction=e.onEviction,this.cache=new Map,this.oldCache=new Map,this._size=0}_set(e,r){if(this.cache.set(e,r),this._size++,this._size>=this.maxSize){if(this._size=0,typeof this.onEviction==\"function\")for(let[o,a]of this.oldCache.entries())this.onEviction(o,a);this.oldCache=this.cache,this.cache=new Map}}get(e){if(this.cache.has(e))return this.cache.get(e);if(this.oldCache.has(e)){let r=this.oldCache.get(e);return this.oldCache.delete(e),this._set(e,r),r}}set(e,r){return this.cache.has(e)?this.cache.set(e,r):this._set(e,r),this}has(e){return this.cache.has(e)||this.oldCache.has(e)}peek(e){if(this.cache.has(e))return this.cache.get(e);if(this.oldCache.has(e))return this.oldCache.get(e)}delete(e){let r=this.cache.delete(e);return r&&this._size--,this.oldCache.delete(e)||r}clear(){this.cache.clear(),this.oldCache.clear(),this._size=0}*keys(){for(let[e]of this)yield e}*values(){for(let[,e]of this)yield e}*[Symbol.iterator](){for(let e of this.cache)yield e;for(let e of this.oldCache){let[r]=e;this.cache.has(r)||(yield e)}}get size(){let e=0;for(let r of this.oldCache.keys())this.cache.has(r)||e++;return Math.min(this._size+e,this.maxSize)}};Goe.exports=YM});var zM=_((RNt,Koe)=>{\"use strict\";var znt=ve(\"events\"),Vnt=ve(\"tls\"),Jnt=ve(\"http2\"),Xnt=WM(),ea=Symbol(\"currentStreamsCount\"),joe=Symbol(\"request\"),Kl=Symbol(\"cachedOriginSet\"),DE=Symbol(\"gracefullyClosing\"),Znt=[\"maxDeflateDynamicTableSize\",\"maxSessionMemory\",\"maxHeaderListPairs\",\"maxOutstandingPings\",\"maxReservedRemoteStreams\",\"maxSendHeaderBlockLength\",\"paddingStrategy\",\"localAddress\",\"path\",\"rejectUnauthorized\",\"minDHSize\",\"ca\",\"cert\",\"clientCertEngine\",\"ciphers\",\"key\",\"pfx\",\"servername\",\"minVersion\",\"maxVersion\",\"secureProtocol\",\"crl\",\"honorCipherOrder\",\"ecdhCurve\",\"dhparam\",\"secureOptions\",\"sessionIdContext\"],$nt=(t,e,r)=>{let o=0,a=t.length;for(;o<a;){let n=o+a>>>1;r(t[n],e)?o=n+1:a=n}return o},eit=(t,e)=>t.remoteSettings.maxConcurrentStreams>e.remoteSettings.maxConcurrentStreams,KM=(t,e)=>{for(let r of t)r[Kl].length<e[Kl].length&&r[Kl].every(o=>e[Kl].includes(o))&&r[ea]+e[ea]<=e.remoteSettings.maxConcurrentStreams&&Woe(r)},tit=(t,e)=>{for(let r of t)e[Kl].length<r[Kl].length&&e[Kl].every(o=>r[Kl].includes(o))&&e[ea]+r[ea]<=r.remoteSettings.maxConcurrentStreams&&Woe(e)},Yoe=({agent:t,isFree:e})=>{let r={};for(let o in t.sessions){let n=t.sessions[o].filter(u=>{let A=u[rA.kCurrentStreamsCount]<u.remoteSettings.maxConcurrentStreams;return e?A:!A});n.length!==0&&(r[o]=n)}return r},Woe=t=>{t[DE]=!0,t[ea]===0&&t.close()},rA=class extends znt{constructor({timeout:e=6e4,maxSessions:r=1/0,maxFreeSessions:o=10,maxCachedTlsSessions:a=100}={}){super(),this.sessions={},this.queue={},this.timeout=e,this.maxSessions=r,this.maxFreeSessions=o,this._freeSessionsCount=0,this._sessionsCount=0,this.settings={enablePush:!1},this.tlsSessionCache=new Xnt({maxSize:a})}static normalizeOrigin(e,r){return typeof e==\"string\"&&(e=new URL(e)),r&&e.hostname!==r&&(e.hostname=r),e.origin}normalizeOptions(e){let r=\"\";if(e)for(let o of Znt)e[o]&&(r+=`:${e[o]}`);return r}_tryToCreateNewSession(e,r){if(!(e in this.queue)||!(r in this.queue[e]))return;let o=this.queue[e][r];this._sessionsCount<this.maxSessions&&!o.completed&&(o.completed=!0,o())}getSession(e,r,o){return new Promise((a,n)=>{Array.isArray(o)?(o=[...o],a()):o=[{resolve:a,reject:n}];let u=this.normalizeOptions(r),A=rA.normalizeOrigin(e,r&&r.servername);if(A===void 0){for(let{reject:E}of o)E(new TypeError(\"The `origin` argument needs to be a string or an URL object\"));return}if(u in this.sessions){let E=this.sessions[u],I=-1,v=-1,x;for(let C of E){let R=C.remoteSettings.maxConcurrentStreams;if(R<I)break;if(C[Kl].includes(A)){let N=C[ea];if(N>=R||C[DE]||C.destroyed)continue;x||(I=R),N>v&&(x=C,v=N)}}if(x){if(o.length!==1){for(let{reject:C}of o){let R=new Error(`Expected the length of listeners to be 1, got ${o.length}.\nPlease report this to https://github.com/szmarczak/http2-wrapper/`);C(R)}return}o[0].resolve(x);return}}if(u in this.queue){if(A in this.queue[u]){this.queue[u][A].listeners.push(...o),this._tryToCreateNewSession(u,A);return}}else this.queue[u]={};let p=()=>{u in this.queue&&this.queue[u][A]===h&&(delete this.queue[u][A],Object.keys(this.queue[u]).length===0&&delete this.queue[u])},h=()=>{let E=`${A}:${u}`,I=!1;try{let v=Jnt.connect(e,{createConnection:this.createConnection,settings:this.settings,session:this.tlsSessionCache.get(E),...r});v[ea]=0,v[DE]=!1;let x=()=>v[ea]<v.remoteSettings.maxConcurrentStreams,C=!0;v.socket.once(\"session\",N=>{this.tlsSessionCache.set(E,N)}),v.once(\"error\",N=>{for(let{reject:U}of o)U(N);this.tlsSessionCache.delete(E)}),v.setTimeout(this.timeout,()=>{v.destroy()}),v.once(\"close\",()=>{if(I){C&&this._freeSessionsCount--,this._sessionsCount--;let N=this.sessions[u];N.splice(N.indexOf(v),1),N.length===0&&delete this.sessions[u]}else{let N=new Error(\"Session closed without receiving a SETTINGS frame\");N.code=\"HTTP2WRAPPER_NOSETTINGS\";for(let{reject:U}of o)U(N);p()}this._tryToCreateNewSession(u,A)});let R=()=>{if(!(!(u in this.queue)||!x())){for(let N of v[Kl])if(N in this.queue[u]){let{listeners:U}=this.queue[u][N];for(;U.length!==0&&x();)U.shift().resolve(v);let V=this.queue[u];if(V[N].listeners.length===0&&(delete V[N],Object.keys(V).length===0)){delete this.queue[u];break}if(!x())break}}};v.on(\"origin\",()=>{v[Kl]=v.originSet,x()&&(R(),KM(this.sessions[u],v))}),v.once(\"remoteSettings\",()=>{if(v.ref(),v.unref(),this._sessionsCount++,h.destroyed){let N=new Error(\"Agent has been destroyed\");for(let U of o)U.reject(N);v.destroy();return}v[Kl]=v.originSet;{let N=this.sessions;if(u in N){let U=N[u];U.splice($nt(U,v,eit),0,v)}else N[u]=[v]}this._freeSessionsCount+=1,I=!0,this.emit(\"session\",v),R(),p(),v[ea]===0&&this._freeSessionsCount>this.maxFreeSessions&&v.close(),o.length!==0&&(this.getSession(A,r,o),o.length=0),v.on(\"remoteSettings\",()=>{R(),KM(this.sessions[u],v)})}),v[joe]=v.request,v.request=(N,U)=>{if(v[DE])throw new Error(\"The session is gracefully closing. No new streams are allowed.\");let V=v[joe](N,U);return v.ref(),++v[ea],v[ea]===v.remoteSettings.maxConcurrentStreams&&this._freeSessionsCount--,V.once(\"close\",()=>{if(C=x(),--v[ea],!v.destroyed&&!v.closed&&(tit(this.sessions[u],v),x()&&!v.closed)){C||(this._freeSessionsCount++,C=!0);let te=v[ea]===0;te&&v.unref(),te&&(this._freeSessionsCount>this.maxFreeSessions||v[DE])?v.close():(KM(this.sessions[u],v),R())}}),V}}catch(v){for(let x of o)x.reject(v);p()}};h.listeners=o,h.completed=!1,h.destroyed=!1,this.queue[u][A]=h,this._tryToCreateNewSession(u,A)})}request(e,r,o,a){return new Promise((n,u)=>{this.getSession(e,r,[{reject:u,resolve:A=>{try{n(A.request(o,a))}catch(p){u(p)}}}])})}createConnection(e,r){return rA.connect(e,r)}static connect(e,r){r.ALPNProtocols=[\"h2\"];let o=e.port||443,a=e.hostname||e.host;return typeof r.servername>\"u\"&&(r.servername=a),Vnt.connect(o,a,r)}closeFreeSessions(){for(let e of Object.values(this.sessions))for(let r of e)r[ea]===0&&r.close()}destroy(e){for(let r of Object.values(this.sessions))for(let o of r)o.destroy(e);for(let r of Object.values(this.queue))for(let o of Object.values(r))o.destroyed=!0;this.queue={}}get freeSessions(){return Yoe({agent:this,isFree:!0})}get busySessions(){return Yoe({agent:this,isFree:!1})}};rA.kCurrentStreamsCount=ea;rA.kGracefullyClosing=DE;Koe.exports={Agent:rA,globalAgent:new rA}});var JM=_((TNt,zoe)=>{\"use strict\";var{Readable:rit}=ve(\"stream\"),VM=class extends rit{constructor(e,r){super({highWaterMark:r,autoDestroy:!1}),this.statusCode=null,this.statusMessage=\"\",this.httpVersion=\"2.0\",this.httpVersionMajor=2,this.httpVersionMinor=0,this.headers={},this.trailers={},this.req=null,this.aborted=!1,this.complete=!1,this.upgrade=null,this.rawHeaders=[],this.rawTrailers=[],this.socket=e,this.connection=e,this._dumped=!1}_destroy(e){this.req._request.destroy(e)}setTimeout(e,r){return this.req.setTimeout(e,r),this}_dump(){this._dumped||(this._dumped=!0,this.removeAllListeners(\"data\"),this.resume())}_read(){this.req&&this.req._request.resume()}};zoe.exports=VM});var XM=_((LNt,Voe)=>{\"use strict\";Voe.exports=t=>{let e={protocol:t.protocol,hostname:typeof t.hostname==\"string\"&&t.hostname.startsWith(\"[\")?t.hostname.slice(1,-1):t.hostname,host:t.host,hash:t.hash,search:t.search,pathname:t.pathname,href:t.href,path:`${t.pathname||\"\"}${t.search||\"\"}`};return typeof t.port==\"string\"&&t.port.length!==0&&(e.port=Number(t.port)),(t.username||t.password)&&(e.auth=`${t.username||\"\"}:${t.password||\"\"}`),e}});var Xoe=_((NNt,Joe)=>{\"use strict\";Joe.exports=(t,e,r)=>{for(let o of r)t.on(o,(...a)=>e.emit(o,...a))}});var $oe=_((ONt,Zoe)=>{\"use strict\";Zoe.exports=t=>{switch(t){case\":method\":case\":scheme\":case\":authority\":case\":path\":return!0;default:return!1}}});var tae=_((UNt,eae)=>{\"use strict\";var PE=(t,e,r)=>{eae.exports[e]=class extends t{constructor(...a){super(typeof r==\"string\"?r:r(a)),this.name=`${super.name} [${e}]`,this.code=e}}};PE(TypeError,\"ERR_INVALID_ARG_TYPE\",t=>{let e=t[0].includes(\".\")?\"property\":\"argument\",r=t[1],o=Array.isArray(r);return o&&(r=`${r.slice(0,-1).join(\", \")} or ${r.slice(-1)}`),`The \"${t[0]}\" ${e} must be ${o?\"one of\":\"of\"} type ${r}. Received ${typeof t[2]}`});PE(TypeError,\"ERR_INVALID_PROTOCOL\",t=>`Protocol \"${t[0]}\" not supported. Expected \"${t[1]}\"`);PE(Error,\"ERR_HTTP_HEADERS_SENT\",t=>`Cannot ${t[0]} headers after they are sent to the client`);PE(TypeError,\"ERR_INVALID_HTTP_TOKEN\",t=>`${t[0]} must be a valid HTTP token [${t[1]}]`);PE(TypeError,\"ERR_HTTP_INVALID_HEADER_VALUE\",t=>`Invalid value \"${t[0]} for header \"${t[1]}\"`);PE(TypeError,\"ERR_INVALID_CHAR\",t=>`Invalid character in ${t[0]} [${t[1]}]`)});var r4=_((_Nt,lae)=>{\"use strict\";var nit=ve(\"http2\"),{Writable:iit}=ve(\"stream\"),{Agent:rae,globalAgent:sit}=zM(),oit=JM(),ait=XM(),lit=Xoe(),cit=$oe(),{ERR_INVALID_ARG_TYPE:ZM,ERR_INVALID_PROTOCOL:uit,ERR_HTTP_HEADERS_SENT:nae,ERR_INVALID_HTTP_TOKEN:Ait,ERR_HTTP_INVALID_HEADER_VALUE:fit,ERR_INVALID_CHAR:pit}=tae(),{HTTP2_HEADER_STATUS:iae,HTTP2_HEADER_METHOD:sae,HTTP2_HEADER_PATH:oae,HTTP2_METHOD_CONNECT:hit}=nit.constants,Qo=Symbol(\"headers\"),$M=Symbol(\"origin\"),e4=Symbol(\"session\"),aae=Symbol(\"options\"),rb=Symbol(\"flushedHeaders\"),h1=Symbol(\"jobs\"),git=/^[\\^`\\-\\w!#$%&*+.|~]+$/,dit=/[^\\t\\u0020-\\u007E\\u0080-\\u00FF]/,t4=class extends iit{constructor(e,r,o){super({autoDestroy:!1});let a=typeof e==\"string\"||e instanceof URL;if(a&&(e=ait(e instanceof URL?e:new URL(e))),typeof r==\"function\"||r===void 0?(o=r,r=a?e:{...e}):r={...e,...r},r.h2session)this[e4]=r.h2session;else if(r.agent===!1)this.agent=new rae({maxFreeSessions:0});else if(typeof r.agent>\"u\"||r.agent===null)typeof r.createConnection==\"function\"?(this.agent=new rae({maxFreeSessions:0}),this.agent.createConnection=r.createConnection):this.agent=sit;else if(typeof r.agent.request==\"function\")this.agent=r.agent;else throw new ZM(\"options.agent\",[\"Agent-like Object\",\"undefined\",\"false\"],r.agent);if(r.protocol&&r.protocol!==\"https:\")throw new uit(r.protocol,\"https:\");let n=r.port||r.defaultPort||this.agent&&this.agent.defaultPort||443,u=r.hostname||r.host||\"localhost\";delete r.hostname,delete r.host,delete r.port;let{timeout:A}=r;if(r.timeout=void 0,this[Qo]=Object.create(null),this[h1]=[],this.socket=null,this.connection=null,this.method=r.method||\"GET\",this.path=r.path,this.res=null,this.aborted=!1,this.reusedSocket=!1,r.headers)for(let[p,h]of Object.entries(r.headers))this.setHeader(p,h);r.auth&&!(\"authorization\"in this[Qo])&&(this[Qo].authorization=\"Basic \"+Buffer.from(r.auth).toString(\"base64\")),r.session=r.tlsSession,r.path=r.socketPath,this[aae]=r,n===443?(this[$M]=`https://${u}`,\":authority\"in this[Qo]||(this[Qo][\":authority\"]=u)):(this[$M]=`https://${u}:${n}`,\":authority\"in this[Qo]||(this[Qo][\":authority\"]=`${u}:${n}`)),A&&this.setTimeout(A),o&&this.once(\"response\",o),this[rb]=!1}get method(){return this[Qo][sae]}set method(e){e&&(this[Qo][sae]=e.toUpperCase())}get path(){return this[Qo][oae]}set path(e){e&&(this[Qo][oae]=e)}get _mustNotHaveABody(){return this.method===\"GET\"||this.method===\"HEAD\"||this.method===\"DELETE\"}_write(e,r,o){if(this._mustNotHaveABody){o(new Error(\"The GET, HEAD and DELETE methods must NOT have a body\"));return}this.flushHeaders();let a=()=>this._request.write(e,r,o);this._request?a():this[h1].push(a)}_final(e){if(this.destroyed)return;this.flushHeaders();let r=()=>{if(this._mustNotHaveABody){e();return}this._request.end(e)};this._request?r():this[h1].push(r)}abort(){this.res&&this.res.complete||(this.aborted||process.nextTick(()=>this.emit(\"abort\")),this.aborted=!0,this.destroy())}_destroy(e,r){this.res&&this.res._dump(),this._request&&this._request.destroy(),r(e)}async flushHeaders(){if(this[rb]||this.destroyed)return;this[rb]=!0;let e=this.method===hit,r=o=>{if(this._request=o,this.destroyed){o.destroy();return}e||lit(o,this,[\"timeout\",\"continue\",\"close\",\"error\"]);let a=u=>(...A)=>{!this.writable&&!this.destroyed?u(...A):this.once(\"finish\",()=>{u(...A)})};o.once(\"response\",a((u,A,p)=>{let h=new oit(this.socket,o.readableHighWaterMark);this.res=h,h.req=this,h.statusCode=u[iae],h.headers=u,h.rawHeaders=p,h.once(\"end\",()=>{this.aborted?(h.aborted=!0,h.emit(\"aborted\")):(h.complete=!0,h.socket=null,h.connection=null)}),e?(h.upgrade=!0,this.emit(\"connect\",h,o,Buffer.alloc(0))?this.emit(\"close\"):o.destroy()):(o.on(\"data\",E=>{!h._dumped&&!h.push(E)&&o.pause()}),o.once(\"end\",()=>{h.push(null)}),this.emit(\"response\",h)||h._dump())})),o.once(\"headers\",a(u=>this.emit(\"information\",{statusCode:u[iae]}))),o.once(\"trailers\",a((u,A,p)=>{let{res:h}=this;h.trailers=u,h.rawTrailers=p}));let{socket:n}=o.session;this.socket=n,this.connection=n;for(let u of this[h1])u();this.emit(\"socket\",this.socket)};if(this[e4])try{r(this[e4].request(this[Qo]))}catch(o){this.emit(\"error\",o)}else{this.reusedSocket=!0;try{r(await this.agent.request(this[$M],this[aae],this[Qo]))}catch(o){this.emit(\"error\",o)}}}getHeader(e){if(typeof e!=\"string\")throw new ZM(\"name\",\"string\",e);return this[Qo][e.toLowerCase()]}get headersSent(){return this[rb]}removeHeader(e){if(typeof e!=\"string\")throw new ZM(\"name\",\"string\",e);if(this.headersSent)throw new nae(\"remove\");delete this[Qo][e.toLowerCase()]}setHeader(e,r){if(this.headersSent)throw new nae(\"set\");if(typeof e!=\"string\"||!git.test(e)&&!cit(e))throw new Ait(\"Header name\",e);if(typeof r>\"u\")throw new fit(r,e);if(dit.test(r))throw new pit(\"header content\",e);this[Qo][e.toLowerCase()]=r}setNoDelay(){}setSocketKeepAlive(){}setTimeout(e,r){let o=()=>this._request.setTimeout(e,r);return this._request?o():this[h1].push(o),this}get maxHeadersCount(){if(!this.destroyed&&this._request)return this._request.session.localSettings.maxHeaderListSize}set maxHeadersCount(e){}};lae.exports=t4});var uae=_((HNt,cae)=>{\"use strict\";var mit=ve(\"tls\");cae.exports=(t={},e=mit.connect)=>new Promise((r,o)=>{let a=!1,n,u=async()=>{await p,n.off(\"timeout\",A),n.off(\"error\",o),t.resolveSocket?(r({alpnProtocol:n.alpnProtocol,socket:n,timeout:a}),a&&(await Promise.resolve(),n.emit(\"timeout\"))):(n.destroy(),r({alpnProtocol:n.alpnProtocol,timeout:a}))},A=async()=>{a=!0,u()},p=(async()=>{try{n=await e(t,u),n.on(\"error\",o),n.once(\"timeout\",A)}catch(h){o(h)}})()})});var fae=_((qNt,Aae)=>{\"use strict\";var yit=ve(\"net\");Aae.exports=t=>{let e=t.host,r=t.headers&&t.headers.host;return r&&(r.startsWith(\"[\")?r.indexOf(\"]\")===-1?e=r:e=r.slice(1,-1):e=r.split(\":\",1)[0]),yit.isIP(e)?\"\":e}});var gae=_((GNt,i4)=>{\"use strict\";var pae=ve(\"http\"),n4=ve(\"https\"),Eit=uae(),Cit=WM(),wit=r4(),Iit=fae(),Bit=XM(),nb=new Cit({maxSize:100}),g1=new Map,hae=(t,e,r)=>{e._httpMessage={shouldKeepAlive:!0};let o=()=>{t.emit(\"free\",e,r)};e.on(\"free\",o);let a=()=>{t.removeSocket(e,r)};e.on(\"close\",a);let n=()=>{t.removeSocket(e,r),e.off(\"close\",a),e.off(\"free\",o),e.off(\"agentRemove\",n)};e.on(\"agentRemove\",n),t.emit(\"free\",e,r)},vit=async t=>{let e=`${t.host}:${t.port}:${t.ALPNProtocols.sort()}`;if(!nb.has(e)){if(g1.has(e))return(await g1.get(e)).alpnProtocol;let{path:r,agent:o}=t;t.path=t.socketPath;let a=Eit(t);g1.set(e,a);try{let{socket:n,alpnProtocol:u}=await a;if(nb.set(e,u),t.path=r,u===\"h2\")n.destroy();else{let{globalAgent:A}=n4,p=n4.Agent.prototype.createConnection;o?o.createConnection===p?hae(o,n,t):n.destroy():A.createConnection===p?hae(A,n,t):n.destroy()}return g1.delete(e),u}catch(n){throw g1.delete(e),n}}return nb.get(e)};i4.exports=async(t,e,r)=>{if((typeof t==\"string\"||t instanceof URL)&&(t=Bit(new URL(t))),typeof e==\"function\"&&(r=e,e=void 0),e={ALPNProtocols:[\"h2\",\"http/1.1\"],...t,...e,resolveSocket:!0},!Array.isArray(e.ALPNProtocols)||e.ALPNProtocols.length===0)throw new Error(\"The `ALPNProtocols` option must be an Array with at least one entry\");e.protocol=e.protocol||\"https:\";let o=e.protocol===\"https:\";e.host=e.hostname||e.host||\"localhost\",e.session=e.tlsSession,e.servername=e.servername||Iit(e),e.port=e.port||(o?443:80),e._defaultAgent=o?n4.globalAgent:pae.globalAgent;let a=e.agent;if(a){if(a.addRequest)throw new Error(\"The `options.agent` object can contain only `http`, `https` or `http2` properties\");e.agent=a[o?\"https\":\"http\"]}return o&&await vit(e)===\"h2\"?(a&&(e.agent=a.http2),new wit(e,r)):pae.request(e,r)};i4.exports.protocolCache=nb});var mae=_((jNt,dae)=>{\"use strict\";var Dit=ve(\"http2\"),Pit=zM(),s4=r4(),Sit=JM(),bit=gae(),xit=(t,e,r)=>new s4(t,e,r),kit=(t,e,r)=>{let o=new s4(t,e,r);return o.end(),o};dae.exports={...Dit,ClientRequest:s4,IncomingMessage:Sit,...Pit,request:xit,get:kit,auto:bit}});var a4=_(o4=>{\"use strict\";Object.defineProperty(o4,\"__esModule\",{value:!0});var yae=Tf();o4.default=t=>yae.default.nodeStream(t)&&yae.default.function_(t.getBoundary)});var Iae=_(l4=>{\"use strict\";Object.defineProperty(l4,\"__esModule\",{value:!0});var Cae=ve(\"fs\"),wae=ve(\"util\"),Eae=Tf(),Qit=a4(),Fit=wae.promisify(Cae.stat);l4.default=async(t,e)=>{if(e&&\"content-length\"in e)return Number(e[\"content-length\"]);if(!t)return 0;if(Eae.default.string(t))return Buffer.byteLength(t);if(Eae.default.buffer(t))return t.length;if(Qit.default(t))return wae.promisify(t.getLength.bind(t))();if(t instanceof Cae.ReadStream){let{size:r}=await Fit(t.path);return r===0?void 0:r}}});var u4=_(c4=>{\"use strict\";Object.defineProperty(c4,\"__esModule\",{value:!0});function Rit(t,e,r){let o={};for(let a of r)o[a]=(...n)=>{e.emit(a,...n)},t.on(a,o[a]);return()=>{for(let a of r)t.off(a,o[a])}}c4.default=Rit});var Bae=_(A4=>{\"use strict\";Object.defineProperty(A4,\"__esModule\",{value:!0});A4.default=()=>{let t=[];return{once(e,r,o){e.once(r,o),t.push({origin:e,event:r,fn:o})},unhandleAll(){for(let e of t){let{origin:r,event:o,fn:a}=e;r.removeListener(o,a)}t.length=0}}}});var Dae=_(d1=>{\"use strict\";Object.defineProperty(d1,\"__esModule\",{value:!0});d1.TimeoutError=void 0;var Tit=ve(\"net\"),Lit=Bae(),vae=Symbol(\"reentry\"),Nit=()=>{},ib=class extends Error{constructor(e,r){super(`Timeout awaiting '${r}' for ${e}ms`),this.event=r,this.name=\"TimeoutError\",this.code=\"ETIMEDOUT\"}};d1.TimeoutError=ib;d1.default=(t,e,r)=>{if(vae in t)return Nit;t[vae]=!0;let o=[],{once:a,unhandleAll:n}=Lit.default(),u=(I,v,x)=>{var C;let R=setTimeout(v,I,I,x);(C=R.unref)===null||C===void 0||C.call(R);let N=()=>{clearTimeout(R)};return o.push(N),N},{host:A,hostname:p}=r,h=(I,v)=>{t.destroy(new ib(I,v))},E=()=>{for(let I of o)I();n()};if(t.once(\"error\",I=>{if(E(),t.listenerCount(\"error\")===0)throw I}),t.once(\"close\",E),a(t,\"response\",I=>{a(I,\"end\",E)}),typeof e.request<\"u\"&&u(e.request,h,\"request\"),typeof e.socket<\"u\"){let I=()=>{h(e.socket,\"socket\")};t.setTimeout(e.socket,I),o.push(()=>{t.removeListener(\"timeout\",I)})}return a(t,\"socket\",I=>{var v;let{socketPath:x}=t;if(I.connecting){let C=Boolean(x??Tit.isIP((v=p??A)!==null&&v!==void 0?v:\"\")!==0);if(typeof e.lookup<\"u\"&&!C&&typeof I.address().address>\"u\"){let R=u(e.lookup,h,\"lookup\");a(I,\"lookup\",R)}if(typeof e.connect<\"u\"){let R=()=>u(e.connect,h,\"connect\");C?a(I,\"connect\",R()):a(I,\"lookup\",N=>{N===null&&a(I,\"connect\",R())})}typeof e.secureConnect<\"u\"&&r.protocol===\"https:\"&&a(I,\"connect\",()=>{let R=u(e.secureConnect,h,\"secureConnect\");a(I,\"secureConnect\",R)})}if(typeof e.send<\"u\"){let C=()=>u(e.send,h,\"send\");I.connecting?a(I,\"connect\",()=>{a(t,\"upload-complete\",C())}):a(t,\"upload-complete\",C())}}),typeof e.response<\"u\"&&a(t,\"upload-complete\",()=>{let I=u(e.response,h,\"response\");a(t,\"response\",I)}),E}});var Sae=_(f4=>{\"use strict\";Object.defineProperty(f4,\"__esModule\",{value:!0});var Pae=Tf();f4.default=t=>{t=t;let e={protocol:t.protocol,hostname:Pae.default.string(t.hostname)&&t.hostname.startsWith(\"[\")?t.hostname.slice(1,-1):t.hostname,host:t.host,hash:t.hash,search:t.search,pathname:t.pathname,href:t.href,path:`${t.pathname||\"\"}${t.search||\"\"}`};return Pae.default.string(t.port)&&t.port.length>0&&(e.port=Number(t.port)),(t.username||t.password)&&(e.auth=`${t.username||\"\"}:${t.password||\"\"}`),e}});var bae=_(p4=>{\"use strict\";Object.defineProperty(p4,\"__esModule\",{value:!0});var Oit=ve(\"url\"),Mit=[\"protocol\",\"host\",\"hostname\",\"port\",\"pathname\",\"search\"];p4.default=(t,e)=>{var r,o;if(e.path){if(e.pathname)throw new TypeError(\"Parameters `path` and `pathname` are mutually exclusive.\");if(e.search)throw new TypeError(\"Parameters `path` and `search` are mutually exclusive.\");if(e.searchParams)throw new TypeError(\"Parameters `path` and `searchParams` are mutually exclusive.\")}if(e.search&&e.searchParams)throw new TypeError(\"Parameters `search` and `searchParams` are mutually exclusive.\");if(!t){if(!e.protocol)throw new TypeError(\"No URL protocol specified\");t=`${e.protocol}//${(o=(r=e.hostname)!==null&&r!==void 0?r:e.host)!==null&&o!==void 0?o:\"\"}`}let a=new Oit.URL(t);if(e.path){let n=e.path.indexOf(\"?\");n===-1?e.pathname=e.path:(e.pathname=e.path.slice(0,n),e.search=e.path.slice(n+1)),delete e.path}for(let n of Mit)e[n]&&(a[n]=e[n].toString());return a}});var xae=_(g4=>{\"use strict\";Object.defineProperty(g4,\"__esModule\",{value:!0});var h4=class{constructor(){this.weakMap=new WeakMap,this.map=new Map}set(e,r){typeof e==\"object\"?this.weakMap.set(e,r):this.map.set(e,r)}get(e){return typeof e==\"object\"?this.weakMap.get(e):this.map.get(e)}has(e){return typeof e==\"object\"?this.weakMap.has(e):this.map.has(e)}};g4.default=h4});var m4=_(d4=>{\"use strict\";Object.defineProperty(d4,\"__esModule\",{value:!0});var Uit=async t=>{let e=[],r=0;for await(let o of t)e.push(o),r+=Buffer.byteLength(o);return Buffer.isBuffer(e[0])?Buffer.concat(e,r):Buffer.from(e.join(\"\"))};d4.default=Uit});var Qae=_(bd=>{\"use strict\";Object.defineProperty(bd,\"__esModule\",{value:!0});bd.dnsLookupIpVersionToFamily=bd.isDnsLookupIpVersion=void 0;var kae={auto:0,ipv4:4,ipv6:6};bd.isDnsLookupIpVersion=t=>t in kae;bd.dnsLookupIpVersionToFamily=t=>{if(bd.isDnsLookupIpVersion(t))return kae[t];throw new Error(\"Invalid DNS lookup IP version\")}});var y4=_(sb=>{\"use strict\";Object.defineProperty(sb,\"__esModule\",{value:!0});sb.isResponseOk=void 0;sb.isResponseOk=t=>{let{statusCode:e}=t,r=t.request.options.followRedirect?299:399;return e>=200&&e<=r||e===304}});var Rae=_(E4=>{\"use strict\";Object.defineProperty(E4,\"__esModule\",{value:!0});var Fae=new Set;E4.default=t=>{Fae.has(t)||(Fae.add(t),process.emitWarning(`Got: ${t}`,{type:\"DeprecationWarning\"}))}});var Tae=_(C4=>{\"use strict\";Object.defineProperty(C4,\"__esModule\",{value:!0});var Ai=Tf(),_it=(t,e)=>{if(Ai.default.null_(t.encoding))throw new TypeError(\"To get a Buffer, set `options.responseType` to `buffer` instead\");Ai.assert.any([Ai.default.string,Ai.default.undefined],t.encoding),Ai.assert.any([Ai.default.boolean,Ai.default.undefined],t.resolveBodyOnly),Ai.assert.any([Ai.default.boolean,Ai.default.undefined],t.methodRewriting),Ai.assert.any([Ai.default.boolean,Ai.default.undefined],t.isStream),Ai.assert.any([Ai.default.string,Ai.default.undefined],t.responseType),t.responseType===void 0&&(t.responseType=\"text\");let{retry:r}=t;if(e?t.retry={...e.retry}:t.retry={calculateDelay:o=>o.computedValue,limit:0,methods:[],statusCodes:[],errorCodes:[],maxRetryAfter:void 0},Ai.default.object(r)?(t.retry={...t.retry,...r},t.retry.methods=[...new Set(t.retry.methods.map(o=>o.toUpperCase()))],t.retry.statusCodes=[...new Set(t.retry.statusCodes)],t.retry.errorCodes=[...new Set(t.retry.errorCodes)]):Ai.default.number(r)&&(t.retry.limit=r),Ai.default.undefined(t.retry.maxRetryAfter)&&(t.retry.maxRetryAfter=Math.min(...[t.timeout.request,t.timeout.connect].filter(Ai.default.number))),Ai.default.object(t.pagination)){e&&(t.pagination={...e.pagination,...t.pagination});let{pagination:o}=t;if(!Ai.default.function_(o.transform))throw new Error(\"`options.pagination.transform` must be implemented\");if(!Ai.default.function_(o.shouldContinue))throw new Error(\"`options.pagination.shouldContinue` must be implemented\");if(!Ai.default.function_(o.filter))throw new TypeError(\"`options.pagination.filter` must be implemented\");if(!Ai.default.function_(o.paginate))throw new Error(\"`options.pagination.paginate` must be implemented\")}return t.responseType===\"json\"&&t.headers.accept===void 0&&(t.headers.accept=\"application/json\"),t};C4.default=_it});var Lae=_(m1=>{\"use strict\";Object.defineProperty(m1,\"__esModule\",{value:!0});m1.retryAfterStatusCodes=void 0;m1.retryAfterStatusCodes=new Set([413,429,503]);var Hit=({attemptCount:t,retryOptions:e,error:r,retryAfter:o})=>{if(t>e.limit)return 0;let a=e.methods.includes(r.options.method),n=e.errorCodes.includes(r.code),u=r.response&&e.statusCodes.includes(r.response.statusCode);if(!a||!n&&!u)return 0;if(r.response){if(o)return e.maxRetryAfter===void 0||o>e.maxRetryAfter?0:o;if(r.response.statusCode===413)return 0}let A=Math.random()*100;return 2**(t-1)*1e3+A};m1.default=Hit});var C1=_(Bn=>{\"use strict\";Object.defineProperty(Bn,\"__esModule\",{value:!0});Bn.UnsupportedProtocolError=Bn.ReadError=Bn.TimeoutError=Bn.UploadError=Bn.CacheError=Bn.HTTPError=Bn.MaxRedirectsError=Bn.RequestError=Bn.setNonEnumerableProperties=Bn.knownHookEvents=Bn.withoutBody=Bn.kIsNormalizedAlready=void 0;var Nae=ve(\"util\"),Oae=ve(\"stream\"),qit=ve(\"fs\"),lh=ve(\"url\"),Mae=ve(\"http\"),w4=ve(\"http\"),Git=ve(\"https\"),jit=Zse(),Yit=soe(),Uae=Moe(),Wit=qoe(),Kit=mae(),zit=eb(),st=Tf(),Vit=Iae(),_ae=a4(),Jit=u4(),Hae=Dae(),Xit=Sae(),qae=bae(),Zit=xae(),$it=m4(),Gae=Qae(),est=y4(),ch=Rae(),tst=Tae(),rst=Lae(),I4,Zs=Symbol(\"request\"),lb=Symbol(\"response\"),SE=Symbol(\"responseSize\"),bE=Symbol(\"downloadedSize\"),xE=Symbol(\"bodySize\"),kE=Symbol(\"uploadedSize\"),ob=Symbol(\"serverResponsesPiped\"),jae=Symbol(\"unproxyEvents\"),Yae=Symbol(\"isFromCache\"),B4=Symbol(\"cancelTimeouts\"),Wae=Symbol(\"startedReading\"),QE=Symbol(\"stopReading\"),ab=Symbol(\"triggerRead\"),uh=Symbol(\"body\"),y1=Symbol(\"jobs\"),Kae=Symbol(\"originalResponse\"),zae=Symbol(\"retryTimeout\");Bn.kIsNormalizedAlready=Symbol(\"isNormalizedAlready\");var nst=st.default.string(process.versions.brotli);Bn.withoutBody=new Set([\"GET\",\"HEAD\"]);Bn.knownHookEvents=[\"init\",\"beforeRequest\",\"beforeRedirect\",\"beforeError\",\"beforeRetry\",\"afterResponse\"];function ist(t){for(let e in t){let r=t[e];if(!st.default.string(r)&&!st.default.number(r)&&!st.default.boolean(r)&&!st.default.null_(r)&&!st.default.undefined(r))throw new TypeError(`The \\`searchParams\\` value '${String(r)}' must be a string, number, boolean or null`)}}function sst(t){return st.default.object(t)&&!(\"statusCode\"in t)}var v4=new Zit.default,ost=async t=>new Promise((e,r)=>{let o=a=>{r(a)};t.pending||e(),t.once(\"error\",o),t.once(\"ready\",()=>{t.off(\"error\",o),e()})}),ast=new Set([300,301,302,303,304,307,308]),lst=[\"context\",\"body\",\"json\",\"form\"];Bn.setNonEnumerableProperties=(t,e)=>{let r={};for(let o of t)if(!!o)for(let a of lst)a in o&&(r[a]={writable:!0,configurable:!0,enumerable:!1,value:o[a]});Object.defineProperties(e,r)};var zi=class extends Error{constructor(e,r,o){var a;if(super(e),Error.captureStackTrace(this,this.constructor),this.name=\"RequestError\",this.code=r.code,o instanceof db?(Object.defineProperty(this,\"request\",{enumerable:!1,value:o}),Object.defineProperty(this,\"response\",{enumerable:!1,value:o[lb]}),Object.defineProperty(this,\"options\",{enumerable:!1,value:o.options})):Object.defineProperty(this,\"options\",{enumerable:!1,value:o}),this.timings=(a=this.request)===null||a===void 0?void 0:a.timings,st.default.string(r.stack)&&st.default.string(this.stack)){let n=this.stack.indexOf(this.message)+this.message.length,u=this.stack.slice(n).split(`\n`).reverse(),A=r.stack.slice(r.stack.indexOf(r.message)+r.message.length).split(`\n`).reverse();for(;A.length!==0&&A[0]===u[0];)u.shift();this.stack=`${this.stack.slice(0,n)}${u.reverse().join(`\n`)}${A.reverse().join(`\n`)}`}}};Bn.RequestError=zi;var ub=class extends zi{constructor(e){super(`Redirected ${e.options.maxRedirects} times. Aborting.`,{},e),this.name=\"MaxRedirectsError\"}};Bn.MaxRedirectsError=ub;var Ab=class extends zi{constructor(e){super(`Response code ${e.statusCode} (${e.statusMessage})`,{},e.request),this.name=\"HTTPError\"}};Bn.HTTPError=Ab;var fb=class extends zi{constructor(e,r){super(e.message,e,r),this.name=\"CacheError\"}};Bn.CacheError=fb;var pb=class extends zi{constructor(e,r){super(e.message,e,r),this.name=\"UploadError\"}};Bn.UploadError=pb;var hb=class extends zi{constructor(e,r,o){super(e.message,e,o),this.name=\"TimeoutError\",this.event=e.event,this.timings=r}};Bn.TimeoutError=hb;var E1=class extends zi{constructor(e,r){super(e.message,e,r),this.name=\"ReadError\"}};Bn.ReadError=E1;var gb=class extends zi{constructor(e){super(`Unsupported protocol \"${e.url.protocol}\"`,{},e),this.name=\"UnsupportedProtocolError\"}};Bn.UnsupportedProtocolError=gb;var cst=[\"socket\",\"connect\",\"continue\",\"information\",\"upgrade\",\"timeout\"],db=class extends Oae.Duplex{constructor(e,r={},o){super({autoDestroy:!1,highWaterMark:0}),this[bE]=0,this[kE]=0,this.requestInitialized=!1,this[ob]=new Set,this.redirects=[],this[QE]=!1,this[ab]=!1,this[y1]=[],this.retryCount=0,this._progressCallbacks=[];let a=()=>this._unlockWrite(),n=()=>this._lockWrite();this.on(\"pipe\",h=>{h.prependListener(\"data\",a),h.on(\"data\",n),h.prependListener(\"end\",a),h.on(\"end\",n)}),this.on(\"unpipe\",h=>{h.off(\"data\",a),h.off(\"data\",n),h.off(\"end\",a),h.off(\"end\",n)}),this.on(\"pipe\",h=>{h instanceof w4.IncomingMessage&&(this.options.headers={...h.headers,...this.options.headers})});let{json:u,body:A,form:p}=r;if((u||A||p)&&this._lockWrite(),Bn.kIsNormalizedAlready in r)this.options=r;else try{this.options=this.constructor.normalizeArguments(e,r,o)}catch(h){st.default.nodeStream(r.body)&&r.body.destroy(),this.destroy(h);return}(async()=>{var h;try{this.options.body instanceof qit.ReadStream&&await ost(this.options.body);let{url:E}=this.options;if(!E)throw new TypeError(\"Missing `url` property\");if(this.requestUrl=E.toString(),decodeURI(this.requestUrl),await this._finalizeBody(),await this._makeRequest(),this.destroyed){(h=this[Zs])===null||h===void 0||h.destroy();return}for(let I of this[y1])I();this[y1].length=0,this.requestInitialized=!0}catch(E){if(E instanceof zi){this._beforeError(E);return}this.destroyed||this.destroy(E)}})()}static normalizeArguments(e,r,o){var a,n,u,A,p;let h=r;if(st.default.object(e)&&!st.default.urlInstance(e))r={...o,...e,...r};else{if(e&&r&&r.url!==void 0)throw new TypeError(\"The `url` option is mutually exclusive with the `input` argument\");r={...o,...r},e!==void 0&&(r.url=e),st.default.urlInstance(r.url)&&(r.url=new lh.URL(r.url.toString()))}if(r.cache===!1&&(r.cache=void 0),r.dnsCache===!1&&(r.dnsCache=void 0),st.assert.any([st.default.string,st.default.undefined],r.method),st.assert.any([st.default.object,st.default.undefined],r.headers),st.assert.any([st.default.string,st.default.urlInstance,st.default.undefined],r.prefixUrl),st.assert.any([st.default.object,st.default.undefined],r.cookieJar),st.assert.any([st.default.object,st.default.string,st.default.undefined],r.searchParams),st.assert.any([st.default.object,st.default.string,st.default.undefined],r.cache),st.assert.any([st.default.object,st.default.number,st.default.undefined],r.timeout),st.assert.any([st.default.object,st.default.undefined],r.context),st.assert.any([st.default.object,st.default.undefined],r.hooks),st.assert.any([st.default.boolean,st.default.undefined],r.decompress),st.assert.any([st.default.boolean,st.default.undefined],r.ignoreInvalidCookies),st.assert.any([st.default.boolean,st.default.undefined],r.followRedirect),st.assert.any([st.default.number,st.default.undefined],r.maxRedirects),st.assert.any([st.default.boolean,st.default.undefined],r.throwHttpErrors),st.assert.any([st.default.boolean,st.default.undefined],r.http2),st.assert.any([st.default.boolean,st.default.undefined],r.allowGetBody),st.assert.any([st.default.string,st.default.undefined],r.localAddress),st.assert.any([Gae.isDnsLookupIpVersion,st.default.undefined],r.dnsLookupIpVersion),st.assert.any([st.default.object,st.default.undefined],r.https),st.assert.any([st.default.boolean,st.default.undefined],r.rejectUnauthorized),r.https&&(st.assert.any([st.default.boolean,st.default.undefined],r.https.rejectUnauthorized),st.assert.any([st.default.function_,st.default.undefined],r.https.checkServerIdentity),st.assert.any([st.default.string,st.default.object,st.default.array,st.default.undefined],r.https.certificateAuthority),st.assert.any([st.default.string,st.default.object,st.default.array,st.default.undefined],r.https.key),st.assert.any([st.default.string,st.default.object,st.default.array,st.default.undefined],r.https.certificate),st.assert.any([st.default.string,st.default.undefined],r.https.passphrase),st.assert.any([st.default.string,st.default.buffer,st.default.array,st.default.undefined],r.https.pfx)),st.assert.any([st.default.object,st.default.undefined],r.cacheOptions),st.default.string(r.method)?r.method=r.method.toUpperCase():r.method=\"GET\",r.headers===o?.headers?r.headers={...r.headers}:r.headers=zit({...o?.headers,...r.headers}),\"slashes\"in r)throw new TypeError(\"The legacy `url.Url` has been deprecated. Use `URL` instead.\");if(\"auth\"in r)throw new TypeError(\"Parameter `auth` is deprecated. Use `username` / `password` instead.\");if(\"searchParams\"in r&&r.searchParams&&r.searchParams!==o?.searchParams){let x;if(st.default.string(r.searchParams)||r.searchParams instanceof lh.URLSearchParams)x=new lh.URLSearchParams(r.searchParams);else{ist(r.searchParams),x=new lh.URLSearchParams;for(let C in r.searchParams){let R=r.searchParams[C];R===null?x.append(C,\"\"):R!==void 0&&x.append(C,R)}}(a=o?.searchParams)===null||a===void 0||a.forEach((C,R)=>{x.has(R)||x.append(R,C)}),r.searchParams=x}if(r.username=(n=r.username)!==null&&n!==void 0?n:\"\",r.password=(u=r.password)!==null&&u!==void 0?u:\"\",st.default.undefined(r.prefixUrl)?r.prefixUrl=(A=o?.prefixUrl)!==null&&A!==void 0?A:\"\":(r.prefixUrl=r.prefixUrl.toString(),r.prefixUrl!==\"\"&&!r.prefixUrl.endsWith(\"/\")&&(r.prefixUrl+=\"/\")),st.default.string(r.url)){if(r.url.startsWith(\"/\"))throw new Error(\"`input` must not start with a slash when using `prefixUrl`\");r.url=qae.default(r.prefixUrl+r.url,r)}else(st.default.undefined(r.url)&&r.prefixUrl!==\"\"||r.protocol)&&(r.url=qae.default(r.prefixUrl,r));if(r.url){\"port\"in r&&delete r.port;let{prefixUrl:x}=r;Object.defineProperty(r,\"prefixUrl\",{set:R=>{let N=r.url;if(!N.href.startsWith(R))throw new Error(`Cannot change \\`prefixUrl\\` from ${x} to ${R}: ${N.href}`);r.url=new lh.URL(R+N.href.slice(x.length)),x=R},get:()=>x});let{protocol:C}=r.url;if(C===\"unix:\"&&(C=\"http:\",r.url=new lh.URL(`http://unix${r.url.pathname}${r.url.search}`)),r.searchParams&&(r.url.search=r.searchParams.toString()),C!==\"http:\"&&C!==\"https:\")throw new gb(r);r.username===\"\"?r.username=r.url.username:r.url.username=r.username,r.password===\"\"?r.password=r.url.password:r.url.password=r.password}let{cookieJar:E}=r;if(E){let{setCookie:x,getCookieString:C}=E;st.assert.function_(x),st.assert.function_(C),x.length===4&&C.length===0&&(x=Nae.promisify(x.bind(r.cookieJar)),C=Nae.promisify(C.bind(r.cookieJar)),r.cookieJar={setCookie:x,getCookieString:C})}let{cache:I}=r;if(I&&(v4.has(I)||v4.set(I,new Uae((x,C)=>{let R=x[Zs](x,C);return st.default.promise(R)&&(R.once=(N,U)=>{if(N===\"error\")R.catch(U);else if(N===\"abort\")(async()=>{try{(await R).once(\"abort\",U)}catch{}})();else throw new Error(`Unknown HTTP2 promise event: ${N}`);return R}),R},I))),r.cacheOptions={...r.cacheOptions},r.dnsCache===!0)I4||(I4=new Yit.default),r.dnsCache=I4;else if(!st.default.undefined(r.dnsCache)&&!r.dnsCache.lookup)throw new TypeError(`Parameter \\`dnsCache\\` must be a CacheableLookup instance or a boolean, got ${st.default(r.dnsCache)}`);st.default.number(r.timeout)?r.timeout={request:r.timeout}:o&&r.timeout!==o.timeout?r.timeout={...o.timeout,...r.timeout}:r.timeout={...r.timeout},r.context||(r.context={});let v=r.hooks===o?.hooks;r.hooks={...r.hooks};for(let x of Bn.knownHookEvents)if(x in r.hooks)if(st.default.array(r.hooks[x]))r.hooks[x]=[...r.hooks[x]];else throw new TypeError(`Parameter \\`${x}\\` must be an Array, got ${st.default(r.hooks[x])}`);else r.hooks[x]=[];if(o&&!v)for(let x of Bn.knownHookEvents)o.hooks[x].length>0&&(r.hooks[x]=[...o.hooks[x],...r.hooks[x]]);if(\"family\"in r&&ch.default('\"options.family\" was never documented, please use \"options.dnsLookupIpVersion\"'),o?.https&&(r.https={...o.https,...r.https}),\"rejectUnauthorized\"in r&&ch.default('\"options.rejectUnauthorized\" is now deprecated, please use \"options.https.rejectUnauthorized\"'),\"checkServerIdentity\"in r&&ch.default('\"options.checkServerIdentity\" was never documented, please use \"options.https.checkServerIdentity\"'),\"ca\"in r&&ch.default('\"options.ca\" was never documented, please use \"options.https.certificateAuthority\"'),\"key\"in r&&ch.default('\"options.key\" was never documented, please use \"options.https.key\"'),\"cert\"in r&&ch.default('\"options.cert\" was never documented, please use \"options.https.certificate\"'),\"passphrase\"in r&&ch.default('\"options.passphrase\" was never documented, please use \"options.https.passphrase\"'),\"pfx\"in r&&ch.default('\"options.pfx\" was never documented, please use \"options.https.pfx\"'),\"followRedirects\"in r)throw new TypeError(\"The `followRedirects` option does not exist. Use `followRedirect` instead.\");if(r.agent){for(let x in r.agent)if(x!==\"http\"&&x!==\"https\"&&x!==\"http2\")throw new TypeError(`Expected the \\`options.agent\\` properties to be \\`http\\`, \\`https\\` or \\`http2\\`, got \\`${x}\\``)}return r.maxRedirects=(p=r.maxRedirects)!==null&&p!==void 0?p:0,Bn.setNonEnumerableProperties([o,h],r),tst.default(r,o)}_lockWrite(){let e=()=>{throw new TypeError(\"The payload has been already provided\")};this.write=e,this.end=e}_unlockWrite(){this.write=super.write,this.end=super.end}async _finalizeBody(){let{options:e}=this,{headers:r}=e,o=!st.default.undefined(e.form),a=!st.default.undefined(e.json),n=!st.default.undefined(e.body),u=o||a||n,A=Bn.withoutBody.has(e.method)&&!(e.method===\"GET\"&&e.allowGetBody);if(this._cannotHaveBody=A,u){if(A)throw new TypeError(`The \\`${e.method}\\` method cannot be used with a body`);if([n,o,a].filter(p=>p).length>1)throw new TypeError(\"The `body`, `json` and `form` options are mutually exclusive\");if(n&&!(e.body instanceof Oae.Readable)&&!st.default.string(e.body)&&!st.default.buffer(e.body)&&!_ae.default(e.body))throw new TypeError(\"The `body` option must be a stream.Readable, string or Buffer\");if(o&&!st.default.object(e.form))throw new TypeError(\"The `form` option must be an Object\");{let p=!st.default.string(r[\"content-type\"]);n?(_ae.default(e.body)&&p&&(r[\"content-type\"]=`multipart/form-data; boundary=${e.body.getBoundary()}`),this[uh]=e.body):o?(p&&(r[\"content-type\"]=\"application/x-www-form-urlencoded\"),this[uh]=new lh.URLSearchParams(e.form).toString()):(p&&(r[\"content-type\"]=\"application/json\"),this[uh]=e.stringifyJson(e.json));let h=await Vit.default(this[uh],e.headers);st.default.undefined(r[\"content-length\"])&&st.default.undefined(r[\"transfer-encoding\"])&&!A&&!st.default.undefined(h)&&(r[\"content-length\"]=String(h))}}else A?this._lockWrite():this._unlockWrite();this[xE]=Number(r[\"content-length\"])||void 0}async _onResponseBase(e){let{options:r}=this,{url:o}=r;this[Kae]=e,r.decompress&&(e=Wit(e));let a=e.statusCode,n=e;n.statusMessage=n.statusMessage?n.statusMessage:Mae.STATUS_CODES[a],n.url=r.url.toString(),n.requestUrl=this.requestUrl,n.redirectUrls=this.redirects,n.request=this,n.isFromCache=e.fromCache||!1,n.ip=this.ip,n.retryCount=this.retryCount,this[Yae]=n.isFromCache,this[SE]=Number(e.headers[\"content-length\"])||void 0,this[lb]=e,e.once(\"end\",()=>{this[SE]=this[bE],this.emit(\"downloadProgress\",this.downloadProgress)}),e.once(\"error\",A=>{e.destroy(),this._beforeError(new E1(A,this))}),e.once(\"aborted\",()=>{this._beforeError(new E1({name:\"Error\",message:\"The server aborted pending request\",code:\"ECONNRESET\"},this))}),this.emit(\"downloadProgress\",this.downloadProgress);let u=e.headers[\"set-cookie\"];if(st.default.object(r.cookieJar)&&u){let A=u.map(async p=>r.cookieJar.setCookie(p,o.toString()));r.ignoreInvalidCookies&&(A=A.map(async p=>p.catch(()=>{})));try{await Promise.all(A)}catch(p){this._beforeError(p);return}}if(r.followRedirect&&e.headers.location&&ast.has(a)){if(e.resume(),this[Zs]&&(this[B4](),delete this[Zs],this[jae]()),(a===303&&r.method!==\"GET\"&&r.method!==\"HEAD\"||!r.methodRewriting)&&(r.method=\"GET\",\"body\"in r&&delete r.body,\"json\"in r&&delete r.json,\"form\"in r&&delete r.form,this[uh]=void 0,delete r.headers[\"content-length\"]),this.redirects.length>=r.maxRedirects){this._beforeError(new ub(this));return}try{let p=Buffer.from(e.headers.location,\"binary\").toString(),h=new lh.URL(p,o),E=h.toString();decodeURI(E),h.hostname!==o.hostname||h.port!==o.port?(\"host\"in r.headers&&delete r.headers.host,\"cookie\"in r.headers&&delete r.headers.cookie,\"authorization\"in r.headers&&delete r.headers.authorization,(r.username||r.password)&&(r.username=\"\",r.password=\"\")):(h.username=r.username,h.password=r.password),this.redirects.push(E),r.url=h;for(let I of r.hooks.beforeRedirect)await I(r,n);this.emit(\"redirect\",n,r),await this._makeRequest()}catch(p){this._beforeError(p);return}return}if(r.isStream&&r.throwHttpErrors&&!est.isResponseOk(n)){this._beforeError(new Ab(n));return}e.on(\"readable\",()=>{this[ab]&&this._read()}),this.on(\"resume\",()=>{e.resume()}),this.on(\"pause\",()=>{e.pause()}),e.once(\"end\",()=>{this.push(null)}),this.emit(\"response\",e);for(let A of this[ob])if(!A.headersSent){for(let p in e.headers){let h=r.decompress?p!==\"content-encoding\":!0,E=e.headers[p];h&&A.setHeader(p,E)}A.statusCode=a}}async _onResponse(e){try{await this._onResponseBase(e)}catch(r){this._beforeError(r)}}_onRequest(e){let{options:r}=this,{timeout:o,url:a}=r;jit.default(e),this[B4]=Hae.default(e,o,a);let n=r.cache?\"cacheableResponse\":\"response\";e.once(n,p=>{this._onResponse(p)}),e.once(\"error\",p=>{var h;e.destroy(),(h=e.res)===null||h===void 0||h.removeAllListeners(\"end\"),p=p instanceof Hae.TimeoutError?new hb(p,this.timings,this):new zi(p.message,p,this),this._beforeError(p)}),this[jae]=Jit.default(e,this,cst),this[Zs]=e,this.emit(\"uploadProgress\",this.uploadProgress);let u=this[uh],A=this.redirects.length===0?this:e;st.default.nodeStream(u)?(u.pipe(A),u.once(\"error\",p=>{this._beforeError(new pb(p,this))})):(this._unlockWrite(),st.default.undefined(u)?(this._cannotHaveBody||this._noPipe)&&(A.end(),this._lockWrite()):(this._writeRequest(u,void 0,()=>{}),A.end(),this._lockWrite())),this.emit(\"request\",e)}async _createCacheableRequest(e,r){return new Promise((o,a)=>{Object.assign(r,Xit.default(e)),delete r.url;let n,u=v4.get(r.cache)(r,async A=>{A._readableState.autoDestroy=!1,n&&(await n).emit(\"cacheableResponse\",A),o(A)});r.url=e,u.once(\"error\",a),u.once(\"request\",async A=>{n=A,o(n)})})}async _makeRequest(){var e,r,o,a,n;let{options:u}=this,{headers:A}=u;for(let U in A)if(st.default.undefined(A[U]))delete A[U];else if(st.default.null_(A[U]))throw new TypeError(`Use \\`undefined\\` instead of \\`null\\` to delete the \\`${U}\\` header`);if(u.decompress&&st.default.undefined(A[\"accept-encoding\"])&&(A[\"accept-encoding\"]=nst?\"gzip, deflate, br\":\"gzip, deflate\"),u.cookieJar){let U=await u.cookieJar.getCookieString(u.url.toString());st.default.nonEmptyString(U)&&(u.headers.cookie=U)}for(let U of u.hooks.beforeRequest){let V=await U(u);if(!st.default.undefined(V)){u.request=()=>V;break}}u.body&&this[uh]!==u.body&&(this[uh]=u.body);let{agent:p,request:h,timeout:E,url:I}=u;if(u.dnsCache&&!(\"lookup\"in u)&&(u.lookup=u.dnsCache.lookup),I.hostname===\"unix\"){let U=/(?<socketPath>.+?):(?<path>.+)/.exec(`${I.pathname}${I.search}`);if(U?.groups){let{socketPath:V,path:te}=U.groups;Object.assign(u,{socketPath:V,path:te,host:\"\"})}}let v=I.protocol===\"https:\",x;u.http2?x=Kit.auto:x=v?Git.request:Mae.request;let C=(e=u.request)!==null&&e!==void 0?e:x,R=u.cache?this._createCacheableRequest:C;p&&!u.http2&&(u.agent=p[v?\"https\":\"http\"]),u[Zs]=C,delete u.request,delete u.timeout;let N=u;if(N.shared=(r=u.cacheOptions)===null||r===void 0?void 0:r.shared,N.cacheHeuristic=(o=u.cacheOptions)===null||o===void 0?void 0:o.cacheHeuristic,N.immutableMinTimeToLive=(a=u.cacheOptions)===null||a===void 0?void 0:a.immutableMinTimeToLive,N.ignoreCargoCult=(n=u.cacheOptions)===null||n===void 0?void 0:n.ignoreCargoCult,u.dnsLookupIpVersion!==void 0)try{N.family=Gae.dnsLookupIpVersionToFamily(u.dnsLookupIpVersion)}catch{throw new Error(\"Invalid `dnsLookupIpVersion` option value\")}u.https&&(\"rejectUnauthorized\"in u.https&&(N.rejectUnauthorized=u.https.rejectUnauthorized),u.https.checkServerIdentity&&(N.checkServerIdentity=u.https.checkServerIdentity),u.https.certificateAuthority&&(N.ca=u.https.certificateAuthority),u.https.certificate&&(N.cert=u.https.certificate),u.https.key&&(N.key=u.https.key),u.https.passphrase&&(N.passphrase=u.https.passphrase),u.https.pfx&&(N.pfx=u.https.pfx));try{let U=await R(I,N);st.default.undefined(U)&&(U=x(I,N)),u.request=h,u.timeout=E,u.agent=p,u.https&&(\"rejectUnauthorized\"in u.https&&delete N.rejectUnauthorized,u.https.checkServerIdentity&&delete N.checkServerIdentity,u.https.certificateAuthority&&delete N.ca,u.https.certificate&&delete N.cert,u.https.key&&delete N.key,u.https.passphrase&&delete N.passphrase,u.https.pfx&&delete N.pfx),sst(U)?this._onRequest(U):this.writable?(this.once(\"finish\",()=>{this._onResponse(U)}),this._unlockWrite(),this.end(),this._lockWrite()):this._onResponse(U)}catch(U){throw U instanceof Uae.CacheError?new fb(U,this):new zi(U.message,U,this)}}async _error(e){try{for(let r of this.options.hooks.beforeError)e=await r(e)}catch(r){e=new zi(r.message,r,this)}this.destroy(e)}_beforeError(e){if(this[QE])return;let{options:r}=this,o=this.retryCount+1;this[QE]=!0,e instanceof zi||(e=new zi(e.message,e,this));let a=e,{response:n}=a;(async()=>{if(n&&!n.body){n.setEncoding(this._readableState.encoding);try{n.rawBody=await $it.default(n),n.body=n.rawBody.toString()}catch{}}if(this.listenerCount(\"retry\")!==0){let u;try{let A;n&&\"retry-after\"in n.headers&&(A=Number(n.headers[\"retry-after\"]),Number.isNaN(A)?(A=Date.parse(n.headers[\"retry-after\"])-Date.now(),A<=0&&(A=1)):A*=1e3),u=await r.retry.calculateDelay({attemptCount:o,retryOptions:r.retry,error:a,retryAfter:A,computedValue:rst.default({attemptCount:o,retryOptions:r.retry,error:a,retryAfter:A,computedValue:0})})}catch(A){this._error(new zi(A.message,A,this));return}if(u){let A=async()=>{try{for(let p of this.options.hooks.beforeRetry)await p(this.options,a,o)}catch(p){this._error(new zi(p.message,e,this));return}this.destroyed||(this.destroy(),this.emit(\"retry\",o,e))};this[zae]=setTimeout(A,u);return}}this._error(a)})()}_read(){this[ab]=!0;let e=this[lb];if(e&&!this[QE]){e.readableLength&&(this[ab]=!1);let r;for(;(r=e.read())!==null;){this[bE]+=r.length,this[Wae]=!0;let o=this.downloadProgress;o.percent<1&&this.emit(\"downloadProgress\",o),this.push(r)}}}_write(e,r,o){let a=()=>{this._writeRequest(e,r,o)};this.requestInitialized?a():this[y1].push(a)}_writeRequest(e,r,o){this[Zs].destroyed||(this._progressCallbacks.push(()=>{this[kE]+=Buffer.byteLength(e,r);let a=this.uploadProgress;a.percent<1&&this.emit(\"uploadProgress\",a)}),this[Zs].write(e,r,a=>{!a&&this._progressCallbacks.length>0&&this._progressCallbacks.shift()(),o(a)}))}_final(e){let r=()=>{for(;this._progressCallbacks.length!==0;)this._progressCallbacks.shift()();if(!(Zs in this)){e();return}if(this[Zs].destroyed){e();return}this[Zs].end(o=>{o||(this[xE]=this[kE],this.emit(\"uploadProgress\",this.uploadProgress),this[Zs].emit(\"upload-complete\")),e(o)})};this.requestInitialized?r():this[y1].push(r)}_destroy(e,r){var o;this[QE]=!0,clearTimeout(this[zae]),Zs in this&&(this[B4](),!((o=this[lb])===null||o===void 0)&&o.complete||this[Zs].destroy()),e!==null&&!st.default.undefined(e)&&!(e instanceof zi)&&(e=new zi(e.message,e,this)),r(e)}get _isAboutToError(){return this[QE]}get ip(){var e;return(e=this.socket)===null||e===void 0?void 0:e.remoteAddress}get aborted(){var e,r,o;return((r=(e=this[Zs])===null||e===void 0?void 0:e.destroyed)!==null&&r!==void 0?r:this.destroyed)&&!(!((o=this[Kae])===null||o===void 0)&&o.complete)}get socket(){var e,r;return(r=(e=this[Zs])===null||e===void 0?void 0:e.socket)!==null&&r!==void 0?r:void 0}get downloadProgress(){let e;return this[SE]?e=this[bE]/this[SE]:this[SE]===this[bE]?e=1:e=0,{percent:e,transferred:this[bE],total:this[SE]}}get uploadProgress(){let e;return this[xE]?e=this[kE]/this[xE]:this[xE]===this[kE]?e=1:e=0,{percent:e,transferred:this[kE],total:this[xE]}}get timings(){var e;return(e=this[Zs])===null||e===void 0?void 0:e.timings}get isFromCache(){return this[Yae]}pipe(e,r){if(this[Wae])throw new Error(\"Failed to pipe. The response has been emitted already.\");return e instanceof w4.ServerResponse&&this[ob].add(e),super.pipe(e,r)}unpipe(e){return e instanceof w4.ServerResponse&&this[ob].delete(e),super.unpipe(e),this}};Bn.default=db});var w1=_(jc=>{\"use strict\";var ust=jc&&jc.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),Ast=jc&&jc.__exportStar||function(t,e){for(var r in t)r!==\"default\"&&!Object.prototype.hasOwnProperty.call(e,r)&&ust(e,t,r)};Object.defineProperty(jc,\"__esModule\",{value:!0});jc.CancelError=jc.ParseError=void 0;var Vae=C1(),D4=class extends Vae.RequestError{constructor(e,r){let{options:o}=r.request;super(`${e.message} in \"${o.url.toString()}\"`,e,r.request),this.name=\"ParseError\"}};jc.ParseError=D4;var P4=class extends Vae.RequestError{constructor(e){super(\"Promise was canceled\",{},e),this.name=\"CancelError\"}get isCanceled(){return!0}};jc.CancelError=P4;Ast(C1(),jc)});var Xae=_(S4=>{\"use strict\";Object.defineProperty(S4,\"__esModule\",{value:!0});var Jae=w1(),fst=(t,e,r,o)=>{let{rawBody:a}=t;try{if(e===\"text\")return a.toString(o);if(e===\"json\")return a.length===0?\"\":r(a.toString());if(e===\"buffer\")return a;throw new Jae.ParseError({message:`Unknown body type '${e}'`,name:\"Error\"},t)}catch(n){throw new Jae.ParseError(n,t)}};S4.default=fst});var b4=_(Ah=>{\"use strict\";var pst=Ah&&Ah.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),hst=Ah&&Ah.__exportStar||function(t,e){for(var r in t)r!==\"default\"&&!Object.prototype.hasOwnProperty.call(e,r)&&pst(e,t,r)};Object.defineProperty(Ah,\"__esModule\",{value:!0});var gst=ve(\"events\"),dst=Tf(),mst=Jse(),mb=w1(),Zae=Xae(),$ae=C1(),yst=u4(),Est=m4(),ele=y4(),Cst=[\"request\",\"response\",\"redirect\",\"uploadProgress\",\"downloadProgress\"];function tle(t){let e,r,o=new gst.EventEmitter,a=new mst((u,A,p)=>{let h=E=>{let I=new $ae.default(void 0,t);I.retryCount=E,I._noPipe=!0,p(()=>I.destroy()),p.shouldReject=!1,p(()=>A(new mb.CancelError(I))),e=I,I.once(\"response\",async C=>{var R;if(C.retryCount=E,C.request.aborted)return;let N;try{N=await Est.default(I),C.rawBody=N}catch{return}if(I._isAboutToError)return;let U=((R=C.headers[\"content-encoding\"])!==null&&R!==void 0?R:\"\").toLowerCase(),V=[\"gzip\",\"deflate\",\"br\"].includes(U),{options:te}=I;if(V&&!te.decompress)C.body=N;else try{C.body=Zae.default(C,te.responseType,te.parseJson,te.encoding)}catch(ae){if(C.body=N.toString(),ele.isResponseOk(C)){I._beforeError(ae);return}}try{for(let[ae,fe]of te.hooks.afterResponse.entries())C=await fe(C,async ue=>{let me=$ae.default.normalizeArguments(void 0,{...ue,retry:{calculateDelay:()=>0},throwHttpErrors:!1,resolveBodyOnly:!1},te);me.hooks.afterResponse=me.hooks.afterResponse.slice(0,ae);for(let Be of me.hooks.beforeRetry)await Be(me);let he=tle(me);return p(()=>{he.catch(()=>{}),he.cancel()}),he})}catch(ae){I._beforeError(new mb.RequestError(ae.message,ae,I));return}if(!ele.isResponseOk(C)){I._beforeError(new mb.HTTPError(C));return}r=C,u(I.options.resolveBodyOnly?C.body:C)});let v=C=>{if(a.isCanceled)return;let{options:R}=I;if(C instanceof mb.HTTPError&&!R.throwHttpErrors){let{response:N}=C;u(I.options.resolveBodyOnly?N.body:N);return}A(C)};I.once(\"error\",v);let x=I.options.body;I.once(\"retry\",(C,R)=>{var N,U;if(x===((N=R.request)===null||N===void 0?void 0:N.options.body)&&dst.default.nodeStream((U=R.request)===null||U===void 0?void 0:U.options.body)){v(R);return}h(C)}),yst.default(I,o,Cst)};h(0)});a.on=(u,A)=>(o.on(u,A),a);let n=u=>{let A=(async()=>{await a;let{options:p}=r.request;return Zae.default(r,u,p.parseJson,p.encoding)})();return Object.defineProperties(A,Object.getOwnPropertyDescriptors(a)),A};return a.json=()=>{let{headers:u}=e.options;return!e.writableFinished&&u.accept===void 0&&(u.accept=\"application/json\"),n(\"json\")},a.buffer=()=>n(\"buffer\"),a.text=()=>n(\"text\"),a}Ah.default=tle;hst(w1(),Ah)});var rle=_(x4=>{\"use strict\";Object.defineProperty(x4,\"__esModule\",{value:!0});var wst=w1();function Ist(t,...e){let r=(async()=>{if(t instanceof wst.RequestError)try{for(let a of e)if(a)for(let n of a)t=await n(t)}catch(a){t=a}throw t})(),o=()=>r;return r.json=o,r.text=o,r.buffer=o,r.on=o,r}x4.default=Ist});var sle=_(k4=>{\"use strict\";Object.defineProperty(k4,\"__esModule\",{value:!0});var nle=Tf();function ile(t){for(let e of Object.values(t))(nle.default.plainObject(e)||nle.default.array(e))&&ile(e);return Object.freeze(t)}k4.default=ile});var ale=_(ole=>{\"use strict\";Object.defineProperty(ole,\"__esModule\",{value:!0})});var Q4=_(Vl=>{\"use strict\";var Bst=Vl&&Vl.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),vst=Vl&&Vl.__exportStar||function(t,e){for(var r in t)r!==\"default\"&&!Object.prototype.hasOwnProperty.call(e,r)&&Bst(e,t,r)};Object.defineProperty(Vl,\"__esModule\",{value:!0});Vl.defaultHandler=void 0;var lle=Tf(),zl=b4(),Dst=rle(),Eb=C1(),Pst=sle(),Sst={RequestError:zl.RequestError,CacheError:zl.CacheError,ReadError:zl.ReadError,HTTPError:zl.HTTPError,MaxRedirectsError:zl.MaxRedirectsError,TimeoutError:zl.TimeoutError,ParseError:zl.ParseError,CancelError:zl.CancelError,UnsupportedProtocolError:zl.UnsupportedProtocolError,UploadError:zl.UploadError},bst=async t=>new Promise(e=>{setTimeout(e,t)}),{normalizeArguments:yb}=Eb.default,cle=(...t)=>{let e;for(let r of t)e=yb(void 0,r,e);return e},xst=t=>t.isStream?new Eb.default(void 0,t):zl.default(t),kst=t=>\"defaults\"in t&&\"options\"in t.defaults,Qst=[\"get\",\"post\",\"put\",\"patch\",\"head\",\"delete\"];Vl.defaultHandler=(t,e)=>e(t);var ule=(t,e)=>{if(t)for(let r of t)r(e)},Ale=t=>{t._rawHandlers=t.handlers,t.handlers=t.handlers.map(o=>(a,n)=>{let u,A=o(a,p=>(u=n(p),u));if(A!==u&&!a.isStream&&u){let p=A,{then:h,catch:E,finally:I}=p;Object.setPrototypeOf(p,Object.getPrototypeOf(u)),Object.defineProperties(p,Object.getOwnPropertyDescriptors(u)),p.then=h,p.catch=E,p.finally=I}return A});let e=(o,a={},n)=>{var u,A;let p=0,h=E=>t.handlers[p++](E,p===t.handlers.length?xst:h);if(lle.default.plainObject(o)){let E={...o,...a};Eb.setNonEnumerableProperties([o,a],E),a=E,o=void 0}try{let E;try{ule(t.options.hooks.init,a),ule((u=a.hooks)===null||u===void 0?void 0:u.init,a)}catch(v){E=v}let I=yb(o,a,n??t.options);if(I[Eb.kIsNormalizedAlready]=!0,E)throw new zl.RequestError(E.message,E,I);return h(I)}catch(E){if(a.isStream)throw E;return Dst.default(E,t.options.hooks.beforeError,(A=a.hooks)===null||A===void 0?void 0:A.beforeError)}};e.extend=(...o)=>{let a=[t.options],n=[...t._rawHandlers],u;for(let A of o)kst(A)?(a.push(A.defaults.options),n.push(...A.defaults._rawHandlers),u=A.defaults.mutableDefaults):(a.push(A),\"handlers\"in A&&n.push(...A.handlers),u=A.mutableDefaults);return n=n.filter(A=>A!==Vl.defaultHandler),n.length===0&&n.push(Vl.defaultHandler),Ale({options:cle(...a),handlers:n,mutableDefaults:Boolean(u)})};let r=async function*(o,a){let n=yb(o,a,t.options);n.resolveBodyOnly=!1;let u=n.pagination;if(!lle.default.object(u))throw new TypeError(\"`options.pagination` must be implemented\");let A=[],{countLimit:p}=u,h=0;for(;h<u.requestLimit;){h!==0&&await bst(u.backoff);let E=await e(void 0,void 0,n),I=await u.transform(E),v=[];for(let C of I)if(u.filter(C,A,v)&&(!u.shouldContinue(C,A,v)||(yield C,u.stackAllItems&&A.push(C),v.push(C),--p<=0)))return;let x=u.paginate(E,A,v);if(x===!1)return;x===E.request.options?n=E.request.options:x!==void 0&&(n=yb(void 0,x,n)),h++}};e.paginate=r,e.paginate.all=async(o,a)=>{let n=[];for await(let u of r(o,a))n.push(u);return n},e.paginate.each=r,e.stream=(o,a)=>e(o,{...a,isStream:!0});for(let o of Qst)e[o]=(a,n)=>e(a,{...n,method:o}),e.stream[o]=(a,n)=>e(a,{...n,method:o,isStream:!0});return Object.assign(e,Sst),Object.defineProperty(e,\"defaults\",{value:t.mutableDefaults?t:Pst.default(t),writable:t.mutableDefaults,configurable:t.mutableDefaults,enumerable:!0}),e.mergeOptions=cle,e};Vl.default=Ale;vst(ale(),Vl)});var hle=_((Lf,Cb)=>{\"use strict\";var Fst=Lf&&Lf.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),fle=Lf&&Lf.__exportStar||function(t,e){for(var r in t)r!==\"default\"&&!Object.prototype.hasOwnProperty.call(e,r)&&Fst(e,t,r)};Object.defineProperty(Lf,\"__esModule\",{value:!0});var Rst=ve(\"url\"),ple=Q4(),Tst={options:{method:\"GET\",retry:{limit:2,methods:[\"GET\",\"PUT\",\"HEAD\",\"DELETE\",\"OPTIONS\",\"TRACE\"],statusCodes:[408,413,429,500,502,503,504,521,522,524],errorCodes:[\"ETIMEDOUT\",\"ECONNRESET\",\"EADDRINUSE\",\"ECONNREFUSED\",\"EPIPE\",\"ENOTFOUND\",\"ENETUNREACH\",\"EAI_AGAIN\"],maxRetryAfter:void 0,calculateDelay:({computedValue:t})=>t},timeout:{},headers:{\"user-agent\":\"got (https://github.com/sindresorhus/got)\"},hooks:{init:[],beforeRequest:[],beforeRedirect:[],beforeRetry:[],beforeError:[],afterResponse:[]},cache:void 0,dnsCache:void 0,decompress:!0,throwHttpErrors:!0,followRedirect:!0,isStream:!1,responseType:\"text\",resolveBodyOnly:!1,maxRedirects:10,prefixUrl:\"\",methodRewriting:!0,ignoreInvalidCookies:!1,context:{},http2:!1,allowGetBody:!1,https:void 0,pagination:{transform:t=>t.request.options.responseType===\"json\"?t.body:JSON.parse(t.body),paginate:t=>{if(!Reflect.has(t.headers,\"link\"))return!1;let e=t.headers.link.split(\",\"),r;for(let o of e){let a=o.split(\";\");if(a[1].includes(\"next\")){r=a[0].trimStart().trim(),r=r.slice(1,-1);break}}return r?{url:new Rst.URL(r)}:!1},filter:()=>!0,shouldContinue:()=>!0,countLimit:1/0,backoff:0,requestLimit:1e4,stackAllItems:!0},parseJson:t=>JSON.parse(t),stringifyJson:t=>JSON.stringify(t),cacheOptions:{}},handlers:[ple.defaultHandler],mutableDefaults:!1},F4=ple.default(Tst);Lf.default=F4;Cb.exports=F4;Cb.exports.default=F4;Cb.exports.__esModule=!0;fle(Q4(),Lf);fle(b4(),Lf)});var nn={};zt(nn,{Method:()=>wle,del:()=>Ust,get:()=>N4,getNetworkSettings:()=>Cle,post:()=>O4,put:()=>Mst,request:()=>I1});function mle(t){let e=new URL(t),r={host:e.hostname,headers:{}};return e.port&&(r.port=Number(e.port)),e.username&&e.password&&(r.proxyAuth=`${e.username}:${e.password}`),{proxy:r}}async function R4(t){return al(dle,t,()=>oe.readFilePromise(t).then(e=>(dle.set(t,e),e)))}function Ost({statusCode:t,statusMessage:e},r){let o=Ut(r,t,yt.NUMBER),a=`https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/${t}`;return Zy(r,`${o}${e?` (${e})`:\"\"}`,a)}async function wb(t,{configuration:e,customErrorMessage:r}){try{return await t}catch(o){if(o.name!==\"HTTPError\")throw o;let a=r?.(o,e)??o.response.body?.error;a==null&&(o.message.startsWith(\"Response code\")?a=\"The remote server failed to provide the requested resource\":a=o.message),o.code===\"ETIMEDOUT\"&&o.event===\"socket\"&&(a+=`(can be increased via ${Ut(e,\"httpTimeout\",yt.SETTING)})`);let n=new Jt(35,a,u=>{o.response&&u.reportError(35,`  ${Xu(e,{label:\"Response Code\",value:Hc(yt.NO_HINT,Ost(o.response,e))})}`),o.request&&(u.reportError(35,`  ${Xu(e,{label:\"Request Method\",value:Hc(yt.NO_HINT,o.request.options.method)})}`),u.reportError(35,`  ${Xu(e,{label:\"Request URL\",value:Hc(yt.URL,o.request.requestUrl)})}`)),o.request.redirects.length>0&&u.reportError(35,`  ${Xu(e,{label:\"Request Redirects\",value:Hc(yt.NO_HINT,bN(e,o.request.redirects,yt.URL))})}`),o.request.retryCount===o.request.options.retry.limit&&u.reportError(35,`  ${Xu(e,{label:\"Request Retry Count\",value:Hc(yt.NO_HINT,`${Ut(e,o.request.retryCount,yt.NUMBER)} (can be increased via ${Ut(e,\"httpRetry\",yt.SETTING)})`)})}`)});throw n.originalError=o,n}}function Cle(t,e){let r=[...e.configuration.get(\"networkSettings\")].sort(([u],[A])=>A.length-u.length),o={enableNetwork:void 0,httpsCaFilePath:void 0,httpProxy:void 0,httpsProxy:void 0,httpsKeyFilePath:void 0,httpsCertFilePath:void 0},a=Object.keys(o),n=typeof t==\"string\"?new URL(t):t;for(let[u,A]of r)if(L4.default.isMatch(n.hostname,u))for(let p of a){let h=A.get(p);h!==null&&typeof o[p]>\"u\"&&(o[p]=h)}for(let u of a)typeof o[u]>\"u\"&&(o[u]=e.configuration.get(u));return o}async function I1(t,e,{configuration:r,headers:o,jsonRequest:a,jsonResponse:n,method:u=\"GET\",wrapNetworkRequest:A}){let p={target:t,body:e,configuration:r,headers:o,jsonRequest:a,jsonResponse:n,method:u},h=async()=>await _st(t,e,p),E=typeof A<\"u\"?await A(h,p):h;return await(await r.reduceHook(v=>v.wrapNetworkRequest,E,p))()}async function N4(t,{configuration:e,jsonResponse:r,customErrorMessage:o,wrapNetworkRequest:a,...n}){let u=()=>wb(I1(t,null,{configuration:e,wrapNetworkRequest:a,...n}),{configuration:e,customErrorMessage:o}).then(p=>p.body),A=await(typeof a<\"u\"?u():al(gle,t,()=>u().then(p=>(gle.set(t,p),p))));return r?JSON.parse(A.toString()):A}async function Mst(t,e,{customErrorMessage:r,...o}){return(await wb(I1(t,e,{...o,method:\"PUT\"}),{customErrorMessage:r,configuration:o.configuration})).body}async function O4(t,e,{customErrorMessage:r,...o}){return(await wb(I1(t,e,{...o,method:\"POST\"}),{customErrorMessage:r,configuration:o.configuration})).body}async function Ust(t,{customErrorMessage:e,...r}){return(await wb(I1(t,null,{...r,method:\"DELETE\"}),{customErrorMessage:e,configuration:r.configuration})).body}async function _st(t,e,{configuration:r,headers:o,jsonRequest:a,jsonResponse:n,method:u=\"GET\"}){let A=typeof t==\"string\"?new URL(t):t,p=Cle(A,{configuration:r});if(p.enableNetwork===!1)throw new Jt(80,`Request to '${A.href}' has been blocked because of your configuration settings`);if(A.protocol===\"http:\"&&!L4.default.isMatch(A.hostname,r.get(\"unsafeHttpWhitelist\")))throw new Jt(81,`Unsafe http requests must be explicitly whitelisted in your configuration (${A.hostname})`);let E={agent:{http:p.httpProxy?T4.default.httpOverHttp(mle(p.httpProxy)):Lst,https:p.httpsProxy?T4.default.httpsOverHttp(mle(p.httpsProxy)):Nst},headers:o,method:u};E.responseType=n?\"json\":\"buffer\",e!==null&&(Buffer.isBuffer(e)||!a&&typeof e==\"string\"?E.body=e:E.json=e);let I=r.get(\"httpTimeout\"),v=r.get(\"httpRetry\"),x=r.get(\"enableStrictSsl\"),C=p.httpsCaFilePath,R=p.httpsCertFilePath,N=p.httpsKeyFilePath,{default:U}=await Promise.resolve().then(()=>$e(hle())),V=C?await R4(C):void 0,te=R?await R4(R):void 0,ae=N?await R4(N):void 0,fe=U.extend({timeout:{socket:I},retry:v,https:{rejectUnauthorized:x,certificateAuthority:V,certificate:te,key:ae},...E});return r.getLimit(\"networkConcurrency\")(()=>fe(A))}var yle,Ele,L4,T4,gle,dle,Lst,Nst,wle,Ib=Et(()=>{Pt();yle=ve(\"https\"),Ele=ve(\"http\"),L4=$e(Zo()),T4=$e(Yse());Wl();jl();Gl();gle=new Map,dle=new Map,Lst=new Ele.Agent({keepAlive:!0}),Nst=new yle.Agent({keepAlive:!0});wle=(a=>(a.GET=\"GET\",a.PUT=\"PUT\",a.POST=\"POST\",a.DELETE=\"DELETE\",a))(wle||{})});var Vi={};zt(Vi,{availableParallelism:()=>U4,getArchitecture:()=>B1,getArchitectureName:()=>Yst,getArchitectureSet:()=>M4,getCaller:()=>Vst,major:()=>Hst,openUrl:()=>qst});function jst(){if(process.platform===\"darwin\"||process.platform===\"win32\")return null;let t;try{t=oe.readFileSync(Gst)}catch{}if(typeof t<\"u\"){if(t&&(t.includes(\"GLIBC\")||t.includes(\"libc\")))return\"glibc\";if(t&&t.includes(\"musl\"))return\"musl\"}let r=(process.report?.getReport()??{}).sharedObjects??[],o=/\\/(?:(ld-linux-|[^/]+-linux-gnu\\/)|(libc.musl-|ld-musl-))/;return KI(r,a=>{let n=a.match(o);if(!n)return KI.skip;if(n[1])return\"glibc\";if(n[2])return\"musl\";throw new Error(\"Assertion failed: Expected the libc variant to have been detected\")})??null}function B1(){return Ble=Ble??{os:process.platform,cpu:process.arch,libc:jst()}}function Yst(t=B1()){return t.libc?`${t.os}-${t.cpu}-${t.libc}`:`${t.os}-${t.cpu}`}function M4(){let t=B1();return vle=vle??{os:[t.os],cpu:[t.cpu],libc:t.libc?[t.libc]:[]}}function zst(t){let e=Wst.exec(t);if(!e)return null;let r=e[2]&&e[2].indexOf(\"native\")===0,o=e[2]&&e[2].indexOf(\"eval\")===0,a=Kst.exec(e[2]);return o&&a!=null&&(e[2]=a[1],e[3]=a[2],e[4]=a[3]),{file:r?null:e[2],methodName:e[1]||\"<unknown>\",arguments:r?[e[2]]:[],line:e[3]?+e[3]:null,column:e[4]?+e[4]:null}}function Vst(){let e=new Error().stack.split(`\n`)[3];return zst(e)}function U4(){return typeof Bb.default.availableParallelism<\"u\"?Bb.default.availableParallelism():Math.max(1,Bb.default.cpus().length)}var Bb,Hst,Ile,qst,Gst,Ble,vle,Wst,Kst,vb=Et(()=>{Pt();Bb=$e(ve(\"os\"));Db();Gl();Hst=Number(process.versions.node.split(\".\")[0]),Ile=new Map([[\"darwin\",\"open\"],[\"linux\",\"xdg-open\"],[\"win32\",\"explorer.exe\"]]).get(process.platform),qst=typeof Ile<\"u\"?async t=>{try{return await _4(Ile,[t],{cwd:z.cwd()}),!0}catch{return!1}}:void 0,Gst=\"/usr/bin/ldd\";Wst=/^\\s*at (.*?) ?\\(((?:file|https?|blob|chrome-extension|native|eval|webpack|<anonymous>|\\/|[a-z]:\\\\|\\\\\\\\).*?)(?::(\\d+))?(?::(\\d+))?\\)?\\s*$/i,Kst=/\\((\\S*)(?::(\\d+))(?::(\\d+))\\)/});function Y4(t,e,r,o,a){let n=A1(r);if(o.isArray||o.type===\"ANY\"&&Array.isArray(n))return Array.isArray(n)?n.map((u,A)=>H4(t,`${e}[${A}]`,u,o,a)):String(n).split(/,/).map(u=>H4(t,e,u,o,a));if(Array.isArray(n))throw new Error(`Non-array configuration settings \"${e}\" cannot be an array`);return H4(t,e,r,o,a)}function H4(t,e,r,o,a){let n=A1(r);switch(o.type){case\"ANY\":return jS(n);case\"SHAPE\":return $st(t,e,r,o,a);case\"MAP\":return eot(t,e,r,o,a)}if(n===null&&!o.isNullable&&o.default!==null)throw new Error(`Non-nullable configuration settings \"${e}\" cannot be set to null`);if(o.values?.includes(n))return n;let A=(()=>{if(o.type===\"BOOLEAN\"&&typeof n!=\"string\")return zI(n);if(typeof n!=\"string\")throw new Error(`Expected configuration setting \"${e}\" to be a string, got ${typeof n}`);let p=iS(n,{env:t.env});switch(o.type){case\"ABSOLUTE_PATH\":{let h=a,E=mM(r);return E&&E[0]!==\"<\"&&(h=z.dirname(E)),z.resolve(h,le.toPortablePath(p))}case\"LOCATOR_LOOSE\":return xf(p,!1);case\"NUMBER\":return parseInt(p);case\"LOCATOR\":return xf(p);case\"BOOLEAN\":return zI(p);default:return p}})();if(o.values&&!o.values.includes(A))throw new Error(`Invalid value, expected one of ${o.values.join(\", \")}`);return A}function $st(t,e,r,o,a){let n=A1(r);if(typeof n!=\"object\"||Array.isArray(n))throw new it(`Object configuration settings \"${e}\" must be an object`);let u=W4(t,o,{ignoreArrays:!0});if(n===null)return u;for(let[A,p]of Object.entries(n)){let h=`${e}.${A}`;if(!o.properties[A])throw new it(`Unrecognized configuration settings found: ${e}.${A} - run \"yarn config -v\" to see the list of settings supported in Yarn`);u.set(A,Y4(t,h,p,o.properties[A],a))}return u}function eot(t,e,r,o,a){let n=A1(r),u=new Map;if(typeof n!=\"object\"||Array.isArray(n))throw new it(`Map configuration settings \"${e}\" must be an object`);if(n===null)return u;for(let[A,p]of Object.entries(n)){let h=o.normalizeKeys?o.normalizeKeys(A):A,E=`${e}['${h}']`,I=o.valueDefinition;u.set(h,Y4(t,E,p,I,a))}return u}function W4(t,e,{ignoreArrays:r=!1}={}){switch(e.type){case\"SHAPE\":{if(e.isArray&&!r)return[];let o=new Map;for(let[a,n]of Object.entries(e.properties))o.set(a,W4(t,n));return o}case\"MAP\":return e.isArray&&!r?[]:new Map;case\"ABSOLUTE_PATH\":return e.default===null?null:t.projectCwd===null?Array.isArray(e.default)?e.default.map(o=>z.normalize(o)):z.isAbsolute(e.default)?z.normalize(e.default):e.isNullable?null:void 0:Array.isArray(e.default)?e.default.map(o=>z.resolve(t.projectCwd,o)):z.resolve(t.projectCwd,e.default);default:return e.default}}function Sb(t,e,r){if(e.type===\"SECRET\"&&typeof t==\"string\"&&r.hideSecrets)return Zst;if(e.type===\"ABSOLUTE_PATH\"&&typeof t==\"string\"&&r.getNativePaths)return le.fromPortablePath(t);if(e.isArray&&Array.isArray(t)){let o=[];for(let a of t)o.push(Sb(a,e,r));return o}if(e.type===\"MAP\"&&t instanceof Map){if(t.size===0)return;let o=new Map;for(let[a,n]of t.entries()){let u=Sb(n,e.valueDefinition,r);typeof u<\"u\"&&o.set(a,u)}return o}if(e.type===\"SHAPE\"&&t instanceof Map){if(t.size===0)return;let o=new Map;for(let[a,n]of t.entries()){let u=e.properties[a],A=Sb(n,u,r);typeof A<\"u\"&&o.set(a,A)}return o}return t}function tot(){let t={};for(let[e,r]of Object.entries(process.env))e=e.toLowerCase(),e.startsWith(bb)&&(e=(0,Ple.default)(e.slice(bb.length)),t[e]=r);return t}function G4(){let t=`${bb}rc_filename`;for(let[e,r]of Object.entries(process.env))if(e.toLowerCase()===t&&typeof r==\"string\")return r;return j4}async function Dle(t){try{return await oe.readFilePromise(t)}catch{return Buffer.of()}}async function rot(t,e){return Buffer.compare(...await Promise.all([Dle(t),Dle(e)]))===0}async function not(t,e){let[r,o]=await Promise.all([oe.statPromise(t),oe.statPromise(e)]);return r.dev===o.dev&&r.ino===o.ino}async function sot({configuration:t,selfPath:e}){let r=t.get(\"yarnPath\");return t.get(\"ignorePath\")||r===null||r===e||await iot(r,e)?null:r}var Ple,Nf,Sle,ble,xle,q4,Jst,v1,Xst,FE,bb,j4,Zst,D1,kle,xb,Pb,iot,nA,Ke,P1=Et(()=>{Pt();Nl();Ple=$e(sz()),Nf=$e(rd());qt();Sle=$e(Zz()),ble=ve(\"module\"),xle=$e(sd()),q4=ve(\"stream\");ose();fE();cM();uM();AM();Tse();fM();Dd();Use();WS();jl();ih();Ib();Gl();vb();Qf();bo();Jst=function(){if(!Nf.GITHUB_ACTIONS||!process.env.GITHUB_EVENT_PATH)return!1;let t=le.toPortablePath(process.env.GITHUB_EVENT_PATH),e;try{e=oe.readJsonSync(t)}catch{return!1}return!(!(\"repository\"in e)||!e.repository||(e.repository.private??!0))}(),v1=new Set([\"@yarnpkg/plugin-constraints\",\"@yarnpkg/plugin-exec\",\"@yarnpkg/plugin-interactive-tools\",\"@yarnpkg/plugin-stage\",\"@yarnpkg/plugin-typescript\",\"@yarnpkg/plugin-version\",\"@yarnpkg/plugin-workspace-tools\"]),Xst=new Set([\"isTestEnv\",\"injectNpmUser\",\"injectNpmPassword\",\"injectNpm2FaToken\",\"zipDataEpilogue\",\"cacheCheckpointOverride\",\"cacheVersionOverride\",\"lockfileVersionOverride\",\"binFolder\",\"version\",\"flags\",\"profile\",\"gpg\",\"ignoreNode\",\"wrapOutput\",\"home\",\"confDir\",\"registry\",\"ignoreCwd\"]),FE=/^(?!v)[a-z0-9._-]+$/i,bb=\"yarn_\",j4=\".yarnrc.yml\",Zst=\"********\",D1=(E=>(E.ANY=\"ANY\",E.BOOLEAN=\"BOOLEAN\",E.ABSOLUTE_PATH=\"ABSOLUTE_PATH\",E.LOCATOR=\"LOCATOR\",E.LOCATOR_LOOSE=\"LOCATOR_LOOSE\",E.NUMBER=\"NUMBER\",E.STRING=\"STRING\",E.SECRET=\"SECRET\",E.SHAPE=\"SHAPE\",E.MAP=\"MAP\",E))(D1||{}),kle=yt,xb=(r=>(r.JUNCTIONS=\"junctions\",r.SYMLINKS=\"symlinks\",r))(xb||{}),Pb={lastUpdateCheck:{description:\"Last timestamp we checked whether new Yarn versions were available\",type:\"STRING\",default:null},yarnPath:{description:\"Path to the local executable that must be used over the global one\",type:\"ABSOLUTE_PATH\",default:null},ignorePath:{description:\"If true, the local executable will be ignored when using the global one\",type:\"BOOLEAN\",default:!1},globalFolder:{description:\"Folder where all system-global files are stored\",type:\"ABSOLUTE_PATH\",default:EM()},cacheFolder:{description:\"Folder where the cache files must be written\",type:\"ABSOLUTE_PATH\",default:\"./.yarn/cache\"},compressionLevel:{description:\"Zip files compression level, from 0 to 9 or mixed (a variant of 9, which stores some files uncompressed, when compression doesn't yield good results)\",type:\"NUMBER\",values:[\"mixed\",0,1,2,3,4,5,6,7,8,9],default:0},virtualFolder:{description:\"Folder where the virtual packages (cf doc) will be mapped on the disk (must be named __virtual__)\",type:\"ABSOLUTE_PATH\",default:\"./.yarn/__virtual__\"},installStatePath:{description:\"Path of the file where the install state will be persisted\",type:\"ABSOLUTE_PATH\",default:\"./.yarn/install-state.gz\"},immutablePatterns:{description:\"Array of glob patterns; files matching them won't be allowed to change during immutable installs\",type:\"STRING\",default:[],isArray:!0},rcFilename:{description:\"Name of the files where the configuration can be found\",type:\"STRING\",default:G4()},enableGlobalCache:{description:\"If true, the system-wide cache folder will be used regardless of `cache-folder`\",type:\"BOOLEAN\",default:!0},cacheMigrationMode:{description:\"Defines the conditions under which Yarn upgrades should cause the cache archives to be regenerated.\",type:\"STRING\",values:[\"always\",\"match-spec\",\"required-only\"],default:\"always\"},enableColors:{description:\"If true, the CLI is allowed to use colors in its output\",type:\"BOOLEAN\",default:aS,defaultText:\"<dynamic>\"},enableHyperlinks:{description:\"If true, the CLI is allowed to use hyperlinks in its output\",type:\"BOOLEAN\",default:SN,defaultText:\"<dynamic>\"},enableInlineBuilds:{description:\"If true, the CLI will print the build output on the command line\",type:\"BOOLEAN\",default:Nf.isCI,defaultText:\"<dynamic>\"},enableMessageNames:{description:\"If true, the CLI will prefix most messages with codes suitable for search engines\",type:\"BOOLEAN\",default:!0},enableProgressBars:{description:\"If true, the CLI is allowed to show a progress bar for long-running events\",type:\"BOOLEAN\",default:!Nf.isCI,defaultText:\"<dynamic>\"},enableTimers:{description:\"If true, the CLI is allowed to print the time spent executing commands\",type:\"BOOLEAN\",default:!0},enableTips:{description:\"If true, installs will print a helpful message every day of the week\",type:\"BOOLEAN\",default:!Nf.isCI,defaultText:\"<dynamic>\"},preferInteractive:{description:\"If true, the CLI will automatically use the interactive mode when called from a TTY\",type:\"BOOLEAN\",default:!1},preferTruncatedLines:{description:\"If true, the CLI will truncate lines that would go beyond the size of the terminal\",type:\"BOOLEAN\",default:!1},progressBarStyle:{description:\"Which style of progress bar should be used (only when progress bars are enabled)\",type:\"STRING\",default:void 0,defaultText:\"<dynamic>\"},defaultLanguageName:{description:\"Default language mode that should be used when a package doesn't offer any insight\",type:\"STRING\",default:\"node\"},defaultProtocol:{description:\"Default resolution protocol used when resolving pure semver and tag ranges\",type:\"STRING\",default:\"npm:\"},enableTransparentWorkspaces:{description:\"If false, Yarn won't automatically resolve workspace dependencies unless they use the `workspace:` protocol\",type:\"BOOLEAN\",default:!0},supportedArchitectures:{description:\"Architectures that Yarn will fetch and inject into the resolver\",type:\"SHAPE\",properties:{os:{description:\"Array of supported process.platform strings, or null to target them all\",type:\"STRING\",isArray:!0,isNullable:!0,default:[\"current\"]},cpu:{description:\"Array of supported process.arch strings, or null to target them all\",type:\"STRING\",isArray:!0,isNullable:!0,default:[\"current\"]},libc:{description:\"Array of supported libc libraries, or null to target them all\",type:\"STRING\",isArray:!0,isNullable:!0,default:[\"current\"]}}},enableMirror:{description:\"If true, the downloaded packages will be retrieved and stored in both the local and global folders\",type:\"BOOLEAN\",default:!0},enableNetwork:{description:\"If false, Yarn will refuse to use the network if required to\",type:\"BOOLEAN\",default:!0},enableOfflineMode:{description:\"If true, Yarn will attempt to retrieve files and metadata from the global cache rather than the network\",type:\"BOOLEAN\",default:!1},httpProxy:{description:\"URL of the http proxy that must be used for outgoing http requests\",type:\"STRING\",default:null},httpsProxy:{description:\"URL of the http proxy that must be used for outgoing https requests\",type:\"STRING\",default:null},unsafeHttpWhitelist:{description:\"List of the hostnames for which http queries are allowed (glob patterns are supported)\",type:\"STRING\",default:[],isArray:!0},httpTimeout:{description:\"Timeout of each http request in milliseconds\",type:\"NUMBER\",default:6e4},httpRetry:{description:\"Retry times on http failure\",type:\"NUMBER\",default:3},networkConcurrency:{description:\"Maximal number of concurrent requests\",type:\"NUMBER\",default:50},taskPoolConcurrency:{description:\"Maximal amount of concurrent heavy task processing\",type:\"NUMBER\",default:U4()},taskPoolMode:{description:\"Execution strategy for heavy tasks\",type:\"STRING\",values:[\"async\",\"workers\"],default:\"workers\"},networkSettings:{description:\"Network settings per hostname (glob patterns are supported)\",type:\"MAP\",valueDefinition:{description:\"\",type:\"SHAPE\",properties:{httpsCaFilePath:{description:\"Path to file containing one or multiple Certificate Authority signing certificates\",type:\"ABSOLUTE_PATH\",default:null},enableNetwork:{description:\"If false, the package manager will refuse to use the network if required to\",type:\"BOOLEAN\",default:null},httpProxy:{description:\"URL of the http proxy that must be used for outgoing http requests\",type:\"STRING\",default:null},httpsProxy:{description:\"URL of the http proxy that must be used for outgoing https requests\",type:\"STRING\",default:null},httpsKeyFilePath:{description:\"Path to file containing private key in PEM format\",type:\"ABSOLUTE_PATH\",default:null},httpsCertFilePath:{description:\"Path to file containing certificate chain in PEM format\",type:\"ABSOLUTE_PATH\",default:null}}}},httpsCaFilePath:{description:\"A path to a file containing one or multiple Certificate Authority signing certificates\",type:\"ABSOLUTE_PATH\",default:null},httpsKeyFilePath:{description:\"Path to file containing private key in PEM format\",type:\"ABSOLUTE_PATH\",default:null},httpsCertFilePath:{description:\"Path to file containing certificate chain in PEM format\",type:\"ABSOLUTE_PATH\",default:null},enableStrictSsl:{description:\"If false, SSL certificate errors will be ignored\",type:\"BOOLEAN\",default:!0},logFilters:{description:\"Overrides for log levels\",type:\"SHAPE\",isArray:!0,concatenateValues:!0,properties:{code:{description:\"Code of the messages covered by this override\",type:\"STRING\",default:void 0},text:{description:\"Code of the texts covered by this override\",type:\"STRING\",default:void 0},pattern:{description:\"Code of the patterns covered by this override\",type:\"STRING\",default:void 0},level:{description:\"Log level override, set to null to remove override\",type:\"STRING\",values:Object.values(cS),isNullable:!0,default:void 0}}},enableTelemetry:{description:\"If true, telemetry will be periodically sent, following the rules in https://yarnpkg.com/advanced/telemetry\",type:\"BOOLEAN\",default:!0},telemetryInterval:{description:\"Minimal amount of time between two telemetry uploads, in days\",type:\"NUMBER\",default:7},telemetryUserId:{description:\"If you desire to tell us which project you are, you can set this field. Completely optional and opt-in.\",type:\"STRING\",default:null},enableHardenedMode:{description:\"If true, automatically enable --check-resolutions --refresh-lockfile on installs\",type:\"BOOLEAN\",default:Nf.isPR&&Jst,defaultText:\"<true on public PRs>\"},enableScripts:{description:\"If true, packages are allowed to have install scripts by default\",type:\"BOOLEAN\",default:!0},enableStrictSettings:{description:\"If true, unknown settings will cause Yarn to abort\",type:\"BOOLEAN\",default:!0},enableImmutableCache:{description:\"If true, the cache is reputed immutable and actions that would modify it will throw\",type:\"BOOLEAN\",default:!1},checksumBehavior:{description:\"Enumeration defining what to do when a checksum doesn't match expectations\",type:\"STRING\",default:\"throw\"},injectEnvironmentFiles:{description:\"List of all the environment files that Yarn should inject inside the process when it starts\",type:\"ABSOLUTE_PATH\",default:[\".env.yarn?\"],isArray:!0},packageExtensions:{description:\"Map of package corrections to apply on the dependency tree\",type:\"MAP\",valueDefinition:{description:\"The extension that will be applied to any package whose version matches the specified range\",type:\"SHAPE\",properties:{dependencies:{description:\"The set of dependencies that must be made available to the current package in order for it to work properly\",type:\"MAP\",valueDefinition:{description:\"A range\",type:\"STRING\"}},peerDependencies:{description:\"Inherited dependencies - the consumer of the package will be tasked to provide them\",type:\"MAP\",valueDefinition:{description:\"A semver range\",type:\"STRING\"}},peerDependenciesMeta:{description:\"Extra information related to the dependencies listed in the peerDependencies field\",type:\"MAP\",valueDefinition:{description:\"The peerDependency meta\",type:\"SHAPE\",properties:{optional:{description:\"If true, the selected peer dependency will be marked as optional by the package manager and the consumer omitting it won't be reported as an error\",type:\"BOOLEAN\",default:!1}}}}}}}};iot=process.platform===\"win32\"?rot:not;nA=class{constructor(e){this.isCI=Nf.isCI;this.projectCwd=null;this.plugins=new Map;this.settings=new Map;this.values=new Map;this.sources=new Map;this.invalid=new Map;this.env={};this.limits=new Map;this.packageExtensions=null;this.startingCwd=e}static create(e,r,o){let a=new nA(e);typeof r<\"u\"&&!(r instanceof Map)&&(a.projectCwd=r),a.importSettings(Pb);let n=typeof o<\"u\"?o:r instanceof Map?r:new Map;for(let[u,A]of n)a.activatePlugin(u,A);return a}static async find(e,r,{strict:o=!0,usePathCheck:a=null,useRc:n=!0}={}){let u=tot();delete u.rcFilename;let A=new nA(e),p=await nA.findRcFiles(e),h=await nA.findFolderRcFile(EE());h&&(p.find(me=>me.path===h.path)||p.unshift(h));let E=Mse(p.map(ue=>[ue.path,ue.data])),I=Bt.dot,v=new Set(Object.keys(Pb)),x=({yarnPath:ue,ignorePath:me,injectEnvironmentFiles:he})=>({yarnPath:ue,ignorePath:me,injectEnvironmentFiles:he}),C=({yarnPath:ue,ignorePath:me,injectEnvironmentFiles:he,...Be})=>{let we={};for(let[g,Ee]of Object.entries(Be))v.has(g)&&(we[g]=Ee);return we},R=({yarnPath:ue,ignorePath:me,...he})=>{let Be={};for(let[we,g]of Object.entries(he))v.has(we)||(Be[we]=g);return Be};if(A.importSettings(x(Pb)),A.useWithSource(\"<environment>\",x(u),e,{strict:!1}),E){let[ue,me]=E;A.useWithSource(ue,x(me),I,{strict:!1})}if(a){if(await sot({configuration:A,selfPath:a})!==null)return A;A.useWithSource(\"<override>\",{ignorePath:!0},e,{strict:!1,overwrite:!0})}let N=await nA.findProjectCwd(e);A.startingCwd=e,A.projectCwd=N;let U=Object.assign(Object.create(null),process.env);A.env=U;let V=await Promise.all(A.get(\"injectEnvironmentFiles\").map(async ue=>{let me=ue.endsWith(\"?\")?await oe.readFilePromise(ue.slice(0,-1),\"utf8\").catch(()=>\"\"):await oe.readFilePromise(ue,\"utf8\");return(0,Sle.parse)(me)}));for(let ue of V)for(let[me,he]of Object.entries(ue))A.env[me]=iS(he,{env:U});if(A.importSettings(C(Pb)),A.useWithSource(\"<environment>\",C(u),e,{strict:o}),E){let[ue,me]=E;A.useWithSource(ue,C(me),I,{strict:o})}let te=ue=>\"default\"in ue?ue.default:ue,ae=new Map([[\"@@core\",sse]]);if(r!==null)for(let ue of r.plugins.keys())ae.set(ue,te(r.modules.get(ue)));for(let[ue,me]of ae)A.activatePlugin(ue,me);let fe=new Map([]);if(r!==null){let ue=new Map;for(let Be of ble.builtinModules)ue.set(Be,()=>Df(Be));for(let[Be,we]of r.modules)ue.set(Be,()=>we);let me=new Set,he=async(Be,we)=>{let{factory:g,name:Ee}=Df(Be);if(!g||me.has(Ee))return;let Pe=new Map(ue),ce=ee=>{if(Pe.has(ee))return Pe.get(ee)();throw new it(`This plugin cannot access the package referenced via ${ee} which is neither a builtin, nor an exposed entry`)},ne=await Ky(async()=>te(await g(ce)),ee=>`${ee} (when initializing ${Ee}, defined in ${we})`);ue.set(Ee,()=>ne),me.add(Ee),fe.set(Ee,ne)};if(u.plugins)for(let Be of u.plugins.split(\";\")){let we=z.resolve(e,le.toPortablePath(Be));await he(we,\"<environment>\")}for(let{path:Be,cwd:we,data:g}of p)if(!!n&&!!Array.isArray(g.plugins))for(let Ee of g.plugins){let Pe=typeof Ee!=\"string\"?Ee.path:Ee,ce=Ee?.spec??\"\",ne=Ee?.checksum??\"\";if(v1.has(ce))continue;let ee=z.resolve(we,le.toPortablePath(Pe));if(!await oe.existsPromise(ee)){if(!ce){let At=Ut(A,z.basename(ee,\".cjs\"),yt.NAME),H=Ut(A,\".gitignore\",yt.NAME),at=Ut(A,A.values.get(\"rcFilename\"),yt.NAME),Re=Ut(A,\"https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored\",yt.URL);throw new it(`Missing source for the ${At} plugin - please try to remove the plugin from ${at} then reinstall it manually. This error usually occurs because ${H} is incorrect, check ${Re} to make sure your plugin folder isn't gitignored.`)}if(!ce.match(/^https?:/)){let At=Ut(A,z.basename(ee,\".cjs\"),yt.NAME),H=Ut(A,A.values.get(\"rcFilename\"),yt.NAME);throw new it(`Failed to recognize the source for the ${At} plugin - please try to delete the plugin from ${H} then reinstall it manually.`)}let Ie=await N4(ce,{configuration:A}),Fe=Js(Ie);if(ne&&ne!==Fe){let At=Ut(A,z.basename(ee,\".cjs\"),yt.NAME),H=Ut(A,A.values.get(\"rcFilename\"),yt.NAME),at=Ut(A,`yarn plugin import ${ce}`,yt.CODE);throw new it(`Failed to fetch the ${At} plugin from its remote location: its checksum seems to have changed. If this is expected, please remove the plugin from ${H} then run ${at} to reimport it.`)}await oe.mkdirPromise(z.dirname(ee),{recursive:!0}),await oe.writeFilePromise(ee,Ie)}await he(ee,Be)}}for(let[ue,me]of fe)A.activatePlugin(ue,me);if(A.useWithSource(\"<environment>\",R(u),e,{strict:o}),E){let[ue,me]=E;A.useWithSource(ue,R(me),I,{strict:o})}return A.get(\"enableGlobalCache\")&&(A.values.set(\"cacheFolder\",`${A.get(\"globalFolder\")}/cache`),A.sources.set(\"cacheFolder\",\"<internal>\")),A}static async findRcFiles(e){let r=G4(),o=[],a=e,n=null;for(;a!==n;){n=a;let u=z.join(n,r);if(oe.existsSync(u)){let A=await oe.readFilePromise(u,\"utf8\"),p;try{p=Ki(A)}catch{let E=\"\";throw A.match(/^\\s+(?!-)[^:]+\\s+\\S+/m)&&(E=\" (in particular, make sure you list the colons after each key name)\"),new it(`Parse error when loading ${u}; please check it's proper Yaml${E}`)}o.unshift({path:u,cwd:n,data:p})}a=z.dirname(n)}return o}static async findFolderRcFile(e){let r=z.join(e,dr.rc),o;try{o=await oe.readFilePromise(r,\"utf8\")}catch(n){if(n.code===\"ENOENT\")return null;throw n}let a=Ki(o);return{path:r,cwd:e,data:a}}static async findProjectCwd(e){let r=null,o=e,a=null;for(;o!==a;){if(a=o,oe.existsSync(z.join(a,dr.lockfile)))return a;oe.existsSync(z.join(a,dr.manifest))&&(r=a),o=z.dirname(a)}return r}static async updateConfiguration(e,r,o={}){let a=G4(),n=z.join(e,a),u=oe.existsSync(n)?Ki(await oe.readFilePromise(n,\"utf8\")):{},A=!1,p;if(typeof r==\"function\"){try{p=r(u)}catch{p=r({})}if(p===u)return!1}else{p=u;for(let h of Object.keys(r)){let E=u[h],I=r[h],v;if(typeof I==\"function\")try{v=I(E)}catch{v=I(void 0)}else v=I;E!==v&&(v===nA.deleteProperty?delete p[h]:p[h]=v,A=!0)}if(!A)return!1}return await oe.changeFilePromise(n,Ba(p),{automaticNewlines:!0}),!0}static async addPlugin(e,r){r.length!==0&&await nA.updateConfiguration(e,o=>{let a=o.plugins??[];if(a.length===0)return{...o,plugins:r};let n=[],u=[...r];for(let A of a){let p=typeof A!=\"string\"?A.path:A,h=u.find(E=>E.path===p);h?(n.push(h),u=u.filter(E=>E!==h)):n.push(A)}return n.push(...u),{...o,plugins:n}})}static async updateHomeConfiguration(e){let r=EE();return await nA.updateConfiguration(r,e)}activatePlugin(e,r){this.plugins.set(e,r),typeof r.configuration<\"u\"&&this.importSettings(r.configuration)}importSettings(e){for(let[r,o]of Object.entries(e))if(o!=null){if(this.settings.has(r))throw new Error(`Cannot redefine settings \"${r}\"`);this.settings.set(r,o),this.values.set(r,W4(this,o))}}useWithSource(e,r,o,a){try{this.use(e,r,o,a)}catch(n){throw n.message+=` (in ${Ut(this,e,yt.PATH)})`,n}}use(e,r,o,{strict:a=!0,overwrite:n=!1}={}){a=a&&this.get(\"enableStrictSettings\");for(let u of[\"enableStrictSettings\",...Object.keys(r)]){let A=r[u],p=mM(A);if(p&&(e=p),typeof A>\"u\"||u===\"plugins\"||e===\"<environment>\"&&Xst.has(u))continue;if(u===\"rcFilename\")throw new it(`The rcFilename settings can only be set via ${`${bb}RC_FILENAME`.toUpperCase()}, not via a rc file`);let h=this.settings.get(u);if(!h){let I=EE(),v=e[0]!==\"<\"?z.dirname(e):null;if(a&&!(v!==null?I===v:!1))throw new it(`Unrecognized or legacy configuration settings found: ${u} - run \"yarn config -v\" to see the list of settings supported in Yarn`);this.invalid.set(u,e);continue}if(this.sources.has(u)&&!(n||h.type===\"MAP\"||h.isArray&&h.concatenateValues))continue;let E;try{E=Y4(this,u,A,h,o)}catch(I){throw I.message+=` in ${Ut(this,e,yt.PATH)}`,I}if(u===\"enableStrictSettings\"&&e!==\"<environment>\"){a=E;continue}if(h.type===\"MAP\"){let I=this.values.get(u);this.values.set(u,new Map(n?[...I,...E]:[...E,...I])),this.sources.set(u,`${this.sources.get(u)}, ${e}`)}else if(h.isArray&&h.concatenateValues){let I=this.values.get(u);this.values.set(u,n?[...I,...E]:[...E,...I]),this.sources.set(u,`${this.sources.get(u)}, ${e}`)}else this.values.set(u,E),this.sources.set(u,e)}}get(e){if(!this.values.has(e))throw new Error(`Invalid configuration key \"${e}\"`);return this.values.get(e)}getSpecial(e,{hideSecrets:r=!1,getNativePaths:o=!1}){let a=this.get(e),n=this.settings.get(e);if(typeof n>\"u\")throw new it(`Couldn't find a configuration settings named \"${e}\"`);return Sb(a,n,{hideSecrets:r,getNativePaths:o})}getSubprocessStreams(e,{header:r,prefix:o,report:a}){let n,u,A=oe.createWriteStream(e);if(this.get(\"enableInlineBuilds\")){let p=a.createStreamReporter(`${o} ${Ut(this,\"STDOUT\",\"green\")}`),h=a.createStreamReporter(`${o} ${Ut(this,\"STDERR\",\"red\")}`);n=new q4.PassThrough,n.pipe(p),n.pipe(A),u=new q4.PassThrough,u.pipe(h),u.pipe(A)}else n=A,u=A,typeof r<\"u\"&&n.write(`${r}\n`);return{stdout:n,stderr:u}}makeResolver(){let e=[];for(let r of this.plugins.values())for(let o of r.resolvers||[])e.push(new o);return new Pd([new c1,new Xn,...e])}makeFetcher(){let e=[];for(let r of this.plugins.values())for(let o of r.fetchers||[])e.push(new o);return new hE([new gE,new mE,...e])}getLinkers(){let e=[];for(let r of this.plugins.values())for(let o of r.linkers||[])e.push(new o);return e}getSupportedArchitectures(){let e=B1(),r=this.get(\"supportedArchitectures\"),o=r.get(\"os\");o!==null&&(o=o.map(u=>u===\"current\"?e.os:u));let a=r.get(\"cpu\");a!==null&&(a=a.map(u=>u===\"current\"?e.cpu:u));let n=r.get(\"libc\");return n!==null&&(n=ol(n,u=>u===\"current\"?e.libc??ol.skip:u)),{os:o,cpu:a,libc:n}}async getPackageExtensions(){if(this.packageExtensions!==null)return this.packageExtensions;this.packageExtensions=new Map;let e=this.packageExtensions,r=(o,a,{userProvided:n=!1}={})=>{if(!xa(o.range))throw new Error(\"Only semver ranges are allowed as keys for the packageExtensions setting\");let u=new Ot;u.load(a,{yamlCompatibilityMode:!0});let A=Yy(e,o.identHash),p=[];A.push([o.range,p]);let h={status:\"inactive\",userProvided:n,parentDescriptor:o};for(let E of u.dependencies.values())p.push({...h,type:\"Dependency\",descriptor:E});for(let E of u.peerDependencies.values())p.push({...h,type:\"PeerDependency\",descriptor:E});for(let[E,I]of u.peerDependenciesMeta)for(let[v,x]of Object.entries(I))p.push({...h,type:\"PeerDependencyMeta\",selector:E,key:v,value:x})};await this.triggerHook(o=>o.registerPackageExtensions,this,r);for(let[o,a]of this.get(\"packageExtensions\"))r(sh(o,!0),nS(a),{userProvided:!0});return e}normalizeLocator(e){return xa(e.reference)?Qs(e,`${this.get(\"defaultProtocol\")}${e.reference}`):FE.test(e.reference)?Qs(e,`${this.get(\"defaultProtocol\")}${e.reference}`):e}normalizeDependency(e){return xa(e.range)?In(e,`${this.get(\"defaultProtocol\")}${e.range}`):FE.test(e.range)?In(e,`${this.get(\"defaultProtocol\")}${e.range}`):e}normalizeDependencyMap(e){return new Map([...e].map(([r,o])=>[r,this.normalizeDependency(o)]))}normalizePackage(e,{packageExtensions:r}){let o=e1(e),a=r.get(e.identHash);if(typeof a<\"u\"){let u=e.version;if(u!==null){for(let[A,p]of a)if(!!kf(u,A))for(let h of p)switch(h.status===\"inactive\"&&(h.status=\"redundant\"),h.type){case\"Dependency\":typeof o.dependencies.get(h.descriptor.identHash)>\"u\"&&(h.status=\"active\",o.dependencies.set(h.descriptor.identHash,this.normalizeDependency(h.descriptor)));break;case\"PeerDependency\":typeof o.peerDependencies.get(h.descriptor.identHash)>\"u\"&&(h.status=\"active\",o.peerDependencies.set(h.descriptor.identHash,h.descriptor));break;case\"PeerDependencyMeta\":{let E=o.peerDependenciesMeta.get(h.selector);(typeof E>\"u\"||!Object.hasOwn(E,h.key)||E[h.key]!==h.value)&&(h.status=\"active\",al(o.peerDependenciesMeta,h.selector,()=>({}))[h.key]=h.value)}break;default:EN(h)}}}let n=u=>u.scope?`${u.scope}__${u.name}`:`${u.name}`;for(let u of o.peerDependenciesMeta.keys()){let A=Vs(u);o.peerDependencies.has(A.identHash)||o.peerDependencies.set(A.identHash,In(A,\"*\"))}for(let u of o.peerDependencies.values()){if(u.scope===\"types\")continue;let A=n(u),p=tA(\"types\",A),h=fn(p);o.peerDependencies.has(p.identHash)||o.peerDependenciesMeta.has(h)||(o.peerDependencies.set(p.identHash,In(p,\"*\")),o.peerDependenciesMeta.set(h,{optional:!0}))}return o.dependencies=new Map(ks(o.dependencies,([,u])=>Sa(u))),o.peerDependencies=new Map(ks(o.peerDependencies,([,u])=>Sa(u))),o}getLimit(e){return al(this.limits,e,()=>(0,xle.default)(this.get(e)))}async triggerHook(e,...r){for(let o of this.plugins.values()){let a=o.hooks;if(!a)continue;let n=e(a);!n||await n(...r)}}async triggerMultipleHooks(e,r){for(let o of r)await this.triggerHook(e,...o)}async reduceHook(e,r,...o){let a=r;for(let n of this.plugins.values()){let u=n.hooks;if(!u)continue;let A=e(u);!A||(a=await A(a,...o))}return a}async firstHook(e,...r){for(let o of this.plugins.values()){let a=o.hooks;if(!a)continue;let n=e(a);if(!n)continue;let u=await n(...r);if(typeof u<\"u\")return u}return null}},Ke=nA;Ke.deleteProperty=Symbol(),Ke.telemetry=null});var Ur={};zt(Ur,{EndStrategy:()=>J4,ExecError:()=>kb,PipeError:()=>S1,execvp:()=>_4,pipevp:()=>Yc});function xd(t){return t!==null&&typeof t.fd==\"number\"}function K4(){}function z4(){for(let t of kd)t.kill()}async function Yc(t,e,{cwd:r,env:o=process.env,strict:a=!1,stdin:n=null,stdout:u,stderr:A,end:p=2}){let h=[\"pipe\",\"pipe\",\"pipe\"];n===null?h[0]=\"ignore\":xd(n)&&(h[0]=n),xd(u)&&(h[1]=u),xd(A)&&(h[2]=A);let E=(0,V4.default)(t,e,{cwd:le.fromPortablePath(r),env:{...o,PWD:le.fromPortablePath(r)},stdio:h});kd.add(E),kd.size===1&&(process.on(\"SIGINT\",K4),process.on(\"SIGTERM\",z4)),!xd(n)&&n!==null&&n.pipe(E.stdin),xd(u)||E.stdout.pipe(u,{end:!1}),xd(A)||E.stderr.pipe(A,{end:!1});let I=()=>{for(let v of new Set([u,A]))xd(v)||v.end()};return new Promise((v,x)=>{E.on(\"error\",C=>{kd.delete(E),kd.size===0&&(process.off(\"SIGINT\",K4),process.off(\"SIGTERM\",z4)),(p===2||p===1)&&I(),x(C)}),E.on(\"close\",(C,R)=>{kd.delete(E),kd.size===0&&(process.off(\"SIGINT\",K4),process.off(\"SIGTERM\",z4)),(p===2||p===1&&C!==0)&&I(),C===0||!a?v({code:X4(C,R)}):x(new S1({fileName:t,code:C,signal:R}))})})}async function _4(t,e,{cwd:r,env:o=process.env,encoding:a=\"utf8\",strict:n=!1}){let u=[\"ignore\",\"pipe\",\"pipe\"],A=[],p=[],h=le.fromPortablePath(r);typeof o.PWD<\"u\"&&(o={...o,PWD:h});let E=(0,V4.default)(t,e,{cwd:h,env:o,stdio:u});return E.stdout.on(\"data\",I=>{A.push(I)}),E.stderr.on(\"data\",I=>{p.push(I)}),await new Promise((I,v)=>{E.on(\"error\",x=>{let C=Ke.create(r),R=Ut(C,t,yt.PATH);v(new Jt(1,`Process ${R} failed to spawn`,N=>{N.reportError(1,`  ${Xu(C,{label:\"Thrown Error\",value:Hc(yt.NO_HINT,x.message)})}`)}))}),E.on(\"close\",(x,C)=>{let R=a===\"buffer\"?Buffer.concat(A):Buffer.concat(A).toString(a),N=a===\"buffer\"?Buffer.concat(p):Buffer.concat(p).toString(a);x===0||!n?I({code:X4(x,C),stdout:R,stderr:N}):v(new kb({fileName:t,code:x,signal:C,stdout:R,stderr:N}))})})}function X4(t,e){let r=oot.get(e);return typeof r<\"u\"?128+r:t??1}function aot(t,e,{configuration:r,report:o}){o.reportError(1,`  ${Xu(r,t!==null?{label:\"Exit Code\",value:Hc(yt.NUMBER,t)}:{label:\"Exit Signal\",value:Hc(yt.CODE,e)})}`)}var V4,J4,S1,kb,kd,oot,Db=Et(()=>{Pt();V4=$e(sT());P1();Wl();jl();J4=(o=>(o[o.Never=0]=\"Never\",o[o.ErrorCode=1]=\"ErrorCode\",o[o.Always=2]=\"Always\",o))(J4||{}),S1=class extends Jt{constructor({fileName:r,code:o,signal:a}){let n=Ke.create(z.cwd()),u=Ut(n,r,yt.PATH);super(1,`Child ${u} reported an error`,A=>{aot(o,a,{configuration:n,report:A})});this.code=X4(o,a)}},kb=class extends S1{constructor({fileName:r,code:o,signal:a,stdout:n,stderr:u}){super({fileName:r,code:o,signal:a});this.stdout=n,this.stderr=u}};kd=new Set;oot=new Map([[\"SIGINT\",2],[\"SIGQUIT\",3],[\"SIGKILL\",9],[\"SIGTERM\",15]])});function Fle(t){Qle=t}function b1(){return typeof Z4>\"u\"&&(Z4=Qle()),Z4}var Z4,Qle,$4=Et(()=>{Qle=()=>{throw new Error(\"Assertion failed: No libzip instance is available, and no factory was configured\")}});var Rle=_((Qb,tU)=>{var lot=Object.assign({},ve(\"fs\")),eU=function(){var t=typeof document<\"u\"&&document.currentScript?document.currentScript.src:void 0;return typeof __filename<\"u\"&&(t=t||__filename),function(e){e=e||{};var r=typeof e<\"u\"?e:{},o,a;r.ready=new Promise(function(We,tt){o=We,a=tt});var n={},u;for(u in r)r.hasOwnProperty(u)&&(n[u]=r[u]);var A=[],p=\"./this.program\",h=function(We,tt){throw tt},E=!1,I=!0,v=\"\";function x(We){return r.locateFile?r.locateFile(We,v):v+We}var C,R,N,U;I&&(E?v=ve(\"path\").dirname(v)+\"/\":v=__dirname+\"/\",C=function(tt,It){var ir=ii(tt);return ir?It?ir:ir.toString():(N||(N=lot),U||(U=ve(\"path\")),tt=U.normalize(tt),N.readFileSync(tt,It?null:\"utf8\"))},R=function(tt){var It=C(tt,!0);return It.buffer||(It=new Uint8Array(It)),Ee(It.buffer),It},process.argv.length>1&&(p=process.argv[1].replace(/\\\\/g,\"/\")),A=process.argv.slice(2),h=function(We){process.exit(We)},r.inspect=function(){return\"[Emscripten Module object]\"});var V=r.print||console.log.bind(console),te=r.printErr||console.warn.bind(console);for(u in n)n.hasOwnProperty(u)&&(r[u]=n[u]);n=null,r.arguments&&(A=r.arguments),r.thisProgram&&(p=r.thisProgram),r.quit&&(h=r.quit);var ae=0,fe=function(We){ae=We},ue;r.wasmBinary&&(ue=r.wasmBinary);var me=r.noExitRuntime||!0;typeof WebAssembly!=\"object\"&&Ti(\"no native wasm support detected\");function he(We,tt,It){switch(tt=tt||\"i8\",tt.charAt(tt.length-1)===\"*\"&&(tt=\"i32\"),tt){case\"i1\":return He[We>>0];case\"i8\":return He[We>>0];case\"i16\":return up((We>>1)*2);case\"i32\":return Os((We>>2)*4);case\"i64\":return Os((We>>2)*4);case\"float\":return uu((We>>2)*4);case\"double\":return cp((We>>3)*8);default:Ti(\"invalid type for getValue: \"+tt)}return null}var Be,we=!1,g;function Ee(We,tt){We||Ti(\"Assertion failed: \"+tt)}function Pe(We){var tt=r[\"_\"+We];return Ee(tt,\"Cannot call unknown function \"+We+\", make sure it is exported\"),tt}function ce(We,tt,It,ir,$){var ye={string:function(es){var bi=0;if(es!=null&&es!==0){var qo=(es.length<<2)+1;bi=Un(qo),At(es,bi,qo)}return bi},array:function(es){var bi=Un(es.length);return Re(es,bi),bi}};function Ne(es){return tt===\"string\"?Ie(es):tt===\"boolean\"?Boolean(es):es}var pt=Pe(We),ht=[],Tt=0;if(ir)for(var er=0;er<ir.length;er++){var $r=ye[It[er]];$r?(Tt===0&&(Tt=ms()),ht[er]=$r(ir[er])):ht[er]=ir[er]}var Gi=pt.apply(null,ht);return Gi=Ne(Gi),Tt!==0&&_s(Tt),Gi}function ne(We,tt,It,ir){It=It||[];var $=It.every(function(Ne){return Ne===\"number\"}),ye=tt!==\"string\";return ye&&$&&!ir?Pe(We):function(){return ce(We,tt,It,arguments,ir)}}var ee=new TextDecoder(\"utf8\");function Ie(We,tt){if(!We)return\"\";for(var It=We+tt,ir=We;!(ir>=It)&&Te[ir];)++ir;return ee.decode(Te.subarray(We,ir))}function Fe(We,tt,It,ir){if(!(ir>0))return 0;for(var $=It,ye=It+ir-1,Ne=0;Ne<We.length;++Ne){var pt=We.charCodeAt(Ne);if(pt>=55296&&pt<=57343){var ht=We.charCodeAt(++Ne);pt=65536+((pt&1023)<<10)|ht&1023}if(pt<=127){if(It>=ye)break;tt[It++]=pt}else if(pt<=2047){if(It+1>=ye)break;tt[It++]=192|pt>>6,tt[It++]=128|pt&63}else if(pt<=65535){if(It+2>=ye)break;tt[It++]=224|pt>>12,tt[It++]=128|pt>>6&63,tt[It++]=128|pt&63}else{if(It+3>=ye)break;tt[It++]=240|pt>>18,tt[It++]=128|pt>>12&63,tt[It++]=128|pt>>6&63,tt[It++]=128|pt&63}}return tt[It]=0,It-$}function At(We,tt,It){return Fe(We,Te,tt,It)}function H(We){for(var tt=0,It=0;It<We.length;++It){var ir=We.charCodeAt(It);ir>=55296&&ir<=57343&&(ir=65536+((ir&1023)<<10)|We.charCodeAt(++It)&1023),ir<=127?++tt:ir<=2047?tt+=2:ir<=65535?tt+=3:tt+=4}return tt}function at(We){var tt=H(We)+1,It=Ni(tt);return It&&Fe(We,He,It,tt),It}function Re(We,tt){He.set(We,tt)}function ke(We,tt){return We%tt>0&&(We+=tt-We%tt),We}var xe,He,Te,Ve,qe,b,w,S,y,F;function J(We){xe=We,r.HEAP_DATA_VIEW=F=new DataView(We),r.HEAP8=He=new Int8Array(We),r.HEAP16=Ve=new Int16Array(We),r.HEAP32=b=new Int32Array(We),r.HEAPU8=Te=new Uint8Array(We),r.HEAPU16=qe=new Uint16Array(We),r.HEAPU32=w=new Uint32Array(We),r.HEAPF32=S=new Float32Array(We),r.HEAPF64=y=new Float64Array(We)}var X=r.INITIAL_MEMORY||16777216,Z,ie=[],be=[],Le=[],ot=!1;function dt(){if(r.preRun)for(typeof r.preRun==\"function\"&&(r.preRun=[r.preRun]);r.preRun.length;)bt(r.preRun.shift());oo(ie)}function Gt(){ot=!0,oo(be)}function $t(){if(r.postRun)for(typeof r.postRun==\"function\"&&(r.postRun=[r.postRun]);r.postRun.length;)Qr(r.postRun.shift());oo(Le)}function bt(We){ie.unshift(We)}function an(We){be.unshift(We)}function Qr(We){Le.unshift(We)}var mr=0,br=null,Wr=null;function Kn(We){mr++,r.monitorRunDependencies&&r.monitorRunDependencies(mr)}function Ls(We){if(mr--,r.monitorRunDependencies&&r.monitorRunDependencies(mr),mr==0&&(br!==null&&(clearInterval(br),br=null),Wr)){var tt=Wr;Wr=null,tt()}}r.preloadedImages={},r.preloadedAudios={};function Ti(We){r.onAbort&&r.onAbort(We),We+=\"\",te(We),we=!0,g=1,We=\"abort(\"+We+\"). Build with -s ASSERTIONS=1 for more info.\";var tt=new WebAssembly.RuntimeError(We);throw a(tt),tt}var ps=\"data:application/octet-stream;base64,\";function io(We){return We.startsWith(ps)}var Si=\"data:application/octet-stream;base64,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QCAAKAJIIgEgASADaiADEAcaAkAgAyAAKAJsIgFNBEAgACABIANrNgJsDAELIABCADcCbAsgACAAKAJoIANrIgE2AmggACAAKAJYIANrNgJYIAEgACgChC5JBEAgACABNgKELgsgAEH8gAEoAgARAwAgAiADaiECCwJAIAAoAgAiASgCBCIERQ0AIAAoAjwhBSAAIAIgBCACIARJGyICBH8gACgCSCAAKAJoaiAFaiEFIAEgBCACazYCBAJAAkACQAJAIAEoAhwiBCgCFEEBaw4CAQACCyAEQaABaiAFIAEoAgAgAkHcgAEoAgARCAAMAgsgASABKAIwIAUgASgCACACQcSAASgCABEEADYCMAwBCyAFIAEoAgAgAhAHGgsgASABKAIAIAJqNgIAIAEgASgCCCACajYCCCAAKAI8BSAFCyACaiICNgI8AkAgACgChC4iASACakEDSQ0AIAAoAmggAWshAQJAIAAoAnRBgQhPBEAgACAAIAAoAkggAWoiAi0AACACLQABIAAoAnwRAAA2AlQMAQsgAUUNACAAIAFBAWsgACgChAERAgAaCyAAKAKELiAAKAI8IgJBAUZrIgRFDQAgACABIAQgACgCgAERBQAgACAAKAKELiAEazYChC4gACgCPCECCyACQYUCSw0AIAAoAgAoAgRFDQAgACgCMCEBDAELCwJAIAAoAkQiAiAAKAJAIgNNDQAgAAJ/IAAoAjwgACgCaGoiASADSwRAIAAoAkggAWpBACACIAFrIgNBggIgA0GCAkkbIgMQGSABIANqDAELIAFBggJqIgEgA00NASAAKAJIIANqQQAgAiADayICIAEgA2siAyACIANJGyIDEBkgACgCQCADags2AkALC50CAQF/AkAgAAJ/IAAoAqAuIgFBwABGBEAgACgCBCAAKAIQaiAAKQOYLjcAACAAQgA3A5guIAAgACgCEEEIajYCEEEADAELIAFBIE4EQCAAKAIEIAAoAhBqIAApA5guPgAAIAAgAEGcLmo1AgA3A5guIAAgACgCEEEEajYCECAAIAAoAqAuQSBrIgE2AqAuCyABQRBOBEAgACgCBCAAKAIQaiAAKQOYLj0AACAAIAAoAhBBAmo2AhAgACAAKQOYLkIQiDcDmC4gACAAKAKgLkEQayIBNgKgLgsgAUEISA0BIAAgACgCECIBQQFqNgIQ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KAJUIgEEfyABQQAgARAiEBkgACgCVAVBAAsQBiAAQQA2AlQLC9wMAgl/AX4jAEFAaiIGJAACQAJAAkACQAJAIAEoAjBBABAjIgVBAkZBACABKAI4QQAQIyIEQQFGGw0AIAVBAUZBACAEQQJGGw0AIAVBAkciAw0BIARBAkcNAQsgASABLwEMQYAQcjsBDEEAIQMMAQsgASABLwEMQf/vA3E7AQxBACEFIANFBEBB9eABIAEoAjAgAEEIahBpIgVFDQILIAJBgAJxBEAgBSEDDAELIARBAkcEQCAFIQMMAQtB9cYBIAEoAjggAEEIahBpIgNFBEAgBRAcDAILIAMgBTYCAAsgASABLwEMQf7/A3EgAS8BUiIFQQBHcjsBDAJAAkACQAJAAn8CQAJAIAEpAyhC/v///w9WDQAgASkDIEL+////D1YNACACQYAEcUUNASABKQNIQv////8PVA0BCyAFQYECa0H//wNxQQNJIQdBAQwBCyAFQYECa0H//wNxIQQgAkGACnFBgApHDQEgBEEDSSEHQQALIQkgBkIcEBciBEUEQCAAQQhqIgAEQCAAQQA2AgQgAEEONgIACyADEBwMBQsgAkGACHEhBQJAAkAgAkGAAnEEQAJAIAUNACABKQMgQv////8PVg0AIAEpAyhCgICAgBBUDQMLIAQgASkDKBAYIAEpAyAhDAwBCwJAAkACQCAFDQAgASkDIEL/////D1YNACABKQMoIgxC/////w9WDQEgASkDSEKAgICAEFQNBAsgASkDKCIMQv////8PVA0BCyAEIAwQGAsgASkDICIMQv////8PWgRAIAQgDBAYCyABKQNIIgxC/////w9UDQELIAQgDBAYCyAELQAARQRAIABBCGoiAARAIABBADYCBCAAQRQ2AgALIAQQCCADEBwMBQtBASEKQQEgBC0AAAR+IAQpAxAFQgALp0H//wNxIAYQRyEFIAQQCCAFIAM2AgAgBw0BDAILIAMhBSAEQQJLDQELIAZCBxAXIgRFBEAgAEEIaiIABEAgAEEANgIEIABBDjYCAAsgBRAcDAMLIARBAhANIARBhxJBAhAsIAQgAS0AUhBwIAQgAS8BEBANIAQtAABFBEAgAEEIaiIABEAgAEEANgIEIABBFDYCAAsgBBAIDAILQYGyAkEHIAYQRyEDIAQQCCADIAU2AgBBASEL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NgIEIABB7A42AhggGiEdDAMLIARB/wFxIgJBwABxRQRAIAggDSADLwECQQJ0aiAdp0F/IAJ0QX9zcUECdGoiAy0AASICayEIIB0gAq2IIR0gAy0AACIERQ0HDAELCyAEQSBxBEAgB0G//gA2AgQgASECDAgLIAdB0f4ANgIEIABB0A42AhggASECDAcLIB1BfyAGdEF/c62DIBt8IhunIQUgCCAEQQ9xIgNrIQggGiAErUIPg4ghHSABIBdrIgYgAjMBAiAaQX8gA3RBf3Otg3ynIgRPDQIgBCAGayIGIBlNDQEgBygCjEdFDQEgB0HR/gA2AgQgAEG5DDYCGAsgASECIAshBQwFCwJAIA5FBEAgDCARIAZraiEDDAELIAYgDk0EQCAMIA4gBmtqIQMMAQsgDCARIAYgDmsiBmtqIQMgBSAGTQ0AIAUgBmshBQJAAkAgASADTSABIA8gAWusIhogBq0iGyAaIBtUGyIapyIGaiICIANLcQ0AIAMgBmogAUsgASADT3ENACABIAMgBhAHGiACIQEMAQsgASADIAMgAWsiASABQR91IgFqIAFzIgIQByACaiEBIBogAq0iHn0iHFANACACIANqIQIDQAJAIBwgHiAcIB5UGyIbQiBUBEAgGyEaDAELIBsiGkIgfSIgQgWIQgF8QgODIh9QRQRAA0AgASACKQAANwAAIAEgAikAGDcAGCABIAIpABA3ABAgASACKQAINwAIIBpCIH0hGiACQSBqIQIgAUEgaiEBIB9CAX0iH0IAUg0ACwsgIELgAFQNAANAIAEgAikAADcAACABIAIpABg3ABggASACKQAQNwAQIAEgAikACDcACCABIAIpADg3ADggASACKQAwNwAwIAEgAikAKDcAKCABIAIpACA3ACAgASACKQBYNwBYIAEgAikAUDcAUCABIAIpAEg3AEggASACKQBANwBAIAEgAikAYDcAYCABIAIpAGg3AGggASACKQBwNwBwIAEgAikAeDcAeCACQYABaiECIAFBgAFqIQEgGkKAAX0iGkIfVg0ACwsgGkIQWgRAIAEgAikAADcAACABIAIpAAg3AAggGkIQfSEaIAJBEGohAiABQRBqIQELIBpCCFoEQCABIAIpAAA3AAAgGkIIfSEaIAJBCGohAiABQQhqIQELIBpCBFoEQCABIAIoAAA2AAAgGkIEfSEaIAJBBGohAiABQQRqIQELIBpCAloEQCABIAIvAAA7AAAgGkICfSEaIAJBAmohAiABQQJqIQELIBwgG30hHCAaUEUEQCABIAItAAA6AAAgAkEBaiECIAFBAWohAQsgHEIAUg0ACwsgDiEGIAwhAwsgBSAGSwRAAkACQCABIANNIAEgDyABa6wiGiAGrSIbIBogG1QbIhqnIglqIgIgA0txDQAgAyAJaiABSyABIANPcQ0AIAEgAyAJEAcaDAELIAEgAyADIAFrIgEgAUEfdSIBaiABcyIBEAcgAWohAiAaIAGtIh59IhxQDQAgASADaiEBA0ACQCAcIB4gHCAeVBsiG0IgVARAIBshGgwBCyAbIhpCIH0iIEIFiEIBfEIDgyIfUEUEQANAIAIgASkAADcAACACIAEpABg3ABggAiABKQAQNwAQIAIgASkACDcACCAaQiB9IRogAUEgaiEBIAJBIGohAiAfQgF9Ih9CAFINAAsLICBC4ABUDQADQCACIAEpAAA3AAAgAiABKQAYNwAYIAIgASkAEDcAECACIAEpAAg3AAggAiABKQA4NwA4IAIgASkAMDcAMCACIAEpACg3ACggAiABKQAgNwAgIAIgASkAWDcAWCACIAEpAFA3AFAgAiABKQBINwBIIAIgASkAQDcAQCACIAEpAGA3AGAgAiABKQBoNwBoIAIgASkAcDcAcCACIAEpAHg3AHggAUGAAWohASACQYABaiECIBpCgAF9IhpCH1YNAAsLIBpCEFoEQCACIAEpAAA3AAAgAiABKQAINwAIIBpCEH0hGiACQRBqIQIgAUEQaiEBCyAaQghaBEAgAiABKQAANwAAIBpCCH0hGiACQQhqIQIgAUEIaiEBCyAaQgRaBEAgAiABKAAANgAAIBpCBH0hGiACQQRqIQIgAUEEaiEBCyAaQgJaBEAgAiABLwAAOwAAIBpCAn0hGiACQQJqIQIgAUECaiEBCyAcIBt9IRwgGlBFBEAgAiABLQAAOgAAIAJBAWohAiABQQFqIQELIBxCAFINAAsLIAUgBmshAUEAIARrIQUCQCAEQQdLBEAgBCEDDAELIAEgBE0EQCAEIQMMAQsgAiAEayEFA0ACQCACIAUpAAA3AAAgBEEBdCEDIAEgBGshASACIARqIQIgBEEDSw0AIAMhBCABIANLDQELC0EAIANrIQULIAIgBWohBAJAIAUgDyACa6wiGiABrSIbIBogG1QbIhqnIgFIIAVBf0pxDQAgBUEBSCABIARqIAJLcQ0AIAIgBCABEAcgAWohAgwDCyACIAQgAyADQR91IgFqIAFzIgEQByABaiECIBogAa0iHn0iHFANAiABIARqIQEDQAJAIBwgHiAcIB5UGyIbQiBUBEAgGyEaDAELIBsiGkIgfSIgQgWIQgF8QgODIh9QRQRAA0AgAiABKQAANwAAIAIgASkAGDcAGCACIAEpABA3ABAgAiABKQAINwAIIBpCIH0hGiABQSBqIQEgAkEgaiECIB9CAX0iH0IAUg0ACwsgIELgAFQNAANAIAIgASkAADcAACACIAEpABg3ABggAiABKQAQNwAQIAIgASkACDcACCACIAEpADg3ADggAiABKQAwNwAwIAIgASkAKDcAKCACIAEpACA3ACAgAiABKQBYNwBYIAIgASkAUDcAUCACIAEpAEg3AEggAiABKQBANwBAIAIgASkAYDcAYCACIAEpAGg3AGggAiABKQBwNwBwIAIgASkAeDcAeCABQYABaiEBIAJBgAFqIQIgGkKAAX0iGkIfVg0ACwsgGkIQWgRAIAIgASkAADcAACACIAEpAAg3AAggGkIQfSEaIAJBEGohAiABQRBqIQELIBpCCFoEQCACIAEpAAA3AAAgGkIIfSEaIAJBCGohAiABQQhqIQELIBpCBFoEQCACIAEoAAA2AAAgGkIEfSEaIAJBBGohAiABQQRqIQELIBpCAloEQCACIAEvAAA7AAAgGkICfSEaIAJBAmohAiABQQJqIQELIBwgG30hHCAaUEUEQCACIAEtAAA6AAAgAkEBaiECIAFBAWohAQsgHFBFDQALDAILAkAgASADTSABIA8gAWusIhogBa0iGyAaIBtUGyIapyIEaiICIANLcQ0AIAMgBGogAUsgASADT3ENACABIAMgBBAHGgwCCyABIAMgAyABayIBIAFBH3UiAWogAXMiARAHIAFqIQIgGiABrSIefSIcUA0BIAEgA2ohAQNAAkAgHCAeIBwgHlQbIhtCIFQEQCAbIRoMAQsgGyIaQiB9IiBCBYhCAXxCA4MiH1BFBEADQCACIAEpAAA3AAAgAiABKQAYNwAYIAIgASkAEDcAECACIAEpAAg3AAggGkIgfSEaIAFBIGohASACQSBqIQIgH0IBfSIfQgBSDQALCyAgQuAAVA0AA0AgAiABKQAANwAAIAIgASkAGDcAGCACIAEpABA3ABAgAiABKQAINwAIIAIgASkAODcAOCACIAEpADA3ADAgAiABKQAoNwAoIAIgASkAIDcAICACIAEpAFg3AFggAiABKQBQNwBQIAIgASkASDcASCACIAEpAEA3AEAgAiABKQBgNwBgIAIgASkAaDcAaCACIAEpAHA3AHAgAiABKQB4NwB4IAFBgAFqIQEgAkGAAWohAiAaQoABfSIaQh9WDQALCyAaQhBaBEAgAiABKQAANwAAIAIgASkACDcACCAaQhB9IRogAkEQaiECIAFBEGohAQsgGkIIWgRAIAIgASkAADcAACAaQgh9IRogAkEIaiECIAFBCGohAQsgGkIEWgRAIAIgASgAADYAACAaQgR9IRogAkEEaiECIAFBBGohAQsgGkICWgRAIAIgAS8AADsAACAaQgJ9IRogAkECaiECIAFBAmohAQsgHCAbfSEcIBpQRQRAIAIgAS0AADoAACACQQFqIQIgAUEBaiEBCyAcUEUNAAsMAQsCQAJAIBYEQAJAIAQgBUkEQCAHKAKYRyAESw0BCyABIARrIQMCQEEAIARrIgVBf0ogDyABa6wiGiAbIBogG1QbIhqnIgIgBUpxDQAgBUEBSCACIANqIAFLcQ0AIAEgAyACEAcgAmohAgwFCyABIAMgBCAEQR91IgFqIAFzIgEQByABaiECIBogAa0iHn0iHFANBCABIANqIQEDQAJAIBwgHiAcIB5UGyIbQiBUBEAgGyEaDAELIBsiGkIgfSIgQgWIQgF8QgODIh9QRQRAA0AgAiABKQAANwAAIAIgASkAGDcAGCACIAEpABA3ABAgAiABKQAINwAIIBpCIH0hGiABQSBqIQEgAkEgaiECIB9CAX0iH0IAUg0ACwsgIELgAFQNAANAIAIgASkAADcAACACIAEpABg3ABggAiABKQAQNwAQIAIgASkACDcACCACIAEpADg3ADggAiABKQAwNwAwIAIgASkAKDcAKCACIAEpACA3ACAgAiABKQBYNwBYIAIgASkAUDcAUCACIAEpAEg3AEggAiABKQBANwBAIAIgASkAYDcAYCACIAEpAGg3AGggAiABKQBwNwBwIAIgASkAeDcAeCABQYABaiEBIAJBgAFqIQIgGkKAAX0iGkIfVg0ACwsgGkIQWgRAIAIgASkAADcAACACIAEpAAg3AAggGkIQfSEaIAJBEGohAiABQRBqIQELIBpCCFoEQCACIAEpAAA3AAAgGkIIfSEaIAJBCGohAiABQQhqIQELIBpCBFoEQCACIAEoAAA2AAAgGkIEfSEaIAJBBGohAiABQQRqIQELIBpCAloEQCACIAEvAAA7AAAgGkICfSEaIAJBAmohAiABQQJqIQELIBwgG30hHCAaUEUEQCACIAEtAAA6AAAgAkEBaiECIAFBAWohAQsgHFBFDQALDAQLIBAgAWsiCUEBaiIGIAUgBSAGSxshAyABIARrIQIgAUEHcUUNAiADRQ0CIAEgAi0AADoAACACQQFqIQIgAUEBaiIGQQdxQQAgA0EBayIFGw0BIAYhASAFIQMgCSEGDAILAkAgBCAFSQRAIAcoAphHIARLDQELIAEgASAEayIGKQAANwAAIAEgBUEBa0EHcUEBaiIDaiECIAUgA2siBEUNAyADIAZqIQEDQCACIAEpAAA3AAAgAUEIaiEBIAJBCGohAiAEQQhrIgQNAAsMAwsgASAEIAUQPyECDAILIAEgAi0AADoAASAJQQFrIQYgA0ECayEFIAJBAWohAgJAIAFBAmoiCkEHcUUNACAFRQ0AIAEgAi0AADoAAiAJQQJrIQYgA0EDayEFIAJBAWohAgJAIAFBA2oiCkEHcUUNACAFRQ0AIAEgAi0AADoAAyAJQQNrIQYgA0EEayEFIAJBAWohAgJAIAFBBGoiCkEHcUUNACAFRQ0AIAEgAi0AADoABCAJQQRrIQYgA0EFayEFIAJBAWohAgJAIAFBBWoiCkEHcUUNACAFRQ0AIAEgAi0AADoABSAJQQVrIQYgA0EGayEFIAJBAWohAgJAIAFBBmoiCkEHcUUNACAFRQ0AIAEgAi0AADoABiAJQQZrIQYgA0EHayEFIAJBAWohAgJAIAFBB2oiCkEHcUUNACAFRQ0AIAEgAi0AADoAByAJQQdrIQYgA0EIayEDIAFBCGohASACQQFqIQIMBgsgCiEBIAUhAwwFCyAKIQEgBSEDDAQLIAohASAFIQMMAwsgCiEBIAUhAwwCCyAKIQEgBSEDDAELIAohASAFIQMLAkACQCAGQRdNBEAgA0UNASADQQFrIQUgA0EHcSIEBEADQCABIAItAAA6AAAgA0EBayEDIAFBAWohASACQQFqIQIgBEEBayIEDQALCyAFQQdJDQEDQCABIAItAAA6AAAgASACLQABOgABIAEgAi0AAjoAAiABIAItAAM6AAMgASACLQAEOgAEIAEgAi0ABToABSABIAItAAY6AAYgASACLQAHOgAHIAFBCGohASACQQhqIQIgA0EIayIDDQALDAELIAMNAQsgASECDAELIAEgBCADED8hAgsgCyEFDAELIAEgAy0AAjoAACABQQFqIQILIAUgFE8NACACIBNJDQELCyAAIAI2AgwgACAFIAhBA3ZrIgE2AgAgACATIAJrQYMCajYCECAAIBQgAWtBDmo2AgQgByAIQQdxIgA2AogBIAcgHUJ/IACthkJ/hYM+AoQBC+cFAQR/IAMgAiACIANLGyEEIAAgAWshAgJAIABBB3FFDQAgBEUNACAAIAItAAA6AAAgA0EBayEGIAJBAWohAiAAQQFqIgdBB3FBACAEQQFrIgUbRQRAIAchACAFIQQgBiEDDAELIAAgAi0AADoAASADQQJrIQYgBEECayEFIAJBAWohAgJAIABBAmoiB0EHcUUNACAFRQ0AIAAgAi0AADoAAiADQQNrIQYgBEEDayEFIAJBAWohAgJAIABBA2oiB0EHcUUNACAFRQ0AIAAgAi0AADoAAyADQQRrIQYgBEEEayEFIAJBAWohAgJAIABBBGoiB0EHcUUNACAFRQ0AIAAgAi0AADoABCADQQVrIQYgBEEFayEFIAJBAWohAgJAIABBBWoiB0EHcUUNACAFRQ0AIAAgAi0AADoABSADQQZrIQYgBEEGayEFIAJBAWohAgJAIABBBmoiB0EHcUUNACAFRQ0AIAAgAi0AADoABiADQQdrIQYgBEEHayEFIAJBAWohAgJAIABBB2oiB0EHcUUNACAFRQ0AIAAgAi0AADoAByADQQhrIQMgBEEIayEEIABBCGohACACQQFqIQIMBgsgByEAIAUhBCAGIQMMBQsgByEAIAUhBCAGIQMMBAsgByEAIAUhBCAGIQMMAwsgByEAIAUhBCAGIQMMAgsgByEAIAUhBCAGIQMMAQsgByEAIAUhBCAGIQMLAkAgA0EXTQRAIARFDQEgBEEBayEBIARBB3EiAwRAA0AgACACLQAAOgAAIARBAWshBCAAQQFqIQAgAkEBaiECIANBAWsiAw0ACwsgAUEHSQ0BA0AgACACLQAAOgAAIAAgAi0AAToAASAAIAItAAI6AAIgACACLQADOgADIAAgAi0ABDoABCAAIAItAAU6AAUgACACLQAGOgAGIAAgAi0ABzoAByAAQQhqIQAgAkEIaiECIARBCGsiBA0ACwwBCyAERQ0AIAAgASAEED8hAAsgAAvyCAEXfyAAKAJoIgwgACgCMEGGAmsiBWtBACAFIAxJGyENIAAoAnQhAiAAKAKQASEPIAAoAkgiDiAMaiIJIAAoAnAiBUECIAUbIgVBAWsiBmoiAy0AASESIAMtAAAhEyAGIA5qIQZBAyEDIAAoApQBIRYgACgCPCEUIAAoAkwhECAAKAI4IRECQAJ/IAVBA0kEQCANIQggDgwBCyAAIABBACAJLQABIAAoAnwRAAAgCS0AAiAAKAJ8EQAAIQoDQCAAIAogAyAJai0AACAAKAJ8EQAAIQogACgCUCAKQQF0ai8BACIIIAEgCCABQf//A3FJIggbIQEgA0ECayAHIAgbIQcgA0EBaiIDIAVNDQALIAFB//8DcSAHIA1qIghB//8DcU0NASAGIAdB//8DcSIDayEGIA4gA2sLIQMCQAJAIAwgAUH//wNxTQ0AIAIgAkECdiAFIA9JGyEKIA1B//8DcSEVIAlBAmohDyAJQQRrIRcDQAJAAkAgBiABQf//A3EiC2otAAAgE0cNACAGIAtBAWoiAWotAAAgEkcNACADIAtqIgItAAAgCS0AAEcNACABIANqLQAAIAktAAFGDQELIApBAWsiCkUNAiAQIAsgEXFBAXRqLwEAIgEgCEH//wNxSw0BDAILIAJBAmohAUEAIQQgDyECAkADQCACLQAAIAEtAABHDQEgAi0AASABLQABRwRAIARBAXIhBAwCCyACLQACIAEtAAJHBEAgBEECciEEDAILIAItAAMgAS0AA0cEQCAEQQNyIQQMAgsgAi0ABCABLQAERwRAIARBBHIhBAwCCyACLQAFIAEtAAVHBEAgBEEFciEEDAILIAItAAYgAS0ABkcEQCAEQQZyIQQMAgsgAi0AByABLQAHRwRAIARBB3IhBAwCCyABQQhqIQEgAkEIaiECIARB+AFJIRggBEEIaiEEIBgNAAtBgAIhBAsCQAJAIAUgBEECaiICSQRAIAAgCyAHQf//A3FrIgY2AmwgAiAUSwRAIBQPCyACIBZPBEAgAg8LIAkgBEEBaiIFaiIBLQABIRIgAS0AACETAkAgAkEESQ0AIAIgBmogDE8NACAGQf//A3EhCCAEQQFrIQtBACEDQQAhBwNAIBAgAyAIaiARcUEBdGovAQAiASAGQf//A3FJBEAgAyAVaiABTw0IIAMhByABIQYLIANBAWoiAyALTQ0ACyAAIAAgAEEAIAIgF2oiAS0AACAAKAJ8EQAAIAEtAAEgACgCfBEAACABLQACIAAoAnwRAAAhASAAKAJQIAFBAXRqLwEAIgEgBkH//wNxTwRAIAdB//8DcSEDIAYhAQwDCyAEQQJrIgdB//8DcSIDIBVqIAFPDQYMAgsgAyAFaiEGIAIhBQsgCkEBayIKRQ0DIBAgCyARcUEBdGovAQAiASAIQf//A3FNDQMMAQsgByANaiEIIA4gA2siAyAFaiEGIAIhBQsgDCABQf//A3FLDQALCyAFDwsgAiEFCyAFIAAoAjwiACAAIAVLGwuGBQETfyAAKAJ0IgMgA0ECdiAAKAJwIgNBAiADGyIDIAAoApABSRshByAAKAJoIgogACgCMEGGAmsiBWtB//8DcUEAIAUgCkkbIQwgACgCSCIIIApqIgkgA0EBayICaiIFLQABIQ0gBS0AACEOIAlBAmohBSACIAhqIQsgACgClAEhEiAAKAI8IQ8gACgCTCEQIAAoAjghESAAKAKIAUEFSCETA0ACQCAKIAFB//8DcU0NAANAAkACQCALIAFB//8DcSIGai0AACAORw0AIAsgBkEBaiIBai0AACANRw0AIAYgCGoiAi0AACAJLQAARw0AIAEgCGotAAAgCS0AAUYNAQsgB0EBayIHRQ0CIAwgECAGIBFxQQF0ai8BACIBSQ0BDAILCyACQQJqIQRBACECIAUhAQJAA0AgAS0AACAELQAARw0BIAEtAAEgBC0AAUcEQCACQQFyIQIMAgsgAS0AAiAELQACRwRAIAJBAnIhAgwCCyABLQADIAQtAANHBEAgAkEDciECDAILIAEtAAQgBC0ABEcEQCACQQRyIQIMAgsgAS0ABSAELQAFRwRAIAJBBXIhAgwCCyABLQAGIAQtAAZHBEAgAkEGciECDAILIAEtAAcgBC0AB0cEQCACQQdyIQIMAgsgBEEIaiEEIAFBCGohASACQfgBSSEUIAJBCGohAiAUDQALQYACIQILAkAgAyACQQJqIgFJBEAgACAGNgJsIAEgD0sEQCAPDwsgASASTwRAIAEPCyAIIAJBAWoiA2ohCyADIAlqIgMtAAEhDSADLQAAIQ4gASEDDAELIBMNAQsgB0EBayIHRQ0AIAwgECAGIBFxQQF0ai8BACIBSQ0BCwsgAwvLAQECfwJAA0AgAC0AACABLQAARw0BIAAtAAEgAS0AAUcEQCACQQFyDwsgAC0AAiABLQACRwRAIAJBAnIPCyAALQADIAEtAANHBEAgAkEDcg8LIAAtAAQgAS0ABEcEQCACQQRyDwsgAC0ABSABLQAFRwRAIAJBBXIPCyAALQAGIAEtAAZHBEAgAkEGcg8LIAAtAAcgAS0AB0cEQCACQQdyDwsgAUEIaiEBIABBCGohACACQfgBSSEDIAJBCGohAiADDQALQYACIQILIAIL5wwBB38gAEF/cyEAIAJBF08EQAJAIAFBA3FFDQAgAS0AACAAQf8BcXNBAnRB0BhqKAIAIABBCHZzIQAgAkEBayIEQQAgAUEBaiIDQQNxG0UEQCAEIQIgAyEBDAELIAEtAAEgAEH/AXFzQQJ0QdAYaigCACAAQQh2cyEAIAFBAmohAwJAIAJBAmsiBEUNACADQQNxRQ0AIAEtAAIgAEH/AXFzQQJ0QdAYaigCACAAQQh2cyEAIAFBA2ohAwJAIAJBA2siBEUNACADQQNxRQ0AIAEtAAMgAEH/AXFzQQJ0QdAYaigCACAAQQh2cyEAIAFBBGohASACQQRrIQIMAgsgBCECIAMhAQwBCyAEIQIgAyEBCyACQRRuIgNBbGwhCQJAIANBAWsiCEUEQEEAIQQMAQsgA0EUbCABakEUayEDQQAhBANAIAEoAhAgB3MiB0EWdkH8B3FB0DhqKAIAIAdBDnZB/AdxQdAwaigCACAHQQZ2QfwHcUHQKGooAgAgB0H/AXFBAnRB0CBqKAIAc3NzIQcgASgCDCAGcyIGQRZ2QfwHcUHQOGooAgAgBkEOdkH8B3FB0DBqKAIAIAZBBnZB/AdxQdAoaigCACAGQf8BcUECdEHQIGooAgBzc3MhBiABKAIIIAVzIgVBFnZB/AdxQdA4aigCACAFQQ52QfwHcUHQMGooAgAgBUEGdkH8B3FB0ChqKAIAIAVB/wFxQQJ0QdAgaigCAHNzcyEFIAEoAgQgBHMiBEEWdkH8B3FB0DhqKAIAIARBDnZB/AdxQdAwaigCACAEQQZ2QfwHcUHQKGooAgAgBEH/AXFBAnRB0CBqKAIAc3NzIQQgASgCACAAcyIAQRZ2QfwHcUHQOGooAgAgAEEOdkH8B3FB0DBqKAIAIABBBnZB/AdxQdAoaigCACAAQf8BcUECdEHQIGooAgBzc3MhACABQRRqIQEgCEEBayIIDQALIAMhAQsgAiAJaiECIAEoAhAgASgCDCABKAIIIAEoAgQgASgCACAAcyIAQQh2IABB/wFxQQJ0QdAYaigCAHMiAEEIdiAAQf8BcUECdEHQGGooAgBzIgBBCHYgAEH/AXFBAnRB0BhqKAIAcyIAQf8BcUECdEHQGGooAgAgBHNzIABBCHZzIgBBCHYgAEH/AXFBAnRB0BhqKAIAcyIAQQh2IABB/wFxQQJ0QdAYaigCAHMiAEEIdiAAQf8BcUECdEHQGGooAgBzIgBB/wFxQQJ0QdAYaigCACAFc3MgAEEIdnMiAEEIdiAAQf8BcUECdEHQGGooAgBzIgBBCHYgAEH/AXFBAnRB0BhqKAIAcyIAQQh2IABB/wFxQQJ0QdAYaigCAHMiAEH/AXFBAnRB0BhqKAIAIAZzcyAAQQh2cyIAQQh2IABB/wFxQQJ0QdAYaigCAHMiAEEIdiAAQf8BcUECdEHQGGooAgBzIgBBCHYgAEH/AXFBAnRB0BhqKAIAcyIAQf8BcUECdEHQGGooAgAgB3NzIABBCHZzIgBBCHYgAEH/AXFBAnRB0BhqKAIAcyIAQQh2IABB/wFxQQJ0QdAYaigCAHMiAEEIdiAAQf8BcUECdEHQGGooAgBzIgBBCHYgAEH/AXFBAnRB0BhqKAIAcyEAIAFBFGohAQsgAkEHSwRAA0AgAS0AByABLQAGIAEtAAUgAS0ABCABLQADIAEtAAIgAS0AASABLQAAIABB/wFxc0ECdEHQGGooAgAgAEEIdnMiAEH/AXFzQQJ0QdAYaigCACAAQQh2cyIAQf8BcXNBAnRB0BhqKAIAIABBCHZzIgBB/wFxc0ECdEHQGGooAgAgAEEIdnMiAEH/AXFzQQJ0QdAYaigCACAAQQh2cyIAQf8BcXNBAnRB0BhqKAIAIABBCHZzIgBB/wFxc0ECdEHQGGooAgAgAEEIdnMiAEH/AXFzQQJ0QdAYaigCACAAQQh2cyEAIAFBCGohASACQQhrIgJBB0sNAAsLAkAgAkUNACACQQFxBH8gAS0AACAAQf8BcXNBAnRB0BhqKAIAIABBCHZzIQAgAUEBaiEBIAJBAWsFIAILIQMgAkEBRg0AA0AgAS0AASABLQAAIABB/wFxc0ECdEHQGGooAgAgAEEIdnMiAEH/AXFzQQJ0QdAYaigCACAAQQh2cyEAIAFBAmohASADQQJrIgMNAAsLIABBf3MLwgIBA38jAEEQayIIJAACfwJAIAAEQCAEDQEgBVANAQsgBgRAIAZBADYCBCAGQRI2AgALQQAMAQtBgAEQCSIHRQRAIAYEQCAGQQA2AgQgBkEONgIAC0EADAELIAcgATcDCCAHQgA3AwAgB0EoaiIJECogByAFNwMYIAcgBDYCECAHIAM6AGAgB0EANgJsIAdCADcCZCAAKQMYIQEgCEF/NgIIIAhCjoCAgPAANwMAIAdBECAIECQgAUL/gQGDhCIBNwNwIAcgAadBBnZBAXE6AHgCQCACRQ0AIAkgAhBgQX9KDQAgBxAGQQAMAQsgBhBfIgIEQCAAIAAoAjBBAWo2AjAgAiAHNgIIIAJBATYCBCACIAA2AgAgAkI/IAAgB0EAQgBBDkEBEQoAIgEgAUIAUxs3AxgLIAILIQAgCEEQaiQAIAALYgEBf0E4EAkiAUUEQCAABEAgAEEANgIEIABBDjYCAAtBAA8LIAFBADYCCCABQgA3AwAgAUIANwMgIAFCgICAgBA3AiwgAUEAOgAoIAFBADYCFCABQgA3AgwgAUEAOwE0IAELuwEBAX4gASkDACICQgKDUEUEQCAAIAEpAxA3AxALIAJCBINQRQRAIAAgASkDGDcDGAsgAkIIg1BFBEAgACABKQMgNwMgCyACQhCDUEUEQCAAIAEoAig2AigLIAJCIINQRQRAIAAgASgCLDYCLAsgAkLAAINQRQRAIAAgAS8BMDsBMAsgAkKAAYNQRQRAIAAgAS8BMjsBMgsgAkKAAoNQRQRAIAAgASgCNDYCNAsgACAAKQMAIAKENwMAQQALGQAgAUUEQEEADwsgACABKAIAIAEzAQQQGws3AQJ/IABBACABG0UEQCAAIAFGDwsgAC8BBCIDIAEvAQRGBH8gACgCACABKAIAIAMQPQVBAQtFCyIBAX8gAUUEQEEADwsgARAJIgJFBEBBAA8LIAIgACABEAcLKQAgACABIAIgAyAEEEUiAEUEQEEADwsgACACQQAgBBA1IQEgABAGIAELcQEBfgJ/AkAgAkJ/VwRAIAMEQCADQQA2AgQgA0EUNgIACwwBCyAAIAEgAhARIgRCf1cEQCADBEAgAyAAKAIMNgIAIAMgACgCEDYCBAsMAQtBACACIARXDQEaIAMEQCADQQA2AgQgA0ERNgIACwtBfwsLNQAgACABIAJBABAmIgBFBEBBfw8LIAMEQCADIAAtAAk6AAALIAQEQCAEIAAoAkQ2AgALQQAL/AECAn8BfiMAQRBrIgMkAAJAIAAgA0EOaiABQYAGQQAQRiIARQRAIAIhAAwBCyADLwEOIgFBBUkEQCACIQAMAQsgAC0AAEEBRwRAIAIhAAwBCyAAIAGtQv//A4MQFyIBRQRAIAIhAAwBCyABEH0aAkAgARAVIAIEfwJ/IAIvAQQhAEEAIAIoAgAiBEUNABpBACAEIABB1IABKAIAEQAACwVBAAtHBEAgAiEADAELIAEgAS0AAAR+IAEpAwggASkDEH0FQgALIgVC//8DgxATIAWnQf//A3FBgBBBABA1IgBFBEAgAiEADAELIAIQEAsgARAICyADQRBqJAAgAAvmDwIIfwJ+IwBB4ABrIgckAEEeQS4gAxshCwJAAkAgAgRAIAIiBSIGLQAABH4gBikDCCAGKQMQfQVCAAsgC61aDQEgBARAIARBADYCBCAEQRM2AgALQn8hDQwCCyABIAutIAcgBBAtIgUNAEJ/IQ0MAQsgBUIEEBMoAABBoxJBqBIgAxsoAABHBEAgBARAIARBADYCBCAEQRM2AgALQn8hDSACDQEgBRAIDAELIABCADcDICAAQQA2AhggAEL/////DzcDECAAQQA7AQwgAEG/hig2AgggAEEBOgAGIABBADsBBCAAQQA2AgAgAEIANwNIIABBgIDYjXg2AkQgAEIANwMoIABCADcDMCAAQgA3AzggAEFAa0EAOwEAIABCADcDUCAAIAMEf0EABSAFEAwLOwEIIAAgBRAMOwEKIAAgBRAMOwEMIAAgBRAMNgIQIAUQDCEGIAUQDCEJIAdBADYCWCAHQgA3A1AgB0IANwNIIAcgCUEfcTYCPCAHIAZBC3Y2AjggByAGQQV2QT9xNgI0IAcgBkEBdEE+cTYCMCAHIAlBCXZB0ABqNgJEIAcgCUEFdkEPcUEBazYCQCAAIAdBMGoQBTYCFCAAIAUQFTYCGCAAIAUQFa03AyAgACAFEBWtNwMoIAUQDCEIIAUQDCEGIAACfiADBEBBACEJIABBADYCRCAAQQA7AUAgAEEANgI8QgAMAQsgBRAMIQkgACAFEAw2AjwgACAFEAw7AUAgACAFEBU2AkQgBRAVrQs3A0ggBS0AAEUEQCAEBEAgBEEANgIEIARBFDYCAAtCfyENIAINASAFEAgMAQsCQCAALwEMIgpBAXEEQCAKQcAAcQRAIABB//8DOwFSDAILIABBATsBUgwBCyAAQQA7AVILIABBADYCOCAAQgA3AzAgBiAIaiAJaiEKAkAgAgRAIAUtAAAEfiAFKQMIIAUpAxB9BUIACyAKrVoNASAEBEAgBEEANgIEIARBFTYCAAtCfyENDAILIAUQCCABIAqtQQAgBBAtIgUNAEJ/IQ0MAQsCQCAIRQ0AIAAgBSABIAhBASAEEGQiCDYCMCAIRQRAIAQoAgBBEUYEQCAEBEAgBEEANgIEIARBFTYCAAsLQn8hDSACDQIgBRAIDAILIAAtAA1BCHFFDQAgCEECECNBBUcNACAEBEAgBEEANgIEIARBFTYCAAtCfyENIAINASAFEAgMAQsgAEE0aiEIAkAgBkUNACAFIAEgBkEAIAQQRSIMRQRAQn8hDSACDQIgBRAIDAILIAwgBkGAAkGABCADGyAIIAQQbiEGIAwQBiAGRQRAQn8hDSACDQIgBRAIDAILIANFDQAgAEEBOgAECwJAIAlFDQAgACAFIAEgCUEAIAQQZCIBNgI4IAFFBEBCfyENIAINAiAFEAgMAgsgAC0ADUEIcUUNACABQQIQI0EFRw0AIAQEQCAEQQA2AgQgBEEVNgIAC0J/IQ0gAg0BIAUQCAwBCyAAIAAoAjRB9eABIAAoAjAQZzYCMCAAIAAoAjRB9cYBIAAoAjgQZzYCOAJAAkAgACkDKEL/////D1ENACAAKQMgQv////8PUQ0AIAApA0hC/////w9SDQELAkACQAJAIAgoAgAgB0EwakEBQYACQYAEIAMbIAQQRiIBRQRAIAJFDQEMAgsgASAHMwEwEBciAUUEQCAEBEAgBEEANgIEIARBDjYCAAsgAkUNAQwCCwJAIAApAyhC/////w9RBEAgACABEB03AygMAQsgA0UNAEEAIQYCQCABKQMQIg5CCHwiDSAOVA0AIAEpAwggDVQNACABIA03AxBBASEGCyABIAY6AAALIAApAyBC/////w9RBEAgACABEB03AyALAkAgAw0AIAApA0hC/////w9RBEAgACABEB03A0gLIAAoAjxB//8DRw0AIAAgARAVNgI8CyABLQAABH8gASkDECABKQMIUQVBAAsNAiAEBEAgBEEANgIEIARBFTYCAAsgARAIIAINAQsgBRAIC0J/IQ0MAgsgARAICyAFLQAARQRAIAQEQCAEQQA2AgQgBEEUNgIAC0J/IQ0gAg0BIAUQCAwBCyACRQRAIAUQCAtCfyENIAApA0hCf1cEQCAEBEAgBEEWNgIEIARBBDYCAAsMAQsjAEEQayIDJABBASEBAkAgACgCEEHjAEcNAEEAIQECQCAAKAI0IANBDmpBgbICQYAGQQAQRiICBEAgAy8BDiIFQQZLDQELIAQEQCAEQQA2AgQgBEEVNgIACwwBCyACIAWtQv//A4MQFyICRQRAIAQEQCAEQQA2AgQgBEEUNgIACwwBC0EBIQECQAJAAkAgAhAMQQFrDgICAQALQQAhASAEBEAgBEEANgIEIARBGDYCAAsgAhAIDAILIAApAyhCE1YhAQsgAkICEBMvAABBwYoBRwRAQQAhASAEBEAgBEEANgIEIARBGDYCAAsgAhAIDAELIAIQfUEBayIFQf8BcUEDTwRAQQAhASAEBEAgBEEANgIEIARBGDYCAAsgAhAIDAELIAMvAQ5BB0cEQEEAIQEgBARAIARBADYCBCAEQRU2AgALIAIQCAwBCyAAIAE6AAYgACAFQf8BcUGBAmo7AVIgACACEAw2AhAgAhAIQQEhAQsgA0EQaiQAIAFFDQAgCCAIKAIAEG02AgAgCiALaq0hDQsgB0HgAGokACANC4ECAQR/IwBBEGsiBCQAAkAgASAEQQxqQcAAQQAQJSIGRQ0AIAQoAgxBBWoiA0GAgARPBEAgAgRAIAJBADYCBCACQRI2AgALDAELQQAgA60QFyIDRQRAIAIEQCACQQA2AgQgAkEONgIACwwBCyADQQEQcCADIAEEfwJ/IAEvAQQhBUEAIAEoAgAiAUUNABpBACABIAVB1IABKAIAEQAACwVBAAsQEiADIAYgBCgCDBAsAn8gAy0AAEUEQCACBEAgAkEANgIEIAJBFDYCAAtBAAwBCyAAIAMtAAAEfiADKQMQBUIAC6dB//8DcSADKAIEEEcLIQUgAxAICyAEQRBqJAAgBQvgAQICfwF+QTAQCSICRQRAIAEEQCABQQA2AgQgAUEONgIAC0EADwsgAkIANwMIIAJBADYCACACQgA3AxAgAkIANwMYIAJCADcDICACQgA3ACUgAFAEQCACDwsCQCAAQv////8AVg0AIACnQQR0EAkiA0UNACACIAM2AgBBACEBQgEhBANAIAMgAUEEdGoiAUIANwIAIAFCADcABSAAIARSBEAgBKchASAEQgF8IQQMAQsLIAIgADcDCCACIAA3AxAgAg8LIAEEQCABQQA2AgQgAUEONgIAC0EAEBAgAhAGQQAL7gECA38BfiMAQRBrIgQkAAJAIARBDGpCBBAXIgNFBEBBfyECDAELAkAgAQRAIAJBgAZxIQUDQAJAIAUgASgCBHFFDQACQCADKQMIQgBUBEAgA0EAOgAADAELIANCADcDECADQQE6AAALIAMgAS8BCBANIAMgAS8BChANIAMtAABFBEAgAEEIaiIABEAgAEEANgIEIABBFDYCAAtBfyECDAQLQX8hAiAAIARBDGpCBBAbQQBIDQMgATMBCiIGUA0AIAAgASgCDCAGEBtBAEgNAwsgASgCACIBDQALC0EAIQILIAMQCAsgBEEQaiQAIAILPAEBfyAABEAgAUGABnEhAQNAIAEgACgCBHEEQCACIAAvAQpqQQRqIQILIAAoAgAiAA0ACwsgAkH//wNxC5wBAQN/IABFBEBBAA8LIAAhAwNAAn8CQAJAIAAvAQgiAUH04AFNBEAgAUEBRg0BIAFB9cYBRg0BDAILIAFBgbICRg0AIAFB9eABRw0BCyAAKAIAIQEgAEEANgIAIAAoAgwQBiAAEAYgASADIAAgA0YbIQMCQCACRQRAQQAhAgwBCyACIAE2AgALIAEMAQsgACICKAIACyIADQALIAMLsgQCBX8BfgJAAkACQCAAIAGtEBciAQRAIAEtAAANAUEAIQAMAgsgBARAIARBADYCBCAEQQ42AgALQQAPC0EAIQADQCABLQAABH4gASkDCCABKQMQfQVCAAtCBFQNASABEAwhByABIAEQDCIGrRATIghFBEBBACECIAQEQCAEQQA2AgQgBEEVNgIACyABEAggAEUNAwNAIAAoAgAhASAAKAIMEAYg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DCAAQRg2AggLDAMLIAAgBiAFLwFqQQAgBCABEQYAIQEgBhALIAFFDQILAkAgDUUEQCABIQMMAQsgACABIAUvAWgQgQEhAyABEAsgA0UNAQsCQCAJRSAMckUEQCADIQEMAQsgACADQQEQgAEhASADEAsgAUUNAQsgASEDDAELQQAhAwsgBUHwAGokACADC4UBAQF/IAFFBEAgAEEIaiIABEAgAEEANgIEIABBEjYCAAtBAA8LQTgQCSIDRQRAIABBCGoiAARAIABBADYCBCAAQQ42AgALQQAPCyADQQA2AhAgA0IANwIIIANCADcDKCADQQA2AgQgAyACNgIAIANCADcDGCADQQA2AjAgACABQTsgAxBCCw8AIAAgASACQQBBABCCAQusAgECfyABRQRAIABBCGoiAARAIABBADYCBCAAQRI2AgALQQAPCwJAIAJBfUsNACACQf//A3FBCEYNACAAQQhqIgAEQCAAQQA2AgQgAEEQNgIAC0EADwsCQEGwwAAQCSIFBEAgBUEANgIIIAVCADcCACAFQYiBAUGogQEgAxs2AqhAIAUgAjYCFCAFIAM6ABAgBUEAOgAPIAVBADsBDCAFIAMgAkF9SyIGcToADiAFQQggAiAGG0H//wNxIAQgBUGIgQFBqIEBIAMbKAIAEQAAIgI2AqxAIAINASAFEDEgBRAGCyAAQQhqIgAEQCAAQQA2AgQgAEEONgIAC0EADwsgACABQTogBRBCIgAEfyAABSAFKAKsQCAFKAKoQCgCBBEDACAFEDEgBRAGQQALC6ABAQF/IAIgACgCBCIDIAIgA0kbIgIEQCAAIAMgAms2AgQCQAJAAkACQCAAKAIcIgMoAhRBAWsOAgEAAgsgA0GgAWogASAAKAIAIAJB3IABKAIAEQgADAILIAAgACgCMCABIAAoAgAgAkHEgAEoAgARBAA2AjAMAQsgASAAKAIAIAIQBxoLIAAgACgCACACajYCACAAIAAoAgggAmo2AggLC7cCAQR/QX4hAgJAIABFDQAgACgCIEUNACAAKAIkIgRFDQAgACgCHCIBRQ0AIAEoAgAgAEcNAAJAAkAgASgCICIDQTlrDjkBAgICAgICAgICAgIBAgICAQICAgICAgICAgICAgICAgICAQICAgICAgICAgICAQICAgICAgICAgEACyADQZoFRg0AIANBKkcN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DCABajYCDCAGIAYoAgggAWo2AgggBSAFKAIUIAFqNgIUIAUgBSgCECABazYCECAGIAYoAhAgAWsiATYCECABDQAgBiAGKAIENgIIC0EAIQRBACEJIAMoAhBFDQAMCgsgAygCHCgCJCEGIAMgAygCGCIBQQFqNgIYIAEgBmotAAAhASADIARBAWo2AhAgAygCBCAEaiABOgAAIAEEQCADKAIQIQQMAQsLIAMoAhwoAixFDQAgAygCECIGIAlNDQAgBQJ/IAUoAjAhBEEAIAMoAgQgCWoiAUUNABogBCABIAYgCWtB1IABKAIAEQAACzYCMAsgA0HnADYCIAsCQCADKAIcKAIsBEAgAygCDCADKAIQIgFBAmpJBH8gBRAKIAMoAhANAkEABSABCyADKAIEaiAFKAIwOwAAIAMgAygCEEECajYCECADQaABakHkgAEoAgARAQAaCyADQfEANgIgIAUQCiADKAIQRQ0BDAcLDAYLIAUoAgQNAQsgAygCPA0AIApFDQEgAygCIEGaBUYNAQsCfyADKAKIASIBRQRAIAMgChCFAQwBCwJAAkACQCADKAKMAUECaw4CAAECCwJ/AkADQAJAAkAgAygCPA0AIAMQLyADKAI8DQAgCg0BQQAMBAsgAygCSCADKAJoai0AACEEIAMgAygC8C0iAUEBajYC8C0gASADKALsLWpBADoAACADIAMoAvAtIgFBAWo2AvAtIAEgAygC7C1qQQA6AAAgAyADKALwLSIBQQFqNgLwLSABIAMoAuwtaiAEOgAAIAMgBEECdGoiASABLwHkAUEBajsB5AEgAyADKAI8QQFrNgI8IAMgAygCaEEBaiIBNgJoIAMoAvAtIAMoAvQtRw0BQQAhBCADIAMoAlgiBkEATgR/IAMoAkggBmoFQQALIAEgBmtBABAPIAMgAygCaDYCWCADKAIAEAogAygCACgCEA0BDAILCyADQQA2AoQuIApBBEYEQCADIAMoAlgiAUEATgR/IAMoAkggAWoFQQALIAMoAmggAWtBARAPIAMgAygCaDYCWCADKAIAEApBA0ECIAMoAgAoAhAbDAILIAMoAvAtBEBBACEEIAMgAygCWCIBQQBOBH8gAygCSCABagVBAAsgAygCaCABa0EAEA8gAyADKAJoNgJYIAMoAgAQCiADKAIAKAIQRQ0BC0EBIQQLIAQLDAILAn8CQANAAkACQAJAAkACQCADKAI8Ig1BggJLDQAgAxAvAkAgAygCPCINQYICSw0AIAoNAEEADAgLIA1FDQQgDUECSw0AIAMoAmghCAwBCyADKAJoIghFBEBBACEIDAELIAMoAkggCGoiAUEBayIELQAAIgYgAS0AAEcNACAGIAQtAAJHDQAgBEEDaiEEQQAhCQJAA0AgBiAELQAARw0BIAQtAAEgBkcEQCAJQQFyIQkMAgsgBC0AAiAGRwRAIAlBAnIhCQwCCyAELQADIAZHBEAgCUEDciEJDAILIAQtAAQgBkcEQCAJQQRyIQkMAgsgBC0ABSAGRwRAIAlBBXIhCQwCCyAELQAGIAZHBEAgCUEGciEJDAILIAQtAAcgBkcEQCAJQQdyIQkMAgsgBEEIaiEEIAlB+AFJIQEgCUEIaiEJIAENAAtBgAIhCQtBggIhBCANIAlBAmoiASABIA1LGyIBQYECSw0BIAEiBEECSw0BCyADKAJIIAhqLQAAIQQgAyADKALwLSIBQQFqNgLwLSABIAMoAuwtakEAOgAAIAMgAygC8C0iAUEBajYC8C0gASADKALsLWpBADoAACADIAMoAvAtIgFBAWo2AvAtIAEgAygC7C1qIAQ6AAAgAyAEQQJ0aiIBIAEvAeQBQQFqOwHkASADIAMoAjxBAWs2AjwgAyADKAJoQQFqIgQ2AmgMAQsgAyADKALwLSIBQQFqNgLwLSABIAMoAuwtakEBOgAAIAMgAygC8C0iAUEBajYC8C0gASADKALsLWpBADoAACADIAMoAvAtIgFBAWo2AvAtIAEgAygC7C1qIARBA2s6AAAgAyADKAKALkEBajYCgC4gBEH9zgBqLQAAQQJ0IANqQegJaiIBIAEvAQBBAWo7AQAgA0GAywAtAABBAnRqQdgTaiIBIAEvAQBBAWo7AQAgAyADKAI8IARrNgI8IAMgAygCaCAEaiIENgJoCyADKALwLSADKAL0LUcNAUEAIQggAyADKAJYIgFBAE4EfyADKAJIIAFqBUEACyAEIAFrQQAQDyADIAMoAmg2AlggAygCABAKIAMoAgAoAhANAQwCCwsgA0EANgKELiAKQQRGBEAgAyADKAJYIgFBAE4EfyADKAJIIAFqBUEACyADKAJoIAFrQQEQDyADIAMoAmg2AlggAygCABAKQQNBAiADKAIAKAIQGwwCCyADKALwLQRAQQAhCCADIAMoAlgiAUEATgR/IAMoAkggAWoFQQALIAMoAmggAWtBABAPIAMgAygCaDYCWCADKAIAEAogAygCACgCEEUNAQtBASEICyAICwwBCyADIAogAUEMbEG42ABqKAIAEQIACyIBQX5xQQJGBEAgA0GaBTYCIAsgAUF9cUUEQEEAIQQgBSgCEA0CDAQLIAFBAUcNAAJAAkACQCAKQQFrDgUAAQEBAgELIAMpA5guISICfwJ+IAMoAqAuIgFBA2oiCUE/TQRAQgIgAa2GICKEDAELIAFBwABGBEAgAygCBCADKAIQaiAiNwAAIAMgAygCEEEIajYCEEICISJBCgwCCyADKAIEIAMoAhBqQgIgAa2GICKENwAAIAMgAygCEEEIajYCECABQT1rIQlCAkHAACABa62ICyEiIAlBB2ogCUE5SQ0AGiADKAIEIAMoAhBqICI3AAAgAyADKAIQQQhqNgIQQgAhIiAJQTlrCyEBIAMgIjcDmC4gAyABNgKgLiADEDAMAQsgA0EAQQBBABA5IApBA0cNACADKAJQQQBBgIAIEBkgAygCPA0AIANBADYChC4gA0EANgJYIANBADYCaAsgBRAKIAUoAhANAAwDC0EAIQQgCkEERw0AAkACfwJAAkAgAygCFEEBaw4CAQADCyAFIANBoAFqQeCAASgCABEBACIBNgIwIAMoAgQgAygCEGogATYAACADIAMoAhBBBGoiATYCECADKAIEIAFqIQQgBSgCCAwBCyADKAIEIAMoAhBqIQQgBSgCMCIBQRh0IAFBCHRBgID8B3FyIAFBCHZBgP4DcSABQRh2cnILIQEgBCABNgAAIAMgAygCEEEEajYCEAsgBRAKIAMoAhQiAUEBTgRAIANBACABazYCFAsgAygCEEUhBAsgBAwCCyAFQezAACgCADYCGEF7DAELIANBfzYCJEEACwwBCyMAQRBrIhQkAEF+IRcCQCABIgxFDQAgDCgCIEUNACAMKAIkRQ0AIAwoAhwiB0UNACAHKAIAIAxHDQAgBygCBCIIQbT+AGtBH0sNACAMKAIMIhBFDQAgDCgCACIBRQRAIAwoAgQNAQsgCEG//gBGBEAgB0HA/gA2AgRBwP4AIQgLIAdBpAFqIR8gB0G8BmohGSAHQbwBaiEcIAdBoAFqIR0gB0G4AWohGiAHQfwKaiEYIAdBQGshHiAHKAKIASEFIAwoAgQiICEGIAcoAoQBIQogDCgCECIPIRYCfwJAAkACQANAAkBBfSEEQQEhCQJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAIAhBtP4Aaw4fBwYICQolJicoBSwtLQsZGgQMAjIzATUANw0OAzlISUwLIAcoApQBIQMgASEEIAYhCAw1CyAHKAKUASEDIAEhBCAGIQgMMgsgBygCtAEhCAwuCyAHKAIMIQgMQQsgBUEOTw0pIAZFDUEgBUEIaiEIIAFBAWohBCAGQQFrIQkgAS0AACAFdCAKaiEKIAVBBkkNDCAEIQEgCSEGIAghBQwpCyAFQSBPDSUgBkUNQCABQQFqIQQgBkEBayEIIAEtAAAgBXQgCmohCiAFQRhJDQ0gBCEBIAghBgwlCyAFQRBPDRUgBkUNPyAFQQhqIQggAUEBaiEEIAZBAWshCSABLQAAIAV0IApqIQogBUEISQ0NIAQhASAJIQYgCCEFDBULIAcoAgwiC0UNByAFQRBPDSIgBkUNPiAFQQhqIQggAUEBaiEEIAZBAWshCSABLQAAIAV0IApqIQogBUEISQ0NIAQhASAJIQYgCCEFDCILIAVBH0sNFQwUCyAFQQ9LDRYMFQsgBygCFCIEQYAIcUUEQCAFIQgMFwsgCiEIIAVBD0sNGAwXCyAKIAVBB3F2IQogBUF4cSIFQR9LDQwgBkUNOiAFQQhqIQggAUEBaiEEIAZBAWshCSABLQAAIAV0IApqIQogBUEYSQ0GIAQhASAJIQYgCCEFDAwLIAcoArQBIgggBygCqAEiC08NIwwiCyAPRQ0qIBAgBygCjAE6AAAgB0HI/gA2AgQgD0EBayEPIBBBAWohECAHKAIEIQgMOQsgBygCDCIDRQRAQQAhCAwJCyAFQR9LDQcgBkUNNyAFQQhqIQggAUEBaiEEIAZBAWshCSABLQAAIAV0IApqIQogBUEYSQ0BIAQhASAJIQYgCCEFDAcLIAdBwP4ANgIEDCoLIAlFBEAgBCEBQQAhBiAIIQUgDSEEDDgLIAVBEGohCSABQQJqIQQgBkECayELIAEtAAEgCHQgCmohCiAFQQ9LBEAgBCEBIAshBiAJIQUMBgsgC0UEQCAEIQFBACEGIAkhBSANIQQMOAsgBUEYaiEIIAFBA2ohBCAGQQNrIQsgAS0AAiAJdCAKaiEKIAVBB0sEQCAEIQEgCyEGIAghBQwGCyALRQRAIAQhAUEAIQYgCCEFIA0hBAw4CyAFQSBqIQUgBkEEayEGIAEtAAMgCHQgCmohCiABQQRqIQEMBQsgCUUEQCAEIQFBACEGIAghBSANIQQMNwsgBUEQaiEFIAZBAmshBiABLQABIAh0IApqIQogAUECaiEBDBwLIAlFBEAgBCEBQQAhBiAIIQUgDSEEDDYLIAVBEGohCSABQQJqIQQgBkECayELIAEtAAEgCHQgCmohCiAFQQ9LBEAgBCEBIAshBiAJIQUMBgsgC0UEQCAEIQFBACEGIAkhBSANIQQMNgsgBUEYaiEIIAFBA2ohBCAGQQNrIQsgAS0AAiAJdCAKaiEKIAUEQCAEIQEgCyEGIAghBQwGCyALRQRAIAQhAUEAIQYgCCEFIA0hBAw2CyAFQSBqIQUgBkEEayEGIAEtAAMgCHQgCmohCiABQQRqIQEMBQsgBUEIaiEJIAhFBEAgBCEBQQAhBiAJIQUgDSEEDDULIAFBAmohBCAGQQJrIQggAS0AASAJdCAKaiEKIAVBD0sEQCAEIQEgCCEGDBgLIAVBEGohCSAIRQRAIAQhAUEAIQYgCSEFIA0hBAw1CyABQQNqIQQgBkEDayEIIAEtAAIgCXQgCmohCiAFQQdLBEAgBCEBIAghBgwYCyAFQRhqIQUgCEUEQCAEIQFBACEGIA0hBAw1CyAGQQRrIQYgAS0AAyAFdCAKaiEKIAFBBGohAQwXCyAJDQYgBCEBQQAhBiAIIQUgDSEEDDMLIAlFBEAgBCEBQQAhBiAIIQUgDSEEDDMLIAVBEGohBSAGQQJrIQYgAS0AASAIdCAKaiEKIAFBAmohAQwUCyAMIBYgD2siCSAMKAIUajYCFCAHIAcoAiAgCWo2AiACQCADQQRxRQ0AIAkEQAJAIBAgCWshBCAMKAIcIggoAhQEQCAIQUBrIAQgCUEAQdiAASgCABEIAAwBCyAIIAgoAhwgBCAJQcCAASgCABEAACIENgIcIAwgBDYCMAsLIAcoAhRFDQAgByAeQeCAASgCABEBACIENgIcIAwgBDYCMAsCQCAHKAIMIghBBHFFDQAgBygCHCAKIApBCHRBgID8B3EgCkEYdHIgCkEIdkGA/gNxIApBGHZyciAHKAIUG0YNACAHQdH+ADYCBCAMQaQMNgIYIA8hFiAHKAIEIQgMMQtBACEKQQAhBSAPIRYLIAdBz/4ANgIEDC0LIApB//8DcSIEIApBf3NBEHZHBEAgB0HR/gA2AgQgDEGOCjYCGCAHKAIEIQgMLwsgB0HC/gA2AgQgByAENgKMAUEAIQpBACEFCyAHQcP+ADYCBAsgBygCjAEiBARAIA8gBiAEIAQgBksbIgQgBCAPSxsiCEUNHiAQIAEgCBAHIQQgByAHKAKMASAIazYCjAEgBCAIaiEQIA8gCGshDyABIAhqIQEgBiAIayEGIAcoAgQhCAwtCyAHQb/+ADYCBCAHKAIEIQgMLAsgBUEQaiEFIAZBAmshBiABLQABIAh0IApqIQogAUECaiEBCyAHIAo2AhQgCkH/AXFBCEcEQCAHQdH+ADYCBCAMQYIPNgIYIAcoAgQhCAwrCyAKQYDAA3EEQCAHQdH+ADYCBCAMQY0JNgIYIAcoAgQhCAwrCyAHKAIkIgQEQCAEIApBCHZBAXE2AgALAkAgCkGABHFFDQAgBy0ADEEEcUUNACAUIAo7AAwgBwJ/IAcoAhwhBUEAIBRBDGoiBEUNABogBSAEQQJB1IABKAIAEQAACzYCHAsgB0G2/gA2AgRBACEFQQAhCgsgBkUNKCABQQFqIQQgBkEBayEIIAEtAAAgBXQgCmohCiAFQRhPBEAgBCEBIAghBgwBCyAFQQhqIQkgCEUEQCAEIQFBACEGIAkhBSANIQQMKwsgAUECaiEEIAZBAmshCCABLQABIAl0IApqIQogBUEPSwRAIAQhASAIIQYMAQsgBUEQaiEJIAhFBEAgBCEBQQAhBiAJIQUgDSEEDCsLIAFBA2ohBCAGQQNrIQggAS0AAiAJdCAKaiEKIAVBB0sEQCAEIQEgCCEGDAELIAVBGGohBSAIRQRAIAQhAUEAIQYgDSEEDCsLIAZBBGshBiABLQADIAV0IApqIQogAUEEaiEBCyAHKAIkIgQEQCAEIAo2AgQLAkAgBy0AFUECcUUNACAHLQAMQQRxRQ0AIBQgCjYADCAHAn8gBygCHCEFQQAgFEEMaiIERQ0AGiAFIARBBEHUgAEoAgARAAALNgIcCyAHQbf+ADYCBEEAIQVBACEKCyAGRQ0mIAFBAWohBCAGQQFrIQggAS0AACAFdCAKaiEKIAVBCE8EQCAEIQEgCCEGDAELIAVBCGohBSAIRQRAIAQhAUEAIQYgDSEEDCkLIAZBAmshBiABLQABIAV0IApqIQogAUECaiEBCyAHKAIkIgQEQCAEIApBCHY2AgwgBCAKQf8BcTYCCAsCQCAHLQAVQQJxRQ0AIActAAxBBHFFDQAgFCAKOwAMIAcCfyAHKAIcIQVBACAUQQxqIgRFDQAaIAUgBEECQdSAASgCABEAAAs2AhwLIAdBuP4ANgIEQQAhCEEAIQVBACEKIAcoAhQiBEGACHENAQsgBygCJCIEBEAgBEEANgIQCyAIIQUMAgsgBkUEQEEAIQYgCCEKIA0hBAwmCyABQQFqIQkgBkEBayELIAEtAAAgBXQgCGohCiAFQQhPBEAgCSEBIAshBgwBCyAFQQhqIQUgC0UEQCAJIQFBACEGIA0hBAwmCyAGQQJrIQYgAS0AASAFdCAKaiEKIAFBAmohAQsgByAKQf//A3EiCDYCjAEgBygCJCIFBEAgBSAINgIUC0EAIQUCQCAEQYAEcUUNACAHLQAMQQRxRQ0AIBQgCjsADCAHAn8gBygCHCEIQQAgFEEMaiIERQ0AGiAIIARBAkHUgAEoAgARAAALNgIcC0EAIQoLIAdBuf4ANgIECyAHKAIUIglBgAhxBEAgBiAHKAKMASIIIAYgCEkbIg4EQAJAIAcoAiQiA0UNACADKAIQIgRFDQAgAygCGCILIAMoAhQgCGsiCE0NACAEIAhqIAEgCyAIayAOIAggDmogC0sbEAcaIAcoAhQhCQsCQCAJQYAEcUUNACAHLQAMQQRxRQ0AIAcCfyAHKAIcIQRBACABRQ0AGiAEIAEgDkHUgAEoAgARAAALNgIcCyAHIAcoAowBIA5rIgg2AowBIAYgDmshBiABIA5qIQELIAgNEwsgB0G6/gA2AgQgB0EANgKMAQsCQCAHLQAVQQhxBEBBACEIIAZFDQQDQCABIAhqLQAAIQMCQCAHKAIkIgtFDQAgCygCHCIERQ0AIAcoAowBIgkgCygCIE8NACAHIAlBAWo2AowBIAQgCWogAzoAAAsgA0EAIAYgCEEBaiIISxsNAAsCQCAHLQAVQQJxRQ0AIActAAxBBHFFDQAgBwJ/IAcoAhwhBEEAIAFFDQAaIAQgASAIQdSAASgCABEAAAs2AhwLIAEgCGohASAGIAhrIQYgA0UNAQwTCyAHKAIkIgRFDQAgBEEANgIcCyAHQbv+ADYCBCAHQQA2AowBCwJAIActABVBEHEEQEEAIQggBkUNAwNAIAEgCGotAAAhAwJAIAcoAiQiC0UNACALKAIkIgRFDQAgBygCjAEiCSALKAIoTw0AIAcgCUEBajYCjAEgBCAJaiADOgAACyADQQAgBiAIQQFqIghLGw0ACwJAIActABVBAnFFDQAgBy0ADEEEcUUNACAHAn8gBygCHCEEQQAgAUUNABogBCABIAhB1IABKAIAEQAACzYCHAsgASAIaiEBIAYgCGshBiADRQ0BDBILIAcoAiQiBEUNACAEQQA2AiQLIAdBvP4ANgIECyAHKAIUIgtBgARxBEACQCAFQQ9LDQAgBkUNHyAFQQhqIQggAUEBaiEEIAZBAWshCSABLQAAIAV0IApqIQogBUEITwRAIAQhASAJIQYgCCEFDAELIAlFBEAgBCEBQQAhBiAIIQUgDSEEDCILIAVBEGohBSAGQQJrIQYgAS0AASAIdCAKaiEKIAFBAmohAQsCQCAHLQAMQQRxRQ0AIAogBy8BHEYNACAHQdH+ADYCBCAMQdcMNgIYIAcoAgQhCAwgC0EAIQpBACEFCyAHKAIkIgQEQCAEQQE2AjAgBCALQQl2QQFxNgIsCwJAIActAAxBBHFFDQAgC0UNACAHIB5B5IABKAIAEQEAIgQ2AhwgDCAENgIwCyAHQb/+ADYCBCAHKAIEIQgMHgtBACEGDA4LAkAgC0ECcUUNACAKQZ+WAkcNACAHKAIoRQRAIAdBDzYCKAtBACEKIAdBADYCHCAUQZ+WAjsADCAHIBRBDGoiBAR/QQAgBEECQdSAASgCABEAAAVBAAs2AhwgB0G1/gA2AgRBACEFIAcoAgQhCAwdCyAHKAIkIgQEQCAEQX82AjALAkAgC0EBcQRAIApBCHRBgP4DcSAKQQh2akEfcEUNAQsgB0HR/gA2AgQgDEH2CzYCGCAHKAIEIQgMHQsgCkEPcUEIRwRAIAdB0f4ANgIEIAxBgg82AhggBygCBCEIDB0LIApBBHYiBEEPcSIJQQhqIQsgCUEHTUEAIAcoAigiCAR/IAgFIAcgCzYCKCALCyALTxtFBEAgBUEEayEFIAdB0f4ANgIEIAxB+gw2AhggBCEKIAcoAgQhCAwdCyAHQQE2AhxBACEFIAdBADYCFCAHQYACIAl0NgIYIAxBATYCMCAHQb3+AEG//gAgCkGAwABxGzYCBEEAIQogBygCBCEIDBwLIAcgCkEIdEGAgPwHcSAKQRh0ciAKQQh2QYD+A3EgCkEYdnJyIgQ2AhwgDCAENgIwIAdBvv4ANgIEQQAhCkEAIQULIAcoAhBFBEAgDCAPNgIQIAwgEDYCDCAMIAY2AgQgDCABNgIAIAcgBTYCiAEgByAKNgKEAUECIRcMIAsgB0EBNgIcIAxBATYCMCAHQb/+ADYCBAsCfwJAIAcoAghFBEAgBUEDSQ0BIAUMAgsgB0HO/gA2AgQgCiAFQQdxdiEKIAVBeHEhBSAHKAIEIQgMGwsgBkUNGSAGQQFrIQYgAS0AACAFdCAKaiEKIAFBAWohASAFQQhqCyEEIAcgCkEBcTYCCAJAAkACQAJAAkAgCkEBdkEDcUEBaw4DAQIDAAsgB0HB/gA2AgQMAwsgB0Gw2wA2ApgBIAdCiYCAgNAANwOgASAHQbDrADYCnAEgB0HH/gA2AgQMAgsgB0HE/gA2AgQMAQsgB0HR/gA2AgQgDEHXDTYCGAsgBEEDayEFIApBA3YhCiAHKAIEIQgMGQsgByAKQR9xIghBgQJqNgKsASAHIApBBXZBH3EiBEEBajYCsAEgByAKQQp2QQ9xQQRqIgs2AqgBIAVBDmshBSAKQQ52IQogCEEdTUEAIARBHkkbRQRAIAdB0f4ANgIEIAxB6gk2AhggBygCBCEIDBkLIAdBxf4ANgIEQQAhCCAHQQA2ArQBCyAIIQQDQCAFQQJNBEAgBkUNGCAGQQFrIQYgAS0AACAFdCAKaiEKIAVBCGohBSABQQFqIQELIAcgBEEBaiIINgK0ASAHIARBAXRBsOwAai8BAEEBdGogCkEHcTsBvAEgBUEDayEFIApBA3YhCiALIAgiBEsNAAsLIAhBEk0EQEESIAhrIQ1BAyAIa0EDcSIEBEADQCAHIAhBAXRBsOwAai8BAEEBdGpBADsBvAEgCEEBaiEIIARBAWsiBA0ACwsgDUEDTwRAA0AgB0G8AWoiDSAIQQF0IgRBsOwAai8BAEEBdGpBADsBACANIARBsuwAai8BAEEBdGpBADsBACANIARBtOwAai8BAEEBdGpBADsBACANIARBtuwAai8BAEEBdGpBADsBACAIQQRqIghBE0cNAAsLIAdBEzYCtAELIAdBBzYCoAEgByAYNgKYASAHIBg2ArgBQQAhCEEAIBxBEyAaIB0gGRBOIg0EQCAHQdH+ADYCBCAMQfQINgIYIAcoAgQhCAwXCyAHQcb+ADYCBCAHQQA2ArQBQQAhDQsgBygCrAEiFSAHKAKwAWoiESAISwRAQX8gBygCoAF0QX9zIRIgBygCmAEhGwNAIAYhCSABIQsCQCAFIgMgGyAKIBJxIhNBAnRqLQABIg5PBEAgBSEEDAELA0AgCUUNDSALLQAAIAN0IQ4gC0EBaiELIAlBAWshCSADQQhqIgQhAyAEIBsgCiAOaiIKIBJxIhNBAnRqLQABIg5JDQALIAshASAJIQYLAkAgGyATQQJ0ai8BAiIFQQ9NBEAgByAIQQFqIgk2ArQBIAcgCEEBdGogBTsBvAEgBCAOayEFIAogDnYhCiAJIQgMAQsCfwJ/AkACQAJAIAVBEGsOAgABAgsgDkECaiIFIARLBEADQCAGRQ0bIAZBAWshBiABLQAAIAR0IApqIQogAUEBaiEBIARBCGoiBCAFSQ0ACwsgBCAOayEFIAogDnYhBCAIRQRAIAdB0f4ANgIEIAxBvAk2AhggBCEKIAcoAgQhCAwdCyAFQQJrIQUgBEECdiEKIARBA3FBA2ohCSAIQQF0IAdqLwG6AQwDCyAOQQNqIgUgBEsEQANAIAZFDRogBkEBayEGIAEtAAAgBHQgCmohCiABQQFqIQEgBEEIaiIEIAVJDQALCyAEIA5rQQNrIQUgCiAOdiIEQQN2IQogBEEHcUEDagwBCyAOQQdqIgUgBEsEQANAIAZFDRkgBkEBayEGIAEtAAAgBHQgCmohCiABQQFqIQEgBEEIaiIEIAVJDQALCyAEIA5rQQdrIQUgCiAOdiIEQQd2IQogBEH/AHFBC2oLIQlBAAshAyAIIAlqIBFLDRMgCUEBayEEIAlBA3EiCwRAA0AgByAIQQF0aiADOwG8ASAIQQFqIQggCUEBayEJIAtBAWsiCw0ACwsgBEEDTwRAA0AgByAIQQF0aiIEIAM7Ab4BIAQgAzsBvAEgBCADOwHAASAEIAM7AcIBIAhBBGohCCAJQQRrIgkNAAsLIAcgCDYCtAELIAggEUkNAAsLIAcvAbwFRQRAIAdB0f4ANgIEIAxB0Qs2AhggBygCBCEIDBYLIAdBCjYCoAEgByAYNgKYASAHIBg2ArgBQQEgHCAVIBogHSAZEE4iDQRAIAdB0f4ANgIEIAxB2Ag2AhggBygCBCEIDBYLIAdBCTYCpAEgByAHKAK4ATYCnAFBAiAHIAcoAqwBQQF0akG8AWogBygCsAEgGiAfIBkQTiINBEAgB0HR/gA2AgQgDEGmCTYCGCAHKAIEIQgMFgsgB0HH/gA2AgRBACENCyAHQcj+ADYCBAsCQCAGQQ9JDQAgD0GEAkkNACAMIA82AhAgDCAQNgIMIAwgBjYCBCAMIAE2AgAgByAFNgKIASAHIAo2AoQBIAwgFkHogAEoAgARBwAgBygCiAEhBSAHKAKEASEKIAwoAgQhBiAMKAIAIQEgDCgCECEPIAwoAgwhECAHKAIEQb/+AEcNByAHQX82ApBHIAcoAgQhCAwUCyAHQQA2ApBHIAUhCSAGIQggASEEAkAgBygCmAEiEiAKQX8gBygCoAF0QX9zIhVxIg5BAnRqLQABIgsgBU0EQCAFIQMMAQsDQCAIRQ0PIAQtAAAgCXQhCyAEQQFqIQQgCEEBayEIIAlBCGoiAyEJIAMgEiAKIAtqIgogFXEiDkECdGotAAEiC0kNAAsLIBIgDkECdGoiAS8BAiETAkBBACABLQAAIhEgEUHwAXEbRQRAIAshBgwBCyAIIQYgBCEBAkAgAyIFIAsgEiAKQX8gCyARanRBf3MiFXEgC3YgE2oiEUECdGotAAEiDmpPBEAgAyEJDAELA0AgBkUNDyABLQAAIAV0IQ4gAUEBaiEBIAZBAWshBiAFQQhqIgkhBSALIBIgCiAOaiIKIBVxIAt2IBNqIhFBAnRqLQABIg5qIAlLDQALIAEhBCAGIQgLIBIgEUECdGoiAS0AACERIAEvAQIhEyAHIAs2ApBHIAsgDmohBiAJIAtrIQMgCiALdiEKIA4hCwsgByAGNgKQRyAHIBNB//8DcTYCjAEgAyALayEFIAogC3YhCiARRQRAIAdBzf4ANgIEDBALIBFBIHEEQCAHQb/+ADYCBCAHQX82ApBHDBALIBFBwABxBEAgB0HR/gA2AgQgDEHQDjYCGAwQCyAHQcn+ADYCBCAHIBFBD3EiAzYClAELAkAgA0UEQCAHKAKMASELIAQhASAIIQYMAQsgBSEJIAghBiAEIQsCQCADIAVNBEAgBCEBDAELA0AgBkUNDSAGQQFrIQYgCy0AACAJdCAKaiEKIAtBAWoiASELIAlBCGoiCSADSQ0ACwsgByAHKAKQRyADajYCkEcgByAHKAKMASAKQX8gA3RBf3NxaiILNgKMASAJIANrIQUgCiADdiEKCyAHQcr+ADYCBCAHIAs2ApRHCyAFIQkgBiEIIAEhBAJAIAcoApwBIhIgCkF/IAcoAqQBdEF/cyIVcSIOQQJ0ai0AASIDIAVNBEAgBSELDAELA0AgCEUNCiAELQAAIAl0IQMgBEEBaiEEIAhBAWshCCAJQQhqIgshCSALIBIgAyAKaiIKIBVxIg5BAnRqLQABIgNJDQALCyASIA5BAnRqIgEvAQIhEwJAIAEtAAAiEUHwAXEEQCAHKAKQRyEGIAMhCQwBCyAIIQYgBCEBAkAgCyIFIAMgEiAKQX8gAyARanRBf3MiFXEgA3YgE2oiEUECdGotAAEiCWpPBEAgCyEODAELA0AgBkUNCiABLQAAIAV0IQkgAUEBaiEBIAZBAWshBiAFQQhqIg4hBSADIBIgCSAKaiIKIBVxIAN2IBNqIhFBAnRqLQABIglqIA5LDQALIAEhBCAGIQgLIBIgEUECdGoiAS0AACERIAEvAQIhEyAHIAcoApBHIANqIgY2ApBHIA4gA2shCyAKIAN2IQoLIAcgBiAJajYCkEcgCyAJayEFIAogCXYhCiARQcAAcQRAIAdB0f4ANgIEIAxB7A42AhggBCEBIAghBiAHKAIEIQgMEgsgB0HL/gA2AgQgByARQQ9xIgM2ApQBIAcgE0H//wNxNgKQAQsCQCADRQRAIAQhASAIIQYMAQsgBSEJIAghBiAEIQsCQCADIAVNBEAgBCEBDAELA0AgBkUNCCAGQQFrIQYgCy0AACAJdCAKaiEKIAtBAWoiASELIAlBCGoiCSADSQ0ACwsgByAHKAKQRyADajYCkEcgByAHKAKQASAKQX8gA3RBf3NxajYCkAEgCSADayEFIAogA3YhCgsgB0HM/gA2AgQLIA9FDQACfyAHKAKQASIIIBYgD2siBEsEQAJAIAggBGsiCCAHKAIwTQ0AIAcoAoxHRQ0AIAdB0f4ANgIEIAxBuQw2AhggBygCBCEIDBILAn8CQAJ/IAcoAjQiBCAISQRAIAcoAjggBygCLCAIIARrIghragwBCyAHKAI4IAQgCGtqCyILIBAgDyAQaiAQa0EBaqwiISAPIAcoAowBIgQgCCAEIAhJGyIEIAQgD0sbIgitIiIgISAiVBsiIqciCWoiBEkgCyAQT3ENACALIBBNIAkgC2ogEEtxDQAgECALIAkQBxogBAwBCyAQIAsgCyAQayIEIARBH3UiBGogBHMiCRAHIAlqIQQgIiAJrSIkfSIjUEUEQCAJIAtqIQkDQAJAICMgJCAjICRUGyIiQiBUBEAgIiEhDAELICIiIUIgfSImQgWIQgF8QgODIiVQRQRAA0AgBCAJKQAANwAAIAQgCSkAGDcAGCAEIAkpABA3ABAgBCAJKQAINwAIICFCIH0hISAJQSBqIQkgBEEgaiEEICVCAX0iJUIAUg0ACwsgJkLgAFQNAANAIAQgCSkAADcAACAEIAkpABg3ABggBCAJKQAQNwAQIAQgCSkACDcACCAEIAkpADg3ADggBCAJKQAwNwAwIAQgCSkAKDcAKCAEIAkpACA3ACAgBCAJKQBYNwBYIAQgCSkAUDcAUCAEIAkpAEg3AEggBCAJKQBANwBAIAQgCSkAYDcAYCAEIAkpAGg3AGggBCAJKQBwNwBwIAQgCSkAeDcAeCAJQYABaiEJIARBgAFqIQQgIUKAAX0iIUIfVg0ACwsgIUIQWgRAIAQgCSkAADcAACAEIAkpAAg3AAggIUIQfSEhIAlBEGohCSAEQRBqIQQLICFCCFoEQCAEIAkpAAA3AAAgIUIIfSEhIAlBCGohCSAEQQhqIQQLICFCBFoEQCAEIAkoAAA2AAAgIUIEfSEhIAlBBGohCSAEQQRqIQQLICFCAloEQCAEIAkvAAA7AAAgIUICfSEhIAlBAmohCSAEQQJqIQQLICMgIn0hIyAhUEUEQCAEIAktAAA6AAAgCUEBaiEJIARBAWohBAsgI0IAUg0ACwsgBAsMAQsgECAIIA8gBygCjAEiBCAEIA9LGyIIIA9ByIABKAIAEQQACyEQIAcgBygCjAEgCGsiBDYCjAEgDyAIayEPIAQNAiAHQcj+ADYCBCAHKAIEIQgMDwsgDSEJCyAJIQQMDgsgBygCBCEIDAwLIAEgBmohASAFIAZBA3RqIQUMCgsgBCAIaiEBIAUgCEEDdGohBQwJCyAEIAhqIQEgCyAIQQN0aiEFDAgLIAEgBmohASAFIAZBA3RqIQUMBwsgBCAIaiEBIAUgCEEDdGohBQwGCyAEIAhqIQEgAyAIQQN0aiEFDAULIAEgBmohASAFIAZBA3RqIQUMBAsgB0HR/gA2AgQgDEG8CTYCGCAHKAIEIQgMBAsgBCEBIAghBiAHKAIEIQgMAwtBACEGIAQhBSANIQQMAwsCQAJAIAhFBEAgCiEJDAELIAcoAhRFBEAgCiEJDAELAkAgBUEfSw0AIAZFDQMgBUEIaiEJIAFBAWohBCAGQQFrIQsgAS0AACAFdCAKaiEKIAVBGE8EQCAEIQEgCyEGIAkhBQwBCyALRQRAIAQhAUEAIQYgCSEFIA0hBAwGCyAFQRBqIQsgAUECaiEEIAZBAmshAyABLQABIAl0IApqIQogBUEPSwRAIAQhASADIQYgCyEFDAELIANFBEAgBCEBQQAhBiALIQUgDSEEDAYLIAVBGGohCSABQQNqIQQgBkEDayEDIAEtAAIgC3QgCmohCiAFQQdLBEAgBCEBIAMhBiAJIQUMAQsgA0UEQCAEIQFBACEGIAkhBSANIQQMBgsgBUEgaiEFIAZBBGshBiABLQADIAl0IApqIQogAUEEaiEBC0EAIQkgCEEEcQRAIAogBygCIEcNAgtBACEFCyAHQdD+ADYCBEEBIQQgCSEKDAMLIAdB0f4ANgIEIAxBjQw2AhggBygCBCEIDAELC0EAIQYgDSEECyAMIA82AhAgDCAQNgIMIAwgBjYCBCAMIAE2AgAgByAFNgKIASAHIAo2AoQBAkAgBygCLA0AIA8gFkYNAiAHKAIEIgFB0P4ASw0CIAFBzv4ASQ0ACwJ/IBYgD2shCiAHKAIMQQRxIQkCQAJAAkAgDCgCHCIDKAI4Ig1FBEBBASEIIAMgAygCACIBKAIgIAEoAiggAygCmEdBASADKAIodGpBARAoIg02AjggDUUNAQsgAygCLCIGRQRAIANCADcDMCADQQEgAygCKHQiBjYCLAsgBiAKTQRAAkAgCQRAAkAgBiAKTw0AIAogBmshBSAQIAprIQEgDCgCHCIGKAIUBEAgBkFAayABIAVBAEHYgAEoAgARCAAMAQsgBiAGKAIcIAEgBUHAgAEoAgARAAAiATYCHCAMIAE2AjALIAMoAiwiDUUNASAQIA1rIQUgAygCOCEBIAwoAhwiBigCFARAIAZBQGsgASAFIA1B3IABKAIAEQgADAILIAYgBigCHCABIAUgDUHEgAEoAgARBAAiATYCHCAMIAE2AjAMAQsgDSAQIAZrIAYQBxoLIANBADYCNCADIAMoAiw2AjBBAAwECyAKIAYgAygCNCIFayIBIAEgCksbIQsgECAKayEGIAUgDWohBQJAIAkEQAJAIAtFDQAgDCgCHCIBKAIUBEAgAUFAayAFIAYgC0HcgAEoAgARCAAMAQsgASABKAIcIAUgBiALQcSAASgCABEEACIBNgIcIAwgATYCMAsgCiALayIFRQ0BIBAgBWshBiADKAI4IQEgDCgCHCINKAIUBEAgDUFAayABIAYgBUHcgAEoAgARCAAMBQsgDSANKAIcIAEgBiAFQcSAASgCABEEACIBNgIcIAwgATYCMAwECyAFIAYgCxAHGiAKIAtrIgUNAgtBACEIIANBACADKAI0IAtqIgUgBSADKAIsIgFGGzYCNCABIAMoAjAiAU0NACADIAEgC2o2AjALIAgMAgsgAygCOCAQIAVrIAUQBxoLIAMgBTYCNCADIAMoAiw2AjBBAAtFBEAgDCgCECEPIAwoAgQhFyAHKAKIAQwDCyAHQdL+ADYCBAtBfCEXDAILIAYhFyAFCyEFIAwgICAXayIBIAwoAghqNgIIIAwgFiAPayIGIAwoAhRqNgIUIAcgBygCICAGajYCICAMIAcoAghBAEdBBnQgBWogBygCBCIFQb/+AEZBB3RqQYACIAVBwv4ARkEIdCAFQcf+AEYbajYCLCAEIARBeyAEGyABIAZyGyEXCyAUQRBqJAAgFwshASACIAIpAwAgADUCIH03AwACQAJAAkACQCABQQVqDgcBAgICAgMAAgtBAQ8LIAAoAhQNAEEDDwsgACgCACIABEAgACABNgIEIABBDTYCAAtBAiEBCyABCwkAIABBAToADAtEAAJAIAJC/////w9YBEAgACgCFEUNAQsgACgCACIABEAgAEEANgIEIABBEjYCAAtBAA8LIAAgATYCECAAIAI+AhRBAQu5AQEEfyAAQRBqIQECfyAALQAEBEAgARCEAQwBC0F+IQMCQCABRQ0AIAEoAiBFDQAgASgCJCIERQ0AIAEoAhwiAkUNACACKAIAIAFHDQAgAigCBEG0/gBrQR9LDQAgAigCOCIDBEAgBCABKAIoIAMQHiABKAIkIQQgASgCHCECCyAEIAEoAiggAhAeQQAhAyABQQA2AhwLIAMLIgEEQCAAKAIAIgAEQCAAIAE2AgQgAEENNgIACwsgAUUL0gwBBn8gAEIANwIQIABCADcCHCAAQRBqIQICfyAALQAEBEAgACgCCCEBQesMLQAAQTFGBH8Cf0F+IQMCQCACRQ0AIAJBADYCGCACKAIgIgRFBEAgAkEANgIoIAJBJzYCIEEnIQQLIAIoAiRFBEAgAkEoNgIkC0EGIAEgAUF/RhsiBUEASA0AIAVBCUoNAEF8IQMgBCACKAIoQQFB0C4QKCIBRQ0AIAIgATYCHCABIAI2AgAgAUEPNgI0IAFCgICAgKAFNwIcIAFBADYCFCABQYCAAjYCMCABQf//ATYCOCABIAIoAiAgAigCKEGAgAJBAhAoNgJIIAEgAigCICACKAIoIAEoAjBBAhAoIgM2AkwgA0EAIAEoAjBBAXQQGSACKAIgIAIoAihBgIAEQQIQKCEDIAFBgIACNgLoLSABQQA2AkAgASADNgJQIAEgAigCICACKAIoQYCAAkEEECgiAzYCBCABIAEoAugtIgRBAnQ2AgwCQAJAIAEoAkhFDQAgASgCTEUNACABKAJQRQ0AIAMNAQsgAUGaBTYCICACQejAACgCADYCGCACEIQBGkF8DAILIAFBADYCjAEgASAFNgKIASABQgA3AyggASADIARqNgLsLSABIARBA2xBA2s2AvQtQX4hAwJAIAJFDQAgAigCIEUNACACKAIkRQ0AIAIoAhwiAUUNACABKAIAIAJHDQACQAJAIAEoAiAiBEE5aw45AQICAgICAgICAgICAQICAgECAgICAgICAgICAgICAgICAgECAgICAgICAgICAgECAgICAgICAgIBAAsgBEGaBUYNACAEQSpHDQELIAJBAjYCLCACQQA2AgggAkIANwIUIAFBADYCECABIAEoAgQ2AgggASgCFCIDQX9MBEAgAUEAIANrIgM2AhQLIAFBOUEqIANBAkYbNgIgIAIgA0ECRgR/IAFBoAFqQeSAASgCABEBAAVBAQs2AjAgAUF+NgIkIAFBADYCoC4gAUIANwOYLiABQYgXakGg0wA2AgAgASABQcwVajYCgBcgAUH8FmpBjNMANgIAIAEgAUHYE2o2AvQWIAFB8BZqQfjSADYCACABIAFB5AFqNgLoFiABEIgBQQAhAwsgAw0AIAIoAhwiAiACKAIwQQF0NgJEQQAhAyACKAJQQQBBgIAIEBkgAiACKAKIASIEQQxsIgFBtNgAai8BADYClAEgAiABQbDYAGovAQA2ApABIAIgAUGy2ABqLwEANgJ4IAIgAUG22ABqLwEANgJ0QfiAASgCACEFQeyAASgCACEGQYCBASgCACEBIAJCADcCbCACQgA3AmQgAkEANgI8IAJBADYChC4gAkIANwJUIAJBKSABIARBCUYiARs2AnwgAkEqIAYgARs2AoABIAJBKyAFIAEbNgKEAQsgAwsFQXoLDAELAn9BekHrDC0AAEExRw0AGkF+IAJFDQAaIAJBADYCGCACKAIgIgNFBEAgAkEANgIoIAJBJzYCIEEnIQMLIAIoAiRFBEAgAkEoNgIkC0F8IAMgAigCKEEBQaDHABAoIgRFDQAaIAIgBDYCHCAEQQA2AjggBCACNgIAIARBtP4ANgIEIARBzIABKAIAEQkANgKYR0F+IQMCQCACRQ0AIAIoAiBFDQAgAigCJCIFRQ0AIAIoAhwiAUUNACABKAIAIAJHDQAgASgCBEG0/gBrQR9LDQACQAJAIAEoAjgiBgRAIAEoAihBD0cNAQsgAUEPNgIoIAFBADYCDAwBCyAFIAIoAiggBhAeIAFBADYCOCACKAIgIQUgAUEPNgIoIAFBADYCDCAFRQ0BCyACKAIkRQ0AIAIoAhwiAUUNACABKAIAIAJHDQAgASgCBEG0/gBrQR9LDQBBACEDIAFBADYCNCABQgA3AiwgAUEANgIgIAJBADYCCCACQgA3AhQgASgCDCIFBEAgAiAFQQFxNgIwCyABQrT+ADcCBCABQgA3AoQBIAFBADYCJCABQoCAgoAQNwMYIAFCgICAgHA3AxAgAUKBgICAcDcCjEcgASABQfwKaiIFNgK4ASABIAU2ApwBIAEgBTYCmAELQQAgA0UNABogAigCJCACKAIoIAQQHiACQQA2AhwgAwsLIgIEQCAAKAIAIgAEQCAAIAI2AgQgAEENNgIACwsgAkULKQEBfyAALQAERQRAQQAPC0ECIQEgACgCCCIAQQNOBH8gAEEHSgVBAgsLBgAgABAGC2MAQcgAEAkiAEUEQEGEhAEoAgAhASACBEAgAiABNgIEIAJBATYCAAsgAA8LIABBADoADCAAQQE6AAQgACACNgIAIABBADYCOCAAQgA3AzAgACABQQkgAUEBa0EJSRs2AgggAAukCgIIfwF+QfCAAUH0gAEgACgCdEGBCEkbIQYCQANAAkACfwJAIAAoAjxBhQJLDQAgABAvAkAgACgCPCICQYUCSw0AIAENAEEADwsgAkUNAiACQQRPDQBBAAwBCyAAIAAoAmggACgChAERAgALIQMgACAAKAJsOwFgQQIhAgJAIAA1AmggA619IgpCAVMNACAKIAAoAjBBhgJrrVUNACAAKAJwIAAoAnhPDQAgA0UNACAAIAMgBigCABECACICQQVLDQBBAiACIAAoAowBQQFGGyECCwJAIAAoAnAiA0EDSQ0AIAIgA0sNACAAIAAoAvAtIgJBAWo2AvAtIAAoAjwhBCACIAAoAuwtaiAAKAJoIgcgAC8BYEF/c2oiAjoAACAAIAAoAvAtIgVBAWo2AvAtIAUgACgC7C1qIAJBCHY6AAAgACAAKALwLSIFQQFqNgLwLSAFIAAoAuwtaiADQQNrOgAAIAAgACgCgC5BAWo2AoAuIANB/c4Aai0AAEECdCAAakHoCWoiAyADLwEAQQFqOwEAIAAgAkEBayICIAJBB3ZBgAJqIAJBgAJJG0GAywBqLQAAQQJ0akHYE2oiAiACLwEAQQFqOwEAIAAgACgCcCIFQQFrIgM2AnAgACAAKAI8IANrNgI8IAAoAvQtIQggACgC8C0hCSAEIAdqQQNrIgQgACgCaCICSwRAIAAgAkEBaiAEIAJrIgIgBUECayIEIAIgBEkbIAAoAoABEQUAIAAoAmghAgsgAEEANgJkIABBADYCcCAAIAIgA2oiBDYCaCAIIAlHDQJBACECIAAgACgCWCIDQQBOBH8gACgCSCADagVBAAsgBCADa0EAEA8gACAAKAJoNgJYIAAoAgAQCiAAKAIAKAIQDQIMAwsgACgCZARAIAAoAmggACgCSGpBAWstAAAhAyAAIAAoAvAtIgRBAWo2AvAtIAQgACgC7C1qQQA6AAAgACAAKALwLSIEQQFqNgLwLSAEIAAoAuwtakEAOgAAIAAgACgC8C0iBEEBajYC8C0gBCAAKALsLWogAzoAACAAIANBAnRqIgMgAy8B5AFBAWo7AeQBIAAoAvAtIAAoAvQtRgRAIAAgACgCWCIDQQBOBH8gACgCSCADagVBAAsgACgCaCADa0EAEA8gACAAKAJoNgJYIAAoAgAQCgsgACACNgJwIAAgACgCaEEBajYCaCAAIAAoAjxBAWs2AjwgACgCACgCEA0CQQAPBSAAQQE2AmQgACACNgJwIAAgACgCaEEBajYCaCAAIAAoAjxBAWs2AjwMAgsACwsgACgCZARAIAAoAmggACgCSGpBAWstAAAhAiAAIAAoAvAtIgNBAWo2AvAtIAMgACgC7C1qQQA6AAAgACAAKALwLSIDQQFqNgLwLSADIAAoAuwtakEAOgAAIAAgACgC8C0iA0EBajYC8C0gAyAAKALsLWogAjoAACAAIAJBAnRqIgIgAi8B5AFBAWo7AeQBIAAoAvAtIAAoAvQtRhogAEEANgJkCyAAIAAoAmgiA0ECIANBAkkbNgKELiABQQRGBEAgACAAKAJYIgFBAE4EfyAAKAJIIAFqBUEACyADIAFrQQEQDyAAIAAoAmg2AlggACgCABAKQQNBAiAAKAIAKAIQGw8LIAAoAvAtBEBBACECIAAgACgCWCIBQQBOBH8gACgCSCABagVBAAsgAyABa0EAEA8gACAAKAJoNgJYIAAoAgAQCiAAKAIAKAIQRQ0BC0EBIQILIAIL2BACEH8BfiAAKAKIAUEFSCEOA0ACQAJ/AkACQAJAAn8CQAJAIAAoAjxBhQJNBEAgABAvIAAoAjwiA0GFAksNASABDQFBAA8LIA4NASAIIQMgBSEHIAohDSAGQf//A3FFDQEMAwsgA0UNA0EAIANBBEkNARoLIAAgACgCaEH4gAEoAgARAgALIQZBASECQQAhDSAAKAJoIgOtIAatfSISQgFTDQIgEiAAKAIwQYYCa61VDQIgBkUNAiAAIAZB8IABKAIAEQIAIgZBASAGQfz/A3EbQQEgACgCbCINQf//A3EgA0H//wNxSRshBiADIQcLAkAgACgCPCIEIAZB//8DcSICQQRqTQ0AIAZB//8DcUEDTQRAQQEgBkEBa0H//wNxIglFDQQaIANB//8DcSIEIAdBAWpB//8DcSIDSw0BIAAgAyAJIAQgA2tBAWogAyAJaiAESxtB7IABKAIAEQUADAELAkAgACgCeEEEdCACSQ0AIARBBEkNACAGQQFrQf//A3EiDCAHQQFqQf//A3EiBGohCSAEIANB//8DcSIDTwRAQeyAASgCACELIAMgCUkEQCAAIAQgDCALEQUADAMLIAAgBCADIARrQQFqIAsRBQAMAgsgAyAJTw0BIAAgAyAJIANrQeyAASgCABEFAAwBCyAGIAdqQf//A3EiA0UNACAAIANBAWtB+IABKAIAEQIAGgsgBgwCCyAAIAAoAmgiBUECIAVBAkkbNgKELiABQQRGBEBBACEDIAAgACgCWCIBQQBOBH8gACgCSCABagVBAAsgBSABa0EBEA8gACAAKAJoNgJYIAAoAgAQCkEDQQIgACgCACgCEBsPCyAAKALwLQRAQQAhAkEAIQMgACAAKAJYIgFBAE4EfyAAKAJIIAFqBUEACyAFIAFrQQAQDyAAIAAoAmg2AlggACgCABAKIAAoAgAoAhBFDQMLQQEhAgwCCyADIQdBAQshBEEAIQYCQCAODQAgACgCPEGHAkkNACACIAdB//8DcSIQaiIDIAAoAkRBhgJrTw0AIAAgAzYCaEEAIQogACADQfiAASgCABECACEFAn8CQCAAKAJoIgitIAWtfSISQgFTDQAgEiAAKAIwQYYCa61VDQAgBUUNACAAIAVB8IABKAIAEQIAIQYgAC8BbCIKIAhB//8DcSIFTw0AIAZB//8DcSIDQQRJDQAgCCAEQf//A3FBAkkNARogCCACIApBAWpLDQEaIAggAiAFQQFqSw0BGiAIIAAoAkgiCSACa0EBaiICIApqLQAAIAIgBWotAABHDQEaIAggCUEBayICIApqIgwtAAAgAiAFaiIPLQAARw0BGiAIIAUgCCAAKAIwQYYCayICa0H//wNxQQAgAiAFSRsiEU0NARogCCADQf8BSw0BGiAGIQUgCCECIAQhAyAIIAoiCUECSQ0BGgNAAkAgA0EBayEDIAVBAWohCyAJQQFrIQkgAkEBayECIAxBAWsiDC0AACAPQQFrIg8tAABHDQAgA0H//wNxRQ0AIBEgAkH//wNxTw0AIAVB//8DcUH+AUsNACALIQUgCUH//wNxQQFLDQELCyAIIANB//8DcUEBSw0BGiAIIAtB//8DcUECRg0BGiAIQQFqIQggAyEEIAshBiAJIQogAgwBC0EBIQYgCAshBSAAIBA2AmgLAn8gBEH//wNxIgNBA00EQCAEQf//A3EiA0UNAyAAKAJIIAdB//8DcWotAAAhBCAAIAAoAvAtIgJBAWo2AvAtIAIgACgC7C1qQQA6AAAgACAAKALwLSICQQFqNgLwLSACIAAoAuwtakEAOgAAIAAgACgC8C0iAkEBajYC8C0gAiAAKALsLWogBDoAACAAIARBAnRqIgRB5AFqIAQvAeQBQQFqOwEAIAAgACgCPEEBazYCPCAAKALwLSICIAAoAvQtRiIEIANBAUYNARogACgCSCAHQQFqQf//A3FqLQAAIQkgACACQQFqNgLwLSAAKALsLSACakEAOgAAIAAgACgC8C0iAkEBajYC8C0gAiAAKALsLWpBADoAACAAIAAoAvAtIgJBAWo2AvAtIAIgACgC7C1qIAk6AAAgACAJQQJ0aiICQeQBaiACLwHkAUEBajsBACAAIAAoAjxBAWs2AjwgBCAAKALwLSICIAAoAvQtRmoiBCADQQJGDQEaIAAoAkggB0ECakH//wNxai0AACEHIAAgAkEBajYC8C0gACgC7C0gAmpBADoAACAAIAAoAvAtIgJBAWo2AvAtIAIgACgC7C1qQQA6AAAgACAAKALwLSICQQFqNgLwLSACIAAoAuwtaiAHOgAAIAAgB0ECdGoiB0HkAWogBy8B5AFBAWo7AQAgACAAKAI8QQFrNgI8IAQgACgC8C0gACgC9C1GagwBCyAAIAAoAvAtIgJBAWo2AvAtIAIgACgC7C1qIAdB//8DcSANQf//A3FrIgc6AAAgACAAKALwLSICQQFqNgLwLSACIAAoAuwtaiAHQQh2OgAAIAAgACgC8C0iAkEBajYC8C0gAiAAKALsLWogBEEDazoAACAAIAAoAoAuQQFqNgKALiADQf3OAGotAABBAnQgAGpB6AlqIgQgBC8BAEEBajsBACAAIAdBAWsiBCAEQQd2QYACaiAEQYACSRtBgMsAai0AAEECdGpB2BNqIgQgBC8BAEEBajsBACAAIAAoAjwgA2s2AjwgACgC8C0gACgC9C1GCyEEIAAgACgCaCADaiIHNgJoIARFDQFBACECQQAhBCAAIAAoAlgiA0EATgR/IAAoAkggA2oFQQALIAcgA2tBABAPIAAgACgCaDYCWCAAKAIAEAogACgCACgCEA0BCwsgAgu0BwIEfwF+AkADQAJAAkACQAJAIAAoAjxBhQJNBEAgABAvAkAgACgCPCICQYUCSw0AIAENAEEADwsgAkUNBCACQQRJDQELIAAgACgCaEH4gAEoAgARAgAhAiAANQJoIAKtfSIGQgFTDQAgBiAAKAIwQYYCa61VDQAgAkUNACAAIAJB8IABKAIAEQIAIgJBBEkNACAAIAAoAvAtIgNBAWo2AvAtIAMgACgC7C1qIAAoAmggACgCbGsiAzoAACAAIAAoAvAtIgRBAWo2AvAtIAQgACgC7C1qIANBCHY6AAAgACAAKALwLSIEQQFqNgLwLSAEIAAoAuwtaiACQQNrOgAAIAAgACgCgC5BAWo2AoAuIAJB/c4Aai0AAEECdCAAakHoCWoiBCAELwEAQQFqOwEAIAAgA0EBayIDIANBB3ZBgAJqIANBgAJJG0GAywBqLQAAQQJ0akHYE2oiAyADLwEAQQFqOwEAIAAgACgCPCACayIFNgI8IAAoAvQtIQMgACgC8C0hBCAAKAJ4IAJPQQAgBUEDSxsNASAAIAAoAmggAmoiAjYCaCAAIAJBAWtB+IABKAIAEQIAGiADIARHDQQMAgsgACgCSCAAKAJoai0AACECIAAgACgC8C0iA0EBajYC8C0gAyAAKALsLWpBADoAACAAIAAoAvAtIgNBAWo2AvAtIAMgACgC7C1qQQA6AAAgACAAKALwLSIDQQFqNgLwLSADIAAoAuwtaiACOgAAIAAgAkECdGoiAkHkAWogAi8B5AFBAWo7AQAgACAAKAI8QQFrNgI8IAAgACgCaEEBajYCaCAAKALwLSAAKAL0LUcNAwwBCyAAIAAoAmhBAWoiBTYCaCAAIAUgAkEBayICQeyAASgCABEFACAAIAAoAmggAmo2AmggAyAERw0CC0EAIQNBACECIAAgACgCWCIEQQBOBH8gACgCSCAEagVBAAsgACgCaCAEa0EAEA8gACAAKAJoNgJYIAAoAgAQCiAAKAIAKAIQDQEMAgsLIAAgACgCaCIEQQIgBEECSRs2AoQuIAFBBEYEQEEAIQIgACAAKAJYIgFBAE4EfyAAKAJIIAFqBUEACyAEIAFrQQEQDyAAIAAoAmg2AlggACgCABAKQQNBAiAAKAIAKAIQGw8LIAAoAvAtBEBBACEDQQAhAiAAIAAoAlgiAUEATgR/IAAoAkggAWoFQQALIAQgAWtBABAPIAAgACgCaDYCWCAAKAIAEAogACgCACgCEEUNAQtBASEDCyADC80JAgl/An4gAUEERiEGIAAoAiwhAgJAAkACQCABQQRGBEAgAkECRg0CIAIEQCAAQQAQUCAAQQA2AiwgACAAKAJoNgJYIAAoAgAQCiAAKAIAKAIQRQ0ECyAAIAYQTyAAQQI2AiwMAQsgAg0BIAAoAjxFDQEgACAGEE8gAEEBNgIsCyAAIAAoAmg2AlgLQQJBASABQQRGGyEKA0ACQCAAKAIMIAAoAhBBCGpLDQAgACgCABAKIAAoAgAiAigCEA0AQQAhAyABQQRHDQIgAigCBA0CIAAoAqAuDQIgACgCLEVBAXQPCwJAAkAgACgCPEGFAk0EQCAAEC8CQCAAKAI8IgNBhQJLDQAgAQ0AQQAPCyADRQ0CIAAoAiwEfyADBSAAIAYQTyAAIAo2AiwgACAAKAJoNgJYIAAoAjwLQQRJDQELIAAgACgCaEH4gAEoAgARAgAhBCAAKAJoIgKtIAStfSILQgFTDQAgCyAAKAIwQYYCa61VDQAgAiAAKAJIIgJqIgMvAAAgAiAEaiICLwAARw0AIANBAmogAkECakHQgAEoAgARAgBBAmoiA0EESQ0AIAAoAjwiAiADIAIgA0kbIgJBggIgAkGCAkkbIgdB/c4Aai0AACICQQJ0IgRBhMkAajMBACEMIARBhskAai8BACEDIAJBCGtBE00EQCAHQQNrIARBgNEAaigCAGutIAOthiAMhCEMIARBsNYAaigCACADaiEDCyAAKAKgLiEFIAMgC6dBAWsiCCAIQQd2QYACaiAIQYACSRtBgMsAai0AACICQQJ0IglBgsoAai8BAGohBCAJQYDKAGozAQAgA62GIAyEIQsgACkDmC4hDAJAIAUgAkEESQR/IAQFIAggCUGA0gBqKAIAa60gBK2GIAuEIQsgCUGw1wBqKAIAIARqCyICaiIDQT9NBEAgCyAFrYYgDIQhCwwBCyAFQcAARgRAIAAoAgQgACgCEGogDDcAACAAIAAoAhBBCGo2AhAgAiEDDAELIAAoAgQgACgCEGogCyAFrYYgDIQ3AAAgACAAKAIQQQhqNgIQIANBQGohAyALQcAAIAVrrYghCwsgACALNwOYLiAAIAM2AqAuIAAgACgCPCAHazYCPCAAIAAoAmggB2o2AmgMAgsgACgCSCAAKAJoai0AAEECdCICQYDBAGozAQAhCyAAKQOYLiEMAkAgACgCoC4iBCACQYLBAGovAQAiAmoiA0E/TQRAIAsgBK2GIAyEIQsMAQsgBEHAAEYEQCAAKAIEIAAoAhBqIAw3AAAgACAAKAIQQQhqNgIQIAIhAwwBCyAAKAIEIAAoAhBqIAsgBK2GIAyENwAAIAAgACgCEEEIajYCECADQUBqIQMgC0HAACAEa62IIQsLIAAgCzcDmC4gACADNgKgLiAAIAAoAmhBAWo2AmggACAAKAI8QQFrNgI8DAELCyAAIAAoAmgiAkECIAJBAkkbNgKELiAAKAIsIQIgAUEERgRAAkAgAkUNACAAQQEQUCAAQQA2AiwgACAAKAJoNgJYIAAoAgAQCiAAKAIAKAIQDQBBAg8LQQMPCyACBEBBACEDIABBABBQIABBADYCLCAAIAAoAmg2AlggACgCABAKIAAoAgAoAhBFDQELQQEhAwsgAwucAQEFfyACQQFOBEAgAiAAKAJIIAFqIgNqQQJqIQQgA0ECaiECIAAoAlQhAyAAKAJQIQUDQCAAIAItAAAgA0EFdEHg/wFxcyIDNgJUIAUgA0EBdGoiBi8BACIHIAFB//8DcUcEQCAAKAJMIAEgACgCOHFB//8DcUEBdGogBzsBACAGIAE7AQALIAFBAWohASACQQFqIgIgBEkNAAsLC1sBAn8gACAAKAJIIAFqLQACIAAoAlRBBXRB4P8BcXMiAjYCVCABIAAoAlAgAkEBdGoiAy8BACICRwRAIAAoAkwgACgCOCABcUEBdGogAjsBACADIAE7AQALIAILEwAgAUEFdEHg/wFxIAJB/wFxcwsGACABEAYLLwAjAEEQayIAJAAgAEEMaiABIAJsEIwBIQEgACgCDCECIABBEGokAEEAIAIgARsLjAoCAX4CfyMAQfAAayIGJAACQAJAAkACQAJAAkACQAJAIAQODwABBwIEBQYGBgYGBgYGAwYLQn8hBQJAIAAgBkHkAGpCDBARIgNCf1cEQCABBEAgASAAKAIMNgIAIAEgACgCEDYCBAsMAQsCQCADQgxSBEAgAQRAIAFBADYCBCABQRE2AgALDAELIAEoAhQhBEEAIQJCASEFA0AgBkHkAGogAmoiAiACLQAAIARB/f8DcSICQQJyIAJBA3NsQQh2cyICOgAAIAYgAjoAKCABAn8gASgCDEF/cyECQQAgBkEoaiIERQ0AGiACIARBAUHUgAEoAgARAAALQX9zIgI2AgwgASABKAIQIAJB/wFxakGFiKLAAGxBAWoiAjYCECAGIAJBGHY6ACggAQJ/IAEoAhRBf3MhAkEAIAZBKGoiBEUNABogAiAEQQFB1IABKAIAEQAAC0F/cyIENgIUIAVCDFIEQCAFpyECIAVCAXwhBQwBCwtCACEFIAAgBkEoahAhQQBIDQEgBigCUCEAIwBBEGsiAiQAIAIgADYCDCAGAn8gAkEMahCNASIARQRAIAZBITsBJEEADAELAn8gACgCFCIEQdAATgRAIARBCXQMAQsgAEHQADYCFEGAwAILIQQgBiAAKAIMIAQgACgCEEEFdGpqQaDAAWo7ASQgACgCBEEFdCAAKAIIQQt0aiAAKAIAQQF2ags7ASYgAkEQaiQAIAYtAG8iACAGLQBXRg0BIAYtACcgAEYNASABBEAgAUEANgIEIAFBGzYCAAsLQn8hBQsgBkHwAGokACAFDwtCfyEFIAAgAiADEBEiA0J/VwRAIAEEQCABIAAoAgw2AgAgASAAKAIQNgIECwwGCyMAQRBrIgAkAAJAIANQDQAgASgCFCEEIAJFBEBCASEFA0AgACACIAdqLQAAIARB/f8DcSIEQQJyIARBA3NsQQh2czoADyABAn8gASgCDEF/cyEEQQAgAEEPaiIHRQ0AGiAEIAdBAUHUgAEoAgARAAALQX9zIgQ2AgwgASABKAIQIARB/wFxakGFiKLAAGxBAWoiBDYCECAAIARBGHY6AA8gAQJ/IAEoAhRBf3MhBEEAIABBD2oiB0UNABogBCAHQQFB1IABKAIAEQAAC0F/cyIENgIUIAMgBVENAiAFpyEHIAVCAXwhBQwACwALQgEhBQNAIAAgAiAHai0AACAEQf3/A3EiBEECciAEQQNzbEEIdnMiBDoADyACIAdqIAQ6AAAgAQJ/IAEoAgxBf3MhBEEAIABBD2oiB0UNABogBCAHQQFB1IABKAIAEQAAC0F/cyIENgIMIAEgASgCECAEQf8BcWpBhYiiwABsQQFqIgQ2AhAgACAEQRh2OgAPIAECfyABKAIUQX9zIQRBACAAQQ9qIgdFDQAaIAQgB0EBQdSAASgCABEAAAtBf3MiBDYCFCADIAVRDQEgBachByAFQgF8IQUMAAsACyAAQRBqJAAgAyEFDAULIAJBADsBMiACIAIpAwAiA0KAAYQ3AwAgA0IIg1ANBCACIAIpAyBCDH03AyAMBAsgBkKFgICAcDcDECAGQoOAgIDAADcDCCAGQoGAgIAgNwMAQQAgBhAkIQUMAwsgA0IIWgR+IAIgASgCADYCACACIAEoAgQ2AgRCCAVCfwshBQwCCyABEAYMAQsgAQRAIAFBADYCBCABQRI2AgALQn8hBQsgBkHwAGokACAFC60DAgJ/An4jAEEQayIGJAACQAJAAkAgBEUNACABRQ0AIAJBAUYNAQtBACEDIABBCGoiAARAIABBADYCBCAAQRI2AgALDAELIANBAXEEQEEAIQMgAEEIaiIABEAgAEEANgIEIABBGDYCAAsMAQtBGBAJIgVFBEBBACEDIABBCGoiAARAIABBADYCBCAAQQ42AgALDAELIAVBADYCCCAFQgA3AgAgBUGQ8dmiAzYCFCAFQvis0ZGR8dmiIzcCDAJAIAQQIiICRQ0AIAKtIQhBACEDQYfTru5+IQJCASEHA0AgBiADIARqLQAAOgAPIAUgBkEPaiIDBH8gAiADQQFB1IABKAIAEQAABUEAC0F/cyICNgIMIAUgBSgCECACQf8BcWpBhYiiwABsQQFqIgI2AhAgBiACQRh2OgAPIAUCfyAFKAIUQX9zIQJBACAGQQ9qIgNFDQAaIAIgA0EBQdSAASgCABEAAAtBf3M2AhQgByAIUQ0BIAUoAgxBf3MhAiAHpyEDIAdCAXwhBwwACwALIAAgAUElIAUQQiIDDQAgBRAGQQAhAwsgBkEQaiQAIAMLnRoCBn4FfyMAQdAAayILJAACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCADDhQFBhULAwQJDgACCBAKDw0HEQERDBELAkBByAAQCSIBBEAgAUIANwMAIAFCADcDMCABQQA2AiggAUIANwMgIAFCADcDGCABQgA3AxAgAUIANwMIIAFCADcDOCABQQgQCSIDNgIEIAMNASABEAYgAARAIABBADYCBCAAQQ42AgALCyAAQQA2AhQMFAsgA0IANwMAIAAgATYCFCABQUBrQgA3AwAgAUIANwM4DBQLAkACQCACUARAQcgAEAkiA0UNFCADQgA3AwAgA0IANwMwIANBADYCKCADQgA3AyAgA0IANwMYIANCADcDECADQgA3AwggA0IANwM4IANBCBAJIgE2AgQgAQ0BIAMQBiAABEAgAEEANgIEIABBDjYCAAsMFAsgAiAAKAIQIgEpAzBWBEAgAARAIABBADYCBCAAQRI2AgALDBQLIAEoAigEQCAABEAgAEEANgIEIABBHTYCAAsMFAsgASgCBCEDAkAgASkDCCIGQgF9IgdQDQADQAJAIAIgAyAHIAR9QgGIIAR8IgWnQQN0aikDAFQEQCAFQgF9IQcMAQsgBSAGUQRAIAYhBQwDCyADIAVCAXwiBKdBA3RqKQMAIAJWDQILIAQhBSAEIAdUDQALCwJAIAIgAyAFpyIKQQN0aikDAH0iBFBFBEAgASgCACIDIApBBHRqKQMIIQcMAQsgASgCACIDIAVCAX0iBadBBHRqKQMIIgchBAsgAiAHIAR9VARAIAAEQCAAQQA2AgQgAEEcNgIACwwUCyADIAVCAXwiBUEAIAAQiQEiA0UNEyADKAIAIAMoAggiCkEEdGpBCGsgBDcDACADKAIEIApBA3RqIAI3AwAgAyACNwMwIAMgASkDGCIGIAMpAwgiBEIBfSIHIAYgB1QbNwMYIAEgAzYCKCADIAE2AiggASAENwMgIAMgBTcDIAwBCyABQgA3AwALIAAgAzYCFCADIAQ3A0AgAyACNwM4QgAhBAwTCyAAKAIQIgEEQAJAIAEoAigiA0UEQCABKQMYIQIMAQsgA0EANgIoIAEoAihCADcDICABIAEpAxgiAiABKQMgIgUgAiAFVhsiAjcDGAsgASkDCCACVgRAA0AgASgCACACp0EEdGooAgAQBiACQgF8IgIgASkDCFQNAAsLIAEoAgAQBiABKAIEEAYgARAGCyAAKAIUIQEgAEEANgIUIAAgATYCEAwSCyACQghaBH4gASAAKAIANgIAIAEgACgCBDYCBEIIBUJ/CyEEDBELIAAoAhAiAQRAAkAgASgCKCIDRQRAIAEpAxghAgwBCyADQQA2AiggASgCKEIANwMgIAEgASkDGCICIAEpAyAiBSACIAVWGyICNwMYCyABKQMIIAJWBEADQCABKAIAIAKnQQR0aigCABAGIAJCAXwiAiABKQMIVA0ACwsgASgCABAGIAEoAgQQBiABEAYLIAAoAhQiAQRAAkAgASgCKCIDRQRAIAEpAxghAgwBCyADQQA2AiggASgCKEIANwMgIAEgASkDGCICIAEpAyAiBSACIAVWGyICNwMYCyABKQMIIAJWBEADQCABKAIAIAKnQQR0aigCABAGIAJCAXwiAiABKQMIVA0ACwsgASgCABAGIAEoAgQQBiABEAYLIAAQBgwQCyAAKAIQIgBCADcDOCAAQUBrQgA3AwAMDwsgAkJ/VwRAIAAEQCAAQQA2AgQgAEESNgIACwwOCyACIAAoAhAiAykDMCADKQM4IgZ9IgUgAiAFVBsiBVANDiABIAMpA0AiB6ciAEEEdCIBIAMoAgBqIgooAgAgBiADKAIEIABBA3RqKQMAfSICp2ogBSAKKQMIIAJ9IgYgBSAGVBsiBKcQByEKIAcgBCADKAIAIgAgAWopAwggAn1RrXwhAiAFIAZWBEADQCAKIASnaiAAIAKnQQR0IgFqIgAoAgAgBSAEfSIGIAApAwgiByAGIAdUGyIGpxAHGiACIAYgAygCACIAIAFqKQMIUa18IQIgBSAEIAZ8IgRWDQALCyADIAI3A0AgAyADKQM4IAR8NwM4DA4LQn8hBEHIABAJIgNFDQ0gA0IANwMAIANCADcDMCADQQA2AiggA0IANwMgIANCADcDGCADQgA3AxAgA0IANwMIIANCADcDOCADQQgQCSIBNgIEIAFFBEAgAxAGIAAEQCAAQQA2AgQgAEEONgIACwwOCyABQgA3AwAgACgCECIBBEACQCABKAIoIgpFBEAgASkDGCEEDAELIApBADYCKCABKAIoQgA3AyAgASABKQMYIgIgASkDICIFIAIgBVYbIgQ3AxgLIAEpAwggBFYEQANAIAEoAgAgBKdBBHRqKAIAEAYgBEIBfCIEIAEpAwhUDQALCyABKAIAEAYgASgCBBAGIAEQBgsgACADNgIQQgAhBAwNCyAAKAIUIgEEQAJAIAEoAigiA0UEQCABKQMYIQIMAQsgA0EANgIoIAEoAihCADcDICABIAEpAxgiAiABKQMgIgUgAiAFVhsiAjcDGAsgASkDCCACVgRAA0AgASgCACACp0EEdGooAgAQBiACQgF8IgIgASkDCFQNAAsLIAEoAgAQBiABKAIEEAYgARAGCyAAQQA2AhQMDAsgACgCECIDKQM4IAMpAzAgASACIAAQRCIHQgBTDQogAyAHNwM4AkAgAykDCCIGQgF9IgJQDQAgAygCBCEAA0ACQCAHIAAgAiAEfUIBiCAEfCIFp0EDdGopAwBUBEAgBUIBfSECDAELIAUgBlEEQCAGIQUMAwsgACAFQgF8IgSnQQN0aikDACAHVg0CCyAEIQUgAiAEVg0ACwsgAyAFNwNAQgAhBAwLCyAAKAIUIgMpAzggAykDMCABIAIgABBEIgdCAFMNCSADIAc3AzgCQCADKQMIIgZCAX0iAlANACADKAIEIQADQAJAIAcgACACIAR9QgGIIAR8IgWnQQN0aikDAFQEQCAFQgF9IQIMAQsgBSAGUQRAIAYhBQwDCyAAIAVCAXwiBKdBA3RqKQMAIAdWDQILIAQhBSACIARWDQALCyADIAU3A0BCACEEDAoLIAJCN1gEQCAABEAgAEEANgIEIABBEjYCAAsMCQsgARAqIAEgACgCDDYCKCAAKAIQKQMwIQIgAUEANgIwIAEgAjcDICABIAI3AxggAULcATcDAEI4IQQMCQsgACABKAIANgIMDAgLIAtBQGtBfzYCACALQouAgICwAjcDOCALQoyAgIDQATcDMCALQo+AgICgATcDKCALQpGAgICQATcDICALQoeAgICAATcDGCALQoWAgIDgADcDECALQoOAgIDAADcDCCALQoGAgIAgNwMAQQAgCxAkIQQMBwsgACgCECkDOCIEQn9VDQYgAARAIABBPTYCBCAAQR42AgALDAULIAAoAhQpAzgiBEJ/VQ0FIAAEQCAAQT02AgQgAEEeNgIACwwEC0J/IQQgAkJ/VwRAIAAEQCAAQQA2AgQgAEESNgIACwwFCyACIAAoAhQiAykDOCACfCIFQv//A3wiBFYEQCAABEAgAEEANgIEIABBEjYCAAsMBAsCQCAFIAMoAgQiCiADKQMIIganQQN0aikDACIHWA0AAkAgBCAHfUIQiCAGfCIIIAMpAxAiCVgNAEIQIAkgCVAbIQUDQCAFIgRCAYYhBSAEIAhUDQALIAQgCVQNACADKAIAIASnIgpBBHQQNCIMRQ0DIAMgDDYCACADKAIEIApBA3RBCGoQNCIKRQ0DIAMgBDcDECADIAo2AgQgAykDCCEGCyAGIAhaDQAgAygCACEMA0AgDCAGp0EEdGoiDUGAgAQQCSIONgIAIA5FBEAgAARAIABBADYCBCAAQQ42AgALDAYLIA1CgIAENwMIIAMgBkIBfCIFNwMIIAogBadBA3RqIAdCgIAEfCIHNwMAIAMpAwgiBiAIVA0ACwsgAykDQCEFIAMpAzghBwJAIAJQBEBCACEEDAELIAWnIgBBBHQiDCADKAIAaiINKAIAIAcgCiAAQQN0aikDAH0iBqdqIAEgAiANKQMIIAZ9IgcgAiAHVBsiBKcQBxogBSAEIAMoAgAiACAMaikDCCAGfVGtfCEFIAIgB1YEQANAIAAgBadBBHQiCmoiACgCACABIASnaiACIAR9IgYgACkDCCIHIAYgB1QbIganEAcaIAUgBiADKAIAIgAgCmopAwhRrXwhBSAEIAZ8IgQgAlQNAAsLIAMpAzghBwsgAyAFNwNAIAMgBCAHfCICNwM4IAIgAykDMFgNBCADIAI3AzAMBAsgAARAIABBADYCBCAAQRw2AgALDAILIAAEQCAAQQA2AgQgAEEONgIACyAABEAgAEEANgIEIABBDjYCAAsMAQsgAEEANgIUC0J/IQQLIAtB0ABqJAAgBAtIAQF/IABCADcCBCAAIAE2AgACQCABQQBIDQBBsBMoAgAgAUwNACABQQJ0QcATaigCAEEBRw0AQYSEASgCACECCyAAIAI2AgQLDgAgAkGx893xeWxBEHYLvgEAIwBBEGsiACQAIABBADoACEGAgQFBAjYCAEH8gAFBAzYCAEH4gAFBBDYCAEH0gAFBBTYCAEHwgAFBBjYCAEHsgAFBBzYCAEHogAFBCDYCAEHkgAFBCTYCAEHggAFBCjYCAEHcgAFBCzYCAEHYgAFBDDYCAEHUgAFBDTYCAEHQgAFBDjYCAEHMgAFBDzYCAEHIgAFBEDYCAEHEgAFBETYCAEHAgAFBEjYCACAAQRBqJAAgAkGx893xeWxBEHYLuQEBAX8jAEEQayIBJAAgAUEAOgAIQYCBAUECNgIAQfyAAUEDNgIAQfiAAUEENgIAQfSAAUEFNgIAQfCAAUEGNgIAQeyAAUEHNgIAQeiAAUEINgIAQeSAAUEJNgIAQeCAAUEKNgIAQdyAAUELNgIAQdiAAUEMNgIAQdSAAUENNgIAQdCAAUEONgIAQcyAAUEPNgIAQciAAUEQNgIAQcSAAUERNgIAQcCAAUESNgIAIAAQjgEgAUEQaiQAC78BAQF/IwBBEGsiAiQAIAJBADoACEGAgQFBAjYCAEH8gAFBAzYCAEH4gAFBBDYCAEH0gAFBBTYCAEHwgAFBBjYCAEHsgAFBBzYCAEHogAFBCDYCAEHkgAFBCTYCAEHggAFBCjYCAEHcgAFBCzYCAEHYgAFBDDYCAEHUgAFBDTYCAEHQgAFBDjYCAEHMgAFBDzYCAEHIgAFBEDYCAEHEgAFBETYCAEHAgAFBEjYCACAAIAEQkAEhACACQRBqJAAgAAu+AQEBfyMAQRBrIgIkACACQQA6AAhBgIEBQQI2AgBB/IABQQM2AgBB+IABQQQ2AgBB9IABQQU2AgBB8IABQQY2AgBB7IABQQc2AgBB6IABQQg2AgBB5IABQQk2AgBB4IABQQo2AgBB3IABQQs2AgBB2IABQQw2AgBB1IABQQ02AgBB0IABQQ42AgBBzIABQQ82AgBByIABQRA2AgBBxIABQRE2AgBBwIABQRI2AgAgACABEFohACACQRBqJAAgAAu+AQEBfyMAQRBrIgIkACACQQA6AAhBgIEBQQI2AgBB/IABQQM2AgBB+IABQQQ2AgBB9IABQQU2AgBB8IABQQY2AgBB7IABQQc2AgBB6IABQQg2AgBB5IABQQk2AgBB4IABQQo2AgBB3IABQQs2AgBB2IABQQw2AgBB1IABQQ02AgBB0IABQQ42AgBBzIABQQ82AgBByIABQRA2AgBBxIABQRE2AgBBwIABQRI2AgAgACABEFshACACQRBqJAAgAAu9AQEBfyMAQRBrIgMkACADQQA6AAhBgIEBQQI2AgBB/IABQQM2AgBB+IABQQQ2AgBB9IABQQU2AgBB8IABQQY2AgBB7IABQQc2AgBB6IABQQg2AgBB5IABQQk2AgBB4IABQQo2AgBB3IABQQs2AgBB2IABQQw2AgBB1IABQQ02AgBB0IABQQ42AgBBzIABQQ82AgBByIABQRA2AgBBxIABQRE2AgBBwIABQRI2AgAgACABIAIQjwEgA0EQaiQAC4UBAgR/AX4jAEEQayIBJAACQCAAKQMwUARADAELA0ACQCAAIAVBACABQQ9qIAFBCGoQZiIEQX9GDQAgAS0AD0EDRw0AIAIgASgCCEGAgICAf3FBgICAgHpGaiECC0F/IQMgBEF/Rg0BIAIhAyAFQgF8IgUgACkDMFQNAAsLIAFBEGokACADCwuMdSUAQYAIC7ELaW5zdWZmaWNpZW50IG1lbW9yeQBuZWVkIGRpY3Rpb25hcnkALSsgICAwWDB4AFppcCBhcmNoaXZlIGluY29uc2lzdGVudABJbnZhbGlkIGFyZ3VtZW50AGludmFsaWQgbGl0ZXJhbC9sZW5ndGhzIHNldABpbnZhbGlkIGNvZGUgbGVuZ3RocyBzZXQAdW5rbm93biBoZWFkZXIgZmxhZ3Mgc2V0AGludmFsaWQgZGlzdGFuY2VzIHNldABpbnZhbGlkIGJpdCBsZW5ndGggcmVwZWF0AEZpbGUgYWxyZWFkeSBleGlzdHMAdG9vIG1hbnkgbGVuZ3RoIG9yIGRpc3RhbmNlIHN5bWJvbHMAaW52YWxpZCBzdG9yZWQgYmxvY2sgbGVuZ3RocwAlcyVzJXMAYnVmZmVyIGVycm9yAE5vIGVycm9yAHN0cmVhbSBlcnJvcgBUZWxsIGVycm9yAEludGVybmFsIGVycm9yAFNlZWsgZXJyb3IAV3JpdGUgZXJyb3IAZmlsZSBlcnJvcgBSZWFkIGVycm9yAFpsaWIgZXJyb3IAZGF0YSBlcnJvcgBDUkMgZXJyb3IAaW5jb21wYXRpYmxlIHZlcnNpb24AaW52YWxpZCBjb2RlIC0tIG1pc3NpbmcgZW5kLW9mLWJsb2NrAGluY29ycmVjdCBoZWFkZXIgY2hlY2sAaW5jb3JyZWN0IGxlbmd0aCBjaGVjawBpbmNvcnJlY3QgZGF0YSBjaGVjawBpbnZhbGlkIGRpc3RhbmNlIHRvbyBmYXIgYmFjawBoZWFkZXIgY3JjIG1pc21hdGNoADEuMi4xMy56bGliLW5nAGludmFsaWQgd2luZG93IHNpemUAUmVhZC1vbmx5IGFyY2hpdmUATm90IGEgemlwIGFyY2hpdmUAUmVzb3VyY2Ugc3RpbGwgaW4gdXNlAE1hbGxvYyBmYWlsdXJlAGludmFsaWQgYmxvY2sgdHlwZQBGYWlsdXJlIHRvIGNyZWF0ZSB0ZW1wb3JhcnkgZmlsZQBDYW4ndCBvcGVuIGZpbGUATm8gc3VjaCBmaWxlAFByZW1hdHVyZSBlbmQgb2YgZmlsZQBDYW4ndCByZW1vdmUgZmlsZQBpbnZhbGlkIGxpdGVyYWwvbGVuZ3RoIGNvZGUAaW52YWxpZCBkaXN0YW5jZSBjb2RlAHVua25vd24gY29tcHJlc3Npb24gbWV0aG9kAHN0cmVhbSBlbmQAQ29tcHJlc3NlZCBkYXRhIGludmFsaWQATXVsdGktZGlzayB6aXAgYXJjaGl2ZXMgbm90IHN1cHBvcnRl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UgAIANIACAAyAAgAsgAIAHIACADyAAgACgAIAIoACABKAAgAygAIACoACACqAAgAagAIAOoACAAaAAgAmgAIAFoACADaAAgAOgAIALoACAB6AAgA+gAIAAYACACGAAgARgAIAMYACAAmAAgApgAIAGYACADmAAgAFgAIAJYACABWAAgA1gAIADYACAC2AAgAdgAIAPYACAAOAAgAjgAIAE4ACADOAAgALgAIAK4ACABuAAgA7gAIAB4ACACeAAgAXgAIAN4ACAA+AAgAvgAIAH4ACAD+AAgAAQAIAIEACABBAAgAwQAIACEACAChAAgAYQAIAOEACAARAAgAkQAIAFEACADRAAgAMQAIALEACABxAAgA8QAIAAkACACJAAgASQAIAMkACAApAAgAqQAIAGkACADpAAgAGQAIAJkACABZAAgA2QAIADkACAC5AAgAeQAIAPkACAAFAAgAhQAIAEUACADFAAgAJQAIAKUACABlAAgA5QAIABUACACVAAgAVQAIANUACAA1AAgAtQAIAHUACAD1AAgADQAIAI0ACABNAAgAzQAIAC0ACACtAAgAbQAIAO0ACAAdAAgAnQAIAF0ACADdAAgAPQAIAL0ACAB9AAgA/QAIABMACQATAQkAkwAJAJMBCQBTAAkAUwEJANMACQDTAQkAMwAJADMBCQCzAAkAswEJAHMACQBzAQkA8wAJAPMBCQALAAkACwEJAIsACQCLAQkASwAJAEsBCQDLAAkAywEJACsACQArAQkAqwAJAKsBCQBrAAkAawEJAOsACQDrAQkAGwAJABsBCQCbAAkAmwEJAFsACQBbAQkA2wAJANsBCQA7AAkAOwEJALsACQC7AQkAewAJAHsBCQD7AAkA+wEJAAcACQAHAQkAhwAJAIcBCQBHAAkARwEJAMcACQDHAQkAJwAJACcBCQCnAAkApwEJAGcACQBnAQkA5wAJAOcBCQAXAAkAFwEJAJcACQCXAQkAVwAJAFcBCQDXAAkA1wEJADcACQA3AQkAtwAJALcBCQB3AAkAdwEJAPcACQD3AQkADwAJAA8BCQCPAAkAjwEJAE8ACQBPAQkAzwAJAM8BCQAvAAkALwEJAK8ACQCvAQkAbwAJAG8BCQDvAAkA7wEJAB8ACQAfAQkAnwAJAJ8BCQBfAAkAXwEJAN8ACQDfAQkAPwAJAD8BCQC/AAkA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SXMgYSBkaXJlY3RvcnkAVGV4dCBmaWxlIGJ1c3kARXhlYyBmb3JtYXQgZXJyb3IASW52YWxpZCBhcmd1bWVudABBcmd1bWVudCBsaXN0IHRvbyBsb25nAFN5bWJvbGljIGxpbmsgbG9vcABGaWxlbmFtZSB0b28gbG9uZwBUb28gbWFueSBvcGVuIGZpbGVzIGluIHN5c3RlbQBObyBmaWxlIGRlc2NyaXB0b3JzIGF2YWlsYWJsZQBCYWQgZmlsZSBkZXNjcmlwdG9yAE5vIGNoaWxkIHByb2Nlc3MAQmFkIGFkZHJlc3MARmlsZSB0b28gbGFyZ2UAVG9vIG1hbnkgbGlua3MATm8gbG9ja3MgYXZhaWxhYmxlAFJlc291cmNlIGRlYWRsb2NrIHdvdWxkIG9jY3VyAFN0YXRlIG5vdCByZWNvdmVyYWJsZQBQcmV2aW91cyBvd25lciBkaWVkAE9wZXJhdGlvbiBjYW5jZWxlZABGdW5jdGlvbiBub3QgaW1wbGVtZW50ZWQATm8gbWVzc2FnZSBvZiBkZXNpcmVkIHR5cGUASWRlbnRpZmllciByZW1vdmVkAERldmljZSBub3QgYSBzdHJlYW0ATm8gZGF0YSBhdmFpbGFibGUARGV2aWNlIHRpbWVvdXQAT3V0IG9mIHN0cmVhbXMgcmVzb3VyY2VzAExpbmsgaGFzIGJlZW4gc2V2ZXJlZABQcm90b2NvbCBlcnJvcgBCYWQgbWVzc2FnZQBGaWxlIGRlc2NyaXB0b3IgaW4gYmFkIHN0YXRlAE5vdCBhIHNvY2tldABEZXN0aW5hdGlvbiBhZGRyZXNzIHJlcXVpcmVkAE1lc3NhZ2UgdG9vIGxhcmdlAFByb3RvY29sIHdyb25nIHR5cGUgZm9yIHNvY2tldABQcm90b2NvbCBub3QgYXZhaWxhYmxlAFByb3RvY29sIG5vdCBzdXBwb3J0ZWQAU29ja2V0IHR5cGUgbm90IHN1cHBvcnRlZABOb3Qgc3VwcG9ydGVkAFByb3RvY29sIGZhbWlseSBub3Qgc3VwcG9ydGVkAEFkZHJlc3MgZmFtaWx5IG5vdCBzdXBwb3J0ZWQgYnkgcHJvdG9jb2wAQWRkcmVzcyBub3QgYXZhaWxhYmxlAE5ldHdvcmsgaXMgZG93bgBOZXR3b3JrIHVucmVhY2hhYmxlAENvbm5lY3Rpb24gcmVzZXQgYnkgbmV0d29yawBDb25uZWN0aW9uIGFib3J0ZWQATm8gYnVmZmVyIHNwYWNlIGF2YWlsYWJsZQBTb2NrZXQgaXMgY29ubmVjdGVkAFNvY2tldCBub3QgY29ubmVjdGVkAENhbm5vdCBzZW5kIGFmdGVyIHNvY2tldCBzaHV0ZG93bgBPcGVyYXRpb24gYWxyZWFkeSBpbiBwcm9ncmVzcwBPcGVyYXRpb24gaW4gcHJvZ3Jlc3MAU3RhbGUgZmlsZSBoYW5kbGUAUmVtb3RlIEkvTyBlcnJvcgBRdW90YSBleGNlZWRlZABObyBtZWRpdW0gZm91bmQAV3JvbmcgbWVkaXVtIHR5cGUATm8gZXJyb3IgaW5mb3JtYXRpb24AQcCAAQuFARMAAAAUAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAGwAAABwAAAAdAAAAHgAAAB8AAAAgAAAAIQAAACIAAAAjAAAAgERQADEAAAAyAAAAMwAAADQAAAA1AAAANgAAADcAAAA4AAAAOQAAADIAAAAzAAAANAAAADUAAAA2AAAANwAAADgAQfSCAQsCXEQAQbCDAQsQ/////////////////////w==\";io(Si)||(Si=x(Si));function Ns(We){try{if(We==Si&&ue)return new Uint8Array(ue);var tt=ii(We);if(tt)return tt;if(R)return R(We);throw\"sync fetching of the wasm failed: you can preload it to Module['wasmBinary'] manually, or emcc.py will do that for you when generating HTML (but not JS)\"}catch(It){Ti(It)}}function so(We,tt){var It,ir,$;try{$=Ns(We),ir=new WebAssembly.Module($),It=new WebAssembly.Instance(ir,tt)}catch(Ne){var ye=Ne.toString();throw te(\"failed to compile wasm module: \"+ye),(ye.includes(\"imported Memory\")||ye.includes(\"memory import\"))&&te(\"Memory size incompatibility issues may be due to changing INITIAL_MEMORY at runtime to something too large. Use ALLOW_MEMORY_GROWTH to allow any size memory (and also make sure not to set INITIAL_MEMORY at runtime to something smaller than it was at compile time).\"),Ne}return[It,ir]}function uc(){var We={a:Ua};function tt($,ye){var Ne=$.exports;r.asm=Ne,Be=r.asm.g,J(Be.buffer),Z=r.asm.W,an(r.asm.h),Ls(\"wasm-instantiate\")}if(Kn(\"wasm-instantiate\"),r.instantiateWasm)try{var It=r.instantiateWasm(We,tt);return It}catch($){return te(\"Module.instantiateWasm callback failed with error: \"+$),!1}var ir=so(Si,We);return tt(ir[0]),r.asm}function uu(We){return F.getFloat32(We,!0)}function cp(We){return F.getFloat64(We,!0)}function up(We){return F.getInt16(We,!0)}function Os(We){return F.getInt32(We,!0)}function Dn(We,tt){F.setInt32(We,tt,!0)}function oo(We){for(;We.length>0;){var tt=We.shift();if(typeof tt==\"function\"){tt(r);continue}var It=tt.func;typeof It==\"number\"?tt.arg===void 0?Z.get(It)():Z.get(It)(tt.arg):It(tt.arg===void 0?null:tt.arg)}}function Ms(We,tt){var It=new Date(Os((We>>2)*4)*1e3);Dn((tt>>2)*4,It.getUTCSeconds()),Dn((tt+4>>2)*4,It.getUTCMinutes()),Dn((tt+8>>2)*4,It.getUTCHours()),Dn((tt+12>>2)*4,It.getUTCDate()),Dn((tt+16>>2)*4,It.getUTCMonth()),Dn((tt+20>>2)*4,It.getUTCFullYear()-1900),Dn((tt+24>>2)*4,It.getUTCDay()),Dn((tt+36>>2)*4,0),Dn((tt+32>>2)*4,0);var ir=Date.UTC(It.getUTCFullYear(),0,1,0,0,0,0),$=(It.getTime()-ir)/(1e3*60*60*24)|0;return Dn((tt+28>>2)*4,$),Ms.GMTString||(Ms.GMTString=at(\"GMT\")),Dn((tt+40>>2)*4,Ms.GMTString),tt}function yl(We,tt){return Ms(We,tt)}function El(We,tt,It){Te.copyWithin(We,tt,tt+It)}function ao(We){try{return Be.grow(We-xe.byteLength+65535>>>16),J(Be.buffer),1}catch{}}function zn(We){var tt=Te.length;We=We>>>0;var It=2147483648;if(We>It)return!1;for(var ir=1;ir<=4;ir*=2){var $=tt*(1+.2/ir);$=Math.min($,We+100663296);var ye=Math.min(It,ke(Math.max(We,$),65536)),Ne=ao(ye);if(Ne)return!0}return!1}function On(We){fe(We)}function Li(We){var tt=Date.now()/1e3|0;return We&&Dn((We>>2)*4,tt),tt}function Mn(){if(Mn.called)return;Mn.called=!0;var We=new Date().getFullYear(),tt=new Date(We,0,1),It=new Date(We,6,1),ir=tt.getTimezoneOffset(),$=It.getTimezoneOffset(),ye=Math.max(ir,$);Dn((ds()>>2)*4,ye*60),Dn((gs()>>2)*4,Number(ir!=$));function Ne($r){var Gi=$r.toTimeString().match(/\\(([A-Za-z ]+)\\)$/);return Gi?Gi[1]:\"GMT\"}var pt=Ne(tt),ht=Ne(It),Tt=at(pt),er=at(ht);$<ir?(Dn((wi()>>2)*4,Tt),Dn((wi()+4>>2)*4,er)):(Dn((wi()>>2)*4,er),Dn((wi()+4>>2)*4,Tt))}function _i(We){Mn();var tt=Date.UTC(Os((We+20>>2)*4)+1900,Os((We+16>>2)*4),Os((We+12>>2)*4),Os((We+8>>2)*4),Os((We+4>>2)*4),Os((We>>2)*4),0),It=new Date(tt);Dn((We+24>>2)*4,It.getUTCDay());var ir=Date.UTC(It.getUTCFullYear(),0,1,0,0,0,0),$=(It.getTime()-ir)/(1e3*60*60*24)|0;return Dn((We+28>>2)*4,$),It.getTime()/1e3|0}var rr=typeof atob==\"function\"?atob:function(We){var tt=\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\",It=\"\",ir,$,ye,Ne,pt,ht,Tt,er=0;We=We.replace(/[^A-Za-z0-9\\+\\/\\=]/g,\"\");do Ne=tt.indexOf(We.charAt(er++)),pt=tt.indexOf(We.charAt(er++)),ht=tt.indexOf(We.charAt(er++)),Tt=tt.indexOf(We.charAt(er++)),ir=Ne<<2|pt>>4,$=(pt&15)<<4|ht>>2,ye=(ht&3)<<6|Tt,It=It+String.fromCharCode(ir),ht!==64&&(It=It+String.fromCharCode($)),Tt!==64&&(It=It+String.fromCharCode(ye));while(er<We.length);return It};function Oe(We){if(typeof I==\"boolean\"&&I){var tt;try{tt=Buffer.from(We,\"base64\")}catch{tt=new Buffer(We,\"base64\")}return new Uint8Array(tt.buffer,tt.byteOffset,tt.byteLength)}try{for(var It=rr(We),ir=new Uint8Array(It.length),$=0;$<It.length;++$)ir[$]=It.charCodeAt($);return ir}catch{throw new Error(\"Converting base64 string to bytes failed.\")}}function ii(We){if(!!io(We))return Oe(We.slice(ps.length))}var Ua={e:yl,c:El,d:zn,a:On,b:Li,f:_i},hr=uc(),Ac=r.___wasm_call_ctors=hr.h,Au=r._zip_ext_count_symlinks=hr.i,fc=r._zip_file_get_external_attributes=hr.j,Cl=r._zipstruct_statS=hr.k,DA=r._zipstruct_stat_size=hr.l,fu=r._zipstruct_stat_mtime=hr.m,Ce=r._zipstruct_stat_crc=hr.n,Rt=r._zipstruct_errorS=hr.o,pc=r._zipstruct_error_code_zip=hr.p,Hi=r._zipstruct_stat_comp_size=hr.q,pu=r._zipstruct_stat_comp_method=hr.r,Yt=r._zip_close=hr.s,wl=r._zip_delete=hr.t,PA=r._zip_dir_add=hr.u,Ap=r._zip_discard=hr.v,hc=r._zip_error_init_with_code=hr.w,SA=r._zip_get_error=hr.x,Qn=r._zip_file_get_error=hr.y,hi=r._zip_error_strerror=hr.z,gc=r._zip_fclose=hr.A,bA=r._zip_file_add=hr.B,sa=r._free=hr.C,Ni=r._malloc=hr.D,_o=r._zip_source_error=hr.E,Ze=r._zip_source_seek=hr.F,lo=r._zip_file_set_external_attributes=hr.G,dc=r._zip_file_set_mtime=hr.H,hu=r._zip_fopen_index=hr.I,qi=r._zip_fread=hr.J,gu=r._zip_get_name=hr.K,xA=r._zip_get_num_entries=hr.L,Ha=r._zip_source_read=hr.M,mc=r._zip_name_locate=hr.N,hs=r._zip_open_from_source=hr.O,Ht=r._zip_set_file_compression=hr.P,Fn=r._zip_source_buffer=hr.Q,Ci=r._zip_source_buffer_create=hr.R,oa=r._zip_source_close=hr.S,co=r._zip_source_free=hr.T,Us=r._zip_source_keep=hr.U,aa=r._zip_source_open=hr.V,la=r._zip_source_tell=hr.X,Ho=r._zip_stat_index=hr.Y,wi=r.__get_tzname=hr.Z,gs=r.__get_daylight=hr._,ds=r.__get_timezone=hr.$,ms=r.stackSave=hr.aa,_s=r.stackRestore=hr.ba,Un=r.stackAlloc=hr.ca;r.cwrap=ne,r.getValue=he;var Pn;Wr=function We(){Pn||ys(),Pn||(Wr=We)};function ys(We){if(We=We||A,mr>0||(dt(),mr>0))return;function tt(){Pn||(Pn=!0,r.calledRun=!0,!we&&(Gt(),o(r),r.onRuntimeInitialized&&r.onRuntimeInitialized(),$t()))}r.setStatus?(r.setStatus(\"Running...\"),setTimeout(function(){setTimeout(function(){r.setStatus(\"\")},1),tt()},1)):tt()}if(r.run=ys,r.preInit)for(typeof r.preInit==\"function\"&&(r.preInit=[r.preInit]);r.preInit.length>0;)r.preInit.pop()();return ys(),e}}();typeof Qb==\"object\"&&typeof tU==\"object\"?tU.exports=eU:typeof define==\"function\"&&define.amd?define([],function(){return eU}):typeof Qb==\"object\"&&(Qb.createModule=eU)});var Of,Tle,Lle,Nle=Et(()=>{Of=[\"number\",\"number\"],Tle=(ee=>(ee[ee.ZIP_ER_OK=0]=\"ZIP_ER_OK\",ee[ee.ZIP_ER_MULTIDISK=1]=\"ZIP_ER_MULTIDISK\",ee[ee.ZIP_ER_RENAME=2]=\"ZIP_ER_RENAME\",ee[ee.ZIP_ER_CLOSE=3]=\"ZIP_ER_CLOSE\",ee[ee.ZIP_ER_SEEK=4]=\"ZIP_ER_SEEK\",ee[ee.ZIP_ER_READ=5]=\"ZIP_ER_READ\",ee[ee.ZIP_ER_WRITE=6]=\"ZIP_ER_WRITE\",ee[ee.ZIP_ER_CRC=7]=\"ZIP_ER_CRC\",ee[ee.ZIP_ER_ZIPCLOSED=8]=\"ZIP_ER_ZIPCLOSED\",ee[ee.ZIP_ER_NOENT=9]=\"ZIP_ER_NOENT\",ee[ee.ZIP_ER_EXISTS=10]=\"ZIP_ER_EXISTS\",ee[ee.ZIP_ER_OPEN=11]=\"ZIP_ER_OPEN\",ee[ee.ZIP_ER_TMPOPEN=12]=\"ZIP_ER_TMPOPEN\",ee[ee.ZIP_ER_ZLIB=13]=\"ZIP_ER_ZLIB\",ee[ee.ZIP_ER_MEMORY=14]=\"ZIP_ER_MEMORY\",ee[ee.ZIP_ER_CHANGED=15]=\"ZIP_ER_CHANGED\",ee[ee.ZIP_ER_COMPNOTSUPP=16]=\"ZIP_ER_COMPNOTSUPP\",ee[ee.ZIP_ER_EOF=17]=\"ZIP_ER_EOF\",ee[ee.ZIP_ER_INVAL=18]=\"ZIP_ER_INVAL\",ee[ee.ZIP_ER_NOZIP=19]=\"ZIP_ER_NOZIP\",ee[ee.ZIP_ER_INTERNAL=20]=\"ZIP_ER_INTERNAL\",ee[ee.ZIP_ER_INCONS=21]=\"ZIP_ER_INCONS\",ee[ee.ZIP_ER_REMOVE=22]=\"ZIP_ER_REMOVE\",ee[ee.ZIP_ER_DELETED=23]=\"ZIP_ER_DELETED\",ee[ee.ZIP_ER_ENCRNOTSUPP=24]=\"ZIP_ER_ENCRNOTSUPP\",ee[ee.ZIP_ER_RDONLY=25]=\"ZIP_ER_RDONLY\",ee[ee.ZIP_ER_NOPASSWD=26]=\"ZIP_ER_NOPASSWD\",ee[ee.ZIP_ER_WRONGPASSWD=27]=\"ZIP_ER_WRONGPASSWD\",ee[ee.ZIP_ER_OPNOTSUPP=28]=\"ZIP_ER_OPNOTSUPP\",ee[ee.ZIP_ER_INUSE=29]=\"ZIP_ER_INUSE\",ee[ee.ZIP_ER_TELL=30]=\"ZIP_ER_TELL\",ee[ee.ZIP_ER_COMPRESSED_DATA=31]=\"ZIP_ER_COMPRESSED_DATA\",ee))(Tle||{}),Lle=t=>({get HEAPU8(){return t.HEAPU8},errors:Tle,SEEK_SET:0,SEEK_CUR:1,SEEK_END:2,ZIP_CHECKCONS:4,ZIP_EXCL:2,ZIP_RDONLY:16,ZIP_FL_OVERWRITE:8192,ZIP_FL_COMPRESSED:4,ZIP_OPSYS_DOS:0,ZIP_OPSYS_AMIGA:1,ZIP_OPSYS_OPENVMS:2,ZIP_OPSYS_UNIX:3,ZIP_OPSYS_VM_CMS:4,ZIP_OPSYS_ATARI_ST:5,ZIP_OPSYS_OS_2:6,ZIP_OPSYS_MACINTOSH:7,ZIP_OPSYS_Z_SYSTEM:8,ZIP_OPSYS_CPM:9,ZIP_OPSYS_WINDOWS_NTFS:10,ZIP_OPSYS_MVS:11,ZIP_OPSYS_VSE:12,ZIP_OPSYS_ACORN_RISC:13,ZIP_OPSYS_VFAT:14,ZIP_OPSYS_ALTERNATE_MVS:15,ZIP_OPSYS_BEOS:16,ZIP_OPSYS_TANDEM:17,ZIP_OPSYS_OS_400:18,ZIP_OPSYS_OS_X:19,ZIP_CM_DEFAULT:-1,ZIP_CM_STORE:0,ZIP_CM_DEFLATE:8,uint08S:t._malloc(1),uint32S:t._malloc(4),malloc:t._malloc,free:t._free,getValue:t.getValue,openFromSource:t.cwrap(\"zip_open_from_source\",\"number\",[\"number\",\"number\",\"number\"]),close:t.cwrap(\"zip_close\",\"number\",[\"number\"]),discard:t.cwrap(\"zip_discard\",null,[\"number\"]),getError:t.cwrap(\"zip_get_error\",\"number\",[\"number\"]),getName:t.cwrap(\"zip_get_name\",\"string\",[\"number\",\"number\",\"number\"]),getNumEntries:t.cwrap(\"zip_get_num_entries\",\"number\",[\"number\",\"number\"]),delete:t.cwrap(\"zip_delete\",\"number\",[\"number\",\"number\"]),statIndex:t.cwrap(\"zip_stat_index\",\"number\",[\"number\",...Of,\"number\",\"number\"]),fopenIndex:t.cwrap(\"zip_fopen_index\",\"number\",[\"number\",...Of,\"number\"]),fread:t.cwrap(\"zip_fread\",\"number\",[\"number\",\"number\",\"number\",\"number\"]),fclose:t.cwrap(\"zip_fclose\",\"number\",[\"number\"]),dir:{add:t.cwrap(\"zip_dir_add\",\"number\",[\"number\",\"string\"])},file:{add:t.cwrap(\"zip_file_add\",\"number\",[\"number\",\"string\",\"number\",\"number\"]),getError:t.cwrap(\"zip_file_get_error\",\"number\",[\"number\"]),getExternalAttributes:t.cwrap(\"zip_file_get_external_attributes\",\"number\",[\"number\",...Of,\"number\",\"number\",\"number\"]),setExternalAttributes:t.cwrap(\"zip_file_set_external_attributes\",\"number\",[\"number\",...Of,\"number\",\"number\",\"number\"]),setMtime:t.cwrap(\"zip_file_set_mtime\",\"number\",[\"number\",...Of,\"number\",\"number\"]),setCompression:t.cwrap(\"zip_set_file_compression\",\"number\",[\"number\",...Of,\"number\",\"number\"])},ext:{countSymlinks:t.cwrap(\"zip_ext_count_symlinks\",\"number\",[\"number\"])},error:{initWithCode:t.cwrap(\"zip_error_init_with_code\",null,[\"number\",\"number\"]),strerror:t.cwrap(\"zip_error_strerror\",\"string\",[\"number\"])},name:{locate:t.cwrap(\"zip_name_locate\",\"number\",[\"number\",\"string\",\"number\"])},source:{fromUnattachedBuffer:t.cwrap(\"zip_source_buffer_create\",\"number\",[\"number\",...Of,\"number\",\"number\"]),fromBuffer:t.cwrap(\"zip_source_buffer\",\"number\",[\"number\",\"number\",...Of,\"number\"]),free:t.cwrap(\"zip_source_free\",null,[\"number\"]),keep:t.cwrap(\"zip_source_keep\",null,[\"number\"]),open:t.cwrap(\"zip_source_open\",\"number\",[\"number\"]),close:t.cwrap(\"zip_source_close\",\"number\",[\"number\"]),seek:t.cwrap(\"zip_source_seek\",\"number\",[\"number\",...Of,\"number\"]),tell:t.cwrap(\"zip_source_tell\",\"number\",[\"number\"]),read:t.cwrap(\"zip_source_read\",\"number\",[\"number\",\"number\",\"number\"]),error:t.cwrap(\"zip_source_error\",\"number\",[\"number\"])},struct:{statS:t.cwrap(\"zipstruct_statS\",\"number\",[]),statSize:t.cwrap(\"zipstruct_stat_size\",\"number\",[\"number\"]),statCompSize:t.cwrap(\"zipstruct_stat_comp_size\",\"number\",[\"number\"]),statCompMethod:t.cwrap(\"zipstruct_stat_comp_method\",\"number\",[\"number\"]),statMtime:t.cwrap(\"zipstruct_stat_mtime\",\"number\",[\"number\"]),statCrc:t.cwrap(\"zipstruct_stat_crc\",\"number\",[\"number\"]),errorS:t.cwrap(\"zipstruct_errorS\",\"number\",[]),errorCodeZip:t.cwrap(\"zipstruct_error_code_zip\",\"number\",[\"number\"])}})});function rU(t,e){let r=t.indexOf(e);if(r<=0)return null;let o=r;for(;r>=0&&(o=r+e.length,t[o]!==z.sep);){if(t[r-1]===z.sep)return null;r=t.indexOf(e,o)}return t.length>o&&t[o]!==z.sep?null:t.slice(0,o)}var Jl,Ole=Et(()=>{Pt();Pt();iA();Jl=class extends qp{static async openPromise(e,r){let o=new Jl(r);try{return await e(o)}finally{o.saveAndClose()}}constructor(e={}){let r=e.fileExtensions,o=e.readOnlyArchives,a=typeof r>\"u\"?A=>rU(A,\".zip\"):A=>{for(let p of r){let h=rU(A,p);if(h)return h}return null},n=(A,p)=>new Ji(p,{baseFs:A,readOnly:o,stats:A.statSync(p)}),u=async(A,p)=>{let h={baseFs:A,readOnly:o,stats:await A.statPromise(p)};return()=>new Ji(p,h)};super({...e,factorySync:n,factoryPromise:u,getMountPoint:a})}}});function cot(t){if(typeof t==\"string\"&&String(+t)===t)return+t;if(typeof t==\"number\"&&Number.isFinite(t))return t<0?Date.now()/1e3:t;if(Mle.types.isDate(t))return t.getTime()/1e3;throw new Error(\"Invalid time\")}function Fb(){return Buffer.from([80,75,5,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0])}var ta,nU,Mle,iU,Ule,Rb,Ji,sU=Et(()=>{Pt();Pt();Pt();Pt();Pt();Pt();ta=ve(\"fs\"),nU=ve(\"stream\"),Mle=ve(\"util\"),iU=$e(ve(\"zlib\"));$4();Ule=\"mixed\";Rb=class extends Error{constructor(r,o){super(r);this.name=\"Libzip Error\",this.code=o}},Ji=class extends Uu{constructor(r,o={}){super();this.listings=new Map;this.entries=new Map;this.fileSources=new Map;this.fds=new Map;this.nextFd=0;this.ready=!1;this.readOnly=!1;let a=o;if(this.level=typeof a.level<\"u\"?a.level:Ule,r??=Fb(),typeof r==\"string\"){let{baseFs:A=new Tn}=a;this.baseFs=A,this.path=r}else this.path=null,this.baseFs=null;if(o.stats)this.stats=o.stats;else if(typeof r==\"string\")try{this.stats=this.baseFs.statSync(r)}catch(A){if(A.code===\"ENOENT\"&&a.create)this.stats=Ea.makeDefaultStats();else throw A}else this.stats=Ea.makeDefaultStats();this.libzip=b1();let n=this.libzip.malloc(4);try{let A=0;o.readOnly&&(A|=this.libzip.ZIP_RDONLY,this.readOnly=!0),typeof r==\"string\"&&(r=a.create?Fb():this.baseFs.readFileSync(r));let p=this.allocateUnattachedSource(r);try{this.zip=this.libzip.openFromSource(p,A,n),this.lzSource=p}catch(h){throw this.libzip.source.free(p),h}if(this.zip===0){let h=this.libzip.struct.errorS();throw this.libzip.error.initWithCode(h,this.libzip.getValue(n,\"i32\")),this.makeLibzipError(h)}}finally{this.libzip.free(n)}this.listings.set(Bt.root,new Set);let u=this.libzip.getNumEntries(this.zip,0);for(let A=0;A<u;++A){let p=this.libzip.getName(this.zip,A,0);if(z.isAbsolute(p))continue;let h=z.resolve(Bt.root,p);this.registerEntry(h,A),p.endsWith(\"/\")&&this.registerListing(h)}if(this.symlinkCount=this.libzip.ext.countSymlinks(this.zip),this.symlinkCount===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));this.ready=!0}makeLibzipError(r){let o=this.libzip.struct.errorCodeZip(r),a=this.libzip.error.strerror(r),n=new Rb(a,this.libzip.errors[o]);if(o===this.libzip.errors.ZIP_ER_CHANGED)throw new Error(`Assertion failed: Unexpected libzip error: ${n.message}`);return n}getExtractHint(r){for(let o of this.entries.keys()){let a=this.pathUtils.extname(o);if(r.relevantExtensions.has(a))return!0}return!1}getAllFiles(){return Array.from(this.entries.keys())}getRealPath(){if(!this.path)throw new Error(\"ZipFS don't have real paths when loaded from a buffer\");return this.path}prepareClose(){if(!this.ready)throw tr.EBUSY(\"archive closed, close\");_g(this)}getBufferAndClose(){if(this.prepareClose(),this.entries.size===0)return this.discardAndClose(),Fb();try{if(this.libzip.source.keep(this.lzSource),this.libzip.close(this.zip)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));if(this.libzip.source.open(this.lzSource)===-1)throw this.makeLibzipError(this.libzip.source.error(this.lzSource));if(this.libzip.source.seek(this.lzSource,0,0,this.libzip.SEEK_END)===-1)throw this.makeLibzipError(this.libzip.source.error(this.lzSource));let r=this.libzip.source.tell(this.lzSource);if(r===-1)throw this.makeLibzipError(this.libzip.source.error(this.lzSource));if(this.libzip.source.seek(this.lzSource,0,0,this.libzip.SEEK_SET)===-1)throw this.makeLibzipError(this.libzip.source.error(this.lzSource));let o=this.libzip.malloc(r);if(!o)throw new Error(\"Couldn't allocate enough memory\");try{let a=this.libzip.source.read(this.lzSource,o,r);if(a===-1)throw this.makeLibzipError(this.libzip.source.error(this.lzSource));if(a<r)throw new Error(\"Incomplete read\");if(a>r)throw new Error(\"Overread\");let n=Buffer.from(this.libzip.HEAPU8.subarray(o,o+r));return process.env.YARN_IS_TEST_ENV&&process.env.YARN_ZIP_DATA_EPILOGUE&&(n=Buffer.concat([n,Buffer.from(process.env.YARN_ZIP_DATA_EPILOGUE)])),n}finally{this.libzip.free(o)}}finally{this.libzip.source.close(this.lzSource),this.libzip.source.free(this.lzSource),this.ready=!1}}discardAndClose(){this.prepareClose(),this.libzip.discard(this.zip),this.ready=!1}saveAndClose(){if(!this.path||!this.baseFs)throw new Error(\"ZipFS cannot be saved and must be discarded when loaded from a buffer\");if(this.readOnly){this.discardAndClose();return}let r=this.baseFs.existsSync(this.path)||this.stats.mode===Ea.DEFAULT_MODE?void 0:this.stats.mode;this.baseFs.writeFileSync(this.path,this.getBufferAndClose(),{mode:r}),this.ready=!1}resolve(r){return z.resolve(Bt.root,r)}async openPromise(r,o,a){return this.openSync(r,o,a)}openSync(r,o,a){let n=this.nextFd++;return this.fds.set(n,{cursor:0,p:r}),n}hasOpenFileHandles(){return!!this.fds.size}async opendirPromise(r,o){return this.opendirSync(r,o)}opendirSync(r,o={}){let a=this.resolveFilename(`opendir '${r}'`,r);if(!this.entries.has(a)&&!this.listings.has(a))throw tr.ENOENT(`opendir '${r}'`);let n=this.listings.get(a);if(!n)throw tr.ENOTDIR(`opendir '${r}'`);let u=[...n],A=this.openSync(a,\"r\");return SD(this,a,u,{onClose:()=>{this.closeSync(A)}})}async readPromise(r,o,a,n,u){return this.readSync(r,o,a,n,u)}readSync(r,o,a=0,n=o.byteLength,u=-1){let A=this.fds.get(r);if(typeof A>\"u\")throw tr.EBADF(\"read\");let p=u===-1||u===null?A.cursor:u,h=this.readFileSync(A.p);h.copy(o,a,p,p+n);let E=Math.max(0,Math.min(h.length-p,n));return(u===-1||u===null)&&(A.cursor+=E),E}async writePromise(r,o,a,n,u){return typeof o==\"string\"?this.writeSync(r,o,u):this.writeSync(r,o,a,n,u)}writeSync(r,o,a,n,u){throw typeof this.fds.get(r)>\"u\"?tr.EBADF(\"read\"):new Error(\"Unimplemented\")}async closePromise(r){return this.closeSync(r)}closeSync(r){if(typeof this.fds.get(r)>\"u\")throw tr.EBADF(\"read\");this.fds.delete(r)}createReadStream(r,{encoding:o}={}){if(r===null)throw new Error(\"Unimplemented\");let a=this.openSync(r,\"r\"),n=Object.assign(new nU.PassThrough({emitClose:!0,autoDestroy:!0,destroy:(A,p)=>{clearImmediate(u),this.closeSync(a),p(A)}}),{close(){n.destroy()},bytesRead:0,path:r,pending:!1}),u=setImmediate(async()=>{try{let A=await this.readFilePromise(r,o);n.bytesRead=A.length,n.end(A)}catch(A){n.destroy(A)}});return n}createWriteStream(r,{encoding:o}={}){if(this.readOnly)throw tr.EROFS(`open '${r}'`);if(r===null)throw new Error(\"Unimplemented\");let a=[],n=this.openSync(r,\"w\"),u=Object.assign(new nU.PassThrough({autoDestroy:!0,emitClose:!0,destroy:(A,p)=>{try{A?p(A):(this.writeFileSync(r,Buffer.concat(a),o),p(null))}catch(h){p(h)}finally{this.closeSync(n)}}}),{close(){u.destroy()},bytesWritten:0,path:r,pending:!1});return u.on(\"data\",A=>{let p=Buffer.from(A);u.bytesWritten+=p.length,a.push(p)}),u}async realpathPromise(r){return this.realpathSync(r)}realpathSync(r){let o=this.resolveFilename(`lstat '${r}'`,r);if(!this.entries.has(o)&&!this.listings.has(o))throw tr.ENOENT(`lstat '${r}'`);return o}async existsPromise(r){return this.existsSync(r)}existsSync(r){if(!this.ready)throw tr.EBUSY(`archive closed, existsSync '${r}'`);if(this.symlinkCount===0){let a=z.resolve(Bt.root,r);return this.entries.has(a)||this.listings.has(a)}let o;try{o=this.resolveFilename(`stat '${r}'`,r,void 0,!1)}catch{return!1}return o===void 0?!1:this.entries.has(o)||this.listings.has(o)}async accessPromise(r,o){return this.accessSync(r,o)}accessSync(r,o=ta.constants.F_OK){let a=this.resolveFilename(`access '${r}'`,r);if(!this.entries.has(a)&&!this.listings.has(a))throw tr.ENOENT(`access '${r}'`);if(this.readOnly&&o&ta.constants.W_OK)throw tr.EROFS(`access '${r}'`)}async statPromise(r,o={bigint:!1}){return o.bigint?this.statSync(r,{bigint:!0}):this.statSync(r)}statSync(r,o={bigint:!1,throwIfNoEntry:!0}){let a=this.resolveFilename(`stat '${r}'`,r,void 0,o.throwIfNoEntry);if(a!==void 0){if(!this.entries.has(a)&&!this.listings.has(a)){if(o.throwIfNoEntry===!1)return;throw tr.ENOENT(`stat '${r}'`)}if(r[r.length-1]===\"/\"&&!this.listings.has(a))throw tr.ENOTDIR(`stat '${r}'`);return this.statImpl(`stat '${r}'`,a,o)}}async fstatPromise(r,o){return this.fstatSync(r,o)}fstatSync(r,o){let a=this.fds.get(r);if(typeof a>\"u\")throw tr.EBADF(\"fstatSync\");let{p:n}=a,u=this.resolveFilename(`stat '${n}'`,n);if(!this.entries.has(u)&&!this.listings.has(u))throw tr.ENOENT(`stat '${n}'`);if(n[n.length-1]===\"/\"&&!this.listings.has(u))throw tr.ENOTDIR(`stat '${n}'`);return this.statImpl(`fstat '${n}'`,u,o)}async lstatPromise(r,o={bigint:!1}){return o.bigint?this.lstatSync(r,{bigint:!0}):this.lstatSync(r)}lstatSync(r,o={bigint:!1,throwIfNoEntry:!0}){let a=this.resolveFilename(`lstat '${r}'`,r,!1,o.throwIfNoEntry);if(a!==void 0){if(!this.entries.has(a)&&!this.listings.has(a)){if(o.throwIfNoEntry===!1)return;throw tr.ENOENT(`lstat '${r}'`)}if(r[r.length-1]===\"/\"&&!this.listings.has(a))throw tr.ENOTDIR(`lstat '${r}'`);return this.statImpl(`lstat '${r}'`,a,o)}}statImpl(r,o,a={}){let n=this.entries.get(o);if(typeof n<\"u\"){let u=this.libzip.struct.statS();if(this.libzip.statIndex(this.zip,n,0,0,u)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));let p=this.stats.uid,h=this.stats.gid,E=this.libzip.struct.statSize(u)>>>0,I=512,v=Math.ceil(E/I),x=(this.libzip.struct.statMtime(u)>>>0)*1e3,C=x,R=x,N=x,U=new Date(C),V=new Date(R),te=new Date(N),ae=new Date(x),fe=this.listings.has(o)?ta.constants.S_IFDIR:this.isSymbolicLink(n)?ta.constants.S_IFLNK:ta.constants.S_IFREG,ue=fe===ta.constants.S_IFDIR?493:420,me=fe|this.getUnixMode(n,ue)&511,he=this.libzip.struct.statCrc(u),Be=Object.assign(new Ea.StatEntry,{uid:p,gid:h,size:E,blksize:I,blocks:v,atime:U,birthtime:V,ctime:te,mtime:ae,atimeMs:C,birthtimeMs:R,ctimeMs:N,mtimeMs:x,mode:me,crc:he});return a.bigint===!0?Ea.convertToBigIntStats(Be):Be}if(this.listings.has(o)){let u=this.stats.uid,A=this.stats.gid,p=0,h=512,E=0,I=this.stats.mtimeMs,v=this.stats.mtimeMs,x=this.stats.mtimeMs,C=this.stats.mtimeMs,R=new Date(I),N=new Date(v),U=new Date(x),V=new Date(C),te=ta.constants.S_IFDIR|493,ae=0,fe=Object.assign(new Ea.StatEntry,{uid:u,gid:A,size:p,blksize:h,blocks:E,atime:R,birthtime:N,ctime:U,mtime:V,atimeMs:I,birthtimeMs:v,ctimeMs:x,mtimeMs:C,mode:te,crc:ae});return a.bigint===!0?Ea.convertToBigIntStats(fe):fe}throw new Error(\"Unreachable\")}getUnixMode(r,o){if(this.libzip.file.getExternalAttributes(this.zip,r,0,0,this.libzip.uint08S,this.libzip.uint32S)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));return this.libzip.getValue(this.libzip.uint08S,\"i8\")>>>0!==this.libzip.ZIP_OPSYS_UNIX?o:this.libzip.getValue(this.libzip.uint32S,\"i32\")>>>16}registerListing(r){let o=this.listings.get(r);if(o)return o;this.registerListing(z.dirname(r)).add(z.basename(r));let n=new Set;return this.listings.set(r,n),n}registerEntry(r,o){this.registerListing(z.dirname(r)).add(z.basename(r)),this.entries.set(r,o)}unregisterListing(r){this.listings.delete(r),this.listings.get(z.dirname(r))?.delete(z.basename(r))}unregisterEntry(r){this.unregisterListing(r);let o=this.entries.get(r);this.entries.delete(r),!(typeof o>\"u\")&&(this.fileSources.delete(o),this.isSymbolicLink(o)&&this.symlinkCount--)}deleteEntry(r,o){if(this.unregisterEntry(r),this.libzip.delete(this.zip,o)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip))}resolveFilename(r,o,a=!0,n=!0){if(!this.ready)throw tr.EBUSY(`archive closed, ${r}`);let u=z.resolve(Bt.root,o);if(u===\"/\")return Bt.root;let A=this.entries.get(u);if(a&&A!==void 0)if(this.symlinkCount!==0&&this.isSymbolicLink(A)){let p=this.getFileSource(A).toString();return this.resolveFilename(r,z.resolve(z.dirname(u),p),!0,n)}else return u;for(;;){let p=this.resolveFilename(r,z.dirname(u),!0,n);if(p===void 0)return p;let h=this.listings.has(p),E=this.entries.has(p);if(!h&&!E){if(n===!1)return;throw tr.ENOENT(r)}if(!h)throw tr.ENOTDIR(r);if(u=z.resolve(p,z.basename(u)),!a||this.symlinkCount===0)break;let I=this.libzip.name.locate(this.zip,u.slice(1),0);if(I===-1)break;if(this.isSymbolicLink(I)){let v=this.getFileSource(I).toString();u=z.resolve(z.dirname(u),v)}else break}return u}allocateBuffer(r){Buffer.isBuffer(r)||(r=Buffer.from(r));let o=this.libzip.malloc(r.byteLength);if(!o)throw new Error(\"Couldn't allocate enough memory\");return new Uint8Array(this.libzip.HEAPU8.buffer,o,r.byteLength).set(r),{buffer:o,byteLength:r.byteLength}}allocateUnattachedSource(r){let o=this.libzip.struct.errorS(),{buffer:a,byteLength:n}=this.allocateBuffer(r),u=this.libzip.source.fromUnattachedBuffer(a,n,0,1,o);if(u===0)throw this.libzip.free(o),this.makeLibzipError(o);return u}allocateSource(r){let{buffer:o,byteLength:a}=this.allocateBuffer(r),n=this.libzip.source.fromBuffer(this.zip,o,a,0,1);if(n===0)throw this.libzip.free(o),this.makeLibzipError(this.libzip.getError(this.zip));return n}setFileSource(r,o){let a=Buffer.isBuffer(o)?o:Buffer.from(o),n=z.relative(Bt.root,r),u=this.allocateSource(o);try{let A=this.libzip.file.add(this.zip,n,u,this.libzip.ZIP_FL_OVERWRITE);if(A===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));if(this.level!==\"mixed\"){let p=this.level===0?this.libzip.ZIP_CM_STORE:this.libzip.ZIP_CM_DEFLATE;if(this.libzip.file.setCompression(this.zip,A,0,p,this.level)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip))}return this.fileSources.set(A,a),A}catch(A){throw this.libzip.source.free(u),A}}isSymbolicLink(r){if(this.symlinkCount===0)return!1;if(this.libzip.file.getExternalAttributes(this.zip,r,0,0,this.libzip.uint08S,this.libzip.uint32S)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));return this.libzip.getValue(this.libzip.uint08S,\"i8\")>>>0!==this.libzip.ZIP_OPSYS_UNIX?!1:(this.libzip.getValue(this.libzip.uint32S,\"i32\")>>>16&ta.constants.S_IFMT)===ta.constants.S_IFLNK}getFileSource(r,o={asyncDecompress:!1}){let a=this.fileSources.get(r);if(typeof a<\"u\")return a;let n=this.libzip.struct.statS();if(this.libzip.statIndex(this.zip,r,0,0,n)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));let A=this.libzip.struct.statCompSize(n),p=this.libzip.struct.statCompMethod(n),h=this.libzip.malloc(A);try{let E=this.libzip.fopenIndex(this.zip,r,0,this.libzip.ZIP_FL_COMPRESSED);if(E===0)throw this.makeLibzipError(this.libzip.getError(this.zip));try{let I=this.libzip.fread(E,h,A,0);if(I===-1)throw this.makeLibzipError(this.libzip.file.getError(E));if(I<A)throw new Error(\"Incomplete read\");if(I>A)throw new Error(\"Overread\");let v=this.libzip.HEAPU8.subarray(h,h+A),x=Buffer.from(v);if(p===0)return this.fileSources.set(r,x),x;if(o.asyncDecompress)return new Promise((C,R)=>{iU.default.inflateRaw(x,(N,U)=>{N?R(N):(this.fileSources.set(r,U),C(U))})});{let C=iU.default.inflateRawSync(x);return this.fileSources.set(r,C),C}}finally{this.libzip.fclose(E)}}finally{this.libzip.free(h)}}async fchmodPromise(r,o){return this.chmodPromise(this.fdToPath(r,\"fchmod\"),o)}fchmodSync(r,o){return this.chmodSync(this.fdToPath(r,\"fchmodSync\"),o)}async chmodPromise(r,o){return this.chmodSync(r,o)}chmodSync(r,o){if(this.readOnly)throw tr.EROFS(`chmod '${r}'`);o&=493;let a=this.resolveFilename(`chmod '${r}'`,r,!1),n=this.entries.get(a);if(typeof n>\"u\")throw new Error(`Assertion failed: The entry should have been registered (${a})`);let A=this.getUnixMode(n,ta.constants.S_IFREG|0)&-512|o;if(this.libzip.file.setExternalAttributes(this.zip,n,0,0,this.libzip.ZIP_OPSYS_UNIX,A<<16)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip))}async fchownPromise(r,o,a){return this.chownPromise(this.fdToPath(r,\"fchown\"),o,a)}fchownSync(r,o,a){return this.chownSync(this.fdToPath(r,\"fchownSync\"),o,a)}async chownPromise(r,o,a){return this.chownSync(r,o,a)}chownSync(r,o,a){throw new Error(\"Unimplemented\")}async renamePromise(r,o){return this.renameSync(r,o)}renameSync(r,o){throw new Error(\"Unimplemented\")}async copyFilePromise(r,o,a){let{indexSource:n,indexDest:u,resolvedDestP:A}=this.prepareCopyFile(r,o,a),p=await this.getFileSource(n,{asyncDecompress:!0}),h=this.setFileSource(A,p);h!==u&&this.registerEntry(A,h)}copyFileSync(r,o,a=0){let{indexSource:n,indexDest:u,resolvedDestP:A}=this.prepareCopyFile(r,o,a),p=this.getFileSource(n),h=this.setFileSource(A,p);h!==u&&this.registerEntry(A,h)}prepareCopyFile(r,o,a=0){if(this.readOnly)throw tr.EROFS(`copyfile '${r} -> '${o}'`);if((a&ta.constants.COPYFILE_FICLONE_FORCE)!==0)throw tr.ENOSYS(\"unsupported clone operation\",`copyfile '${r}' -> ${o}'`);let n=this.resolveFilename(`copyfile '${r} -> ${o}'`,r),u=this.entries.get(n);if(typeof u>\"u\")throw tr.EINVAL(`copyfile '${r}' -> '${o}'`);let A=this.resolveFilename(`copyfile '${r}' -> ${o}'`,o),p=this.entries.get(A);if((a&(ta.constants.COPYFILE_EXCL|ta.constants.COPYFILE_FICLONE_FORCE))!==0&&typeof p<\"u\")throw tr.EEXIST(`copyfile '${r}' -> '${o}'`);return{indexSource:u,resolvedDestP:A,indexDest:p}}async appendFilePromise(r,o,a){if(this.readOnly)throw tr.EROFS(`open '${r}'`);return typeof a>\"u\"?a={flag:\"a\"}:typeof a==\"string\"?a={flag:\"a\",encoding:a}:typeof a.flag>\"u\"&&(a={flag:\"a\",...a}),this.writeFilePromise(r,o,a)}appendFileSync(r,o,a={}){if(this.readOnly)throw tr.EROFS(`open '${r}'`);return typeof a>\"u\"?a={flag:\"a\"}:typeof a==\"string\"?a={flag:\"a\",encoding:a}:typeof a.flag>\"u\"&&(a={flag:\"a\",...a}),this.writeFileSync(r,o,a)}fdToPath(r,o){let a=this.fds.get(r)?.p;if(typeof a>\"u\")throw tr.EBADF(o);return a}async writeFilePromise(r,o,a){let{encoding:n,mode:u,index:A,resolvedP:p}=this.prepareWriteFile(r,a);A!==void 0&&typeof a==\"object\"&&a.flag&&a.flag.includes(\"a\")&&(o=Buffer.concat([await this.getFileSource(A,{asyncDecompress:!0}),Buffer.from(o)])),n!==null&&(o=o.toString(n));let h=this.setFileSource(p,o);h!==A&&this.registerEntry(p,h),u!==null&&await this.chmodPromise(p,u)}writeFileSync(r,o,a){let{encoding:n,mode:u,index:A,resolvedP:p}=this.prepareWriteFile(r,a);A!==void 0&&typeof a==\"object\"&&a.flag&&a.flag.includes(\"a\")&&(o=Buffer.concat([this.getFileSource(A),Buffer.from(o)])),n!==null&&(o=o.toString(n));let h=this.setFileSource(p,o);h!==A&&this.registerEntry(p,h),u!==null&&this.chmodSync(p,u)}prepareWriteFile(r,o){if(typeof r==\"number\"&&(r=this.fdToPath(r,\"read\")),this.readOnly)throw tr.EROFS(`open '${r}'`);let a=this.resolveFilename(`open '${r}'`,r);if(this.listings.has(a))throw tr.EISDIR(`open '${r}'`);let n=null,u=null;typeof o==\"string\"?n=o:typeof o==\"object\"&&({encoding:n=null,mode:u=null}=o);let A=this.entries.get(a);return{encoding:n,mode:u,resolvedP:a,index:A}}async unlinkPromise(r){return this.unlinkSync(r)}unlinkSync(r){if(this.readOnly)throw tr.EROFS(`unlink '${r}'`);let o=this.resolveFilename(`unlink '${r}'`,r);if(this.listings.has(o))throw tr.EISDIR(`unlink '${r}'`);let a=this.entries.get(o);if(typeof a>\"u\")throw tr.EINVAL(`unlink '${r}'`);this.deleteEntry(o,a)}async utimesPromise(r,o,a){return this.utimesSync(r,o,a)}utimesSync(r,o,a){if(this.readOnly)throw tr.EROFS(`utimes '${r}'`);let n=this.resolveFilename(`utimes '${r}'`,r);this.utimesImpl(n,a)}async lutimesPromise(r,o,a){return this.lutimesSync(r,o,a)}lutimesSync(r,o,a){if(this.readOnly)throw tr.EROFS(`lutimes '${r}'`);let n=this.resolveFilename(`utimes '${r}'`,r,!1);this.utimesImpl(n,a)}utimesImpl(r,o){this.listings.has(r)&&(this.entries.has(r)||this.hydrateDirectory(r));let a=this.entries.get(r);if(a===void 0)throw new Error(\"Unreachable\");if(this.libzip.file.setMtime(this.zip,a,0,cot(o),0)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip))}async mkdirPromise(r,o){return this.mkdirSync(r,o)}mkdirSync(r,{mode:o=493,recursive:a=!1}={}){if(a)return this.mkdirpSync(r,{chmod:o});if(this.readOnly)throw tr.EROFS(`mkdir '${r}'`);let n=this.resolveFilename(`mkdir '${r}'`,r);if(this.entries.has(n)||this.listings.has(n))throw tr.EEXIST(`mkdir '${r}'`);this.hydrateDirectory(n),this.chmodSync(n,o)}async rmdirPromise(r,o){return this.rmdirSync(r,o)}rmdirSync(r,{recursive:o=!1}={}){if(this.readOnly)throw tr.EROFS(`rmdir '${r}'`);if(o){this.removeSync(r);return}let a=this.resolveFilename(`rmdir '${r}'`,r),n=this.listings.get(a);if(!n)throw tr.ENOTDIR(`rmdir '${r}'`);if(n.size>0)throw tr.ENOTEMPTY(`rmdir '${r}'`);let u=this.entries.get(a);if(typeof u>\"u\")throw tr.EINVAL(`rmdir '${r}'`);this.deleteEntry(r,u)}async rmPromise(r,o){return this.rmSync(r,o)}rmSync(r,{recursive:o=!1}={}){if(this.readOnly)throw tr.EROFS(`rm '${r}'`);if(o){this.removeSync(r);return}let a=this.resolveFilename(`rm '${r}'`,r),n=this.listings.get(a);if(!n)throw tr.ENOTDIR(`rm '${r}'`);if(n.size>0)throw tr.ENOTEMPTY(`rm '${r}'`);let u=this.entries.get(a);if(typeof u>\"u\")throw tr.EINVAL(`rm '${r}'`);this.deleteEntry(r,u)}hydrateDirectory(r){let o=this.libzip.dir.add(this.zip,z.relative(Bt.root,r));if(o===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));return this.registerListing(r),this.registerEntry(r,o),o}async linkPromise(r,o){return this.linkSync(r,o)}linkSync(r,o){throw tr.EOPNOTSUPP(`link '${r}' -> '${o}'`)}async symlinkPromise(r,o){return this.symlinkSync(r,o)}symlinkSync(r,o){if(this.readOnly)throw tr.EROFS(`symlink '${r}' -> '${o}'`);let a=this.resolveFilename(`symlink '${r}' -> '${o}'`,o);if(this.listings.has(a))throw tr.EISDIR(`symlink '${r}' -> '${o}'`);if(this.entries.has(a))throw tr.EEXIST(`symlink '${r}' -> '${o}'`);let n=this.setFileSource(a,r);if(this.registerEntry(a,n),this.libzip.file.setExternalAttributes(this.zip,n,0,0,this.libzip.ZIP_OPSYS_UNIX,(ta.constants.S_IFLNK|511)<<16)===-1)throw this.makeLibzipError(this.libzip.getError(this.zip));this.symlinkCount+=1}async readFilePromise(r,o){typeof o==\"object\"&&(o=o?o.encoding:void 0);let a=await this.readFileBuffer(r,{asyncDecompress:!0});return o?a.toString(o):a}readFileSync(r,o){typeof o==\"object\"&&(o=o?o.encoding:void 0);let a=this.readFileBuffer(r);return o?a.toString(o):a}readFileBuffer(r,o={asyncDecompress:!1}){typeof r==\"number\"&&(r=this.fdToPath(r,\"read\"));let a=this.resolveFilename(`open '${r}'`,r);if(!this.entries.has(a)&&!this.listings.has(a))throw tr.ENOENT(`open '${r}'`);if(r[r.length-1]===\"/\"&&!this.listings.has(a))throw tr.ENOTDIR(`open '${r}'`);if(this.listings.has(a))throw tr.EISDIR(\"read\");let n=this.entries.get(a);if(n===void 0)throw new Error(\"Unreachable\");return this.getFileSource(n,o)}async readdirPromise(r,o){return this.readdirSync(r,o)}readdirSync(r,o){let a=this.resolveFilename(`scandir '${r}'`,r);if(!this.entries.has(a)&&!this.listings.has(a))throw tr.ENOENT(`scandir '${r}'`);let n=this.listings.get(a);if(!n)throw tr.ENOTDIR(`scandir '${r}'`);if(o?.recursive)if(o?.withFileTypes){let u=Array.from(n,A=>Object.assign(this.statImpl(\"lstat\",z.join(r,A)),{name:A,path:Bt.dot}));for(let A of u){if(!A.isDirectory())continue;let p=z.join(A.path,A.name),h=this.listings.get(z.join(a,p));for(let E of h)u.push(Object.assign(this.statImpl(\"lstat\",z.join(r,p,E)),{name:E,path:p}))}return u}else{let u=[...n];for(let A of u){let p=this.listings.get(z.join(a,A));if(!(typeof p>\"u\"))for(let h of p)u.push(z.join(A,h))}return u}else return o?.withFileTypes?Array.from(n,u=>Object.assign(this.statImpl(\"lstat\",z.join(r,u)),{name:u,path:void 0})):[...n]}async readlinkPromise(r){let o=this.prepareReadlink(r);return(await this.getFileSource(o,{asyncDecompress:!0})).toString()}readlinkSync(r){let o=this.prepareReadlink(r);return this.getFileSource(o).toString()}prepareReadlink(r){let o=this.resolveFilename(`readlink '${r}'`,r,!1);if(!this.entries.has(o)&&!this.listings.has(o))throw tr.ENOENT(`readlink '${r}'`);if(r[r.length-1]===\"/\"&&!this.listings.has(o))throw tr.ENOTDIR(`open '${r}'`);if(this.listings.has(o))throw tr.EINVAL(`readlink '${r}'`);let a=this.entries.get(o);if(a===void 0)throw new Error(\"Unreachable\");if(!this.isSymbolicLink(a))throw tr.EINVAL(`readlink '${r}'`);return a}async truncatePromise(r,o=0){let a=this.resolveFilename(`open '${r}'`,r),n=this.entries.get(a);if(typeof n>\"u\")throw tr.EINVAL(`open '${r}'`);let u=await this.getFileSource(n,{asyncDecompress:!0}),A=Buffer.alloc(o,0);return u.copy(A),await this.writeFilePromise(r,A)}truncateSync(r,o=0){let a=this.resolveFilename(`open '${r}'`,r),n=this.entries.get(a);if(typeof n>\"u\")throw tr.EINVAL(`open '${r}'`);let u=this.getFileSource(n),A=Buffer.alloc(o,0);return u.copy(A),this.writeFileSync(r,A)}async ftruncatePromise(r,o){return this.truncatePromise(this.fdToPath(r,\"ftruncate\"),o)}ftruncateSync(r,o){return this.truncateSync(this.fdToPath(r,\"ftruncateSync\"),o)}watch(r,o,a){let n;switch(typeof o){case\"function\":case\"string\":case\"undefined\":n=!0;break;default:({persistent:n=!0}=o);break}if(!n)return{on:()=>{},close:()=>{}};let u=setInterval(()=>{},24*60*60*1e3);return{on:()=>{},close:()=>{clearInterval(u)}}}watchFile(r,o,a){let n=z.resolve(Bt.root,r);return ny(this,n,o,a)}unwatchFile(r,o){let a=z.resolve(Bt.root,r);return Ug(this,a,o)}}});function Hle(t,e,r=Buffer.alloc(0),o){let a=new Ji(r),n=I=>I===e||I.startsWith(`${e}/`)?I.slice(0,e.length):null,u=async(I,v)=>()=>a,A=(I,v)=>a,p={...t},h=new Tn(p),E=new qp({baseFs:h,getMountPoint:n,factoryPromise:u,factorySync:A,magicByte:21,maxAge:1/0,typeCheck:o?.typeCheck});return Kw(_le.default,new Gp(E)),a}var _le,qle=Et(()=>{Pt();_le=$e(ve(\"fs\"));sU()});var Gle=Et(()=>{Ole();sU();qle()});var x1={};zt(x1,{DEFAULT_COMPRESSION_LEVEL:()=>Ule,LibzipError:()=>Rb,ZipFS:()=>Ji,ZipOpenFS:()=>Jl,getArchivePart:()=>rU,getLibzipPromise:()=>Aot,getLibzipSync:()=>uot,makeEmptyArchive:()=>Fb,mountMemoryDrive:()=>Hle});function uot(){return b1()}async function Aot(){return b1()}var jle,iA=Et(()=>{$4();jle=$e(Rle());Nle();Gle();Fle(()=>{let t=(0,jle.default)();return Lle(t)})});var RE,Yle=Et(()=>{Pt();qt();k1();RE=class extends nt{constructor(){super(...arguments);this.cwd=ge.String(\"--cwd\",process.cwd(),{description:\"The directory to run the command in\"});this.commandName=ge.String();this.args=ge.Proxy()}async execute(){let r=this.args.length>0?`${this.commandName} ${this.args.join(\" \")}`:this.commandName;return await TE(r,[],{cwd:le.toPortablePath(this.cwd),stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr})}};RE.usage={description:\"run a command using yarn's portable shell\",details:`\n      This command will run a command using Yarn's portable shell.\n\n      Make sure to escape glob patterns, redirections, and other features that might be expanded by your own shell.\n\n      Note: To escape something from Yarn's shell, you might have to escape it twice, the first time from your own shell.\n\n      Note: Don't use this command in Yarn scripts, as Yarn's shell is automatically used.\n\n      For a list of features, visit: https://github.com/yarnpkg/berry/blob/master/packages/yarnpkg-shell/README.md.\n    `,examples:[[\"Run a simple command\",\"$0 echo Hello\"],[\"Run a command with a glob pattern\",\"$0 echo '*.js'\"],[\"Run a command with a redirection\",\"$0 echo Hello World '>' hello.txt\"],[\"Run a command with an escaped glob pattern (The double escape is needed in Unix shells)\",`$0 echo '\"*.js\"'`],[\"Run a command with a variable (Double quotes are needed in Unix shells, to prevent them from expanding the variable)\",'$0 \"GREETING=Hello echo $GREETING World\"']]}});var ll,Wle=Et(()=>{ll=class extends Error{constructor(e){super(e),this.name=\"ShellError\"}}});var Nb={};zt(Nb,{fastGlobOptions:()=>Vle,isBraceExpansion:()=>oU,isGlobPattern:()=>fot,match:()=>pot,micromatchOptions:()=>Lb});function fot(t){if(!Tb.default.scan(t,Lb).isGlob)return!1;try{Tb.default.parse(t,Lb)}catch{return!1}return!0}function pot(t,{cwd:e,baseFs:r}){return(0,Kle.default)(t,{...Vle,cwd:le.fromPortablePath(e),fs:FD(zle.default,new Gp(r))})}function oU(t){return Tb.default.scan(t,Lb).isBrace}var Kle,zle,Tb,Lb,Vle,Jle=Et(()=>{Pt();Kle=$e(RS()),zle=$e(ve(\"fs\")),Tb=$e(Zo()),Lb={strictBrackets:!0},Vle={onlyDirectories:!1,onlyFiles:!1}});function aU(){}function lU(){for(let t of Qd)t.kill()}function ece(t,e,r,o){return a=>{let n=a[0]instanceof sA.Transform?\"pipe\":a[0],u=a[1]instanceof sA.Transform?\"pipe\":a[1],A=a[2]instanceof sA.Transform?\"pipe\":a[2],p=(0,Zle.default)(t,e,{...o,stdio:[n,u,A]});return Qd.add(p),Qd.size===1&&(process.on(\"SIGINT\",aU),process.on(\"SIGTERM\",lU)),a[0]instanceof sA.Transform&&a[0].pipe(p.stdin),a[1]instanceof sA.Transform&&p.stdout.pipe(a[1],{end:!1}),a[2]instanceof sA.Transform&&p.stderr.pipe(a[2],{end:!1}),{stdin:p.stdin,promise:new Promise(h=>{p.on(\"error\",E=>{switch(Qd.delete(p),Qd.size===0&&(process.off(\"SIGINT\",aU),process.off(\"SIGTERM\",lU)),E.code){case\"ENOENT\":a[2].write(`command not found: ${t}\n`),h(127);break;case\"EACCES\":a[2].write(`permission denied: ${t}\n`),h(128);break;default:a[2].write(`uncaught error: ${E.message}\n`),h(1);break}}),p.on(\"close\",E=>{Qd.delete(p),Qd.size===0&&(process.off(\"SIGINT\",aU),process.off(\"SIGTERM\",lU)),h(E!==null?E:129)})})}}}function tce(t){return e=>{let r=e[0]===\"pipe\"?new sA.PassThrough:e[0];return{stdin:r,promise:Promise.resolve().then(()=>t({stdin:r,stdout:e[1],stderr:e[2]}))}}}function Ob(t,e){return LE.start(t,e)}function Xle(t,e=null){let r=new sA.PassThrough,o=new $le.StringDecoder,a=\"\";return r.on(\"data\",n=>{let u=o.write(n),A;do if(A=u.indexOf(`\n`),A!==-1){let p=a+u.substring(0,A);u=u.substring(A+1),a=\"\",t(e!==null?`${e} ${p}`:p)}while(A!==-1);a+=u}),r.on(\"end\",()=>{let n=o.end();n!==\"\"&&t(e!==null?`${e} ${n}`:n)}),r}function rce(t,{prefix:e}){return{stdout:Xle(r=>t.stdout.write(`${r}\n`),t.stdout.isTTY?e:null),stderr:Xle(r=>t.stderr.write(`${r}\n`),t.stderr.isTTY?e:null)}}var Zle,sA,$le,Qd,Xl,cU,LE,uU=Et(()=>{Zle=$e(sT()),sA=ve(\"stream\"),$le=ve(\"string_decoder\"),Qd=new Set;Xl=class{constructor(e){this.stream=e}close(){}get(){return this.stream}},cU=class{constructor(){this.stream=null}close(){if(this.stream===null)throw new Error(\"Assertion failed: No stream attached\");this.stream.end()}attach(e){this.stream=e}get(){if(this.stream===null)throw new Error(\"Assertion failed: No stream attached\");return this.stream}},LE=class{constructor(e,r){this.stdin=null;this.stdout=null;this.stderr=null;this.pipe=null;this.ancestor=e,this.implementation=r}static start(e,{stdin:r,stdout:o,stderr:a}){let n=new LE(null,e);return n.stdin=r,n.stdout=o,n.stderr=a,n}pipeTo(e,r=1){let o=new LE(this,e),a=new cU;return o.pipe=a,o.stdout=this.stdout,o.stderr=this.stderr,(r&1)===1?this.stdout=a:this.ancestor!==null&&(this.stderr=this.ancestor.stdout),(r&2)===2?this.stderr=a:this.ancestor!==null&&(this.stderr=this.ancestor.stderr),o}async exec(){let e=[\"ignore\",\"ignore\",\"ignore\"];if(this.pipe)e[0]=\"pipe\";else{if(this.stdin===null)throw new Error(\"Assertion failed: No input stream registered\");e[0]=this.stdin.get()}let r;if(this.stdout===null)throw new Error(\"Assertion failed: No output stream registered\");r=this.stdout,e[1]=r.get();let o;if(this.stderr===null)throw new Error(\"Assertion failed: No error stream registered\");o=this.stderr,e[2]=o.get();let a=this.implementation(e);return this.pipe&&this.pipe.attach(a.stdin),await a.promise.then(n=>(r.close(),o.close(),n))}async run(){let e=[];for(let o=this;o;o=o.ancestor)e.push(o.exec());return(await Promise.all(e))[0]}}});var T1={};zt(T1,{EntryCommand:()=>RE,ShellError:()=>ll,execute:()=>TE,globUtils:()=>Nb});function nce(t,e,r){let o=new cl.PassThrough({autoDestroy:!0});switch(t){case 0:(e&1)===1&&r.stdin.pipe(o,{end:!1}),(e&2)===2&&r.stdin instanceof cl.Writable&&o.pipe(r.stdin,{end:!1});break;case 1:(e&1)===1&&r.stdout.pipe(o,{end:!1}),(e&2)===2&&o.pipe(r.stdout,{end:!1});break;case 2:(e&1)===1&&r.stderr.pipe(o,{end:!1}),(e&2)===2&&o.pipe(r.stderr,{end:!1});break;default:throw new ll(`Bad file descriptor: \"${t}\"`)}return o}function Ub(t,e={}){let r={...t,...e};return r.environment={...t.environment,...e.environment},r.variables={...t.variables,...e.variables},r}async function got(t,e,r){let o=[],a=new cl.PassThrough;return a.on(\"data\",n=>o.push(n)),await _b(t,e,Ub(r,{stdout:a})),Buffer.concat(o).toString().replace(/[\\r\\n]+$/,\"\")}async function ice(t,e,r){let o=t.map(async n=>{let u=await Fd(n.args,e,r);return{name:n.name,value:u.join(\" \")}});return(await Promise.all(o)).reduce((n,u)=>(n[u.name]=u.value,n),{})}function Mb(t){return t.match(/[^ \\r\\n\\t]+/g)||[]}async function uce(t,e,r,o,a=o){switch(t.name){case\"$\":o(String(process.pid));break;case\"#\":o(String(e.args.length));break;case\"@\":if(t.quoted)for(let n of e.args)a(n);else for(let n of e.args){let u=Mb(n);for(let A=0;A<u.length-1;++A)a(u[A]);o(u[u.length-1])}break;case\"*\":{let n=e.args.join(\" \");if(t.quoted)o(n);else for(let u of Mb(n))a(u)}break;case\"PPID\":o(String(process.ppid));break;case\"RANDOM\":o(String(Math.floor(Math.random()*32768)));break;default:{let n=parseInt(t.name,10),u,A=Number.isFinite(n);if(A?n>=0&&n<e.args.length&&(u=e.args[n]):Object.hasOwn(r.variables,t.name)?u=r.variables[t.name]:Object.hasOwn(r.environment,t.name)&&(u=r.environment[t.name]),typeof u<\"u\"&&t.alternativeValue?u=(await Fd(t.alternativeValue,e,r)).join(\" \"):typeof u>\"u\"&&(t.defaultValue?u=(await Fd(t.defaultValue,e,r)).join(\" \"):t.alternativeValue&&(u=\"\")),typeof u>\"u\")throw A?new ll(`Unbound argument #${n}`):new ll(`Unbound variable \"${t.name}\"`);if(t.quoted)o(u);else{let p=Mb(u);for(let E=0;E<p.length-1;++E)a(p[E]);let h=p[p.length-1];typeof h<\"u\"&&o(h)}}break}}async function Q1(t,e,r){if(t.type===\"number\"){if(Number.isInteger(t.value))return t.value;throw new Error(`Invalid number: \"${t.value}\", only integers are allowed`)}else if(t.type===\"variable\"){let o=[];await uce({...t,quoted:!0},e,r,n=>o.push(n));let a=Number(o.join(\" \"));return Number.isNaN(a)?Q1({type:\"variable\",name:o.join(\" \")},e,r):Q1({type:\"number\",value:a},e,r)}else return dot[t.type](await Q1(t.left,e,r),await Q1(t.right,e,r))}async function Fd(t,e,r){let o=new Map,a=[],n=[],u=E=>{n.push(E)},A=()=>{n.length>0&&a.push(n.join(\"\")),n=[]},p=E=>{u(E),A()},h=(E,I,v)=>{let x=JSON.stringify({type:E,fd:I}),C=o.get(x);typeof C>\"u\"&&o.set(x,C=[]),C.push(v)};for(let E of t){let I=!1;switch(E.type){case\"redirection\":{let v=await Fd(E.args,e,r);for(let x of v)h(E.subtype,E.fd,x)}break;case\"argument\":for(let v of E.segments)switch(v.type){case\"text\":u(v.text);break;case\"glob\":u(v.pattern),I=!0;break;case\"shell\":{let x=await got(v.shell,e,r);if(v.quoted)u(x);else{let C=Mb(x);for(let R=0;R<C.length-1;++R)p(C[R]);u(C[C.length-1])}}break;case\"variable\":await uce(v,e,r,u,p);break;case\"arithmetic\":u(String(await Q1(v.arithmetic,e,r)));break}break}if(A(),I){let v=a.pop();if(typeof v>\"u\")throw new Error(\"Assertion failed: Expected a glob pattern to have been set\");let x=await e.glob.match(v,{cwd:r.cwd,baseFs:e.baseFs});if(x.length===0){let C=oU(v)?\". Note: Brace expansion of arbitrary strings isn't currently supported. For more details, please read this issue: https://github.com/yarnpkg/berry/issues/22\":\"\";throw new ll(`No matches found: \"${v}\"${C}`)}for(let C of x.sort())p(C)}}if(o.size>0){let E=[];for(let[I,v]of o.entries())E.splice(E.length,0,I,String(v.length),...v);a.splice(0,0,\"__ysh_set_redirects\",...E,\"--\")}return a}function F1(t,e,r){e.builtins.has(t[0])||(t=[\"command\",...t]);let o=le.fromPortablePath(r.cwd),a=r.environment;typeof a.PWD<\"u\"&&(a={...a,PWD:o});let[n,...u]=t;if(n===\"command\")return ece(u[0],u.slice(1),e,{cwd:o,env:a});let A=e.builtins.get(n);if(typeof A>\"u\")throw new Error(`Assertion failed: A builtin should exist for \"${n}\"`);return tce(async({stdin:p,stdout:h,stderr:E})=>{let{stdin:I,stdout:v,stderr:x}=r;r.stdin=p,r.stdout=h,r.stderr=E;try{return await A(u,e,r)}finally{r.stdin=I,r.stdout=v,r.stderr=x}})}function mot(t,e,r){return o=>{let a=new cl.PassThrough,n=_b(t,e,Ub(r,{stdin:a}));return{stdin:a,promise:n}}}function yot(t,e,r){return o=>{let a=new cl.PassThrough,n=_b(t,e,r);return{stdin:a,promise:n}}}function sce(t,e,r,o){if(e.length===0)return t;{let a;do a=String(Math.random());while(Object.hasOwn(o.procedures,a));return o.procedures={...o.procedures},o.procedures[a]=t,F1([...e,\"__ysh_run_procedure\",a],r,o)}}async function oce(t,e,r){let o=t,a=null,n=null;for(;o;){let u=o.then?{...r}:r,A;switch(o.type){case\"command\":{let p=await Fd(o.args,e,r),h=await ice(o.envs,e,r);A=o.envs.length?F1(p,e,Ub(u,{environment:h})):F1(p,e,u)}break;case\"subshell\":{let p=await Fd(o.args,e,r),h=mot(o.subshell,e,u);A=sce(h,p,e,u)}break;case\"group\":{let p=await Fd(o.args,e,r),h=yot(o.group,e,u);A=sce(h,p,e,u)}break;case\"envs\":{let p=await ice(o.envs,e,r);u.environment={...u.environment,...p},A=F1([\"true\"],e,u)}break}if(typeof A>\"u\")throw new Error(\"Assertion failed: An action should have been generated\");if(a===null)n=Ob(A,{stdin:new Xl(u.stdin),stdout:new Xl(u.stdout),stderr:new Xl(u.stderr)});else{if(n===null)throw new Error(\"Assertion failed: The execution pipeline should have been setup\");switch(a){case\"|\":n=n.pipeTo(A,1);break;case\"|&\":n=n.pipeTo(A,3);break}}o.then?(a=o.then.type,o=o.then.chain):o=null}if(n===null)throw new Error(\"Assertion failed: The execution pipeline should have been setup\");return await n.run()}async function Eot(t,e,r,{background:o=!1}={}){function a(n){let u=[\"#2E86AB\",\"#A23B72\",\"#F18F01\",\"#C73E1D\",\"#CCE2A3\"],A=u[n%u.length];return ace.default.hex(A)}if(o){let n=r.nextBackgroundJobIndex++,u=a(n),A=`[${n}]`,p=u(A),{stdout:h,stderr:E}=rce(r,{prefix:p});return r.backgroundJobs.push(oce(t,e,Ub(r,{stdout:h,stderr:E})).catch(I=>E.write(`${I.message}\n`)).finally(()=>{r.stdout.isTTY&&r.stdout.write(`Job ${p}, '${u(uy(t))}' has ended\n`)})),0}return await oce(t,e,r)}async function Cot(t,e,r,{background:o=!1}={}){let a,n=A=>{a=A,r.variables[\"?\"]=String(A)},u=async A=>{try{return await Eot(A.chain,e,r,{background:o&&typeof A.then>\"u\"})}catch(p){if(!(p instanceof ll))throw p;return r.stderr.write(`${p.message}\n`),1}};for(n(await u(t));t.then;){if(r.exitCode!==null)return r.exitCode;switch(t.then.type){case\"&&\":a===0&&n(await u(t.then.line));break;case\"||\":a!==0&&n(await u(t.then.line));break;default:throw new Error(`Assertion failed: Unsupported command type: \"${t.then.type}\"`)}t=t.then.line}return a}async function _b(t,e,r){let o=r.backgroundJobs;r.backgroundJobs=[];let a=0;for(let{command:n,type:u}of t){if(a=await Cot(n,e,r,{background:u===\"&\"}),r.exitCode!==null)return r.exitCode;r.variables[\"?\"]=String(a)}return await Promise.all(r.backgroundJobs),r.backgroundJobs=o,a}function Ace(t){switch(t.type){case\"variable\":return t.name===\"@\"||t.name===\"#\"||t.name===\"*\"||Number.isFinite(parseInt(t.name,10))||\"defaultValue\"in t&&!!t.defaultValue&&t.defaultValue.some(e=>R1(e))||\"alternativeValue\"in t&&!!t.alternativeValue&&t.alternativeValue.some(e=>R1(e));case\"arithmetic\":return AU(t.arithmetic);case\"shell\":return fU(t.shell);default:return!1}}function R1(t){switch(t.type){case\"redirection\":return t.args.some(e=>R1(e));case\"argument\":return t.segments.some(e=>Ace(e));default:throw new Error(`Assertion failed: Unsupported argument type: \"${t.type}\"`)}}function AU(t){switch(t.type){case\"variable\":return Ace(t);case\"number\":return!1;default:return AU(t.left)||AU(t.right)}}function fU(t){return t.some(({command:e})=>{for(;e;){let r=e.chain;for(;r;){let o;switch(r.type){case\"subshell\":o=fU(r.subshell);break;case\"command\":o=r.envs.some(a=>a.args.some(n=>R1(n)))||r.args.some(a=>R1(a));break}if(o)return!0;if(!r.then)break;r=r.then.chain}if(!e.then)break;e=e.then.line}return!1})}async function TE(t,e=[],{baseFs:r=new Tn,builtins:o={},cwd:a=le.toPortablePath(process.cwd()),env:n=process.env,stdin:u=process.stdin,stdout:A=process.stdout,stderr:p=process.stderr,variables:h={},glob:E=Nb}={}){let I={};for(let[C,R]of Object.entries(n))typeof R<\"u\"&&(I[C]=R);let v=new Map(hot);for(let[C,R]of Object.entries(o))v.set(C,R);u===null&&(u=new cl.PassThrough,u.end());let x=LD(t,E);if(!fU(x)&&x.length>0&&e.length>0){let{command:C}=x[x.length-1];for(;C.then;)C=C.then.line;let R=C.chain;for(;R.then;)R=R.then.chain;R.type===\"command\"&&(R.args=R.args.concat(e.map(N=>({type:\"argument\",segments:[{type:\"text\",text:N}]}))))}return await _b(x,{args:e,baseFs:r,builtins:v,initialStdin:u,initialStdout:A,initialStderr:p,glob:E},{cwd:a,environment:I,exitCode:null,procedures:{},stdin:u,stdout:A,stderr:p,variables:Object.assign({},h,{[\"?\"]:0}),nextBackgroundJobIndex:1,backgroundJobs:[]})}var ace,lce,cl,cce,hot,dot,k1=Et(()=>{Pt();Nl();ace=$e(IL()),lce=ve(\"os\"),cl=ve(\"stream\"),cce=ve(\"timers/promises\");Yle();Wle();Jle();uU();uU();hot=new Map([[\"cd\",async([t=(0,lce.homedir)(),...e],r,o)=>{let a=z.resolve(o.cwd,le.toPortablePath(t));if(!(await r.baseFs.statPromise(a).catch(u=>{throw u.code===\"ENOENT\"?new ll(`cd: no such file or directory: ${t}`):u})).isDirectory())throw new ll(`cd: not a directory: ${t}`);return o.cwd=a,0}],[\"pwd\",async(t,e,r)=>(r.stdout.write(`${le.fromPortablePath(r.cwd)}\n`),0)],[\":\",async(t,e,r)=>0],[\"true\",async(t,e,r)=>0],[\"false\",async(t,e,r)=>1],[\"exit\",async([t,...e],r,o)=>o.exitCode=parseInt(t??o.variables[\"?\"],10)],[\"echo\",async(t,e,r)=>(r.stdout.write(`${t.join(\" \")}\n`),0)],[\"sleep\",async([t],e,r)=>{if(typeof t>\"u\")throw new ll(\"sleep: missing operand\");let o=Number(t);if(Number.isNaN(o))throw new ll(`sleep: invalid time interval '${t}'`);return await(0,cce.setTimeout)(1e3*o,0)}],[\"__ysh_run_procedure\",async(t,e,r)=>{let o=r.procedures[t[0]];return await Ob(o,{stdin:new Xl(r.stdin),stdout:new Xl(r.stdout),stderr:new Xl(r.stderr)}).run()}],[\"__ysh_set_redirects\",async(t,e,r)=>{let o=r.stdin,a=r.stdout,n=r.stderr,u=[],A=[],p=[],h=0;for(;t[h]!==\"--\";){let I=t[h++],{type:v,fd:x}=JSON.parse(I),C=V=>{switch(x){case null:case 0:u.push(V);break;default:throw new Error(`Unsupported file descriptor: \"${x}\"`)}},R=V=>{switch(x){case null:case 1:A.push(V);break;case 2:p.push(V);break;default:throw new Error(`Unsupported file descriptor: \"${x}\"`)}},N=Number(t[h++]),U=h+N;for(let V=h;V<U;++h,++V)switch(v){case\"<\":C(()=>e.baseFs.createReadStream(z.resolve(r.cwd,le.toPortablePath(t[V]))));break;case\"<<<\":C(()=>{let te=new cl.PassThrough;return process.nextTick(()=>{te.write(`${t[V]}\n`),te.end()}),te});break;case\"<&\":C(()=>nce(Number(t[V]),1,r));break;case\">\":case\">>\":{let te=z.resolve(r.cwd,le.toPortablePath(t[V]));R(te===\"/dev/null\"?new cl.Writable({autoDestroy:!0,emitClose:!0,write(ae,fe,ue){setImmediate(ue)}}):e.baseFs.createWriteStream(te,v===\">>\"?{flags:\"a\"}:void 0))}break;case\">&\":R(nce(Number(t[V]),2,r));break;default:throw new Error(`Assertion failed: Unsupported redirection type: \"${v}\"`)}}if(u.length>0){let I=new cl.PassThrough;o=I;let v=x=>{if(x===u.length)I.end();else{let C=u[x]();C.pipe(I,{end:!1}),C.on(\"end\",()=>{v(x+1)})}};v(0)}if(A.length>0){let I=new cl.PassThrough;a=I;for(let v of A)I.pipe(v)}if(p.length>0){let I=new cl.PassThrough;n=I;for(let v of p)I.pipe(v)}let E=await Ob(F1(t.slice(h+1),e,r),{stdin:new Xl(o),stdout:new Xl(a),stderr:new Xl(n)}).run();return await Promise.all(A.map(I=>new Promise((v,x)=>{I.on(\"error\",C=>{x(C)}),I.on(\"close\",()=>{v()}),I.end()}))),await Promise.all(p.map(I=>new Promise((v,x)=>{I.on(\"error\",C=>{x(C)}),I.on(\"close\",()=>{v()}),I.end()}))),E}]]);dot={addition:(t,e)=>t+e,subtraction:(t,e)=>t-e,multiplication:(t,e)=>t*e,division:(t,e)=>Math.trunc(t/e)}});var Hb=_((n4t,fce)=>{function wot(t,e){for(var r=-1,o=t==null?0:t.length,a=Array(o);++r<o;)a[r]=e(t[r],r,t);return a}fce.exports=wot});var yce=_((i4t,mce)=>{var pce=hd(),Iot=Hb(),Bot=ql(),vot=pE(),Dot=1/0,hce=pce?pce.prototype:void 0,gce=hce?hce.toString:void 0;function dce(t){if(typeof t==\"string\")return t;if(Bot(t))return Iot(t,dce)+\"\";if(vot(t))return gce?gce.call(t):\"\";var e=t+\"\";return e==\"0\"&&1/t==-Dot?\"-0\":e}mce.exports=dce});var L1=_((s4t,Ece)=>{var Pot=yce();function Sot(t){return t==null?\"\":Pot(t)}Ece.exports=Sot});var pU=_((o4t,Cce)=>{function bot(t,e,r){var o=-1,a=t.length;e<0&&(e=-e>a?0:a+e),r=r>a?a:r,r<0&&(r+=a),a=e>r?0:r-e>>>0,e>>>=0;for(var n=Array(a);++o<a;)n[o]=t[o+e];return n}Cce.exports=bot});var Ice=_((a4t,wce)=>{var xot=pU();function kot(t,e,r){var o=t.length;return r=r===void 0?o:r,!e&&r>=o?t:xot(t,e,r)}wce.exports=kot});var hU=_((l4t,Bce)=>{var Qot=\"\\\\ud800-\\\\udfff\",Fot=\"\\\\u0300-\\\\u036f\",Rot=\"\\\\ufe20-\\\\ufe2f\",Tot=\"\\\\u20d0-\\\\u20ff\",Lot=Fot+Rot+Tot,Not=\"\\\\ufe0e\\\\ufe0f\",Oot=\"\\\\u200d\",Mot=RegExp(\"[\"+Oot+Qot+Lot+Not+\"]\");function Uot(t){return Mot.test(t)}Bce.exports=Uot});var Dce=_((c4t,vce)=>{function _ot(t){return t.split(\"\")}vce.exports=_ot});var Rce=_((u4t,Fce)=>{var Pce=\"\\\\ud800-\\\\udfff\",Hot=\"\\\\u0300-\\\\u036f\",qot=\"\\\\ufe20-\\\\ufe2f\",Got=\"\\\\u20d0-\\\\u20ff\",jot=Hot+qot+Got,Yot=\"\\\\ufe0e\\\\ufe0f\",Wot=\"[\"+Pce+\"]\",gU=\"[\"+jot+\"]\",dU=\"\\\\ud83c[\\\\udffb-\\\\udfff]\",Kot=\"(?:\"+gU+\"|\"+dU+\")\",Sce=\"[^\"+Pce+\"]\",bce=\"(?:\\\\ud83c[\\\\udde6-\\\\uddff]){2}\",xce=\"[\\\\ud800-\\\\udbff][\\\\udc00-\\\\udfff]\",zot=\"\\\\u200d\",kce=Kot+\"?\",Qce=\"[\"+Yot+\"]?\",Vot=\"(?:\"+zot+\"(?:\"+[Sce,bce,xce].join(\"|\")+\")\"+Qce+kce+\")*\",Jot=Qce+kce+Vot,Xot=\"(?:\"+[Sce+gU+\"?\",gU,bce,xce,Wot].join(\"|\")+\")\",Zot=RegExp(dU+\"(?=\"+dU+\")|\"+Xot+Jot,\"g\");function $ot(t){return t.match(Zot)||[]}Fce.exports=$ot});var Lce=_((A4t,Tce)=>{var eat=Dce(),tat=hU(),rat=Rce();function nat(t){return tat(t)?rat(t):eat(t)}Tce.exports=nat});var Oce=_((f4t,Nce)=>{var iat=Ice(),sat=hU(),oat=Lce(),aat=L1();function lat(t){return function(e){e=aat(e);var r=sat(e)?oat(e):void 0,o=r?r[0]:e.charAt(0),a=r?iat(r,1).join(\"\"):e.slice(1);return o[t]()+a}}Nce.exports=lat});var Uce=_((p4t,Mce)=>{var cat=Oce(),uat=cat(\"toUpperCase\");Mce.exports=uat});var mU=_((h4t,_ce)=>{var Aat=L1(),fat=Uce();function pat(t){return fat(Aat(t).toLowerCase())}_ce.exports=pat});var Hce=_((g4t,qb)=>{function hat(){var t=0,e=1,r=2,o=3,a=4,n=5,u=6,A=7,p=8,h=9,E=10,I=11,v=12,x=13,C=14,R=15,N=16,U=17,V=0,te=1,ae=2,fe=3,ue=4;function me(g,Ee){return 55296<=g.charCodeAt(Ee)&&g.charCodeAt(Ee)<=56319&&56320<=g.charCodeAt(Ee+1)&&g.charCodeAt(Ee+1)<=57343}function he(g,Ee){Ee===void 0&&(Ee=0);var Pe=g.charCodeAt(Ee);if(55296<=Pe&&Pe<=56319&&Ee<g.length-1){var ce=Pe,ne=g.charCodeAt(Ee+1);return 56320<=ne&&ne<=57343?(ce-55296)*1024+(ne-56320)+65536:ce}if(56320<=Pe&&Pe<=57343&&Ee>=1){var ce=g.charCodeAt(Ee-1),ne=Pe;return 55296<=ce&&ce<=56319?(ce-55296)*1024+(ne-56320)+65536:ne}return Pe}function Be(g,Ee,Pe){var ce=[g].concat(Ee).concat([Pe]),ne=ce[ce.length-2],ee=Pe,Ie=ce.lastIndexOf(C);if(Ie>1&&ce.slice(1,Ie).every(function(H){return H==o})&&[o,x,U].indexOf(g)==-1)return ae;var Fe=ce.lastIndexOf(a);if(Fe>0&&ce.slice(1,Fe).every(function(H){return H==a})&&[v,a].indexOf(ne)==-1)return ce.filter(function(H){return H==a}).length%2==1?fe:ue;if(ne==t&&ee==e)return V;if(ne==r||ne==t||ne==e)return ee==C&&Ee.every(function(H){return H==o})?ae:te;if(ee==r||ee==t||ee==e)return te;if(ne==u&&(ee==u||ee==A||ee==h||ee==E))return V;if((ne==h||ne==A)&&(ee==A||ee==p))return V;if((ne==E||ne==p)&&ee==p)return V;if(ee==o||ee==R)return V;if(ee==n)return V;if(ne==v)return V;var At=ce.indexOf(o)!=-1?ce.lastIndexOf(o)-1:ce.length-2;return[x,U].indexOf(ce[At])!=-1&&ce.slice(At+1,-1).every(function(H){return H==o})&&ee==C||ne==R&&[N,U].indexOf(ee)!=-1?V:Ee.indexOf(a)!=-1?ae:ne==a&&ee==a?V:te}this.nextBreak=function(g,Ee){if(Ee===void 0&&(Ee=0),Ee<0)return 0;if(Ee>=g.length-1)return g.length;for(var Pe=we(he(g,Ee)),ce=[],ne=Ee+1;ne<g.length;ne++)if(!me(g,ne-1)){var ee=we(he(g,ne));if(Be(Pe,ce,ee))return ne;ce.push(ee)}return g.length},this.splitGraphemes=function(g){for(var Ee=[],Pe=0,ce;(ce=this.nextBreak(g,Pe))<g.length;)Ee.push(g.slice(Pe,ce)),Pe=ce;return Pe<g.length&&Ee.push(g.slice(Pe)),Ee},this.iterateGraphemes=function(g){var Ee=0,Pe={next:function(){var ce,ne;return(ne=this.nextBreak(g,Ee))<g.length?(ce=g.slice(Ee,ne),Ee=ne,{value:ce,done:!1}):Ee<g.length?(ce=g.slice(Ee),Ee=g.length,{value:ce,done:!1}):{value:void 0,done:!0}}.bind(this)};return typeof Symbol<\"u\"&&Symbol.iterator&&(Pe[Symbol.iterator]=function(){return Pe}),Pe},this.countGraphemes=function(g){for(var Ee=0,Pe=0,ce;(ce=this.nextBreak(g,Pe))<g.length;)Pe=ce,Ee++;return Pe<g.length&&Ee++,Ee};function we(g){return 1536<=g&&g<=1541||g==1757||g==1807||g==2274||g==3406||g==69821||70082<=g&&g<=70083||g==72250||72326<=g&&g<=72329||g==73030?v:g==13?t:g==10?e:0<=g&&g<=9||11<=g&&g<=12||14<=g&&g<=31||127<=g&&g<=159||g==173||g==1564||g==6158||g==8203||8206<=g&&g<=8207||g==8232||g==8233||8234<=g&&g<=8238||8288<=g&&g<=8292||g==8293||8294<=g&&g<=8303||55296<=g&&g<=57343||g==65279||65520<=g&&g<=65528||65529<=g&&g<=65531||113824<=g&&g<=113827||119155<=g&&g<=119162||g==917504||g==917505||917506<=g&&g<=917535||917632<=g&&g<=917759||918e3<=g&&g<=921599?r:768<=g&&g<=879||1155<=g&&g<=1159||1160<=g&&g<=1161||1425<=g&&g<=1469||g==1471||1473<=g&&g<=1474||1476<=g&&g<=1477||g==1479||1552<=g&&g<=1562||1611<=g&&g<=1631||g==1648||1750<=g&&g<=1756||1759<=g&&g<=1764||1767<=g&&g<=1768||1770<=g&&g<=1773||g==1809||1840<=g&&g<=1866||1958<=g&&g<=1968||2027<=g&&g<=2035||2070<=g&&g<=2073||2075<=g&&g<=2083||2085<=g&&g<=2087||2089<=g&&g<=2093||2137<=g&&g<=2139||2260<=g&&g<=2273||2275<=g&&g<=2306||g==2362||g==2364||2369<=g&&g<=2376||g==2381||2385<=g&&g<=2391||2402<=g&&g<=2403||g==2433||g==2492||g==2494||2497<=g&&g<=2500||g==2509||g==2519||2530<=g&&g<=2531||2561<=g&&g<=2562||g==2620||2625<=g&&g<=2626||2631<=g&&g<=2632||2635<=g&&g<=2637||g==2641||2672<=g&&g<=2673||g==2677||2689<=g&&g<=2690||g==2748||2753<=g&&g<=2757||2759<=g&&g<=2760||g==2765||2786<=g&&g<=2787||2810<=g&&g<=2815||g==2817||g==2876||g==2878||g==2879||2881<=g&&g<=2884||g==2893||g==2902||g==2903||2914<=g&&g<=2915||g==2946||g==3006||g==3008||g==3021||g==3031||g==3072||3134<=g&&g<=3136||3142<=g&&g<=3144||3146<=g&&g<=3149||3157<=g&&g<=3158||3170<=g&&g<=3171||g==3201||g==3260||g==3263||g==3266||g==3270||3276<=g&&g<=3277||3285<=g&&g<=3286||3298<=g&&g<=3299||3328<=g&&g<=3329||3387<=g&&g<=3388||g==3390||3393<=g&&g<=3396||g==3405||g==3415||3426<=g&&g<=3427||g==3530||g==3535||3538<=g&&g<=3540||g==3542||g==3551||g==3633||3636<=g&&g<=3642||3655<=g&&g<=3662||g==3761||3764<=g&&g<=3769||3771<=g&&g<=3772||3784<=g&&g<=3789||3864<=g&&g<=3865||g==3893||g==3895||g==3897||3953<=g&&g<=3966||3968<=g&&g<=3972||3974<=g&&g<=3975||3981<=g&&g<=3991||3993<=g&&g<=4028||g==4038||4141<=g&&g<=4144||4146<=g&&g<=4151||4153<=g&&g<=4154||4157<=g&&g<=4158||4184<=g&&g<=4185||4190<=g&&g<=4192||4209<=g&&g<=4212||g==4226||4229<=g&&g<=4230||g==4237||g==4253||4957<=g&&g<=4959||5906<=g&&g<=5908||5938<=g&&g<=5940||5970<=g&&g<=5971||6002<=g&&g<=6003||6068<=g&&g<=6069||6071<=g&&g<=6077||g==6086||6089<=g&&g<=6099||g==6109||6155<=g&&g<=6157||6277<=g&&g<=6278||g==6313||6432<=g&&g<=6434||6439<=g&&g<=6440||g==6450||6457<=g&&g<=6459||6679<=g&&g<=6680||g==6683||g==6742||6744<=g&&g<=6750||g==6752||g==6754||6757<=g&&g<=6764||6771<=g&&g<=6780||g==6783||6832<=g&&g<=6845||g==6846||6912<=g&&g<=6915||g==6964||6966<=g&&g<=6970||g==6972||g==6978||7019<=g&&g<=7027||7040<=g&&g<=7041||7074<=g&&g<=7077||7080<=g&&g<=7081||7083<=g&&g<=7085||g==7142||7144<=g&&g<=7145||g==7149||7151<=g&&g<=7153||7212<=g&&g<=7219||7222<=g&&g<=7223||7376<=g&&g<=7378||7380<=g&&g<=7392||7394<=g&&g<=7400||g==7405||g==7412||7416<=g&&g<=7417||7616<=g&&g<=7673||7675<=g&&g<=7679||g==8204||8400<=g&&g<=8412||8413<=g&&g<=8416||g==8417||8418<=g&&g<=8420||8421<=g&&g<=8432||11503<=g&&g<=11505||g==11647||11744<=g&&g<=11775||12330<=g&&g<=12333||12334<=g&&g<=12335||12441<=g&&g<=12442||g==42607||42608<=g&&g<=42610||42612<=g&&g<=42621||42654<=g&&g<=42655||42736<=g&&g<=42737||g==43010||g==43014||g==43019||43045<=g&&g<=43046||43204<=g&&g<=43205||43232<=g&&g<=43249||43302<=g&&g<=43309||43335<=g&&g<=43345||43392<=g&&g<=43394||g==43443||43446<=g&&g<=43449||g==43452||g==43493||43561<=g&&g<=43566||43569<=g&&g<=43570||43573<=g&&g<=43574||g==43587||g==43596||g==43644||g==43696||43698<=g&&g<=43700||43703<=g&&g<=43704||43710<=g&&g<=43711||g==43713||43756<=g&&g<=43757||g==43766||g==44005||g==44008||g==44013||g==64286||65024<=g&&g<=65039||65056<=g&&g<=65071||65438<=g&&g<=65439||g==66045||g==66272||66422<=g&&g<=66426||68097<=g&&g<=68099||68101<=g&&g<=68102||68108<=g&&g<=68111||68152<=g&&g<=68154||g==68159||68325<=g&&g<=68326||g==69633||69688<=g&&g<=69702||69759<=g&&g<=69761||69811<=g&&g<=69814||69817<=g&&g<=69818||69888<=g&&g<=69890||69927<=g&&g<=69931||69933<=g&&g<=69940||g==70003||70016<=g&&g<=70017||70070<=g&&g<=70078||70090<=g&&g<=70092||70191<=g&&g<=70193||g==70196||70198<=g&&g<=70199||g==70206||g==70367||70371<=g&&g<=70378||70400<=g&&g<=70401||g==70460||g==70462||g==70464||g==70487||70502<=g&&g<=70508||70512<=g&&g<=70516||70712<=g&&g<=70719||70722<=g&&g<=70724||g==70726||g==70832||70835<=g&&g<=70840||g==70842||g==70845||70847<=g&&g<=70848||70850<=g&&g<=70851||g==71087||71090<=g&&g<=71093||71100<=g&&g<=71101||71103<=g&&g<=71104||71132<=g&&g<=71133||71219<=g&&g<=71226||g==71229||71231<=g&&g<=71232||g==71339||g==71341||71344<=g&&g<=71349||g==71351||71453<=g&&g<=71455||71458<=g&&g<=71461||71463<=g&&g<=71467||72193<=g&&g<=72198||72201<=g&&g<=72202||72243<=g&&g<=72248||72251<=g&&g<=72254||g==72263||72273<=g&&g<=72278||72281<=g&&g<=72283||72330<=g&&g<=72342||72344<=g&&g<=72345||72752<=g&&g<=72758||72760<=g&&g<=72765||g==72767||72850<=g&&g<=72871||72874<=g&&g<=72880||72882<=g&&g<=72883||72885<=g&&g<=72886||73009<=g&&g<=73014||g==73018||73020<=g&&g<=73021||73023<=g&&g<=73029||g==73031||92912<=g&&g<=92916||92976<=g&&g<=92982||94095<=g&&g<=94098||113821<=g&&g<=113822||g==119141||119143<=g&&g<=119145||119150<=g&&g<=119154||119163<=g&&g<=119170||119173<=g&&g<=119179||119210<=g&&g<=119213||119362<=g&&g<=119364||121344<=g&&g<=121398||121403<=g&&g<=121452||g==121461||g==121476||121499<=g&&g<=121503||121505<=g&&g<=121519||122880<=g&&g<=122886||122888<=g&&g<=122904||122907<=g&&g<=122913||122915<=g&&g<=122916||122918<=g&&g<=122922||125136<=g&&g<=125142||125252<=g&&g<=125258||917536<=g&&g<=917631||917760<=g&&g<=917999?o:127462<=g&&g<=127487?a:g==2307||g==2363||2366<=g&&g<=2368||2377<=g&&g<=2380||2382<=g&&g<=2383||2434<=g&&g<=2435||2495<=g&&g<=2496||2503<=g&&g<=2504||2507<=g&&g<=2508||g==2563||2622<=g&&g<=2624||g==2691||2750<=g&&g<=2752||g==2761||2763<=g&&g<=2764||2818<=g&&g<=2819||g==2880||2887<=g&&g<=2888||2891<=g&&g<=2892||g==3007||3009<=g&&g<=3010||3014<=g&&g<=3016||3018<=g&&g<=3020||3073<=g&&g<=3075||3137<=g&&g<=3140||3202<=g&&g<=3203||g==3262||3264<=g&&g<=3265||3267<=g&&g<=3268||3271<=g&&g<=3272||3274<=g&&g<=3275||3330<=g&&g<=3331||3391<=g&&g<=3392||3398<=g&&g<=3400||3402<=g&&g<=3404||3458<=g&&g<=3459||3536<=g&&g<=3537||3544<=g&&g<=3550||3570<=g&&g<=3571||g==3635||g==3763||3902<=g&&g<=3903||g==3967||g==4145||4155<=g&&g<=4156||4182<=g&&g<=4183||g==4228||g==6070||6078<=g&&g<=6085||6087<=g&&g<=6088||6435<=g&&g<=6438||6441<=g&&g<=6443||6448<=g&&g<=6449||6451<=g&&g<=6456||6681<=g&&g<=6682||g==6741||g==6743||6765<=g&&g<=6770||g==6916||g==6965||g==6971||6973<=g&&g<=6977||6979<=g&&g<=6980||g==7042||g==7073||7078<=g&&g<=7079||g==7082||g==7143||7146<=g&&g<=7148||g==7150||7154<=g&&g<=7155||7204<=g&&g<=7211||7220<=g&&g<=7221||g==7393||7410<=g&&g<=7411||g==7415||43043<=g&&g<=43044||g==43047||43136<=g&&g<=43137||43188<=g&&g<=43203||43346<=g&&g<=43347||g==43395||43444<=g&&g<=43445||43450<=g&&g<=43451||43453<=g&&g<=43456||43567<=g&&g<=43568||43571<=g&&g<=43572||g==43597||g==43755||43758<=g&&g<=43759||g==43765||44003<=g&&g<=44004||44006<=g&&g<=44007||44009<=g&&g<=44010||g==44012||g==69632||g==69634||g==69762||69808<=g&&g<=69810||69815<=g&&g<=69816||g==69932||g==70018||70067<=g&&g<=70069||70079<=g&&g<=70080||70188<=g&&g<=70190||70194<=g&&g<=70195||g==70197||70368<=g&&g<=70370||70402<=g&&g<=70403||g==70463||70465<=g&&g<=70468||70471<=g&&g<=70472||70475<=g&&g<=70477||70498<=g&&g<=70499||70709<=g&&g<=70711||70720<=g&&g<=70721||g==70725||70833<=g&&g<=70834||g==70841||70843<=g&&g<=70844||g==70846||g==70849||71088<=g&&g<=71089||71096<=g&&g<=71099||g==71102||71216<=g&&g<=71218||71227<=g&&g<=71228||g==71230||g==71340||71342<=g&&g<=71343||g==71350||71456<=g&&g<=71457||g==71462||72199<=g&&g<=72200||g==72249||72279<=g&&g<=72280||g==72343||g==72751||g==72766||g==72873||g==72881||g==72884||94033<=g&&g<=94078||g==119142||g==119149?n:4352<=g&&g<=4447||43360<=g&&g<=43388?u:4448<=g&&g<=4519||55216<=g&&g<=55238?A:4520<=g&&g<=4607||55243<=g&&g<=55291?p:g==44032||g==44060||g==44088||g==44116||g==44144||g==44172||g==44200||g==44228||g==44256||g==44284||g==44312||g==44340||g==44368||g==44396||g==44424||g==44452||g==44480||g==44508||g==44536||g==44564||g==44592||g==44620||g==44648||g==44676||g==44704||g==44732||g==44760||g==44788||g==44816||g==44844||g==44872||g==44900||g==44928||g==44956||g==44984||g==45012||g==45040||g==45068||g==45096||g==45124||g==45152||g==45180||g==45208||g==45236||g==45264||g==45292||g==45320||g==45348||g==45376||g==45404||g==45432||g==45460||g==45488||g==45516||g==45544||g==45572||g==45600||g==45628||g==45656||g==45684||g==45712||g==45740||g==45768||g==45796||g==45824||g==45852||g==45880||g==45908||g==45936||g==45964||g==45992||g==46020||g==46048||g==46076||g==46104||g==46132||g==46160||g==46188||g==46216||g==46244||g==46272||g==46300||g==46328||g==46356||g==46384||g==46412||g==46440||g==46468||g==46496||g==46524||g==46552||g==46580||g==46608||g==46636||g==46664||g==46692||g==46720||g==46748||g==46776||g==46804||g==46832||g==46860||g==46888||g==46916||g==46944||g==46972||g==47e3||g==47028||g==47056||g==47084||g==47112||g==47140||g==47168||g==47196||g==47224||g==47252||g==47280||g==47308||g==47336||g==47364||g==47392||g==47420||g==47448||g==47476||g==47504||g==47532||g==47560||g==47588||g==47616||g==47644||g==47672||g==47700||g==47728||g==47756||g==47784||g==47812||g==47840||g==47868||g==47896||g==47924||g==47952||g==47980||g==48008||g==48036||g==48064||g==48092||g==48120||g==48148||g==48176||g==48204||g==48232||g==48260||g==48288||g==48316||g==48344||g==48372||g==48400||g==48428||g==48456||g==48484||g==48512||g==48540||g==48568||g==48596||g==48624||g==48652||g==48680||g==48708||g==48736||g==48764||g==48792||g==48820||g==48848||g==48876||g==48904||g==48932||g==48960||g==48988||g==49016||g==49044||g==49072||g==49100||g==49128||g==49156||g==49184||g==49212||g==49240||g==49268||g==49296||g==49324||g==49352||g==49380||g==49408||g==49436||g==49464||g==49492||g==49520||g==49548||g==49576||g==49604||g==49632||g==49660||g==49688||g==49716||g==49744||g==49772||g==49800||g==49828||g==49856||g==49884||g==49912||g==49940||g==49968||g==49996||g==50024||g==50052||g==50080||g==50108||g==50136||g==50164||g==50192||g==50220||g==50248||g==50276||g==50304||g==50332||g==50360||g==50388||g==50416||g==50444||g==50472||g==50500||g==50528||g==50556||g==50584||g==50612||g==50640||g==50668||g==50696||g==50724||g==50752||g==50780||g==50808||g==50836||g==50864||g==50892||g==50920||g==50948||g==50976||g==51004||g==51032||g==51060||g==51088||g==51116||g==51144||g==51172||g==51200||g==51228||g==51256||g==51284||g==51312||g==51340||g==51368||g==51396||g==51424||g==51452||g==51480||g==51508||g==51536||g==51564||g==51592||g==51620||g==51648||g==51676||g==51704||g==51732||g==51760||g==51788||g==51816||g==51844||g==51872||g==51900||g==51928||g==51956||g==51984||g==52012||g==52040||g==52068||g==52096||g==52124||g==52152||g==52180||g==52208||g==52236||g==52264||g==52292||g==52320||g==52348||g==52376||g==52404||g==52432||g==52460||g==52488||g==52516||g==52544||g==52572||g==52600||g==52628||g==52656||g==52684||g==52712||g==52740||g==52768||g==52796||g==52824||g==52852||g==52880||g==52908||g==52936||g==52964||g==52992||g==53020||g==53048||g==53076||g==53104||g==53132||g==53160||g==53188||g==53216||g==53244||g==53272||g==53300||g==53328||g==53356||g==53384||g==53412||g==53440||g==53468||g==53496||g==53524||g==53552||g==53580||g==53608||g==53636||g==53664||g==53692||g==53720||g==53748||g==53776||g==53804||g==53832||g==53860||g==53888||g==53916||g==53944||g==53972||g==54e3||g==54028||g==54056||g==54084||g==54112||g==54140||g==54168||g==54196||g==54224||g==54252||g==54280||g==54308||g==54336||g==54364||g==54392||g==54420||g==54448||g==54476||g==54504||g==54532||g==54560||g==54588||g==54616||g==54644||g==54672||g==54700||g==54728||g==54756||g==54784||g==54812||g==54840||g==54868||g==54896||g==54924||g==54952||g==54980||g==55008||g==55036||g==55064||g==55092||g==55120||g==55148||g==55176?h:44033<=g&&g<=44059||44061<=g&&g<=44087||44089<=g&&g<=44115||44117<=g&&g<=44143||44145<=g&&g<=44171||44173<=g&&g<=44199||44201<=g&&g<=44227||44229<=g&&g<=44255||44257<=g&&g<=44283||44285<=g&&g<=44311||44313<=g&&g<=44339||44341<=g&&g<=44367||44369<=g&&g<=44395||44397<=g&&g<=44423||44425<=g&&g<=44451||44453<=g&&g<=44479||44481<=g&&g<=44507||44509<=g&&g<=44535||44537<=g&&g<=44563||44565<=g&&g<=44591||44593<=g&&g<=44619||44621<=g&&g<=44647||44649<=g&&g<=44675||44677<=g&&g<=44703||44705<=g&&g<=44731||44733<=g&&g<=44759||44761<=g&&g<=44787||44789<=g&&g<=44815||44817<=g&&g<=44843||44845<=g&&g<=44871||44873<=g&&g<=44899||44901<=g&&g<=44927||44929<=g&&g<=44955||44957<=g&&g<=44983||44985<=g&&g<=45011||45013<=g&&g<=45039||45041<=g&&g<=45067||45069<=g&&g<=45095||45097<=g&&g<=45123||45125<=g&&g<=45151||45153<=g&&g<=45179||45181<=g&&g<=45207||45209<=g&&g<=45235||45237<=g&&g<=45263||45265<=g&&g<=45291||45293<=g&&g<=45319||45321<=g&&g<=45347||45349<=g&&g<=45375||45377<=g&&g<=45403||45405<=g&&g<=45431||45433<=g&&g<=45459||45461<=g&&g<=45487||45489<=g&&g<=45515||45517<=g&&g<=45543||45545<=g&&g<=45571||45573<=g&&g<=45599||45601<=g&&g<=45627||45629<=g&&g<=45655||45657<=g&&g<=45683||45685<=g&&g<=45711||45713<=g&&g<=45739||45741<=g&&g<=45767||45769<=g&&g<=45795||45797<=g&&g<=45823||45825<=g&&g<=45851||45853<=g&&g<=45879||45881<=g&&g<=45907||45909<=g&&g<=45935||45937<=g&&g<=45963||45965<=g&&g<=45991||45993<=g&&g<=46019||46021<=g&&g<=46047||46049<=g&&g<=46075||46077<=g&&g<=46103||46105<=g&&g<=46131||46133<=g&&g<=46159||46161<=g&&g<=46187||46189<=g&&g<=46215||46217<=g&&g<=46243||46245<=g&&g<=46271||46273<=g&&g<=46299||46301<=g&&g<=46327||46329<=g&&g<=46355||46357<=g&&g<=46383||46385<=g&&g<=46411||46413<=g&&g<=46439||46441<=g&&g<=46467||46469<=g&&g<=46495||46497<=g&&g<=46523||46525<=g&&g<=46551||46553<=g&&g<=46579||46581<=g&&g<=46607||46609<=g&&g<=46635||46637<=g&&g<=46663||46665<=g&&g<=46691||46693<=g&&g<=46719||46721<=g&&g<=46747||46749<=g&&g<=46775||46777<=g&&g<=46803||46805<=g&&g<=46831||46833<=g&&g<=46859||46861<=g&&g<=46887||46889<=g&&g<=46915||46917<=g&&g<=46943||46945<=g&&g<=46971||46973<=g&&g<=46999||47001<=g&&g<=47027||47029<=g&&g<=47055||47057<=g&&g<=47083||47085<=g&&g<=47111||47113<=g&&g<=47139||47141<=g&&g<=47167||47169<=g&&g<=47195||47197<=g&&g<=47223||47225<=g&&g<=47251||47253<=g&&g<=47279||47281<=g&&g<=47307||47309<=g&&g<=47335||47337<=g&&g<=47363||47365<=g&&g<=47391||47393<=g&&g<=47419||47421<=g&&g<=47447||47449<=g&&g<=47475||47477<=g&&g<=47503||47505<=g&&g<=47531||47533<=g&&g<=47559||47561<=g&&g<=47587||47589<=g&&g<=47615||47617<=g&&g<=47643||47645<=g&&g<=47671||47673<=g&&g<=47699||47701<=g&&g<=47727||47729<=g&&g<=47755||47757<=g&&g<=47783||47785<=g&&g<=47811||47813<=g&&g<=47839||47841<=g&&g<=47867||47869<=g&&g<=47895||47897<=g&&g<=47923||47925<=g&&g<=47951||47953<=g&&g<=47979||47981<=g&&g<=48007||48009<=g&&g<=48035||48037<=g&&g<=48063||48065<=g&&g<=48091||48093<=g&&g<=48119||48121<=g&&g<=48147||48149<=g&&g<=48175||48177<=g&&g<=48203||48205<=g&&g<=48231||48233<=g&&g<=48259||48261<=g&&g<=48287||48289<=g&&g<=48315||48317<=g&&g<=48343||48345<=g&&g<=48371||48373<=g&&g<=48399||48401<=g&&g<=48427||48429<=g&&g<=48455||48457<=g&&g<=48483||48485<=g&&g<=48511||48513<=g&&g<=48539||48541<=g&&g<=48567||48569<=g&&g<=48595||48597<=g&&g<=48623||48625<=g&&g<=48651||48653<=g&&g<=48679||48681<=g&&g<=48707||48709<=g&&g<=48735||48737<=g&&g<=48763||48765<=g&&g<=48791||48793<=g&&g<=48819||48821<=g&&g<=48847||48849<=g&&g<=48875||48877<=g&&g<=48903||48905<=g&&g<=48931||48933<=g&&g<=48959||48961<=g&&g<=48987||48989<=g&&g<=49015||49017<=g&&g<=49043||49045<=g&&g<=49071||49073<=g&&g<=49099||49101<=g&&g<=49127||49129<=g&&g<=49155||49157<=g&&g<=49183||49185<=g&&g<=49211||49213<=g&&g<=49239||49241<=g&&g<=49267||49269<=g&&g<=49295||49297<=g&&g<=49323||49325<=g&&g<=49351||49353<=g&&g<=49379||49381<=g&&g<=49407||49409<=g&&g<=49435||49437<=g&&g<=49463||49465<=g&&g<=49491||49493<=g&&g<=49519||49521<=g&&g<=49547||49549<=g&&g<=49575||49577<=g&&g<=49603||49605<=g&&g<=49631||49633<=g&&g<=49659||49661<=g&&g<=49687||49689<=g&&g<=49715||49717<=g&&g<=49743||49745<=g&&g<=49771||49773<=g&&g<=49799||49801<=g&&g<=49827||49829<=g&&g<=49855||49857<=g&&g<=49883||49885<=g&&g<=49911||49913<=g&&g<=49939||49941<=g&&g<=49967||49969<=g&&g<=49995||49997<=g&&g<=50023||50025<=g&&g<=50051||50053<=g&&g<=50079||50081<=g&&g<=50107||50109<=g&&g<=50135||50137<=g&&g<=50163||50165<=g&&g<=50191||50193<=g&&g<=50219||50221<=g&&g<=50247||50249<=g&&g<=50275||50277<=g&&g<=50303||50305<=g&&g<=50331||50333<=g&&g<=50359||50361<=g&&g<=50387||50389<=g&&g<=50415||50417<=g&&g<=50443||50445<=g&&g<=50471||50473<=g&&g<=50499||50501<=g&&g<=50527||50529<=g&&g<=50555||50557<=g&&g<=50583||50585<=g&&g<=50611||50613<=g&&g<=50639||50641<=g&&g<=50667||50669<=g&&g<=50695||50697<=g&&g<=50723||50725<=g&&g<=50751||50753<=g&&g<=50779||50781<=g&&g<=50807||50809<=g&&g<=50835||50837<=g&&g<=50863||50865<=g&&g<=50891||50893<=g&&g<=50919||50921<=g&&g<=50947||50949<=g&&g<=50975||50977<=g&&g<=51003||51005<=g&&g<=51031||51033<=g&&g<=51059||51061<=g&&g<=51087||51089<=g&&g<=51115||51117<=g&&g<=51143||51145<=g&&g<=51171||51173<=g&&g<=51199||51201<=g&&g<=51227||51229<=g&&g<=51255||51257<=g&&g<=51283||51285<=g&&g<=51311||51313<=g&&g<=51339||51341<=g&&g<=51367||51369<=g&&g<=51395||51397<=g&&g<=51423||51425<=g&&g<=51451||51453<=g&&g<=51479||51481<=g&&g<=51507||51509<=g&&g<=51535||51537<=g&&g<=51563||51565<=g&&g<=51591||51593<=g&&g<=51619||51621<=g&&g<=51647||51649<=g&&g<=51675||51677<=g&&g<=51703||51705<=g&&g<=51731||51733<=g&&g<=51759||51761<=g&&g<=51787||51789<=g&&g<=51815||51817<=g&&g<=51843||51845<=g&&g<=51871||51873<=g&&g<=51899||51901<=g&&g<=51927||51929<=g&&g<=51955||51957<=g&&g<=51983||51985<=g&&g<=52011||52013<=g&&g<=52039||52041<=g&&g<=52067||52069<=g&&g<=52095||52097<=g&&g<=52123||52125<=g&&g<=52151||52153<=g&&g<=52179||52181<=g&&g<=52207||52209<=g&&g<=52235||52237<=g&&g<=52263||52265<=g&&g<=52291||52293<=g&&g<=52319||52321<=g&&g<=52347||52349<=g&&g<=52375||52377<=g&&g<=52403||52405<=g&&g<=52431||52433<=g&&g<=52459||52461<=g&&g<=52487||52489<=g&&g<=52515||52517<=g&&g<=52543||52545<=g&&g<=52571||52573<=g&&g<=52599||52601<=g&&g<=52627||52629<=g&&g<=52655||52657<=g&&g<=52683||52685<=g&&g<=52711||52713<=g&&g<=52739||52741<=g&&g<=52767||52769<=g&&g<=52795||52797<=g&&g<=52823||52825<=g&&g<=52851||52853<=g&&g<=52879||52881<=g&&g<=52907||52909<=g&&g<=52935||52937<=g&&g<=52963||52965<=g&&g<=52991||52993<=g&&g<=53019||53021<=g&&g<=53047||53049<=g&&g<=53075||53077<=g&&g<=53103||53105<=g&&g<=53131||53133<=g&&g<=53159||53161<=g&&g<=53187||53189<=g&&g<=53215||53217<=g&&g<=53243||53245<=g&&g<=53271||53273<=g&&g<=53299||53301<=g&&g<=53327||53329<=g&&g<=53355||53357<=g&&g<=53383||53385<=g&&g<=53411||53413<=g&&g<=53439||53441<=g&&g<=53467||53469<=g&&g<=53495||53497<=g&&g<=53523||53525<=g&&g<=53551||53553<=g&&g<=53579||53581<=g&&g<=53607||53609<=g&&g<=53635||53637<=g&&g<=53663||53665<=g&&g<=53691||53693<=g&&g<=53719||53721<=g&&g<=53747||53749<=g&&g<=53775||53777<=g&&g<=53803||53805<=g&&g<=53831||53833<=g&&g<=53859||53861<=g&&g<=53887||53889<=g&&g<=53915||53917<=g&&g<=53943||53945<=g&&g<=53971||53973<=g&&g<=53999||54001<=g&&g<=54027||54029<=g&&g<=54055||54057<=g&&g<=54083||54085<=g&&g<=54111||54113<=g&&g<=54139||54141<=g&&g<=54167||54169<=g&&g<=54195||54197<=g&&g<=54223||54225<=g&&g<=54251||54253<=g&&g<=54279||54281<=g&&g<=54307||54309<=g&&g<=54335||54337<=g&&g<=54363||54365<=g&&g<=54391||54393<=g&&g<=54419||54421<=g&&g<=54447||54449<=g&&g<=54475||54477<=g&&g<=54503||54505<=g&&g<=54531||54533<=g&&g<=54559||54561<=g&&g<=54587||54589<=g&&g<=54615||54617<=g&&g<=54643||54645<=g&&g<=54671||54673<=g&&g<=54699||54701<=g&&g<=54727||54729<=g&&g<=54755||54757<=g&&g<=54783||54785<=g&&g<=54811||54813<=g&&g<=54839||54841<=g&&g<=54867||54869<=g&&g<=54895||54897<=g&&g<=54923||54925<=g&&g<=54951||54953<=g&&g<=54979||54981<=g&&g<=55007||55009<=g&&g<=55035||55037<=g&&g<=55063||55065<=g&&g<=55091||55093<=g&&g<=55119||55121<=g&&g<=55147||55149<=g&&g<=55175||55177<=g&&g<=55203?E:g==9757||g==9977||9994<=g&&g<=9997||g==127877||127938<=g&&g<=127940||g==127943||127946<=g&&g<=127948||128066<=g&&g<=128067||128070<=g&&g<=128080||g==128110||128112<=g&&g<=128120||g==128124||128129<=g&&g<=128131||128133<=g&&g<=128135||g==128170||128372<=g&&g<=128373||g==128378||g==128400||128405<=g&&g<=128406||128581<=g&&g<=128583||128587<=g&&g<=128591||g==128675||128692<=g&&g<=128694||g==128704||g==128716||129304<=g&&g<=129308||129310<=g&&g<=129311||g==129318||129328<=g&&g<=129337||129341<=g&&g<=129342||129489<=g&&g<=129501?x:127995<=g&&g<=127999?C:g==8205?R:g==9792||g==9794||9877<=g&&g<=9878||g==9992||g==10084||g==127752||g==127806||g==127859||g==127891||g==127908||g==127912||g==127979||g==127981||g==128139||128187<=g&&g<=128188||g==128295||g==128300||g==128488||g==128640||g==128658?N:128102<=g&&g<=128105?U:I}return this}typeof qb<\"u\"&&qb.exports&&(qb.exports=hat)});var Gce=_((d4t,qce)=>{var gat=/^(.*?)(\\x1b\\[[^m]+m|\\x1b\\]8;;.*?(\\x1b\\\\|\\u0007))/,Gb;function dat(){if(Gb)return Gb;if(typeof Intl.Segmenter<\"u\"){let t=new Intl.Segmenter(\"en\",{granularity:\"grapheme\"});return Gb=e=>Array.from(t.segment(e),({segment:r})=>r)}else{let t=Hce(),e=new t;return Gb=r=>e.splitGraphemes(r)}}qce.exports=(t,e=0,r=t.length)=>{if(e<0||r<0)throw new RangeError(\"Negative indices aren't supported by this implementation\");let o=r-e,a=\"\",n=0,u=0;for(;t.length>0;){let A=t.match(gat)||[t,t,void 0],p=dat()(A[1]),h=Math.min(e-n,p.length);p=p.slice(h);let E=Math.min(o-u,p.length);a+=p.slice(0,E).join(\"\"),n+=h,u+=E,typeof A[2]<\"u\"&&(a+=A[2]),t=t.slice(A[0].length)}return a}});var rn,N1=Et(()=>{rn=process.env.YARN_IS_TEST_ENV?\"0.0.0\":\"4.2.2\"});function Vce(t,{configuration:e,json:r}){if(!e.get(\"enableMessageNames\"))return\"\";let a=Ku(t===null?0:t);return!r&&t===null?Ut(e,a,\"grey\"):a}function yU(t,{configuration:e,json:r}){let o=Vce(t,{configuration:e,json:r});if(!o||t===null||t===0)return o;let a=wr[t],n=`https://yarnpkg.com/advanced/error-codes#${o}---${a}`.toLowerCase();return Zy(e,o,n)}async function NE({configuration:t,stdout:e,forceError:r},o){let a=await Lt.start({configuration:t,stdout:e,includeFooter:!1},async n=>{let u=!1,A=!1;for(let p of o)typeof p.option<\"u\"&&(p.error||r?(A=!0,n.reportError(50,p.message)):(u=!0,n.reportWarning(50,p.message)),p.callback?.());u&&!A&&n.reportSeparator()});return a.hasErrors()?a.exitCode():null}var Kce,jb,mat,jce,Yce,fh,zce,Wce,yat,Eat,Yb,Cat,Lt,O1=Et(()=>{Kce=$e(Gce()),jb=$e(rd());fP();Wl();N1();jl();mat=\"\\xB7\",jce=[\"\\u280B\",\"\\u2819\",\"\\u2839\",\"\\u2838\",\"\\u283C\",\"\\u2834\",\"\\u2826\",\"\\u2827\",\"\\u2807\",\"\\u280F\"],Yce=80,fh=jb.default.GITHUB_ACTIONS?{start:t=>`::group::${t}\n`,end:t=>`::endgroup::\n`}:jb.default.TRAVIS?{start:t=>`travis_fold:start:${t}\n`,end:t=>`travis_fold:end:${t}\n`}:jb.default.GITLAB?{start:t=>`section_start:${Math.floor(Date.now()/1e3)}:${t.toLowerCase().replace(/\\W+/g,\"_\")}[collapsed=true]\\r\\x1B[0K${t}\n`,end:t=>`section_end:${Math.floor(Date.now()/1e3)}:${t.toLowerCase().replace(/\\W+/g,\"_\")}\\r\\x1B[0K`}:null,zce=fh!==null,Wce=new Date,yat=[\"iTerm.app\",\"Apple_Terminal\",\"WarpTerminal\",\"vscode\"].includes(process.env.TERM_PROGRAM)||!!process.env.WT_SESSION,Eat=t=>t,Yb=Eat({patrick:{date:[17,3],chars:[\"\\u{1F340}\",\"\\u{1F331}\"],size:40},simba:{date:[19,7],chars:[\"\\u{1F981}\",\"\\u{1F334}\"],size:40},jack:{date:[31,10],chars:[\"\\u{1F383}\",\"\\u{1F987}\"],size:40},hogsfather:{date:[31,12],chars:[\"\\u{1F389}\",\"\\u{1F384}\"],size:40},default:{chars:[\"=\",\"-\"],size:80}}),Cat=yat&&Object.keys(Yb).find(t=>{let e=Yb[t];return!(e.date&&(e.date[0]!==Wce.getDate()||e.date[1]!==Wce.getMonth()+1))})||\"default\";Lt=class extends Xs{constructor({configuration:r,stdout:o,json:a=!1,forceSectionAlignment:n=!1,includeNames:u=!0,includePrefix:A=!0,includeFooter:p=!0,includeLogs:h=!a,includeInfos:E=h,includeWarnings:I=h}){super();this.uncommitted=new Set;this.warningCount=0;this.errorCount=0;this.timerFooter=[];this.startTime=Date.now();this.indent=0;this.level=0;this.progress=new Map;this.progressTime=0;this.progressFrame=0;this.progressTimeout=null;this.progressStyle=null;this.progressMaxScaledSize=null;if(XI(this,{configuration:r}),this.configuration=r,this.forceSectionAlignment=n,this.includeNames=u,this.includePrefix=A,this.includeFooter=p,this.includeInfos=E,this.includeWarnings=I,this.json=a,this.stdout=o,r.get(\"enableProgressBars\")&&!a&&o.isTTY&&o.columns>22){let v=r.get(\"progressBarStyle\")||Cat;if(!Object.hasOwn(Yb,v))throw new Error(\"Assertion failed: Invalid progress bar style\");this.progressStyle=Yb[v];let x=Math.min(this.getRecommendedLength(),80);this.progressMaxScaledSize=Math.floor(this.progressStyle.size*x/80)}}static async start(r,o){let a=new this(r),n=process.emitWarning;process.emitWarning=(u,A)=>{if(typeof u!=\"string\"){let h=u;u=h.message,A=A??h.name}let p=typeof A<\"u\"?`${A}: ${u}`:u;a.reportWarning(0,p)},r.includeVersion&&a.reportInfo(0,Ed(r.configuration,`Yarn ${rn}`,2));try{await o(a)}catch(u){a.reportExceptionOnce(u)}finally{await a.finalize(),process.emitWarning=n}return a}hasErrors(){return this.errorCount>0}exitCode(){return this.hasErrors()?1:0}getRecommendedLength(){let o=this.progressStyle!==null?this.stdout.columns-1:super.getRecommendedLength();return Math.max(40,o-12-this.indent*2)}startSectionSync({reportHeader:r,reportFooter:o,skipIfEmpty:a},n){let u={committed:!1,action:()=>{r?.()}};a?this.uncommitted.add(u):(u.action(),u.committed=!0);let A=Date.now();try{return n()}catch(p){throw this.reportExceptionOnce(p),p}finally{let p=Date.now();this.uncommitted.delete(u),u.committed&&o?.(p-A)}}async startSectionPromise({reportHeader:r,reportFooter:o,skipIfEmpty:a},n){let u={committed:!1,action:()=>{r?.()}};a?this.uncommitted.add(u):(u.action(),u.committed=!0);let A=Date.now();try{return await n()}catch(p){throw this.reportExceptionOnce(p),p}finally{let p=Date.now();this.uncommitted.delete(u),u.committed&&o?.(p-A)}}startTimerImpl(r,o,a){return{cb:typeof o==\"function\"?o:a,reportHeader:()=>{this.level+=1,this.reportInfo(null,`\\u250C ${r}`),this.indent+=1,fh!==null&&!this.json&&this.includeInfos&&this.stdout.write(fh.start(r))},reportFooter:A=>{if(this.indent-=1,fh!==null&&!this.json&&this.includeInfos){this.stdout.write(fh.end(r));for(let p of this.timerFooter)p()}this.configuration.get(\"enableTimers\")&&A>200?this.reportInfo(null,`\\u2514 Completed in ${Ut(this.configuration,A,yt.DURATION)}`):this.reportInfo(null,\"\\u2514 Completed\"),this.level-=1},skipIfEmpty:(typeof o==\"function\"?{}:o).skipIfEmpty}}startTimerSync(r,o,a){let{cb:n,...u}=this.startTimerImpl(r,o,a);return this.startSectionSync(u,n)}async startTimerPromise(r,o,a){let{cb:n,...u}=this.startTimerImpl(r,o,a);return this.startSectionPromise(u,n)}reportSeparator(){this.indent===0?this.writeLine(\"\"):this.reportInfo(null,\"\")}reportInfo(r,o){if(!this.includeInfos)return;this.commit();let a=this.formatNameWithHyperlink(r),n=a?`${a}: `:\"\",u=`${this.formatPrefix(n,\"blueBright\")}${o}`;this.json?this.reportJson({type:\"info\",name:r,displayName:this.formatName(r),indent:this.formatIndent(),data:o}):this.writeLine(u)}reportWarning(r,o){if(this.warningCount+=1,!this.includeWarnings)return;this.commit();let a=this.formatNameWithHyperlink(r),n=a?`${a}: `:\"\";this.json?this.reportJson({type:\"warning\",name:r,displayName:this.formatName(r),indent:this.formatIndent(),data:o}):this.writeLine(`${this.formatPrefix(n,\"yellowBright\")}${o}`)}reportError(r,o){this.errorCount+=1,this.timerFooter.push(()=>this.reportErrorImpl(r,o)),this.reportErrorImpl(r,o)}reportErrorImpl(r,o){this.commit();let a=this.formatNameWithHyperlink(r),n=a?`${a}: `:\"\";this.json?this.reportJson({type:\"error\",name:r,displayName:this.formatName(r),indent:this.formatIndent(),data:o}):this.writeLine(`${this.formatPrefix(n,\"redBright\")}${o}`,{truncate:!1})}reportFold(r,o){if(!fh)return;let a=`${fh.start(r)}${o}${fh.end(r)}`;this.timerFooter.push(()=>this.stdout.write(a))}reportProgress(r){if(this.progressStyle===null)return{...Promise.resolve(),stop:()=>{}};if(r.hasProgress&&r.hasTitle)throw new Error(\"Unimplemented: Progress bars can't have both progress and titles.\");let o=!1,a=Promise.resolve().then(async()=>{let u={progress:r.hasProgress?0:void 0,title:r.hasTitle?\"\":void 0};this.progress.set(r,{definition:u,lastScaledSize:r.hasProgress?-1:void 0,lastTitle:void 0}),this.refreshProgress({delta:-1});for await(let{progress:A,title:p}of r)o||u.progress===A&&u.title===p||(u.progress=A,u.title=p,this.refreshProgress());n()}),n=()=>{o||(o=!0,this.progress.delete(r),this.refreshProgress({delta:1}))};return{...a,stop:n}}reportJson(r){this.json&&this.writeLine(`${JSON.stringify(r)}`)}async finalize(){if(!this.includeFooter)return;let r=\"\";this.errorCount>0?r=\"Failed with errors\":this.warningCount>0?r=\"Done with warnings\":r=\"Done\";let o=Ut(this.configuration,Date.now()-this.startTime,yt.DURATION),a=this.configuration.get(\"enableTimers\")?`${r} in ${o}`:r;this.errorCount>0?this.reportError(0,a):this.warningCount>0?this.reportWarning(0,a):this.reportInfo(0,a)}writeLine(r,{truncate:o}={}){this.clearProgress({clear:!0}),this.stdout.write(`${this.truncate(r,{truncate:o})}\n`),this.writeProgress()}writeLines(r,{truncate:o}={}){this.clearProgress({delta:r.length});for(let a of r)this.stdout.write(`${this.truncate(a,{truncate:o})}\n`);this.writeProgress()}commit(){let r=this.uncommitted;this.uncommitted=new Set;for(let o of r)o.committed=!0,o.action()}clearProgress({delta:r=0,clear:o=!1}){this.progressStyle!==null&&this.progress.size+r>0&&(this.stdout.write(`\\x1B[${this.progress.size+r}A`),(r>0||o)&&this.stdout.write(\"\\x1B[0J\"))}writeProgress(){if(this.progressStyle===null||(this.progressTimeout!==null&&clearTimeout(this.progressTimeout),this.progressTimeout=null,this.progress.size===0))return;let r=Date.now();r-this.progressTime>Yce&&(this.progressFrame=(this.progressFrame+1)%jce.length,this.progressTime=r);let o=jce[this.progressFrame];for(let a of this.progress.values()){let n=\"\";if(typeof a.lastScaledSize<\"u\"){let h=this.progressStyle.chars[0].repeat(a.lastScaledSize),E=this.progressStyle.chars[1].repeat(this.progressMaxScaledSize-a.lastScaledSize);n=` ${h}${E}`}let u=this.formatName(null),A=u?`${u}: `:\"\",p=a.definition.title?` ${a.definition.title}`:\"\";this.stdout.write(`${Ut(this.configuration,\"\\u27A4\",\"blueBright\")} ${A}${o}${n}${p}\n`)}this.progressTimeout=setTimeout(()=>{this.refreshProgress({force:!0})},Yce)}refreshProgress({delta:r=0,force:o=!1}={}){let a=!1,n=!1;if(o||this.progress.size===0)a=!0;else for(let u of this.progress.values()){let A=typeof u.definition.progress<\"u\"?Math.trunc(this.progressMaxScaledSize*u.definition.progress):void 0,p=u.lastScaledSize;u.lastScaledSize=A;let h=u.lastTitle;if(u.lastTitle=u.definition.title,A!==p||(n=h!==u.definition.title)){a=!0;break}}a&&(this.clearProgress({delta:r,clear:n}),this.writeProgress())}truncate(r,{truncate:o}={}){return this.progressStyle===null&&(o=!1),typeof o>\"u\"&&(o=this.configuration.get(\"preferTruncatedLines\")),o&&(r=(0,Kce.default)(r,0,this.stdout.columns-1)),r}formatName(r){return this.includeNames?Vce(r,{configuration:this.configuration,json:this.json}):\"\"}formatPrefix(r,o){return this.includePrefix?`${Ut(this.configuration,\"\\u27A4\",o)} ${r}${this.formatIndent()}`:\"\"}formatNameWithHyperlink(r){return this.includeNames?yU(r,{configuration:this.configuration,json:this.json}):\"\"}formatIndent(){return this.level>0||!this.forceSectionAlignment?\"\\u2502 \".repeat(this.indent):`${mat} `}}});var un={};zt(un,{PackageManager:()=>Zce,detectPackageManager:()=>$ce,executePackageAccessibleBinary:()=>iue,executePackageScript:()=>Wb,executePackageShellcode:()=>EU,executeWorkspaceAccessibleBinary:()=>Sat,executeWorkspaceLifecycleScript:()=>rue,executeWorkspaceScript:()=>tue,getPackageAccessibleBinaries:()=>Kb,getWorkspaceAccessibleBinaries:()=>nue,hasPackageScript:()=>vat,hasWorkspaceScript:()=>CU,isNodeScript:()=>wU,makeScriptEnv:()=>M1,maybeExecuteWorkspaceLifecycleScript:()=>Pat,prepareExternalProject:()=>Bat});async function ph(t,e,r,o=[]){if(process.platform===\"win32\"){let a=`@goto #_undefined_# 2>NUL || @title %COMSPEC% & @setlocal & @\"${r}\" ${o.map(n=>`\"${n.replace('\"','\"\"')}\"`).join(\" \")} %*`;await oe.writeFilePromise(z.format({dir:t,name:e,ext:\".cmd\"}),a)}await oe.writeFilePromise(z.join(t,e),`#!/bin/sh\nexec \"${r}\" ${o.map(a=>`'${a.replace(/'/g,`'\"'\"'`)}'`).join(\" \")} \"$@\"\n`,{mode:493})}async function $ce(t){let e=await Ot.tryFind(t);if(e?.packageManager){let o=US(e.packageManager);if(o?.name){let a=`found ${JSON.stringify({packageManager:e.packageManager})} in manifest`,[n]=o.reference.split(\".\");switch(o.name){case\"yarn\":return{packageManagerField:!0,packageManager:Number(n)===1?\"Yarn Classic\":\"Yarn\",reason:a};case\"npm\":return{packageManagerField:!0,packageManager:\"npm\",reason:a};case\"pnpm\":return{packageManagerField:!0,packageManager:\"pnpm\",reason:a}}}}let r;try{r=await oe.readFilePromise(z.join(t,dr.lockfile),\"utf8\")}catch{}return r!==void 0?r.match(/^__metadata:$/m)?{packageManager:\"Yarn\",reason:'\"__metadata\" key found in yarn.lock'}:{packageManager:\"Yarn Classic\",reason:'\"__metadata\" key not found in yarn.lock, must be a Yarn classic lockfile'}:oe.existsSync(z.join(t,\"package-lock.json\"))?{packageManager:\"npm\",reason:`found npm's \"package-lock.json\" lockfile`}:oe.existsSync(z.join(t,\"pnpm-lock.yaml\"))?{packageManager:\"pnpm\",reason:`found pnpm's \"pnpm-lock.yaml\" lockfile`}:null}async function M1({project:t,locator:e,binFolder:r,ignoreCorepack:o,lifecycleScript:a,baseEnv:n=t?.configuration.env??process.env}){let u={};for(let[E,I]of Object.entries(n))typeof I<\"u\"&&(u[E.toLowerCase()!==\"path\"?E:\"PATH\"]=I);let A=le.fromPortablePath(r);u.BERRY_BIN_FOLDER=le.fromPortablePath(A);let p=process.env.COREPACK_ROOT&&!o?le.join(process.env.COREPACK_ROOT,\"dist/yarn.js\"):process.argv[1];if(await Promise.all([ph(r,\"node\",process.execPath),...rn!==null?[ph(r,\"run\",process.execPath,[p,\"run\"]),ph(r,\"yarn\",process.execPath,[p]),ph(r,\"yarnpkg\",process.execPath,[p]),ph(r,\"node-gyp\",process.execPath,[p,\"run\",\"--top-level\",\"node-gyp\"])]:[]]),t&&(u.INIT_CWD=le.fromPortablePath(t.configuration.startingCwd),u.PROJECT_CWD=le.fromPortablePath(t.cwd)),u.PATH=u.PATH?`${A}${le.delimiter}${u.PATH}`:`${A}`,u.npm_execpath=`${A}${le.sep}yarn`,u.npm_node_execpath=`${A}${le.sep}node`,e){if(!t)throw new Error(\"Assertion failed: Missing project\");let E=t.tryWorkspaceByLocator(e),I=E?E.manifest.version??\"\":t.storedPackages.get(e.locatorHash).version??\"\";u.npm_package_name=fn(e),u.npm_package_version=I;let v;if(E)v=E.cwd;else{let x=t.storedPackages.get(e.locatorHash);if(!x)throw new Error(`Package for ${qr(t.configuration,e)} not found in the project`);let C=t.configuration.getLinkers(),R={project:t,report:new Lt({stdout:new hh.PassThrough,configuration:t.configuration})},N=C.find(U=>U.supportsPackage(x,R));if(!N)throw new Error(`The package ${qr(t.configuration,x)} isn't supported by any of the available linkers`);v=await N.findPackageLocation(x,R)}u.npm_package_json=le.fromPortablePath(z.join(v,dr.manifest))}let h=rn!==null?`yarn/${rn}`:`yarn/${Df(\"@yarnpkg/core\").version}-core`;return u.npm_config_user_agent=`${h} npm/? node/${process.version} ${process.platform} ${process.arch}`,a&&(u.npm_lifecycle_event=a),t&&await t.configuration.triggerHook(E=>E.setupScriptEnvironment,t,u,async(E,I,v)=>await ph(r,E,I,v)),u}async function Bat(t,e,{configuration:r,report:o,workspace:a=null,locator:n=null}){await Iat(async()=>{await oe.mktempPromise(async u=>{let A=z.join(u,\"pack.log\"),p=null,{stdout:h,stderr:E}=r.getSubprocessStreams(A,{prefix:le.fromPortablePath(t),report:o}),I=n&&qc(n)?r1(n):n,v=I?ba(I):\"an external project\";h.write(`Packing ${v} from sources\n`);let x=await $ce(t),C;x!==null?(h.write(`Using ${x.packageManager} for bootstrap. Reason: ${x.reason}\n\n`),C=x.packageManager):(h.write(`No package manager configuration detected; defaulting to Yarn\n\n`),C=\"Yarn\");let R=C===\"Yarn\"&&!x?.packageManagerField;await oe.mktempPromise(async N=>{let U=await M1({binFolder:N,ignoreCorepack:R}),te=new Map([[\"Yarn Classic\",async()=>{let fe=a!==null?[\"workspace\",a]:[],ue=z.join(t,dr.manifest),me=await oe.readFilePromise(ue),he=await Yc(process.execPath,[process.argv[1],\"set\",\"version\",\"classic\",\"--only-if-needed\",\"--yarn-path\"],{cwd:t,env:U,stdin:p,stdout:h,stderr:E,end:1});if(he.code!==0)return he.code;await oe.writeFilePromise(ue,me),await oe.appendFilePromise(z.join(t,\".npmignore\"),`/.yarn\n`),h.write(`\n`),delete U.NODE_ENV;let Be=await Yc(\"yarn\",[\"install\"],{cwd:t,env:U,stdin:p,stdout:h,stderr:E,end:1});if(Be.code!==0)return Be.code;h.write(`\n`);let we=await Yc(\"yarn\",[...fe,\"pack\",\"--filename\",le.fromPortablePath(e)],{cwd:t,env:U,stdin:p,stdout:h,stderr:E});return we.code!==0?we.code:0}],[\"Yarn\",async()=>{let fe=a!==null?[\"workspace\",a]:[];U.YARN_ENABLE_INLINE_BUILDS=\"1\";let ue=z.join(t,dr.lockfile);await oe.existsPromise(ue)||await oe.writeFilePromise(ue,\"\");let me=await Yc(\"yarn\",[...fe,\"pack\",\"--install-if-needed\",\"--filename\",le.fromPortablePath(e)],{cwd:t,env:U,stdin:p,stdout:h,stderr:E});return me.code!==0?me.code:0}],[\"npm\",async()=>{if(a!==null){let Ee=new hh.PassThrough,Pe=zy(Ee);Ee.pipe(h,{end:!1});let ce=await Yc(\"npm\",[\"--version\"],{cwd:t,env:U,stdin:p,stdout:Ee,stderr:E,end:0});if(Ee.end(),ce.code!==0)return h.end(),E.end(),ce.code;let ne=(await Pe).toString().trim();if(!kf(ne,\">=7.x\")){let ee=tA(null,\"npm\"),Ie=In(ee,ne),Fe=In(ee,\">=7.x\");throw new Error(`Workspaces aren't supported by ${Gn(r,Ie)}; please upgrade to ${Gn(r,Fe)} (npm has been detected as the primary package manager for ${Ut(r,t,yt.PATH)})`)}}let fe=a!==null?[\"--workspace\",a]:[];delete U.npm_config_user_agent,delete U.npm_config_production,delete U.NPM_CONFIG_PRODUCTION,delete U.NODE_ENV;let ue=await Yc(\"npm\",[\"install\",\"--legacy-peer-deps\"],{cwd:t,env:U,stdin:p,stdout:h,stderr:E,end:1});if(ue.code!==0)return ue.code;let me=new hh.PassThrough,he=zy(me);me.pipe(h);let Be=await Yc(\"npm\",[\"pack\",\"--silent\",...fe],{cwd:t,env:U,stdin:p,stdout:me,stderr:E});if(Be.code!==0)return Be.code;let we=(await he).toString().trim().replace(/^.*\\n/s,\"\"),g=z.resolve(t,le.toPortablePath(we));return await oe.renamePromise(g,e),0}]]).get(C);if(typeof te>\"u\")throw new Error(\"Assertion failed: Unsupported workflow\");let ae=await te();if(!(ae===0||typeof ae>\"u\"))throw oe.detachTemp(u),new Jt(58,`Packing the package failed (exit code ${ae}, logs can be found here: ${Ut(r,A,yt.PATH)})`)})})})}async function vat(t,e,{project:r}){let o=r.tryWorkspaceByLocator(t);if(o!==null)return CU(o,e);let a=r.storedPackages.get(t.locatorHash);if(!a)throw new Error(`Package for ${qr(r.configuration,t)} not found in the project`);return await Jl.openPromise(async n=>{let u=r.configuration,A=r.configuration.getLinkers(),p={project:r,report:new Lt({stdout:new hh.PassThrough,configuration:u})},h=A.find(x=>x.supportsPackage(a,p));if(!h)throw new Error(`The package ${qr(r.configuration,a)} isn't supported by any of the available linkers`);let E=await h.findPackageLocation(a,p),I=new gn(E,{baseFs:n});return(await Ot.find(Bt.dot,{baseFs:I})).scripts.has(e)})}async function Wb(t,e,r,{cwd:o,project:a,stdin:n,stdout:u,stderr:A}){return await oe.mktempPromise(async p=>{let{manifest:h,env:E,cwd:I}=await eue(t,{project:a,binFolder:p,cwd:o,lifecycleScript:e}),v=h.scripts.get(e);if(typeof v>\"u\")return 1;let x=async()=>await TE(v,r,{cwd:I,env:E,stdin:n,stdout:u,stderr:A});return await(await a.configuration.reduceHook(R=>R.wrapScriptExecution,x,a,t,e,{script:v,args:r,cwd:I,env:E,stdin:n,stdout:u,stderr:A}))()})}async function EU(t,e,r,{cwd:o,project:a,stdin:n,stdout:u,stderr:A}){return await oe.mktempPromise(async p=>{let{env:h,cwd:E}=await eue(t,{project:a,binFolder:p,cwd:o});return await TE(e,r,{cwd:E,env:h,stdin:n,stdout:u,stderr:A})})}async function Dat(t,{binFolder:e,cwd:r,lifecycleScript:o}){let a=await M1({project:t.project,locator:t.anchoredLocator,binFolder:e,lifecycleScript:o});return await IU(e,await nue(t)),typeof r>\"u\"&&(r=z.dirname(await oe.realpathPromise(z.join(t.cwd,\"package.json\")))),{manifest:t.manifest,binFolder:e,env:a,cwd:r}}async function eue(t,{project:e,binFolder:r,cwd:o,lifecycleScript:a}){let n=e.tryWorkspaceByLocator(t);if(n!==null)return Dat(n,{binFolder:r,cwd:o,lifecycleScript:a});let u=e.storedPackages.get(t.locatorHash);if(!u)throw new Error(`Package for ${qr(e.configuration,t)} not found in the project`);return await Jl.openPromise(async A=>{let p=e.configuration,h=e.configuration.getLinkers(),E={project:e,report:new Lt({stdout:new hh.PassThrough,configuration:p})},I=h.find(N=>N.supportsPackage(u,E));if(!I)throw new Error(`The package ${qr(e.configuration,u)} isn't supported by any of the available linkers`);let v=await M1({project:e,locator:t,binFolder:r,lifecycleScript:a});await IU(r,await Kb(t,{project:e}));let x=await I.findPackageLocation(u,E),C=new gn(x,{baseFs:A}),R=await Ot.find(Bt.dot,{baseFs:C});return typeof o>\"u\"&&(o=x),{manifest:R,binFolder:r,env:v,cwd:o}})}async function tue(t,e,r,{cwd:o,stdin:a,stdout:n,stderr:u}){return await Wb(t.anchoredLocator,e,r,{cwd:o,project:t.project,stdin:a,stdout:n,stderr:u})}function CU(t,e){return t.manifest.scripts.has(e)}async function rue(t,e,{cwd:r,report:o}){let{configuration:a}=t.project,n=null;await oe.mktempPromise(async u=>{let A=z.join(u,`${e}.log`),p=`# This file contains the result of Yarn calling the \"${e}\" lifecycle script inside a workspace (\"${le.fromPortablePath(t.cwd)}\")\n`,{stdout:h,stderr:E}=a.getSubprocessStreams(A,{report:o,prefix:qr(a,t.anchoredLocator),header:p});o.reportInfo(36,`Calling the \"${e}\" lifecycle script`);let I=await tue(t,e,[],{cwd:r,stdin:n,stdout:h,stderr:E});if(h.end(),E.end(),I!==0)throw oe.detachTemp(u),new Jt(36,`${(0,Jce.default)(e)} script failed (exit code ${Ut(a,I,yt.NUMBER)}, logs can be found here: ${Ut(a,A,yt.PATH)}); run ${Ut(a,`yarn ${e}`,yt.CODE)} to investigate`)})}async function Pat(t,e,r){CU(t,e)&&await rue(t,e,r)}function wU(t){let e=z.extname(t);if(e.match(/\\.[cm]?[jt]sx?$/))return!0;if(e===\".exe\"||e===\".bin\")return!1;let r=Buffer.alloc(4),o;try{o=oe.openSync(t,\"r\")}catch{return!0}try{oe.readSync(o,r,0,r.length,0)}finally{oe.closeSync(o)}let a=r.readUint32BE();return!(a===3405691582||a===3489328638||a===2135247942||(a&4294901760)===1297743872)}async function Kb(t,{project:e}){let r=e.configuration,o=new Map,a=e.storedPackages.get(t.locatorHash);if(!a)throw new Error(`Package for ${qr(r,t)} not found in the project`);let n=new hh.Writable,u=r.getLinkers(),A={project:e,report:new Lt({configuration:r,stdout:n})},p=new Set([t.locatorHash]);for(let E of a.dependencies.values()){let I=e.storedResolutions.get(E.descriptorHash);if(!I)throw new Error(`Assertion failed: The resolution (${Gn(r,E)}) should have been registered`);p.add(I)}let h=await Promise.all(Array.from(p,async E=>{let I=e.storedPackages.get(E);if(!I)throw new Error(`Assertion failed: The package (${E}) should have been registered`);if(I.bin.size===0)return ol.skip;let v=u.find(C=>C.supportsPackage(I,A));if(!v)return ol.skip;let x=null;try{x=await v.findPackageLocation(I,A)}catch(C){if(C.code===\"LOCATOR_NOT_INSTALLED\")return ol.skip;throw C}return{dependency:I,packageLocation:x}}));for(let E of h){if(E===ol.skip)continue;let{dependency:I,packageLocation:v}=E;for(let[x,C]of I.bin){let R=z.resolve(v,C);o.set(x,[I,le.fromPortablePath(R),wU(R)])}}return o}async function nue(t){return await Kb(t.anchoredLocator,{project:t.project})}async function IU(t,e){await Promise.all(Array.from(e,([r,[,o,a]])=>a?ph(t,r,process.execPath,[o]):ph(t,r,o,[])))}async function iue(t,e,r,{cwd:o,project:a,stdin:n,stdout:u,stderr:A,nodeArgs:p=[],packageAccessibleBinaries:h}){h??=await Kb(t,{project:a});let E=h.get(e);if(!E)throw new Error(`Binary not found (${e}) for ${qr(a.configuration,t)}`);return await oe.mktempPromise(async I=>{let[,v]=E,x=await M1({project:a,locator:t,binFolder:I});await IU(x.BERRY_BIN_FOLDER,h);let C=wU(le.toPortablePath(v))?Yc(process.execPath,[...p,v,...r],{cwd:o,env:x,stdin:n,stdout:u,stderr:A}):Yc(v,r,{cwd:o,env:x,stdin:n,stdout:u,stderr:A}),R;try{R=await C}finally{await oe.removePromise(x.BERRY_BIN_FOLDER)}return R.code})}async function Sat(t,e,r,{cwd:o,stdin:a,stdout:n,stderr:u,packageAccessibleBinaries:A}){return await iue(t.anchoredLocator,e,r,{project:t.project,cwd:o,stdin:a,stdout:n,stderr:u,packageAccessibleBinaries:A})}var Jce,Xce,hh,Zce,wat,Iat,BU=Et(()=>{Pt();Pt();iA();k1();Jce=$e(mU()),Xce=$e(sd()),hh=ve(\"stream\");fE();Wl();O1();N1();Db();jl();Gl();Qf();bo();Zce=(a=>(a.Yarn1=\"Yarn Classic\",a.Yarn2=\"Yarn\",a.Npm=\"npm\",a.Pnpm=\"pnpm\",a))(Zce||{});wat=2,Iat=(0,Xce.default)(wat)});var OE=_((O4t,oue)=>{\"use strict\";var sue=new Map([[\"C\",\"cwd\"],[\"f\",\"file\"],[\"z\",\"gzip\"],[\"P\",\"preservePaths\"],[\"U\",\"unlink\"],[\"strip-components\",\"strip\"],[\"stripComponents\",\"strip\"],[\"keep-newer\",\"newer\"],[\"keepNewer\",\"newer\"],[\"keep-newer-files\",\"newer\"],[\"keepNewerFiles\",\"newer\"],[\"k\",\"keep\"],[\"keep-existing\",\"keep\"],[\"keepExisting\",\"keep\"],[\"m\",\"noMtime\"],[\"no-mtime\",\"noMtime\"],[\"p\",\"preserveOwner\"],[\"L\",\"follow\"],[\"h\",\"follow\"]]);oue.exports=t=>t?Object.keys(t).map(e=>[sue.has(e)?sue.get(e):e,t[e]]).reduce((e,r)=>(e[r[0]]=r[1],e),Object.create(null)):{}});var UE=_((M4t,gue)=>{\"use strict\";var aue=typeof process==\"object\"&&process?process:{stdout:null,stderr:null},bat=ve(\"events\"),lue=ve(\"stream\"),cue=ve(\"string_decoder\").StringDecoder,Mf=Symbol(\"EOF\"),Uf=Symbol(\"maybeEmitEnd\"),gh=Symbol(\"emittedEnd\"),zb=Symbol(\"emittingEnd\"),U1=Symbol(\"emittedError\"),Vb=Symbol(\"closed\"),uue=Symbol(\"read\"),Jb=Symbol(\"flush\"),Aue=Symbol(\"flushChunk\"),ka=Symbol(\"encoding\"),_f=Symbol(\"decoder\"),Xb=Symbol(\"flowing\"),_1=Symbol(\"paused\"),ME=Symbol(\"resume\"),Fs=Symbol(\"bufferLength\"),vU=Symbol(\"bufferPush\"),DU=Symbol(\"bufferShift\"),Fo=Symbol(\"objectMode\"),Ro=Symbol(\"destroyed\"),PU=Symbol(\"emitData\"),fue=Symbol(\"emitEnd\"),SU=Symbol(\"emitEnd2\"),Hf=Symbol(\"async\"),H1=t=>Promise.resolve().then(t),pue=global._MP_NO_ITERATOR_SYMBOLS_!==\"1\",xat=pue&&Symbol.asyncIterator||Symbol(\"asyncIterator not implemented\"),kat=pue&&Symbol.iterator||Symbol(\"iterator not implemented\"),Qat=t=>t===\"end\"||t===\"finish\"||t===\"prefinish\",Fat=t=>t instanceof ArrayBuffer||typeof t==\"object\"&&t.constructor&&t.constructor.name===\"ArrayBuffer\"&&t.byteLength>=0,Rat=t=>!Buffer.isBuffer(t)&&ArrayBuffer.isView(t),Zb=class{constructor(e,r,o){this.src=e,this.dest=r,this.opts=o,this.ondrain=()=>e[ME](),r.on(\"drain\",this.ondrain)}unpipe(){this.dest.removeListener(\"drain\",this.ondrain)}proxyErrors(){}end(){this.unpipe(),this.opts.end&&this.dest.end()}},bU=class extends Zb{unpipe(){this.src.removeListener(\"error\",this.proxyErrors),super.unpipe()}constructor(e,r,o){super(e,r,o),this.proxyErrors=a=>r.emit(\"error\",a),e.on(\"error\",this.proxyErrors)}};gue.exports=class hue extends lue{constructor(e){super(),this[Xb]=!1,this[_1]=!1,this.pipes=[],this.buffer=[],this[Fo]=e&&e.objectMode||!1,this[Fo]?this[ka]=null:this[ka]=e&&e.encoding||null,this[ka]===\"buffer\"&&(this[ka]=null),this[Hf]=e&&!!e.async||!1,this[_f]=this[ka]?new cue(this[ka]):null,this[Mf]=!1,this[gh]=!1,this[zb]=!1,this[Vb]=!1,this[U1]=null,this.writable=!0,this.readable=!0,this[Fs]=0,this[Ro]=!1}get bufferLength(){return this[Fs]}get encoding(){return this[ka]}set encoding(e){if(this[Fo])throw new Error(\"cannot set encoding in objectMode\");if(this[ka]&&e!==this[ka]&&(this[_f]&&this[_f].lastNeed||this[Fs]))throw new Error(\"cannot change encoding\");this[ka]!==e&&(this[_f]=e?new cue(e):null,this.buffer.length&&(this.buffer=this.buffer.map(r=>this[_f].write(r)))),this[ka]=e}setEncoding(e){this.encoding=e}get objectMode(){return this[Fo]}set objectMode(e){this[Fo]=this[Fo]||!!e}get async(){return this[Hf]}set async(e){this[Hf]=this[Hf]||!!e}write(e,r,o){if(this[Mf])throw new Error(\"write after end\");if(this[Ro])return this.emit(\"error\",Object.assign(new Error(\"Cannot call write after a stream was destroyed\"),{code:\"ERR_STREAM_DESTROYED\"})),!0;typeof r==\"function\"&&(o=r,r=\"utf8\"),r||(r=\"utf8\");let a=this[Hf]?H1:n=>n();return!this[Fo]&&!Buffer.isBuffer(e)&&(Rat(e)?e=Buffer.from(e.buffer,e.byteOffset,e.byteLength):Fat(e)?e=Buffer.from(e):typeof e!=\"string\"&&(this.objectMode=!0)),this[Fo]?(this.flowing&&this[Fs]!==0&&this[Jb](!0),this.flowing?this.emit(\"data\",e):this[vU](e),this[Fs]!==0&&this.emit(\"readable\"),o&&a(o),this.flowing):e.length?(typeof e==\"string\"&&!(r===this[ka]&&!this[_f].lastNeed)&&(e=Buffer.from(e,r)),Buffer.isBuffer(e)&&this[ka]&&(e=this[_f].write(e)),this.flowing&&this[Fs]!==0&&this[Jb](!0),this.flowing?this.emit(\"data\",e):this[vU](e),this[Fs]!==0&&this.emit(\"readable\"),o&&a(o),this.flowing):(this[Fs]!==0&&this.emit(\"readable\"),o&&a(o),this.flowing)}read(e){if(this[Ro])return null;if(this[Fs]===0||e===0||e>this[Fs])return this[Uf](),null;this[Fo]&&(e=null),this.buffer.length>1&&!this[Fo]&&(this.encoding?this.buffer=[this.buffer.join(\"\")]:this.buffer=[Buffer.concat(this.buffer,this[Fs])]);let r=this[uue](e||null,this.buffer[0]);return this[Uf](),r}[uue](e,r){return e===r.length||e===null?this[DU]():(this.buffer[0]=r.slice(e),r=r.slice(0,e),this[Fs]-=e),this.emit(\"data\",r),!this.buffer.length&&!this[Mf]&&this.emit(\"drain\"),r}end(e,r,o){return typeof e==\"function\"&&(o=e,e=null),typeof r==\"function\"&&(o=r,r=\"utf8\"),e&&this.write(e,r),o&&this.once(\"end\",o),this[Mf]=!0,this.writable=!1,(this.flowing||!this[_1])&&this[Uf](),this}[ME](){this[Ro]||(this[_1]=!1,this[Xb]=!0,this.emit(\"resume\"),this.buffer.length?this[Jb]():this[Mf]?this[Uf]():this.emit(\"drain\"))}resume(){return this[ME]()}pause(){this[Xb]=!1,this[_1]=!0}get destroyed(){return this[Ro]}get flowing(){return this[Xb]}get paused(){return this[_1]}[vU](e){this[Fo]?this[Fs]+=1:this[Fs]+=e.length,this.buffer.push(e)}[DU](){return this.buffer.length&&(this[Fo]?this[Fs]-=1:this[Fs]-=this.buffer[0].length),this.buffer.shift()}[Jb](e){do;while(this[Aue](this[DU]()));!e&&!this.buffer.length&&!this[Mf]&&this.emit(\"drain\")}[Aue](e){return e?(this.emit(\"data\",e),this.flowing):!1}pipe(e,r){if(this[Ro])return;let o=this[gh];return r=r||{},e===aue.stdout||e===aue.stderr?r.end=!1:r.end=r.end!==!1,r.proxyErrors=!!r.proxyErrors,o?r.end&&e.end():(this.pipes.push(r.proxyErrors?new bU(this,e,r):new Zb(this,e,r)),this[Hf]?H1(()=>this[ME]()):this[ME]()),e}unpipe(e){let r=this.pipes.find(o=>o.dest===e);r&&(this.pipes.splice(this.pipes.indexOf(r),1),r.unpipe())}addListener(e,r){return this.on(e,r)}on(e,r){let o=super.on(e,r);return e===\"data\"&&!this.pipes.length&&!this.flowing?this[ME]():e===\"readable\"&&this[Fs]!==0?super.emit(\"readable\"):Qat(e)&&this[gh]?(super.emit(e),this.removeAllListeners(e)):e===\"error\"&&this[U1]&&(this[Hf]?H1(()=>r.call(this,this[U1])):r.call(this,this[U1])),o}get emittedEnd(){return this[gh]}[Uf](){!this[zb]&&!this[gh]&&!this[Ro]&&this.buffer.length===0&&this[Mf]&&(this[zb]=!0,this.emit(\"end\"),this.emit(\"prefinish\"),this.emit(\"finish\"),this[Vb]&&this.emit(\"close\"),this[zb]=!1)}emit(e,r,...o){if(e!==\"error\"&&e!==\"close\"&&e!==Ro&&this[Ro])return;if(e===\"data\")return r?this[Hf]?H1(()=>this[PU](r)):this[PU](r):!1;if(e===\"end\")return this[fue]();if(e===\"close\"){if(this[Vb]=!0,!this[gh]&&!this[Ro])return;let n=super.emit(\"close\");return this.removeAllListeners(\"close\"),n}else if(e===\"error\"){this[U1]=r;let n=super.emit(\"error\",r);return this[Uf](),n}else if(e===\"resume\"){let n=super.emit(\"resume\");return this[Uf](),n}else if(e===\"finish\"||e===\"prefinish\"){let n=super.emit(e);return this.removeAllListeners(e),n}let a=super.emit(e,r,...o);return this[Uf](),a}[PU](e){for(let o of this.pipes)o.dest.write(e)===!1&&this.pause();let r=super.emit(\"data\",e);return this[Uf](),r}[fue](){this[gh]||(this[gh]=!0,this.readable=!1,this[Hf]?H1(()=>this[SU]()):this[SU]())}[SU](){if(this[_f]){let r=this[_f].end();if(r){for(let o of this.pipes)o.dest.write(r);super.emit(\"data\",r)}}for(let r of this.pipes)r.end();let e=super.emit(\"end\");return this.removeAllListeners(\"end\"),e}collect(){let e=[];this[Fo]||(e.dataLength=0);let r=this.promise();return this.on(\"data\",o=>{e.push(o),this[Fo]||(e.dataLength+=o.length)}),r.then(()=>e)}concat(){return this[Fo]?Promise.reject(new Error(\"cannot concat in objectMode\")):this.collect().then(e=>this[Fo]?Promise.reject(new Error(\"cannot concat in objectMode\")):this[ka]?e.join(\"\"):Buffer.concat(e,e.dataLength))}promise(){return new Promise((e,r)=>{this.on(Ro,()=>r(new Error(\"stream destroyed\"))),this.on(\"error\",o=>r(o)),this.on(\"end\",()=>e())})}[xat](){return{next:()=>{let r=this.read();if(r!==null)return Promise.resolve({done:!1,value:r});if(this[Mf])return Promise.resolve({done:!0});let o=null,a=null,n=h=>{this.removeListener(\"data\",u),this.removeListener(\"end\",A),a(h)},u=h=>{this.removeListener(\"error\",n),this.removeListener(\"end\",A),this.pause(),o({value:h,done:!!this[Mf]})},A=()=>{this.removeListener(\"error\",n),this.removeListener(\"data\",u),o({done:!0})},p=()=>n(new Error(\"stream destroyed\"));return new Promise((h,E)=>{a=E,o=h,this.once(Ro,p),this.once(\"error\",n),this.once(\"end\",A),this.once(\"data\",u)})}}}[kat](){return{next:()=>{let r=this.read();return{value:r,done:r===null}}}}destroy(e){return this[Ro]?(e?this.emit(\"error\",e):this.emit(Ro),this):(this[Ro]=!0,this.buffer.length=0,this[Fs]=0,typeof this.close==\"function\"&&!this[Vb]&&this.close(),e?this.emit(\"error\",e):this.emit(Ro),this)}static isStream(e){return!!e&&(e instanceof hue||e instanceof lue||e instanceof bat&&(typeof e.pipe==\"function\"||typeof e.write==\"function\"&&typeof e.end==\"function\"))}}});var mue=_((U4t,due)=>{var Tat=ve(\"zlib\").constants||{ZLIB_VERNUM:4736};due.exports=Object.freeze(Object.assign(Object.create(null),{Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_MEM_ERROR:-4,Z_BUF_ERROR:-5,Z_VERSION_ERROR:-6,Z_NO_COMPRESSION:0,Z_BEST_SPEED:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,DEFLATE:1,INFLATE:2,GZIP:3,GUNZIP:4,DEFLATERAW:5,INFLATERAW:6,UNZIP:7,BROTLI_DECODE:8,BROTLI_ENCODE:9,Z_MIN_WINDOWBITS:8,Z_MAX_WINDOWBITS:15,Z_DEFAULT_WINDOWBITS:15,Z_MIN_CHUNK:64,Z_MAX_CHUNK:1/0,Z_DEFAULT_CHUNK:16384,Z_MIN_MEMLEVEL:1,Z_MAX_MEMLEVEL:9,Z_DEFAULT_MEMLEVEL:8,Z_MIN_LEVEL:-1,Z_MAX_LEVEL:9,Z_DEFAULT_LEVEL:-1,BROTLI_OPERATION_PROCESS:0,BROTLI_OPERATION_FLUSH:1,BROTLI_OPERATION_FINISH:2,BROTLI_OPERATION_EMIT_METADATA:3,BROTLI_MODE_GENERIC:0,BROTLI_MODE_TEXT:1,BROTLI_MODE_FONT:2,BROTLI_DEFAULT_MODE:0,BROTLI_MIN_QUALITY:0,BROTLI_MAX_QUALITY:11,BROTLI_DEFAULT_QUALITY:11,BROTLI_MIN_WINDOW_BITS:10,BROTLI_MAX_WINDOW_BITS:24,BROTLI_LARGE_MAX_WINDOW_BITS:30,BROTLI_DEFAULT_WINDOW:22,BROTLI_MIN_INPUT_BLOCK_BITS:16,BROTLI_MAX_INPUT_BLOCK_BITS:24,BROTLI_PARAM_MODE:0,BROTLI_PARAM_QUALITY:1,BROTLI_PARAM_LGWIN:2,BROTLI_PARAM_LGBLOCK:3,BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING:4,BROTLI_PARAM_SIZE_HINT:5,BROTLI_PARAM_LARGE_WINDOW:6,BROTLI_PARAM_NPOSTFIX:7,BROTLI_PARAM_NDIRECT:8,BROTLI_DECODER_RESULT_ERROR:0,BROTLI_DECODER_RESULT_SUCCESS:1,BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT:2,BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT:3,BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION:0,BROTLI_DECODER_PARAM_LARGE_WINDOW:1,BROTLI_DECODER_NO_ERROR:0,BROTLI_DECODER_SUCCESS:1,BROTLI_DECODER_NEEDS_MORE_INPUT:2,BROTLI_DECODER_NEEDS_MORE_OUTPUT:3,BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE:-1,BROTLI_DECODER_ERROR_FORMAT_RESERVED:-2,BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE:-3,BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET:-4,BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME:-5,BROTLI_DECODER_ERROR_FORMAT_CL_SPACE:-6,BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE:-7,BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT:-8,BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1:-9,BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2:-10,BROTLI_DECODER_ERROR_FORMAT_TRANSFORM:-11,BROTLI_DECODER_ERROR_FORMAT_DICTIONARY:-12,BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS:-13,BROTLI_DECODER_ERROR_FORMAT_PADDING_1:-14,BROTLI_DECODER_ERROR_FORMAT_PADDING_2:-15,BROTLI_DECODER_ERROR_FORMAT_DISTANCE:-16,BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET:-19,BROTLI_DECODER_ERROR_INVALID_ARGUMENTS:-20,BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES:-21,BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS:-22,BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP:-25,BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1:-26,BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2:-27,BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES:-30,BROTLI_DECODER_ERROR_UNREACHABLE:-31},Tat))});var jU=_(ul=>{\"use strict\";var RU=ve(\"assert\"),dh=ve(\"buffer\").Buffer,Cue=ve(\"zlib\"),Rd=ul.constants=mue(),Lat=UE(),yue=dh.concat,Td=Symbol(\"_superWrite\"),HE=class extends Error{constructor(e){super(\"zlib: \"+e.message),this.code=e.code,this.errno=e.errno,this.code||(this.code=\"ZLIB_ERROR\"),this.message=\"zlib: \"+e.message,Error.captureStackTrace(this,this.constructor)}get name(){return\"ZlibError\"}},Nat=Symbol(\"opts\"),q1=Symbol(\"flushFlag\"),Eue=Symbol(\"finishFlushFlag\"),GU=Symbol(\"fullFlushFlag\"),ti=Symbol(\"handle\"),$b=Symbol(\"onError\"),_E=Symbol(\"sawError\"),xU=Symbol(\"level\"),kU=Symbol(\"strategy\"),QU=Symbol(\"ended\"),_4t=Symbol(\"_defaultFullFlush\"),ex=class extends Lat{constructor(e,r){if(!e||typeof e!=\"object\")throw new TypeError(\"invalid options for ZlibBase constructor\");super(e),this[_E]=!1,this[QU]=!1,this[Nat]=e,this[q1]=e.flush,this[Eue]=e.finishFlush;try{this[ti]=new Cue[r](e)}catch(o){throw new HE(o)}this[$b]=o=>{this[_E]||(this[_E]=!0,this.close(),this.emit(\"error\",o))},this[ti].on(\"error\",o=>this[$b](new HE(o))),this.once(\"end\",()=>this.close)}close(){this[ti]&&(this[ti].close(),this[ti]=null,this.emit(\"close\"))}reset(){if(!this[_E])return RU(this[ti],\"zlib binding closed\"),this[ti].reset()}flush(e){this.ended||(typeof e!=\"number\"&&(e=this[GU]),this.write(Object.assign(dh.alloc(0),{[q1]:e})))}end(e,r,o){return e&&this.write(e,r),this.flush(this[Eue]),this[QU]=!0,super.end(null,null,o)}get ended(){return this[QU]}write(e,r,o){if(typeof r==\"function\"&&(o=r,r=\"utf8\"),typeof e==\"string\"&&(e=dh.from(e,r)),this[_E])return;RU(this[ti],\"zlib binding closed\");let a=this[ti]._handle,n=a.close;a.close=()=>{};let u=this[ti].close;this[ti].close=()=>{},dh.concat=h=>h;let A;try{let h=typeof e[q1]==\"number\"?e[q1]:this[q1];A=this[ti]._processChunk(e,h),dh.concat=yue}catch(h){dh.concat=yue,this[$b](new HE(h))}finally{this[ti]&&(this[ti]._handle=a,a.close=n,this[ti].close=u,this[ti].removeAllListeners(\"error\"))}this[ti]&&this[ti].on(\"error\",h=>this[$b](new HE(h)));let p;if(A)if(Array.isArray(A)&&A.length>0){p=this[Td](dh.from(A[0]));for(let h=1;h<A.length;h++)p=this[Td](A[h])}else p=this[Td](dh.from(A));return o&&o(),p}[Td](e){return super.write(e)}},qf=class extends ex{constructor(e,r){e=e||{},e.flush=e.flush||Rd.Z_NO_FLUSH,e.finishFlush=e.finishFlush||Rd.Z_FINISH,super(e,r),this[GU]=Rd.Z_FULL_FLUSH,this[xU]=e.level,this[kU]=e.strategy}params(e,r){if(!this[_E]){if(!this[ti])throw new Error(\"cannot switch params when binding is closed\");if(!this[ti].params)throw new Error(\"not supported in this implementation\");if(this[xU]!==e||this[kU]!==r){this.flush(Rd.Z_SYNC_FLUSH),RU(this[ti],\"zlib binding closed\");let o=this[ti].flush;this[ti].flush=(a,n)=>{this.flush(a),n()};try{this[ti].params(e,r)}finally{this[ti].flush=o}this[ti]&&(this[xU]=e,this[kU]=r)}}}},TU=class extends qf{constructor(e){super(e,\"Deflate\")}},LU=class extends qf{constructor(e){super(e,\"Inflate\")}},FU=Symbol(\"_portable\"),NU=class extends qf{constructor(e){super(e,\"Gzip\"),this[FU]=e&&!!e.portable}[Td](e){return this[FU]?(this[FU]=!1,e[9]=255,super[Td](e)):super[Td](e)}},OU=class extends qf{constructor(e){super(e,\"Gunzip\")}},MU=class extends qf{constructor(e){super(e,\"DeflateRaw\")}},UU=class extends qf{constructor(e){super(e,\"InflateRaw\")}},_U=class extends qf{constructor(e){super(e,\"Unzip\")}},tx=class extends ex{constructor(e,r){e=e||{},e.flush=e.flush||Rd.BROTLI_OPERATION_PROCESS,e.finishFlush=e.finishFlush||Rd.BROTLI_OPERATION_FINISH,super(e,r),this[GU]=Rd.BROTLI_OPERATION_FLUSH}},HU=class extends tx{constructor(e){super(e,\"BrotliCompress\")}},qU=class extends tx{constructor(e){super(e,\"BrotliDecompress\")}};ul.Deflate=TU;ul.Inflate=LU;ul.Gzip=NU;ul.Gunzip=OU;ul.DeflateRaw=MU;ul.InflateRaw=UU;ul.Unzip=_U;typeof Cue.BrotliCompress==\"function\"?(ul.BrotliCompress=HU,ul.BrotliDecompress=qU):ul.BrotliCompress=ul.BrotliDecompress=class{constructor(){throw new Error(\"Brotli is not supported in this version of Node.js\")}}});var qE=_((G4t,wue)=>{var Oat=process.env.TESTING_TAR_FAKE_PLATFORM||process.platform;wue.exports=Oat!==\"win32\"?t=>t:t=>t&&t.replace(/\\\\/g,\"/\")});var rx=_((Y4t,Iue)=>{\"use strict\";var Mat=UE(),YU=qE(),WU=Symbol(\"slurp\");Iue.exports=class extends Mat{constructor(e,r,o){switch(super(),this.pause(),this.extended=r,this.globalExtended=o,this.header=e,this.startBlockSize=512*Math.ceil(e.size/512),this.blockRemain=this.startBlockSize,this.remain=e.size,this.type=e.type,this.meta=!1,this.ignore=!1,this.type){case\"File\":case\"OldFile\":case\"Link\":case\"SymbolicLink\":case\"CharacterDevice\":case\"BlockDevice\":case\"Directory\":case\"FIFO\":case\"ContiguousFile\":case\"GNUDumpDir\":break;case\"NextFileHasLongLinkpath\":case\"NextFileHasLongPath\":case\"OldGnuLongPath\":case\"GlobalExtendedHeader\":case\"ExtendedHeader\":case\"OldExtendedHeader\":this.meta=!0;break;default:this.ignore=!0}this.path=YU(e.path),this.mode=e.mode,this.mode&&(this.mode=this.mode&4095),this.uid=e.uid,this.gid=e.gid,this.uname=e.uname,this.gname=e.gname,this.size=e.size,this.mtime=e.mtime,this.atime=e.atime,this.ctime=e.ctime,this.linkpath=YU(e.linkpath),this.uname=e.uname,this.gname=e.gname,r&&this[WU](r),o&&this[WU](o,!0)}write(e){let r=e.length;if(r>this.blockRemain)throw new Error(\"writing more to entry than is appropriate\");let o=this.remain,a=this.blockRemain;return this.remain=Math.max(0,o-r),this.blockRemain=Math.max(0,a-r),this.ignore?!0:o>=r?super.write(e):super.write(e.slice(0,o))}[WU](e,r){for(let o in e)e[o]!==null&&e[o]!==void 0&&!(r&&o===\"path\")&&(this[o]=o===\"path\"||o===\"linkpath\"?YU(e[o]):e[o])}}});var KU=_(nx=>{\"use strict\";nx.name=new Map([[\"0\",\"File\"],[\"\",\"OldFile\"],[\"1\",\"Link\"],[\"2\",\"SymbolicLink\"],[\"3\",\"CharacterDevice\"],[\"4\",\"BlockDevice\"],[\"5\",\"Directory\"],[\"6\",\"FIFO\"],[\"7\",\"ContiguousFile\"],[\"g\",\"GlobalExtendedHeader\"],[\"x\",\"ExtendedHeader\"],[\"A\",\"SolarisACL\"],[\"D\",\"GNUDumpDir\"],[\"I\",\"Inode\"],[\"K\",\"NextFileHasLongLinkpath\"],[\"L\",\"NextFileHasLongPath\"],[\"M\",\"ContinuationFile\"],[\"N\",\"OldGnuLongPath\"],[\"S\",\"SparseFile\"],[\"V\",\"TapeVolumeHeader\"],[\"X\",\"OldExtendedHeader\"]]);nx.code=new Map(Array.from(nx.name).map(t=>[t[1],t[0]]))});var Pue=_((K4t,Due)=>{\"use strict\";var Uat=(t,e)=>{if(Number.isSafeInteger(t))t<0?Hat(t,e):_at(t,e);else throw Error(\"cannot encode number outside of javascript safe integer range\");return e},_at=(t,e)=>{e[0]=128;for(var r=e.length;r>1;r--)e[r-1]=t&255,t=Math.floor(t/256)},Hat=(t,e)=>{e[0]=255;var r=!1;t=t*-1;for(var o=e.length;o>1;o--){var a=t&255;t=Math.floor(t/256),r?e[o-1]=Bue(a):a===0?e[o-1]=0:(r=!0,e[o-1]=vue(a))}},qat=t=>{let e=t[0],r=e===128?jat(t.slice(1,t.length)):e===255?Gat(t):null;if(r===null)throw Error(\"invalid base256 encoding\");if(!Number.isSafeInteger(r))throw Error(\"parsed number outside of javascript safe integer range\");return r},Gat=t=>{for(var e=t.length,r=0,o=!1,a=e-1;a>-1;a--){var n=t[a],u;o?u=Bue(n):n===0?u=n:(o=!0,u=vue(n)),u!==0&&(r-=u*Math.pow(256,e-a-1))}return r},jat=t=>{for(var e=t.length,r=0,o=e-1;o>-1;o--){var a=t[o];a!==0&&(r+=a*Math.pow(256,e-o-1))}return r},Bue=t=>(255^t)&255,vue=t=>(255^t)+1&255;Due.exports={encode:Uat,parse:qat}});var jE=_((z4t,bue)=>{\"use strict\";var zU=KU(),GE=ve(\"path\").posix,Sue=Pue(),VU=Symbol(\"slurp\"),Al=Symbol(\"type\"),ZU=class{constructor(e,r,o,a){this.cksumValid=!1,this.needPax=!1,this.nullBlock=!1,this.block=null,this.path=null,this.mode=null,this.uid=null,this.gid=null,this.size=null,this.mtime=null,this.cksum=null,this[Al]=\"0\",this.linkpath=null,this.uname=null,this.gname=null,this.devmaj=0,this.devmin=0,this.atime=null,this.ctime=null,Buffer.isBuffer(e)?this.decode(e,r||0,o,a):e&&this.set(e)}decode(e,r,o,a){if(r||(r=0),!e||!(e.length>=r+512))throw new Error(\"need 512 bytes for header\");if(this.path=Ld(e,r,100),this.mode=mh(e,r+100,8),this.uid=mh(e,r+108,8),this.gid=mh(e,r+116,8),this.size=mh(e,r+124,12),this.mtime=JU(e,r+136,12),this.cksum=mh(e,r+148,12),this[VU](o),this[VU](a,!0),this[Al]=Ld(e,r+156,1),this[Al]===\"\"&&(this[Al]=\"0\"),this[Al]===\"0\"&&this.path.substr(-1)===\"/\"&&(this[Al]=\"5\"),this[Al]===\"5\"&&(this.size=0),this.linkpath=Ld(e,r+157,100),e.slice(r+257,r+265).toString()===\"ustar\\x0000\")if(this.uname=Ld(e,r+265,32),this.gname=Ld(e,r+297,32),this.devmaj=mh(e,r+329,8),this.devmin=mh(e,r+337,8),e[r+475]!==0){let u=Ld(e,r+345,155);this.path=u+\"/\"+this.path}else{let u=Ld(e,r+345,130);u&&(this.path=u+\"/\"+this.path),this.atime=JU(e,r+476,12),this.ctime=JU(e,r+488,12)}let n=8*32;for(let u=r;u<r+148;u++)n+=e[u];for(let u=r+156;u<r+512;u++)n+=e[u];this.cksumValid=n===this.cksum,this.cksum===null&&n===8*32&&(this.nullBlock=!0)}[VU](e,r){for(let o in e)e[o]!==null&&e[o]!==void 0&&!(r&&o===\"path\")&&(this[o]=e[o])}encode(e,r){if(e||(e=this.block=Buffer.alloc(512),r=0),r||(r=0),!(e.length>=r+512))throw new Error(\"need 512 bytes for header\");let o=this.ctime||this.atime?130:155,a=Yat(this.path||\"\",o),n=a[0],u=a[1];this.needPax=a[2],this.needPax=Nd(e,r,100,n)||this.needPax,this.needPax=yh(e,r+100,8,this.mode)||this.needPax,this.needPax=yh(e,r+108,8,this.uid)||this.needPax,this.needPax=yh(e,r+116,8,this.gid)||this.needPax,this.needPax=yh(e,r+124,12,this.size)||this.needPax,this.needPax=XU(e,r+136,12,this.mtime)||this.needPax,e[r+156]=this[Al].charCodeAt(0),this.needPax=Nd(e,r+157,100,this.linkpath)||this.needPax,e.write(\"ustar\\x0000\",r+257,8),this.needPax=Nd(e,r+265,32,this.uname)||this.needPax,this.needPax=Nd(e,r+297,32,this.gname)||this.needPax,this.needPax=yh(e,r+329,8,this.devmaj)||this.needPax,this.needPax=yh(e,r+337,8,this.devmin)||this.needPax,this.needPax=Nd(e,r+345,o,u)||this.needPax,e[r+475]!==0?this.needPax=Nd(e,r+345,155,u)||this.needPax:(this.needPax=Nd(e,r+345,130,u)||this.needPax,this.needPax=XU(e,r+476,12,this.atime)||this.needPax,this.needPax=XU(e,r+488,12,this.ctime)||this.needPax);let A=8*32;for(let p=r;p<r+148;p++)A+=e[p];for(let p=r+156;p<r+512;p++)A+=e[p];return this.cksum=A,yh(e,r+148,8,this.cksum),this.cksumValid=!0,this.needPax}set(e){for(let r in e)e[r]!==null&&e[r]!==void 0&&(this[r]=e[r])}get type(){return zU.name.get(this[Al])||this[Al]}get typeKey(){return this[Al]}set type(e){zU.code.has(e)?this[Al]=zU.code.get(e):this[Al]=e}},Yat=(t,e)=>{let o=t,a=\"\",n,u=GE.parse(t).root||\".\";if(Buffer.byteLength(o)<100)n=[o,a,!1];else{a=GE.dirname(o),o=GE.basename(o);do Buffer.byteLength(o)<=100&&Buffer.byteLength(a)<=e?n=[o,a,!1]:Buffer.byteLength(o)>100&&Buffer.byteLength(a)<=e?n=[o.substr(0,100-1),a,!0]:(o=GE.join(GE.basename(a),o),a=GE.dirname(a));while(a!==u&&!n);n||(n=[t.substr(0,100-1),\"\",!0])}return n},Ld=(t,e,r)=>t.slice(e,e+r).toString(\"utf8\").replace(/\\0.*/,\"\"),JU=(t,e,r)=>Wat(mh(t,e,r)),Wat=t=>t===null?null:new Date(t*1e3),mh=(t,e,r)=>t[e]&128?Sue.parse(t.slice(e,e+r)):zat(t,e,r),Kat=t=>isNaN(t)?null:t,zat=(t,e,r)=>Kat(parseInt(t.slice(e,e+r).toString(\"utf8\").replace(/\\0.*$/,\"\").trim(),8)),Vat={12:8589934591,8:2097151},yh=(t,e,r,o)=>o===null?!1:o>Vat[r]||o<0?(Sue.encode(o,t.slice(e,e+r)),!0):(Jat(t,e,r,o),!1),Jat=(t,e,r,o)=>t.write(Xat(o,r),e,r,\"ascii\"),Xat=(t,e)=>Zat(Math.floor(t).toString(8),e),Zat=(t,e)=>(t.length===e-1?t:new Array(e-t.length-1).join(\"0\")+t+\" \")+\"\\0\",XU=(t,e,r,o)=>o===null?!1:yh(t,e,r,o.getTime()/1e3),$at=new Array(156).join(\"\\0\"),Nd=(t,e,r,o)=>o===null?!1:(t.write(o+$at,e,r,\"utf8\"),o.length!==Buffer.byteLength(o)||o.length>r);bue.exports=ZU});var ix=_((V4t,xue)=>{\"use strict\";var elt=jE(),tlt=ve(\"path\"),G1=class{constructor(e,r){this.atime=e.atime||null,this.charset=e.charset||null,this.comment=e.comment||null,this.ctime=e.ctime||null,this.gid=e.gid||null,this.gname=e.gname||null,this.linkpath=e.linkpath||null,this.mtime=e.mtime||null,this.path=e.path||null,this.size=e.size||null,this.uid=e.uid||null,this.uname=e.uname||null,this.dev=e.dev||null,this.ino=e.ino||null,this.nlink=e.nlink||null,this.global=r||!1}encode(){let e=this.encodeBody();if(e===\"\")return null;let r=Buffer.byteLength(e),o=512*Math.ceil(1+r/512),a=Buffer.allocUnsafe(o);for(let n=0;n<512;n++)a[n]=0;new elt({path:(\"PaxHeader/\"+tlt.basename(this.path)).slice(0,99),mode:this.mode||420,uid:this.uid||null,gid:this.gid||null,size:r,mtime:this.mtime||null,type:this.global?\"GlobalExtendedHeader\":\"ExtendedHeader\",linkpath:\"\",uname:this.uname||\"\",gname:this.gname||\"\",devmaj:0,devmin:0,atime:this.atime||null,ctime:this.ctime||null}).encode(a),a.write(e,512,r,\"utf8\");for(let n=r+512;n<a.length;n++)a[n]=0;return a}encodeBody(){return this.encodeField(\"path\")+this.encodeField(\"ctime\")+this.encodeField(\"atime\")+this.encodeField(\"dev\")+this.encodeField(\"ino\")+this.encodeField(\"nlink\")+this.encodeField(\"charset\")+this.encodeField(\"comment\")+this.encodeField(\"gid\")+this.encodeField(\"gname\")+this.encodeField(\"linkpath\")+this.encodeField(\"mtime\")+this.encodeField(\"size\")+this.encodeField(\"uid\")+this.encodeField(\"uname\")}encodeField(e){if(this[e]===null||this[e]===void 0)return\"\";let r=this[e]instanceof Date?this[e].getTime()/1e3:this[e],o=\" \"+(e===\"dev\"||e===\"ino\"||e===\"nlink\"?\"SCHILY.\":\"\")+e+\"=\"+r+`\n`,a=Buffer.byteLength(o),n=Math.floor(Math.log(a)/Math.log(10))+1;return a+n>=Math.pow(10,n)&&(n+=1),n+a+o}};G1.parse=(t,e,r)=>new G1(rlt(nlt(t),e),r);var rlt=(t,e)=>e?Object.keys(t).reduce((r,o)=>(r[o]=t[o],r),e):t,nlt=t=>t.replace(/\\n$/,\"\").split(`\n`).reduce(ilt,Object.create(null)),ilt=(t,e)=>{let r=parseInt(e,10);if(r!==Buffer.byteLength(e)+1)return t;e=e.substr((r+\" \").length);let o=e.split(\"=\"),a=o.shift().replace(/^SCHILY\\.(dev|ino|nlink)/,\"$1\");if(!a)return t;let n=o.join(\"=\");return t[a]=/^([A-Z]+\\.)?([mac]|birth|creation)time$/.test(a)?new Date(n*1e3):/^[0-9]+$/.test(n)?+n:n,t};xue.exports=G1});var YE=_((J4t,kue)=>{kue.exports=t=>{let e=t.length-1,r=-1;for(;e>-1&&t.charAt(e)===\"/\";)r=e,e--;return r===-1?t:t.slice(0,r)}});var sx=_((X4t,Que)=>{\"use strict\";Que.exports=t=>class extends t{warn(e,r,o={}){this.file&&(o.file=this.file),this.cwd&&(o.cwd=this.cwd),o.code=r instanceof Error&&r.code||e,o.tarCode=e,!this.strict&&o.recoverable!==!1?(r instanceof Error&&(o=Object.assign(r,o),r=r.message),this.emit(\"warn\",o.tarCode,r,o)):r instanceof Error?this.emit(\"error\",Object.assign(r,o)):this.emit(\"error\",Object.assign(new Error(`${e}: ${r}`),o))}}});var e3=_(($4t,Fue)=>{\"use strict\";var ox=[\"|\",\"<\",\">\",\"?\",\":\"],$U=ox.map(t=>String.fromCharCode(61440+t.charCodeAt(0))),slt=new Map(ox.map((t,e)=>[t,$U[e]])),olt=new Map($U.map((t,e)=>[t,ox[e]]));Fue.exports={encode:t=>ox.reduce((e,r)=>e.split(r).join(slt.get(r)),t),decode:t=>$U.reduce((e,r)=>e.split(r).join(olt.get(r)),t)}});var t3=_((eUt,Tue)=>{var{isAbsolute:alt,parse:Rue}=ve(\"path\").win32;Tue.exports=t=>{let e=\"\",r=Rue(t);for(;alt(t)||r.root;){let o=t.charAt(0)===\"/\"&&t.slice(0,4)!==\"//?/\"?\"/\":r.root;t=t.substr(o.length),e+=o,r=Rue(t)}return[e,t]}});var Nue=_((tUt,Lue)=>{\"use strict\";Lue.exports=(t,e,r)=>(t&=4095,r&&(t=(t|384)&-19),e&&(t&256&&(t|=64),t&32&&(t|=8),t&4&&(t|=1)),t)});var A3=_((iUt,Jue)=>{\"use strict\";var Gue=UE(),jue=ix(),Yue=jE(),aA=ve(\"fs\"),Oue=ve(\"path\"),oA=qE(),llt=YE(),Wue=(t,e)=>e?(t=oA(t).replace(/^\\.(\\/|$)/,\"\"),llt(e)+\"/\"+t):oA(t),clt=16*1024*1024,Mue=Symbol(\"process\"),Uue=Symbol(\"file\"),_ue=Symbol(\"directory\"),n3=Symbol(\"symlink\"),Hue=Symbol(\"hardlink\"),j1=Symbol(\"header\"),ax=Symbol(\"read\"),i3=Symbol(\"lstat\"),lx=Symbol(\"onlstat\"),s3=Symbol(\"onread\"),o3=Symbol(\"onreadlink\"),a3=Symbol(\"openfile\"),l3=Symbol(\"onopenfile\"),Eh=Symbol(\"close\"),cx=Symbol(\"mode\"),c3=Symbol(\"awaitDrain\"),r3=Symbol(\"ondrain\"),lA=Symbol(\"prefix\"),que=Symbol(\"hadError\"),Kue=sx(),ult=e3(),zue=t3(),Vue=Nue(),ux=Kue(class extends Gue{constructor(e,r){if(r=r||{},super(r),typeof e!=\"string\")throw new TypeError(\"path is required\");this.path=oA(e),this.portable=!!r.portable,this.myuid=process.getuid&&process.getuid()||0,this.myuser=process.env.USER||\"\",this.maxReadSize=r.maxReadSize||clt,this.linkCache=r.linkCache||new Map,this.statCache=r.statCache||new Map,this.preservePaths=!!r.preservePaths,this.cwd=oA(r.cwd||process.cwd()),this.strict=!!r.strict,this.noPax=!!r.noPax,this.noMtime=!!r.noMtime,this.mtime=r.mtime||null,this.prefix=r.prefix?oA(r.prefix):null,this.fd=null,this.blockLen=null,this.blockRemain=null,this.buf=null,this.offset=null,this.length=null,this.pos=null,this.remain=null,typeof r.onwarn==\"function\"&&this.on(\"warn\",r.onwarn);let o=!1;if(!this.preservePaths){let[a,n]=zue(this.path);a&&(this.path=n,o=a)}this.win32=!!r.win32||process.platform===\"win32\",this.win32&&(this.path=ult.decode(this.path.replace(/\\\\/g,\"/\")),e=e.replace(/\\\\/g,\"/\")),this.absolute=oA(r.absolute||Oue.resolve(this.cwd,e)),this.path===\"\"&&(this.path=\"./\"),o&&this.warn(\"TAR_ENTRY_INFO\",`stripping ${o} from absolute path`,{entry:this,path:o+this.path}),this.statCache.has(this.absolute)?this[lx](this.statCache.get(this.absolute)):this[i3]()}emit(e,...r){return e===\"error\"&&(this[que]=!0),super.emit(e,...r)}[i3](){aA.lstat(this.absolute,(e,r)=>{if(e)return this.emit(\"error\",e);this[lx](r)})}[lx](e){this.statCache.set(this.absolute,e),this.stat=e,e.isFile()||(e.size=0),this.type=flt(e),this.emit(\"stat\",e),this[Mue]()}[Mue](){switch(this.type){case\"File\":return this[Uue]();case\"Directory\":return this[_ue]();case\"SymbolicLink\":return this[n3]();default:return this.end()}}[cx](e){return Vue(e,this.type===\"Directory\",this.portable)}[lA](e){return Wue(e,this.prefix)}[j1](){this.type===\"Directory\"&&this.portable&&(this.noMtime=!0),this.header=new Yue({path:this[lA](this.path),linkpath:this.type===\"Link\"?this[lA](this.linkpath):this.linkpath,mode:this[cx](this.stat.mode),uid:this.portable?null:this.stat.uid,gid:this.portable?null:this.stat.gid,size:this.stat.size,mtime:this.noMtime?null:this.mtime||this.stat.mtime,type:this.type,uname:this.portable?null:this.stat.uid===this.myuid?this.myuser:\"\",atime:this.portable?null:this.stat.atime,ctime:this.portable?null:this.stat.ctime}),this.header.encode()&&!this.noPax&&super.write(new jue({atime:this.portable?null:this.header.atime,ctime:this.portable?null:this.header.ctime,gid:this.portable?null:this.header.gid,mtime:this.noMtime?null:this.mtime||this.header.mtime,path:this[lA](this.path),linkpath:this.type===\"Link\"?this[lA](this.linkpath):this.linkpath,size:this.header.size,uid:this.portable?null:this.header.uid,uname:this.portable?null:this.header.uname,dev:this.portable?null:this.stat.dev,ino:this.portable?null:this.stat.ino,nlink:this.portable?null:this.stat.nlink}).encode()),super.write(this.header.block)}[_ue](){this.path.substr(-1)!==\"/\"&&(this.path+=\"/\"),this.stat.size=0,this[j1](),this.end()}[n3](){aA.readlink(this.absolute,(e,r)=>{if(e)return this.emit(\"error\",e);this[o3](r)})}[o3](e){this.linkpath=oA(e),this[j1](),this.end()}[Hue](e){this.type=\"Link\",this.linkpath=oA(Oue.relative(this.cwd,e)),this.stat.size=0,this[j1](),this.end()}[Uue](){if(this.stat.nlink>1){let e=this.stat.dev+\":\"+this.stat.ino;if(this.linkCache.has(e)){let r=this.linkCache.get(e);if(r.indexOf(this.cwd)===0)return this[Hue](r)}this.linkCache.set(e,this.absolute)}if(this[j1](),this.stat.size===0)return this.end();this[a3]()}[a3](){aA.open(this.absolute,\"r\",(e,r)=>{if(e)return this.emit(\"error\",e);this[l3](r)})}[l3](e){if(this.fd=e,this[que])return this[Eh]();this.blockLen=512*Math.ceil(this.stat.size/512),this.blockRemain=this.blockLen;let r=Math.min(this.blockLen,this.maxReadSize);this.buf=Buffer.allocUnsafe(r),this.offset=0,this.pos=0,this.remain=this.stat.size,this.length=this.buf.length,this[ax]()}[ax](){let{fd:e,buf:r,offset:o,length:a,pos:n}=this;aA.read(e,r,o,a,n,(u,A)=>{if(u)return this[Eh](()=>this.emit(\"error\",u));this[s3](A)})}[Eh](e){aA.close(this.fd,e)}[s3](e){if(e<=0&&this.remain>0){let a=new Error(\"encountered unexpected EOF\");return a.path=this.absolute,a.syscall=\"read\",a.code=\"EOF\",this[Eh](()=>this.emit(\"error\",a))}if(e>this.remain){let a=new Error(\"did not encounter expected EOF\");return a.path=this.absolute,a.syscall=\"read\",a.code=\"EOF\",this[Eh](()=>this.emit(\"error\",a))}if(e===this.remain)for(let a=e;a<this.length&&e<this.blockRemain;a++)this.buf[a+this.offset]=0,e++,this.remain++;let r=this.offset===0&&e===this.buf.length?this.buf:this.buf.slice(this.offset,this.offset+e);this.write(r)?this[r3]():this[c3](()=>this[r3]())}[c3](e){this.once(\"drain\",e)}write(e){if(this.blockRemain<e.length){let r=new Error(\"writing more data than expected\");return r.path=this.absolute,this.emit(\"error\",r)}return this.remain-=e.length,this.blockRemain-=e.length,this.pos+=e.length,this.offset+=e.length,super.write(e)}[r3](){if(!this.remain)return this.blockRemain&&super.write(Buffer.alloc(this.blockRemain)),this[Eh](e=>e?this.emit(\"error\",e):this.end());this.offset>=this.length&&(this.buf=Buffer.allocUnsafe(Math.min(this.blockRemain,this.buf.length)),this.offset=0),this.length=this.buf.length-this.offset,this[ax]()}}),u3=class extends ux{[i3](){this[lx](aA.lstatSync(this.absolute))}[n3](){this[o3](aA.readlinkSync(this.absolute))}[a3](){this[l3](aA.openSync(this.absolute,\"r\"))}[ax](){let e=!0;try{let{fd:r,buf:o,offset:a,length:n,pos:u}=this,A=aA.readSync(r,o,a,n,u);this[s3](A),e=!1}finally{if(e)try{this[Eh](()=>{})}catch{}}}[c3](e){e()}[Eh](e){aA.closeSync(this.fd),e()}},Alt=Kue(class extends Gue{constructor(e,r){r=r||{},super(r),this.preservePaths=!!r.preservePaths,this.portable=!!r.portable,this.strict=!!r.strict,this.noPax=!!r.noPax,this.noMtime=!!r.noMtime,this.readEntry=e,this.type=e.type,this.type===\"Directory\"&&this.portable&&(this.noMtime=!0),this.prefix=r.prefix||null,this.path=oA(e.path),this.mode=this[cx](e.mode),this.uid=this.portable?null:e.uid,this.gid=this.portable?null:e.gid,this.uname=this.portable?null:e.uname,this.gname=this.portable?null:e.gname,this.size=e.size,this.mtime=this.noMtime?null:r.mtime||e.mtime,this.atime=this.portable?null:e.atime,this.ctime=this.portable?null:e.ctime,this.linkpath=oA(e.linkpath),typeof r.onwarn==\"function\"&&this.on(\"warn\",r.onwarn);let o=!1;if(!this.preservePaths){let[a,n]=zue(this.path);a&&(this.path=n,o=a)}this.remain=e.size,this.blockRemain=e.startBlockSize,this.header=new Yue({path:this[lA](this.path),linkpath:this.type===\"Link\"?this[lA](this.linkpath):this.linkpath,mode:this.mode,uid:this.portable?null:this.uid,gid:this.portable?null:this.gid,size:this.size,mtime:this.noMtime?null:this.mtime,type:this.type,uname:this.portable?null:this.uname,atime:this.portable?null:this.atime,ctime:this.portable?null:this.ctime}),o&&this.warn(\"TAR_ENTRY_INFO\",`stripping ${o} from absolute path`,{entry:this,path:o+this.path}),this.header.encode()&&!this.noPax&&super.write(new jue({atime:this.portable?null:this.atime,ctime:this.portable?null:this.ctime,gid:this.portable?null:this.gid,mtime:this.noMtime?null:this.mtime,path:this[lA](this.path),linkpath:this.type===\"Link\"?this[lA](this.linkpath):this.linkpath,size:this.size,uid:this.portable?null:this.uid,uname:this.portable?null:this.uname,dev:this.portable?null:this.readEntry.dev,ino:this.portable?null:this.readEntry.ino,nlink:this.portable?null:this.readEntry.nlink}).encode()),super.write(this.header.block),e.pipe(this)}[lA](e){return Wue(e,this.prefix)}[cx](e){return Vue(e,this.type===\"Directory\",this.portable)}write(e){let r=e.length;if(r>this.blockRemain)throw new Error(\"writing more to entry than is appropriate\");return this.blockRemain-=r,super.write(e)}end(){return this.blockRemain&&super.write(Buffer.alloc(this.blockRemain)),super.end()}});ux.Sync=u3;ux.Tar=Alt;var flt=t=>t.isFile()?\"File\":t.isDirectory()?\"Directory\":t.isSymbolicLink()?\"SymbolicLink\":\"Unsupported\";Jue.exports=ux});var Ex=_((oUt,nAe)=>{\"use strict\";var mx=class{constructor(e,r){this.path=e||\"./\",this.absolute=r,this.entry=null,this.stat=null,this.readdir=null,this.pending=!1,this.ignore=!1,this.piped=!1}},plt=UE(),hlt=jU(),glt=rx(),C3=A3(),dlt=C3.Sync,mlt=C3.Tar,ylt=IP(),Xue=Buffer.alloc(1024),px=Symbol(\"onStat\"),Ax=Symbol(\"ended\"),cA=Symbol(\"queue\"),WE=Symbol(\"current\"),Od=Symbol(\"process\"),fx=Symbol(\"processing\"),Zue=Symbol(\"processJob\"),uA=Symbol(\"jobs\"),f3=Symbol(\"jobDone\"),hx=Symbol(\"addFSEntry\"),$ue=Symbol(\"addTarEntry\"),d3=Symbol(\"stat\"),m3=Symbol(\"readdir\"),gx=Symbol(\"onreaddir\"),dx=Symbol(\"pipe\"),eAe=Symbol(\"entry\"),p3=Symbol(\"entryOpt\"),y3=Symbol(\"writeEntryClass\"),rAe=Symbol(\"write\"),h3=Symbol(\"ondrain\"),yx=ve(\"fs\"),tAe=ve(\"path\"),Elt=sx(),g3=qE(),w3=Elt(class extends plt{constructor(e){super(e),e=e||Object.create(null),this.opt=e,this.file=e.file||\"\",this.cwd=e.cwd||process.cwd(),this.maxReadSize=e.maxReadSize,this.preservePaths=!!e.preservePaths,this.strict=!!e.strict,this.noPax=!!e.noPax,this.prefix=g3(e.prefix||\"\"),this.linkCache=e.linkCache||new Map,this.statCache=e.statCache||new Map,this.readdirCache=e.readdirCache||new Map,this[y3]=C3,typeof e.onwarn==\"function\"&&this.on(\"warn\",e.onwarn),this.portable=!!e.portable,this.zip=null,e.gzip?(typeof e.gzip!=\"object\"&&(e.gzip={}),this.portable&&(e.gzip.portable=!0),this.zip=new hlt.Gzip(e.gzip),this.zip.on(\"data\",r=>super.write(r)),this.zip.on(\"end\",r=>super.end()),this.zip.on(\"drain\",r=>this[h3]()),this.on(\"resume\",r=>this.zip.resume())):this.on(\"drain\",this[h3]),this.noDirRecurse=!!e.noDirRecurse,this.follow=!!e.follow,this.noMtime=!!e.noMtime,this.mtime=e.mtime||null,this.filter=typeof e.filter==\"function\"?e.filter:r=>!0,this[cA]=new ylt,this[uA]=0,this.jobs=+e.jobs||4,this[fx]=!1,this[Ax]=!1}[rAe](e){return super.write(e)}add(e){return this.write(e),this}end(e){return e&&this.write(e),this[Ax]=!0,this[Od](),this}write(e){if(this[Ax])throw new Error(\"write after end\");return e instanceof glt?this[$ue](e):this[hx](e),this.flowing}[$ue](e){let r=g3(tAe.resolve(this.cwd,e.path));if(!this.filter(e.path,e))e.resume();else{let o=new mx(e.path,r,!1);o.entry=new mlt(e,this[p3](o)),o.entry.on(\"end\",a=>this[f3](o)),this[uA]+=1,this[cA].push(o)}this[Od]()}[hx](e){let r=g3(tAe.resolve(this.cwd,e));this[cA].push(new mx(e,r)),this[Od]()}[d3](e){e.pending=!0,this[uA]+=1;let r=this.follow?\"stat\":\"lstat\";yx[r](e.absolute,(o,a)=>{e.pending=!1,this[uA]-=1,o?this.emit(\"error\",o):this[px](e,a)})}[px](e,r){this.statCache.set(e.absolute,r),e.stat=r,this.filter(e.path,r)||(e.ignore=!0),this[Od]()}[m3](e){e.pending=!0,this[uA]+=1,yx.readdir(e.absolute,(r,o)=>{if(e.pending=!1,this[uA]-=1,r)return this.emit(\"error\",r);this[gx](e,o)})}[gx](e,r){this.readdirCache.set(e.absolute,r),e.readdir=r,this[Od]()}[Od](){if(!this[fx]){this[fx]=!0;for(let e=this[cA].head;e!==null&&this[uA]<this.jobs;e=e.next)if(this[Zue](e.value),e.value.ignore){let r=e.next;this[cA].removeNode(e),e.next=r}this[fx]=!1,this[Ax]&&!this[cA].length&&this[uA]===0&&(this.zip?this.zip.end(Xue):(super.write(Xue),super.end()))}}get[WE](){return this[cA]&&this[cA].head&&this[cA].head.value}[f3](e){this[cA].shift(),this[uA]-=1,this[Od]()}[Zue](e){if(!e.pending){if(e.entry){e===this[WE]&&!e.piped&&this[dx](e);return}if(e.stat||(this.statCache.has(e.absolute)?this[px](e,this.statCache.get(e.absolute)):this[d3](e)),!!e.stat&&!e.ignore&&!(!this.noDirRecurse&&e.stat.isDirectory()&&!e.readdir&&(this.readdirCache.has(e.absolute)?this[gx](e,this.readdirCache.get(e.absolute)):this[m3](e),!e.readdir))){if(e.entry=this[eAe](e),!e.entry){e.ignore=!0;return}e===this[WE]&&!e.piped&&this[dx](e)}}}[p3](e){return{onwarn:(r,o,a)=>this.warn(r,o,a),noPax:this.noPax,cwd:this.cwd,absolute:e.absolute,preservePaths:this.preservePaths,maxReadSize:this.maxReadSize,strict:this.strict,portable:this.portable,linkCache:this.linkCache,statCache:this.statCache,noMtime:this.noMtime,mtime:this.mtime,prefix:this.prefix}}[eAe](e){this[uA]+=1;try{return new this[y3](e.path,this[p3](e)).on(\"end\",()=>this[f3](e)).on(\"error\",r=>this.emit(\"error\",r))}catch(r){this.emit(\"error\",r)}}[h3](){this[WE]&&this[WE].entry&&this[WE].entry.resume()}[dx](e){e.piped=!0,e.readdir&&e.readdir.forEach(a=>{let n=e.path,u=n===\"./\"?\"\":n.replace(/\\/*$/,\"/\");this[hx](u+a)});let r=e.entry,o=this.zip;o?r.on(\"data\",a=>{o.write(a)||r.pause()}):r.on(\"data\",a=>{super.write(a)||r.pause()})}pause(){return this.zip&&this.zip.pause(),super.pause()}}),E3=class extends w3{constructor(e){super(e),this[y3]=dlt}pause(){}resume(){}[d3](e){let r=this.follow?\"statSync\":\"lstatSync\";this[px](e,yx[r](e.absolute))}[m3](e,r){this[gx](e,yx.readdirSync(e.absolute))}[dx](e){let r=e.entry,o=this.zip;e.readdir&&e.readdir.forEach(a=>{let n=e.path,u=n===\"./\"?\"\":n.replace(/\\/*$/,\"/\");this[hx](u+a)}),o?r.on(\"data\",a=>{o.write(a)}):r.on(\"data\",a=>{super[rAe](a)})}};w3.Sync=E3;nAe.exports=w3});var eC=_(W1=>{\"use strict\";var Clt=UE(),wlt=ve(\"events\").EventEmitter,Qa=ve(\"fs\"),v3=Qa.writev;if(!v3){let t=process.binding(\"fs\"),e=t.FSReqWrap||t.FSReqCallback;v3=(r,o,a,n)=>{let u=(p,h)=>n(p,h,o),A=new e;A.oncomplete=u,t.writeBuffers(r,o,a,A)}}var ZE=Symbol(\"_autoClose\"),Wc=Symbol(\"_close\"),Y1=Symbol(\"_ended\"),jn=Symbol(\"_fd\"),iAe=Symbol(\"_finished\"),wh=Symbol(\"_flags\"),I3=Symbol(\"_flush\"),D3=Symbol(\"_handleChunk\"),P3=Symbol(\"_makeBuf\"),vx=Symbol(\"_mode\"),Cx=Symbol(\"_needDrain\"),JE=Symbol(\"_onerror\"),$E=Symbol(\"_onopen\"),B3=Symbol(\"_onread\"),zE=Symbol(\"_onwrite\"),Ih=Symbol(\"_open\"),Gf=Symbol(\"_path\"),Md=Symbol(\"_pos\"),AA=Symbol(\"_queue\"),VE=Symbol(\"_read\"),sAe=Symbol(\"_readSize\"),Ch=Symbol(\"_reading\"),wx=Symbol(\"_remain\"),oAe=Symbol(\"_size\"),Ix=Symbol(\"_write\"),KE=Symbol(\"_writing\"),Bx=Symbol(\"_defaultFlag\"),XE=Symbol(\"_errored\"),Dx=class extends Clt{constructor(e,r){if(r=r||{},super(r),this.readable=!0,this.writable=!1,typeof e!=\"string\")throw new TypeError(\"path must be a string\");this[XE]=!1,this[jn]=typeof r.fd==\"number\"?r.fd:null,this[Gf]=e,this[sAe]=r.readSize||16*1024*1024,this[Ch]=!1,this[oAe]=typeof r.size==\"number\"?r.size:1/0,this[wx]=this[oAe],this[ZE]=typeof r.autoClose==\"boolean\"?r.autoClose:!0,typeof this[jn]==\"number\"?this[VE]():this[Ih]()}get fd(){return this[jn]}get path(){return this[Gf]}write(){throw new TypeError(\"this is a readable stream\")}end(){throw new TypeError(\"this is a readable stream\")}[Ih](){Qa.open(this[Gf],\"r\",(e,r)=>this[$E](e,r))}[$E](e,r){e?this[JE](e):(this[jn]=r,this.emit(\"open\",r),this[VE]())}[P3](){return Buffer.allocUnsafe(Math.min(this[sAe],this[wx]))}[VE](){if(!this[Ch]){this[Ch]=!0;let e=this[P3]();if(e.length===0)return process.nextTick(()=>this[B3](null,0,e));Qa.read(this[jn],e,0,e.length,null,(r,o,a)=>this[B3](r,o,a))}}[B3](e,r,o){this[Ch]=!1,e?this[JE](e):this[D3](r,o)&&this[VE]()}[Wc](){if(this[ZE]&&typeof this[jn]==\"number\"){let e=this[jn];this[jn]=null,Qa.close(e,r=>r?this.emit(\"error\",r):this.emit(\"close\"))}}[JE](e){this[Ch]=!0,this[Wc](),this.emit(\"error\",e)}[D3](e,r){let o=!1;return this[wx]-=e,e>0&&(o=super.write(e<r.length?r.slice(0,e):r)),(e===0||this[wx]<=0)&&(o=!1,this[Wc](),super.end()),o}emit(e,r){switch(e){case\"prefinish\":case\"finish\":break;case\"drain\":typeof this[jn]==\"number\"&&this[VE]();break;case\"error\":return this[XE]?void 0:(this[XE]=!0,super.emit(e,r));default:return super.emit(e,r)}}},S3=class extends Dx{[Ih](){let e=!0;try{this[$E](null,Qa.openSync(this[Gf],\"r\")),e=!1}finally{e&&this[Wc]()}}[VE](){let e=!0;try{if(!this[Ch]){this[Ch]=!0;do{let r=this[P3](),o=r.length===0?0:Qa.readSync(this[jn],r,0,r.length,null);if(!this[D3](o,r))break}while(!0);this[Ch]=!1}e=!1}finally{e&&this[Wc]()}}[Wc](){if(this[ZE]&&typeof this[jn]==\"number\"){let e=this[jn];this[jn]=null,Qa.closeSync(e),this.emit(\"close\")}}},Px=class extends wlt{constructor(e,r){r=r||{},super(r),this.readable=!1,this.writable=!0,this[XE]=!1,this[KE]=!1,this[Y1]=!1,this[Cx]=!1,this[AA]=[],this[Gf]=e,this[jn]=typeof r.fd==\"number\"?r.fd:null,this[vx]=r.mode===void 0?438:r.mode,this[Md]=typeof r.start==\"number\"?r.start:null,this[ZE]=typeof r.autoClose==\"boolean\"?r.autoClose:!0;let o=this[Md]!==null?\"r+\":\"w\";this[Bx]=r.flags===void 0,this[wh]=this[Bx]?o:r.flags,this[jn]===null&&this[Ih]()}emit(e,r){if(e===\"error\"){if(this[XE])return;this[XE]=!0}return super.emit(e,r)}get fd(){return this[jn]}get path(){return this[Gf]}[JE](e){this[Wc](),this[KE]=!0,this.emit(\"error\",e)}[Ih](){Qa.open(this[Gf],this[wh],this[vx],(e,r)=>this[$E](e,r))}[$E](e,r){this[Bx]&&this[wh]===\"r+\"&&e&&e.code===\"ENOENT\"?(this[wh]=\"w\",this[Ih]()):e?this[JE](e):(this[jn]=r,this.emit(\"open\",r),this[I3]())}end(e,r){return e&&this.write(e,r),this[Y1]=!0,!this[KE]&&!this[AA].length&&typeof this[jn]==\"number\"&&this[zE](null,0),this}write(e,r){return typeof e==\"string\"&&(e=Buffer.from(e,r)),this[Y1]?(this.emit(\"error\",new Error(\"write() after end()\")),!1):this[jn]===null||this[KE]||this[AA].length?(this[AA].push(e),this[Cx]=!0,!1):(this[KE]=!0,this[Ix](e),!0)}[Ix](e){Qa.write(this[jn],e,0,e.length,this[Md],(r,o)=>this[zE](r,o))}[zE](e,r){e?this[JE](e):(this[Md]!==null&&(this[Md]+=r),this[AA].length?this[I3]():(this[KE]=!1,this[Y1]&&!this[iAe]?(this[iAe]=!0,this[Wc](),this.emit(\"finish\")):this[Cx]&&(this[Cx]=!1,this.emit(\"drain\"))))}[I3](){if(this[AA].length===0)this[Y1]&&this[zE](null,0);else if(this[AA].length===1)this[Ix](this[AA].pop());else{let e=this[AA];this[AA]=[],v3(this[jn],e,this[Md],(r,o)=>this[zE](r,o))}}[Wc](){if(this[ZE]&&typeof this[jn]==\"number\"){let e=this[jn];this[jn]=null,Qa.close(e,r=>r?this.emit(\"error\",r):this.emit(\"close\"))}}},b3=class extends Px{[Ih](){let e;if(this[Bx]&&this[wh]===\"r+\")try{e=Qa.openSync(this[Gf],this[wh],this[vx])}catch(r){if(r.code===\"ENOENT\")return this[wh]=\"w\",this[Ih]();throw r}else e=Qa.openSync(this[Gf],this[wh],this[vx]);this[$E](null,e)}[Wc](){if(this[ZE]&&typeof this[jn]==\"number\"){let e=this[jn];this[jn]=null,Qa.closeSync(e),this.emit(\"close\")}}[Ix](e){let r=!0;try{this[zE](null,Qa.writeSync(this[jn],e,0,e.length,this[Md])),r=!1}finally{if(r)try{this[Wc]()}catch{}}}};W1.ReadStream=Dx;W1.ReadStreamSync=S3;W1.WriteStream=Px;W1.WriteStreamSync=b3});var Rx=_((cUt,pAe)=>{\"use strict\";var Ilt=sx(),Blt=jE(),vlt=ve(\"events\"),Dlt=IP(),Plt=1024*1024,Slt=rx(),aAe=ix(),blt=jU(),x3=Buffer.from([31,139]),Zl=Symbol(\"state\"),Ud=Symbol(\"writeEntry\"),jf=Symbol(\"readEntry\"),k3=Symbol(\"nextEntry\"),lAe=Symbol(\"processEntry\"),$l=Symbol(\"extendedHeader\"),K1=Symbol(\"globalExtendedHeader\"),Bh=Symbol(\"meta\"),cAe=Symbol(\"emitMeta\"),fi=Symbol(\"buffer\"),Yf=Symbol(\"queue\"),_d=Symbol(\"ended\"),uAe=Symbol(\"emittedEnd\"),Hd=Symbol(\"emit\"),Fa=Symbol(\"unzip\"),Sx=Symbol(\"consumeChunk\"),bx=Symbol(\"consumeChunkSub\"),Q3=Symbol(\"consumeBody\"),AAe=Symbol(\"consumeMeta\"),fAe=Symbol(\"consumeHeader\"),xx=Symbol(\"consuming\"),F3=Symbol(\"bufferConcat\"),R3=Symbol(\"maybeEnd\"),z1=Symbol(\"writing\"),vh=Symbol(\"aborted\"),kx=Symbol(\"onDone\"),qd=Symbol(\"sawValidEntry\"),Qx=Symbol(\"sawNullBlock\"),Fx=Symbol(\"sawEOF\"),xlt=t=>!0;pAe.exports=Ilt(class extends vlt{constructor(e){e=e||{},super(e),this.file=e.file||\"\",this[qd]=null,this.on(kx,r=>{(this[Zl]===\"begin\"||this[qd]===!1)&&this.warn(\"TAR_BAD_ARCHIVE\",\"Unrecognized archive format\")}),e.ondone?this.on(kx,e.ondone):this.on(kx,r=>{this.emit(\"prefinish\"),this.emit(\"finish\"),this.emit(\"end\"),this.emit(\"close\")}),this.strict=!!e.strict,this.maxMetaEntrySize=e.maxMetaEntrySize||Plt,this.filter=typeof e.filter==\"function\"?e.filter:xlt,this.writable=!0,this.readable=!1,this[Yf]=new Dlt,this[fi]=null,this[jf]=null,this[Ud]=null,this[Zl]=\"begin\",this[Bh]=\"\",this[$l]=null,this[K1]=null,this[_d]=!1,this[Fa]=null,this[vh]=!1,this[Qx]=!1,this[Fx]=!1,typeof e.onwarn==\"function\"&&this.on(\"warn\",e.onwarn),typeof e.onentry==\"function\"&&this.on(\"entry\",e.onentry)}[fAe](e,r){this[qd]===null&&(this[qd]=!1);let o;try{o=new Blt(e,r,this[$l],this[K1])}catch(a){return this.warn(\"TAR_ENTRY_INVALID\",a)}if(o.nullBlock)this[Qx]?(this[Fx]=!0,this[Zl]===\"begin\"&&(this[Zl]=\"header\"),this[Hd](\"eof\")):(this[Qx]=!0,this[Hd](\"nullBlock\"));else if(this[Qx]=!1,!o.cksumValid)this.warn(\"TAR_ENTRY_INVALID\",\"checksum failure\",{header:o});else if(!o.path)this.warn(\"TAR_ENTRY_INVALID\",\"path is required\",{header:o});else{let a=o.type;if(/^(Symbolic)?Link$/.test(a)&&!o.linkpath)this.warn(\"TAR_ENTRY_INVALID\",\"linkpath required\",{header:o});else if(!/^(Symbolic)?Link$/.test(a)&&o.linkpath)this.warn(\"TAR_ENTRY_INVALID\",\"linkpath forbidden\",{header:o});else{let n=this[Ud]=new Slt(o,this[$l],this[K1]);if(!this[qd])if(n.remain){let u=()=>{n.invalid||(this[qd]=!0)};n.on(\"end\",u)}else this[qd]=!0;n.meta?n.size>this.maxMetaEntrySize?(n.ignore=!0,this[Hd](\"ignoredEntry\",n),this[Zl]=\"ignore\",n.resume()):n.size>0&&(this[Bh]=\"\",n.on(\"data\",u=>this[Bh]+=u),this[Zl]=\"meta\"):(this[$l]=null,n.ignore=n.ignore||!this.filter(n.path,n),n.ignore?(this[Hd](\"ignoredEntry\",n),this[Zl]=n.remain?\"ignore\":\"header\",n.resume()):(n.remain?this[Zl]=\"body\":(this[Zl]=\"header\",n.end()),this[jf]?this[Yf].push(n):(this[Yf].push(n),this[k3]())))}}}[lAe](e){let r=!0;return e?Array.isArray(e)?this.emit.apply(this,e):(this[jf]=e,this.emit(\"entry\",e),e.emittedEnd||(e.on(\"end\",o=>this[k3]()),r=!1)):(this[jf]=null,r=!1),r}[k3](){do;while(this[lAe](this[Yf].shift()));if(!this[Yf].length){let e=this[jf];!e||e.flowing||e.size===e.remain?this[z1]||this.emit(\"drain\"):e.once(\"drain\",o=>this.emit(\"drain\"))}}[Q3](e,r){let o=this[Ud],a=o.blockRemain,n=a>=e.length&&r===0?e:e.slice(r,r+a);return o.write(n),o.blockRemain||(this[Zl]=\"header\",this[Ud]=null,o.end()),n.length}[AAe](e,r){let o=this[Ud],a=this[Q3](e,r);return this[Ud]||this[cAe](o),a}[Hd](e,r,o){!this[Yf].length&&!this[jf]?this.emit(e,r,o):this[Yf].push([e,r,o])}[cAe](e){switch(this[Hd](\"meta\",this[Bh]),e.type){case\"ExtendedHeader\":case\"OldExtendedHeader\":this[$l]=aAe.parse(this[Bh],this[$l],!1);break;case\"GlobalExtendedHeader\":this[K1]=aAe.parse(this[Bh],this[K1],!0);break;case\"NextFileHasLongPath\":case\"OldGnuLongPath\":this[$l]=this[$l]||Object.create(null),this[$l].path=this[Bh].replace(/\\0.*/,\"\");break;case\"NextFileHasLongLinkpath\":this[$l]=this[$l]||Object.create(null),this[$l].linkpath=this[Bh].replace(/\\0.*/,\"\");break;default:throw new Error(\"unknown meta: \"+e.type)}}abort(e){this[vh]=!0,this.emit(\"abort\",e),this.warn(\"TAR_ABORT\",e,{recoverable:!1})}write(e){if(this[vh])return;if(this[Fa]===null&&e){if(this[fi]&&(e=Buffer.concat([this[fi],e]),this[fi]=null),e.length<x3.length)return this[fi]=e,!0;for(let o=0;this[Fa]===null&&o<x3.length;o++)e[o]!==x3[o]&&(this[Fa]=!1);if(this[Fa]===null){let o=this[_d];this[_d]=!1,this[Fa]=new blt.Unzip,this[Fa].on(\"data\",n=>this[Sx](n)),this[Fa].on(\"error\",n=>this.abort(n)),this[Fa].on(\"end\",n=>{this[_d]=!0,this[Sx]()}),this[z1]=!0;let a=this[Fa][o?\"end\":\"write\"](e);return this[z1]=!1,a}}this[z1]=!0,this[Fa]?this[Fa].write(e):this[Sx](e),this[z1]=!1;let r=this[Yf].length?!1:this[jf]?this[jf].flowing:!0;return!r&&!this[Yf].length&&this[jf].once(\"drain\",o=>this.emit(\"drain\")),r}[F3](e){e&&!this[vh]&&(this[fi]=this[fi]?Buffer.concat([this[fi],e]):e)}[R3](){if(this[_d]&&!this[uAe]&&!this[vh]&&!this[xx]){this[uAe]=!0;let e=this[Ud];if(e&&e.blockRemain){let r=this[fi]?this[fi].length:0;this.warn(\"TAR_BAD_ARCHIVE\",`Truncated input (needed ${e.blockRemain} more bytes, only ${r} available)`,{entry:e}),this[fi]&&e.write(this[fi]),e.end()}this[Hd](kx)}}[Sx](e){if(this[xx])this[F3](e);else if(!e&&!this[fi])this[R3]();else{if(this[xx]=!0,this[fi]){this[F3](e);let r=this[fi];this[fi]=null,this[bx](r)}else this[bx](e);for(;this[fi]&&this[fi].length>=512&&!this[vh]&&!this[Fx];){let r=this[fi];this[fi]=null,this[bx](r)}this[xx]=!1}(!this[fi]||this[_d])&&this[R3]()}[bx](e){let r=0,o=e.length;for(;r+512<=o&&!this[vh]&&!this[Fx];)switch(this[Zl]){case\"begin\":case\"header\":this[fAe](e,r),r+=512;break;case\"ignore\":case\"body\":r+=this[Q3](e,r);break;case\"meta\":r+=this[AAe](e,r);break;default:throw new Error(\"invalid state: \"+this[Zl])}r<o&&(this[fi]?this[fi]=Buffer.concat([e.slice(r),this[fi]]):this[fi]=e.slice(r))}end(e){this[vh]||(this[Fa]?this[Fa].end(e):(this[_d]=!0,this.write(e)))}})});var Tx=_((uUt,mAe)=>{\"use strict\";var klt=OE(),gAe=Rx(),tC=ve(\"fs\"),Qlt=eC(),hAe=ve(\"path\"),T3=YE();mAe.exports=(t,e,r)=>{typeof t==\"function\"?(r=t,e=null,t={}):Array.isArray(t)&&(e=t,t={}),typeof e==\"function\"&&(r=e,e=null),e?e=Array.from(e):e=[];let o=klt(t);if(o.sync&&typeof r==\"function\")throw new TypeError(\"callback not supported for sync tar functions\");if(!o.file&&typeof r==\"function\")throw new TypeError(\"callback only supported with file option\");return e.length&&Rlt(o,e),o.noResume||Flt(o),o.file&&o.sync?Tlt(o):o.file?Llt(o,r):dAe(o)};var Flt=t=>{let e=t.onentry;t.onentry=e?r=>{e(r),r.resume()}:r=>r.resume()},Rlt=(t,e)=>{let r=new Map(e.map(n=>[T3(n),!0])),o=t.filter,a=(n,u)=>{let A=u||hAe.parse(n).root||\".\",p=n===A?!1:r.has(n)?r.get(n):a(hAe.dirname(n),A);return r.set(n,p),p};t.filter=o?(n,u)=>o(n,u)&&a(T3(n)):n=>a(T3(n))},Tlt=t=>{let e=dAe(t),r=t.file,o=!0,a;try{let n=tC.statSync(r),u=t.maxReadSize||16*1024*1024;if(n.size<u)e.end(tC.readFileSync(r));else{let A=0,p=Buffer.allocUnsafe(u);for(a=tC.openSync(r,\"r\");A<n.size;){let h=tC.readSync(a,p,0,u,A);A+=h,e.write(p.slice(0,h))}e.end()}o=!1}finally{if(o&&a)try{tC.closeSync(a)}catch{}}},Llt=(t,e)=>{let r=new gAe(t),o=t.maxReadSize||16*1024*1024,a=t.file,n=new Promise((u,A)=>{r.on(\"error\",A),r.on(\"end\",u),tC.stat(a,(p,h)=>{if(p)A(p);else{let E=new Qlt.ReadStream(a,{readSize:o,size:h.size});E.on(\"error\",A),E.pipe(r)}})});return e?n.then(e,e):n},dAe=t=>new gAe(t)});var BAe=_((AUt,IAe)=>{\"use strict\";var Nlt=OE(),Lx=Ex(),yAe=eC(),EAe=Tx(),CAe=ve(\"path\");IAe.exports=(t,e,r)=>{if(typeof e==\"function\"&&(r=e),Array.isArray(t)&&(e=t,t={}),!e||!Array.isArray(e)||!e.length)throw new TypeError(\"no files or directories specified\");e=Array.from(e);let o=Nlt(t);if(o.sync&&typeof r==\"function\")throw new TypeError(\"callback not supported for sync tar functions\");if(!o.file&&typeof r==\"function\")throw new TypeError(\"callback only supported with file option\");return o.file&&o.sync?Olt(o,e):o.file?Mlt(o,e,r):o.sync?Ult(o,e):_lt(o,e)};var Olt=(t,e)=>{let r=new Lx.Sync(t),o=new yAe.WriteStreamSync(t.file,{mode:t.mode||438});r.pipe(o),wAe(r,e)},Mlt=(t,e,r)=>{let o=new Lx(t),a=new yAe.WriteStream(t.file,{mode:t.mode||438});o.pipe(a);let n=new Promise((u,A)=>{a.on(\"error\",A),a.on(\"close\",u),o.on(\"error\",A)});return L3(o,e),r?n.then(r,r):n},wAe=(t,e)=>{e.forEach(r=>{r.charAt(0)===\"@\"?EAe({file:CAe.resolve(t.cwd,r.substr(1)),sync:!0,noResume:!0,onentry:o=>t.add(o)}):t.add(r)}),t.end()},L3=(t,e)=>{for(;e.length;){let r=e.shift();if(r.charAt(0)===\"@\")return EAe({file:CAe.resolve(t.cwd,r.substr(1)),noResume:!0,onentry:o=>t.add(o)}).then(o=>L3(t,e));t.add(r)}t.end()},Ult=(t,e)=>{let r=new Lx.Sync(t);return wAe(r,e),r},_lt=(t,e)=>{let r=new Lx(t);return L3(r,e),r}});var N3=_((fUt,kAe)=>{\"use strict\";var Hlt=OE(),vAe=Ex(),fl=ve(\"fs\"),DAe=eC(),PAe=Tx(),SAe=ve(\"path\"),bAe=jE();kAe.exports=(t,e,r)=>{let o=Hlt(t);if(!o.file)throw new TypeError(\"file is required\");if(o.gzip)throw new TypeError(\"cannot append to compressed archives\");if(!e||!Array.isArray(e)||!e.length)throw new TypeError(\"no files or directories specified\");return e=Array.from(e),o.sync?qlt(o,e):jlt(o,e,r)};var qlt=(t,e)=>{let r=new vAe.Sync(t),o=!0,a,n;try{try{a=fl.openSync(t.file,\"r+\")}catch(p){if(p.code===\"ENOENT\")a=fl.openSync(t.file,\"w+\");else throw p}let u=fl.fstatSync(a),A=Buffer.alloc(512);e:for(n=0;n<u.size;n+=512){for(let E=0,I=0;E<512;E+=I){if(I=fl.readSync(a,A,E,A.length-E,n+E),n===0&&A[0]===31&&A[1]===139)throw new Error(\"cannot append to compressed archives\");if(!I)break e}let p=new bAe(A);if(!p.cksumValid)break;let h=512*Math.ceil(p.size/512);if(n+h+512>u.size)break;n+=h,t.mtimeCache&&t.mtimeCache.set(p.path,p.mtime)}o=!1,Glt(t,r,n,a,e)}finally{if(o)try{fl.closeSync(a)}catch{}}},Glt=(t,e,r,o,a)=>{let n=new DAe.WriteStreamSync(t.file,{fd:o,start:r});e.pipe(n),Ylt(e,a)},jlt=(t,e,r)=>{e=Array.from(e);let o=new vAe(t),a=(u,A,p)=>{let h=(C,R)=>{C?fl.close(u,N=>p(C)):p(null,R)},E=0;if(A===0)return h(null,0);let I=0,v=Buffer.alloc(512),x=(C,R)=>{if(C)return h(C);if(I+=R,I<512&&R)return fl.read(u,v,I,v.length-I,E+I,x);if(E===0&&v[0]===31&&v[1]===139)return h(new Error(\"cannot append to compressed archives\"));if(I<512)return h(null,E);let N=new bAe(v);if(!N.cksumValid)return h(null,E);let U=512*Math.ceil(N.size/512);if(E+U+512>A||(E+=U+512,E>=A))return h(null,E);t.mtimeCache&&t.mtimeCache.set(N.path,N.mtime),I=0,fl.read(u,v,0,512,E,x)};fl.read(u,v,0,512,E,x)},n=new Promise((u,A)=>{o.on(\"error\",A);let p=\"r+\",h=(E,I)=>{if(E&&E.code===\"ENOENT\"&&p===\"r+\")return p=\"w+\",fl.open(t.file,p,h);if(E)return A(E);fl.fstat(I,(v,x)=>{if(v)return fl.close(I,()=>A(v));a(I,x.size,(C,R)=>{if(C)return A(C);let N=new DAe.WriteStream(t.file,{fd:I,start:R});o.pipe(N),N.on(\"error\",A),N.on(\"close\",u),xAe(o,e)})})};fl.open(t.file,p,h)});return r?n.then(r,r):n},Ylt=(t,e)=>{e.forEach(r=>{r.charAt(0)===\"@\"?PAe({file:SAe.resolve(t.cwd,r.substr(1)),sync:!0,noResume:!0,onentry:o=>t.add(o)}):t.add(r)}),t.end()},xAe=(t,e)=>{for(;e.length;){let r=e.shift();if(r.charAt(0)===\"@\")return PAe({file:SAe.resolve(t.cwd,r.substr(1)),noResume:!0,onentry:o=>t.add(o)}).then(o=>xAe(t,e));t.add(r)}t.end()}});var FAe=_((pUt,QAe)=>{\"use strict\";var Wlt=OE(),Klt=N3();QAe.exports=(t,e,r)=>{let o=Wlt(t);if(!o.file)throw new TypeError(\"file is required\");if(o.gzip)throw new TypeError(\"cannot append to compressed archives\");if(!e||!Array.isArray(e)||!e.length)throw new TypeError(\"no files or directories specified\");return e=Array.from(e),zlt(o),Klt(o,e,r)};var zlt=t=>{let e=t.filter;t.mtimeCache||(t.mtimeCache=new Map),t.filter=e?(r,o)=>e(r,o)&&!(t.mtimeCache.get(r)>o.mtime):(r,o)=>!(t.mtimeCache.get(r)>o.mtime)}});var LAe=_((hUt,TAe)=>{var{promisify:RAe}=ve(\"util\"),Dh=ve(\"fs\"),Vlt=t=>{if(!t)t={mode:511,fs:Dh};else if(typeof t==\"object\")t={mode:511,fs:Dh,...t};else if(typeof t==\"number\")t={mode:t,fs:Dh};else if(typeof t==\"string\")t={mode:parseInt(t,8),fs:Dh};else throw new TypeError(\"invalid options argument\");return t.mkdir=t.mkdir||t.fs.mkdir||Dh.mkdir,t.mkdirAsync=RAe(t.mkdir),t.stat=t.stat||t.fs.stat||Dh.stat,t.statAsync=RAe(t.stat),t.statSync=t.statSync||t.fs.statSync||Dh.statSync,t.mkdirSync=t.mkdirSync||t.fs.mkdirSync||Dh.mkdirSync,t};TAe.exports=Vlt});var OAe=_((gUt,NAe)=>{var Jlt=process.platform,{resolve:Xlt,parse:Zlt}=ve(\"path\"),$lt=t=>{if(/\\0/.test(t))throw Object.assign(new TypeError(\"path must be a string without null bytes\"),{path:t,code:\"ERR_INVALID_ARG_VALUE\"});if(t=Xlt(t),Jlt===\"win32\"){let e=/[*|\"<>?:]/,{root:r}=Zlt(t);if(e.test(t.substr(r.length)))throw Object.assign(new Error(\"Illegal characters in path.\"),{path:t,code:\"EINVAL\"})}return t};NAe.exports=$lt});var qAe=_((dUt,HAe)=>{var{dirname:MAe}=ve(\"path\"),UAe=(t,e,r=void 0)=>r===e?Promise.resolve():t.statAsync(e).then(o=>o.isDirectory()?r:void 0,o=>o.code===\"ENOENT\"?UAe(t,MAe(e),e):void 0),_Ae=(t,e,r=void 0)=>{if(r!==e)try{return t.statSync(e).isDirectory()?r:void 0}catch(o){return o.code===\"ENOENT\"?_Ae(t,MAe(e),e):void 0}};HAe.exports={findMade:UAe,findMadeSync:_Ae}});var U3=_((mUt,jAe)=>{var{dirname:GAe}=ve(\"path\"),O3=(t,e,r)=>{e.recursive=!1;let o=GAe(t);return o===t?e.mkdirAsync(t,e).catch(a=>{if(a.code!==\"EISDIR\")throw a}):e.mkdirAsync(t,e).then(()=>r||t,a=>{if(a.code===\"ENOENT\")return O3(o,e).then(n=>O3(t,e,n));if(a.code!==\"EEXIST\"&&a.code!==\"EROFS\")throw a;return e.statAsync(t).then(n=>{if(n.isDirectory())return r;throw a},()=>{throw a})})},M3=(t,e,r)=>{let o=GAe(t);if(e.recursive=!1,o===t)try{return e.mkdirSync(t,e)}catch(a){if(a.code!==\"EISDIR\")throw a;return}try{return e.mkdirSync(t,e),r||t}catch(a){if(a.code===\"ENOENT\")return M3(t,e,M3(o,e,r));if(a.code!==\"EEXIST\"&&a.code!==\"EROFS\")throw a;try{if(!e.statSync(t).isDirectory())throw a}catch{throw a}}};jAe.exports={mkdirpManual:O3,mkdirpManualSync:M3}});var KAe=_((yUt,WAe)=>{var{dirname:YAe}=ve(\"path\"),{findMade:ect,findMadeSync:tct}=qAe(),{mkdirpManual:rct,mkdirpManualSync:nct}=U3(),ict=(t,e)=>(e.recursive=!0,YAe(t)===t?e.mkdirAsync(t,e):ect(e,t).then(o=>e.mkdirAsync(t,e).then(()=>o).catch(a=>{if(a.code===\"ENOENT\")return rct(t,e);throw a}))),sct=(t,e)=>{if(e.recursive=!0,YAe(t)===t)return e.mkdirSync(t,e);let o=tct(e,t);try{return e.mkdirSync(t,e),o}catch(a){if(a.code===\"ENOENT\")return nct(t,e);throw a}};WAe.exports={mkdirpNative:ict,mkdirpNativeSync:sct}});var XAe=_((EUt,JAe)=>{var zAe=ve(\"fs\"),oct=process.version,_3=oct.replace(/^v/,\"\").split(\".\"),VAe=+_3[0]>10||+_3[0]==10&&+_3[1]>=12,act=VAe?t=>t.mkdir===zAe.mkdir:()=>!1,lct=VAe?t=>t.mkdirSync===zAe.mkdirSync:()=>!1;JAe.exports={useNative:act,useNativeSync:lct}});var nfe=_((CUt,rfe)=>{var rC=LAe(),nC=OAe(),{mkdirpNative:ZAe,mkdirpNativeSync:$Ae}=KAe(),{mkdirpManual:efe,mkdirpManualSync:tfe}=U3(),{useNative:cct,useNativeSync:uct}=XAe(),iC=(t,e)=>(t=nC(t),e=rC(e),cct(e)?ZAe(t,e):efe(t,e)),Act=(t,e)=>(t=nC(t),e=rC(e),uct(e)?$Ae(t,e):tfe(t,e));iC.sync=Act;iC.native=(t,e)=>ZAe(nC(t),rC(e));iC.manual=(t,e)=>efe(nC(t),rC(e));iC.nativeSync=(t,e)=>$Ae(nC(t),rC(e));iC.manualSync=(t,e)=>tfe(nC(t),rC(e));rfe.exports=iC});var ufe=_((wUt,cfe)=>{\"use strict\";var ec=ve(\"fs\"),Gd=ve(\"path\"),fct=ec.lchown?\"lchown\":\"chown\",pct=ec.lchownSync?\"lchownSync\":\"chownSync\",sfe=ec.lchown&&!process.version.match(/v1[1-9]+\\./)&&!process.version.match(/v10\\.[6-9]/),ife=(t,e,r)=>{try{return ec[pct](t,e,r)}catch(o){if(o.code!==\"ENOENT\")throw o}},hct=(t,e,r)=>{try{return ec.chownSync(t,e,r)}catch(o){if(o.code!==\"ENOENT\")throw o}},gct=sfe?(t,e,r,o)=>a=>{!a||a.code!==\"EISDIR\"?o(a):ec.chown(t,e,r,o)}:(t,e,r,o)=>o,H3=sfe?(t,e,r)=>{try{return ife(t,e,r)}catch(o){if(o.code!==\"EISDIR\")throw o;hct(t,e,r)}}:(t,e,r)=>ife(t,e,r),dct=process.version,ofe=(t,e,r)=>ec.readdir(t,e,r),mct=(t,e)=>ec.readdirSync(t,e);/^v4\\./.test(dct)&&(ofe=(t,e,r)=>ec.readdir(t,r));var Nx=(t,e,r,o)=>{ec[fct](t,e,r,gct(t,e,r,a=>{o(a&&a.code!==\"ENOENT\"?a:null)}))},afe=(t,e,r,o,a)=>{if(typeof e==\"string\")return ec.lstat(Gd.resolve(t,e),(n,u)=>{if(n)return a(n.code!==\"ENOENT\"?n:null);u.name=e,afe(t,u,r,o,a)});if(e.isDirectory())q3(Gd.resolve(t,e.name),r,o,n=>{if(n)return a(n);let u=Gd.resolve(t,e.name);Nx(u,r,o,a)});else{let n=Gd.resolve(t,e.name);Nx(n,r,o,a)}},q3=(t,e,r,o)=>{ofe(t,{withFileTypes:!0},(a,n)=>{if(a){if(a.code===\"ENOENT\")return o();if(a.code!==\"ENOTDIR\"&&a.code!==\"ENOTSUP\")return o(a)}if(a||!n.length)return Nx(t,e,r,o);let u=n.length,A=null,p=h=>{if(!A){if(h)return o(A=h);if(--u===0)return Nx(t,e,r,o)}};n.forEach(h=>afe(t,h,e,r,p))})},yct=(t,e,r,o)=>{if(typeof e==\"string\")try{let a=ec.lstatSync(Gd.resolve(t,e));a.name=e,e=a}catch(a){if(a.code===\"ENOENT\")return;throw a}e.isDirectory()&&lfe(Gd.resolve(t,e.name),r,o),H3(Gd.resolve(t,e.name),r,o)},lfe=(t,e,r)=>{let o;try{o=mct(t,{withFileTypes:!0})}catch(a){if(a.code===\"ENOENT\")return;if(a.code===\"ENOTDIR\"||a.code===\"ENOTSUP\")return H3(t,e,r);throw a}return o&&o.length&&o.forEach(a=>yct(t,a,e,r)),H3(t,e,r)};cfe.exports=q3;q3.sync=lfe});var hfe=_((IUt,G3)=>{\"use strict\";var Afe=nfe(),tc=ve(\"fs\"),Ox=ve(\"path\"),ffe=ufe(),Kc=qE(),Mx=class extends Error{constructor(e,r){super(\"Cannot extract through symbolic link\"),this.path=r,this.symlink=e}get name(){return\"SylinkError\"}},Ux=class extends Error{constructor(e,r){super(r+\": Cannot cd into '\"+e+\"'\"),this.path=e,this.code=r}get name(){return\"CwdError\"}},_x=(t,e)=>t.get(Kc(e)),V1=(t,e,r)=>t.set(Kc(e),r),Ect=(t,e)=>{tc.stat(t,(r,o)=>{(r||!o.isDirectory())&&(r=new Ux(t,r&&r.code||\"ENOTDIR\")),e(r)})};G3.exports=(t,e,r)=>{t=Kc(t);let o=e.umask,a=e.mode|448,n=(a&o)!==0,u=e.uid,A=e.gid,p=typeof u==\"number\"&&typeof A==\"number\"&&(u!==e.processUid||A!==e.processGid),h=e.preserve,E=e.unlink,I=e.cache,v=Kc(e.cwd),x=(N,U)=>{N?r(N):(V1(I,t,!0),U&&p?ffe(U,u,A,V=>x(V)):n?tc.chmod(t,a,r):r())};if(I&&_x(I,t)===!0)return x();if(t===v)return Ect(t,x);if(h)return Afe(t,{mode:a}).then(N=>x(null,N),x);let R=Kc(Ox.relative(v,t)).split(\"/\");Hx(v,R,a,I,E,v,null,x)};var Hx=(t,e,r,o,a,n,u,A)=>{if(!e.length)return A(null,u);let p=e.shift(),h=Kc(Ox.resolve(t+\"/\"+p));if(_x(o,h))return Hx(h,e,r,o,a,n,u,A);tc.mkdir(h,r,pfe(h,e,r,o,a,n,u,A))},pfe=(t,e,r,o,a,n,u,A)=>p=>{p?tc.lstat(t,(h,E)=>{if(h)h.path=h.path&&Kc(h.path),A(h);else if(E.isDirectory())Hx(t,e,r,o,a,n,u,A);else if(a)tc.unlink(t,I=>{if(I)return A(I);tc.mkdir(t,r,pfe(t,e,r,o,a,n,u,A))});else{if(E.isSymbolicLink())return A(new Mx(t,t+\"/\"+e.join(\"/\")));A(p)}}):(u=u||t,Hx(t,e,r,o,a,n,u,A))},Cct=t=>{let e=!1,r=\"ENOTDIR\";try{e=tc.statSync(t).isDirectory()}catch(o){r=o.code}finally{if(!e)throw new Ux(t,r)}};G3.exports.sync=(t,e)=>{t=Kc(t);let r=e.umask,o=e.mode|448,a=(o&r)!==0,n=e.uid,u=e.gid,A=typeof n==\"number\"&&typeof u==\"number\"&&(n!==e.processUid||u!==e.processGid),p=e.preserve,h=e.unlink,E=e.cache,I=Kc(e.cwd),v=N=>{V1(E,t,!0),N&&A&&ffe.sync(N,n,u),a&&tc.chmodSync(t,o)};if(E&&_x(E,t)===!0)return v();if(t===I)return Cct(I),v();if(p)return v(Afe.sync(t,o));let C=Kc(Ox.relative(I,t)).split(\"/\"),R=null;for(let N=C.shift(),U=I;N&&(U+=\"/\"+N);N=C.shift())if(U=Kc(Ox.resolve(U)),!_x(E,U))try{tc.mkdirSync(U,o),R=R||U,V1(E,U,!0)}catch{let te=tc.lstatSync(U);if(te.isDirectory()){V1(E,U,!0);continue}else if(h){tc.unlinkSync(U),tc.mkdirSync(U,o),R=R||U,V1(E,U,!0);continue}else if(te.isSymbolicLink())return new Mx(U,U+\"/\"+C.join(\"/\"))}return v(R)}});var Y3=_((BUt,gfe)=>{var j3=Object.create(null),{hasOwnProperty:wct}=Object.prototype;gfe.exports=t=>(wct.call(j3,t)||(j3[t]=t.normalize(\"NFKD\")),j3[t])});var Efe=_((vUt,yfe)=>{var dfe=ve(\"assert\"),Ict=Y3(),Bct=YE(),{join:mfe}=ve(\"path\"),vct=process.env.TESTING_TAR_FAKE_PLATFORM||process.platform,Dct=vct===\"win32\";yfe.exports=()=>{let t=new Map,e=new Map,r=h=>h.split(\"/\").slice(0,-1).reduce((I,v)=>(I.length&&(v=mfe(I[I.length-1],v)),I.push(v||\"/\"),I),[]),o=new Set,a=h=>{let E=e.get(h);if(!E)throw new Error(\"function does not have any path reservations\");return{paths:E.paths.map(I=>t.get(I)),dirs:[...E.dirs].map(I=>t.get(I))}},n=h=>{let{paths:E,dirs:I}=a(h);return E.every(v=>v[0]===h)&&I.every(v=>v[0]instanceof Set&&v[0].has(h))},u=h=>o.has(h)||!n(h)?!1:(o.add(h),h(()=>A(h)),!0),A=h=>{if(!o.has(h))return!1;let{paths:E,dirs:I}=e.get(h),v=new Set;return E.forEach(x=>{let C=t.get(x);dfe.equal(C[0],h),C.length===1?t.delete(x):(C.shift(),typeof C[0]==\"function\"?v.add(C[0]):C[0].forEach(R=>v.add(R)))}),I.forEach(x=>{let C=t.get(x);dfe(C[0]instanceof Set),C[0].size===1&&C.length===1?t.delete(x):C[0].size===1?(C.shift(),v.add(C[0])):C[0].delete(h)}),o.delete(h),v.forEach(x=>u(x)),!0};return{check:n,reserve:(h,E)=>{h=Dct?[\"win32 parallelization disabled\"]:h.map(v=>Ict(Bct(mfe(v))).toLowerCase());let I=new Set(h.map(v=>r(v)).reduce((v,x)=>v.concat(x)));return e.set(E,{dirs:I,paths:h}),h.forEach(v=>{let x=t.get(v);x?x.push(E):t.set(v,[E])}),I.forEach(v=>{let x=t.get(v);x?x[x.length-1]instanceof Set?x[x.length-1].add(E):x.push(new Set([E])):t.set(v,[new Set([E])])}),u(E)}}}});var Ife=_((DUt,wfe)=>{var Pct=process.platform,Sct=Pct===\"win32\",bct=global.__FAKE_TESTING_FS__||ve(\"fs\"),{O_CREAT:xct,O_TRUNC:kct,O_WRONLY:Qct,UV_FS_O_FILEMAP:Cfe=0}=bct.constants,Fct=Sct&&!!Cfe,Rct=512*1024,Tct=Cfe|kct|xct|Qct;wfe.exports=Fct?t=>t<Rct?Tct:\"w\":()=>\"w\"});var e_=_((PUt,Nfe)=>{\"use strict\";var Lct=ve(\"assert\"),Nct=Rx(),vn=ve(\"fs\"),Oct=eC(),Wf=ve(\"path\"),Rfe=hfe(),Bfe=e3(),Mct=Efe(),Uct=t3(),pl=qE(),_ct=YE(),Hct=Y3(),vfe=Symbol(\"onEntry\"),z3=Symbol(\"checkFs\"),Dfe=Symbol(\"checkFs2\"),jx=Symbol(\"pruneCache\"),V3=Symbol(\"isReusable\"),rc=Symbol(\"makeFs\"),J3=Symbol(\"file\"),X3=Symbol(\"directory\"),Yx=Symbol(\"link\"),Pfe=Symbol(\"symlink\"),Sfe=Symbol(\"hardlink\"),bfe=Symbol(\"unsupported\"),xfe=Symbol(\"checkPath\"),Ph=Symbol(\"mkdir\"),To=Symbol(\"onError\"),qx=Symbol(\"pending\"),kfe=Symbol(\"pend\"),sC=Symbol(\"unpend\"),W3=Symbol(\"ended\"),K3=Symbol(\"maybeClose\"),Z3=Symbol(\"skip\"),J1=Symbol(\"doChown\"),X1=Symbol(\"uid\"),Z1=Symbol(\"gid\"),$1=Symbol(\"checkedCwd\"),Tfe=ve(\"crypto\"),Lfe=Ife(),qct=process.env.TESTING_TAR_FAKE_PLATFORM||process.platform,e2=qct===\"win32\",Gct=(t,e)=>{if(!e2)return vn.unlink(t,e);let r=t+\".DELETE.\"+Tfe.randomBytes(16).toString(\"hex\");vn.rename(t,r,o=>{if(o)return e(o);vn.unlink(r,e)})},jct=t=>{if(!e2)return vn.unlinkSync(t);let e=t+\".DELETE.\"+Tfe.randomBytes(16).toString(\"hex\");vn.renameSync(t,e),vn.unlinkSync(e)},Qfe=(t,e,r)=>t===t>>>0?t:e===e>>>0?e:r,Ffe=t=>Hct(_ct(pl(t))).toLowerCase(),Yct=(t,e)=>{e=Ffe(e);for(let r of t.keys()){let o=Ffe(r);(o===e||o.indexOf(e+\"/\")===0)&&t.delete(r)}},Wct=t=>{for(let e of t.keys())t.delete(e)},t2=class extends Nct{constructor(e){if(e||(e={}),e.ondone=r=>{this[W3]=!0,this[K3]()},super(e),this[$1]=!1,this.reservations=Mct(),this.transform=typeof e.transform==\"function\"?e.transform:null,this.writable=!0,this.readable=!1,this[qx]=0,this[W3]=!1,this.dirCache=e.dirCache||new Map,typeof e.uid==\"number\"||typeof e.gid==\"number\"){if(typeof e.uid!=\"number\"||typeof e.gid!=\"number\")throw new TypeError(\"cannot set owner without number uid and gid\");if(e.preserveOwner)throw new TypeError(\"cannot preserve owner in archive and also set owner explicitly\");this.uid=e.uid,this.gid=e.gid,this.setOwner=!0}else this.uid=null,this.gid=null,this.setOwner=!1;e.preserveOwner===void 0&&typeof e.uid!=\"number\"?this.preserveOwner=process.getuid&&process.getuid()===0:this.preserveOwner=!!e.preserveOwner,this.processUid=(this.preserveOwner||this.setOwner)&&process.getuid?process.getuid():null,this.processGid=(this.preserveOwner||this.setOwner)&&process.getgid?process.getgid():null,this.forceChown=e.forceChown===!0,this.win32=!!e.win32||e2,this.newer=!!e.newer,this.keep=!!e.keep,this.noMtime=!!e.noMtime,this.preservePaths=!!e.preservePaths,this.unlink=!!e.unlink,this.cwd=pl(Wf.resolve(e.cwd||process.cwd())),this.strip=+e.strip||0,this.processUmask=e.noChmod?0:process.umask(),this.umask=typeof e.umask==\"number\"?e.umask:this.processUmask,this.dmode=e.dmode||511&~this.umask,this.fmode=e.fmode||438&~this.umask,this.on(\"entry\",r=>this[vfe](r))}warn(e,r,o={}){return(e===\"TAR_BAD_ARCHIVE\"||e===\"TAR_ABORT\")&&(o.recoverable=!1),super.warn(e,r,o)}[K3](){this[W3]&&this[qx]===0&&(this.emit(\"prefinish\"),this.emit(\"finish\"),this.emit(\"end\"),this.emit(\"close\"))}[xfe](e){if(this.strip){let r=pl(e.path).split(\"/\");if(r.length<this.strip)return!1;if(e.path=r.slice(this.strip).join(\"/\"),e.type===\"Link\"){let o=pl(e.linkpath).split(\"/\");if(o.length>=this.strip)e.linkpath=o.slice(this.strip).join(\"/\");else return!1}}if(!this.preservePaths){let r=pl(e.path),o=r.split(\"/\");if(o.includes(\"..\")||e2&&/^[a-z]:\\.\\.$/i.test(o[0]))return this.warn(\"TAR_ENTRY_ERROR\",\"path contains '..'\",{entry:e,path:r}),!1;let[a,n]=Uct(r);a&&(e.path=n,this.warn(\"TAR_ENTRY_INFO\",`stripping ${a} from absolute path`,{entry:e,path:r}))}if(Wf.isAbsolute(e.path)?e.absolute=pl(Wf.resolve(e.path)):e.absolute=pl(Wf.resolve(this.cwd,e.path)),!this.preservePaths&&e.absolute.indexOf(this.cwd+\"/\")!==0&&e.absolute!==this.cwd)return this.warn(\"TAR_ENTRY_ERROR\",\"path escaped extraction target\",{entry:e,path:pl(e.path),resolvedPath:e.absolute,cwd:this.cwd}),!1;if(e.absolute===this.cwd&&e.type!==\"Directory\"&&e.type!==\"GNUDumpDir\")return!1;if(this.win32){let{root:r}=Wf.win32.parse(e.absolute);e.absolute=r+Bfe.encode(e.absolute.substr(r.length));let{root:o}=Wf.win32.parse(e.path);e.path=o+Bfe.encode(e.path.substr(o.length))}return!0}[vfe](e){if(!this[xfe](e))return e.resume();switch(Lct.equal(typeof e.absolute,\"string\"),e.type){case\"Directory\":case\"GNUDumpDir\":e.mode&&(e.mode=e.mode|448);case\"File\":case\"OldFile\":case\"ContiguousFile\":case\"Link\":case\"SymbolicLink\":return this[z3](e);case\"CharacterDevice\":case\"BlockDevice\":case\"FIFO\":default:return this[bfe](e)}}[To](e,r){e.name===\"CwdError\"?this.emit(\"error\",e):(this.warn(\"TAR_ENTRY_ERROR\",e,{entry:r}),this[sC](),r.resume())}[Ph](e,r,o){Rfe(pl(e),{uid:this.uid,gid:this.gid,processUid:this.processUid,processGid:this.processGid,umask:this.processUmask,preserve:this.preservePaths,unlink:this.unlink,cache:this.dirCache,cwd:this.cwd,mode:r,noChmod:this.noChmod},o)}[J1](e){return this.forceChown||this.preserveOwner&&(typeof e.uid==\"number\"&&e.uid!==this.processUid||typeof e.gid==\"number\"&&e.gid!==this.processGid)||typeof this.uid==\"number\"&&this.uid!==this.processUid||typeof this.gid==\"number\"&&this.gid!==this.processGid}[X1](e){return Qfe(this.uid,e.uid,this.processUid)}[Z1](e){return Qfe(this.gid,e.gid,this.processGid)}[J3](e,r){let o=e.mode&4095||this.fmode,a=new Oct.WriteStream(e.absolute,{flags:Lfe(e.size),mode:o,autoClose:!1});a.on(\"error\",p=>{a.fd&&vn.close(a.fd,()=>{}),a.write=()=>!0,this[To](p,e),r()});let n=1,u=p=>{if(p){a.fd&&vn.close(a.fd,()=>{}),this[To](p,e),r();return}--n===0&&vn.close(a.fd,h=>{h?this[To](h,e):this[sC](),r()})};a.on(\"finish\",p=>{let h=e.absolute,E=a.fd;if(e.mtime&&!this.noMtime){n++;let I=e.atime||new Date,v=e.mtime;vn.futimes(E,I,v,x=>x?vn.utimes(h,I,v,C=>u(C&&x)):u())}if(this[J1](e)){n++;let I=this[X1](e),v=this[Z1](e);vn.fchown(E,I,v,x=>x?vn.chown(h,I,v,C=>u(C&&x)):u())}u()});let A=this.transform&&this.transform(e)||e;A!==e&&(A.on(\"error\",p=>{this[To](p,e),r()}),e.pipe(A)),A.pipe(a)}[X3](e,r){let o=e.mode&4095||this.dmode;this[Ph](e.absolute,o,a=>{if(a){this[To](a,e),r();return}let n=1,u=A=>{--n===0&&(r(),this[sC](),e.resume())};e.mtime&&!this.noMtime&&(n++,vn.utimes(e.absolute,e.atime||new Date,e.mtime,u)),this[J1](e)&&(n++,vn.chown(e.absolute,this[X1](e),this[Z1](e),u)),u()})}[bfe](e){e.unsupported=!0,this.warn(\"TAR_ENTRY_UNSUPPORTED\",`unsupported entry type: ${e.type}`,{entry:e}),e.resume()}[Pfe](e,r){this[Yx](e,e.linkpath,\"symlink\",r)}[Sfe](e,r){let o=pl(Wf.resolve(this.cwd,e.linkpath));this[Yx](e,o,\"link\",r)}[kfe](){this[qx]++}[sC](){this[qx]--,this[K3]()}[Z3](e){this[sC](),e.resume()}[V3](e,r){return e.type===\"File\"&&!this.unlink&&r.isFile()&&r.nlink<=1&&!e2}[z3](e){this[kfe]();let r=[e.path];e.linkpath&&r.push(e.linkpath),this.reservations.reserve(r,o=>this[Dfe](e,o))}[jx](e){e.type===\"SymbolicLink\"?Wct(this.dirCache):e.type!==\"Directory\"&&Yct(this.dirCache,e.absolute)}[Dfe](e,r){this[jx](e);let o=A=>{this[jx](e),r(A)},a=()=>{this[Ph](this.cwd,this.dmode,A=>{if(A){this[To](A,e),o();return}this[$1]=!0,n()})},n=()=>{if(e.absolute!==this.cwd){let A=pl(Wf.dirname(e.absolute));if(A!==this.cwd)return this[Ph](A,this.dmode,p=>{if(p){this[To](p,e),o();return}u()})}u()},u=()=>{vn.lstat(e.absolute,(A,p)=>{if(p&&(this.keep||this.newer&&p.mtime>e.mtime)){this[Z3](e),o();return}if(A||this[V3](e,p))return this[rc](null,e,o);if(p.isDirectory()){if(e.type===\"Directory\"){let h=!this.noChmod&&e.mode&&(p.mode&4095)!==e.mode,E=I=>this[rc](I,e,o);return h?vn.chmod(e.absolute,e.mode,E):E()}if(e.absolute!==this.cwd)return vn.rmdir(e.absolute,h=>this[rc](h,e,o))}if(e.absolute===this.cwd)return this[rc](null,e,o);Gct(e.absolute,h=>this[rc](h,e,o))})};this[$1]?n():a()}[rc](e,r,o){if(e){this[To](e,r),o();return}switch(r.type){case\"File\":case\"OldFile\":case\"ContiguousFile\":return this[J3](r,o);case\"Link\":return this[Sfe](r,o);case\"SymbolicLink\":return this[Pfe](r,o);case\"Directory\":case\"GNUDumpDir\":return this[X3](r,o)}}[Yx](e,r,o,a){vn[o](r,e.absolute,n=>{n?this[To](n,e):(this[sC](),e.resume()),a()})}},Gx=t=>{try{return[null,t()]}catch(e){return[e,null]}},$3=class extends t2{[rc](e,r){return super[rc](e,r,()=>{})}[z3](e){if(this[jx](e),!this[$1]){let n=this[Ph](this.cwd,this.dmode);if(n)return this[To](n,e);this[$1]=!0}if(e.absolute!==this.cwd){let n=pl(Wf.dirname(e.absolute));if(n!==this.cwd){let u=this[Ph](n,this.dmode);if(u)return this[To](u,e)}}let[r,o]=Gx(()=>vn.lstatSync(e.absolute));if(o&&(this.keep||this.newer&&o.mtime>e.mtime))return this[Z3](e);if(r||this[V3](e,o))return this[rc](null,e);if(o.isDirectory()){if(e.type===\"Directory\"){let u=!this.noChmod&&e.mode&&(o.mode&4095)!==e.mode,[A]=u?Gx(()=>{vn.chmodSync(e.absolute,e.mode)}):[];return this[rc](A,e)}let[n]=Gx(()=>vn.rmdirSync(e.absolute));this[rc](n,e)}let[a]=e.absolute===this.cwd?[]:Gx(()=>jct(e.absolute));this[rc](a,e)}[J3](e,r){let o=e.mode&4095||this.fmode,a=A=>{let p;try{vn.closeSync(n)}catch(h){p=h}(A||p)&&this[To](A||p,e),r()},n;try{n=vn.openSync(e.absolute,Lfe(e.size),o)}catch(A){return a(A)}let u=this.transform&&this.transform(e)||e;u!==e&&(u.on(\"error\",A=>this[To](A,e)),e.pipe(u)),u.on(\"data\",A=>{try{vn.writeSync(n,A,0,A.length)}catch(p){a(p)}}),u.on(\"end\",A=>{let p=null;if(e.mtime&&!this.noMtime){let h=e.atime||new Date,E=e.mtime;try{vn.futimesSync(n,h,E)}catch(I){try{vn.utimesSync(e.absolute,h,E)}catch{p=I}}}if(this[J1](e)){let h=this[X1](e),E=this[Z1](e);try{vn.fchownSync(n,h,E)}catch(I){try{vn.chownSync(e.absolute,h,E)}catch{p=p||I}}}a(p)})}[X3](e,r){let o=e.mode&4095||this.dmode,a=this[Ph](e.absolute,o);if(a){this[To](a,e),r();return}if(e.mtime&&!this.noMtime)try{vn.utimesSync(e.absolute,e.atime||new Date,e.mtime)}catch{}if(this[J1](e))try{vn.chownSync(e.absolute,this[X1](e),this[Z1](e))}catch{}r(),e.resume()}[Ph](e,r){try{return Rfe.sync(pl(e),{uid:this.uid,gid:this.gid,processUid:this.processUid,processGid:this.processGid,umask:this.processUmask,preserve:this.preservePaths,unlink:this.unlink,cache:this.dirCache,cwd:this.cwd,mode:r})}catch(o){return o}}[Yx](e,r,o,a){try{vn[o+\"Sync\"](r,e.absolute),a(),e.resume()}catch(n){return this[To](n,e)}}};t2.Sync=$3;Nfe.exports=t2});var Hfe=_((SUt,_fe)=>{\"use strict\";var Kct=OE(),Wx=e_(),Mfe=ve(\"fs\"),Ufe=eC(),Ofe=ve(\"path\"),t_=YE();_fe.exports=(t,e,r)=>{typeof t==\"function\"?(r=t,e=null,t={}):Array.isArray(t)&&(e=t,t={}),typeof e==\"function\"&&(r=e,e=null),e?e=Array.from(e):e=[];let o=Kct(t);if(o.sync&&typeof r==\"function\")throw new TypeError(\"callback not supported for sync tar functions\");if(!o.file&&typeof r==\"function\")throw new TypeError(\"callback only supported with file option\");return e.length&&zct(o,e),o.file&&o.sync?Vct(o):o.file?Jct(o,r):o.sync?Xct(o):Zct(o)};var zct=(t,e)=>{let r=new Map(e.map(n=>[t_(n),!0])),o=t.filter,a=(n,u)=>{let A=u||Ofe.parse(n).root||\".\",p=n===A?!1:r.has(n)?r.get(n):a(Ofe.dirname(n),A);return r.set(n,p),p};t.filter=o?(n,u)=>o(n,u)&&a(t_(n)):n=>a(t_(n))},Vct=t=>{let e=new Wx.Sync(t),r=t.file,o=Mfe.statSync(r),a=t.maxReadSize||16*1024*1024;new Ufe.ReadStreamSync(r,{readSize:a,size:o.size}).pipe(e)},Jct=(t,e)=>{let r=new Wx(t),o=t.maxReadSize||16*1024*1024,a=t.file,n=new Promise((u,A)=>{r.on(\"error\",A),r.on(\"close\",u),Mfe.stat(a,(p,h)=>{if(p)A(p);else{let E=new Ufe.ReadStream(a,{readSize:o,size:h.size});E.on(\"error\",A),E.pipe(r)}})});return e?n.then(e,e):n},Xct=t=>new Wx.Sync(t),Zct=t=>new Wx(t)});var qfe=_(us=>{\"use strict\";us.c=us.create=BAe();us.r=us.replace=N3();us.t=us.list=Tx();us.u=us.update=FAe();us.x=us.extract=Hfe();us.Pack=Ex();us.Unpack=e_();us.Parse=Rx();us.ReadEntry=rx();us.WriteEntry=A3();us.Header=jE();us.Pax=ix();us.types=KU()});var r_,Gfe,Sh,r2,n2,jfe=Et(()=>{r_=$e(sd()),Gfe=ve(\"worker_threads\"),Sh=Symbol(\"kTaskInfo\"),r2=class{constructor(e,r){this.fn=e;this.limit=(0,r_.default)(r.poolSize)}run(e){return this.limit(()=>this.fn(e))}},n2=class{constructor(e,r){this.source=e;this.workers=[];this.limit=(0,r_.default)(r.poolSize),this.cleanupInterval=setInterval(()=>{if(this.limit.pendingCount===0&&this.limit.activeCount===0){let o=this.workers.pop();o?o.terminate():clearInterval(this.cleanupInterval)}},5e3).unref()}createWorker(){this.cleanupInterval.refresh();let e=new Gfe.Worker(this.source,{eval:!0,execArgv:[...process.execArgv,\"--unhandled-rejections=strict\"]});return e.on(\"message\",r=>{if(!e[Sh])throw new Error(\"Assertion failed: Worker sent a result without having a task assigned\");e[Sh].resolve(r),e[Sh]=null,e.unref(),this.workers.push(e)}),e.on(\"error\",r=>{e[Sh]?.reject(r),e[Sh]=null}),e.on(\"exit\",r=>{r!==0&&e[Sh]?.reject(new Error(`Worker exited with code ${r}`)),e[Sh]=null}),e}run(e){return this.limit(()=>{let r=this.workers.pop()??this.createWorker();return r.ref(),new Promise((o,a)=>{r[Sh]={resolve:o,reject:a},r.postMessage(e)})})}}});var Wfe=_((QUt,Yfe)=>{var n_;Yfe.exports.getContent=()=>(typeof n_>\"u\"&&(n_=ve(\"zlib\").brotliDecompressSync(Buffer.from(\"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\",\"base64\")).toString()),n_)});var Xi={};zt(Xi,{convertToZip:()=>rut,convertToZipWorker:()=>o_,extractArchiveTo:()=>Xfe,getDefaultTaskPool:()=>Vfe,getTaskPoolForConfiguration:()=>Jfe,makeArchiveFromDirectory:()=>tut});function $ct(t,e){switch(t){case\"async\":return new r2(o_,{poolSize:e});case\"workers\":return new n2((0,s_.getContent)(),{poolSize:e});default:throw new Error(`Assertion failed: Unknown value ${t} for taskPoolMode`)}}function Vfe(){return typeof i_>\"u\"&&(i_=$ct(\"workers\",Vi.availableParallelism())),i_}function Jfe(t){return typeof t>\"u\"?Vfe():al(eut,t,()=>{let e=t.get(\"taskPoolMode\"),r=t.get(\"taskPoolConcurrency\");switch(e){case\"async\":return new r2(o_,{poolSize:r});case\"workers\":return new n2((0,s_.getContent)(),{poolSize:r});default:throw new Error(`Assertion failed: Unknown value ${e} for taskPoolMode`)}})}async function o_(t){let{tmpFile:e,tgz:r,compressionLevel:o,extractBufferOpts:a}=t,n=new Ji(e,{create:!0,level:o,stats:Ea.makeDefaultStats()}),u=Buffer.from(r.buffer,r.byteOffset,r.byteLength);return await Xfe(u,n,a),n.saveAndClose(),e}async function tut(t,{baseFs:e=new Tn,prefixPath:r=Bt.root,compressionLevel:o,inMemory:a=!1}={}){let n;if(a)n=new Ji(null,{level:o});else{let A=await oe.mktempPromise(),p=z.join(A,\"archive.zip\");n=new Ji(p,{create:!0,level:o})}let u=z.resolve(Bt.root,r);return await n.copyPromise(u,t,{baseFs:e,stableTime:!0,stableSort:!0}),n}async function rut(t,e={}){let r=await oe.mktempPromise(),o=z.join(r,\"archive.zip\"),a=e.compressionLevel??e.configuration?.get(\"compressionLevel\")??\"mixed\",n={prefixPath:e.prefixPath,stripComponents:e.stripComponents};return await(e.taskPool??Jfe(e.configuration)).run({tmpFile:o,tgz:t,compressionLevel:a,extractBufferOpts:n}),new Ji(o,{level:e.compressionLevel})}async function*nut(t){let e=new zfe.default.Parse,r=new Kfe.PassThrough({objectMode:!0,autoDestroy:!0,emitClose:!0});e.on(\"entry\",o=>{r.write(o)}),e.on(\"error\",o=>{r.destroy(o)}),e.on(\"close\",()=>{r.destroyed||r.end()}),e.end(t);for await(let o of r){let a=o;yield a,a.resume()}}async function Xfe(t,e,{stripComponents:r=0,prefixPath:o=Bt.dot}={}){function a(n){if(n.path[0]===\"/\")return!0;let u=n.path.split(/\\//g);return!!(u.some(A=>A===\"..\")||u.length<=r)}for await(let n of nut(t)){if(a(n))continue;let u=z.normalize(le.toPortablePath(n.path)).replace(/\\/$/,\"\").split(/\\//g);if(u.length<=r)continue;let A=u.slice(r).join(\"/\"),p=z.join(o,A),h=420;switch((n.type===\"Directory\"||((n.mode??0)&73)!==0)&&(h|=73),n.type){case\"Directory\":e.mkdirpSync(z.dirname(p),{chmod:493,utimes:[vi.SAFE_TIME,vi.SAFE_TIME]}),e.mkdirSync(p,{mode:h}),e.utimesSync(p,vi.SAFE_TIME,vi.SAFE_TIME);break;case\"OldFile\":case\"File\":e.mkdirpSync(z.dirname(p),{chmod:493,utimes:[vi.SAFE_TIME,vi.SAFE_TIME]}),e.writeFileSync(p,await zy(n),{mode:h}),e.utimesSync(p,vi.SAFE_TIME,vi.SAFE_TIME);break;case\"SymbolicLink\":e.mkdirpSync(z.dirname(p),{chmod:493,utimes:[vi.SAFE_TIME,vi.SAFE_TIME]}),e.symlinkSync(n.linkpath,p),e.lutimesSync(p,vi.SAFE_TIME,vi.SAFE_TIME);break}}return e}var Kfe,zfe,s_,i_,eut,Zfe=Et(()=>{Ye();Pt();iA();Kfe=ve(\"stream\"),zfe=$e(qfe());jfe();Gl();s_=$e(Wfe());eut=new WeakMap});var epe=_((a_,$fe)=>{(function(t,e){typeof a_==\"object\"?$fe.exports=e():typeof define==\"function\"&&define.amd?define(e):t.treeify=e()})(a_,function(){function t(a,n){var u=n?\"\\u2514\":\"\\u251C\";return a?u+=\"\\u2500 \":u+=\"\\u2500\\u2500\\u2510\",u}function e(a,n){var u=[];for(var A in a)!a.hasOwnProperty(A)||n&&typeof a[A]==\"function\"||u.push(A);return u}function r(a,n,u,A,p,h,E){var I=\"\",v=0,x,C,R=A.slice(0);if(R.push([n,u])&&A.length>0&&(A.forEach(function(U,V){V>0&&(I+=(U[1]?\" \":\"\\u2502\")+\"  \"),!C&&U[0]===n&&(C=!0)}),I+=t(a,u)+a,p&&(typeof n!=\"object\"||n instanceof Date)&&(I+=\": \"+n),C&&(I+=\" (circular ref.)\"),E(I)),!C&&typeof n==\"object\"){var N=e(n,h);N.forEach(function(U){x=++v===N.length,r(U,n[U],x,R,p,h,E)})}}var o={};return o.asLines=function(a,n,u,A){var p=typeof u!=\"function\"?u:!1;r(\".\",a,!1,[],n,p,A||u)},o.asTree=function(a,n,u){var A=\"\";return r(\".\",a,!1,[],n,u,function(p){A+=p+`\n`}),A},o})});var $s={};zt($s,{emitList:()=>iut,emitTree:()=>ipe,treeNodeToJson:()=>npe,treeNodeToTreeify:()=>rpe});function rpe(t,{configuration:e}){let r={},o=0,a=(n,u)=>{let A=Array.isArray(n)?n.entries():Object.entries(n);for(let[p,h]of A){if(!h)continue;let{label:E,value:I,children:v}=h,x=[];typeof E<\"u\"&&x.push(Ed(e,E,2)),typeof I<\"u\"&&x.push(Ut(e,I[0],I[1])),x.length===0&&x.push(Ed(e,`${p}`,2));let C=x.join(\": \").trim(),R=`\\0${o++}\\0`,N=u[`${R}${C}`]={};typeof v<\"u\"&&a(v,N)}};if(typeof t.children>\"u\")throw new Error(\"The root node must only contain children\");return a(t.children,r),r}function npe(t){let e=r=>{if(typeof r.children>\"u\"){if(typeof r.value>\"u\")throw new Error(\"Assertion failed: Expected a value to be set if the children are missing\");return Cd(r.value[0],r.value[1])}let o=Array.isArray(r.children)?r.children.entries():Object.entries(r.children??{}),a=Array.isArray(r.children)?[]:{};for(let[n,u]of o)u&&(a[sut(n)]=e(u));return typeof r.value>\"u\"?a:{value:Cd(r.value[0],r.value[1]),children:a}};return e(t)}function iut(t,{configuration:e,stdout:r,json:o}){let a=t.map(n=>({value:n}));ipe({children:a},{configuration:e,stdout:r,json:o})}function ipe(t,{configuration:e,stdout:r,json:o,separators:a=0}){if(o){let u=Array.isArray(t.children)?t.children.values():Object.values(t.children??{});for(let A of u)A&&r.write(`${JSON.stringify(npe(A))}\n`);return}let n=(0,tpe.asTree)(rpe(t,{configuration:e}),!1,!1);if(n=n.replace(/\\0[0-9]+\\0/g,\"\"),a>=1&&(n=n.replace(/^([├└]─)/gm,`\\u2502\n$1`).replace(/^│\\n/,\"\")),a>=2)for(let u=0;u<2;++u)n=n.replace(/^([│ ].{2}[├│ ].{2}[^\\n]+\\n)(([│ ]).{2}[├└].{2}[^\\n]*\\n[│ ].{2}[│ ].{2}[├└]─)/gm,`$1$3  \\u2502 \n$2`).replace(/^│\\n/,\"\");if(a>=3)throw new Error(\"Only the first two levels are accepted by treeUtils.emitTree\");r.write(n)}function sut(t){return typeof t==\"string\"?t.replace(/^\\0[0-9]+\\0/,\"\"):t}var tpe,spe=Et(()=>{tpe=$e(epe());jl()});function i2(t){let e=t.match(out);if(!e?.groups)throw new Error(\"Assertion failed: Expected the checksum to match the requested pattern\");let r=e.groups.cacheVersion?parseInt(e.groups.cacheVersion):null;return{cacheKey:e.groups.cacheKey??null,cacheVersion:r,cacheSpec:e.groups.cacheSpec??null,hash:e.groups.hash}}var ope,l_,c_,Kx,Nr,out,u_=Et(()=>{Ye();Pt();Pt();iA();ope=ve(\"crypto\"),l_=$e(ve(\"fs\"));Wl();ih();Gl();bo();c_=Vy(process.env.YARN_CACHE_CHECKPOINT_OVERRIDE??process.env.YARN_CACHE_VERSION_OVERRIDE??9),Kx=Vy(process.env.YARN_CACHE_VERSION_OVERRIDE??10),Nr=class{constructor(e,{configuration:r,immutable:o=r.get(\"enableImmutableCache\"),check:a=!1}){this.markedFiles=new Set;this.mutexes=new Map;this.cacheId=`-${(0,ope.randomBytes)(8).toString(\"hex\")}.tmp`;this.configuration=r,this.cwd=e,this.immutable=o,this.check=a;let{cacheSpec:n,cacheKey:u}=Nr.getCacheKey(r);this.cacheSpec=n,this.cacheKey=u}static async find(e,{immutable:r,check:o}={}){let a=new Nr(e.get(\"cacheFolder\"),{configuration:e,immutable:r,check:o});return await a.setup(),a}static getCacheKey(e){let r=e.get(\"compressionLevel\"),o=r!==\"mixed\"?`c${r}`:\"\";return{cacheKey:[Kx,o].join(\"\"),cacheSpec:o}}get mirrorCwd(){if(!this.configuration.get(\"enableMirror\"))return null;let e=`${this.configuration.get(\"globalFolder\")}/cache`;return e!==this.cwd?e:null}getVersionFilename(e){return`${lE(e)}-${this.cacheKey}.zip`}getChecksumFilename(e,r){let a=i2(r).hash.slice(0,10);return`${lE(e)}-${a}.zip`}isChecksumCompatible(e){if(e===null)return!1;let{cacheVersion:r,cacheSpec:o}=i2(e);if(r===null||r<c_)return!1;let a=this.configuration.get(\"cacheMigrationMode\");return!(r<Kx&&a===\"always\"||o!==this.cacheSpec&&a!==\"required-only\")}getLocatorPath(e,r){return this.mirrorCwd===null?z.resolve(this.cwd,this.getVersionFilename(e)):r===null?z.resolve(this.cwd,this.getVersionFilename(e)):z.resolve(this.cwd,this.getChecksumFilename(e,r))}getLocatorMirrorPath(e){let r=this.mirrorCwd;return r!==null?z.resolve(r,this.getVersionFilename(e)):null}async setup(){if(!this.configuration.get(\"enableGlobalCache\"))if(this.immutable){if(!await oe.existsPromise(this.cwd))throw new Jt(56,\"Cache path does not exist.\")}else{await oe.mkdirPromise(this.cwd,{recursive:!0});let e=z.resolve(this.cwd,\".gitignore\");await oe.changeFilePromise(e,`/.gitignore\n*.flock\n*.tmp\n`)}(this.mirrorCwd||!this.immutable)&&await oe.mkdirPromise(this.mirrorCwd||this.cwd,{recursive:!0})}async fetchPackageFromCache(e,r,{onHit:o,onMiss:a,loader:n,...u}){let A=this.getLocatorMirrorPath(e),p=new Tn,h=()=>{let he=new Ji,Be=z.join(Bt.root,nM(e));return he.mkdirSync(Be,{recursive:!0}),he.writeJsonSync(z.join(Be,dr.manifest),{name:fn(e),mocked:!0}),he},E=async(he,{isColdHit:Be,controlPath:we=null})=>{if(we===null&&u.unstablePackages?.has(e.locatorHash))return{isValid:!0,hash:null};let g=r&&!Be?i2(r).cacheKey:this.cacheKey,Ee=!u.skipIntegrityCheck||!r?`${g}/${await LS(he)}`:r;if(we!==null){let ce=!u.skipIntegrityCheck||!r?`${this.cacheKey}/${await LS(we)}`:r;if(Ee!==ce)throw new Jt(18,\"The remote archive doesn't match the local checksum - has the local cache been corrupted?\")}let Pe=null;switch(r!==null&&Ee!==r&&(this.check?Pe=\"throw\":i2(r).cacheKey!==i2(Ee).cacheKey?Pe=\"update\":Pe=this.configuration.get(\"checksumBehavior\")),Pe){case null:case\"update\":return{isValid:!0,hash:Ee};case\"ignore\":return{isValid:!0,hash:r};case\"reset\":return{isValid:!1,hash:r};default:case\"throw\":throw new Jt(18,\"The remote archive doesn't match the expected checksum\")}},I=async he=>{if(!n)throw new Error(`Cache check required but no loader configured for ${qr(this.configuration,e)}`);let Be=await n(),we=Be.getRealPath();Be.saveAndClose(),await oe.chmodPromise(we,420);let g=await E(he,{controlPath:we,isColdHit:!1});if(!g.isValid)throw new Error(\"Assertion failed: Expected a valid checksum\");return g.hash},v=async()=>{if(A===null||!await oe.existsPromise(A)){let he=await n(),Be=he.getRealPath();return he.saveAndClose(),{source:\"loader\",path:Be}}return{source:\"mirror\",path:A}},x=async()=>{if(!n)throw new Error(`Cache entry required but missing for ${qr(this.configuration,e)}`);if(this.immutable)throw new Jt(56,`Cache entry required but missing for ${qr(this.configuration,e)}`);let{path:he,source:Be}=await v(),{hash:we}=await E(he,{isColdHit:!0}),g=this.getLocatorPath(e,we),Ee=[];Be!==\"mirror\"&&A!==null&&Ee.push(async()=>{let ce=`${A}${this.cacheId}`;await oe.copyFilePromise(he,ce,l_.default.constants.COPYFILE_FICLONE),await oe.chmodPromise(ce,420),await oe.renamePromise(ce,A)}),(!u.mirrorWriteOnly||A===null)&&Ee.push(async()=>{let ce=`${g}${this.cacheId}`;await oe.copyFilePromise(he,ce,l_.default.constants.COPYFILE_FICLONE),await oe.chmodPromise(ce,420),await oe.renamePromise(ce,g)});let Pe=u.mirrorWriteOnly?A??g:g;return await Promise.all(Ee.map(ce=>ce())),[!1,Pe,we]},C=async()=>{let Be=(async()=>{let we=u.unstablePackages?.has(e.locatorHash),g=we||!r||this.isChecksumCompatible(r)?this.getLocatorPath(e,r):null,Ee=g!==null?this.markedFiles.has(g)||await p.existsPromise(g):!1,Pe=!!u.mockedPackages?.has(e.locatorHash)&&(!this.check||!Ee),ce=Pe||Ee,ne=ce?o:a;if(ne&&ne(),ce){let ee=null,Ie=g;if(!Pe)if(this.check)ee=await I(Ie);else{let Fe=await E(Ie,{isColdHit:!1});if(Fe.isValid)ee=Fe.hash;else return x()}return[Pe,Ie,ee]}else{if(this.immutable&&we)throw new Jt(56,`Cache entry required but missing for ${qr(this.configuration,e)}; consider defining ${de.pretty(this.configuration,\"supportedArchitectures\",de.Type.CODE)} to cache packages for multiple systems`);return x()}})();this.mutexes.set(e.locatorHash,Be);try{return await Be}finally{this.mutexes.delete(e.locatorHash)}};for(let he;he=this.mutexes.get(e.locatorHash);)await he;let[R,N,U]=await C();R||this.markedFiles.add(N);let V,te=R?()=>h():()=>new Ji(N,{baseFs:p,readOnly:!0}),ae=new iy(()=>CN(()=>V=te(),he=>`Failed to open the cache entry for ${qr(this.configuration,e)}: ${he}`),z),fe=new _u(N,{baseFs:ae,pathUtils:z}),ue=()=>{V?.discardAndClose()},me=u.unstablePackages?.has(e.locatorHash)?null:U;return[fe,ue,me]}},out=/^(?:(?<cacheKey>(?<cacheVersion>[0-9]+)(?<cacheSpec>.*))\\/)?(?<hash>.*)$/});var zx,ape=Et(()=>{zx=(r=>(r[r.SCRIPT=0]=\"SCRIPT\",r[r.SHELLCODE=1]=\"SHELLCODE\",r))(zx||{})});var aut,oC,A_=Et(()=>{Pt();Nl();Qf();bo();aut=[[/^(git(?:\\+(?:https|ssh))?:\\/\\/.*(?:\\.git)?)#(.*)$/,(t,e,r,o)=>`${r}#commit=${o}`],[/^https:\\/\\/((?:[^/]+?)@)?codeload\\.github\\.com\\/([^/]+\\/[^/]+)\\/tar\\.gz\\/([0-9a-f]+)$/,(t,e,r=\"\",o,a)=>`https://${r}github.com/${o}.git#commit=${a}`],[/^https:\\/\\/((?:[^/]+?)@)?github\\.com\\/([^/]+\\/[^/]+?)(?:\\.git)?#([0-9a-f]+)$/,(t,e,r=\"\",o,a)=>`https://${r}github.com/${o}.git#commit=${a}`],[/^https?:\\/\\/[^/]+\\/(?:[^/]+\\/)*(?:@.+(?:\\/|(?:%2f)))?([^/]+)\\/(?:-|download)\\/\\1-[^/]+\\.tgz(?:#|$)/,t=>`npm:${t}`],[/^https:\\/\\/npm\\.pkg\\.github\\.com\\/download\\/(?:@[^/]+)\\/(?:[^/]+)\\/(?:[^/]+)\\/(?:[0-9a-f]+)(?:#|$)/,t=>`npm:${t}`],[/^https:\\/\\/npm\\.fontawesome\\.com\\/(?:@[^/]+)\\/([^/]+)\\/-\\/([^/]+)\\/\\1-\\2.tgz(?:#|$)/,t=>`npm:${t}`],[/^https?:\\/\\/[^/]+\\/.*\\/(@[^/]+)\\/([^/]+)\\/-\\/\\1\\/\\2-(?:[.\\d\\w-]+)\\.tgz(?:#|$)/,(t,e)=>_S({protocol:\"npm:\",source:null,selector:t,params:{__archiveUrl:e}})],[/^[^/]+\\.tgz#[0-9a-f]+$/,t=>`npm:${t}`]],oC=class{constructor(e){this.resolver=e;this.resolutions=null}async setup(e,{report:r}){let o=z.join(e.cwd,dr.lockfile);if(!oe.existsSync(o))return;let a=await oe.readFilePromise(o,\"utf8\"),n=Ki(a);if(Object.hasOwn(n,\"__metadata\"))return;let u=this.resolutions=new Map;for(let A of Object.keys(n)){let p=s1(A);if(!p){r.reportWarning(14,`Failed to parse the string \"${A}\" into a proper descriptor`);continue}let h=xa(p.range)?In(p,`npm:${p.range}`):p,{version:E,resolved:I}=n[A];if(!I)continue;let v;for(let[C,R]of aut){let N=I.match(C);if(N){v=R(E,...N);break}}if(!v){r.reportWarning(14,`${Gn(e.configuration,h)}: Only some patterns can be imported from legacy lockfiles (not \"${I}\")`);continue}let x=h;try{let C=vd(h.range),R=s1(C.selector,!0);R&&(x=R)}catch{}u.set(h.descriptorHash,Qs(x,v))}}supportsDescriptor(e,r){return this.resolutions?this.resolutions.has(e.descriptorHash):!1}supportsLocator(e,r){return!1}shouldPersistResolution(e,r){throw new Error(\"Assertion failed: This resolver doesn't support resolving locators to packages\")}bindDescriptor(e,r,o){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){if(!this.resolutions)throw new Error(\"Assertion failed: The resolution store should have been setup\");let a=this.resolutions.get(e.descriptorHash);if(!a)throw new Error(\"Assertion failed: The resolution should have been registered\");let n=$O(a),u=o.project.configuration.normalizeDependency(n);return await this.resolver.getCandidates(u,r,o)}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){throw new Error(\"Assertion failed: This resolver doesn't support resolving locators to packages\")}}});var fA,lpe=Et(()=>{Wl();O1();jl();fA=class extends Xs{constructor({configuration:r,stdout:o,suggestInstall:a=!0}){super();this.errorCount=0;XI(this,{configuration:r}),this.configuration=r,this.stdout=o,this.suggestInstall=a}static async start(r,o){let a=new this(r);try{await o(a)}catch(n){a.reportExceptionOnce(n)}finally{await a.finalize()}return a}hasErrors(){return this.errorCount>0}exitCode(){return this.hasErrors()?1:0}reportCacheHit(r){}reportCacheMiss(r){}startSectionSync(r,o){return o()}async startSectionPromise(r,o){return await o()}startTimerSync(r,o,a){return(typeof o==\"function\"?o:a)()}async startTimerPromise(r,o,a){return await(typeof o==\"function\"?o:a)()}reportSeparator(){}reportInfo(r,o){}reportWarning(r,o){}reportError(r,o){this.errorCount+=1,this.stdout.write(`${Ut(this.configuration,\"\\u27A4\",\"redBright\")} ${this.formatNameWithHyperlink(r)}: ${o}\n`)}reportProgress(r){return{...Promise.resolve().then(async()=>{for await(let{}of r);}),stop:()=>{}}}reportJson(r){}reportFold(r,o){}async finalize(){this.errorCount>0&&(this.stdout.write(`\n`),this.stdout.write(`${Ut(this.configuration,\"\\u27A4\",\"redBright\")} Errors happened when preparing the environment required to run this command.\n`),this.suggestInstall&&this.stdout.write(`${Ut(this.configuration,\"\\u27A4\",\"redBright\")} This might be caused by packages being missing from the lockfile, in which case running \"yarn install\" might help.\n`))}formatNameWithHyperlink(r){return yU(r,{configuration:this.configuration,json:!1})}}});var aC,f_=Et(()=>{bo();aC=class{constructor(e){this.resolver=e}supportsDescriptor(e,r){return!!(r.project.storedResolutions.get(e.descriptorHash)||r.project.originalPackages.has(OS(e).locatorHash))}supportsLocator(e,r){return!!(r.project.originalPackages.has(e.locatorHash)&&!r.project.lockfileNeedsRefresh)}shouldPersistResolution(e,r){throw new Error(\"The shouldPersistResolution method shouldn't be called on the lockfile resolver, which would always answer yes\")}bindDescriptor(e,r,o){return e}getResolutionDependencies(e,r){return this.resolver.getResolutionDependencies(e,r)}async getCandidates(e,r,o){let a=o.project.storedResolutions.get(e.descriptorHash);if(a){let u=o.project.originalPackages.get(a);if(u)return[u]}let n=o.project.originalPackages.get(OS(e).locatorHash);if(n)return[n];throw new Error(\"Resolution expected from the lockfile data\")}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){let o=r.project.originalPackages.get(e.locatorHash);if(!o)throw new Error(\"The lockfile resolver isn't meant to resolve packages - they should already have been stored into a cache\");return o}}});function Kf(){}function lut(t,e,r,o,a){for(var n=0,u=e.length,A=0,p=0;n<u;n++){var h=e[n];if(h.removed){if(h.value=t.join(o.slice(p,p+h.count)),p+=h.count,n&&e[n-1].added){var I=e[n-1];e[n-1]=e[n],e[n]=I}}else{if(!h.added&&a){var E=r.slice(A,A+h.count);E=E.map(function(x,C){var R=o[p+C];return R.length>x.length?R:x}),h.value=t.join(E)}else h.value=t.join(r.slice(A,A+h.count));A+=h.count,h.added||(p+=h.count)}}var v=e[u-1];return u>1&&typeof v.value==\"string\"&&(v.added||v.removed)&&t.equals(\"\",v.value)&&(e[u-2].value+=v.value,e.pop()),e}function cut(t){return{newPos:t.newPos,components:t.components.slice(0)}}function uut(t,e){if(typeof t==\"function\")e.callback=t;else if(t)for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r]);return e}function Ape(t,e,r){return r=uut(r,{ignoreWhitespace:!0}),m_.diff(t,e,r)}function Aut(t,e,r){return y_.diff(t,e,r)}function Vx(t){return typeof Symbol==\"function\"&&typeof Symbol.iterator==\"symbol\"?Vx=function(e){return typeof e}:Vx=function(e){return e&&typeof Symbol==\"function\"&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},Vx(t)}function p_(t){return hut(t)||gut(t)||dut(t)||mut()}function hut(t){if(Array.isArray(t))return h_(t)}function gut(t){if(typeof Symbol<\"u\"&&Symbol.iterator in Object(t))return Array.from(t)}function dut(t,e){if(!!t){if(typeof t==\"string\")return h_(t,e);var r=Object.prototype.toString.call(t).slice(8,-1);if(r===\"Object\"&&t.constructor&&(r=t.constructor.name),r===\"Map\"||r===\"Set\")return Array.from(t);if(r===\"Arguments\"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return h_(t,e)}}function h_(t,e){(e==null||e>t.length)&&(e=t.length);for(var r=0,o=new Array(e);r<e;r++)o[r]=t[r];return o}function mut(){throw new TypeError(`Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function g_(t,e,r,o,a){e=e||[],r=r||[],o&&(t=o(a,t));var n;for(n=0;n<e.length;n+=1)if(e[n]===t)return r[n];var u;if(yut.call(t)===\"[object Array]\"){for(e.push(t),u=new Array(t.length),r.push(u),n=0;n<t.length;n+=1)u[n]=g_(t[n],e,r,o,a);return e.pop(),r.pop(),u}if(t&&t.toJSON&&(t=t.toJSON()),Vx(t)===\"object\"&&t!==null){e.push(t),u={},r.push(u);var A=[],p;for(p in t)t.hasOwnProperty(p)&&A.push(p);for(A.sort(),n=0;n<A.length;n+=1)p=A[n],u[p]=g_(t[p],e,r,o,p);e.pop(),r.pop()}else u=t;return u}function fpe(t,e,r,o,a,n,u){u||(u={}),typeof u.context>\"u\"&&(u.context=4);var A=Aut(r,o,u);if(!A)return;A.push({value:\"\",lines:[]});function p(U){return U.map(function(V){return\" \"+V})}for(var h=[],E=0,I=0,v=[],x=1,C=1,R=function(V){var te=A[V],ae=te.lines||te.value.replace(/\\n$/,\"\").split(`\n`);if(te.lines=ae,te.added||te.removed){var fe;if(!E){var ue=A[V-1];E=x,I=C,ue&&(v=u.context>0?p(ue.lines.slice(-u.context)):[],E-=v.length,I-=v.length)}(fe=v).push.apply(fe,p_(ae.map(function(ce){return(te.added?\"+\":\"-\")+ce}))),te.added?C+=ae.length:x+=ae.length}else{if(E)if(ae.length<=u.context*2&&V<A.length-2){var me;(me=v).push.apply(me,p_(p(ae)))}else{var he,Be=Math.min(ae.length,u.context);(he=v).push.apply(he,p_(p(ae.slice(0,Be))));var we={oldStart:E,oldLines:x-E+Be,newStart:I,newLines:C-I+Be,lines:v};if(V>=A.length-2&&ae.length<=u.context){var g=/\\n$/.test(r),Ee=/\\n$/.test(o),Pe=ae.length==0&&v.length>we.oldLines;!g&&Pe&&r.length>0&&v.splice(we.oldLines,0,\"\\\\ No newline at end of file\"),(!g&&!Pe||!Ee)&&v.push(\"\\\\ No newline at end of file\")}h.push(we),E=0,I=0,v=[]}x+=ae.length,C+=ae.length}},N=0;N<A.length;N++)R(N);return{oldFileName:t,newFileName:e,oldHeader:a,newHeader:n,hunks:h}}var i3t,cpe,upe,m_,y_,fut,put,yut,s2,d_,E_=Et(()=>{Kf.prototype={diff:function(e,r){var o=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{},a=o.callback;typeof o==\"function\"&&(a=o,o={}),this.options=o;var n=this;function u(R){return a?(setTimeout(function(){a(void 0,R)},0),!0):R}e=this.castInput(e),r=this.castInput(r),e=this.removeEmpty(this.tokenize(e)),r=this.removeEmpty(this.tokenize(r));var A=r.length,p=e.length,h=1,E=A+p;o.maxEditLength&&(E=Math.min(E,o.maxEditLength));var I=[{newPos:-1,components:[]}],v=this.extractCommon(I[0],r,e,0);if(I[0].newPos+1>=A&&v+1>=p)return u([{value:this.join(r),count:r.length}]);function x(){for(var R=-1*h;R<=h;R+=2){var N=void 0,U=I[R-1],V=I[R+1],te=(V?V.newPos:0)-R;U&&(I[R-1]=void 0);var ae=U&&U.newPos+1<A,fe=V&&0<=te&&te<p;if(!ae&&!fe){I[R]=void 0;continue}if(!ae||fe&&U.newPos<V.newPos?(N=cut(V),n.pushComponent(N.components,void 0,!0)):(N=U,N.newPos++,n.pushComponent(N.components,!0,void 0)),te=n.extractCommon(N,r,e,R),N.newPos+1>=A&&te+1>=p)return u(lut(n,N.components,r,e,n.useLongestToken));I[R]=N}h++}if(a)(function R(){setTimeout(function(){if(h>E)return a();x()||R()},0)})();else for(;h<=E;){var C=x();if(C)return C}},pushComponent:function(e,r,o){var a=e[e.length-1];a&&a.added===r&&a.removed===o?e[e.length-1]={count:a.count+1,added:r,removed:o}:e.push({count:1,added:r,removed:o})},extractCommon:function(e,r,o,a){for(var n=r.length,u=o.length,A=e.newPos,p=A-a,h=0;A+1<n&&p+1<u&&this.equals(r[A+1],o[p+1]);)A++,p++,h++;return h&&e.components.push({count:h}),e.newPos=A,p},equals:function(e,r){return this.options.comparator?this.options.comparator(e,r):e===r||this.options.ignoreCase&&e.toLowerCase()===r.toLowerCase()},removeEmpty:function(e){for(var r=[],o=0;o<e.length;o++)e[o]&&r.push(e[o]);return r},castInput:function(e){return e},tokenize:function(e){return e.split(\"\")},join:function(e){return e.join(\"\")}};i3t=new Kf;cpe=/^[A-Za-z\\xC0-\\u02C6\\u02C8-\\u02D7\\u02DE-\\u02FF\\u1E00-\\u1EFF]+$/,upe=/\\S/,m_=new Kf;m_.equals=function(t,e){return this.options.ignoreCase&&(t=t.toLowerCase(),e=e.toLowerCase()),t===e||this.options.ignoreWhitespace&&!upe.test(t)&&!upe.test(e)};m_.tokenize=function(t){for(var e=t.split(/([^\\S\\r\\n]+|[()[\\]{}'\"\\r\\n]|\\b)/),r=0;r<e.length-1;r++)!e[r+1]&&e[r+2]&&cpe.test(e[r])&&cpe.test(e[r+2])&&(e[r]+=e[r+2],e.splice(r+1,2),r--);return e};y_=new Kf;y_.tokenize=function(t){var e=[],r=t.split(/(\\n|\\r\\n)/);r[r.length-1]||r.pop();for(var o=0;o<r.length;o++){var a=r[o];o%2&&!this.options.newlineIsToken?e[e.length-1]+=a:(this.options.ignoreWhitespace&&(a=a.trim()),e.push(a))}return e};fut=new Kf;fut.tokenize=function(t){return t.split(/(\\S.+?[.!?])(?=\\s+|$)/)};put=new Kf;put.tokenize=function(t){return t.split(/([{}:;,]|\\s+)/)};yut=Object.prototype.toString,s2=new Kf;s2.useLongestToken=!0;s2.tokenize=y_.tokenize;s2.castInput=function(t){var e=this.options,r=e.undefinedReplacement,o=e.stringifyReplacer,a=o===void 0?function(n,u){return typeof u>\"u\"?r:u}:o;return typeof t==\"string\"?t:JSON.stringify(g_(t,null,null,a),a,\"  \")};s2.equals=function(t,e){return Kf.prototype.equals.call(s2,t.replace(/,([\\r\\n])/g,\"$1\"),e.replace(/,([\\r\\n])/g,\"$1\"))};d_=new Kf;d_.tokenize=function(t){return t.slice()};d_.join=d_.removeEmpty=function(t){return t}});var hpe=_((o3t,ppe)=>{var Eut=ql(),Cut=pE(),wut=/\\.|\\[(?:[^[\\]]*|([\"'])(?:(?!\\1)[^\\\\]|\\\\.)*?\\1)\\]/,Iut=/^\\w*$/;function But(t,e){if(Eut(t))return!1;var r=typeof t;return r==\"number\"||r==\"symbol\"||r==\"boolean\"||t==null||Cut(t)?!0:Iut.test(t)||!wut.test(t)||e!=null&&t in Object(e)}ppe.exports=But});var mpe=_((a3t,dpe)=>{var gpe=UP(),vut=\"Expected a function\";function C_(t,e){if(typeof t!=\"function\"||e!=null&&typeof e!=\"function\")throw new TypeError(vut);var r=function(){var o=arguments,a=e?e.apply(this,o):o[0],n=r.cache;if(n.has(a))return n.get(a);var u=t.apply(this,o);return r.cache=n.set(a,u)||n,u};return r.cache=new(C_.Cache||gpe),r}C_.Cache=gpe;dpe.exports=C_});var Epe=_((l3t,ype)=>{var Dut=mpe(),Put=500;function Sut(t){var e=Dut(t,function(o){return r.size===Put&&r.clear(),o}),r=e.cache;return e}ype.exports=Sut});var w_=_((c3t,Cpe)=>{var but=Epe(),xut=/[^.[\\]]+|\\[(?:(-?\\d+(?:\\.\\d+)?)|([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2)\\]|(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))/g,kut=/\\\\(\\\\)?/g,Qut=but(function(t){var e=[];return t.charCodeAt(0)===46&&e.push(\"\"),t.replace(xut,function(r,o,a,n){e.push(a?n.replace(kut,\"$1\"):o||r)}),e});Cpe.exports=Qut});var jd=_((u3t,wpe)=>{var Fut=ql(),Rut=hpe(),Tut=w_(),Lut=L1();function Nut(t,e){return Fut(t)?t:Rut(t,e)?[t]:Tut(Lut(t))}wpe.exports=Nut});var lC=_((A3t,Ipe)=>{var Out=pE(),Mut=1/0;function Uut(t){if(typeof t==\"string\"||Out(t))return t;var e=t+\"\";return e==\"0\"&&1/t==-Mut?\"-0\":e}Ipe.exports=Uut});var Jx=_((f3t,Bpe)=>{var _ut=jd(),Hut=lC();function qut(t,e){e=_ut(e,t);for(var r=0,o=e.length;t!=null&&r<o;)t=t[Hut(e[r++])];return r&&r==o?t:void 0}Bpe.exports=qut});var I_=_((p3t,Dpe)=>{var Gut=tS(),jut=jd(),Yut=_I(),vpe=sl(),Wut=lC();function Kut(t,e,r,o){if(!vpe(t))return t;e=jut(e,t);for(var a=-1,n=e.length,u=n-1,A=t;A!=null&&++a<n;){var p=Wut(e[a]),h=r;if(p===\"__proto__\"||p===\"constructor\"||p===\"prototype\")return t;if(a!=u){var E=A[p];h=o?o(E,p,A):void 0,h===void 0&&(h=vpe(E)?E:Yut(e[a+1])?[]:{})}Gut(A,p,h),A=A[p]}return t}Dpe.exports=Kut});var Spe=_((h3t,Ppe)=>{var zut=Jx(),Vut=I_(),Jut=jd();function Xut(t,e,r){for(var o=-1,a=e.length,n={};++o<a;){var u=e[o],A=zut(t,u);r(A,u)&&Vut(n,Jut(u,t),A)}return n}Ppe.exports=Xut});var xpe=_((g3t,bpe)=>{function Zut(t,e){return t!=null&&e in Object(t)}bpe.exports=Zut});var B_=_((d3t,kpe)=>{var $ut=jd(),eAt=OI(),tAt=ql(),rAt=_I(),nAt=jP(),iAt=lC();function sAt(t,e,r){e=$ut(e,t);for(var o=-1,a=e.length,n=!1;++o<a;){var u=iAt(e[o]);if(!(n=t!=null&&r(t,u)))break;t=t[u]}return n||++o!=a?n:(a=t==null?0:t.length,!!a&&nAt(a)&&rAt(u,a)&&(tAt(t)||eAt(t)))}kpe.exports=sAt});var Fpe=_((m3t,Qpe)=>{var oAt=xpe(),aAt=B_();function lAt(t,e){return t!=null&&aAt(t,e,oAt)}Qpe.exports=lAt});var Tpe=_((y3t,Rpe)=>{var cAt=Spe(),uAt=Fpe();function AAt(t,e){return cAt(t,e,function(r,o){return uAt(t,o)})}Rpe.exports=AAt});var Mpe=_((E3t,Ope)=>{var Lpe=hd(),fAt=OI(),pAt=ql(),Npe=Lpe?Lpe.isConcatSpreadable:void 0;function hAt(t){return pAt(t)||fAt(t)||!!(Npe&&t&&t[Npe])}Ope.exports=hAt});var Hpe=_((C3t,_pe)=>{var gAt=qP(),dAt=Mpe();function Upe(t,e,r,o,a){var n=-1,u=t.length;for(r||(r=dAt),a||(a=[]);++n<u;){var A=t[n];e>0&&r(A)?e>1?Upe(A,e-1,r,o,a):gAt(a,A):o||(a[a.length]=A)}return a}_pe.exports=Upe});var Gpe=_((w3t,qpe)=>{var mAt=Hpe();function yAt(t){var e=t==null?0:t.length;return e?mAt(t,1):[]}qpe.exports=yAt});var v_=_((I3t,jpe)=>{var EAt=Gpe(),CAt=fN(),wAt=pN();function IAt(t){return wAt(CAt(t,void 0,EAt),t+\"\")}jpe.exports=IAt});var D_=_((B3t,Ype)=>{var BAt=Tpe(),vAt=v_(),DAt=vAt(function(t,e){return t==null?{}:BAt(t,e)});Ype.exports=DAt});var Xx,Wpe=Et(()=>{Wl();Xx=class{constructor(e){this.resolver=e}supportsDescriptor(e,r){return this.resolver.supportsDescriptor(e,r)}supportsLocator(e,r){return this.resolver.supportsLocator(e,r)}shouldPersistResolution(e,r){return this.resolver.shouldPersistResolution(e,r)}bindDescriptor(e,r,o){return this.resolver.bindDescriptor(e,r,o)}getResolutionDependencies(e,r){return this.resolver.getResolutionDependencies(e,r)}async getCandidates(e,r,o){throw new Jt(20,`This package doesn't seem to be present in your lockfile; run \"yarn install\" to update the lockfile`)}async getSatisfying(e,r,o,a){throw new Jt(20,`This package doesn't seem to be present in your lockfile; run \"yarn install\" to update the lockfile`)}async resolve(e,r){throw new Jt(20,`This package doesn't seem to be present in your lockfile; run \"yarn install\" to update the lockfile`)}}});var Qi,P_=Et(()=>{Wl();Qi=class extends Xs{reportCacheHit(e){}reportCacheMiss(e){}startSectionSync(e,r){return r()}async startSectionPromise(e,r){return await r()}startTimerSync(e,r,o){return(typeof r==\"function\"?r:o)()}async startTimerPromise(e,r,o){return await(typeof r==\"function\"?r:o)()}reportSeparator(){}reportInfo(e,r){}reportWarning(e,r){}reportError(e,r){}reportProgress(e){return{...Promise.resolve().then(async()=>{for await(let{}of e);}),stop:()=>{}}}reportJson(e){}reportFold(e,r){}async finalize(){}}});var Kpe,cC,S_=Et(()=>{Pt();Kpe=$e(RS());fE();Dd();jl();ih();Qf();bo();cC=class{constructor(e,{project:r}){this.workspacesCwds=new Set;this.project=r,this.cwd=e}async setup(){this.manifest=await Ot.tryFind(this.cwd)??new Ot,this.relativeCwd=z.relative(this.project.cwd,this.cwd)||Bt.dot;let e=this.manifest.name?this.manifest.name:tA(null,`${this.computeCandidateName()}-${Js(this.relativeCwd).substring(0,6)}`);this.anchoredDescriptor=In(e,`${Xn.protocol}${this.relativeCwd}`),this.anchoredLocator=Qs(e,`${Xn.protocol}${this.relativeCwd}`);let r=this.manifest.workspaceDefinitions.map(({pattern:a})=>a);if(r.length===0)return;let o=await(0,Kpe.default)(r,{cwd:le.fromPortablePath(this.cwd),onlyDirectories:!0,ignore:[\"**/node_modules\",\"**/.git\",\"**/.yarn\"]});o.sort(),await o.reduce(async(a,n)=>{let u=z.resolve(this.cwd,le.toPortablePath(n)),A=await oe.existsPromise(z.join(u,\"package.json\"));await a,A&&this.workspacesCwds.add(u)},Promise.resolve())}get anchoredPackage(){let e=this.project.storedPackages.get(this.anchoredLocator.locatorHash);if(!e)throw new Error(`Assertion failed: Expected workspace ${a1(this.project.configuration,this)} (${Ut(this.project.configuration,z.join(this.cwd,dr.manifest),yt.PATH)}) to have been resolved. Run \"yarn install\" to update the lockfile`);return e}accepts(e){let r=e.indexOf(\":\"),o=r!==-1?e.slice(0,r+1):null,a=r!==-1?e.slice(r+1):e;if(o===Xn.protocol&&z.normalize(a)===this.relativeCwd||o===Xn.protocol&&(a===\"*\"||a===\"^\"||a===\"~\"))return!0;let n=xa(a);return n?o===Xn.protocol?n.test(this.manifest.version??\"0.0.0\"):this.project.configuration.get(\"enableTransparentWorkspaces\")&&this.manifest.version!==null?n.test(this.manifest.version):!1:!1}computeCandidateName(){return this.cwd===this.project.cwd?\"root-workspace\":`${z.basename(this.cwd)}`||\"unnamed-workspace\"}getRecursiveWorkspaceDependencies({dependencies:e=Ot.hardDependencies}={}){let r=new Set,o=a=>{for(let n of e)for(let u of a.manifest[n].values()){let A=this.project.tryWorkspaceByDescriptor(u);A===null||r.has(A)||(r.add(A),o(A))}};return o(this),r}getRecursiveWorkspaceDependents({dependencies:e=Ot.hardDependencies}={}){let r=new Set,o=a=>{for(let n of this.project.workspaces)e.some(A=>[...n.manifest[A].values()].some(p=>{let h=this.project.tryWorkspaceByDescriptor(p);return h!==null&&i1(h.anchoredLocator,a.anchoredLocator)}))&&!r.has(n)&&(r.add(n),o(n))};return o(this),r}getRecursiveWorkspaceChildren(){let e=new Set([this]);for(let r of e)for(let o of r.workspacesCwds){let a=this.project.workspacesByCwd.get(o);a&&e.add(a)}return e.delete(this),Array.from(e)}async persistManifest(){let e={};this.manifest.exportTo(e);let r=z.join(this.cwd,Ot.fileName),o=`${JSON.stringify(e,null,this.manifest.indent)}\n`;await oe.changeFilePromise(r,o,{automaticNewlines:!0}),this.manifest.raw=e}}});function QAt({project:t,allDescriptors:e,allResolutions:r,allPackages:o,accessibleLocators:a=new Set,optionalBuilds:n=new Set,peerRequirements:u=new Map,peerWarnings:A=[],volatileDescriptors:p=new Set}){let h=new Map,E=[],I=new Map,v=new Map,x=new Map,C=new Map,R=new Map,N=new Map(t.workspaces.map(ue=>{let me=ue.anchoredLocator.locatorHash,he=o.get(me);if(typeof he>\"u\")throw new Error(\"Assertion failed: The workspace should have an associated package\");return[me,e1(he)]})),U=()=>{let ue=oe.mktempSync(),me=z.join(ue,\"stacktrace.log\"),he=String(E.length+1).length,Be=E.map((we,g)=>`${`${g+1}.`.padStart(he,\" \")} ${ba(we)}\n`).join(\"\");throw oe.writeFileSync(me,Be),oe.detachTemp(ue),new Jt(45,`Encountered a stack overflow when resolving peer dependencies; cf ${le.fromPortablePath(me)}`)},V=ue=>{let me=r.get(ue.descriptorHash);if(typeof me>\"u\")throw new Error(\"Assertion failed: The resolution should have been registered\");let he=o.get(me);if(!he)throw new Error(\"Assertion failed: The package could not be found\");return he},te=(ue,me,he,{top:Be,optional:we})=>{E.length>1e3&&U(),E.push(me);let g=ae(ue,me,he,{top:Be,optional:we});return E.pop(),g},ae=(ue,me,he,{top:Be,optional:we})=>{if(we||n.delete(me.locatorHash),a.has(me.locatorHash))return;a.add(me.locatorHash);let g=o.get(me.locatorHash);if(!g)throw new Error(`Assertion failed: The package (${qr(t.configuration,me)}) should have been registered`);let Ee=[],Pe=[],ce=[],ne=[],ee=[];for(let Fe of Array.from(g.dependencies.values())){if(g.peerDependencies.has(Fe.identHash)&&g.locatorHash!==Be)continue;if(bf(Fe))throw new Error(\"Assertion failed: Virtual packages shouldn't be encountered when virtualizing a branch\");p.delete(Fe.descriptorHash);let At=we;if(!At){let Te=g.dependenciesMeta.get(fn(Fe));if(typeof Te<\"u\"){let Ve=Te.get(null);typeof Ve<\"u\"&&Ve.optional&&(At=!0)}}let H=r.get(Fe.descriptorHash);if(!H)throw new Error(`Assertion failed: The resolution (${Gn(t.configuration,Fe)}) should have been registered`);let at=N.get(H)||o.get(H);if(!at)throw new Error(`Assertion failed: The package (${H}, resolved from ${Gn(t.configuration,Fe)}) should have been registered`);if(at.peerDependencies.size===0){te(Fe,at,new Map,{top:Be,optional:At});continue}let Re,ke,xe=new Set,He;Pe.push(()=>{Re=tM(Fe,me.locatorHash),ke=rM(at,me.locatorHash),g.dependencies.delete(Fe.identHash),g.dependencies.set(Re.identHash,Re),r.set(Re.descriptorHash,ke.locatorHash),e.set(Re.descriptorHash,Re),o.set(ke.locatorHash,ke),Ee.push([at,Re,ke])}),ce.push(()=>{He=new Map;for(let Te of ke.peerDependencies.values()){let Ve=g.dependencies.get(Te.identHash);if(!Ve&&n1(me,Te)&&(ue.identHash===me.identHash?Ve=ue:(Ve=In(me,ue.range),e.set(Ve.descriptorHash,Ve),r.set(Ve.descriptorHash,me.locatorHash),p.delete(Ve.descriptorHash))),(!Ve||Ve.range===\"missing:\")&&ke.dependencies.has(Te.identHash)){ke.peerDependencies.delete(Te.identHash);continue}Ve||(Ve=In(Te,\"missing:\")),ke.dependencies.set(Ve.identHash,Ve),bf(Ve)&&yd(x,Ve.descriptorHash).add(ke.locatorHash),I.set(Ve.identHash,Ve),Ve.range===\"missing:\"&&xe.add(Ve.identHash),He.set(Te.identHash,he.get(Te.identHash)??ke.locatorHash)}ke.dependencies=new Map(ks(ke.dependencies,([Te,Ve])=>fn(Ve)))}),ne.push(()=>{if(!o.has(ke.locatorHash))return;let Te=h.get(at.locatorHash);typeof Te==\"number\"&&Te>=2&&U();let Ve=h.get(at.locatorHash),qe=typeof Ve<\"u\"?Ve+1:1;h.set(at.locatorHash,qe),te(Re,ke,He,{top:Be,optional:At}),h.set(at.locatorHash,qe-1)}),ee.push(()=>{let Te=g.dependencies.get(Fe.identHash);if(typeof Te>\"u\")throw new Error(\"Assertion failed: Expected the peer dependency to have been turned into a dependency\");let Ve=r.get(Te.descriptorHash);if(typeof Ve>\"u\")throw new Error(\"Assertion failed: Expected the descriptor to be registered\");if(yd(R,Ve).add(me.locatorHash),!!o.has(ke.locatorHash)){for(let qe of ke.peerDependencies.values()){let b=He.get(qe.identHash);if(typeof b>\"u\")throw new Error(\"Assertion failed: Expected the peer dependency ident to be registered\");Yy(Wy(C,b),fn(qe)).push(ke.locatorHash)}for(let qe of xe)ke.dependencies.delete(qe)}})}for(let Fe of[...Pe,...ce])Fe();let Ie;do{Ie=!0;for(let[Fe,At,H]of Ee){let at=Wy(v,Fe.locatorHash),Re=Js(...[...H.dependencies.values()].map(Te=>{let Ve=Te.range!==\"missing:\"?r.get(Te.descriptorHash):\"missing:\";if(typeof Ve>\"u\")throw new Error(`Assertion failed: Expected the resolution for ${Gn(t.configuration,Te)} to have been registered`);return Ve===Be?`${Ve} (top)`:Ve}),At.identHash),ke=at.get(Re);if(typeof ke>\"u\"){at.set(Re,At);continue}if(ke===At)continue;o.delete(H.locatorHash),e.delete(At.descriptorHash),r.delete(At.descriptorHash),a.delete(H.locatorHash);let xe=x.get(At.descriptorHash)||[],He=[g.locatorHash,...xe];x.delete(At.descriptorHash);for(let Te of He){let Ve=o.get(Te);typeof Ve>\"u\"||(Ve.dependencies.get(At.identHash).descriptorHash!==ke.descriptorHash&&(Ie=!1),Ve.dependencies.set(At.identHash,ke))}}}while(!Ie);for(let Fe of[...ne,...ee])Fe()};for(let ue of t.workspaces){let me=ue.anchoredLocator;p.delete(ue.anchoredDescriptor.descriptorHash),te(ue.anchoredDescriptor,me,new Map,{top:me.locatorHash,optional:!1})}let fe=new Map;for(let[ue,me]of R){let he=o.get(ue);if(typeof he>\"u\")throw new Error(\"Assertion failed: Expected the root to be registered\");let Be=C.get(ue);if(!(typeof Be>\"u\"))for(let we of me){let g=o.get(we);if(!(typeof g>\"u\")&&!!t.tryWorkspaceByLocator(g))for(let[Ee,Pe]of Be){let ce=Vs(Ee);if(g.peerDependencies.has(ce.identHash))continue;let ne=`p${Js(we,Ee,ue).slice(0,5)}`;u.set(ne,{subject:we,requested:ce,rootRequester:ue,allRequesters:Pe});let ee=he.dependencies.get(ce.identHash);if(typeof ee<\"u\"){let Ie=V(ee),Fe=Ie.version??\"0.0.0\",At=new Set;for(let at of Pe){let Re=o.get(at);if(typeof Re>\"u\")throw new Error(\"Assertion failed: Expected the link to be registered\");let ke=Re.peerDependencies.get(ce.identHash);if(typeof ke>\"u\")throw new Error(\"Assertion failed: Expected the ident to be registered\");At.add(ke.range)}if(![...At].every(at=>{if(at.startsWith(Xn.protocol)){if(!t.tryWorkspaceByLocator(Ie))return!1;at=at.slice(Xn.protocol.length),(at===\"^\"||at===\"~\")&&(at=\"*\")}return kf(Fe,at)})){let at=al(fe,Ie.locatorHash,()=>({type:2,requested:ce,subject:Ie,dependents:new Map,requesters:new Map,links:new Map,version:Fe,hash:`p${Ie.locatorHash.slice(0,5)}`}));at.dependents.set(g.locatorHash,g),at.requesters.set(he.locatorHash,he);for(let Re of Pe)at.links.set(Re,o.get(Re));A.push({type:1,subject:g,requested:ce,requester:he,version:Fe,hash:ne,requirementCount:Pe.length})}}else he.peerDependenciesMeta.get(Ee)?.optional||A.push({type:0,subject:g,requested:ce,requester:he,hash:ne})}}}A.push(...fe.values())}function FAt(t,e){let r=IN(t.peerWarnings,\"type\"),o=r[2]?.map(n=>{let u=Array.from(n.links.values(),E=>{let I=t.storedPackages.get(E.locatorHash);if(typeof I>\"u\")throw new Error(\"Assertion failed: Expected the package to be registered\");let v=I.peerDependencies.get(n.requested.identHash);if(typeof v>\"u\")throw new Error(\"Assertion failed: Expected the ident to be registered\");return v.range}),A=n.links.size>1?\"and other dependencies request\":\"requests\",p=sM(u),h=p?cE(t.configuration,p):Ut(t.configuration,\"but they have non-overlapping ranges!\",\"redBright\");return`${cs(t.configuration,n.requested)} is listed by your project with version ${o1(t.configuration,n.version)}, which doesn't satisfy what ${cs(t.configuration,n.requesters.values().next().value)} (${Ut(t.configuration,n.hash,yt.CODE)}) ${A} (${h}).`})??[],a=r[0]?.map(n=>`${qr(t.configuration,n.subject)} doesn't provide ${cs(t.configuration,n.requested)} (${Ut(t.configuration,n.hash,yt.CODE)}), requested by ${cs(t.configuration,n.requester)}.`)??[];e.startSectionSync({reportFooter:()=>{e.reportWarning(86,`Some peer dependencies are incorrectly met; run ${Ut(t.configuration,\"yarn explain peer-requirements <hash>\",yt.CODE)} for details, where ${Ut(t.configuration,\"<hash>\",yt.CODE)} is the six-letter p-prefixed code.`)},skipIfEmpty:!0},()=>{for(let n of ks(o,u=>Xy.default(u)))e.reportWarning(60,n);for(let n of ks(a,u=>Xy.default(u)))e.reportWarning(2,n)})}var Zx,$x,ek,Jpe,k_,x_,Q_,tk,PAt,SAt,zpe,bAt,xAt,kAt,hl,b_,rk,Vpe,St,Xpe=Et(()=>{Pt();Pt();Nl();qt();Zx=ve(\"crypto\");E_();$x=$e(D_()),ek=$e(sd()),Jpe=$e(Jn()),k_=ve(\"util\"),x_=$e(ve(\"v8\")),Q_=$e(ve(\"zlib\"));u_();P1();A_();f_();fE();uM();Wl();Wpe();O1();P_();Dd();S_();WS();jl();ih();Gl();vb();BU();Qf();bo();tk=Vy(process.env.YARN_LOCKFILE_VERSION_OVERRIDE??8),PAt=3,SAt=/ *, */g,zpe=/\\/$/,bAt=32,xAt=(0,k_.promisify)(Q_.default.gzip),kAt=(0,k_.promisify)(Q_.default.gunzip),hl=(r=>(r.UpdateLockfile=\"update-lockfile\",r.SkipBuild=\"skip-build\",r))(hl||{}),b_={restoreLinkersCustomData:[\"linkersCustomData\"],restoreResolutions:[\"accessibleLocators\",\"conditionalLocators\",\"disabledLocators\",\"optionalBuilds\",\"storedDescriptors\",\"storedResolutions\",\"storedPackages\",\"lockFileChecksum\"],restoreBuildState:[\"skippedBuilds\",\"storedBuildState\"]},rk=(o=>(o[o.NotProvided=0]=\"NotProvided\",o[o.NotCompatible=1]=\"NotCompatible\",o[o.NotCompatibleAggregate=2]=\"NotCompatibleAggregate\",o))(rk||{}),Vpe=t=>Js(`${PAt}`,t),St=class{constructor(e,{configuration:r}){this.resolutionAliases=new Map;this.workspaces=[];this.workspacesByCwd=new Map;this.workspacesByIdent=new Map;this.storedResolutions=new Map;this.storedDescriptors=new Map;this.storedPackages=new Map;this.storedChecksums=new Map;this.storedBuildState=new Map;this.accessibleLocators=new Set;this.conditionalLocators=new Set;this.disabledLocators=new Set;this.originalPackages=new Map;this.optionalBuilds=new Set;this.skippedBuilds=new Set;this.lockfileLastVersion=null;this.lockfileNeedsRefresh=!1;this.peerRequirements=new Map;this.peerWarnings=[];this.linkersCustomData=new Map;this.lockFileChecksum=null;this.installStateChecksum=null;this.configuration=r,this.cwd=e}static async find(e,r){if(!e.projectCwd)throw new it(`No project found in ${r}`);let o=e.projectCwd,a=r,n=null;for(;n!==e.projectCwd;){if(n=a,oe.existsSync(z.join(n,dr.manifest))){o=n;break}a=z.dirname(n)}let u=new St(e.projectCwd,{configuration:e});Ke.telemetry?.reportProject(u.cwd),await u.setupResolutions(),await u.setupWorkspaces(),Ke.telemetry?.reportWorkspaceCount(u.workspaces.length),Ke.telemetry?.reportDependencyCount(u.workspaces.reduce((C,R)=>C+R.manifest.dependencies.size+R.manifest.devDependencies.size,0));let A=u.tryWorkspaceByCwd(o);if(A)return{project:u,workspace:A,locator:A.anchoredLocator};let p=await u.findLocatorForLocation(`${o}/`,{strict:!0});if(p)return{project:u,locator:p,workspace:null};let h=Ut(e,u.cwd,yt.PATH),E=Ut(e,z.relative(u.cwd,o),yt.PATH),I=`- If ${h} isn't intended to be a project, remove any yarn.lock and/or package.json file there.`,v=`- If ${h} is intended to be a project, it might be that you forgot to list ${E} in its workspace configuration.`,x=`- Finally, if ${h} is fine and you intend ${E} to be treated as a completely separate project (not even a workspace), create an empty yarn.lock file in it.`;throw new it(`The nearest package directory (${Ut(e,o,yt.PATH)}) doesn't seem to be part of the project declared in ${Ut(e,u.cwd,yt.PATH)}.\n\n${[I,v,x].join(`\n`)}`)}async setupResolutions(){this.storedResolutions=new Map,this.storedDescriptors=new Map,this.storedPackages=new Map,this.lockFileChecksum=null;let e=z.join(this.cwd,dr.lockfile),r=this.configuration.get(\"defaultLanguageName\");if(oe.existsSync(e)){let o=await oe.readFilePromise(e,\"utf8\");this.lockFileChecksum=Vpe(o);let a=Ki(o);if(a.__metadata){let n=a.__metadata.version,u=a.__metadata.cacheKey;this.lockfileLastVersion=n,this.lockfileNeedsRefresh=n<tk;for(let A of Object.keys(a)){if(A===\"__metadata\")continue;let p=a[A];if(typeof p.resolution>\"u\")throw new Error(`Assertion failed: Expected the lockfile entry to have a resolution field (${A})`);let h=xf(p.resolution,!0),E=new Ot;E.load(p,{yamlCompatibilityMode:!0});let I=E.version,v=E.languageName||r,x=p.linkType.toUpperCase(),C=p.conditions??null,R=E.dependencies,N=E.peerDependencies,U=E.dependenciesMeta,V=E.peerDependenciesMeta,te=E.bin;if(p.checksum!=null){let fe=typeof u<\"u\"&&!p.checksum.includes(\"/\")?`${u}/${p.checksum}`:p.checksum;this.storedChecksums.set(h.locatorHash,fe)}let ae={...h,version:I,languageName:v,linkType:x,conditions:C,dependencies:R,peerDependencies:N,dependenciesMeta:U,peerDependenciesMeta:V,bin:te};this.originalPackages.set(ae.locatorHash,ae);for(let fe of A.split(SAt)){let ue=sh(fe);n<=6&&(ue=this.configuration.normalizeDependency(ue),ue=In(ue,ue.range.replace(/^patch:[^@]+@(?!npm(:|%3A))/,\"$1npm%3A\"))),this.storedDescriptors.set(ue.descriptorHash,ue),this.storedResolutions.set(ue.descriptorHash,h.locatorHash)}}}else o.includes(\"yarn lockfile v1\")&&(this.lockfileLastVersion=-1)}}async setupWorkspaces(){this.workspaces=[],this.workspacesByCwd=new Map,this.workspacesByIdent=new Map;let e=new Set,r=(0,ek.default)(4),o=async(a,n)=>{if(e.has(n))return a;e.add(n);let u=new cC(n,{project:this});await r(()=>u.setup());let A=a.then(()=>{this.addWorkspace(u)});return Array.from(u.workspacesCwds).reduce(o,A)};await o(Promise.resolve(),this.cwd)}addWorkspace(e){let r=this.workspacesByIdent.get(e.anchoredLocator.identHash);if(typeof r<\"u\")throw new Error(`Duplicate workspace name ${cs(this.configuration,e.anchoredLocator)}: ${le.fromPortablePath(e.cwd)} conflicts with ${le.fromPortablePath(r.cwd)}`);this.workspaces.push(e),this.workspacesByCwd.set(e.cwd,e),this.workspacesByIdent.set(e.anchoredLocator.identHash,e)}get topLevelWorkspace(){return this.getWorkspaceByCwd(this.cwd)}tryWorkspaceByCwd(e){z.isAbsolute(e)||(e=z.resolve(this.cwd,e)),e=z.normalize(e).replace(/\\/+$/,\"\");let r=this.workspacesByCwd.get(e);return r||null}getWorkspaceByCwd(e){let r=this.tryWorkspaceByCwd(e);if(!r)throw new Error(`Workspace not found (${e})`);return r}tryWorkspaceByFilePath(e){let r=null;for(let o of this.workspaces)z.relative(o.cwd,e).startsWith(\"../\")||r&&r.cwd.length>=o.cwd.length||(r=o);return r||null}getWorkspaceByFilePath(e){let r=this.tryWorkspaceByFilePath(e);if(!r)throw new Error(`Workspace not found (${e})`);return r}tryWorkspaceByIdent(e){let r=this.workspacesByIdent.get(e.identHash);return typeof r>\"u\"?null:r}getWorkspaceByIdent(e){let r=this.tryWorkspaceByIdent(e);if(!r)throw new Error(`Workspace not found (${cs(this.configuration,e)})`);return r}tryWorkspaceByDescriptor(e){if(e.range.startsWith(Xn.protocol)){let o=e.range.slice(Xn.protocol.length);if(o!==\"^\"&&o!==\"~\"&&o!==\"*\"&&!xa(o))return this.tryWorkspaceByCwd(o)}let r=this.tryWorkspaceByIdent(e);return r===null||(bf(e)&&(e=t1(e)),!r.accepts(e.range))?null:r}getWorkspaceByDescriptor(e){let r=this.tryWorkspaceByDescriptor(e);if(r===null)throw new Error(`Workspace not found (${Gn(this.configuration,e)})`);return r}tryWorkspaceByLocator(e){let r=this.tryWorkspaceByIdent(e);return r===null||(qc(e)&&(e=r1(e)),r.anchoredLocator.locatorHash!==e.locatorHash)?null:r}getWorkspaceByLocator(e){let r=this.tryWorkspaceByLocator(e);if(!r)throw new Error(`Workspace not found (${qr(this.configuration,e)})`);return r}deleteDescriptor(e){this.storedResolutions.delete(e),this.storedDescriptors.delete(e)}deleteLocator(e){this.originalPackages.delete(e),this.storedPackages.delete(e),this.accessibleLocators.delete(e)}forgetResolution(e){if(\"descriptorHash\"in e){let r=this.storedResolutions.get(e.descriptorHash);this.deleteDescriptor(e.descriptorHash);let o=new Set(this.storedResolutions.values());typeof r<\"u\"&&!o.has(r)&&this.deleteLocator(r)}if(\"locatorHash\"in e){this.deleteLocator(e.locatorHash);for(let[r,o]of this.storedResolutions)o===e.locatorHash&&this.deleteDescriptor(r)}}forgetTransientResolutions(){let e=this.configuration.makeResolver(),r=new Map;for(let[o,a]of this.storedResolutions.entries()){let n=r.get(a);n||r.set(a,n=new Set),n.add(o)}for(let o of this.originalPackages.values()){let a;try{a=e.shouldPersistResolution(o,{project:this,resolver:e})}catch{a=!1}if(!a){this.deleteLocator(o.locatorHash);let n=r.get(o.locatorHash);if(n){r.delete(o.locatorHash);for(let u of n)this.deleteDescriptor(u)}}}}forgetVirtualResolutions(){for(let e of this.storedPackages.values())for(let[r,o]of e.dependencies)bf(o)&&e.dependencies.set(r,t1(o))}getDependencyMeta(e,r){let o={},n=this.topLevelWorkspace.manifest.dependenciesMeta.get(fn(e));if(!n)return o;let u=n.get(null);if(u&&Object.assign(o,u),r===null||!Jpe.default.valid(r))return o;for(let[A,p]of n)A!==null&&A===r&&Object.assign(o,p);return o}async findLocatorForLocation(e,{strict:r=!1}={}){let o=new Qi,a=this.configuration.getLinkers(),n={project:this,report:o};for(let u of a){let A=await u.findPackageLocator(e,n);if(A){if(r&&(await u.findPackageLocation(A,n)).replace(zpe,\"\")!==e.replace(zpe,\"\"))continue;return A}}return null}async loadUserConfig(){let e=z.join(this.cwd,\".pnp.cjs\");await oe.existsPromise(e)&&Df(e).setup();let r=z.join(this.cwd,\"yarn.config.cjs\");return await oe.existsPromise(r)?Df(r):null}async preparePackage(e,{resolver:r,resolveOptions:o}){let a=await this.configuration.getPackageExtensions(),n=this.configuration.normalizePackage(e,{packageExtensions:a});for(let[u,A]of n.dependencies){let p=await this.configuration.reduceHook(E=>E.reduceDependency,A,this,n,A,{resolver:r,resolveOptions:o});if(!n1(A,p))throw new Error(\"Assertion failed: The descriptor ident cannot be changed through aliases\");let h=r.bindDescriptor(p,n,o);n.dependencies.set(u,h)}return n}async resolveEverything(e){if(!this.workspacesByCwd||!this.workspacesByIdent)throw new Error(\"Workspaces must have been setup before calling this function\");this.forgetVirtualResolutions();let r=new Map(this.originalPackages),o=[];e.lockfileOnly||this.forgetTransientResolutions();let a=e.resolver||this.configuration.makeResolver(),n=new oC(a);await n.setup(this,{report:e.report});let u=e.lockfileOnly?[new Xx(a)]:[n,a],A=new Pd([new aC(a),...u]),p=new Pd([...u]),h=this.configuration.makeFetcher(),E=e.lockfileOnly?{project:this,report:e.report,resolver:A}:{project:this,report:e.report,resolver:A,fetchOptions:{project:this,cache:e.cache,checksums:this.storedChecksums,report:e.report,fetcher:h,cacheOptions:{mirrorWriteOnly:!0}}},I=new Map,v=new Map,x=new Map,C=new Map,R=new Map,N=new Map,U=this.topLevelWorkspace.anchoredLocator,V=new Set,te=[],ae=M4(),fe=this.configuration.getSupportedArchitectures();await e.report.startProgressPromise(Xs.progressViaTitle(),async ce=>{let ne=async H=>{let at=await Ky(async()=>await A.resolve(H,E),He=>`${qr(this.configuration,H)}: ${He}`);if(!i1(H,at))throw new Error(`Assertion failed: The locator cannot be changed by the resolver (went from ${qr(this.configuration,H)} to ${qr(this.configuration,at)})`);C.set(at.locatorHash,at),!r.delete(at.locatorHash)&&!this.tryWorkspaceByLocator(at)&&o.push(at);let ke=await this.preparePackage(at,{resolver:A,resolveOptions:E}),xe=_c([...ke.dependencies.values()].map(He=>At(He)));return te.push(xe),xe.catch(()=>{}),v.set(ke.locatorHash,ke),ke},ee=async H=>{let at=R.get(H.locatorHash);if(typeof at<\"u\")return at;let Re=Promise.resolve().then(()=>ne(H));return R.set(H.locatorHash,Re),Re},Ie=async(H,at)=>{let Re=await At(at);return I.set(H.descriptorHash,H),x.set(H.descriptorHash,Re.locatorHash),Re},Fe=async H=>{ce.setTitle(Gn(this.configuration,H));let at=this.resolutionAliases.get(H.descriptorHash);if(typeof at<\"u\")return Ie(H,this.storedDescriptors.get(at));let Re=A.getResolutionDependencies(H,E),ke=Object.fromEntries(await _c(Object.entries(Re).map(async([Te,Ve])=>{let qe=A.bindDescriptor(Ve,U,E),b=await At(qe);return V.add(b.locatorHash),[Te,b]}))),He=(await Ky(async()=>await A.getCandidates(H,ke,E),Te=>`${Gn(this.configuration,H)}: ${Te}`))[0];if(typeof He>\"u\")throw new Jt(82,`${Gn(this.configuration,H)}: No candidates found`);if(e.checkResolutions){let{locators:Te}=await p.getSatisfying(H,ke,[He],{...E,resolver:p});if(!Te.find(Ve=>Ve.locatorHash===He.locatorHash))throw new Jt(78,`Invalid resolution ${ZI(this.configuration,H,He)}`)}return I.set(H.descriptorHash,H),x.set(H.descriptorHash,He.locatorHash),ee(He)},At=H=>{let at=N.get(H.descriptorHash);if(typeof at<\"u\")return at;I.set(H.descriptorHash,H);let Re=Promise.resolve().then(()=>Fe(H));return N.set(H.descriptorHash,Re),Re};for(let H of this.workspaces){let at=H.anchoredDescriptor;te.push(At(at))}for(;te.length>0;){let H=[...te];te.length=0,await _c(H)}});let ue=ol(r.values(),ce=>this.tryWorkspaceByLocator(ce)?ol.skip:ce);if(o.length>0||ue.length>0){let ce=new Set(this.workspaces.flatMap(H=>{let at=v.get(H.anchoredLocator.locatorHash);if(!at)throw new Error(\"Assertion failed: The workspace should have been resolved\");return Array.from(at.dependencies.values(),Re=>{let ke=x.get(Re.descriptorHash);if(!ke)throw new Error(\"Assertion failed: The resolution should have been registered\");return ke})})),ne=H=>ce.has(H.locatorHash)?\"0\":\"1\",ee=H=>ba(H),Ie=ks(o,[ne,ee]),Fe=ks(ue,[ne,ee]),At=e.report.getRecommendedLength();Ie.length>0&&e.report.reportInfo(85,`${Ut(this.configuration,\"+\",yt.ADDED)} ${lS(this.configuration,Ie,At)}`),Fe.length>0&&e.report.reportInfo(85,`${Ut(this.configuration,\"-\",yt.REMOVED)} ${lS(this.configuration,Fe,At)}`)}let me=new Set(this.resolutionAliases.values()),he=new Set(v.keys()),Be=new Set,we=new Map,g=[];QAt({project:this,accessibleLocators:Be,volatileDescriptors:me,optionalBuilds:he,peerRequirements:we,peerWarnings:g,allDescriptors:I,allResolutions:x,allPackages:v});for(let ce of V)he.delete(ce);for(let ce of me)I.delete(ce),x.delete(ce);let Ee=new Set,Pe=new Set;for(let ce of v.values())ce.conditions!=null&&(!he.has(ce.locatorHash)||(qS(ce,fe)||(qS(ce,ae)&&e.report.reportWarningOnce(77,`${qr(this.configuration,ce)}: Your current architecture (${process.platform}-${process.arch}) is supported by this package, but is missing from the ${Ut(this.configuration,\"supportedArchitectures\",yt.SETTING)} setting`),Pe.add(ce.locatorHash)),Ee.add(ce.locatorHash)));this.storedResolutions=x,this.storedDescriptors=I,this.storedPackages=v,this.accessibleLocators=Be,this.conditionalLocators=Ee,this.disabledLocators=Pe,this.originalPackages=C,this.optionalBuilds=he,this.peerRequirements=we,this.peerWarnings=g}async fetchEverything({cache:e,report:r,fetcher:o,mode:a,persistProject:n=!0}){let u={mockedPackages:this.disabledLocators,unstablePackages:this.conditionalLocators},A=o||this.configuration.makeFetcher(),p={checksums:this.storedChecksums,project:this,cache:e,fetcher:A,report:r,cacheOptions:u},h=Array.from(new Set(ks(this.storedResolutions.values(),[C=>{let R=this.storedPackages.get(C);if(!R)throw new Error(\"Assertion failed: The locator should have been registered\");return ba(R)}])));a===\"update-lockfile\"&&(h=h.filter(C=>!this.storedChecksums.has(C)));let E=!1,I=Xs.progressViaCounter(h.length);await r.reportProgress(I);let v=(0,ek.default)(bAt);if(await _c(h.map(C=>v(async()=>{let R=this.storedPackages.get(C);if(!R)throw new Error(\"Assertion failed: The locator should have been registered\");if(qc(R))return;let N;try{N=await A.fetch(R,p)}catch(U){U.message=`${qr(this.configuration,R)}: ${U.message}`,r.reportExceptionOnce(U),E=U;return}N.checksum!=null?this.storedChecksums.set(R.locatorHash,N.checksum):this.storedChecksums.delete(R.locatorHash),N.releaseFs&&N.releaseFs()}).finally(()=>{I.tick()}))),E)throw E;let x=n&&a!==\"update-lockfile\"?await this.cacheCleanup({cache:e,report:r}):null;if(r.cacheMisses.size>0||x){let R=(await Promise.all([...r.cacheMisses].map(async ue=>{let me=this.storedPackages.get(ue),he=this.storedChecksums.get(ue)??null,Be=e.getLocatorPath(me,he);return(await oe.statPromise(Be)).size}))).reduce((ue,me)=>ue+me,0)-(x?.size??0),N=r.cacheMisses.size,U=x?.count??0,V=`${rS(N,{zero:\"No new packages\",one:\"A package was\",more:`${Ut(this.configuration,N,yt.NUMBER)} packages were`})} added to the project`,te=`${rS(U,{zero:\"none were\",one:\"one was\",more:`${Ut(this.configuration,U,yt.NUMBER)} were`})} removed`,ae=R!==0?` (${Ut(this.configuration,R,yt.SIZE_DIFF)})`:\"\",fe=U>0?N>0?`${V}, and ${te}${ae}.`:`${V}, but ${te}${ae}.`:`${V}${ae}.`;r.reportInfo(13,fe)}}async linkEverything({cache:e,report:r,fetcher:o,mode:a}){let n={mockedPackages:this.disabledLocators,unstablePackages:this.conditionalLocators,skipIntegrityCheck:!0},u=o||this.configuration.makeFetcher(),A={checksums:this.storedChecksums,project:this,cache:e,fetcher:u,report:r,cacheOptions:n},p=this.configuration.getLinkers(),h={project:this,report:r},E=new Map(p.map(ce=>{let ne=ce.makeInstaller(h),ee=ce.getCustomDataKey(),Ie=this.linkersCustomData.get(ee);return typeof Ie<\"u\"&&ne.attachCustomData(Ie),[ce,ne]})),I=new Map,v=new Map,x=new Map,C=new Map(await _c([...this.accessibleLocators].map(async ce=>{let ne=this.storedPackages.get(ce);if(!ne)throw new Error(\"Assertion failed: The locator should have been registered\");return[ce,await u.fetch(ne,A)]}))),R=[],N=new Set,U=[];for(let ce of this.accessibleLocators){let ne=this.storedPackages.get(ce);if(typeof ne>\"u\")throw new Error(\"Assertion failed: The locator should have been registered\");let ee=C.get(ne.locatorHash);if(typeof ee>\"u\")throw new Error(\"Assertion failed: The fetch result should have been registered\");let Ie=[],Fe=H=>{Ie.push(H)},At=this.tryWorkspaceByLocator(ne);if(At!==null){let H=[],{scripts:at}=At.manifest;for(let ke of[\"preinstall\",\"install\",\"postinstall\"])at.has(ke)&&H.push({type:0,script:ke});try{for(let[ke,xe]of E)if(ke.supportsPackage(ne,h)&&(await xe.installPackage(ne,ee,{holdFetchResult:Fe})).buildRequest!==null)throw new Error(\"Assertion failed: Linkers can't return build directives for workspaces; this responsibility befalls to the Yarn core\")}finally{Ie.length===0?ee.releaseFs?.():R.push(_c(Ie).catch(()=>{}).then(()=>{ee.releaseFs?.()}))}let Re=z.join(ee.packageFs.getRealPath(),ee.prefixPath);v.set(ne.locatorHash,Re),!qc(ne)&&H.length>0&&x.set(ne.locatorHash,{buildDirectives:H,buildLocations:[Re]})}else{let H=p.find(ke=>ke.supportsPackage(ne,h));if(!H)throw new Jt(12,`${qr(this.configuration,ne)} isn't supported by any available linker`);let at=E.get(H);if(!at)throw new Error(\"Assertion failed: The installer should have been registered\");let Re;try{Re=await at.installPackage(ne,ee,{holdFetchResult:Fe})}finally{Ie.length===0?ee.releaseFs?.():R.push(_c(Ie).then(()=>{}).then(()=>{ee.releaseFs?.()}))}I.set(ne.locatorHash,H),v.set(ne.locatorHash,Re.packageLocation),Re.buildRequest&&Re.packageLocation&&(Re.buildRequest.skipped?(N.add(ne.locatorHash),this.skippedBuilds.has(ne.locatorHash)||U.push([ne,Re.buildRequest.explain])):x.set(ne.locatorHash,{buildDirectives:Re.buildRequest.directives,buildLocations:[Re.packageLocation]}))}}let V=new Map;for(let ce of this.accessibleLocators){let ne=this.storedPackages.get(ce);if(!ne)throw new Error(\"Assertion failed: The locator should have been registered\");let ee=this.tryWorkspaceByLocator(ne)!==null,Ie=async(Fe,At)=>{let H=v.get(ne.locatorHash);if(typeof H>\"u\")throw new Error(`Assertion failed: The package (${qr(this.configuration,ne)}) should have been registered`);let at=[];for(let Re of ne.dependencies.values()){let ke=this.storedResolutions.get(Re.descriptorHash);if(typeof ke>\"u\")throw new Error(`Assertion failed: The resolution (${Gn(this.configuration,Re)}, from ${qr(this.configuration,ne)})should have been registered`);let xe=this.storedPackages.get(ke);if(typeof xe>\"u\")throw new Error(`Assertion failed: The package (${ke}, resolved from ${Gn(this.configuration,Re)}) should have been registered`);let He=this.tryWorkspaceByLocator(xe)===null?I.get(ke):null;if(typeof He>\"u\")throw new Error(`Assertion failed: The package (${ke}, resolved from ${Gn(this.configuration,Re)}) should have been registered`);He===Fe||He===null?v.get(xe.locatorHash)!==null&&at.push([Re,xe]):!ee&&H!==null&&Yy(V,ke).push(H)}H!==null&&await At.attachInternalDependencies(ne,at)};if(ee)for(let[Fe,At]of E)Fe.supportsPackage(ne,h)&&await Ie(Fe,At);else{let Fe=I.get(ne.locatorHash);if(!Fe)throw new Error(\"Assertion failed: The linker should have been found\");let At=E.get(Fe);if(!At)throw new Error(\"Assertion failed: The installer should have been registered\");await Ie(Fe,At)}}for(let[ce,ne]of V){let ee=this.storedPackages.get(ce);if(!ee)throw new Error(\"Assertion failed: The package should have been registered\");let Ie=I.get(ee.locatorHash);if(!Ie)throw new Error(\"Assertion failed: The linker should have been found\");let Fe=E.get(Ie);if(!Fe)throw new Error(\"Assertion failed: The installer should have been registered\");await Fe.attachExternalDependents(ee,ne)}let te=new Map;for(let[ce,ne]of E){let ee=await ne.finalizeInstall();for(let Ie of ee?.records??[])Ie.buildRequest.skipped?(N.add(Ie.locator.locatorHash),this.skippedBuilds.has(Ie.locator.locatorHash)||U.push([Ie.locator,Ie.buildRequest.explain])):x.set(Ie.locator.locatorHash,{buildDirectives:Ie.buildRequest.directives,buildLocations:Ie.buildLocations});typeof ee?.customData<\"u\"&&te.set(ce.getCustomDataKey(),ee.customData)}if(this.linkersCustomData=te,await _c(R),a===\"skip-build\")return;for(let[,ce]of ks(U,([ne])=>ba(ne)))ce(r);let ae=new Set(this.storedPackages.keys()),fe=new Set(x.keys());for(let ce of fe)ae.delete(ce);let ue=(0,Zx.createHash)(\"sha512\");ue.update(process.versions.node),await this.configuration.triggerHook(ce=>ce.globalHashGeneration,this,ce=>{ue.update(\"\\0\"),ue.update(ce)});let me=ue.digest(\"hex\"),he=new Map,Be=ce=>{let ne=he.get(ce.locatorHash);if(typeof ne<\"u\")return ne;let ee=this.storedPackages.get(ce.locatorHash);if(typeof ee>\"u\")throw new Error(\"Assertion failed: The package should have been registered\");let Ie=(0,Zx.createHash)(\"sha512\");Ie.update(ce.locatorHash),he.set(ce.locatorHash,\"<recursive>\");for(let Fe of ee.dependencies.values()){let At=this.storedResolutions.get(Fe.descriptorHash);if(typeof At>\"u\")throw new Error(`Assertion failed: The resolution (${Gn(this.configuration,Fe)}) should have been registered`);let H=this.storedPackages.get(At);if(typeof H>\"u\")throw new Error(\"Assertion failed: The package should have been registered\");Ie.update(Be(H))}return ne=Ie.digest(\"hex\"),he.set(ce.locatorHash,ne),ne},we=(ce,ne)=>{let ee=(0,Zx.createHash)(\"sha512\");ee.update(me),ee.update(Be(ce));for(let Ie of ne)ee.update(Ie);return ee.digest(\"hex\")},g=new Map,Ee=!1,Pe=ce=>{let ne=new Set([ce.locatorHash]);for(let ee of ne){let Ie=this.storedPackages.get(ee);if(!Ie)throw new Error(\"Assertion failed: The package should have been registered\");for(let Fe of Ie.dependencies.values()){let At=this.storedResolutions.get(Fe.descriptorHash);if(!At)throw new Error(`Assertion failed: The resolution (${Gn(this.configuration,Fe)}) should have been registered`);if(At!==ce.locatorHash&&fe.has(At))return!1;let H=this.storedPackages.get(At);if(!H)throw new Error(\"Assertion failed: The package should have been registered\");let at=this.tryWorkspaceByLocator(H);if(at){if(at.anchoredLocator.locatorHash!==ce.locatorHash&&fe.has(at.anchoredLocator.locatorHash))return!1;ne.add(at.anchoredLocator.locatorHash)}ne.add(At)}}return!0};for(;fe.size>0;){let ce=fe.size,ne=[];for(let ee of fe){let Ie=this.storedPackages.get(ee);if(!Ie)throw new Error(\"Assertion failed: The package should have been registered\");if(!Pe(Ie))continue;let Fe=x.get(Ie.locatorHash);if(!Fe)throw new Error(\"Assertion failed: The build directive should have been registered\");let At=we(Ie,Fe.buildLocations);if(this.storedBuildState.get(Ie.locatorHash)===At){g.set(Ie.locatorHash,At),fe.delete(ee);continue}Ee||(await this.persistInstallStateFile(),Ee=!0),this.storedBuildState.has(Ie.locatorHash)?r.reportInfo(8,`${qr(this.configuration,Ie)} must be rebuilt because its dependency tree changed`):r.reportInfo(7,`${qr(this.configuration,Ie)} must be built because it never has been before or the last one failed`);let H=Fe.buildLocations.map(async at=>{if(!z.isAbsolute(at))throw new Error(`Assertion failed: Expected the build location to be absolute (not ${at})`);for(let Re of Fe.buildDirectives){let ke=`# This file contains the result of Yarn building a package (${ba(Ie)})\n`;switch(Re.type){case 0:ke+=`# Script name: ${Re.script}\n`;break;case 1:ke+=`# Script code: ${Re.script}\n`;break}let xe=null;if(!await oe.mktempPromise(async Te=>{let Ve=z.join(Te,\"build.log\"),{stdout:qe,stderr:b}=this.configuration.getSubprocessStreams(Ve,{header:ke,prefix:qr(this.configuration,Ie),report:r}),w;try{switch(Re.type){case 0:w=await Wb(Ie,Re.script,[],{cwd:at,project:this,stdin:xe,stdout:qe,stderr:b});break;case 1:w=await EU(Ie,Re.script,[],{cwd:at,project:this,stdin:xe,stdout:qe,stderr:b});break}}catch(F){b.write(F.stack),w=1}if(qe.end(),b.end(),w===0)return!0;oe.detachTemp(Te);let S=`${qr(this.configuration,Ie)} couldn't be built successfully (exit code ${Ut(this.configuration,w,yt.NUMBER)}, logs can be found here: ${Ut(this.configuration,Ve,yt.PATH)})`,y=this.optionalBuilds.has(Ie.locatorHash);return y?r.reportInfo(9,S):r.reportError(9,S),zce&&r.reportFold(le.fromPortablePath(Ve),oe.readFileSync(Ve,\"utf8\")),y}))return!1}return!0});ne.push(...H,Promise.allSettled(H).then(at=>{fe.delete(ee),at.every(Re=>Re.status===\"fulfilled\"&&Re.value===!0)&&g.set(Ie.locatorHash,At)}))}if(await _c(ne),ce===fe.size){let ee=Array.from(fe).map(Ie=>{let Fe=this.storedPackages.get(Ie);if(!Fe)throw new Error(\"Assertion failed: The package should have been registered\");return qr(this.configuration,Fe)}).join(\", \");r.reportError(3,`Some packages have circular dependencies that make their build order unsatisfiable - as a result they won't be built (affected packages are: ${ee})`);break}}this.storedBuildState=g,this.skippedBuilds=N}async installWithNewReport(e,r){return(await Lt.start({configuration:this.configuration,json:e.json,stdout:e.stdout,forceSectionAlignment:!0,includeLogs:!e.json&&!e.quiet,includeVersion:!0},async a=>{await this.install({...r,report:a})})).exitCode()}async install(e){let r=this.configuration.get(\"nodeLinker\");Ke.telemetry?.reportInstall(r);let o=!1;if(await e.report.startTimerPromise(\"Project validation\",{skipIfEmpty:!0},async()=>{this.configuration.get(\"enableOfflineMode\")&&e.report.reportWarning(90,\"Offline work is enabled; Yarn won't fetch packages from the remote registry if it can avoid it\"),await this.configuration.triggerHook(E=>E.validateProject,this,{reportWarning:(E,I)=>{e.report.reportWarning(E,I)},reportError:(E,I)=>{e.report.reportError(E,I),o=!0}})}),o)return;let a=await this.configuration.getPackageExtensions();for(let E of a.values())for(let[,I]of E)for(let v of I)v.status=\"inactive\";let n=z.join(this.cwd,dr.lockfile),u=null;if(e.immutable)try{u=await oe.readFilePromise(n,\"utf8\")}catch(E){throw E.code===\"ENOENT\"?new Jt(28,\"The lockfile would have been created by this install, which is explicitly forbidden.\"):E}await e.report.startTimerPromise(\"Resolution step\",async()=>{await this.resolveEverything(e)}),await e.report.startTimerPromise(\"Post-resolution validation\",{skipIfEmpty:!0},async()=>{FAt(this,e.report);for(let[,E]of a)for(let[,I]of E)for(let v of I)if(v.userProvided){let x=Ut(this.configuration,v,yt.PACKAGE_EXTENSION);switch(v.status){case\"inactive\":e.report.reportWarning(68,`${x}: No matching package in the dependency tree; you may not need this rule anymore.`);break;case\"redundant\":e.report.reportWarning(69,`${x}: This rule seems redundant when applied on the original package; the extension may have been applied upstream.`);break}}if(u!==null){let E=Hg(u,this.generateLockfile());if(E!==u){let I=fpe(n,n,u,E,void 0,void 0,{maxEditLength:100});if(I){e.report.reportSeparator();for(let v of I.hunks){e.report.reportInfo(null,`@@ -${v.oldStart},${v.oldLines} +${v.newStart},${v.newLines} @@`);for(let x of v.lines)x.startsWith(\"+\")?e.report.reportError(28,Ut(this.configuration,x,yt.ADDED)):x.startsWith(\"-\")?e.report.reportError(28,Ut(this.configuration,x,yt.REMOVED)):e.report.reportInfo(null,Ut(this.configuration,x,\"grey\"))}e.report.reportSeparator()}throw new Jt(28,\"The lockfile would have been modified by this install, which is explicitly forbidden.\")}}});for(let E of a.values())for(let[,I]of E)for(let v of I)v.userProvided&&v.status===\"active\"&&Ke.telemetry?.reportPackageExtension(Cd(v,yt.PACKAGE_EXTENSION));await e.report.startTimerPromise(\"Fetch step\",async()=>{await this.fetchEverything(e)});let A=e.immutable?[...new Set(this.configuration.get(\"immutablePatterns\"))].sort():[],p=await Promise.all(A.map(async E=>NS(E,{cwd:this.cwd})));(typeof e.persistProject>\"u\"||e.persistProject)&&await this.persist(),await e.report.startTimerPromise(\"Link step\",async()=>{if(e.mode===\"update-lockfile\"){e.report.reportWarning(73,`Skipped due to ${Ut(this.configuration,\"mode=update-lockfile\",yt.CODE)}`);return}await this.linkEverything(e);let E=await Promise.all(A.map(async I=>NS(I,{cwd:this.cwd})));for(let I=0;I<A.length;++I)p[I]!==E[I]&&e.report.reportError(64,`The checksum for ${A[I]} has been modified by this install, which is explicitly forbidden.`)}),await this.persistInstallStateFile();let h=!1;await e.report.startTimerPromise(\"Post-install validation\",{skipIfEmpty:!0},async()=>{await this.configuration.triggerHook(E=>E.validateProjectAfterInstall,this,{reportWarning:(E,I)=>{e.report.reportWarning(E,I)},reportError:(E,I)=>{e.report.reportError(E,I),h=!0}})}),!h&&await this.configuration.triggerHook(E=>E.afterAllInstalled,this,e)}generateLockfile(){let e=new Map;for(let[n,u]of this.storedResolutions.entries()){let A=e.get(u);A||e.set(u,A=new Set),A.add(n)}let r={},{cacheKey:o}=Nr.getCacheKey(this.configuration);r.__metadata={version:tk,cacheKey:o};for(let[n,u]of e.entries()){let A=this.originalPackages.get(n);if(!A)continue;let p=[];for(let I of u){let v=this.storedDescriptors.get(I);if(!v)throw new Error(\"Assertion failed: The descriptor should have been registered\");p.push(v)}let h=p.map(I=>Sa(I)).sort().join(\", \"),E=new Ot;E.version=A.linkType===\"HARD\"?A.version:\"0.0.0-use.local\",E.languageName=A.languageName,E.dependencies=new Map(A.dependencies),E.peerDependencies=new Map(A.peerDependencies),E.dependenciesMeta=new Map(A.dependenciesMeta),E.peerDependenciesMeta=new Map(A.peerDependenciesMeta),E.bin=new Map(A.bin),r[h]={...E.exportTo({},{compatibilityMode:!1}),linkType:A.linkType.toLowerCase(),resolution:ba(A),checksum:this.storedChecksums.get(A.locatorHash),conditions:A.conditions||void 0}}return`${[`# This file is generated by running \"yarn install\" inside your project.\n`,`# Manual changes might be lost - proceed with caution!\n`].join(\"\")}\n`+Ba(r)}async persistLockfile(){let e=z.join(this.cwd,dr.lockfile),r=\"\";try{r=await oe.readFilePromise(e,\"utf8\")}catch{}let o=this.generateLockfile(),a=Hg(r,o);a!==r&&(await oe.writeFilePromise(e,a),this.lockFileChecksum=Vpe(a),this.lockfileNeedsRefresh=!1)}async persistInstallStateFile(){let e=[];for(let u of Object.values(b_))e.push(...u);let r=(0,$x.default)(this,e),o=x_.default.serialize(r),a=Js(o);if(this.installStateChecksum===a)return;let n=this.configuration.get(\"installStatePath\");await oe.mkdirPromise(z.dirname(n),{recursive:!0}),await oe.writeFilePromise(n,await xAt(o)),this.installStateChecksum=a}async restoreInstallState({restoreLinkersCustomData:e=!0,restoreResolutions:r=!0,restoreBuildState:o=!0}={}){let a=this.configuration.get(\"installStatePath\"),n;try{let u=await kAt(await oe.readFilePromise(a));n=x_.default.deserialize(u),this.installStateChecksum=Js(u)}catch{r&&await this.applyLightResolution();return}e&&typeof n.linkersCustomData<\"u\"&&(this.linkersCustomData=n.linkersCustomData),o&&Object.assign(this,(0,$x.default)(n,b_.restoreBuildState)),r&&(n.lockFileChecksum===this.lockFileChecksum?Object.assign(this,(0,$x.default)(n,b_.restoreResolutions)):await this.applyLightResolution())}async applyLightResolution(){await this.resolveEverything({lockfileOnly:!0,report:new Qi}),await this.persistInstallStateFile()}async persist(){let e=(0,ek.default)(4);await Promise.all([this.persistLockfile(),...this.workspaces.map(r=>e(()=>r.persistManifest()))])}async cacheCleanup({cache:e,report:r}){if(this.configuration.get(\"enableGlobalCache\"))return null;let o=new Set([\".gitignore\"]);if(!CM(e.cwd,this.cwd)||!await oe.existsPromise(e.cwd))return null;let a=[];for(let u of await oe.readdirPromise(e.cwd)){if(o.has(u))continue;let A=z.resolve(e.cwd,u);e.markedFiles.has(A)||(e.immutable?r.reportError(56,`${Ut(this.configuration,z.basename(A),\"magenta\")} appears to be unused and would be marked for deletion, but the cache is immutable`):a.push(oe.lstatPromise(A).then(async p=>(await oe.removePromise(A),p.size))))}if(a.length===0)return null;let n=await Promise.all(a);return{count:a.length,size:n.reduce((u,A)=>u+A,0)}}}});function RAt(t){let o=Math.floor(t.timeNow/864e5),a=t.updateInterval*864e5,n=t.state.lastUpdate??t.timeNow+a+Math.floor(a*t.randomInitialInterval),u=n+a,A=t.state.lastTips??o*864e5,p=A+864e5+8*36e5-t.timeZone,h=u<=t.timeNow,E=p<=t.timeNow,I=null;return(h||E||!t.state.lastUpdate||!t.state.lastTips)&&(I={},I.lastUpdate=h?t.timeNow:n,I.lastTips=A,I.blocks=h?{}:t.state.blocks,I.displayedTips=t.state.displayedTips),{nextState:I,triggerUpdate:h,triggerTips:E,nextTips:E?o*864e5:A}}var uC,Zpe=Et(()=>{Pt();N1();ih();Ib();Gl();Qf();uC=class{constructor(e,r){this.values=new Map;this.hits=new Map;this.enumerators=new Map;this.nextTips=0;this.displayedTips=[];this.shouldCommitTips=!1;this.configuration=e;let o=this.getRegistryPath();this.isNew=!oe.existsSync(o),this.shouldShowTips=!1,this.sendReport(r),this.startBuffer()}commitTips(){this.shouldShowTips&&(this.shouldCommitTips=!0)}selectTip(e){let r=new Set(this.displayedTips),o=A=>A&&rn?kf(rn,A):!1,a=e.map((A,p)=>p).filter(A=>e[A]&&o(e[A]?.selector));if(a.length===0)return null;let n=a.filter(A=>!r.has(A));if(n.length===0){let A=Math.floor(a.length*.2);this.displayedTips=A>0?this.displayedTips.slice(-A):[],n=a.filter(p=>!r.has(p))}let u=n[Math.floor(Math.random()*n.length)];return this.displayedTips.push(u),this.commitTips(),e[u]}reportVersion(e){this.reportValue(\"version\",e.replace(/-git\\..*/,\"-git\"))}reportCommandName(e){this.reportValue(\"commandName\",e||\"<none>\")}reportPluginName(e){this.reportValue(\"pluginName\",e)}reportProject(e){this.reportEnumerator(\"projectCount\",e)}reportInstall(e){this.reportHit(\"installCount\",e)}reportPackageExtension(e){this.reportValue(\"packageExtension\",e)}reportWorkspaceCount(e){this.reportValue(\"workspaceCount\",String(e))}reportDependencyCount(e){this.reportValue(\"dependencyCount\",String(e))}reportValue(e,r){yd(this.values,e).add(r)}reportEnumerator(e,r){yd(this.enumerators,e).add(Js(r))}reportHit(e,r=\"*\"){let o=Wy(this.hits,e),a=al(o,r,()=>0);o.set(r,a+1)}getRegistryPath(){let e=this.configuration.get(\"globalFolder\");return z.join(e,\"telemetry.json\")}sendReport(e){let r=this.getRegistryPath(),o;try{o=oe.readJsonSync(r)}catch{o={}}let{nextState:a,triggerUpdate:n,triggerTips:u,nextTips:A}=RAt({state:o,timeNow:Date.now(),timeZone:new Date().getTimezoneOffset()*60*1e3,randomInitialInterval:Math.random(),updateInterval:this.configuration.get(\"telemetryInterval\")});if(this.nextTips=A,this.displayedTips=o.displayedTips??[],a!==null)try{oe.mkdirSync(z.dirname(r),{recursive:!0}),oe.writeJsonSync(r,a)}catch{return!1}if(u&&this.configuration.get(\"enableTips\")&&(this.shouldShowTips=!0),n){let p=o.blocks??{};if(Object.keys(p).length===0){let h=`https://browser-http-intake.logs.datadoghq.eu/v1/input/${e}?ddsource=yarn`,E=I=>O4(h,I,{configuration:this.configuration}).catch(()=>{});for(let[I,v]of Object.entries(o.blocks??{})){if(Object.keys(v).length===0)continue;let x=v;x.userId=I,x.reportType=\"primary\";for(let N of Object.keys(x.enumerators??{}))x.enumerators[N]=x.enumerators[N].length;E(x);let C=new Map,R=20;for(let[N,U]of Object.entries(x.values))U.length>0&&C.set(N,U.slice(0,R));for(;C.size>0;){let N={};N.userId=I,N.reportType=\"secondary\",N.metrics={};for(let[U,V]of C)N.metrics[U]=V.shift(),V.length===0&&C.delete(U);E(N)}}}}return!0}applyChanges(){let e=this.getRegistryPath(),r;try{r=oe.readJsonSync(e)}catch{r={}}let o=this.configuration.get(\"telemetryUserId\")??\"*\",a=r.blocks=r.blocks??{},n=a[o]=a[o]??{};for(let u of this.hits.keys()){let A=n.hits=n.hits??{},p=A[u]=A[u]??{};for(let[h,E]of this.hits.get(u))p[h]=(p[h]??0)+E}for(let u of[\"values\",\"enumerators\"])for(let A of this[u].keys()){let p=n[u]=n[u]??{};p[A]=[...new Set([...p[A]??[],...this[u].get(A)??[]])]}this.shouldCommitTips&&(r.lastTips=this.nextTips,r.displayedTips=this.displayedTips),oe.mkdirSync(z.dirname(e),{recursive:!0}),oe.writeJsonSync(e,r)}startBuffer(){process.on(\"exit\",()=>{try{this.applyChanges()}catch{}})}}});var o2={};zt(o2,{BuildDirectiveType:()=>zx,CACHE_CHECKPOINT:()=>c_,CACHE_VERSION:()=>Kx,Cache:()=>Nr,Configuration:()=>Ke,DEFAULT_RC_FILENAME:()=>j4,FormatType:()=>kle,InstallMode:()=>hl,LEGACY_PLUGINS:()=>v1,LOCKFILE_VERSION:()=>tk,LegacyMigrationResolver:()=>oC,LightReport:()=>fA,LinkType:()=>Jy,LockfileResolver:()=>aC,Manifest:()=>Ot,MessageName:()=>wr,MultiFetcher:()=>hE,PackageExtensionStatus:()=>vN,PackageExtensionType:()=>BN,PeerWarningType:()=>rk,Project:()=>St,Report:()=>Xs,ReportError:()=>Jt,SettingsType:()=>D1,StreamReport:()=>Lt,TAG_REGEXP:()=>FE,TelemetryManager:()=>uC,ThrowReport:()=>Qi,VirtualFetcher:()=>gE,WindowsLinkType:()=>xb,Workspace:()=>cC,WorkspaceFetcher:()=>mE,WorkspaceResolver:()=>Xn,YarnVersion:()=>rn,execUtils:()=>Ur,folderUtils:()=>YS,formatUtils:()=>de,hashUtils:()=>wn,httpUtils:()=>nn,miscUtils:()=>_e,nodeUtils:()=>Vi,parseMessageName:()=>AP,reportOptionDeprecations:()=>NE,scriptUtils:()=>un,semverUtils:()=>kr,stringifyMessageName:()=>Ku,structUtils:()=>W,tgzUtils:()=>Xi,treeUtils:()=>$s});var Ye=Et(()=>{Db();WS();jl();ih();Ib();Gl();vb();BU();Qf();bo();Zfe();spe();u_();P1();P1();ape();A_();lpe();f_();fE();fP();cM();Xpe();Wl();O1();Zpe();P_();AM();fM();Dd();S_();N1();Cne()});var ihe=_((z_t,l2)=>{\"use strict\";var LAt=process.env.TERM_PROGRAM===\"Hyper\",NAt=process.platform===\"win32\",the=process.platform===\"linux\",F_={ballotDisabled:\"\\u2612\",ballotOff:\"\\u2610\",ballotOn:\"\\u2611\",bullet:\"\\u2022\",bulletWhite:\"\\u25E6\",fullBlock:\"\\u2588\",heart:\"\\u2764\",identicalTo:\"\\u2261\",line:\"\\u2500\",mark:\"\\u203B\",middot:\"\\xB7\",minus:\"\\uFF0D\",multiplication:\"\\xD7\",obelus:\"\\xF7\",pencilDownRight:\"\\u270E\",pencilRight:\"\\u270F\",pencilUpRight:\"\\u2710\",percent:\"%\",pilcrow2:\"\\u2761\",pilcrow:\"\\xB6\",plusMinus:\"\\xB1\",section:\"\\xA7\",starsOff:\"\\u2606\",starsOn:\"\\u2605\",upDownArrow:\"\\u2195\"},rhe=Object.assign({},F_,{check:\"\\u221A\",cross:\"\\xD7\",ellipsisLarge:\"...\",ellipsis:\"...\",info:\"i\",question:\"?\",questionSmall:\"?\",pointer:\">\",pointerSmall:\"\\xBB\",radioOff:\"( )\",radioOn:\"(*)\",warning:\"\\u203C\"}),nhe=Object.assign({},F_,{ballotCross:\"\\u2718\",check:\"\\u2714\",cross:\"\\u2716\",ellipsisLarge:\"\\u22EF\",ellipsis:\"\\u2026\",info:\"\\u2139\",question:\"?\",questionFull:\"\\uFF1F\",questionSmall:\"\\uFE56\",pointer:the?\"\\u25B8\":\"\\u276F\",pointerSmall:the?\"\\u2023\":\"\\u203A\",radioOff:\"\\u25EF\",radioOn:\"\\u25C9\",warning:\"\\u26A0\"});l2.exports=NAt&&!LAt?rhe:nhe;Reflect.defineProperty(l2.exports,\"common\",{enumerable:!1,value:F_});Reflect.defineProperty(l2.exports,\"windows\",{enumerable:!1,value:rhe});Reflect.defineProperty(l2.exports,\"other\",{enumerable:!1,value:nhe})});var zc=_((V_t,R_)=>{\"use strict\";var OAt=t=>t!==null&&typeof t==\"object\"&&!Array.isArray(t),MAt=/[\\u001b\\u009b][[\\]#;?()]*(?:(?:(?:[^\\W_]*;?[^\\W_]*)\\u0007)|(?:(?:[0-9]{1,4}(;[0-9]{0,4})*)?[~0-9=<>cf-nqrtyA-PRZ]))/g,she=()=>{let t={enabled:!0,visible:!0,styles:{},keys:{}};\"FORCE_COLOR\"in process.env&&(t.enabled=process.env.FORCE_COLOR!==\"0\");let e=n=>{let u=n.open=`\\x1B[${n.codes[0]}m`,A=n.close=`\\x1B[${n.codes[1]}m`,p=n.regex=new RegExp(`\\\\u001b\\\\[${n.codes[1]}m`,\"g\");return n.wrap=(h,E)=>{h.includes(A)&&(h=h.replace(p,A+u));let I=u+h+A;return E?I.replace(/\\r*\\n/g,`${A}$&${u}`):I},n},r=(n,u,A)=>typeof n==\"function\"?n(u):n.wrap(u,A),o=(n,u)=>{if(n===\"\"||n==null)return\"\";if(t.enabled===!1)return n;if(t.visible===!1)return\"\";let A=\"\"+n,p=A.includes(`\n`),h=u.length;for(h>0&&u.includes(\"unstyle\")&&(u=[...new Set([\"unstyle\",...u])].reverse());h-- >0;)A=r(t.styles[u[h]],A,p);return A},a=(n,u,A)=>{t.styles[n]=e({name:n,codes:u}),(t.keys[A]||(t.keys[A]=[])).push(n),Reflect.defineProperty(t,n,{configurable:!0,enumerable:!0,set(h){t.alias(n,h)},get(){let h=E=>o(E,h.stack);return Reflect.setPrototypeOf(h,t),h.stack=this.stack?this.stack.concat(n):[n],h}})};return a(\"reset\",[0,0],\"modifier\"),a(\"bold\",[1,22],\"modifier\"),a(\"dim\",[2,22],\"modifier\"),a(\"italic\",[3,23],\"modifier\"),a(\"underline\",[4,24],\"modifier\"),a(\"inverse\",[7,27],\"modifier\"),a(\"hidden\",[8,28],\"modifier\"),a(\"strikethrough\",[9,29],\"modifier\"),a(\"black\",[30,39],\"color\"),a(\"red\",[31,39],\"color\"),a(\"green\",[32,39],\"color\"),a(\"yellow\",[33,39],\"color\"),a(\"blue\",[34,39],\"color\"),a(\"magenta\",[35,39],\"color\"),a(\"cyan\",[36,39],\"color\"),a(\"white\",[37,39],\"color\"),a(\"gray\",[90,39],\"color\"),a(\"grey\",[90,39],\"color\"),a(\"bgBlack\",[40,49],\"bg\"),a(\"bgRed\",[41,49],\"bg\"),a(\"bgGreen\",[42,49],\"bg\"),a(\"bgYellow\",[43,49],\"bg\"),a(\"bgBlue\",[44,49],\"bg\"),a(\"bgMagenta\",[45,49],\"bg\"),a(\"bgCyan\",[46,49],\"bg\"),a(\"bgWhite\",[47,49],\"bg\"),a(\"blackBright\",[90,39],\"bright\"),a(\"redBright\",[91,39],\"bright\"),a(\"greenBright\",[92,39],\"bright\"),a(\"yellowBright\",[93,39],\"bright\"),a(\"blueBright\",[94,39],\"bright\"),a(\"magentaBright\",[95,39],\"bright\"),a(\"cyanBright\",[96,39],\"bright\"),a(\"whiteBright\",[97,39],\"bright\"),a(\"bgBlackBright\",[100,49],\"bgBright\"),a(\"bgRedBright\",[101,49],\"bgBright\"),a(\"bgGreenBright\",[102,49],\"bgBright\"),a(\"bgYellowBright\",[103,49],\"bgBright\"),a(\"bgBlueBright\",[104,49],\"bgBright\"),a(\"bgMagentaBright\",[105,49],\"bgBright\"),a(\"bgCyanBright\",[106,49],\"bgBright\"),a(\"bgWhiteBright\",[107,49],\"bgBright\"),t.ansiRegex=MAt,t.hasColor=t.hasAnsi=n=>(t.ansiRegex.lastIndex=0,typeof n==\"string\"&&n!==\"\"&&t.ansiRegex.test(n)),t.alias=(n,u)=>{let A=typeof u==\"string\"?t[u]:u;if(typeof A!=\"function\")throw new TypeError(\"Expected alias to be the name of an existing color (string) or a function\");A.stack||(Reflect.defineProperty(A,\"name\",{value:n}),t.styles[n]=A,A.stack=[n]),Reflect.defineProperty(t,n,{configurable:!0,enumerable:!0,set(p){t.alias(n,p)},get(){let p=h=>o(h,p.stack);return Reflect.setPrototypeOf(p,t),p.stack=this.stack?this.stack.concat(A.stack):A.stack,p}})},t.theme=n=>{if(!OAt(n))throw new TypeError(\"Expected theme to be an object\");for(let u of Object.keys(n))t.alias(u,n[u]);return t},t.alias(\"unstyle\",n=>typeof n==\"string\"&&n!==\"\"?(t.ansiRegex.lastIndex=0,n.replace(t.ansiRegex,\"\")):\"\"),t.alias(\"noop\",n=>n),t.none=t.clear=t.noop,t.stripColor=t.unstyle,t.symbols=ihe(),t.define=a,t};R_.exports=she();R_.exports.create=she});var Lo=_(sn=>{\"use strict\";var UAt=Object.prototype.toString,nc=zc(),ohe=!1,T_=[],ahe={yellow:\"blue\",cyan:\"red\",green:\"magenta\",black:\"white\",blue:\"yellow\",red:\"cyan\",magenta:\"green\",white:\"black\"};sn.longest=(t,e)=>t.reduce((r,o)=>Math.max(r,e?o[e].length:o.length),0);sn.hasColor=t=>!!t&&nc.hasColor(t);var ik=sn.isObject=t=>t!==null&&typeof t==\"object\"&&!Array.isArray(t);sn.nativeType=t=>UAt.call(t).slice(8,-1).toLowerCase().replace(/\\s/g,\"\");sn.isAsyncFn=t=>sn.nativeType(t)===\"asyncfunction\";sn.isPrimitive=t=>t!=null&&typeof t!=\"object\"&&typeof t!=\"function\";sn.resolve=(t,e,...r)=>typeof e==\"function\"?e.call(t,...r):e;sn.scrollDown=(t=[])=>[...t.slice(1),t[0]];sn.scrollUp=(t=[])=>[t.pop(),...t];sn.reorder=(t=[])=>{let e=t.slice();return e.sort((r,o)=>r.index>o.index?1:r.index<o.index?-1:0),e};sn.swap=(t,e,r)=>{let o=t.length,a=r===o?0:r<0?o-1:r,n=t[e];t[e]=t[a],t[a]=n};sn.width=(t,e=80)=>{let r=t&&t.columns?t.columns:e;return t&&typeof t.getWindowSize==\"function\"&&(r=t.getWindowSize()[0]),process.platform===\"win32\"?r-1:r};sn.height=(t,e=20)=>{let r=t&&t.rows?t.rows:e;return t&&typeof t.getWindowSize==\"function\"&&(r=t.getWindowSize()[1]),r};sn.wordWrap=(t,e={})=>{if(!t)return t;typeof e==\"number\"&&(e={width:e});let{indent:r=\"\",newline:o=`\n`+r,width:a=80}=e,n=(o+r).match(/[^\\S\\n]/g)||[];a-=n.length;let u=`.{1,${a}}([\\\\s\\\\u200B]+|$)|[^\\\\s\\\\u200B]+?([\\\\s\\\\u200B]+|$)`,A=t.trim(),p=new RegExp(u,\"g\"),h=A.match(p)||[];return h=h.map(E=>E.replace(/\\n$/,\"\")),e.padEnd&&(h=h.map(E=>E.padEnd(a,\" \"))),e.padStart&&(h=h.map(E=>E.padStart(a,\" \"))),r+h.join(o)};sn.unmute=t=>{let e=t.stack.find(o=>nc.keys.color.includes(o));return e?nc[e]:t.stack.find(o=>o.slice(2)===\"bg\")?nc[e.slice(2)]:o=>o};sn.pascal=t=>t?t[0].toUpperCase()+t.slice(1):\"\";sn.inverse=t=>{if(!t||!t.stack)return t;let e=t.stack.find(o=>nc.keys.color.includes(o));if(e){let o=nc[\"bg\"+sn.pascal(e)];return o?o.black:t}let r=t.stack.find(o=>o.slice(0,2)===\"bg\");return r?nc[r.slice(2).toLowerCase()]||t:nc.none};sn.complement=t=>{if(!t||!t.stack)return t;let e=t.stack.find(o=>nc.keys.color.includes(o)),r=t.stack.find(o=>o.slice(0,2)===\"bg\");if(e&&!r)return nc[ahe[e]||e];if(r){let o=r.slice(2).toLowerCase(),a=ahe[o];return a&&nc[\"bg\"+sn.pascal(a)]||t}return nc.none};sn.meridiem=t=>{let e=t.getHours(),r=t.getMinutes(),o=e>=12?\"pm\":\"am\";e=e%12;let a=e===0?12:e,n=r<10?\"0\"+r:r;return a+\":\"+n+\" \"+o};sn.set=(t={},e=\"\",r)=>e.split(\".\").reduce((o,a,n,u)=>{let A=u.length-1>n?o[a]||{}:r;return!sn.isObject(A)&&n<u.length-1&&(A={}),o[a]=A},t);sn.get=(t={},e=\"\",r)=>{let o=t[e]==null?e.split(\".\").reduce((a,n)=>a&&a[n],t):t[e];return o??r};sn.mixin=(t,e)=>{if(!ik(t))return e;if(!ik(e))return t;for(let r of Object.keys(e)){let o=Object.getOwnPropertyDescriptor(e,r);if(o.hasOwnProperty(\"value\"))if(t.hasOwnProperty(r)&&ik(o.value)){let a=Object.getOwnPropertyDescriptor(t,r);ik(a.value)?t[r]=sn.merge({},t[r],e[r]):Reflect.defineProperty(t,r,o)}else Reflect.defineProperty(t,r,o);else Reflect.defineProperty(t,r,o)}return t};sn.merge=(...t)=>{let e={};for(let r of t)sn.mixin(e,r);return e};sn.mixinEmitter=(t,e)=>{let r=e.constructor.prototype;for(let o of Object.keys(r)){let a=r[o];typeof a==\"function\"?sn.define(t,o,a.bind(e)):sn.define(t,o,a)}};sn.onExit=t=>{let e=(r,o)=>{ohe||(ohe=!0,T_.forEach(a=>a()),r===!0&&process.exit(128+o))};T_.length===0&&(process.once(\"SIGTERM\",e.bind(null,!0,15)),process.once(\"SIGINT\",e.bind(null,!0,2)),process.once(\"exit\",e)),T_.push(t)};sn.define=(t,e,r)=>{Reflect.defineProperty(t,e,{value:r})};sn.defineExport=(t,e,r)=>{let o;Reflect.defineProperty(t,e,{enumerable:!0,configurable:!0,set(a){o=a},get(){return o?o():r()}})}});var lhe=_(hC=>{\"use strict\";hC.ctrl={a:\"first\",b:\"backward\",c:\"cancel\",d:\"deleteForward\",e:\"last\",f:\"forward\",g:\"reset\",i:\"tab\",k:\"cutForward\",l:\"reset\",n:\"newItem\",m:\"cancel\",j:\"submit\",p:\"search\",r:\"remove\",s:\"save\",u:\"undo\",w:\"cutLeft\",x:\"toggleCursor\",v:\"paste\"};hC.shift={up:\"shiftUp\",down:\"shiftDown\",left:\"shiftLeft\",right:\"shiftRight\",tab:\"prev\"};hC.fn={up:\"pageUp\",down:\"pageDown\",left:\"pageLeft\",right:\"pageRight\",delete:\"deleteForward\"};hC.option={b:\"backward\",f:\"forward\",d:\"cutRight\",left:\"cutLeft\",up:\"altUp\",down:\"altDown\"};hC.keys={pageup:\"pageUp\",pagedown:\"pageDown\",home:\"home\",end:\"end\",cancel:\"cancel\",delete:\"deleteForward\",backspace:\"delete\",down:\"down\",enter:\"submit\",escape:\"cancel\",left:\"left\",space:\"space\",number:\"number\",return:\"submit\",right:\"right\",tab:\"next\",up:\"up\"}});var Ahe=_((Z_t,uhe)=>{\"use strict\";var che=ve(\"readline\"),_At=lhe(),HAt=/^(?:\\x1b)([a-zA-Z0-9])$/,qAt=/^(?:\\x1b+)(O|N|\\[|\\[\\[)(?:(\\d+)(?:;(\\d+))?([~^$])|(?:1;)?(\\d+)?([a-zA-Z]))/,GAt={OP:\"f1\",OQ:\"f2\",OR:\"f3\",OS:\"f4\",\"[11~\":\"f1\",\"[12~\":\"f2\",\"[13~\":\"f3\",\"[14~\":\"f4\",\"[[A\":\"f1\",\"[[B\":\"f2\",\"[[C\":\"f3\",\"[[D\":\"f4\",\"[[E\":\"f5\",\"[15~\":\"f5\",\"[17~\":\"f6\",\"[18~\":\"f7\",\"[19~\":\"f8\",\"[20~\":\"f9\",\"[21~\":\"f10\",\"[23~\":\"f11\",\"[24~\":\"f12\",\"[A\":\"up\",\"[B\":\"down\",\"[C\":\"right\",\"[D\":\"left\",\"[E\":\"clear\",\"[F\":\"end\",\"[H\":\"home\",OA:\"up\",OB:\"down\",OC:\"right\",OD:\"left\",OE:\"clear\",OF:\"end\",OH:\"home\",\"[1~\":\"home\",\"[2~\":\"insert\",\"[3~\":\"delete\",\"[4~\":\"end\",\"[5~\":\"pageup\",\"[6~\":\"pagedown\",\"[[5~\":\"pageup\",\"[[6~\":\"pagedown\",\"[7~\":\"home\",\"[8~\":\"end\",\"[a\":\"up\",\"[b\":\"down\",\"[c\":\"right\",\"[d\":\"left\",\"[e\":\"clear\",\"[2$\":\"insert\",\"[3$\":\"delete\",\"[5$\":\"pageup\",\"[6$\":\"pagedown\",\"[7$\":\"home\",\"[8$\":\"end\",Oa:\"up\",Ob:\"down\",Oc:\"right\",Od:\"left\",Oe:\"clear\",\"[2^\":\"insert\",\"[3^\":\"delete\",\"[5^\":\"pageup\",\"[6^\":\"pagedown\",\"[7^\":\"home\",\"[8^\":\"end\",\"[Z\":\"tab\"};function jAt(t){return[\"[a\",\"[b\",\"[c\",\"[d\",\"[e\",\"[2$\",\"[3$\",\"[5$\",\"[6$\",\"[7$\",\"[8$\",\"[Z\"].includes(t)}function YAt(t){return[\"Oa\",\"Ob\",\"Oc\",\"Od\",\"Oe\",\"[2^\",\"[3^\",\"[5^\",\"[6^\",\"[7^\",\"[8^\"].includes(t)}var sk=(t=\"\",e={})=>{let r,o={name:e.name,ctrl:!1,meta:!1,shift:!1,option:!1,sequence:t,raw:t,...e};if(Buffer.isBuffer(t)?t[0]>127&&t[1]===void 0?(t[0]-=128,t=\"\\x1B\"+String(t)):t=String(t):t!==void 0&&typeof t!=\"string\"?t=String(t):t||(t=o.sequence||\"\"),o.sequence=o.sequence||t||o.name,t===\"\\r\")o.raw=void 0,o.name=\"return\";else if(t===`\n`)o.name=\"enter\";else if(t===\"\t\")o.name=\"tab\";else if(t===\"\\b\"||t===\"\\x7F\"||t===\"\\x1B\\x7F\"||t===\"\\x1B\\b\")o.name=\"backspace\",o.meta=t.charAt(0)===\"\\x1B\";else if(t===\"\\x1B\"||t===\"\\x1B\\x1B\")o.name=\"escape\",o.meta=t.length===2;else if(t===\" \"||t===\"\\x1B \")o.name=\"space\",o.meta=t.length===2;else if(t<=\"\u001a\")o.name=String.fromCharCode(t.charCodeAt(0)+\"a\".charCodeAt(0)-1),o.ctrl=!0;else if(t.length===1&&t>=\"0\"&&t<=\"9\")o.name=\"number\";else if(t.length===1&&t>=\"a\"&&t<=\"z\")o.name=t;else if(t.length===1&&t>=\"A\"&&t<=\"Z\")o.name=t.toLowerCase(),o.shift=!0;else if(r=HAt.exec(t))o.meta=!0,o.shift=/^[A-Z]$/.test(r[1]);else if(r=qAt.exec(t)){let a=[...t];a[0]===\"\\x1B\"&&a[1]===\"\\x1B\"&&(o.option=!0);let n=[r[1],r[2],r[4],r[6]].filter(Boolean).join(\"\"),u=(r[3]||r[5]||1)-1;o.ctrl=!!(u&4),o.meta=!!(u&10),o.shift=!!(u&1),o.code=n,o.name=GAt[n],o.shift=jAt(n)||o.shift,o.ctrl=YAt(n)||o.ctrl}return o};sk.listen=(t={},e)=>{let{stdin:r}=t;if(!r||r!==process.stdin&&!r.isTTY)throw new Error(\"Invalid stream passed\");let o=che.createInterface({terminal:!0,input:r});che.emitKeypressEvents(r,o);let a=(A,p)=>e(A,sk(A,p),o),n=r.isRaw;return r.isTTY&&r.setRawMode(!0),r.on(\"keypress\",a),o.resume(),()=>{r.isTTY&&r.setRawMode(n),r.removeListener(\"keypress\",a),o.pause(),o.close()}};sk.action=(t,e,r)=>{let o={..._At,...r};return e.ctrl?(e.action=o.ctrl[e.name],e):e.option&&o.option?(e.action=o.option[e.name],e):e.shift?(e.action=o.shift[e.name],e):(e.action=o.keys[e.name],e)};uhe.exports=sk});var phe=_(($_t,fhe)=>{\"use strict\";fhe.exports=t=>{t.timers=t.timers||{};let e=t.options.timers;if(!!e)for(let r of Object.keys(e)){let o=e[r];typeof o==\"number\"&&(o={interval:o}),WAt(t,r,o)}};function WAt(t,e,r={}){let o=t.timers[e]={name:e,start:Date.now(),ms:0,tick:0},a=r.interval||120;o.frames=r.frames||[],o.loading=!0;let n=setInterval(()=>{o.ms=Date.now()-o.start,o.tick++,t.render()},a);return o.stop=()=>{o.loading=!1,clearInterval(n)},Reflect.defineProperty(o,\"interval\",{value:n}),t.once(\"close\",()=>o.stop()),o.stop}});var ghe=_((e8t,hhe)=>{\"use strict\";var{define:KAt,width:zAt}=Lo(),L_=class{constructor(e){let r=e.options;KAt(this,\"_prompt\",e),this.type=e.type,this.name=e.name,this.message=\"\",this.header=\"\",this.footer=\"\",this.error=\"\",this.hint=\"\",this.input=\"\",this.cursor=0,this.index=0,this.lines=0,this.tick=0,this.prompt=\"\",this.buffer=\"\",this.width=zAt(r.stdout||process.stdout),Object.assign(this,r),this.name=this.name||this.message,this.message=this.message||this.name,this.symbols=e.symbols,this.styles=e.styles,this.required=new Set,this.cancelled=!1,this.submitted=!1}clone(){let e={...this};return e.status=this.status,e.buffer=Buffer.from(e.buffer),delete e.clone,e}set color(e){this._color=e}get color(){let e=this.prompt.styles;if(this.cancelled)return e.cancelled;if(this.submitted)return e.submitted;let r=this._color||e[this.status];return typeof r==\"function\"?r:e.pending}set loading(e){this._loading=e}get loading(){return typeof this._loading==\"boolean\"?this._loading:this.loadingChoices?\"choices\":!1}get status(){return this.cancelled?\"cancelled\":this.submitted?\"submitted\":\"pending\"}};hhe.exports=L_});var mhe=_((t8t,dhe)=>{\"use strict\";var N_=Lo(),eo=zc(),O_={default:eo.noop,noop:eo.noop,set inverse(t){this._inverse=t},get inverse(){return this._inverse||N_.inverse(this.primary)},set complement(t){this._complement=t},get complement(){return this._complement||N_.complement(this.primary)},primary:eo.cyan,success:eo.green,danger:eo.magenta,strong:eo.bold,warning:eo.yellow,muted:eo.dim,disabled:eo.gray,dark:eo.dim.gray,underline:eo.underline,set info(t){this._info=t},get info(){return this._info||this.primary},set em(t){this._em=t},get em(){return this._em||this.primary.underline},set heading(t){this._heading=t},get heading(){return this._heading||this.muted.underline},set pending(t){this._pending=t},get pending(){return this._pending||this.primary},set submitted(t){this._submitted=t},get submitted(){return this._submitted||this.success},set cancelled(t){this._cancelled=t},get cancelled(){return this._cancelled||this.danger},set typing(t){this._typing=t},get typing(){return this._typing||this.dim},set placeholder(t){this._placeholder=t},get placeholder(){return this._placeholder||this.primary.dim},set highlight(t){this._highlight=t},get highlight(){return this._highlight||this.inverse}};O_.merge=(t={})=>{t.styles&&typeof t.styles.enabled==\"boolean\"&&(eo.enabled=t.styles.enabled),t.styles&&typeof t.styles.visible==\"boolean\"&&(eo.visible=t.styles.visible);let e=N_.merge({},O_,t.styles);delete e.merge;for(let r of Object.keys(eo))e.hasOwnProperty(r)||Reflect.defineProperty(e,r,{get:()=>eo[r]});for(let r of Object.keys(eo.styles))e.hasOwnProperty(r)||Reflect.defineProperty(e,r,{get:()=>eo[r]});return e};dhe.exports=O_});var Ehe=_((r8t,yhe)=>{\"use strict\";var M_=process.platform===\"win32\",zf=zc(),VAt=Lo(),U_={...zf.symbols,upDownDoubleArrow:\"\\u21D5\",upDownDoubleArrow2:\"\\u2B0D\",upDownArrow:\"\\u2195\",asterisk:\"*\",asterism:\"\\u2042\",bulletWhite:\"\\u25E6\",electricArrow:\"\\u2301\",ellipsisLarge:\"\\u22EF\",ellipsisSmall:\"\\u2026\",fullBlock:\"\\u2588\",identicalTo:\"\\u2261\",indicator:zf.symbols.check,leftAngle:\"\\u2039\",mark:\"\\u203B\",minus:\"\\u2212\",multiplication:\"\\xD7\",obelus:\"\\xF7\",percent:\"%\",pilcrow:\"\\xB6\",pilcrow2:\"\\u2761\",pencilUpRight:\"\\u2710\",pencilDownRight:\"\\u270E\",pencilRight:\"\\u270F\",plus:\"+\",plusMinus:\"\\xB1\",pointRight:\"\\u261E\",rightAngle:\"\\u203A\",section:\"\\xA7\",hexagon:{off:\"\\u2B21\",on:\"\\u2B22\",disabled:\"\\u2B22\"},ballot:{on:\"\\u2611\",off:\"\\u2610\",disabled:\"\\u2612\"},stars:{on:\"\\u2605\",off:\"\\u2606\",disabled:\"\\u2606\"},folder:{on:\"\\u25BC\",off:\"\\u25B6\",disabled:\"\\u25B6\"},prefix:{pending:zf.symbols.question,submitted:zf.symbols.check,cancelled:zf.symbols.cross},separator:{pending:zf.symbols.pointerSmall,submitted:zf.symbols.middot,cancelled:zf.symbols.middot},radio:{off:M_?\"( )\":\"\\u25EF\",on:M_?\"(*)\":\"\\u25C9\",disabled:M_?\"(|)\":\"\\u24BE\"},numbers:[\"\\u24EA\",\"\\u2460\",\"\\u2461\",\"\\u2462\",\"\\u2463\",\"\\u2464\",\"\\u2465\",\"\\u2466\",\"\\u2467\",\"\\u2468\",\"\\u2469\",\"\\u246A\",\"\\u246B\",\"\\u246C\",\"\\u246D\",\"\\u246E\",\"\\u246F\",\"\\u2470\",\"\\u2471\",\"\\u2472\",\"\\u2473\",\"\\u3251\",\"\\u3252\",\"\\u3253\",\"\\u3254\",\"\\u3255\",\"\\u3256\",\"\\u3257\",\"\\u3258\",\"\\u3259\",\"\\u325A\",\"\\u325B\",\"\\u325C\",\"\\u325D\",\"\\u325E\",\"\\u325F\",\"\\u32B1\",\"\\u32B2\",\"\\u32B3\",\"\\u32B4\",\"\\u32B5\",\"\\u32B6\",\"\\u32B7\",\"\\u32B8\",\"\\u32B9\",\"\\u32BA\",\"\\u32BB\",\"\\u32BC\",\"\\u32BD\",\"\\u32BE\",\"\\u32BF\"]};U_.merge=t=>{let e=VAt.merge({},zf.symbols,U_,t.symbols);return delete e.merge,e};yhe.exports=U_});var whe=_((n8t,Che)=>{\"use strict\";var JAt=mhe(),XAt=Ehe(),ZAt=Lo();Che.exports=t=>{t.options=ZAt.merge({},t.options.theme,t.options),t.symbols=XAt.merge(t.options),t.styles=JAt.merge(t.options)}});var Phe=_((vhe,Dhe)=>{\"use strict\";var Ihe=process.env.TERM_PROGRAM===\"Apple_Terminal\",$At=zc(),__=Lo(),Vc=Dhe.exports=vhe,Di=\"\\x1B[\",Bhe=\"\\x07\",H_=!1,bh=Vc.code={bell:Bhe,beep:Bhe,beginning:`${Di}G`,down:`${Di}J`,esc:Di,getPosition:`${Di}6n`,hide:`${Di}?25l`,line:`${Di}2K`,lineEnd:`${Di}K`,lineStart:`${Di}1K`,restorePosition:Di+(Ihe?\"8\":\"u\"),savePosition:Di+(Ihe?\"7\":\"s\"),screen:`${Di}2J`,show:`${Di}?25h`,up:`${Di}1J`},Yd=Vc.cursor={get hidden(){return H_},hide(){return H_=!0,bh.hide},show(){return H_=!1,bh.show},forward:(t=1)=>`${Di}${t}C`,backward:(t=1)=>`${Di}${t}D`,nextLine:(t=1)=>`${Di}E`.repeat(t),prevLine:(t=1)=>`${Di}F`.repeat(t),up:(t=1)=>t?`${Di}${t}A`:\"\",down:(t=1)=>t?`${Di}${t}B`:\"\",right:(t=1)=>t?`${Di}${t}C`:\"\",left:(t=1)=>t?`${Di}${t}D`:\"\",to(t,e){return e?`${Di}${e+1};${t+1}H`:`${Di}${t+1}G`},move(t=0,e=0){let r=\"\";return r+=t<0?Yd.left(-t):t>0?Yd.right(t):\"\",r+=e<0?Yd.up(-e):e>0?Yd.down(e):\"\",r},restore(t={}){let{after:e,cursor:r,initial:o,input:a,prompt:n,size:u,value:A}=t;if(o=__.isPrimitive(o)?String(o):\"\",a=__.isPrimitive(a)?String(a):\"\",A=__.isPrimitive(A)?String(A):\"\",u){let p=Vc.cursor.up(u)+Vc.cursor.to(n.length),h=a.length-r;return h>0&&(p+=Vc.cursor.left(h)),p}if(A||e){let p=!a&&!!o?-o.length:-a.length+r;return e&&(p-=e.length),a===\"\"&&o&&!n.includes(o)&&(p+=o.length),Vc.cursor.move(p)}}},q_=Vc.erase={screen:bh.screen,up:bh.up,down:bh.down,line:bh.line,lineEnd:bh.lineEnd,lineStart:bh.lineStart,lines(t){let e=\"\";for(let r=0;r<t;r++)e+=Vc.erase.line+(r<t-1?Vc.cursor.up(1):\"\");return t&&(e+=Vc.code.beginning),e}};Vc.clear=(t=\"\",e=process.stdout.columns)=>{if(!e)return q_.line+Yd.to(0);let r=n=>[...$At.unstyle(n)].length,o=t.split(/\\r?\\n/),a=0;for(let n of o)a+=1+Math.floor(Math.max(r(n)-1,0)/e);return(q_.line+Yd.prevLine()).repeat(a-1)+q_.line+Yd.to(0)}});var gC=_((i8t,bhe)=>{\"use strict\";var eft=ve(\"events\"),She=zc(),G_=Ahe(),tft=phe(),rft=ghe(),nft=whe(),Ra=Lo(),Wd=Phe(),c2=class extends eft{constructor(e={}){super(),this.name=e.name,this.type=e.type,this.options=e,nft(this),tft(this),this.state=new rft(this),this.initial=[e.initial,e.default].find(r=>r!=null),this.stdout=e.stdout||process.stdout,this.stdin=e.stdin||process.stdin,this.scale=e.scale||1,this.term=this.options.term||process.env.TERM_PROGRAM,this.margin=sft(this.options.margin),this.setMaxListeners(0),ift(this)}async keypress(e,r={}){this.keypressed=!0;let o=G_.action(e,G_(e,r),this.options.actions);this.state.keypress=o,this.emit(\"keypress\",e,o),this.emit(\"state\",this.state.clone());let a=this.options[o.action]||this[o.action]||this.dispatch;if(typeof a==\"function\")return await a.call(this,e,o);this.alert()}alert(){delete this.state.alert,this.options.show===!1?this.emit(\"alert\"):this.stdout.write(Wd.code.beep)}cursorHide(){this.stdout.write(Wd.cursor.hide()),Ra.onExit(()=>this.cursorShow())}cursorShow(){this.stdout.write(Wd.cursor.show())}write(e){!e||(this.stdout&&this.state.show!==!1&&this.stdout.write(e),this.state.buffer+=e)}clear(e=0){let r=this.state.buffer;this.state.buffer=\"\",!(!r&&!e||this.options.show===!1)&&this.stdout.write(Wd.cursor.down(e)+Wd.clear(r,this.width))}restore(){if(this.state.closed||this.options.show===!1)return;let{prompt:e,after:r,rest:o}=this.sections(),{cursor:a,initial:n=\"\",input:u=\"\",value:A=\"\"}=this,p=this.state.size=o.length,h={after:r,cursor:a,initial:n,input:u,prompt:e,size:p,value:A},E=Wd.cursor.restore(h);E&&this.stdout.write(E)}sections(){let{buffer:e,input:r,prompt:o}=this.state;o=She.unstyle(o);let a=She.unstyle(e),n=a.indexOf(o),u=a.slice(0,n),p=a.slice(n).split(`\n`),h=p[0],E=p[p.length-1],v=(o+(r?\" \"+r:\"\")).length,x=v<h.length?h.slice(v+1):\"\";return{header:u,prompt:h,after:x,rest:p.slice(1),last:E}}async submit(){this.state.submitted=!0,this.state.validating=!0,this.options.onSubmit&&await this.options.onSubmit.call(this,this.name,this.value,this);let e=this.state.error||await this.validate(this.value,this.state);if(e!==!0){let r=`\n`+this.symbols.pointer+\" \";typeof e==\"string\"?r+=e.trim():r+=\"Invalid input\",this.state.error=`\n`+this.styles.danger(r),this.state.submitted=!1,await this.render(),await this.alert(),this.state.validating=!1,this.state.error=void 0;return}this.state.validating=!1,await this.render(),await this.close(),this.value=await this.result(this.value),this.emit(\"submit\",this.value)}async cancel(e){this.state.cancelled=this.state.submitted=!0,await this.render(),await this.close(),typeof this.options.onCancel==\"function\"&&await this.options.onCancel.call(this,this.name,this.value,this),this.emit(\"cancel\",await this.error(e))}async close(){this.state.closed=!0;try{let e=this.sections(),r=Math.ceil(e.prompt.length/this.width);e.rest&&this.write(Wd.cursor.down(e.rest.length)),this.write(`\n`.repeat(r))}catch{}this.emit(\"close\")}start(){!this.stop&&this.options.show!==!1&&(this.stop=G_.listen(this,this.keypress.bind(this)),this.once(\"close\",this.stop))}async skip(){return this.skipped=this.options.skip===!0,typeof this.options.skip==\"function\"&&(this.skipped=await this.options.skip.call(this,this.name,this.value)),this.skipped}async initialize(){let{format:e,options:r,result:o}=this;if(this.format=()=>e.call(this,this.value),this.result=()=>o.call(this,this.value),typeof r.initial==\"function\"&&(this.initial=await r.initial.call(this,this)),typeof r.onRun==\"function\"&&await r.onRun.call(this,this),typeof r.onSubmit==\"function\"){let a=r.onSubmit.bind(this),n=this.submit.bind(this);delete this.options.onSubmit,this.submit=async()=>(await a(this.name,this.value,this),n())}await this.start(),await this.render()}render(){throw new Error(\"expected prompt to have a custom render method\")}run(){return new Promise(async(e,r)=>{if(this.once(\"submit\",e),this.once(\"cancel\",r),await this.skip())return this.render=()=>{},this.submit();await this.initialize(),this.emit(\"run\")})}async element(e,r,o){let{options:a,state:n,symbols:u,timers:A}=this,p=A&&A[e];n.timer=p;let h=a[e]||n[e]||u[e],E=r&&r[e]!=null?r[e]:await h;if(E===\"\")return E;let I=await this.resolve(E,n,r,o);return!I&&r&&r[e]?this.resolve(h,n,r,o):I}async prefix(){let e=await this.element(\"prefix\")||this.symbols,r=this.timers&&this.timers.prefix,o=this.state;return o.timer=r,Ra.isObject(e)&&(e=e[o.status]||e.pending),Ra.hasColor(e)?e:(this.styles[o.status]||this.styles.pending)(e)}async message(){let e=await this.element(\"message\");return Ra.hasColor(e)?e:this.styles.strong(e)}async separator(){let e=await this.element(\"separator\")||this.symbols,r=this.timers&&this.timers.separator,o=this.state;o.timer=r;let a=e[o.status]||e.pending||o.separator,n=await this.resolve(a,o);return Ra.isObject(n)&&(n=n[o.status]||n.pending),Ra.hasColor(n)?n:this.styles.muted(n)}async pointer(e,r){let o=await this.element(\"pointer\",e,r);if(typeof o==\"string\"&&Ra.hasColor(o))return o;if(o){let a=this.styles,n=this.index===r,u=n?a.primary:h=>h,A=await this.resolve(o[n?\"on\":\"off\"]||o,this.state),p=Ra.hasColor(A)?A:u(A);return n?p:\" \".repeat(A.length)}}async indicator(e,r){let o=await this.element(\"indicator\",e,r);if(typeof o==\"string\"&&Ra.hasColor(o))return o;if(o){let a=this.styles,n=e.enabled===!0,u=n?a.success:a.dark,A=o[n?\"on\":\"off\"]||o;return Ra.hasColor(A)?A:u(A)}return\"\"}body(){return null}footer(){if(this.state.status===\"pending\")return this.element(\"footer\")}header(){if(this.state.status===\"pending\")return this.element(\"header\")}async hint(){if(this.state.status===\"pending\"&&!this.isValue(this.state.input)){let e=await this.element(\"hint\");return Ra.hasColor(e)?e:this.styles.muted(e)}}error(e){return this.state.submitted?\"\":e||this.state.error}format(e){return e}result(e){return e}validate(e){return this.options.required===!0?this.isValue(e):!0}isValue(e){return e!=null&&e!==\"\"}resolve(e,...r){return Ra.resolve(this,e,...r)}get base(){return c2.prototype}get style(){return this.styles[this.state.status]}get height(){return this.options.rows||Ra.height(this.stdout,25)}get width(){return this.options.columns||Ra.width(this.stdout,80)}get size(){return{width:this.width,height:this.height}}set cursor(e){this.state.cursor=e}get cursor(){return this.state.cursor}set input(e){this.state.input=e}get input(){return this.state.input}set value(e){this.state.value=e}get value(){let{input:e,value:r}=this.state,o=[r,e].find(this.isValue.bind(this));return this.isValue(o)?o:this.initial}static get prompt(){return e=>new this(e).run()}};function ift(t){let e=a=>t[a]===void 0||typeof t[a]==\"function\",r=[\"actions\",\"choices\",\"initial\",\"margin\",\"roles\",\"styles\",\"symbols\",\"theme\",\"timers\",\"value\"],o=[\"body\",\"footer\",\"error\",\"header\",\"hint\",\"indicator\",\"message\",\"prefix\",\"separator\",\"skip\"];for(let a of Object.keys(t.options)){if(r.includes(a)||/^on[A-Z]/.test(a))continue;let n=t.options[a];typeof n==\"function\"&&e(a)?o.includes(a)||(t[a]=n.bind(t)):typeof t[a]!=\"function\"&&(t[a]=n)}}function sft(t){typeof t==\"number\"&&(t=[t,t,t,t]);let e=[].concat(t||[]),r=a=>a%2===0?`\n`:\" \",o=[];for(let a=0;a<4;a++){let n=r(a);e[a]?o.push(n.repeat(e[a])):o.push(\"\")}return o}bhe.exports=c2});var Qhe=_((s8t,khe)=>{\"use strict\";var oft=Lo(),xhe={default(t,e){return e},checkbox(t,e){throw new Error(\"checkbox role is not implemented yet\")},editable(t,e){throw new Error(\"editable role is not implemented yet\")},expandable(t,e){throw new Error(\"expandable role is not implemented yet\")},heading(t,e){return e.disabled=\"\",e.indicator=[e.indicator,\" \"].find(r=>r!=null),e.message=e.message||\"\",e},input(t,e){throw new Error(\"input role is not implemented yet\")},option(t,e){return xhe.default(t,e)},radio(t,e){throw new Error(\"radio role is not implemented yet\")},separator(t,e){return e.disabled=\"\",e.indicator=[e.indicator,\" \"].find(r=>r!=null),e.message=e.message||t.symbols.line.repeat(5),e},spacer(t,e){return e}};khe.exports=(t,e={})=>{let r=oft.merge({},xhe,e.roles);return r[t]||r.default}});var u2=_((o8t,The)=>{\"use strict\";var aft=zc(),lft=gC(),cft=Qhe(),ok=Lo(),{reorder:j_,scrollUp:uft,scrollDown:Aft,isObject:Fhe,swap:fft}=ok,Y_=class extends lft{constructor(e){super(e),this.cursorHide(),this.maxSelected=e.maxSelected||1/0,this.multiple=e.multiple||!1,this.initial=e.initial||0,this.delay=e.delay||0,this.longest=0,this.num=\"\"}async initialize(){typeof this.options.initial==\"function\"&&(this.initial=await this.options.initial.call(this)),await this.reset(!0),await super.initialize()}async reset(){let{choices:e,initial:r,autofocus:o,suggest:a}=this.options;if(this.state._choices=[],this.state.choices=[],this.choices=await Promise.all(await this.toChoices(e)),this.choices.forEach(n=>n.enabled=!1),typeof a!=\"function\"&&this.selectable.length===0)throw new Error(\"At least one choice must be selectable\");Fhe(r)&&(r=Object.keys(r)),Array.isArray(r)?(o!=null&&(this.index=this.findIndex(o)),r.forEach(n=>this.enable(this.find(n))),await this.render()):(o!=null&&(r=o),typeof r==\"string\"&&(r=this.findIndex(r)),typeof r==\"number\"&&r>-1&&(this.index=Math.max(0,Math.min(r,this.choices.length)),this.enable(this.find(this.index)))),this.isDisabled(this.focused)&&await this.down()}async toChoices(e,r){this.state.loadingChoices=!0;let o=[],a=0,n=async(u,A)=>{typeof u==\"function\"&&(u=await u.call(this)),u instanceof Promise&&(u=await u);for(let p=0;p<u.length;p++){let h=u[p]=await this.toChoice(u[p],a++,A);o.push(h),h.choices&&await n(h.choices,h)}return o};return n(e,r).then(u=>(this.state.loadingChoices=!1,u))}async toChoice(e,r,o){if(typeof e==\"function\"&&(e=await e.call(this,this)),e instanceof Promise&&(e=await e),typeof e==\"string\"&&(e={name:e}),e.normalized)return e;e.normalized=!0;let a=e.value;if(e=cft(e.role,this.options)(this,e),typeof e.disabled==\"string\"&&!e.hint&&(e.hint=e.disabled,e.disabled=!0),e.disabled===!0&&e.hint==null&&(e.hint=\"(disabled)\"),e.index!=null)return e;e.name=e.name||e.key||e.title||e.value||e.message,e.message=e.message||e.name||\"\",e.value=[e.value,e.name].find(this.isValue.bind(this)),e.input=\"\",e.index=r,e.cursor=0,ok.define(e,\"parent\",o),e.level=o?o.level+1:1,e.indent==null&&(e.indent=o?o.indent+\"  \":e.indent||\"\"),e.path=o?o.path+\".\"+e.name:e.name,e.enabled=!!(this.multiple&&!this.isDisabled(e)&&(e.enabled||this.isSelected(e))),this.isDisabled(e)||(this.longest=Math.max(this.longest,aft.unstyle(e.message).length));let u={...e};return e.reset=(A=u.input,p=u.value)=>{for(let h of Object.keys(u))e[h]=u[h];e.input=A,e.value=p},a==null&&typeof e.initial==\"function\"&&(e.input=await e.initial.call(this,this.state,e,r)),e}async onChoice(e,r){this.emit(\"choice\",e,r,this),typeof e.onChoice==\"function\"&&await e.onChoice.call(this,this.state,e,r)}async addChoice(e,r,o){let a=await this.toChoice(e,r,o);return this.choices.push(a),this.index=this.choices.length-1,this.limit=this.choices.length,a}async newItem(e,r,o){let a={name:\"New choice name?\",editable:!0,newChoice:!0,...e},n=await this.addChoice(a,r,o);return n.updateChoice=()=>{delete n.newChoice,n.name=n.message=n.input,n.input=\"\",n.cursor=0},this.render()}indent(e){return e.indent==null?e.level>1?\"  \".repeat(e.level-1):\"\":e.indent}dispatch(e,r){if(this.multiple&&this[r.name])return this[r.name]();this.alert()}focus(e,r){return typeof r!=\"boolean\"&&(r=e.enabled),r&&!e.enabled&&this.selected.length>=this.maxSelected?this.alert():(this.index=e.index,e.enabled=r&&!this.isDisabled(e),e)}space(){return this.multiple?(this.toggle(this.focused),this.render()):this.alert()}a(){if(this.maxSelected<this.choices.length)return this.alert();let e=this.selectable.every(r=>r.enabled);return this.choices.forEach(r=>r.enabled=!e),this.render()}i(){return this.choices.length-this.selected.length>this.maxSelected?this.alert():(this.choices.forEach(e=>e.enabled=!e.enabled),this.render())}g(e=this.focused){return this.choices.some(r=>!!r.parent)?(this.toggle(e.parent&&!e.choices?e.parent:e),this.render()):this.a()}toggle(e,r){if(!e.enabled&&this.selected.length>=this.maxSelected)return this.alert();typeof r!=\"boolean\"&&(r=!e.enabled),e.enabled=r,e.choices&&e.choices.forEach(a=>this.toggle(a,r));let o=e.parent;for(;o;){let a=o.choices.filter(n=>this.isDisabled(n));o.enabled=a.every(n=>n.enabled===!0),o=o.parent}return Rhe(this,this.choices),this.emit(\"toggle\",e,this),e}enable(e){return this.selected.length>=this.maxSelected?this.alert():(e.enabled=!this.isDisabled(e),e.choices&&e.choices.forEach(this.enable.bind(this)),e)}disable(e){return e.enabled=!1,e.choices&&e.choices.forEach(this.disable.bind(this)),e}number(e){this.num+=e;let r=o=>{let a=Number(o);if(a>this.choices.length-1)return this.alert();let n=this.focused,u=this.choices.find(A=>a===A.index);if(!u.enabled&&this.selected.length>=this.maxSelected)return this.alert();if(this.visible.indexOf(u)===-1){let A=j_(this.choices),p=A.indexOf(u);if(n.index>p){let h=A.slice(p,p+this.limit),E=A.filter(I=>!h.includes(I));this.choices=h.concat(E)}else{let h=p-this.limit+1;this.choices=A.slice(h).concat(A.slice(0,h))}}return this.index=this.choices.indexOf(u),this.toggle(this.focused),this.render()};return clearTimeout(this.numberTimeout),new Promise(o=>{let a=this.choices.length,n=this.num,u=(A=!1,p)=>{clearTimeout(this.numberTimeout),A&&(p=r(n)),this.num=\"\",o(p)};if(n===\"0\"||n.length===1&&Number(n+\"0\")>a)return u(!0);if(Number(n)>a)return u(!1,this.alert());this.numberTimeout=setTimeout(()=>u(!0),this.delay)})}home(){return this.choices=j_(this.choices),this.index=0,this.render()}end(){let e=this.choices.length-this.limit,r=j_(this.choices);return this.choices=r.slice(e).concat(r.slice(0,e)),this.index=this.limit-1,this.render()}first(){return this.index=0,this.render()}last(){return this.index=this.visible.length-1,this.render()}prev(){return this.visible.length<=1?this.alert():this.up()}next(){return this.visible.length<=1?this.alert():this.down()}right(){return this.cursor>=this.input.length?this.alert():(this.cursor++,this.render())}left(){return this.cursor<=0?this.alert():(this.cursor--,this.render())}up(){let e=this.choices.length,r=this.visible.length,o=this.index;return this.options.scroll===!1&&o===0?this.alert():e>r&&o===0?this.scrollUp():(this.index=(o-1%e+e)%e,this.isDisabled()?this.up():this.render())}down(){let e=this.choices.length,r=this.visible.length,o=this.index;return this.options.scroll===!1&&o===r-1?this.alert():e>r&&o===r-1?this.scrollDown():(this.index=(o+1)%e,this.isDisabled()?this.down():this.render())}scrollUp(e=0){return this.choices=uft(this.choices),this.index=e,this.isDisabled()?this.up():this.render()}scrollDown(e=this.visible.length-1){return this.choices=Aft(this.choices),this.index=e,this.isDisabled()?this.down():this.render()}async shiftUp(){if(this.options.sort===!0){this.sorting=!0,this.swap(this.index-1),await this.up(),this.sorting=!1;return}return this.scrollUp(this.index)}async shiftDown(){if(this.options.sort===!0){this.sorting=!0,this.swap(this.index+1),await this.down(),this.sorting=!1;return}return this.scrollDown(this.index)}pageUp(){return this.visible.length<=1?this.alert():(this.limit=Math.max(this.limit-1,0),this.index=Math.min(this.limit-1,this.index),this._limit=this.limit,this.isDisabled()?this.up():this.render())}pageDown(){return this.visible.length>=this.choices.length?this.alert():(this.index=Math.max(0,this.index),this.limit=Math.min(this.limit+1,this.choices.length),this._limit=this.limit,this.isDisabled()?this.down():this.render())}swap(e){fft(this.choices,this.index,e)}isDisabled(e=this.focused){return e&&[\"disabled\",\"collapsed\",\"hidden\",\"completing\",\"readonly\"].some(o=>e[o]===!0)?!0:e&&e.role===\"heading\"}isEnabled(e=this.focused){if(Array.isArray(e))return e.every(r=>this.isEnabled(r));if(e.choices){let r=e.choices.filter(o=>!this.isDisabled(o));return e.enabled&&r.every(o=>this.isEnabled(o))}return e.enabled&&!this.isDisabled(e)}isChoice(e,r){return e.name===r||e.index===Number(r)}isSelected(e){return Array.isArray(this.initial)?this.initial.some(r=>this.isChoice(e,r)):this.isChoice(e,this.initial)}map(e=[],r=\"value\"){return[].concat(e||[]).reduce((o,a)=>(o[a]=this.find(a,r),o),{})}filter(e,r){let a=typeof e==\"function\"?e:(A,p)=>[A.name,p].includes(e),u=(this.options.multiple?this.state._choices:this.choices).filter(a);return r?u.map(A=>A[r]):u}find(e,r){if(Fhe(e))return r?e[r]:e;let a=typeof e==\"function\"?e:(u,A)=>[u.name,A].includes(e),n=this.choices.find(a);if(n)return r?n[r]:n}findIndex(e){return this.choices.indexOf(this.find(e))}async submit(){let e=this.focused;if(!e)return this.alert();if(e.newChoice)return e.input?(e.updateChoice(),this.render()):this.alert();if(this.choices.some(u=>u.newChoice))return this.alert();let{reorder:r,sort:o}=this.options,a=this.multiple===!0,n=this.selected;return n===void 0?this.alert():(Array.isArray(n)&&r!==!1&&o!==!0&&(n=ok.reorder(n)),this.value=a?n.map(u=>u.name):n.name,super.submit())}set choices(e=[]){this.state._choices=this.state._choices||[],this.state.choices=e;for(let r of e)this.state._choices.some(o=>o.name===r.name)||this.state._choices.push(r);if(!this._initial&&this.options.initial){this._initial=!0;let r=this.initial;if(typeof r==\"string\"||typeof r==\"number\"){let o=this.find(r);o&&(this.initial=o.index,this.focus(o,!0))}}}get choices(){return Rhe(this,this.state.choices||[])}set visible(e){this.state.visible=e}get visible(){return(this.state.visible||this.choices).slice(0,this.limit)}set limit(e){this.state.limit=e}get limit(){let{state:e,options:r,choices:o}=this,a=e.limit||this._limit||r.limit||o.length;return Math.min(a,this.height)}set value(e){super.value=e}get value(){return typeof super.value!=\"string\"&&super.value===this.initial?this.input:super.value}set index(e){this.state.index=e}get index(){return Math.max(0,this.state?this.state.index:0)}get enabled(){return this.filter(this.isEnabled.bind(this))}get focused(){let e=this.choices[this.index];return e&&this.state.submitted&&this.multiple!==!0&&(e.enabled=!0),e}get selectable(){return this.choices.filter(e=>!this.isDisabled(e))}get selected(){return this.multiple?this.enabled:this.focused}};function Rhe(t,e){if(e instanceof Promise)return e;if(typeof e==\"function\"){if(ok.isAsyncFn(e))return e;e=e.call(t,t)}for(let r of e){if(Array.isArray(r.choices)){let o=r.choices.filter(a=>!t.isDisabled(a));r.enabled=o.every(a=>a.enabled===!0)}t.isDisabled(r)===!0&&delete r.enabled}return e}The.exports=Y_});var xh=_((a8t,Lhe)=>{\"use strict\";var pft=u2(),W_=Lo(),K_=class extends pft{constructor(e){super(e),this.emptyError=this.options.emptyError||\"No items were selected\"}async dispatch(e,r){if(this.multiple)return this[r.name]?await this[r.name](e,r):await super.dispatch(e,r);this.alert()}separator(){if(this.options.separator)return super.separator();let e=this.styles.muted(this.symbols.ellipsis);return this.state.submitted?super.separator():e}pointer(e,r){return!this.multiple||this.options.pointer?super.pointer(e,r):\"\"}indicator(e,r){return this.multiple?super.indicator(e,r):\"\"}choiceMessage(e,r){let o=this.resolve(e.message,this.state,e,r);return e.role===\"heading\"&&!W_.hasColor(o)&&(o=this.styles.strong(o)),this.resolve(o,this.state,e,r)}choiceSeparator(){return\":\"}async renderChoice(e,r){await this.onChoice(e,r);let o=this.index===r,a=await this.pointer(e,r),n=await this.indicator(e,r)+(e.pad||\"\"),u=await this.resolve(e.hint,this.state,e,r);u&&!W_.hasColor(u)&&(u=this.styles.muted(u));let A=this.indent(e),p=await this.choiceMessage(e,r),h=()=>[this.margin[3],A+a+n,p,this.margin[1],u].filter(Boolean).join(\" \");return e.role===\"heading\"?h():e.disabled?(W_.hasColor(p)||(p=this.styles.disabled(p)),h()):(o&&(p=this.styles.em(p)),h())}async renderChoices(){if(this.state.loading===\"choices\")return this.styles.warning(\"Loading choices\");if(this.state.submitted)return\"\";let e=this.visible.map(async(n,u)=>await this.renderChoice(n,u)),r=await Promise.all(e);r.length||r.push(this.styles.danger(\"No matching choices\"));let o=this.margin[0]+r.join(`\n`),a;return this.options.choicesHeader&&(a=await this.resolve(this.options.choicesHeader,this.state)),[a,o].filter(Boolean).join(`\n`)}format(){return!this.state.submitted||this.state.cancelled?\"\":Array.isArray(this.selected)?this.selected.map(e=>this.styles.primary(e.name)).join(\", \"):this.styles.primary(this.selected.name)}async render(){let{submitted:e,size:r}=this.state,o=\"\",a=await this.header(),n=await this.prefix(),u=await this.separator(),A=await this.message();this.options.promptLine!==!1&&(o=[n,A,u,\"\"].join(\" \"),this.state.prompt=o);let p=await this.format(),h=await this.error()||await this.hint(),E=await this.renderChoices(),I=await this.footer();p&&(o+=p),h&&!o.includes(h)&&(o+=\" \"+h),e&&!p&&!E.trim()&&this.multiple&&this.emptyError!=null&&(o+=this.styles.danger(this.emptyError)),this.clear(r),this.write([a,o,E,I].filter(Boolean).join(`\n`)),this.write(this.margin[2]),this.restore()}};Lhe.exports=K_});var Ohe=_((l8t,Nhe)=>{\"use strict\";var hft=xh(),gft=(t,e)=>{let r=t.toLowerCase();return o=>{let n=o.toLowerCase().indexOf(r),u=e(o.slice(n,n+r.length));return n>=0?o.slice(0,n)+u+o.slice(n+r.length):o}},z_=class extends hft{constructor(e){super(e),this.cursorShow()}moveCursor(e){this.state.cursor+=e}dispatch(e){return this.append(e)}space(e){return this.options.multiple?super.space(e):this.append(e)}append(e){let{cursor:r,input:o}=this.state;return this.input=o.slice(0,r)+e+o.slice(r),this.moveCursor(1),this.complete()}delete(){let{cursor:e,input:r}=this.state;return r?(this.input=r.slice(0,e-1)+r.slice(e),this.moveCursor(-1),this.complete()):this.alert()}deleteForward(){let{cursor:e,input:r}=this.state;return r[e]===void 0?this.alert():(this.input=`${r}`.slice(0,e)+`${r}`.slice(e+1),this.complete())}number(e){return this.append(e)}async complete(){this.completing=!0,this.choices=await this.suggest(this.input,this.state._choices),this.state.limit=void 0,this.index=Math.min(Math.max(this.visible.length-1,0),this.index),await this.render(),this.completing=!1}suggest(e=this.input,r=this.state._choices){if(typeof this.options.suggest==\"function\")return this.options.suggest.call(this,e,r);let o=e.toLowerCase();return r.filter(a=>a.message.toLowerCase().includes(o))}pointer(){return\"\"}format(){if(!this.focused)return this.input;if(this.options.multiple&&this.state.submitted)return this.selected.map(e=>this.styles.primary(e.message)).join(\", \");if(this.state.submitted){let e=this.value=this.input=this.focused.value;return this.styles.primary(e)}return this.input}async render(){if(this.state.status!==\"pending\")return super.render();let e=this.options.highlight?this.options.highlight.bind(this):this.styles.placeholder,r=gft(this.input,e),o=this.choices;this.choices=o.map(a=>({...a,message:r(a.message)})),await super.render(),this.choices=o}submit(){return this.options.multiple&&(this.value=this.selected.map(e=>e.name)),super.submit()}};Nhe.exports=z_});var J_=_((c8t,Mhe)=>{\"use strict\";var V_=Lo();Mhe.exports=(t,e={})=>{t.cursorHide();let{input:r=\"\",initial:o=\"\",pos:a,showCursor:n=!0,color:u}=e,A=u||t.styles.placeholder,p=V_.inverse(t.styles.primary),h=R=>p(t.styles.black(R)),E=r,I=\" \",v=h(I);if(t.blink&&t.blink.off===!0&&(h=R=>R,v=\"\"),n&&a===0&&o===\"\"&&r===\"\")return h(I);if(n&&a===0&&(r===o||r===\"\"))return h(o[0])+A(o.slice(1));o=V_.isPrimitive(o)?`${o}`:\"\",r=V_.isPrimitive(r)?`${r}`:\"\";let x=o&&o.startsWith(r)&&o!==r,C=x?h(o[r.length]):v;if(a!==r.length&&n===!0&&(E=r.slice(0,a)+h(r[a])+r.slice(a+1),C=\"\"),n===!1&&(C=\"\"),x){let R=t.styles.unstyle(E+C);return E+C+A(o.slice(R.length))}return E+C}});var ak=_((u8t,Uhe)=>{\"use strict\";var dft=zc(),mft=xh(),yft=J_(),X_=class extends mft{constructor(e){super({...e,multiple:!0}),this.type=\"form\",this.initial=this.options.initial,this.align=[this.options.align,\"right\"].find(r=>r!=null),this.emptyError=\"\",this.values={}}async reset(e){return await super.reset(),e===!0&&(this._index=this.index),this.index=this._index,this.values={},this.choices.forEach(r=>r.reset&&r.reset()),this.render()}dispatch(e){return!!e&&this.append(e)}append(e){let r=this.focused;if(!r)return this.alert();let{cursor:o,input:a}=r;return r.value=r.input=a.slice(0,o)+e+a.slice(o),r.cursor++,this.render()}delete(){let e=this.focused;if(!e||e.cursor<=0)return this.alert();let{cursor:r,input:o}=e;return e.value=e.input=o.slice(0,r-1)+o.slice(r),e.cursor--,this.render()}deleteForward(){let e=this.focused;if(!e)return this.alert();let{cursor:r,input:o}=e;if(o[r]===void 0)return this.alert();let a=`${o}`.slice(0,r)+`${o}`.slice(r+1);return e.value=e.input=a,this.render()}right(){let e=this.focused;return e?e.cursor>=e.input.length?this.alert():(e.cursor++,this.render()):this.alert()}left(){let e=this.focused;return e?e.cursor<=0?this.alert():(e.cursor--,this.render()):this.alert()}space(e,r){return this.dispatch(e,r)}number(e,r){return this.dispatch(e,r)}next(){let e=this.focused;if(!e)return this.alert();let{initial:r,input:o}=e;return r&&r.startsWith(o)&&o!==r?(e.value=e.input=r,e.cursor=e.value.length,this.render()):super.next()}prev(){let e=this.focused;return e?e.cursor===0?super.prev():(e.value=e.input=\"\",e.cursor=0,this.render()):this.alert()}separator(){return\"\"}format(e){return this.state.submitted?\"\":super.format(e)}pointer(){return\"\"}indicator(e){return e.input?\"\\u29BF\":\"\\u2299\"}async choiceSeparator(e,r){let o=await this.resolve(e.separator,this.state,e,r)||\":\";return o?\" \"+this.styles.disabled(o):\"\"}async renderChoice(e,r){await this.onChoice(e,r);let{state:o,styles:a}=this,{cursor:n,initial:u=\"\",name:A,hint:p,input:h=\"\"}=e,{muted:E,submitted:I,primary:v,danger:x}=a,C=p,R=this.index===r,N=e.validate||(()=>!0),U=await this.choiceSeparator(e,r),V=e.message;this.align===\"right\"&&(V=V.padStart(this.longest+1,\" \")),this.align===\"left\"&&(V=V.padEnd(this.longest+1,\" \"));let te=this.values[A]=h||u,ae=h?\"success\":\"dark\";await N.call(e,te,this.state)!==!0&&(ae=\"danger\");let fe=a[ae],ue=fe(await this.indicator(e,r))+(e.pad||\"\"),me=this.indent(e),he=()=>[me,ue,V+U,h,C].filter(Boolean).join(\" \");if(o.submitted)return V=dft.unstyle(V),h=I(h),C=\"\",he();if(e.format)h=await e.format.call(this,h,e,r);else{let Be=this.styles.muted;h=yft(this,{input:h,initial:u,pos:n,showCursor:R,color:Be})}return this.isValue(h)||(h=this.styles.muted(this.symbols.ellipsis)),e.result&&(this.values[A]=await e.result.call(this,te,e,r)),R&&(V=v(V)),e.error?h+=(h?\" \":\"\")+x(e.error.trim()):e.hint&&(h+=(h?\" \":\"\")+E(e.hint.trim())),he()}async submit(){return this.value=this.values,super.base.submit.call(this)}};Uhe.exports=X_});var Z_=_((A8t,Hhe)=>{\"use strict\";var Eft=ak(),Cft=()=>{throw new Error(\"expected prompt to have a custom authenticate method\")},_he=(t=Cft)=>{class e extends Eft{constructor(o){super(o)}async submit(){this.value=await t.call(this,this.values,this.state),super.base.submit.call(this)}static create(o){return _he(o)}}return e};Hhe.exports=_he()});var jhe=_((f8t,Ghe)=>{\"use strict\";var wft=Z_();function Ift(t,e){return t.username===this.options.username&&t.password===this.options.password}var qhe=(t=Ift)=>{let e=[{name:\"username\",message:\"username\"},{name:\"password\",message:\"password\",format(o){return this.options.showPassword?o:(this.state.submitted?this.styles.primary:this.styles.muted)(this.symbols.asterisk.repeat(o.length))}}];class r extends wft.create(t){constructor(a){super({...a,choices:e})}static create(a){return qhe(a)}}return r};Ghe.exports=qhe()});var lk=_((p8t,Yhe)=>{\"use strict\";var Bft=gC(),{isPrimitive:vft,hasColor:Dft}=Lo(),$_=class extends Bft{constructor(e){super(e),this.cursorHide()}async initialize(){let e=await this.resolve(this.initial,this.state);this.input=await this.cast(e),await super.initialize()}dispatch(e){return this.isValue(e)?(this.input=e,this.submit()):this.alert()}format(e){let{styles:r,state:o}=this;return o.submitted?r.success(e):r.primary(e)}cast(e){return this.isTrue(e)}isTrue(e){return/^[ty1]/i.test(e)}isFalse(e){return/^[fn0]/i.test(e)}isValue(e){return vft(e)&&(this.isTrue(e)||this.isFalse(e))}async hint(){if(this.state.status===\"pending\"){let e=await this.element(\"hint\");return Dft(e)?e:this.styles.muted(e)}}async render(){let{input:e,size:r}=this.state,o=await this.prefix(),a=await this.separator(),n=await this.message(),u=this.styles.muted(this.default),A=[o,n,u,a].filter(Boolean).join(\" \");this.state.prompt=A;let p=await this.header(),h=this.value=this.cast(e),E=await this.format(h),I=await this.error()||await this.hint(),v=await this.footer();I&&!A.includes(I)&&(E+=\" \"+I),A+=\" \"+E,this.clear(r),this.write([p,A,v].filter(Boolean).join(`\n`)),this.restore()}set value(e){super.value=e}get value(){return this.cast(super.value)}};Yhe.exports=$_});var Khe=_((h8t,Whe)=>{\"use strict\";var Pft=lk(),e8=class extends Pft{constructor(e){super(e),this.default=this.options.default||(this.initial?\"(Y/n)\":\"(y/N)\")}};Whe.exports=e8});var Vhe=_((g8t,zhe)=>{\"use strict\";var Sft=xh(),bft=ak(),dC=bft.prototype,t8=class extends Sft{constructor(e){super({...e,multiple:!0}),this.align=[this.options.align,\"left\"].find(r=>r!=null),this.emptyError=\"\",this.values={}}dispatch(e,r){let o=this.focused,a=o.parent||{};return!o.editable&&!a.editable&&(e===\"a\"||e===\"i\")?super[e]():dC.dispatch.call(this,e,r)}append(e,r){return dC.append.call(this,e,r)}delete(e,r){return dC.delete.call(this,e,r)}space(e){return this.focused.editable?this.append(e):super.space()}number(e){return this.focused.editable?this.append(e):super.number(e)}next(){return this.focused.editable?dC.next.call(this):super.next()}prev(){return this.focused.editable?dC.prev.call(this):super.prev()}async indicator(e,r){let o=e.indicator||\"\",a=e.editable?o:super.indicator(e,r);return await this.resolve(a,this.state,e,r)||\"\"}indent(e){return e.role===\"heading\"?\"\":e.editable?\" \":\"  \"}async renderChoice(e,r){return e.indent=\"\",e.editable?dC.renderChoice.call(this,e,r):super.renderChoice(e,r)}error(){return\"\"}footer(){return this.state.error}async validate(){let e=!0;for(let r of this.choices){if(typeof r.validate!=\"function\"||r.role===\"heading\")continue;let o=r.parent?this.value[r.parent.name]:this.value;if(r.editable?o=r.value===r.name?r.initial||\"\":r.value:this.isDisabled(r)||(o=r.enabled===!0),e=await r.validate(o,this.state),e!==!0)break}return e!==!0&&(this.state.error=typeof e==\"string\"?e:\"Invalid Input\"),e}submit(){if(this.focused.newChoice===!0)return super.submit();if(this.choices.some(e=>e.newChoice))return this.alert();this.value={};for(let e of this.choices){let r=e.parent?this.value[e.parent.name]:this.value;if(e.role===\"heading\"){this.value[e.name]={};continue}e.editable?r[e.name]=e.value===e.name?e.initial||\"\":e.value:this.isDisabled(e)||(r[e.name]=e.enabled===!0)}return this.base.submit.call(this)}};zhe.exports=t8});var Kd=_((d8t,Jhe)=>{\"use strict\";var xft=gC(),kft=J_(),{isPrimitive:Qft}=Lo(),r8=class extends xft{constructor(e){super(e),this.initial=Qft(this.initial)?String(this.initial):\"\",this.initial&&this.cursorHide(),this.state.prevCursor=0,this.state.clipboard=[]}async keypress(e,r={}){let o=this.state.prevKeypress;return this.state.prevKeypress=r,this.options.multiline===!0&&r.name===\"return\"&&(!o||o.name!==\"return\")?this.append(`\n`,r):super.keypress(e,r)}moveCursor(e){this.cursor+=e}reset(){return this.input=this.value=\"\",this.cursor=0,this.render()}dispatch(e,r){if(!e||r.ctrl||r.code)return this.alert();this.append(e)}append(e){let{cursor:r,input:o}=this.state;this.input=`${o}`.slice(0,r)+e+`${o}`.slice(r),this.moveCursor(String(e).length),this.render()}insert(e){this.append(e)}delete(){let{cursor:e,input:r}=this.state;if(e<=0)return this.alert();this.input=`${r}`.slice(0,e-1)+`${r}`.slice(e),this.moveCursor(-1),this.render()}deleteForward(){let{cursor:e,input:r}=this.state;if(r[e]===void 0)return this.alert();this.input=`${r}`.slice(0,e)+`${r}`.slice(e+1),this.render()}cutForward(){let e=this.cursor;if(this.input.length<=e)return this.alert();this.state.clipboard.push(this.input.slice(e)),this.input=this.input.slice(0,e),this.render()}cutLeft(){let e=this.cursor;if(e===0)return this.alert();let r=this.input.slice(0,e),o=this.input.slice(e),a=r.split(\" \");this.state.clipboard.push(a.pop()),this.input=a.join(\" \"),this.cursor=this.input.length,this.input+=o,this.render()}paste(){if(!this.state.clipboard.length)return this.alert();this.insert(this.state.clipboard.pop()),this.render()}toggleCursor(){this.state.prevCursor?(this.cursor=this.state.prevCursor,this.state.prevCursor=0):(this.state.prevCursor=this.cursor,this.cursor=0),this.render()}first(){this.cursor=0,this.render()}last(){this.cursor=this.input.length-1,this.render()}next(){let e=this.initial!=null?String(this.initial):\"\";if(!e||!e.startsWith(this.input))return this.alert();this.input=this.initial,this.cursor=this.initial.length,this.render()}prev(){if(!this.input)return this.alert();this.reset()}backward(){return this.left()}forward(){return this.right()}right(){return this.cursor>=this.input.length?this.alert():(this.moveCursor(1),this.render())}left(){return this.cursor<=0?this.alert():(this.moveCursor(-1),this.render())}isValue(e){return!!e}async format(e=this.value){let r=await this.resolve(this.initial,this.state);return this.state.submitted?this.styles.submitted(e||r):kft(this,{input:e,initial:r,pos:this.cursor})}async render(){let e=this.state.size,r=await this.prefix(),o=await this.separator(),a=await this.message(),n=[r,a,o].filter(Boolean).join(\" \");this.state.prompt=n;let u=await this.header(),A=await this.format(),p=await this.error()||await this.hint(),h=await this.footer();p&&!A.includes(p)&&(A+=\" \"+p),n+=\" \"+A,this.clear(e),this.write([u,n,h].filter(Boolean).join(`\n`)),this.restore()}};Jhe.exports=r8});var Zhe=_((m8t,Xhe)=>{\"use strict\";var Fft=t=>t.filter((e,r)=>t.lastIndexOf(e)===r),ck=t=>Fft(t).filter(Boolean);Xhe.exports=(t,e={},r=\"\")=>{let{past:o=[],present:a=\"\"}=e,n,u;switch(t){case\"prev\":case\"undo\":return n=o.slice(0,o.length-1),u=o[o.length-1]||\"\",{past:ck([r,...n]),present:u};case\"next\":case\"redo\":return n=o.slice(1),u=o[0]||\"\",{past:ck([...n,r]),present:u};case\"save\":return{past:ck([...o,r]),present:\"\"};case\"remove\":return u=ck(o.filter(A=>A!==r)),a=\"\",u.length&&(a=u.pop()),{past:u,present:a};default:throw new Error(`Invalid action: \"${t}\"`)}}});var i8=_((y8t,e0e)=>{\"use strict\";var Rft=Kd(),$he=Zhe(),n8=class extends Rft{constructor(e){super(e);let r=this.options.history;if(r&&r.store){let o=r.values||this.initial;this.autosave=!!r.autosave,this.store=r.store,this.data=this.store.get(\"values\")||{past:[],present:o},this.initial=this.data.present||this.data.past[this.data.past.length-1]}}completion(e){return this.store?(this.data=$he(e,this.data,this.input),this.data.present?(this.input=this.data.present,this.cursor=this.input.length,this.render()):this.alert()):this.alert()}altUp(){return this.completion(\"prev\")}altDown(){return this.completion(\"next\")}prev(){return this.save(),super.prev()}save(){!this.store||(this.data=$he(\"save\",this.data,this.input),this.store.set(\"values\",this.data))}submit(){return this.store&&this.autosave===!0&&this.save(),super.submit()}};e0e.exports=n8});var r0e=_((E8t,t0e)=>{\"use strict\";var Tft=Kd(),s8=class extends Tft{format(){return\"\"}};t0e.exports=s8});var i0e=_((C8t,n0e)=>{\"use strict\";var Lft=Kd(),o8=class extends Lft{constructor(e={}){super(e),this.sep=this.options.separator||/, */,this.initial=e.initial||\"\"}split(e=this.value){return e?String(e).split(this.sep):[]}format(){let e=this.state.submitted?this.styles.primary:r=>r;return this.list.map(e).join(\", \")}async submit(e){let r=this.state.error||await this.validate(this.list,this.state);return r!==!0?(this.state.error=r,super.submit()):(this.value=this.list,super.submit())}get list(){return this.split()}};n0e.exports=o8});var o0e=_((w8t,s0e)=>{\"use strict\";var Nft=xh(),a8=class extends Nft{constructor(e){super({...e,multiple:!0})}};s0e.exports=a8});var c8=_((I8t,a0e)=>{\"use strict\";var Oft=Kd(),l8=class extends Oft{constructor(e={}){super({style:\"number\",...e}),this.min=this.isValue(e.min)?this.toNumber(e.min):-1/0,this.max=this.isValue(e.max)?this.toNumber(e.max):1/0,this.delay=e.delay!=null?e.delay:1e3,this.float=e.float!==!1,this.round=e.round===!0||e.float===!1,this.major=e.major||10,this.minor=e.minor||1,this.initial=e.initial!=null?e.initial:\"\",this.input=String(this.initial),this.cursor=this.input.length,this.cursorShow()}append(e){return!/[-+.]/.test(e)||e===\".\"&&this.input.includes(\".\")?this.alert(\"invalid number\"):super.append(e)}number(e){return super.append(e)}next(){return this.input&&this.input!==this.initial?this.alert():this.isValue(this.initial)?(this.input=this.initial,this.cursor=String(this.initial).length,this.render()):this.alert()}up(e){let r=e||this.minor,o=this.toNumber(this.input);return o>this.max+r?this.alert():(this.input=`${o+r}`,this.render())}down(e){let r=e||this.minor,o=this.toNumber(this.input);return o<this.min-r?this.alert():(this.input=`${o-r}`,this.render())}shiftDown(){return this.down(this.major)}shiftUp(){return this.up(this.major)}format(e=this.input){return typeof this.options.format==\"function\"?this.options.format.call(this,e):this.styles.info(e)}toNumber(e=\"\"){return this.float?+e:Math.round(+e)}isValue(e){return/^[-+]?[0-9]+((\\.)|(\\.[0-9]+))?$/.test(e)}submit(){let e=[this.input,this.initial].find(r=>this.isValue(r));return this.value=this.toNumber(e||0),super.submit()}};a0e.exports=l8});var c0e=_((B8t,l0e)=>{l0e.exports=c8()});var A0e=_((v8t,u0e)=>{\"use strict\";var Mft=Kd(),u8=class extends Mft{constructor(e){super(e),this.cursorShow()}format(e=this.input){return this.keypressed?(this.state.submitted?this.styles.primary:this.styles.muted)(this.symbols.asterisk.repeat(e.length)):\"\"}};u0e.exports=u8});var h0e=_((D8t,p0e)=>{\"use strict\";var Uft=zc(),_ft=u2(),f0e=Lo(),A8=class extends _ft{constructor(e={}){super(e),this.widths=[].concat(e.messageWidth||50),this.align=[].concat(e.align||\"left\"),this.linebreak=e.linebreak||!1,this.edgeLength=e.edgeLength||3,this.newline=e.newline||`\n   `;let r=e.startNumber||1;typeof this.scale==\"number\"&&(this.scaleKey=!1,this.scale=Array(this.scale).fill(0).map((o,a)=>({name:a+r})))}async reset(){return this.tableized=!1,await super.reset(),this.render()}tableize(){if(this.tableized===!0)return;this.tableized=!0;let e=0;for(let r of this.choices){e=Math.max(e,r.message.length),r.scaleIndex=r.initial||2,r.scale=[];for(let o=0;o<this.scale.length;o++)r.scale.push({index:o})}this.widths[0]=Math.min(this.widths[0],e+3)}async dispatch(e,r){if(this.multiple)return this[r.name]?await this[r.name](e,r):await super.dispatch(e,r);this.alert()}heading(e,r,o){return this.styles.strong(e)}separator(){return this.styles.muted(this.symbols.ellipsis)}right(){let e=this.focused;return e.scaleIndex>=this.scale.length-1?this.alert():(e.scaleIndex++,this.render())}left(){let e=this.focused;return e.scaleIndex<=0?this.alert():(e.scaleIndex--,this.render())}indent(){return\"\"}format(){return this.state.submitted?this.choices.map(r=>this.styles.info(r.index)).join(\", \"):\"\"}pointer(){return\"\"}renderScaleKey(){return this.scaleKey===!1||this.state.submitted?\"\":[\"\",...this.scale.map(o=>`   ${o.name} - ${o.message}`)].map(o=>this.styles.muted(o)).join(`\n`)}renderScaleHeading(e){let r=this.scale.map(p=>p.name);typeof this.options.renderScaleHeading==\"function\"&&(r=this.options.renderScaleHeading.call(this,e));let o=this.scaleLength-r.join(\"\").length,a=Math.round(o/(r.length-1)),u=r.map(p=>this.styles.strong(p)).join(\" \".repeat(a)),A=\" \".repeat(this.widths[0]);return this.margin[3]+A+this.margin[1]+u}scaleIndicator(e,r,o){if(typeof this.options.scaleIndicator==\"function\")return this.options.scaleIndicator.call(this,e,r,o);let a=e.scaleIndex===r.index;return r.disabled?this.styles.hint(this.symbols.radio.disabled):a?this.styles.success(this.symbols.radio.on):this.symbols.radio.off}renderScale(e,r){let o=e.scale.map(n=>this.scaleIndicator(e,n,r)),a=this.term===\"Hyper\"?\"\":\" \";return o.join(a+this.symbols.line.repeat(this.edgeLength))}async renderChoice(e,r){await this.onChoice(e,r);let o=this.index===r,a=await this.pointer(e,r),n=await e.hint;n&&!f0e.hasColor(n)&&(n=this.styles.muted(n));let u=C=>this.margin[3]+C.replace(/\\s+$/,\"\").padEnd(this.widths[0],\" \"),A=this.newline,p=this.indent(e),h=await this.resolve(e.message,this.state,e,r),E=await this.renderScale(e,r),I=this.margin[1]+this.margin[3];this.scaleLength=Uft.unstyle(E).length,this.widths[0]=Math.min(this.widths[0],this.width-this.scaleLength-I.length);let x=f0e.wordWrap(h,{width:this.widths[0],newline:A}).split(`\n`).map(C=>u(C)+this.margin[1]);return o&&(E=this.styles.info(E),x=x.map(C=>this.styles.info(C))),x[0]+=E,this.linebreak&&x.push(\"\"),[p+a,x.join(`\n`)].filter(Boolean)}async renderChoices(){if(this.state.submitted)return\"\";this.tableize();let e=this.visible.map(async(a,n)=>await this.renderChoice(a,n)),r=await Promise.all(e),o=await this.renderScaleHeading();return this.margin[0]+[o,...r.map(a=>a.join(\" \"))].join(`\n`)}async render(){let{submitted:e,size:r}=this.state,o=await this.prefix(),a=await this.separator(),n=await this.message(),u=\"\";this.options.promptLine!==!1&&(u=[o,n,a,\"\"].join(\" \"),this.state.prompt=u);let A=await this.header(),p=await this.format(),h=await this.renderScaleKey(),E=await this.error()||await this.hint(),I=await this.renderChoices(),v=await this.footer(),x=this.emptyError;p&&(u+=p),E&&!u.includes(E)&&(u+=\" \"+E),e&&!p&&!I.trim()&&this.multiple&&x!=null&&(u+=this.styles.danger(x)),this.clear(r),this.write([A,u,h,I,v].filter(Boolean).join(`\n`)),this.state.submitted||this.write(this.margin[2]),this.restore()}submit(){this.value={};for(let e of this.choices)this.value[e.name]=e.scaleIndex;return this.base.submit.call(this)}};p0e.exports=A8});var m0e=_((P8t,d0e)=>{\"use strict\";var g0e=zc(),Hft=(t=\"\")=>typeof t==\"string\"?t.replace(/^['\"]|['\"]$/g,\"\"):\"\",p8=class{constructor(e){this.name=e.key,this.field=e.field||{},this.value=Hft(e.initial||this.field.initial||\"\"),this.message=e.message||this.name,this.cursor=0,this.input=\"\",this.lines=[]}},qft=async(t={},e={},r=o=>o)=>{let o=new Set,a=t.fields||[],n=t.template,u=[],A=[],p=[],h=1;typeof n==\"function\"&&(n=await n());let E=-1,I=()=>n[++E],v=()=>n[E+1],x=C=>{C.line=h,u.push(C)};for(x({type:\"bos\",value:\"\"});E<n.length-1;){let C=I();if(/^[^\\S\\n ]$/.test(C)){x({type:\"text\",value:C});continue}if(C===`\n`){x({type:\"newline\",value:C}),h++;continue}if(C===\"\\\\\"){C+=I(),x({type:\"text\",value:C});continue}if((C===\"$\"||C===\"#\"||C===\"{\")&&v()===\"{\"){let N=I();C+=N;let U={type:\"template\",open:C,inner:\"\",close:\"\",value:C},V;for(;V=I();){if(V===\"}\"){v()===\"}\"&&(V+=I()),U.value+=V,U.close=V;break}V===\":\"?(U.initial=\"\",U.key=U.inner):U.initial!==void 0&&(U.initial+=V),U.value+=V,U.inner+=V}U.template=U.open+(U.initial||U.inner)+U.close,U.key=U.key||U.inner,e.hasOwnProperty(U.key)&&(U.initial=e[U.key]),U=r(U),x(U),p.push(U.key),o.add(U.key);let te=A.find(ae=>ae.name===U.key);U.field=a.find(ae=>ae.name===U.key),te||(te=new p8(U),A.push(te)),te.lines.push(U.line-1);continue}let R=u[u.length-1];R.type===\"text\"&&R.line===h?R.value+=C:x({type:\"text\",value:C})}return x({type:\"eos\",value:\"\"}),{input:n,tabstops:u,unique:o,keys:p,items:A}};d0e.exports=async t=>{let e=t.options,r=new Set(e.required===!0?[]:e.required||[]),o={...e.values,...e.initial},{tabstops:a,items:n,keys:u}=await qft(e,o),A=f8(\"result\",t,e),p=f8(\"format\",t,e),h=f8(\"validate\",t,e,!0),E=t.isValue.bind(t);return async(I={},v=!1)=>{let x=0;I.required=r,I.items=n,I.keys=u,I.output=\"\";let C=async(V,te,ae,fe)=>{let ue=await h(V,te,ae,fe);return ue===!1?\"Invalid field \"+ae.name:ue};for(let V of a){let te=V.value,ae=V.key;if(V.type!==\"template\"){te&&(I.output+=te);continue}if(V.type===\"template\"){let fe=n.find(we=>we.name===ae);e.required===!0&&I.required.add(fe.name);let ue=[fe.input,I.values[fe.value],fe.value,te].find(E),he=(fe.field||{}).message||V.inner;if(v){let we=await C(I.values[ae],I,fe,x);if(we&&typeof we==\"string\"||we===!1){I.invalid.set(ae,we);continue}I.invalid.delete(ae);let g=await A(I.values[ae],I,fe,x);I.output+=g0e.unstyle(g);continue}fe.placeholder=!1;let Be=te;te=await p(te,I,fe,x),ue!==te?(I.values[ae]=ue,te=t.styles.typing(ue),I.missing.delete(he)):(I.values[ae]=void 0,ue=`<${he}>`,te=t.styles.primary(ue),fe.placeholder=!0,I.required.has(ae)&&I.missing.add(he)),I.missing.has(he)&&I.validating&&(te=t.styles.warning(ue)),I.invalid.has(ae)&&I.validating&&(te=t.styles.danger(ue)),x===I.index&&(Be!==te?te=t.styles.underline(te):te=t.styles.heading(g0e.unstyle(te))),x++}te&&(I.output+=te)}let R=I.output.split(`\n`).map(V=>\" \"+V),N=n.length,U=0;for(let V of n)I.invalid.has(V.name)&&V.lines.forEach(te=>{R[te][0]===\" \"&&(R[te]=I.styles.danger(I.symbols.bullet)+R[te].slice(1))}),t.isValue(I.values[V.name])&&U++;return I.completed=(U/N*100).toFixed(0),I.output=R.join(`\n`),I.output}};function f8(t,e,r,o){return(a,n,u,A)=>typeof u.field[t]==\"function\"?u.field[t].call(e,a,n,u,A):[o,a].find(p=>e.isValue(p))}});var E0e=_((S8t,y0e)=>{\"use strict\";var Gft=zc(),jft=m0e(),Yft=gC(),h8=class extends Yft{constructor(e){super(e),this.cursorHide(),this.reset(!0)}async initialize(){this.interpolate=await jft(this),await super.initialize()}async reset(e){this.state.keys=[],this.state.invalid=new Map,this.state.missing=new Set,this.state.completed=0,this.state.values={},e!==!0&&(await this.initialize(),await this.render())}moveCursor(e){let r=this.getItem();this.cursor+=e,r.cursor+=e}dispatch(e,r){if(!r.code&&!r.ctrl&&e!=null&&this.getItem()){this.append(e,r);return}this.alert()}append(e,r){let o=this.getItem(),a=o.input.slice(0,this.cursor),n=o.input.slice(this.cursor);this.input=o.input=`${a}${e}${n}`,this.moveCursor(1),this.render()}delete(){let e=this.getItem();if(this.cursor<=0||!e.input)return this.alert();let r=e.input.slice(this.cursor),o=e.input.slice(0,this.cursor-1);this.input=e.input=`${o}${r}`,this.moveCursor(-1),this.render()}increment(e){return e>=this.state.keys.length-1?0:e+1}decrement(e){return e<=0?this.state.keys.length-1:e-1}first(){this.state.index=0,this.render()}last(){this.state.index=this.state.keys.length-1,this.render()}right(){if(this.cursor>=this.input.length)return this.alert();this.moveCursor(1),this.render()}left(){if(this.cursor<=0)return this.alert();this.moveCursor(-1),this.render()}prev(){this.state.index=this.decrement(this.state.index),this.getItem(),this.render()}next(){this.state.index=this.increment(this.state.index),this.getItem(),this.render()}up(){this.prev()}down(){this.next()}format(e){let r=this.state.completed<100?this.styles.warning:this.styles.success;return this.state.submitted===!0&&this.state.completed!==100&&(r=this.styles.danger),r(`${this.state.completed}% completed`)}async render(){let{index:e,keys:r=[],submitted:o,size:a}=this.state,n=[this.options.newline,`\n`].find(V=>V!=null),u=await this.prefix(),A=await this.separator(),p=await this.message(),h=[u,p,A].filter(Boolean).join(\" \");this.state.prompt=h;let E=await this.header(),I=await this.error()||\"\",v=await this.hint()||\"\",x=o?\"\":await this.interpolate(this.state),C=this.state.key=r[e]||\"\",R=await this.format(C),N=await this.footer();R&&(h+=\" \"+R),v&&!R&&this.state.completed===0&&(h+=\" \"+v),this.clear(a);let U=[E,h,x,N,I.trim()];this.write(U.filter(Boolean).join(n)),this.restore()}getItem(e){let{items:r,keys:o,index:a}=this.state,n=r.find(u=>u.name===o[a]);return n&&n.input!=null&&(this.input=n.input,this.cursor=n.cursor),n}async submit(){typeof this.interpolate!=\"function\"&&await this.initialize(),await this.interpolate(this.state,!0);let{invalid:e,missing:r,output:o,values:a}=this.state;if(e.size){let A=\"\";for(let[p,h]of e)A+=`Invalid ${p}: ${h}\n`;return this.state.error=A,super.submit()}if(r.size)return this.state.error=\"Required: \"+[...r.keys()].join(\", \"),super.submit();let u=Gft.unstyle(o).split(`\n`).map(A=>A.slice(1)).join(`\n`);return this.value={values:a,result:u},super.submit()}};y0e.exports=h8});var w0e=_((b8t,C0e)=>{\"use strict\";var Wft=\"(Use <shift>+<up/down> to sort)\",Kft=xh(),g8=class extends Kft{constructor(e){super({...e,reorder:!1,sort:!0,multiple:!0}),this.state.hint=[this.options.hint,Wft].find(this.isValue.bind(this))}indicator(){return\"\"}async renderChoice(e,r){let o=await super.renderChoice(e,r),a=this.symbols.identicalTo+\" \",n=this.index===r&&this.sorting?this.styles.muted(a):\"  \";return this.options.drag===!1&&(n=\"\"),this.options.numbered===!0?n+`${r+1} - `+o:n+o}get selected(){return this.choices}submit(){return this.value=this.choices.map(e=>e.value),super.submit()}};C0e.exports=g8});var B0e=_((x8t,I0e)=>{\"use strict\";var zft=u2(),d8=class extends zft{constructor(e={}){if(super(e),this.emptyError=e.emptyError||\"No items were selected\",this.term=process.env.TERM_PROGRAM,!this.options.header){let r=[\"\",\"4 - Strongly Agree\",\"3 - Agree\",\"2 - Neutral\",\"1 - Disagree\",\"0 - Strongly Disagree\",\"\"];r=r.map(o=>this.styles.muted(o)),this.state.header=r.join(`\n   `)}}async toChoices(...e){if(this.createdScales)return!1;this.createdScales=!0;let r=await super.toChoices(...e);for(let o of r)o.scale=Vft(5,this.options),o.scaleIdx=2;return r}dispatch(){this.alert()}space(){let e=this.focused,r=e.scale[e.scaleIdx],o=r.selected;return e.scale.forEach(a=>a.selected=!1),r.selected=!o,this.render()}indicator(){return\"\"}pointer(){return\"\"}separator(){return this.styles.muted(this.symbols.ellipsis)}right(){let e=this.focused;return e.scaleIdx>=e.scale.length-1?this.alert():(e.scaleIdx++,this.render())}left(){let e=this.focused;return e.scaleIdx<=0?this.alert():(e.scaleIdx--,this.render())}indent(){return\"   \"}async renderChoice(e,r){await this.onChoice(e,r);let o=this.index===r,a=this.term===\"Hyper\",n=a?9:8,u=a?\"\":\" \",A=this.symbols.line.repeat(n),p=\" \".repeat(n+(a?0:1)),h=te=>(te?this.styles.success(\"\\u25C9\"):\"\\u25EF\")+u,E=r+1+\".\",I=o?this.styles.heading:this.styles.noop,v=await this.resolve(e.message,this.state,e,r),x=this.indent(e),C=x+e.scale.map((te,ae)=>h(ae===e.scaleIdx)).join(A),R=te=>te===e.scaleIdx?I(te):te,N=x+e.scale.map((te,ae)=>R(ae)).join(p),U=()=>[E,v].filter(Boolean).join(\" \"),V=()=>[U(),C,N,\" \"].filter(Boolean).join(`\n`);return o&&(C=this.styles.cyan(C),N=this.styles.cyan(N)),V()}async renderChoices(){if(this.state.submitted)return\"\";let e=this.visible.map(async(o,a)=>await this.renderChoice(o,a)),r=await Promise.all(e);return r.length||r.push(this.styles.danger(\"No matching choices\")),r.join(`\n`)}format(){return this.state.submitted?this.choices.map(r=>this.styles.info(r.scaleIdx)).join(\", \"):\"\"}async render(){let{submitted:e,size:r}=this.state,o=await this.prefix(),a=await this.separator(),n=await this.message(),u=[o,n,a].filter(Boolean).join(\" \");this.state.prompt=u;let A=await this.header(),p=await this.format(),h=await this.error()||await this.hint(),E=await this.renderChoices(),I=await this.footer();(p||!h)&&(u+=\" \"+p),h&&!u.includes(h)&&(u+=\" \"+h),e&&!p&&!E&&this.multiple&&this.type!==\"form\"&&(u+=this.styles.danger(this.emptyError)),this.clear(r),this.write([u,A,E,I].filter(Boolean).join(`\n`)),this.restore()}submit(){this.value={};for(let e of this.choices)this.value[e.name]=e.scaleIdx;return this.base.submit.call(this)}};function Vft(t,e={}){if(Array.isArray(e.scale))return e.scale.map(o=>({...o}));let r=[];for(let o=1;o<t+1;o++)r.push({i:o,selected:!1});return r}I0e.exports=d8});var D0e=_((k8t,v0e)=>{v0e.exports=i8()});var S0e=_((Q8t,P0e)=>{\"use strict\";var Jft=lk(),m8=class extends Jft{async initialize(){await super.initialize(),this.value=this.initial=!!this.options.initial,this.disabled=this.options.disabled||\"no\",this.enabled=this.options.enabled||\"yes\",await this.render()}reset(){this.value=this.initial,this.render()}delete(){this.alert()}toggle(){this.value=!this.value,this.render()}enable(){if(this.value===!0)return this.alert();this.value=!0,this.render()}disable(){if(this.value===!1)return this.alert();this.value=!1,this.render()}up(){this.toggle()}down(){this.toggle()}right(){this.toggle()}left(){this.toggle()}next(){this.toggle()}prev(){this.toggle()}dispatch(e=\"\",r){switch(e.toLowerCase()){case\" \":return this.toggle();case\"1\":case\"y\":case\"t\":return this.enable();case\"0\":case\"n\":case\"f\":return this.disable();default:return this.alert()}}format(){let e=o=>this.styles.primary.underline(o);return[this.value?this.disabled:e(this.disabled),this.value?e(this.enabled):this.enabled].join(this.styles.muted(\" / \"))}async render(){let{size:e}=this.state,r=await this.header(),o=await this.prefix(),a=await this.separator(),n=await this.message(),u=await this.format(),A=await this.error()||await this.hint(),p=await this.footer(),h=[o,n,a,u].join(\" \");this.state.prompt=h,A&&!h.includes(A)&&(h+=\" \"+A),this.clear(e),this.write([r,h,p].filter(Boolean).join(`\n`)),this.write(this.margin[2]),this.restore()}};P0e.exports=m8});var x0e=_((F8t,b0e)=>{\"use strict\";var Xft=xh(),y8=class extends Xft{constructor(e){if(super(e),typeof this.options.correctChoice!=\"number\"||this.options.correctChoice<0)throw new Error(\"Please specify the index of the correct answer from the list of choices\")}async toChoices(e,r){let o=await super.toChoices(e,r);if(o.length<2)throw new Error(\"Please give at least two choices to the user\");if(this.options.correctChoice>o.length)throw new Error(\"Please specify the index of the correct answer from the list of choices\");return o}check(e){return e.index===this.options.correctChoice}async result(e){return{selectedAnswer:e,correctAnswer:this.options.choices[this.options.correctChoice].value,correct:await this.check(this.state)}}};b0e.exports=y8});var Q0e=_(E8=>{\"use strict\";var k0e=Lo(),As=(t,e)=>{k0e.defineExport(E8,t,e),k0e.defineExport(E8,t.toLowerCase(),e)};As(\"AutoComplete\",()=>Ohe());As(\"BasicAuth\",()=>jhe());As(\"Confirm\",()=>Khe());As(\"Editable\",()=>Vhe());As(\"Form\",()=>ak());As(\"Input\",()=>i8());As(\"Invisible\",()=>r0e());As(\"List\",()=>i0e());As(\"MultiSelect\",()=>o0e());As(\"Numeral\",()=>c0e());As(\"Password\",()=>A0e());As(\"Scale\",()=>h0e());As(\"Select\",()=>xh());As(\"Snippet\",()=>E0e());As(\"Sort\",()=>w0e());As(\"Survey\",()=>B0e());As(\"Text\",()=>D0e());As(\"Toggle\",()=>S0e());As(\"Quiz\",()=>x0e())});var R0e=_((T8t,F0e)=>{F0e.exports={ArrayPrompt:u2(),AuthPrompt:Z_(),BooleanPrompt:lk(),NumberPrompt:c8(),StringPrompt:Kd()}});var f2=_((L8t,L0e)=>{\"use strict\";var T0e=ve(\"assert\"),w8=ve(\"events\"),kh=Lo(),Jc=class extends w8{constructor(e,r){super(),this.options=kh.merge({},e),this.answers={...r}}register(e,r){if(kh.isObject(e)){for(let a of Object.keys(e))this.register(a,e[a]);return this}T0e.equal(typeof r,\"function\",\"expected a function\");let o=e.toLowerCase();return r.prototype instanceof this.Prompt?this.prompts[o]=r:this.prompts[o]=r(this.Prompt,this),this}async prompt(e=[]){for(let r of[].concat(e))try{typeof r==\"function\"&&(r=await r.call(this)),await this.ask(kh.merge({},this.options,r))}catch(o){return Promise.reject(o)}return this.answers}async ask(e){typeof e==\"function\"&&(e=await e.call(this));let r=kh.merge({},this.options,e),{type:o,name:a}=e,{set:n,get:u}=kh;if(typeof o==\"function\"&&(o=await o.call(this,e,this.answers)),!o)return this.answers[a];T0e(this.prompts[o],`Prompt \"${o}\" is not registered`);let A=new this.prompts[o](r),p=u(this.answers,a);A.state.answers=this.answers,A.enquirer=this,a&&A.on(\"submit\",E=>{this.emit(\"answer\",a,E,A),n(this.answers,a,E)});let h=A.emit.bind(A);return A.emit=(...E)=>(this.emit.call(this,...E),h(...E)),this.emit(\"prompt\",A,this),r.autofill&&p!=null?(A.value=A.input=p,r.autofill===\"show\"&&await A.submit()):p=A.value=await A.run(),p}use(e){return e.call(this,this),this}set Prompt(e){this._Prompt=e}get Prompt(){return this._Prompt||this.constructor.Prompt}get prompts(){return this.constructor.prompts}static set Prompt(e){this._Prompt=e}static get Prompt(){return this._Prompt||gC()}static get prompts(){return Q0e()}static get types(){return R0e()}static get prompt(){let e=(r,...o)=>{let a=new this(...o),n=a.emit.bind(a);return a.emit=(...u)=>(e.emit(...u),n(...u)),a.prompt(r)};return kh.mixinEmitter(e,new w8),e}};kh.mixinEmitter(Jc,new w8);var C8=Jc.prompts;for(let t of Object.keys(C8)){let e=t.toLowerCase(),r=o=>new C8[t](o).run();Jc.prompt[e]=r,Jc[e]=r,Jc[t]||Reflect.defineProperty(Jc,t,{get:()=>C8[t]})}var A2=t=>{kh.defineExport(Jc,t,()=>Jc.types[t])};A2(\"ArrayPrompt\");A2(\"AuthPrompt\");A2(\"BooleanPrompt\");A2(\"NumberPrompt\");A2(\"StringPrompt\");L0e.exports=Jc});var d2=_((mHt,q0e)=>{var npt=Jx();function ipt(t,e,r){var o=t==null?void 0:npt(t,e);return o===void 0?r:o}q0e.exports=ipt});var Y0e=_((BHt,j0e)=>{function spt(t,e){for(var r=-1,o=t==null?0:t.length;++r<o&&e(t[r],r,t)!==!1;);return t}j0e.exports=spt});var K0e=_((vHt,W0e)=>{var opt=md(),apt=VP();function lpt(t,e){return t&&opt(e,apt(e),t)}W0e.exports=lpt});var V0e=_((DHt,z0e)=>{var cpt=md(),upt=jy();function Apt(t,e){return t&&cpt(e,upt(e),t)}z0e.exports=Apt});var X0e=_((PHt,J0e)=>{var fpt=md(),ppt=GP();function hpt(t,e){return fpt(t,ppt(t),e)}J0e.exports=hpt});var S8=_((SHt,Z0e)=>{var gpt=qP(),dpt=eS(),mpt=GP(),ypt=KL(),Ept=Object.getOwnPropertySymbols,Cpt=Ept?function(t){for(var e=[];t;)gpt(e,mpt(t)),t=dpt(t);return e}:ypt;Z0e.exports=Cpt});var ege=_((bHt,$0e)=>{var wpt=md(),Ipt=S8();function Bpt(t,e){return wpt(t,Ipt(t),e)}$0e.exports=Bpt});var b8=_((xHt,tge)=>{var vpt=WL(),Dpt=S8(),Ppt=jy();function Spt(t){return vpt(t,Ppt,Dpt)}tge.exports=Spt});var nge=_((kHt,rge)=>{var bpt=Object.prototype,xpt=bpt.hasOwnProperty;function kpt(t){var e=t.length,r=new t.constructor(e);return e&&typeof t[0]==\"string\"&&xpt.call(t,\"index\")&&(r.index=t.index,r.input=t.input),r}rge.exports=kpt});var sge=_((QHt,ige)=>{var Qpt=ZP();function Fpt(t,e){var r=e?Qpt(t.buffer):t.buffer;return new t.constructor(r,t.byteOffset,t.byteLength)}ige.exports=Fpt});var age=_((FHt,oge)=>{var Rpt=/\\w*$/;function Tpt(t){var e=new t.constructor(t.source,Rpt.exec(t));return e.lastIndex=t.lastIndex,e}oge.exports=Tpt});var fge=_((RHt,Age)=>{var lge=hd(),cge=lge?lge.prototype:void 0,uge=cge?cge.valueOf:void 0;function Lpt(t){return uge?Object(uge.call(t)):{}}Age.exports=Lpt});var hge=_((THt,pge)=>{var Npt=ZP(),Opt=sge(),Mpt=age(),Upt=fge(),_pt=aN(),Hpt=\"[object Boolean]\",qpt=\"[object Date]\",Gpt=\"[object Map]\",jpt=\"[object Number]\",Ypt=\"[object RegExp]\",Wpt=\"[object Set]\",Kpt=\"[object String]\",zpt=\"[object Symbol]\",Vpt=\"[object ArrayBuffer]\",Jpt=\"[object DataView]\",Xpt=\"[object Float32Array]\",Zpt=\"[object Float64Array]\",$pt=\"[object Int8Array]\",eht=\"[object Int16Array]\",tht=\"[object Int32Array]\",rht=\"[object Uint8Array]\",nht=\"[object Uint8ClampedArray]\",iht=\"[object Uint16Array]\",sht=\"[object Uint32Array]\";function oht(t,e,r){var o=t.constructor;switch(e){case Vpt:return Npt(t);case Hpt:case qpt:return new o(+t);case Jpt:return Opt(t,r);case Xpt:case Zpt:case $pt:case eht:case tht:case rht:case nht:case iht:case sht:return _pt(t,r);case Gpt:return new o;case jpt:case Kpt:return new o(t);case Ypt:return Mpt(t);case Wpt:return new o;case zpt:return Upt(t)}}pge.exports=oht});var dge=_((LHt,gge)=>{var aht=jI(),lht=Ju(),cht=\"[object Map]\";function uht(t){return lht(t)&&aht(t)==cht}gge.exports=uht});var Cge=_((NHt,Ege)=>{var Aht=dge(),fht=YP(),mge=WP(),yge=mge&&mge.isMap,pht=yge?fht(yge):Aht;Ege.exports=pht});var Ige=_((OHt,wge)=>{var hht=jI(),ght=Ju(),dht=\"[object Set]\";function mht(t){return ght(t)&&hht(t)==dht}wge.exports=mht});var Pge=_((MHt,Dge)=>{var yht=Ige(),Eht=YP(),Bge=WP(),vge=Bge&&Bge.isSet,Cht=vge?Eht(vge):yht;Dge.exports=Cht});var x8=_((UHt,kge)=>{var wht=_P(),Iht=Y0e(),Bht=tS(),vht=K0e(),Dht=V0e(),Pht=oN(),Sht=$P(),bht=X0e(),xht=ege(),kht=XL(),Qht=b8(),Fht=jI(),Rht=nge(),Tht=hge(),Lht=lN(),Nht=ql(),Oht=UI(),Mht=Cge(),Uht=sl(),_ht=Pge(),Hht=VP(),qht=jy(),Ght=1,jht=2,Yht=4,Sge=\"[object Arguments]\",Wht=\"[object Array]\",Kht=\"[object Boolean]\",zht=\"[object Date]\",Vht=\"[object Error]\",bge=\"[object Function]\",Jht=\"[object GeneratorFunction]\",Xht=\"[object Map]\",Zht=\"[object Number]\",xge=\"[object Object]\",$ht=\"[object RegExp]\",e0t=\"[object Set]\",t0t=\"[object String]\",r0t=\"[object Symbol]\",n0t=\"[object WeakMap]\",i0t=\"[object ArrayBuffer]\",s0t=\"[object DataView]\",o0t=\"[object Float32Array]\",a0t=\"[object Float64Array]\",l0t=\"[object Int8Array]\",c0t=\"[object Int16Array]\",u0t=\"[object Int32Array]\",A0t=\"[object Uint8Array]\",f0t=\"[object Uint8ClampedArray]\",p0t=\"[object Uint16Array]\",h0t=\"[object Uint32Array]\",ri={};ri[Sge]=ri[Wht]=ri[i0t]=ri[s0t]=ri[Kht]=ri[zht]=ri[o0t]=ri[a0t]=ri[l0t]=ri[c0t]=ri[u0t]=ri[Xht]=ri[Zht]=ri[xge]=ri[$ht]=ri[e0t]=ri[t0t]=ri[r0t]=ri[A0t]=ri[f0t]=ri[p0t]=ri[h0t]=!0;ri[Vht]=ri[bge]=ri[n0t]=!1;function Ak(t,e,r,o,a,n){var u,A=e&Ght,p=e&jht,h=e&Yht;if(r&&(u=a?r(t,o,a,n):r(t)),u!==void 0)return u;if(!Uht(t))return t;var E=Nht(t);if(E){if(u=Rht(t),!A)return Sht(t,u)}else{var I=Fht(t),v=I==bge||I==Jht;if(Oht(t))return Pht(t,A);if(I==xge||I==Sge||v&&!a){if(u=p||v?{}:Lht(t),!A)return p?xht(t,Dht(u,t)):bht(t,vht(u,t))}else{if(!ri[I])return a?t:{};u=Tht(t,I,A)}}n||(n=new wht);var x=n.get(t);if(x)return x;n.set(t,u),_ht(t)?t.forEach(function(N){u.add(Ak(N,e,r,N,t,n))}):Mht(t)&&t.forEach(function(N,U){u.set(U,Ak(N,e,r,U,t,n))});var C=h?p?Qht:kht:p?qht:Hht,R=E?void 0:C(t);return Iht(R||t,function(N,U){R&&(U=N,N=t[U]),Bht(u,U,Ak(N,e,r,U,t,n))}),u}kge.exports=Ak});var k8=_((_Ht,Qge)=>{var g0t=x8(),d0t=1,m0t=4;function y0t(t){return g0t(t,d0t|m0t)}Qge.exports=y0t});var Q8=_((HHt,Fge)=>{var E0t=I_();function C0t(t,e,r){return t==null?t:E0t(t,e,r)}Fge.exports=C0t});var Oge=_((KHt,Nge)=>{var w0t=Object.prototype,I0t=w0t.hasOwnProperty;function B0t(t,e){return t!=null&&I0t.call(t,e)}Nge.exports=B0t});var Uge=_((zHt,Mge)=>{var v0t=Oge(),D0t=B_();function P0t(t,e){return t!=null&&D0t(t,e,v0t)}Mge.exports=P0t});var Hge=_((VHt,_ge)=>{function S0t(t){var e=t==null?0:t.length;return e?t[e-1]:void 0}_ge.exports=S0t});var Gge=_((JHt,qge)=>{var b0t=Jx(),x0t=pU();function k0t(t,e){return e.length<2?t:b0t(t,x0t(e,0,-1))}qge.exports=k0t});var R8=_((XHt,jge)=>{var Q0t=jd(),F0t=Hge(),R0t=Gge(),T0t=lC();function L0t(t,e){return e=Q0t(e,t),t=R0t(t,e),t==null||delete t[T0t(F0t(e))]}jge.exports=L0t});var T8=_((ZHt,Yge)=>{var N0t=R8();function O0t(t,e){return t==null?!0:N0t(t,e)}Yge.exports=O0t});var Jge=_((S6t,_0t)=>{_0t.exports={name:\"@yarnpkg/cli\",version:\"4.2.2\",license:\"BSD-2-Clause\",main:\"./sources/index.ts\",exports:{\".\":\"./sources/index.ts\",\"./polyfills\":\"./sources/polyfills.ts\",\"./package.json\":\"./package.json\"},dependencies:{\"@yarnpkg/core\":\"workspace:^\",\"@yarnpkg/fslib\":\"workspace:^\",\"@yarnpkg/libzip\":\"workspace:^\",\"@yarnpkg/parsers\":\"workspace:^\",\"@yarnpkg/plugin-compat\":\"workspace:^\",\"@yarnpkg/plugin-constraints\":\"workspace:^\",\"@yarnpkg/plugin-dlx\":\"workspace:^\",\"@yarnpkg/plugin-essentials\":\"workspace:^\",\"@yarnpkg/plugin-exec\":\"workspace:^\",\"@yarnpkg/plugin-file\":\"workspace:^\",\"@yarnpkg/plugin-git\":\"workspace:^\",\"@yarnpkg/plugin-github\":\"workspace:^\",\"@yarnpkg/plugin-http\":\"workspace:^\",\"@yarnpkg/plugin-init\":\"workspace:^\",\"@yarnpkg/plugin-interactive-tools\":\"workspace:^\",\"@yarnpkg/plugin-link\":\"workspace:^\",\"@yarnpkg/plugin-nm\":\"workspace:^\",\"@yarnpkg/plugin-npm\":\"workspace:^\",\"@yarnpkg/plugin-npm-cli\":\"workspace:^\",\"@yarnpkg/plugin-pack\":\"workspace:^\",\"@yarnpkg/plugin-patch\":\"workspace:^\",\"@yarnpkg/plugin-pnp\":\"workspace:^\",\"@yarnpkg/plugin-pnpm\":\"workspace:^\",\"@yarnpkg/plugin-stage\":\"workspace:^\",\"@yarnpkg/plugin-typescript\":\"workspace:^\",\"@yarnpkg/plugin-version\":\"workspace:^\",\"@yarnpkg/plugin-workspace-tools\":\"workspace:^\",\"@yarnpkg/shell\":\"workspace:^\",\"ci-info\":\"^3.2.0\",clipanion:\"^4.0.0-rc.2\",semver:\"^7.1.2\",tslib:\"^2.4.0\",typanion:\"^3.14.0\"},devDependencies:{\"@types/semver\":\"^7.1.0\",\"@yarnpkg/builder\":\"workspace:^\",\"@yarnpkg/monorepo\":\"workspace:^\",\"@yarnpkg/pnpify\":\"workspace:^\"},peerDependencies:{\"@yarnpkg/core\":\"workspace:^\"},scripts:{postpack:\"rm -rf lib\",prepack:'run build:compile \"$(pwd)\"',\"build:cli+hook\":\"run build:pnp:hook && builder build bundle\",\"build:cli\":\"builder build bundle\",\"run:cli\":\"builder run\",\"update-local\":\"run build:cli --no-git-hash && rsync -a --delete bundles/ bin/\"},publishConfig:{main:\"./lib/index.js\",bin:null,exports:{\".\":\"./lib/index.js\",\"./package.json\":\"./package.json\"}},files:[\"/lib/**/*\",\"!/lib/pluginConfiguration.*\",\"!/lib/cli.*\"],\"@yarnpkg/builder\":{bundles:{standard:[\"@yarnpkg/plugin-essentials\",\"@yarnpkg/plugin-compat\",\"@yarnpkg/plugin-constraints\",\"@yarnpkg/plugin-dlx\",\"@yarnpkg/plugin-exec\",\"@yarnpkg/plugin-file\",\"@yarnpkg/plugin-git\",\"@yarnpkg/plugin-github\",\"@yarnpkg/plugin-http\",\"@yarnpkg/plugin-init\",\"@yarnpkg/plugin-interactive-tools\",\"@yarnpkg/plugin-link\",\"@yarnpkg/plugin-nm\",\"@yarnpkg/plugin-npm\",\"@yarnpkg/plugin-npm-cli\",\"@yarnpkg/plugin-pack\",\"@yarnpkg/plugin-patch\",\"@yarnpkg/plugin-pnp\",\"@yarnpkg/plugin-pnpm\",\"@yarnpkg/plugin-stage\",\"@yarnpkg/plugin-typescript\",\"@yarnpkg/plugin-version\",\"@yarnpkg/plugin-workspace-tools\"]}},repository:{type:\"git\",url:\"ssh://git@github.com/yarnpkg/berry.git\",directory:\"packages/yarnpkg-cli\"},engines:{node:\">=18.12.0\"}}});var G8=_((i9t,lde)=>{\"use strict\";lde.exports=function(e,r){r===!0&&(r=0);var o=\"\";if(typeof e==\"string\")try{o=new URL(e).protocol}catch{}else e&&e.constructor===URL&&(o=e.protocol);var a=o.split(/\\:|\\+/).filter(Boolean);return typeof r==\"number\"?a[r]:a}});var ude=_((s9t,cde)=>{\"use strict\";var sgt=G8();function ogt(t){var e={protocols:[],protocol:null,port:null,resource:\"\",host:\"\",user:\"\",password:\"\",pathname:\"\",hash:\"\",search:\"\",href:t,query:{},parse_failed:!1};try{var r=new URL(t);e.protocols=sgt(r),e.protocol=e.protocols[0],e.port=r.port,e.resource=r.hostname,e.host=r.host,e.user=r.username||\"\",e.password=r.password||\"\",e.pathname=r.pathname,e.hash=r.hash.slice(1),e.search=r.search.slice(1),e.href=r.href,e.query=Object.fromEntries(r.searchParams)}catch{e.protocols=[\"file\"],e.protocol=e.protocols[0],e.port=\"\",e.resource=\"\",e.user=\"\",e.pathname=\"\",e.hash=\"\",e.search=\"\",e.href=t,e.query={},e.parse_failed=!0}return e}cde.exports=ogt});var pde=_((o9t,fde)=>{\"use strict\";var agt=ude();function lgt(t){return t&&typeof t==\"object\"&&\"default\"in t?t:{default:t}}var cgt=lgt(agt),ugt=\"text/plain\",Agt=\"us-ascii\",Ade=(t,e)=>e.some(r=>r instanceof RegExp?r.test(t):r===t),fgt=(t,{stripHash:e})=>{let r=/^data:(?<type>[^,]*?),(?<data>[^#]*?)(?:#(?<hash>.*))?$/.exec(t);if(!r)throw new Error(`Invalid URL: ${t}`);let{type:o,data:a,hash:n}=r.groups,u=o.split(\";\");n=e?\"\":n;let A=!1;u[u.length-1]===\"base64\"&&(u.pop(),A=!0);let p=(u.shift()||\"\").toLowerCase(),E=[...u.map(I=>{let[v,x=\"\"]=I.split(\"=\").map(C=>C.trim());return v===\"charset\"&&(x=x.toLowerCase(),x===Agt)?\"\":`${v}${x?`=${x}`:\"\"}`}).filter(Boolean)];return A&&E.push(\"base64\"),(E.length>0||p&&p!==ugt)&&E.unshift(p),`data:${E.join(\";\")},${A?a.trim():a}${n?`#${n}`:\"\"}`};function pgt(t,e){if(e={defaultProtocol:\"http:\",normalizeProtocol:!0,forceHttp:!1,forceHttps:!1,stripAuthentication:!0,stripHash:!1,stripTextFragment:!0,stripWWW:!0,removeQueryParameters:[/^utm_\\w+/i],removeTrailingSlash:!0,removeSingleSlash:!0,removeDirectoryIndex:!1,sortQueryParameters:!0,...e},t=t.trim(),/^data:/i.test(t))return fgt(t,e);if(/^view-source:/i.test(t))throw new Error(\"`view-source:` is not supported as it is a non-standard protocol\");let r=t.startsWith(\"//\");!r&&/^\\.*\\//.test(t)||(t=t.replace(/^(?!(?:\\w+:)?\\/\\/)|^\\/\\//,e.defaultProtocol));let a=new URL(t);if(e.forceHttp&&e.forceHttps)throw new Error(\"The `forceHttp` and `forceHttps` options cannot be used together\");if(e.forceHttp&&a.protocol===\"https:\"&&(a.protocol=\"http:\"),e.forceHttps&&a.protocol===\"http:\"&&(a.protocol=\"https:\"),e.stripAuthentication&&(a.username=\"\",a.password=\"\"),e.stripHash?a.hash=\"\":e.stripTextFragment&&(a.hash=a.hash.replace(/#?:~:text.*?$/i,\"\")),a.pathname){let u=/\\b[a-z][a-z\\d+\\-.]{1,50}:\\/\\//g,A=0,p=\"\";for(;;){let E=u.exec(a.pathname);if(!E)break;let I=E[0],v=E.index,x=a.pathname.slice(A,v);p+=x.replace(/\\/{2,}/g,\"/\"),p+=I,A=v+I.length}let h=a.pathname.slice(A,a.pathname.length);p+=h.replace(/\\/{2,}/g,\"/\"),a.pathname=p}if(a.pathname)try{a.pathname=decodeURI(a.pathname)}catch{}if(e.removeDirectoryIndex===!0&&(e.removeDirectoryIndex=[/^index\\.[a-z]+$/]),Array.isArray(e.removeDirectoryIndex)&&e.removeDirectoryIndex.length>0){let u=a.pathname.split(\"/\"),A=u[u.length-1];Ade(A,e.removeDirectoryIndex)&&(u=u.slice(0,-1),a.pathname=u.slice(1).join(\"/\")+\"/\")}if(a.hostname&&(a.hostname=a.hostname.replace(/\\.$/,\"\"),e.stripWWW&&/^www\\.(?!www\\.)[a-z\\-\\d]{1,63}\\.[a-z.\\-\\d]{2,63}$/.test(a.hostname)&&(a.hostname=a.hostname.replace(/^www\\./,\"\"))),Array.isArray(e.removeQueryParameters))for(let u of[...a.searchParams.keys()])Ade(u,e.removeQueryParameters)&&a.searchParams.delete(u);if(e.removeQueryParameters===!0&&(a.search=\"\"),e.sortQueryParameters){a.searchParams.sort();try{a.search=decodeURIComponent(a.search)}catch{}}e.removeTrailingSlash&&(a.pathname=a.pathname.replace(/\\/$/,\"\"));let n=t;return t=a.toString(),!e.removeSingleSlash&&a.pathname===\"/\"&&!n.endsWith(\"/\")&&a.hash===\"\"&&(t=t.replace(/\\/$/,\"\")),(e.removeTrailingSlash||a.pathname===\"/\")&&a.hash===\"\"&&e.removeSingleSlash&&(t=t.replace(/\\/$/,\"\")),r&&!e.normalizeProtocol&&(t=t.replace(/^http:\\/\\//,\"//\")),e.stripProtocol&&(t=t.replace(/^(?:https?:)?\\/\\//,\"\")),t}var j8=(t,e=!1)=>{let r=/^(?:([a-z_][a-z0-9_-]{0,31})@|https?:\\/\\/)([\\w\\.\\-@]+)[\\/:]([\\~,\\.\\w,\\-,\\_,\\/]+?(?:\\.git|\\/)?)$/,o=n=>{let u=new Error(n);throw u.subject_url=t,u};(typeof t!=\"string\"||!t.trim())&&o(\"Invalid url.\"),t.length>j8.MAX_INPUT_LENGTH&&o(\"Input exceeds maximum length. If needed, change the value of parseUrl.MAX_INPUT_LENGTH.\"),e&&(typeof e!=\"object\"&&(e={stripHash:!1}),t=pgt(t,e));let a=cgt.default(t);if(a.parse_failed){let n=a.href.match(r);n?(a.protocols=[\"ssh\"],a.protocol=\"ssh\",a.resource=n[2],a.host=n[2],a.user=n[1],a.pathname=`/${n[3]}`,a.parse_failed=!1):o(\"URL parsing failed.\")}return a};j8.MAX_INPUT_LENGTH=2048;fde.exports=j8});var dde=_((a9t,gde)=>{\"use strict\";var hgt=G8();function hde(t){if(Array.isArray(t))return t.indexOf(\"ssh\")!==-1||t.indexOf(\"rsync\")!==-1;if(typeof t!=\"string\")return!1;var e=hgt(t);if(t=t.substring(t.indexOf(\"://\")+3),hde(e))return!0;var r=new RegExp(\".([a-zA-Z\\\\d]+):(\\\\d+)/\");return!t.match(r)&&t.indexOf(\"@\")<t.indexOf(\":\")}gde.exports=hde});var Ede=_((l9t,yde)=>{\"use strict\";var ggt=pde(),mde=dde();function dgt(t){var e=ggt(t);return e.token=\"\",e.password===\"x-oauth-basic\"?e.token=e.user:e.user===\"x-token-auth\"&&(e.token=e.password),mde(e.protocols)||e.protocols.length===0&&mde(t)?e.protocol=\"ssh\":e.protocols.length?e.protocol=e.protocols[0]:(e.protocol=\"file\",e.protocols=[\"file\"]),e.href=e.href.replace(/\\/$/,\"\"),e}yde.exports=dgt});var wde=_((c9t,Cde)=>{\"use strict\";var mgt=Ede();function Y8(t){if(typeof t!=\"string\")throw new Error(\"The url must be a string.\");var e=/^([a-z\\d-]{1,39})\\/([-\\.\\w]{1,100})$/i;e.test(t)&&(t=\"https://github.com/\"+t);var r=mgt(t),o=r.resource.split(\".\"),a=null;switch(r.toString=function(N){return Y8.stringify(this,N)},r.source=o.length>2?o.slice(1-o.length).join(\".\"):r.source=r.resource,r.git_suffix=/\\.git$/.test(r.pathname),r.name=decodeURIComponent((r.pathname||r.href).replace(/(^\\/)|(\\/$)/g,\"\").replace(/\\.git$/,\"\")),r.owner=decodeURIComponent(r.user),r.source){case\"git.cloudforge.com\":r.owner=r.user,r.organization=o[0],r.source=\"cloudforge.com\";break;case\"visualstudio.com\":if(r.resource===\"vs-ssh.visualstudio.com\"){a=r.name.split(\"/\"),a.length===4&&(r.organization=a[1],r.owner=a[2],r.name=a[3],r.full_name=a[2]+\"/\"+a[3]);break}else{a=r.name.split(\"/\"),a.length===2?(r.owner=a[1],r.name=a[1],r.full_name=\"_git/\"+r.name):a.length===3?(r.name=a[2],a[0]===\"DefaultCollection\"?(r.owner=a[2],r.organization=a[0],r.full_name=r.organization+\"/_git/\"+r.name):(r.owner=a[0],r.full_name=r.owner+\"/_git/\"+r.name)):a.length===4&&(r.organization=a[0],r.owner=a[1],r.name=a[3],r.full_name=r.organization+\"/\"+r.owner+\"/_git/\"+r.name);break}case\"dev.azure.com\":case\"azure.com\":if(r.resource===\"ssh.dev.azure.com\"){a=r.name.split(\"/\"),a.length===4&&(r.organization=a[1],r.owner=a[2],r.name=a[3]);break}else{a=r.name.split(\"/\"),a.length===5?(r.organization=a[0],r.owner=a[1],r.name=a[4],r.full_name=\"_git/\"+r.name):a.length===3?(r.name=a[2],a[0]===\"DefaultCollection\"?(r.owner=a[2],r.organization=a[0],r.full_name=r.organization+\"/_git/\"+r.name):(r.owner=a[0],r.full_name=r.owner+\"/_git/\"+r.name)):a.length===4&&(r.organization=a[0],r.owner=a[1],r.name=a[3],r.full_name=r.organization+\"/\"+r.owner+\"/_git/\"+r.name),r.query&&r.query.path&&(r.filepath=r.query.path.replace(/^\\/+/g,\"\")),r.query&&r.query.version&&(r.ref=r.query.version.replace(/^GB/,\"\"));break}default:a=r.name.split(\"/\");var n=a.length-1;if(a.length>=2){var u=a.indexOf(\"-\",2),A=a.indexOf(\"blob\",2),p=a.indexOf(\"tree\",2),h=a.indexOf(\"commit\",2),E=a.indexOf(\"src\",2),I=a.indexOf(\"raw\",2),v=a.indexOf(\"edit\",2);n=u>0?u-1:A>0?A-1:p>0?p-1:h>0?h-1:E>0?E-1:I>0?I-1:v>0?v-1:n,r.owner=a.slice(0,n).join(\"/\"),r.name=a[n],h&&(r.commit=a[n+2])}r.ref=\"\",r.filepathtype=\"\",r.filepath=\"\";var x=a.length>n&&a[n+1]===\"-\"?n+1:n;a.length>x+2&&[\"raw\",\"src\",\"blob\",\"tree\",\"edit\"].indexOf(a[x+1])>=0&&(r.filepathtype=a[x+1],r.ref=a[x+2],a.length>x+3&&(r.filepath=a.slice(x+3).join(\"/\"))),r.organization=r.owner;break}r.full_name||(r.full_name=r.owner,r.name&&(r.full_name&&(r.full_name+=\"/\"),r.full_name+=r.name)),r.owner.startsWith(\"scm/\")&&(r.source=\"bitbucket-server\",r.owner=r.owner.replace(\"scm/\",\"\"),r.organization=r.owner,r.full_name=r.owner+\"/\"+r.name);var C=/(projects|users)\\/(.*?)\\/repos\\/(.*?)((\\/.*$)|$)/,R=C.exec(r.pathname);return R!=null&&(r.source=\"bitbucket-server\",R[1]===\"users\"?r.owner=\"~\"+R[2]:r.owner=R[2],r.organization=r.owner,r.name=R[3],a=R[4].split(\"/\"),a.length>1&&([\"raw\",\"browse\"].indexOf(a[1])>=0?(r.filepathtype=a[1],a.length>2&&(r.filepath=a.slice(2).join(\"/\"))):a[1]===\"commits\"&&a.length>2&&(r.commit=a[2])),r.full_name=r.owner+\"/\"+r.name,r.query.at?r.ref=r.query.at:r.ref=\"\"),r}Y8.stringify=function(t,e){e=e||(t.protocols&&t.protocols.length?t.protocols.join(\"+\"):t.protocol);var r=t.port?\":\"+t.port:\"\",o=t.user||\"git\",a=t.git_suffix?\".git\":\"\";switch(e){case\"ssh\":return r?\"ssh://\"+o+\"@\"+t.resource+r+\"/\"+t.full_name+a:o+\"@\"+t.resource+\":\"+t.full_name+a;case\"git+ssh\":case\"ssh+git\":case\"ftp\":case\"ftps\":return e+\"://\"+o+\"@\"+t.resource+r+\"/\"+t.full_name+a;case\"http\":case\"https\":var n=t.token?ygt(t):t.user&&(t.protocols.includes(\"http\")||t.protocols.includes(\"https\"))?t.user+\"@\":\"\";return e+\"://\"+n+t.resource+r+\"/\"+Egt(t)+a;default:return t.href}};function ygt(t){switch(t.source){case\"bitbucket.org\":return\"x-token-auth:\"+t.token+\"@\";default:return t.token+\"@\"}}function Egt(t){switch(t.source){case\"bitbucket-server\":return\"scm/\"+t.full_name;default:return\"\"+t.full_name}}Cde.exports=Y8});var Ode=_((q5t,Nde)=>{var kgt=Hb(),Qgt=$P(),Fgt=ql(),Rgt=pE(),Tgt=w_(),Lgt=lC(),Ngt=L1();function Ogt(t){return Fgt(t)?kgt(t,Lgt):Rgt(t)?[t]:Qgt(Tgt(Ngt(t)))}Nde.exports=Ogt});function Hgt(t,e){return e===1&&_gt.has(t[0])}function B2(t){let e=Array.isArray(t)?t:(0,_de.default)(t);return e.map((o,a)=>Mgt.test(o)?`[${o}]`:Ugt.test(o)&&!Hgt(e,a)?`.${o}`:`[${JSON.stringify(o)}]`).join(\"\").replace(/^\\./,\"\")}function qgt(t,e){let r=[];if(e.methodName!==null&&r.push(de.pretty(t,e.methodName,de.Type.CODE)),e.file!==null){let o=[];o.push(de.pretty(t,e.file,de.Type.PATH)),e.line!==null&&(o.push(de.pretty(t,e.line,de.Type.NUMBER)),e.column!==null&&o.push(de.pretty(t,e.column,de.Type.NUMBER))),r.push(`(${o.join(de.pretty(t,\":\",\"grey\"))})`)}return r.join(\" \")}function gk(t,{manifestUpdates:e,reportedErrors:r},{fix:o}={}){let a=new Map,n=new Map,u=[...r.keys()].map(A=>[A,new Map]);for(let[A,p]of[...u,...e]){let h=r.get(A)?.map(x=>({text:x,fixable:!1}))??[],E=!1,I=t.getWorkspaceByCwd(A),v=I.manifest.exportTo({});for(let[x,C]of p){if(C.size>1){let R=[...C].map(([N,U])=>{let V=de.pretty(t.configuration,N,de.Type.INSPECT),te=U.size>0?qgt(t.configuration,U.values().next().value):null;return te!==null?`\n${V} at ${te}`:`\n${V}`}).join(\"\");h.push({text:`Conflict detected in constraint targeting ${de.pretty(t.configuration,x,de.Type.CODE)}; conflicting values are:${R}`,fixable:!1})}else{let[[R]]=C,N=(0,Mde.default)(v,x);if(JSON.stringify(N)===JSON.stringify(R))continue;if(!o){let U=typeof N>\"u\"?`Missing field ${de.pretty(t.configuration,x,de.Type.CODE)}; expected ${de.pretty(t.configuration,R,de.Type.INSPECT)}`:typeof R>\"u\"?`Extraneous field ${de.pretty(t.configuration,x,de.Type.CODE)} currently set to ${de.pretty(t.configuration,N,de.Type.INSPECT)}`:`Invalid field ${de.pretty(t.configuration,x,de.Type.CODE)}; expected ${de.pretty(t.configuration,R,de.Type.INSPECT)}, found ${de.pretty(t.configuration,N,de.Type.INSPECT)}`;h.push({text:U,fixable:!0});continue}typeof R>\"u\"?(0,Hde.default)(v,x):(0,Ude.default)(v,x,R),E=!0}E&&a.set(I,v)}h.length>0&&n.set(I,h)}return{changedWorkspaces:a,remainingErrors:n}}function qde(t,{configuration:e}){let r={children:[]};for(let[o,a]of t){let n=[];for(let A of a){let p=A.text.split(/\\n/);A.fixable&&(p[0]=`${de.pretty(e,\"\\u2699\",\"gray\")} ${p[0]}`),n.push({value:de.tuple(de.Type.NO_HINT,p[0]),children:p.slice(1).map(h=>({value:de.tuple(de.Type.NO_HINT,h)}))})}let u={value:de.tuple(de.Type.LOCATOR,o.anchoredLocator),children:_e.sortMap(n,A=>A.value[1])};r.children.push(u)}return r.children=_e.sortMap(r.children,o=>o.value[1]),r}var Mde,Ude,_de,Hde,wC,Mgt,Ugt,_gt,v2=Et(()=>{Ye();Mde=$e(d2()),Ude=$e(Q8()),_de=$e(Ode()),Hde=$e(T8()),wC=class{constructor(e){this.indexedFields=e;this.items=[];this.indexes={};this.clear()}clear(){this.items=[];for(let e of this.indexedFields)this.indexes[e]=new Map}insert(e){this.items.push(e);for(let r of this.indexedFields){let o=Object.hasOwn(e,r)?e[r]:void 0;if(typeof o>\"u\")continue;_e.getArrayWithDefault(this.indexes[r],o).push(e)}return e}find(e){if(typeof e>\"u\")return this.items;let r=Object.entries(e);if(r.length===0)return this.items;let o=[],a;for(let[u,A]of r){let p=u,h=Object.hasOwn(this.indexes,p)?this.indexes[p]:void 0;if(typeof h>\"u\"){o.push([p,A]);continue}let E=new Set(h.get(A)??[]);if(E.size===0)return[];if(typeof a>\"u\")a=E;else for(let I of a)E.has(I)||a.delete(I);if(a.size===0)break}let n=[...a??[]];return o.length>0&&(n=n.filter(u=>{for(let[A,p]of o)if(!(typeof p<\"u\"?Object.hasOwn(u,A)&&u[A]===p:Object.hasOwn(u,A)===!1))return!1;return!0})),n}},Mgt=/^[0-9]+$/,Ugt=/^[a-zA-Z0-9_]+$/,_gt=new Set([\"scripts\",...Ot.allDependencies])});var Gde=_((e7t,sH)=>{var Ggt;(function(t){var e=function(){return{\"append/2\":[new t.type.Rule(new t.type.Term(\"append\",[new t.type.Var(\"X\"),new t.type.Var(\"L\")]),new t.type.Term(\"foldl\",[new t.type.Term(\"append\",[]),new t.type.Var(\"X\"),new t.type.Term(\"[]\",[]),new t.type.Var(\"L\")]))],\"append/3\":[new t.type.Rule(new t.type.Term(\"append\",[new t.type.Term(\"[]\",[]),new t.type.Var(\"X\"),new t.type.Var(\"X\")]),null),new t.type.Rule(new t.type.Term(\"append\",[new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Var(\"T\")]),new t.type.Var(\"X\"),new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Var(\"S\")])]),new t.type.Term(\"append\",[new t.type.Var(\"T\"),new t.type.Var(\"X\"),new t.type.Var(\"S\")]))],\"member/2\":[new t.type.Rule(new t.type.Term(\"member\",[new t.type.Var(\"X\"),new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"_\")])]),null),new t.type.Rule(new t.type.Term(\"member\",[new t.type.Var(\"X\"),new t.type.Term(\".\",[new t.type.Var(\"_\"),new t.type.Var(\"Xs\")])]),new t.type.Term(\"member\",[new t.type.Var(\"X\"),new t.type.Var(\"Xs\")]))],\"permutation/2\":[new t.type.Rule(new t.type.Term(\"permutation\",[new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[])]),null),new t.type.Rule(new t.type.Term(\"permutation\",[new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Var(\"T\")]),new t.type.Var(\"S\")]),new t.type.Term(\",\",[new t.type.Term(\"permutation\",[new t.type.Var(\"T\"),new t.type.Var(\"P\")]),new t.type.Term(\",\",[new t.type.Term(\"append\",[new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"P\")]),new t.type.Term(\"append\",[new t.type.Var(\"X\"),new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Var(\"Y\")]),new t.type.Var(\"S\")])])]))],\"maplist/2\":[new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"_\"),new t.type.Term(\"[]\",[])]),null),new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"Xs\")])]),new t.type.Term(\",\",[new t.type.Term(\"call\",[new t.type.Var(\"P\"),new t.type.Var(\"X\")]),new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Var(\"Xs\")])]))],\"maplist/3\":[new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"_\"),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[])]),null),new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Term(\".\",[new t.type.Var(\"A\"),new t.type.Var(\"As\")]),new t.type.Term(\".\",[new t.type.Var(\"B\"),new t.type.Var(\"Bs\")])]),new t.type.Term(\",\",[new t.type.Term(\"call\",[new t.type.Var(\"P\"),new t.type.Var(\"A\"),new t.type.Var(\"B\")]),new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Var(\"As\"),new t.type.Var(\"Bs\")])]))],\"maplist/4\":[new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"_\"),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[])]),null),new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Term(\".\",[new t.type.Var(\"A\"),new t.type.Var(\"As\")]),new t.type.Term(\".\",[new t.type.Var(\"B\"),new t.type.Var(\"Bs\")]),new t.type.Term(\".\",[new t.type.Var(\"C\"),new t.type.Var(\"Cs\")])]),new t.type.Term(\",\",[new t.type.Term(\"call\",[new t.type.Var(\"P\"),new t.type.Var(\"A\"),new t.type.Var(\"B\"),new t.type.Var(\"C\")]),new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Var(\"As\"),new t.type.Var(\"Bs\"),new t.type.Var(\"Cs\")])]))],\"maplist/5\":[new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"_\"),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[])]),null),new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Term(\".\",[new t.type.Var(\"A\"),new t.type.Var(\"As\")]),new t.type.Term(\".\",[new t.type.Var(\"B\"),new t.type.Var(\"Bs\")]),new t.type.Term(\".\",[new t.type.Var(\"C\"),new t.type.Var(\"Cs\")]),new t.type.Term(\".\",[new t.type.Var(\"D\"),new t.type.Var(\"Ds\")])]),new t.type.Term(\",\",[new t.type.Term(\"call\",[new t.type.Var(\"P\"),new t.type.Var(\"A\"),new t.type.Var(\"B\"),new t.type.Var(\"C\"),new t.type.Var(\"D\")]),new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Var(\"As\"),new t.type.Var(\"Bs\"),new t.type.Var(\"Cs\"),new t.type.Var(\"Ds\")])]))],\"maplist/6\":[new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"_\"),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[])]),null),new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Term(\".\",[new t.type.Var(\"A\"),new t.type.Var(\"As\")]),new t.type.Term(\".\",[new t.type.Var(\"B\"),new t.type.Var(\"Bs\")]),new t.type.Term(\".\",[new t.type.Var(\"C\"),new t.type.Var(\"Cs\")]),new t.type.Term(\".\",[new t.type.Var(\"D\"),new t.type.Var(\"Ds\")]),new t.type.Term(\".\",[new t.type.Var(\"E\"),new t.type.Var(\"Es\")])]),new t.type.Term(\",\",[new t.type.Term(\"call\",[new t.type.Var(\"P\"),new t.type.Var(\"A\"),new t.type.Var(\"B\"),new t.type.Var(\"C\"),new t.type.Var(\"D\"),new t.type.Var(\"E\")]),new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Var(\"As\"),new t.type.Var(\"Bs\"),new t.type.Var(\"Cs\"),new t.type.Var(\"Ds\"),new t.type.Var(\"Es\")])]))],\"maplist/7\":[new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"_\"),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[])]),null),new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Term(\".\",[new t.type.Var(\"A\"),new t.type.Var(\"As\")]),new t.type.Term(\".\",[new t.type.Var(\"B\"),new t.type.Var(\"Bs\")]),new t.type.Term(\".\",[new t.type.Var(\"C\"),new t.type.Var(\"Cs\")]),new t.type.Term(\".\",[new t.type.Var(\"D\"),new t.type.Var(\"Ds\")]),new t.type.Term(\".\",[new t.type.Var(\"E\"),new t.type.Var(\"Es\")]),new t.type.Term(\".\",[new t.type.Var(\"F\"),new t.type.Var(\"Fs\")])]),new t.type.Term(\",\",[new t.type.Term(\"call\",[new t.type.Var(\"P\"),new t.type.Var(\"A\"),new t.type.Var(\"B\"),new t.type.Var(\"C\"),new t.type.Var(\"D\"),new t.type.Var(\"E\"),new t.type.Var(\"F\")]),new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Var(\"As\"),new t.type.Var(\"Bs\"),new t.type.Var(\"Cs\"),new t.type.Var(\"Ds\"),new t.type.Var(\"Es\"),new t.type.Var(\"Fs\")])]))],\"maplist/8\":[new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"_\"),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[])]),null),new t.type.Rule(new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Term(\".\",[new t.type.Var(\"A\"),new t.type.Var(\"As\")]),new t.type.Term(\".\",[new t.type.Var(\"B\"),new t.type.Var(\"Bs\")]),new t.type.Term(\".\",[new t.type.Var(\"C\"),new t.type.Var(\"Cs\")]),new t.type.Term(\".\",[new t.type.Var(\"D\"),new t.type.Var(\"Ds\")]),new t.type.Term(\".\",[new t.type.Var(\"E\"),new t.type.Var(\"Es\")]),new t.type.Term(\".\",[new t.type.Var(\"F\"),new t.type.Var(\"Fs\")]),new t.type.Term(\".\",[new t.type.Var(\"G\"),new t.type.Var(\"Gs\")])]),new t.type.Term(\",\",[new t.type.Term(\"call\",[new t.type.Var(\"P\"),new t.type.Var(\"A\"),new t.type.Var(\"B\"),new t.type.Var(\"C\"),new t.type.Var(\"D\"),new t.type.Var(\"E\"),new t.type.Var(\"F\"),new t.type.Var(\"G\")]),new t.type.Term(\"maplist\",[new t.type.Var(\"P\"),new t.type.Var(\"As\"),new t.type.Var(\"Bs\"),new t.type.Var(\"Cs\"),new t.type.Var(\"Ds\"),new t.type.Var(\"Es\"),new t.type.Var(\"Fs\"),new t.type.Var(\"Gs\")])]))],\"include/3\":[new t.type.Rule(new t.type.Term(\"include\",[new t.type.Var(\"_\"),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[])]),null),new t.type.Rule(new t.type.Term(\"include\",[new t.type.Var(\"P\"),new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Var(\"T\")]),new t.type.Var(\"L\")]),new t.type.Term(\",\",[new t.type.Term(\"=..\",[new t.type.Var(\"P\"),new t.type.Var(\"A\")]),new t.type.Term(\",\",[new t.type.Term(\"append\",[new t.type.Var(\"A\"),new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Term(\"[]\",[])]),new t.type.Var(\"B\")]),new t.type.Term(\",\",[new t.type.Term(\"=..\",[new t.type.Var(\"F\"),new t.type.Var(\"B\")]),new t.type.Term(\",\",[new t.type.Term(\";\",[new t.type.Term(\",\",[new t.type.Term(\"call\",[new t.type.Var(\"F\")]),new t.type.Term(\",\",[new t.type.Term(\"=\",[new t.type.Var(\"L\"),new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Var(\"S\")])]),new t.type.Term(\"!\",[])])]),new t.type.Term(\"=\",[new t.type.Var(\"L\"),new t.type.Var(\"S\")])]),new t.type.Term(\"include\",[new t.type.Var(\"P\"),new t.type.Var(\"T\"),new t.type.Var(\"S\")])])])])]))],\"exclude/3\":[new t.type.Rule(new t.type.Term(\"exclude\",[new t.type.Var(\"_\"),new t.type.Term(\"[]\",[]),new t.type.Term(\"[]\",[])]),null),new t.type.Rule(new t.type.Term(\"exclude\",[new t.type.Var(\"P\"),new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Var(\"T\")]),new t.type.Var(\"S\")]),new t.type.Term(\",\",[new t.type.Term(\"exclude\",[new t.type.Var(\"P\"),new t.type.Var(\"T\"),new t.type.Var(\"E\")]),new t.type.Term(\",\",[new t.type.Term(\"=..\",[new t.type.Var(\"P\"),new t.type.Var(\"L\")]),new t.type.Term(\",\",[new t.type.Term(\"append\",[new t.type.Var(\"L\"),new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Term(\"[]\",[])]),new t.type.Var(\"Q\")]),new t.type.Term(\",\",[new t.type.Term(\"=..\",[new t.type.Var(\"R\"),new t.type.Var(\"Q\")]),new t.type.Term(\";\",[new t.type.Term(\",\",[new t.type.Term(\"call\",[new t.type.Var(\"R\")]),new t.type.Term(\",\",[new t.type.Term(\"!\",[]),new t.type.Term(\"=\",[new t.type.Var(\"S\"),new t.type.Var(\"E\")])])]),new t.type.Term(\"=\",[new t.type.Var(\"S\"),new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Var(\"E\")])])])])])])]))],\"foldl/4\":[new t.type.Rule(new t.type.Term(\"foldl\",[new t.type.Var(\"_\"),new t.type.Term(\"[]\",[]),new t.type.Var(\"I\"),new t.type.Var(\"I\")]),null),new t.type.Rule(new t.type.Term(\"foldl\",[new t.type.Var(\"P\"),new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Var(\"T\")]),new t.type.Var(\"I\"),new t.type.Var(\"R\")]),new t.type.Term(\",\",[new t.type.Term(\"=..\",[new t.type.Var(\"P\"),new t.type.Var(\"L\")]),new t.type.Term(\",\",[new t.type.Term(\"append\",[new t.type.Var(\"L\"),new t.type.Term(\".\",[new t.type.Var(\"I\"),new t.type.Term(\".\",[new t.type.Var(\"H\"),new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Term(\"[]\",[])])])]),new t.type.Var(\"L2\")]),new t.type.Term(\",\",[new t.type.Term(\"=..\",[new t.type.Var(\"P2\"),new t.type.Var(\"L2\")]),new t.type.Term(\",\",[new t.type.Term(\"call\",[new t.type.Var(\"P2\")]),new t.type.Term(\"foldl\",[new t.type.Var(\"P\"),new t.type.Var(\"T\"),new t.type.Var(\"X\"),new t.type.Var(\"R\")])])])])]))],\"select/3\":[new t.type.Rule(new t.type.Term(\"select\",[new t.type.Var(\"E\"),new t.type.Term(\".\",[new t.type.Var(\"E\"),new t.type.Var(\"Xs\")]),new t.type.Var(\"Xs\")]),null),new t.type.Rule(new t.type.Term(\"select\",[new t.type.Var(\"E\"),new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"Xs\")]),new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"Ys\")])]),new t.type.Term(\"select\",[new t.type.Var(\"E\"),new t.type.Var(\"Xs\"),new t.type.Var(\"Ys\")]))],\"sum_list/2\":[new t.type.Rule(new t.type.Term(\"sum_list\",[new t.type.Term(\"[]\",[]),new t.type.Num(0,!1)]),null),new t.type.Rule(new t.type.Term(\"sum_list\",[new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"Xs\")]),new t.type.Var(\"S\")]),new t.type.Term(\",\",[new t.type.Term(\"sum_list\",[new t.type.Var(\"Xs\"),new t.type.Var(\"Y\")]),new t.type.Term(\"is\",[new t.type.Var(\"S\"),new t.type.Term(\"+\",[new t.type.Var(\"X\"),new t.type.Var(\"Y\")])])]))],\"max_list/2\":[new t.type.Rule(new t.type.Term(\"max_list\",[new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Term(\"[]\",[])]),new t.type.Var(\"X\")]),null),new t.type.Rule(new t.type.Term(\"max_list\",[new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"Xs\")]),new t.type.Var(\"S\")]),new t.type.Term(\",\",[new t.type.Term(\"max_list\",[new t.type.Var(\"Xs\"),new t.type.Var(\"Y\")]),new t.type.Term(\";\",[new t.type.Term(\",\",[new t.type.Term(\">=\",[new t.type.Var(\"X\"),new t.type.Var(\"Y\")]),new t.type.Term(\",\",[new t.type.Term(\"=\",[new t.type.Var(\"S\"),new t.type.Var(\"X\")]),new t.type.Term(\"!\",[])])]),new t.type.Term(\"=\",[new t.type.Var(\"S\"),new t.type.Var(\"Y\")])])]))],\"min_list/2\":[new t.type.Rule(new t.type.Term(\"min_list\",[new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Term(\"[]\",[])]),new t.type.Var(\"X\")]),null),new t.type.Rule(new t.type.Term(\"min_list\",[new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"Xs\")]),new t.type.Var(\"S\")]),new t.type.Term(\",\",[new t.type.Term(\"min_list\",[new t.type.Var(\"Xs\"),new t.type.Var(\"Y\")]),new t.type.Term(\";\",[new t.type.Term(\",\",[new t.type.Term(\"=<\",[new t.type.Var(\"X\"),new t.type.Var(\"Y\")]),new t.type.Term(\",\",[new t.type.Term(\"=\",[new t.type.Var(\"S\"),new t.type.Var(\"X\")]),new t.type.Term(\"!\",[])])]),new t.type.Term(\"=\",[new t.type.Var(\"S\"),new t.type.Var(\"Y\")])])]))],\"prod_list/2\":[new t.type.Rule(new t.type.Term(\"prod_list\",[new t.type.Term(\"[]\",[]),new t.type.Num(1,!1)]),null),new t.type.Rule(new t.type.Term(\"prod_list\",[new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"Xs\")]),new t.type.Var(\"S\")]),new t.type.Term(\",\",[new t.type.Term(\"prod_list\",[new t.type.Var(\"Xs\"),new t.type.Var(\"Y\")]),new t.type.Term(\"is\",[new t.type.Var(\"S\"),new t.type.Term(\"*\",[new t.type.Var(\"X\"),new t.type.Var(\"Y\")])])]))],\"last/2\":[new t.type.Rule(new t.type.Term(\"last\",[new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Term(\"[]\",[])]),new t.type.Var(\"X\")]),null),new t.type.Rule(new t.type.Term(\"last\",[new t.type.Term(\".\",[new t.type.Var(\"_\"),new t.type.Var(\"Xs\")]),new t.type.Var(\"X\")]),new t.type.Term(\"last\",[new t.type.Var(\"Xs\"),new t.type.Var(\"X\")]))],\"prefix/2\":[new t.type.Rule(new t.type.Term(\"prefix\",[new t.type.Var(\"Part\"),new t.type.Var(\"Whole\")]),new t.type.Term(\"append\",[new t.type.Var(\"Part\"),new t.type.Var(\"_\"),new t.type.Var(\"Whole\")]))],\"nth0/3\":[new t.type.Rule(new t.type.Term(\"nth0\",[new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\")]),new t.type.Term(\";\",[new t.type.Term(\"->\",[new t.type.Term(\"var\",[new t.type.Var(\"X\")]),new t.type.Term(\"nth\",[new t.type.Num(0,!1),new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\"),new t.type.Var(\"_\")])]),new t.type.Term(\",\",[new t.type.Term(\">=\",[new t.type.Var(\"X\"),new t.type.Num(0,!1)]),new t.type.Term(\",\",[new t.type.Term(\"nth\",[new t.type.Num(0,!1),new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\"),new t.type.Var(\"_\")]),new t.type.Term(\"!\",[])])])]))],\"nth1/3\":[new t.type.Rule(new t.type.Term(\"nth1\",[new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\")]),new t.type.Term(\";\",[new t.type.Term(\"->\",[new t.type.Term(\"var\",[new t.type.Var(\"X\")]),new t.type.Term(\"nth\",[new t.type.Num(1,!1),new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\"),new t.type.Var(\"_\")])]),new t.type.Term(\",\",[new t.type.Term(\">\",[new t.type.Var(\"X\"),new t.type.Num(0,!1)]),new t.type.Term(\",\",[new t.type.Term(\"nth\",[new t.type.Num(1,!1),new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\"),new t.type.Var(\"_\")]),new t.type.Term(\"!\",[])])])]))],\"nth0/4\":[new t.type.Rule(new t.type.Term(\"nth0\",[new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\"),new t.type.Var(\"W\")]),new t.type.Term(\";\",[new t.type.Term(\"->\",[new t.type.Term(\"var\",[new t.type.Var(\"X\")]),new t.type.Term(\"nth\",[new t.type.Num(0,!1),new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\"),new t.type.Var(\"W\")])]),new t.type.Term(\",\",[new t.type.Term(\">=\",[new t.type.Var(\"X\"),new t.type.Num(0,!1)]),new t.type.Term(\",\",[new t.type.Term(\"nth\",[new t.type.Num(0,!1),new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\"),new t.type.Var(\"W\")]),new t.type.Term(\"!\",[])])])]))],\"nth1/4\":[new t.type.Rule(new t.type.Term(\"nth1\",[new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\"),new t.type.Var(\"W\")]),new t.type.Term(\";\",[new t.type.Term(\"->\",[new t.type.Term(\"var\",[new t.type.Var(\"X\")]),new t.type.Term(\"nth\",[new t.type.Num(1,!1),new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\"),new t.type.Var(\"W\")])]),new t.type.Term(\",\",[new t.type.Term(\">\",[new t.type.Var(\"X\"),new t.type.Num(0,!1)]),new t.type.Term(\",\",[new t.type.Term(\"nth\",[new t.type.Num(1,!1),new t.type.Var(\"X\"),new t.type.Var(\"Y\"),new t.type.Var(\"Z\"),new t.type.Var(\"W\")]),new t.type.Term(\"!\",[])])])]))],\"nth/5\":[new t.type.Rule(new t.type.Term(\"nth\",[new t.type.Var(\"N\"),new t.type.Var(\"N\"),new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"Xs\")]),new t.type.Var(\"X\"),new t.type.Var(\"Xs\")]),null),new t.type.Rule(new t.type.Term(\"nth\",[new t.type.Var(\"N\"),new t.type.Var(\"O\"),new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"Xs\")]),new t.type.Var(\"Y\"),new t.type.Term(\".\",[new t.type.Var(\"X\"),new t.type.Var(\"Ys\")])]),new t.type.Term(\",\",[new t.type.Term(\"is\",[new t.type.Var(\"M\"),new t.type.Term(\"+\",[new t.type.Var(\"N\"),new t.type.Num(1,!1)])]),new t.type.Term(\"nth\",[new t.type.Var(\"M\"),new t.type.Var(\"O\"),new t.type.Var(\"Xs\"),new t.type.Var(\"Y\"),new t.type.Var(\"Ys\")])]))],\"length/2\":function(o,a,n){var u=n.args[0],A=n.args[1];if(!t.type.is_variable(A)&&!t.type.is_integer(A))o.throw_error(t.error.type(\"integer\",A,n.indicator));else if(t.type.is_integer(A)&&A.value<0)o.throw_error(t.error.domain(\"not_less_than_zero\",A,n.indicator));else{var p=new t.type.Term(\"length\",[u,new t.type.Num(0,!1),A]);t.type.is_integer(A)&&(p=new t.type.Term(\",\",[p,new t.type.Term(\"!\",[])])),o.prepend([new t.type.State(a.goal.replace(p),a.substitution,a)])}},\"length/3\":[new t.type.Rule(new t.type.Term(\"length\",[new t.type.Term(\"[]\",[]),new t.type.Var(\"N\"),new t.type.Var(\"N\")]),null),new t.type.Rule(new t.type.Term(\"length\",[new t.type.Term(\".\",[new t.type.Var(\"_\"),new t.type.Var(\"X\")]),new t.type.Var(\"A\"),new t.type.Var(\"N\")]),new t.type.Term(\",\",[new t.type.Term(\"succ\",[new t.type.Var(\"A\"),new t.type.Var(\"B\")]),new t.type.Term(\"length\",[new t.type.Var(\"X\"),new t.type.Var(\"B\"),new t.type.Var(\"N\")])]))],\"replicate/3\":function(o,a,n){var u=n.args[0],A=n.args[1],p=n.args[2];if(t.type.is_variable(A))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_integer(A))o.throw_error(t.error.type(\"integer\",A,n.indicator));else if(A.value<0)o.throw_error(t.error.domain(\"not_less_than_zero\",A,n.indicator));else if(!t.type.is_variable(p)&&!t.type.is_list(p))o.throw_error(t.error.type(\"list\",p,n.indicator));else{for(var h=new t.type.Term(\"[]\"),E=0;E<A.value;E++)h=new t.type.Term(\".\",[u,h]);o.prepend([new t.type.State(a.goal.replace(new t.type.Term(\"=\",[h,p])),a.substitution,a)])}},\"sort/2\":function(o,a,n){var u=n.args[0],A=n.args[1];if(t.type.is_variable(u))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_variable(A)&&!t.type.is_fully_list(A))o.throw_error(t.error.type(\"list\",A,n.indicator));else{for(var p=[],h=u;h.indicator===\"./2\";)p.push(h.args[0]),h=h.args[1];if(t.type.is_variable(h))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_empty_list(h))o.throw_error(t.error.type(\"list\",u,n.indicator));else{for(var E=p.sort(t.compare),I=E.length-1;I>0;I--)E[I].equals(E[I-1])&&E.splice(I,1);for(var v=new t.type.Term(\"[]\"),I=E.length-1;I>=0;I--)v=new t.type.Term(\".\",[E[I],v]);o.prepend([new t.type.State(a.goal.replace(new t.type.Term(\"=\",[v,A])),a.substitution,a)])}}},\"msort/2\":function(o,a,n){var u=n.args[0],A=n.args[1];if(t.type.is_variable(u))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_variable(A)&&!t.type.is_fully_list(A))o.throw_error(t.error.type(\"list\",A,n.indicator));else{for(var p=[],h=u;h.indicator===\"./2\";)p.push(h.args[0]),h=h.args[1];if(t.type.is_variable(h))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_empty_list(h))o.throw_error(t.error.type(\"list\",u,n.indicator));else{for(var E=p.sort(t.compare),I=new t.type.Term(\"[]\"),v=E.length-1;v>=0;v--)I=new t.type.Term(\".\",[E[v],I]);o.prepend([new t.type.State(a.goal.replace(new t.type.Term(\"=\",[I,A])),a.substitution,a)])}}},\"keysort/2\":function(o,a,n){var u=n.args[0],A=n.args[1];if(t.type.is_variable(u))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_variable(A)&&!t.type.is_fully_list(A))o.throw_error(t.error.type(\"list\",A,n.indicator));else{for(var p=[],h,E=u;E.indicator===\"./2\";){if(h=E.args[0],t.type.is_variable(h)){o.throw_error(t.error.instantiation(n.indicator));return}else if(!t.type.is_term(h)||h.indicator!==\"-/2\"){o.throw_error(t.error.type(\"pair\",h,n.indicator));return}h.args[0].pair=h.args[1],p.push(h.args[0]),E=E.args[1]}if(t.type.is_variable(E))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_empty_list(E))o.throw_error(t.error.type(\"list\",u,n.indicator));else{for(var I=p.sort(t.compare),v=new t.type.Term(\"[]\"),x=I.length-1;x>=0;x--)v=new t.type.Term(\".\",[new t.type.Term(\"-\",[I[x],I[x].pair]),v]),delete I[x].pair;o.prepend([new t.type.State(a.goal.replace(new t.type.Term(\"=\",[v,A])),a.substitution,a)])}}},\"take/3\":function(o,a,n){var u=n.args[0],A=n.args[1],p=n.args[2];if(t.type.is_variable(A)||t.type.is_variable(u))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_list(A))o.throw_error(t.error.type(\"list\",A,n.indicator));else if(!t.type.is_integer(u))o.throw_error(t.error.type(\"integer\",u,n.indicator));else if(!t.type.is_variable(p)&&!t.type.is_list(p))o.throw_error(t.error.type(\"list\",p,n.indicator));else{for(var h=u.value,E=[],I=A;h>0&&I.indicator===\"./2\";)E.push(I.args[0]),I=I.args[1],h--;if(h===0){for(var v=new t.type.Term(\"[]\"),h=E.length-1;h>=0;h--)v=new t.type.Term(\".\",[E[h],v]);o.prepend([new t.type.State(a.goal.replace(new t.type.Term(\"=\",[v,p])),a.substitution,a)])}}},\"drop/3\":function(o,a,n){var u=n.args[0],A=n.args[1],p=n.args[2];if(t.type.is_variable(A)||t.type.is_variable(u))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_list(A))o.throw_error(t.error.type(\"list\",A,n.indicator));else if(!t.type.is_integer(u))o.throw_error(t.error.type(\"integer\",u,n.indicator));else if(!t.type.is_variable(p)&&!t.type.is_list(p))o.throw_error(t.error.type(\"list\",p,n.indicator));else{for(var h=u.value,E=[],I=A;h>0&&I.indicator===\"./2\";)E.push(I.args[0]),I=I.args[1],h--;h===0&&o.prepend([new t.type.State(a.goal.replace(new t.type.Term(\"=\",[I,p])),a.substitution,a)])}},\"reverse/2\":function(o,a,n){var u=n.args[0],A=n.args[1],p=t.type.is_instantiated_list(u),h=t.type.is_instantiated_list(A);if(t.type.is_variable(u)&&t.type.is_variable(A))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_variable(u)&&!t.type.is_fully_list(u))o.throw_error(t.error.type(\"list\",u,n.indicator));else if(!t.type.is_variable(A)&&!t.type.is_fully_list(A))o.throw_error(t.error.type(\"list\",A,n.indicator));else if(!p&&!h)o.throw_error(t.error.instantiation(n.indicator));else{for(var E=p?u:A,I=new t.type.Term(\"[]\",[]);E.indicator===\"./2\";)I=new t.type.Term(\".\",[E.args[0],I]),E=E.args[1];o.prepend([new t.type.State(a.goal.replace(new t.type.Term(\"=\",[I,p?A:u])),a.substitution,a)])}},\"list_to_set/2\":function(o,a,n){var u=n.args[0],A=n.args[1];if(t.type.is_variable(u))o.throw_error(t.error.instantiation(n.indicator));else{for(var p=u,h=[];p.indicator===\"./2\";)h.push(p.args[0]),p=p.args[1];if(t.type.is_variable(p))o.throw_error(t.error.instantiation(n.indicator));else if(!t.type.is_term(p)||p.indicator!==\"[]/0\")o.throw_error(t.error.type(\"list\",u,n.indicator));else{for(var E=[],I=new t.type.Term(\"[]\",[]),v,x=0;x<h.length;x++){v=!1;for(var C=0;C<E.length&&!v;C++)v=t.compare(h[x],E[C])===0;v||E.push(h[x])}for(x=E.length-1;x>=0;x--)I=new t.type.Term(\".\",[E[x],I]);o.prepend([new t.type.State(a.goal.replace(new t.type.Term(\"=\",[A,I])),a.substitution,a)])}}}}},r=[\"append/2\",\"append/3\",\"member/2\",\"permutation/2\",\"maplist/2\",\"maplist/3\",\"maplist/4\",\"maplist/5\",\"maplist/6\",\"maplist/7\",\"maplist/8\",\"include/3\",\"exclude/3\",\"foldl/4\",\"sum_list/2\",\"max_list/2\",\"min_list/2\",\"prod_list/2\",\"last/2\",\"prefix/2\",\"nth0/3\",\"nth1/3\",\"nth0/4\",\"nth1/4\",\"length/2\",\"replicate/3\",\"select/3\",\"sort/2\",\"msort/2\",\"keysort/2\",\"take/3\",\"drop/3\",\"reverse/2\",\"list_to_set/2\"];typeof sH<\"u\"?sH.exports=function(o){t=o,new t.type.Module(\"lists\",e(),r)}:new t.type.Module(\"lists\",e(),r)})(Ggt)});var ime=_(Yr=>{\"use strict\";var em=process.platform===\"win32\",oH=\"aes-256-cbc\",jgt=\"sha256\",Wde=\"The current environment doesn't support interactive reading from TTY.\",Yn=ve(\"fs\"),jde=process.binding(\"tty_wrap\").TTY,lH=ve(\"child_process\"),u0=ve(\"path\"),cH={prompt:\"> \",hideEchoBack:!1,mask:\"*\",limit:[],limitMessage:\"Input another, please.$<( [)limit(])>\",defaultInput:\"\",trueValue:[],falseValue:[],caseSensitive:!1,keepWhitespace:!1,encoding:\"utf8\",bufferSize:1024,print:void 0,history:!0,cd:!1,phContent:void 0,preCheck:void 0},Jf=\"none\",Zc,BC,Yde=!1,c0,mk,aH,Ygt=0,hH=\"\",$d=[],yk,Kde=!1,uH=!1,D2=!1;function zde(t){function e(r){return r.replace(/[^\\w\\u0080-\\uFFFF]/g,function(o){return\"#\"+o.charCodeAt(0)+\";\"})}return mk.concat(function(r){var o=[];return Object.keys(r).forEach(function(a){r[a]===\"boolean\"?t[a]&&o.push(\"--\"+a):r[a]===\"string\"&&t[a]&&o.push(\"--\"+a,e(t[a]))}),o}({display:\"string\",displayOnly:\"boolean\",keyIn:\"boolean\",hideEchoBack:\"boolean\",mask:\"string\",limit:\"string\",caseSensitive:\"boolean\"}))}function Wgt(t,e){function r(U){var V,te=\"\",ae;for(aH=aH||ve(\"os\").tmpdir();;){V=u0.join(aH,U+te);try{ae=Yn.openSync(V,\"wx\")}catch(fe){if(fe.code===\"EEXIST\"){te++;continue}else throw fe}Yn.closeSync(ae);break}return V}var o,a,n,u={},A,p,h=r(\"readline-sync.stdout\"),E=r(\"readline-sync.stderr\"),I=r(\"readline-sync.exit\"),v=r(\"readline-sync.done\"),x=ve(\"crypto\"),C,R,N;C=x.createHash(jgt),C.update(\"\"+process.pid+Ygt+++Math.random()),N=C.digest(\"hex\"),R=x.createDecipher(oH,N),o=zde(t),em?(a=process.env.ComSpec||\"cmd.exe\",process.env.Q='\"',n=[\"/V:ON\",\"/S\",\"/C\",\"(%Q%\"+a+\"%Q% /V:ON /S /C %Q%%Q%\"+c0+\"%Q%\"+o.map(function(U){return\" %Q%\"+U+\"%Q%\"}).join(\"\")+\" & (echo !ERRORLEVEL!)>%Q%\"+I+\"%Q%%Q%) 2>%Q%\"+E+\"%Q% |%Q%\"+process.execPath+\"%Q% %Q%\"+__dirname+\"\\\\encrypt.js%Q% %Q%\"+oH+\"%Q% %Q%\"+N+\"%Q% >%Q%\"+h+\"%Q% & (echo 1)>%Q%\"+v+\"%Q%\"]):(a=\"/bin/sh\",n=[\"-c\",'(\"'+c0+'\"'+o.map(function(U){return\" '\"+U.replace(/'/g,\"'\\\\''\")+\"'\"}).join(\"\")+'; echo $?>\"'+I+'\") 2>\"'+E+'\" |\"'+process.execPath+'\" \"'+__dirname+'/encrypt.js\" \"'+oH+'\" \"'+N+'\" >\"'+h+'\"; echo 1 >\"'+v+'\"']),D2&&D2(\"_execFileSync\",o);try{lH.spawn(a,n,e)}catch(U){u.error=new Error(U.message),u.error.method=\"_execFileSync - spawn\",u.error.program=a,u.error.args=n}for(;Yn.readFileSync(v,{encoding:t.encoding}).trim()!==\"1\";);return(A=Yn.readFileSync(I,{encoding:t.encoding}).trim())===\"0\"?u.input=R.update(Yn.readFileSync(h,{encoding:\"binary\"}),\"hex\",t.encoding)+R.final(t.encoding):(p=Yn.readFileSync(E,{encoding:t.encoding}).trim(),u.error=new Error(Wde+(p?`\n`+p:\"\")),u.error.method=\"_execFileSync\",u.error.program=a,u.error.args=n,u.error.extMessage=p,u.error.exitCode=+A),Yn.unlinkSync(h),Yn.unlinkSync(E),Yn.unlinkSync(I),Yn.unlinkSync(v),u}function Kgt(t){var e,r={},o,a={env:process.env,encoding:t.encoding};if(c0||(em?process.env.PSModulePath?(c0=\"powershell.exe\",mk=[\"-ExecutionPolicy\",\"Bypass\",\"-File\",__dirname+\"\\\\read.ps1\"]):(c0=\"cscript.exe\",mk=[\"//nologo\",__dirname+\"\\\\read.cs.js\"]):(c0=\"/bin/sh\",mk=[__dirname+\"/read.sh\"])),em&&!process.env.PSModulePath&&(a.stdio=[process.stdin]),lH.execFileSync){e=zde(t),D2&&D2(\"execFileSync\",e);try{r.input=lH.execFileSync(c0,e,a)}catch(n){o=n.stderr?(n.stderr+\"\").trim():\"\",r.error=new Error(Wde+(o?`\n`+o:\"\")),r.error.method=\"execFileSync\",r.error.program=c0,r.error.args=e,r.error.extMessage=o,r.error.exitCode=n.status,r.error.code=n.code,r.error.signal=n.signal}}else r=Wgt(t,a);return r.error||(r.input=r.input.replace(/^\\s*'|'\\s*$/g,\"\"),t.display=\"\"),r}function AH(t){var e=\"\",r=t.display,o=!t.display&&t.keyIn&&t.hideEchoBack&&!t.mask;function a(){var n=Kgt(t);if(n.error)throw n.error;return n.input}return uH&&uH(t),function(){var n,u,A;function p(){return n||(n=process.binding(\"fs\"),u=process.binding(\"constants\")),n}if(typeof Jf==\"string\")if(Jf=null,em){if(A=function(h){var E=h.replace(/^\\D+/,\"\").split(\".\"),I=0;return(E[0]=+E[0])&&(I+=E[0]*1e4),(E[1]=+E[1])&&(I+=E[1]*100),(E[2]=+E[2])&&(I+=E[2]),I}(process.version),!(A>=20302&&A<40204||A>=5e4&&A<50100||A>=50600&&A<60200)&&process.stdin.isTTY)process.stdin.pause(),Jf=process.stdin.fd,BC=process.stdin._handle;else try{Jf=p().open(\"CONIN$\",u.O_RDWR,parseInt(\"0666\",8)),BC=new jde(Jf,!0)}catch{}if(process.stdout.isTTY)Zc=process.stdout.fd;else{try{Zc=Yn.openSync(\"\\\\\\\\.\\\\CON\",\"w\")}catch{}if(typeof Zc!=\"number\")try{Zc=p().open(\"CONOUT$\",u.O_RDWR,parseInt(\"0666\",8))}catch{}}}else{if(process.stdin.isTTY){process.stdin.pause();try{Jf=Yn.openSync(\"/dev/tty\",\"r\"),BC=process.stdin._handle}catch{}}else try{Jf=Yn.openSync(\"/dev/tty\",\"r\"),BC=new jde(Jf,!1)}catch{}if(process.stdout.isTTY)Zc=process.stdout.fd;else try{Zc=Yn.openSync(\"/dev/tty\",\"w\")}catch{}}}(),function(){var n,u,A=!t.hideEchoBack&&!t.keyIn,p,h,E,I,v;yk=\"\";function x(C){return C===Yde?!0:BC.setRawMode(C)!==0?!1:(Yde=C,!0)}if(Kde||!BC||typeof Zc!=\"number\"&&(t.display||!A)){e=a();return}if(t.display&&(Yn.writeSync(Zc,t.display),t.display=\"\"),!t.displayOnly){if(!x(!A)){e=a();return}for(h=t.keyIn?1:t.bufferSize,p=Buffer.allocUnsafe&&Buffer.alloc?Buffer.alloc(h):new Buffer(h),t.keyIn&&t.limit&&(u=new RegExp(\"[^\"+t.limit+\"]\",\"g\"+(t.caseSensitive?\"\":\"i\")));;){E=0;try{E=Yn.readSync(Jf,p,0,h)}catch(C){if(C.code!==\"EOF\"){x(!1),e+=a();return}}if(E>0?(I=p.toString(t.encoding,0,E),yk+=I):(I=`\n`,yk+=String.fromCharCode(0)),I&&typeof(v=(I.match(/^(.*?)[\\r\\n]/)||[])[1])==\"string\"&&(I=v,n=!0),I&&(I=I.replace(/[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]/g,\"\")),I&&u&&(I=I.replace(u,\"\")),I&&(A||(t.hideEchoBack?t.mask&&Yn.writeSync(Zc,new Array(I.length+1).join(t.mask)):Yn.writeSync(Zc,I)),e+=I),!t.keyIn&&n||t.keyIn&&e.length>=h)break}!A&&!o&&Yn.writeSync(Zc,`\n`),x(!1)}}(),t.print&&!o&&t.print(r+(t.displayOnly?\"\":(t.hideEchoBack?new Array(e.length+1).join(t.mask):e)+`\n`),t.encoding),t.displayOnly?\"\":hH=t.keepWhitespace||t.keyIn?e:e.trim()}function zgt(t,e){var r=[];function o(a){a!=null&&(Array.isArray(a)?a.forEach(o):(!e||e(a))&&r.push(a))}return o(t),r}function gH(t){return t.replace(/[\\x00-\\x7f]/g,function(e){return\"\\\\x\"+(\"00\"+e.charCodeAt().toString(16)).substr(-2)})}function Rs(){var t=Array.prototype.slice.call(arguments),e,r;return t.length&&typeof t[0]==\"boolean\"&&(r=t.shift(),r&&(e=Object.keys(cH),t.unshift(cH))),t.reduce(function(o,a){return a==null||(a.hasOwnProperty(\"noEchoBack\")&&!a.hasOwnProperty(\"hideEchoBack\")&&(a.hideEchoBack=a.noEchoBack,delete a.noEchoBack),a.hasOwnProperty(\"noTrim\")&&!a.hasOwnProperty(\"keepWhitespace\")&&(a.keepWhitespace=a.noTrim,delete a.noTrim),r||(e=Object.keys(a)),e.forEach(function(n){var u;if(!!a.hasOwnProperty(n))switch(u=a[n],n){case\"mask\":case\"limitMessage\":case\"defaultInput\":case\"encoding\":u=u!=null?u+\"\":\"\",u&&n!==\"limitMessage\"&&(u=u.replace(/[\\r\\n]/g,\"\")),o[n]=u;break;case\"bufferSize\":!isNaN(u=parseInt(u,10))&&typeof u==\"number\"&&(o[n]=u);break;case\"displayOnly\":case\"keyIn\":case\"hideEchoBack\":case\"caseSensitive\":case\"keepWhitespace\":case\"history\":case\"cd\":o[n]=!!u;break;case\"limit\":case\"trueValue\":case\"falseValue\":o[n]=zgt(u,function(A){var p=typeof A;return p===\"string\"||p===\"number\"||p===\"function\"||A instanceof RegExp}).map(function(A){return typeof A==\"string\"?A.replace(/[\\r\\n]/g,\"\"):A});break;case\"print\":case\"phContent\":case\"preCheck\":o[n]=typeof u==\"function\"?u:void 0;break;case\"prompt\":case\"display\":o[n]=u??\"\";break}})),o},{})}function fH(t,e,r){return e.some(function(o){var a=typeof o;return a===\"string\"?r?t===o:t.toLowerCase()===o.toLowerCase():a===\"number\"?parseFloat(t)===o:a===\"function\"?o(t):o instanceof RegExp?o.test(t):!1})}function dH(t,e){var r=u0.normalize(em?(process.env.HOMEDRIVE||\"\")+(process.env.HOMEPATH||\"\"):process.env.HOME||\"\").replace(/[\\/\\\\]+$/,\"\");return t=u0.normalize(t),e?t.replace(/^~(?=\\/|\\\\|$)/,r):t.replace(new RegExp(\"^\"+gH(r)+\"(?=\\\\/|\\\\\\\\|$)\",em?\"i\":\"\"),\"~\")}function vC(t,e){var r=\"(?:\\\\(([\\\\s\\\\S]*?)\\\\))?(\\\\w+|.-.)(?:\\\\(([\\\\s\\\\S]*?)\\\\))?\",o=new RegExp(\"(\\\\$)?(\\\\$<\"+r+\">)\",\"g\"),a=new RegExp(\"(\\\\$)?(\\\\$\\\\{\"+r+\"\\\\})\",\"g\");function n(u,A,p,h,E,I){var v;return A||typeof(v=e(E))!=\"string\"?p:v?(h||\"\")+v+(I||\"\"):\"\"}return t.replace(o,n).replace(a,n)}function Vde(t,e,r){var o,a=[],n=-1,u=0,A=\"\",p;function h(E,I){return I.length>3?(E.push(I[0]+\"...\"+I[I.length-1]),p=!0):I.length&&(E=E.concat(I)),E}return o=t.reduce(function(E,I){return E.concat((I+\"\").split(\"\"))},[]).reduce(function(E,I){var v,x;return e||(I=I.toLowerCase()),v=/^\\d$/.test(I)?1:/^[A-Z]$/.test(I)?2:/^[a-z]$/.test(I)?3:0,r&&v===0?A+=I:(x=I.charCodeAt(0),v&&v===n&&x===u+1?a.push(I):(E=h(E,a),a=[I],n=v),u=x),E},[]),o=h(o,a),A&&(o.push(A),p=!0),{values:o,suppressed:p}}function Jde(t,e){return t.join(t.length>2?\", \":e?\" / \":\"/\")}function Xde(t,e){var r,o,a={},n;if(e.phContent&&(r=e.phContent(t,e)),typeof r!=\"string\")switch(t){case\"hideEchoBack\":case\"mask\":case\"defaultInput\":case\"caseSensitive\":case\"keepWhitespace\":case\"encoding\":case\"bufferSize\":case\"history\":case\"cd\":r=e.hasOwnProperty(t)?typeof e[t]==\"boolean\"?e[t]?\"on\":\"off\":e[t]+\"\":\"\";break;case\"limit\":case\"trueValue\":case\"falseValue\":o=e[e.hasOwnProperty(t+\"Src\")?t+\"Src\":t],e.keyIn?(a=Vde(o,e.caseSensitive),o=a.values):o=o.filter(function(u){var A=typeof u;return A===\"string\"||A===\"number\"}),r=Jde(o,a.suppressed);break;case\"limitCount\":case\"limitCountNotZero\":r=e[e.hasOwnProperty(\"limitSrc\")?\"limitSrc\":\"limit\"].length,r=r||t!==\"limitCountNotZero\"?r+\"\":\"\";break;case\"lastInput\":r=hH;break;case\"cwd\":case\"CWD\":case\"cwdHome\":r=process.cwd(),t===\"CWD\"?r=u0.basename(r):t===\"cwdHome\"&&(r=dH(r));break;case\"date\":case\"time\":case\"localeDate\":case\"localeTime\":r=new Date()[\"to\"+t.replace(/^./,function(u){return u.toUpperCase()})+\"String\"]();break;default:typeof(n=(t.match(/^history_m(\\d+)$/)||[])[1])==\"string\"&&(r=$d[$d.length-n]||\"\")}return r}function Zde(t){var e=/^(.)-(.)$/.exec(t),r=\"\",o,a,n,u;if(!e)return null;for(o=e[1].charCodeAt(0),a=e[2].charCodeAt(0),u=o<a?1:-1,n=o;n!==a+u;n+=u)r+=String.fromCharCode(n);return r}function pH(t){var e=new RegExp(/(\\s*)(?:(\"|')(.*?)(?:\\2|$)|(\\S+))/g),r,o=\"\",a=[],n;for(t=t.trim();r=e.exec(t);)n=r[3]||r[4]||\"\",r[1]&&(a.push(o),o=\"\"),o+=n;return o&&a.push(o),a}function $de(t,e){return e.trueValue.length&&fH(t,e.trueValue,e.caseSensitive)?!0:e.falseValue.length&&fH(t,e.falseValue,e.caseSensitive)?!1:t}function eme(t){var e,r,o,a,n,u,A;function p(E){return Xde(E,t)}function h(E){t.display+=(/[^\\r\\n]$/.test(t.display)?`\n`:\"\")+E}for(t.limitSrc=t.limit,t.displaySrc=t.display,t.limit=\"\",t.display=vC(t.display+\"\",p);;){if(e=AH(t),r=!1,o=\"\",t.defaultInput&&!e&&(e=t.defaultInput),t.history&&((a=/^\\s*\\!(?:\\!|-1)(:p)?\\s*$/.exec(e))?(n=$d[0]||\"\",a[1]?r=!0:e=n,h(n+`\n`),r||(t.displayOnly=!0,AH(t),t.displayOnly=!1)):e&&e!==$d[$d.length-1]&&($d=[e])),!r&&t.cd&&e)switch(u=pH(e),u[0].toLowerCase()){case\"cd\":if(u[1])try{process.chdir(dH(u[1],!0))}catch(E){h(E+\"\")}r=!0;break;case\"pwd\":h(process.cwd()),r=!0;break}if(!r&&t.preCheck&&(A=t.preCheck(e,t),e=A.res,A.forceNext&&(r=!0)),!r){if(!t.limitSrc.length||fH(e,t.limitSrc,t.caseSensitive))break;t.limitMessage&&(o=vC(t.limitMessage,p))}h((o?o+`\n`:\"\")+vC(t.displaySrc+\"\",p))}return $de(e,t)}Yr._DBG_set_useExt=function(t){Kde=t};Yr._DBG_set_checkOptions=function(t){uH=t};Yr._DBG_set_checkMethod=function(t){D2=t};Yr._DBG_clearHistory=function(){hH=\"\",$d=[]};Yr.setDefaultOptions=function(t){return cH=Rs(!0,t),Rs(!0)};Yr.question=function(t,e){return eme(Rs(Rs(!0,e),{display:t}))};Yr.prompt=function(t){var e=Rs(!0,t);return e.display=e.prompt,eme(e)};Yr.keyIn=function(t,e){var r=Rs(Rs(!0,e),{display:t,keyIn:!0,keepWhitespace:!0});return r.limitSrc=r.limit.filter(function(o){var a=typeof o;return a===\"string\"||a===\"number\"}).map(function(o){return vC(o+\"\",Zde)}),r.limit=gH(r.limitSrc.join(\"\")),[\"trueValue\",\"falseValue\"].forEach(function(o){r[o]=r[o].reduce(function(a,n){var u=typeof n;return u===\"string\"||u===\"number\"?a=a.concat((n+\"\").split(\"\")):a.push(n),a},[])}),r.display=vC(r.display+\"\",function(o){return Xde(o,r)}),$de(AH(r),r)};Yr.questionEMail=function(t,e){return t==null&&(t=\"Input e-mail address: \"),Yr.question(t,Rs({hideEchoBack:!1,limit:/^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,limitMessage:\"Input valid e-mail address, please.\",trueValue:null,falseValue:null},e,{keepWhitespace:!1,cd:!1}))};Yr.questionNewPassword=function(t,e){var r,o,a,n=Rs({hideEchoBack:!0,mask:\"*\",limitMessage:`It can include: $<charlist>\nAnd the length must be: $<length>`,trueValue:null,falseValue:null,caseSensitive:!0},e,{history:!1,cd:!1,phContent:function(x){return x===\"charlist\"?r.text:x===\"length\"?o+\"...\"+a:null}}),u,A,p,h,E,I,v;for(e=e||{},u=vC(e.charlist?e.charlist+\"\":\"$<!-~>\",Zde),(isNaN(o=parseInt(e.min,10))||typeof o!=\"number\")&&(o=12),(isNaN(a=parseInt(e.max,10))||typeof a!=\"number\")&&(a=24),h=new RegExp(\"^[\"+gH(u)+\"]{\"+o+\",\"+a+\"}$\"),r=Vde([u],n.caseSensitive,!0),r.text=Jde(r.values,r.suppressed),A=e.confirmMessage!=null?e.confirmMessage:\"Reinput a same one to confirm it: \",p=e.unmatchMessage!=null?e.unmatchMessage:\"It differs from first one. Hit only the Enter key if you want to retry from first one.\",t==null&&(t=\"Input new password: \"),E=n.limitMessage;!v;)n.limit=h,n.limitMessage=E,I=Yr.question(t,n),n.limit=[I,\"\"],n.limitMessage=p,v=Yr.question(A,n);return I};function tme(t,e,r){var o;function a(n){return o=r(n),!isNaN(o)&&typeof o==\"number\"}return Yr.question(t,Rs({limitMessage:\"Input valid number, please.\"},e,{limit:a,cd:!1})),o}Yr.questionInt=function(t,e){return tme(t,e,function(r){return parseInt(r,10)})};Yr.questionFloat=function(t,e){return tme(t,e,parseFloat)};Yr.questionPath=function(t,e){var r,o=\"\",a=Rs({hideEchoBack:!1,limitMessage:`$<error(\n)>Input valid path, please.$<( Min:)min>$<( Max:)max>`,history:!0,cd:!0},e,{keepWhitespace:!1,limit:function(n){var u,A,p;n=dH(n,!0),o=\"\";function h(E){E.split(/\\/|\\\\/).reduce(function(I,v){var x=u0.resolve(I+=v+u0.sep);if(!Yn.existsSync(x))Yn.mkdirSync(x);else if(!Yn.statSync(x).isDirectory())throw new Error(\"Non directory already exists: \"+x);return I},\"\")}try{if(u=Yn.existsSync(n),r=u?Yn.realpathSync(n):u0.resolve(n),!e.hasOwnProperty(\"exists\")&&!u||typeof e.exists==\"boolean\"&&e.exists!==u)return o=(u?\"Already exists\":\"No such file or directory\")+\": \"+r,!1;if(!u&&e.create&&(e.isDirectory?h(r):(h(u0.dirname(r)),Yn.closeSync(Yn.openSync(r,\"w\"))),r=Yn.realpathSync(r)),u&&(e.min||e.max||e.isFile||e.isDirectory)){if(A=Yn.statSync(r),e.isFile&&!A.isFile())return o=\"Not file: \"+r,!1;if(e.isDirectory&&!A.isDirectory())return o=\"Not directory: \"+r,!1;if(e.min&&A.size<+e.min||e.max&&A.size>+e.max)return o=\"Size \"+A.size+\" is out of range: \"+r,!1}if(typeof e.validate==\"function\"&&(p=e.validate(r))!==!0)return typeof p==\"string\"&&(o=p),!1}catch(E){return o=E+\"\",!1}return!0},phContent:function(n){return n===\"error\"?o:n!==\"min\"&&n!==\"max\"?null:e.hasOwnProperty(n)?e[n]+\"\":\"\"}});return e=e||{},t==null&&(t='Input path (you can \"cd\" and \"pwd\"): '),Yr.question(t,a),r};function rme(t,e){var r={},o={};return typeof t==\"object\"?(Object.keys(t).forEach(function(a){typeof t[a]==\"function\"&&(o[e.caseSensitive?a:a.toLowerCase()]=t[a])}),r.preCheck=function(a){var n;return r.args=pH(a),n=r.args[0]||\"\",e.caseSensitive||(n=n.toLowerCase()),r.hRes=n!==\"_\"&&o.hasOwnProperty(n)?o[n].apply(a,r.args.slice(1)):o.hasOwnProperty(\"_\")?o._.apply(a,r.args):null,{res:a,forceNext:!1}},o.hasOwnProperty(\"_\")||(r.limit=function(){var a=r.args[0]||\"\";return e.caseSensitive||(a=a.toLowerCase()),o.hasOwnProperty(a)})):r.preCheck=function(a){return r.args=pH(a),r.hRes=typeof t==\"function\"?t.apply(a,r.args):!0,{res:a,forceNext:!1}},r}Yr.promptCL=function(t,e){var r=Rs({hideEchoBack:!1,limitMessage:\"Requested command is not available.\",caseSensitive:!1,history:!0},e),o=rme(t,r);return r.limit=o.limit,r.preCheck=o.preCheck,Yr.prompt(r),o.args};Yr.promptLoop=function(t,e){for(var r=Rs({hideEchoBack:!1,trueValue:null,falseValue:null,caseSensitive:!1,history:!0},e);!t(Yr.prompt(r)););};Yr.promptCLLoop=function(t,e){var r=Rs({hideEchoBack:!1,limitMessage:\"Requested command is not available.\",caseSensitive:!1,history:!0},e),o=rme(t,r);for(r.limit=o.limit,r.preCheck=o.preCheck;Yr.prompt(r),!o.hRes;);};Yr.promptSimShell=function(t){return Yr.prompt(Rs({hideEchoBack:!1,history:!0},t,{prompt:function(){return em?\"$<cwd>>\":(process.env.USER||\"\")+(process.env.HOSTNAME?\"@\"+process.env.HOSTNAME.replace(/\\..*$/,\"\"):\"\")+\":$<cwdHome>$ \"}()}))};function nme(t,e,r){var o;return t==null&&(t=\"Are you sure? \"),(!e||e.guide!==!1)&&(t+=\"\")&&(t=t.replace(/\\s*:?\\s*$/,\"\")+\" [y/n]: \"),o=Yr.keyIn(t,Rs(e,{hideEchoBack:!1,limit:r,trueValue:\"y\",falseValue:\"n\",caseSensitive:!1})),typeof o==\"boolean\"?o:\"\"}Yr.keyInYN=function(t,e){return nme(t,e)};Yr.keyInYNStrict=function(t,e){return nme(t,e,\"yn\")};Yr.keyInPause=function(t,e){t==null&&(t=\"Continue...\"),(!e||e.guide!==!1)&&(t+=\"\")&&(t=t.replace(/\\s+$/,\"\")+\" (Hit any key)\"),Yr.keyIn(t,Rs({limit:null},e,{hideEchoBack:!0,mask:\"\"}))};Yr.keyInSelect=function(t,e,r){var o=Rs({hideEchoBack:!1},r,{trueValue:null,falseValue:null,caseSensitive:!1,phContent:function(p){return p===\"itemsCount\"?t.length+\"\":p===\"firstItem\"?(t[0]+\"\").trim():p===\"lastItem\"?(t[t.length-1]+\"\").trim():null}}),a=\"\",n={},u=49,A=`\n`;if(!Array.isArray(t)||!t.length||t.length>35)throw\"`items` must be Array (max length: 35).\";return t.forEach(function(p,h){var E=String.fromCharCode(u);a+=E,n[E]=h,A+=\"[\"+E+\"] \"+(p+\"\").trim()+`\n`,u=u===57?97:u+1}),(!r||r.cancel!==!1)&&(a+=\"0\",n[0]=-1,A+=\"[0] \"+(r&&r.cancel!=null&&typeof r.cancel!=\"boolean\"?(r.cancel+\"\").trim():\"CANCEL\")+`\n`),o.limit=a,A+=`\n`,e==null&&(e=\"Choose one from list: \"),(e+=\"\")&&((!r||r.guide!==!1)&&(e=e.replace(/\\s*:?\\s*$/,\"\")+\" [$<limit>]: \"),A+=e),n[Yr.keyIn(A,o).toLowerCase()]};Yr.getRawInput=function(){return yk};function P2(t,e){var r;return e.length&&(r={},r[t]=e[0]),Yr.setDefaultOptions(r)[t]}Yr.setPrint=function(){return P2(\"print\",arguments)};Yr.setPrompt=function(){return P2(\"prompt\",arguments)};Yr.setEncoding=function(){return P2(\"encoding\",arguments)};Yr.setMask=function(){return P2(\"mask\",arguments)};Yr.setBufferSize=function(){return P2(\"bufferSize\",arguments)}});var mH=_((r7t,gl)=>{(function(){var t={major:0,minor:2,patch:66,status:\"beta\"};tau_file_system={files:{},open:function(w,S,y){var F=tau_file_system.files[w];if(!F){if(y===\"read\")return null;F={path:w,text:\"\",type:S,get:function(J,X){return X===this.text.length||X>this.text.length?\"end_of_file\":this.text.substring(X,X+J)},put:function(J,X){return X===\"end_of_file\"?(this.text+=J,!0):X===\"past_end_of_file\"?null:(this.text=this.text.substring(0,X)+J+this.text.substring(X+J.length),!0)},get_byte:function(J){if(J===\"end_of_stream\")return-1;var X=Math.floor(J/2);if(this.text.length<=X)return-1;var Z=n(this.text[Math.floor(J/2)],0);return J%2===0?Z&255:Z/256>>>0},put_byte:function(J,X){var Z=X===\"end_of_stream\"?this.text.length:Math.floor(X/2);if(this.text.length<Z)return null;var ie=this.text.length===Z?-1:n(this.text[Math.floor(X/2)],0);return X%2===0?(ie=ie/256>>>0,ie=(ie&255)<<8|J&255):(ie=ie&255,ie=(J&255)<<8|ie&255),this.text.length===Z?this.text+=u(ie):this.text=this.text.substring(0,Z)+u(ie)+this.text.substring(Z+1),!0},flush:function(){return!0},close:function(){var J=tau_file_system.files[this.path];return J?!0:null}},tau_file_system.files[w]=F}return y===\"write\"&&(F.text=\"\"),F}},tau_user_input={buffer:\"\",get:function(w,S){for(var y;tau_user_input.buffer.length<w;)y=window.prompt(),y&&(tau_user_input.buffer+=y);return y=tau_user_input.buffer.substr(0,w),tau_user_input.buffer=tau_user_input.buffer.substr(w),y}},tau_user_output={put:function(w,S){return console.log(w),!0},flush:function(){return!0}},nodejs_file_system={open:function(w,S,y){var F=ve(\"fs\"),J=F.openSync(w,y[0]);return y===\"read\"&&!F.existsSync(w)?null:{get:function(X,Z){var ie=new Buffer(X);return F.readSync(J,ie,0,X,Z),ie.toString()},put:function(X,Z){var ie=Buffer.from(X);if(Z===\"end_of_file\")F.writeSync(J,ie);else{if(Z===\"past_end_of_file\")return null;F.writeSync(J,ie,0,ie.length,Z)}return!0},get_byte:function(X){return null},put_byte:function(X,Z){return null},flush:function(){return!0},close:function(){return F.closeSync(J),!0}}}},nodejs_user_input={buffer:\"\",get:function(w,S){for(var y,F=ime();nodejs_user_input.buffer.length<w;)nodejs_user_input.buffer+=F.question();return y=nodejs_user_input.buffer.substr(0,w),nodejs_user_input.buffer=nodejs_user_input.buffer.substr(w),y}},nodejs_user_output={put:function(w,S){return process.stdout.write(w),!0},flush:function(){return!0}};var e;Array.prototype.indexOf?e=function(w,S){return w.indexOf(S)}:e=function(w,S){for(var y=w.length,F=0;F<y;F++)if(S===w[F])return F;return-1};var r=function(w,S){if(w.length!==0){for(var y=w[0],F=w.length,J=1;J<F;J++)y=S(y,w[J]);return y}},o;Array.prototype.map?o=function(w,S){return w.map(S)}:o=function(w,S){for(var y=[],F=w.length,J=0;J<F;J++)y.push(S(w[J]));return y};var a;Array.prototype.filter?a=function(w,S){return w.filter(S)}:a=function(w,S){for(var y=[],F=w.length,J=0;J<F;J++)S(w[J])&&y.push(w[J]);return y};var n;String.prototype.codePointAt?n=function(w,S){return w.codePointAt(S)}:n=function(w,S){return w.charCodeAt(S)};var u;String.fromCodePoint?u=function(){return String.fromCodePoint.apply(null,arguments)}:u=function(){return String.fromCharCode.apply(null,arguments)};var A=0,p=1,h=/(\\\\a)|(\\\\b)|(\\\\f)|(\\\\n)|(\\\\r)|(\\\\t)|(\\\\v)|\\\\x([0-9a-fA-F]+)\\\\|\\\\([0-7]+)\\\\|(\\\\\\\\)|(\\\\')|('')|(\\\\\")|(\\\\`)|(\\\\.)|(.)/g,E={\"\\\\a\":7,\"\\\\b\":8,\"\\\\f\":12,\"\\\\n\":10,\"\\\\r\":13,\"\\\\t\":9,\"\\\\v\":11};function I(w){var S=[],y=!1;return w.replace(h,function(F,J,X,Z,ie,be,Le,ot,dt,Gt,$t,bt,an,Qr,mr,br,Wr){switch(!0){case dt!==void 0:return S.push(parseInt(dt,16)),\"\";case Gt!==void 0:return S.push(parseInt(Gt,8)),\"\";case $t!==void 0:case bt!==void 0:case an!==void 0:case Qr!==void 0:case mr!==void 0:return S.push(n(F.substr(1),0)),\"\";case Wr!==void 0:return S.push(n(Wr,0)),\"\";case br!==void 0:y=!0;default:return S.push(E[F]),\"\"}}),y?null:S}function v(w,S){var y=\"\";if(w.length<2)return w;try{w=w.replace(/\\\\([0-7]+)\\\\/g,function(Z,ie){return u(parseInt(ie,8))}),w=w.replace(/\\\\x([0-9a-fA-F]+)\\\\/g,function(Z,ie){return u(parseInt(ie,16))})}catch{return null}for(var F=0;F<w.length;F++){var J=w.charAt(F),X=w.charAt(F+1);if(J===S&&X===S)F++,y+=S;else if(J===\"\\\\\")if([\"a\",\"b\",\"f\",\"n\",\"r\",\"t\",\"v\",\"'\",'\"',\"\\\\\",\"a\",\"\\b\",\"\\f\",`\n`,\"\\r\",\"\t\",\"\\v\"].indexOf(X)!==-1)switch(F+=1,X){case\"a\":y+=\"a\";break;case\"b\":y+=\"\\b\";break;case\"f\":y+=\"\\f\";break;case\"n\":y+=`\n`;break;case\"r\":y+=\"\\r\";break;case\"t\":y+=\"\t\";break;case\"v\":y+=\"\\v\";break;case\"'\":y+=\"'\";break;case'\"':y+='\"';break;case\"\\\\\":y+=\"\\\\\";break}else return null;else y+=J}return y}function x(w){for(var S=\"\",y=0;y<w.length;y++)switch(w.charAt(y)){case\"'\":S+=\"\\\\'\";break;case\"\\\\\":S+=\"\\\\\\\\\";break;case\"\\b\":S+=\"\\\\b\";break;case\"\\f\":S+=\"\\\\f\";break;case`\n`:S+=\"\\\\n\";break;case\"\\r\":S+=\"\\\\r\";break;case\"\t\":S+=\"\\\\t\";break;case\"\\v\":S+=\"\\\\v\";break;default:S+=w.charAt(y);break}return S}function C(w){var S=w.substr(2);switch(w.substr(0,2).toLowerCase()){case\"0x\":return parseInt(S,16);case\"0b\":return parseInt(S,2);case\"0o\":return parseInt(S,8);case\"0'\":return I(S)[0];default:return parseFloat(w)}}var R={whitespace:/^\\s*(?:(?:%.*)|(?:\\/\\*(?:\\n|\\r|.)*?\\*\\/)|(?:\\s+))\\s*/,variable:/^(?:[A-Z_][a-zA-Z0-9_]*)/,atom:/^(\\!|,|;|[a-z][0-9a-zA-Z_]*|[#\\$\\&\\*\\+\\-\\.\\/\\:\\<\\=\\>\\?\\@\\^\\~\\\\]+|'(?:[^']*?(?:\\\\(?:x?\\d+)?\\\\)*(?:'')*(?:\\\\')*)*')/,number:/^(?:0o[0-7]+|0x[0-9a-fA-F]+|0b[01]+|0'(?:''|\\\\[abfnrtv\\\\'\"`]|\\\\x?\\d+\\\\|[^\\\\])|\\d+(?:\\.\\d+(?:[eE][+-]?\\d+)?)?)/,string:/^(?:\"([^\"]|\"\"|\\\\\")*\"|`([^`]|``|\\\\`)*`)/,l_brace:/^(?:\\[)/,r_brace:/^(?:\\])/,l_bracket:/^(?:\\{)/,r_bracket:/^(?:\\})/,bar:/^(?:\\|)/,l_paren:/^(?:\\()/,r_paren:/^(?:\\))/};function N(w,S){return w.get_flag(\"char_conversion\").id===\"on\"?S.replace(/./g,function(y){return w.get_char_conversion(y)}):S}function U(w){this.thread=w,this.text=\"\",this.tokens=[]}U.prototype.set_last_tokens=function(w){return this.tokens=w},U.prototype.new_text=function(w){this.text=w,this.tokens=[]},U.prototype.get_tokens=function(w){var S,y=0,F=0,J=0,X=[],Z=!1;if(w){var ie=this.tokens[w-1];y=ie.len,S=N(this.thread,this.text.substr(ie.len)),F=ie.line,J=ie.start}else S=this.text;if(/^\\s*$/.test(S))return null;for(;S!==\"\";){var be=[],Le=!1;if(/^\\n/.exec(S)!==null){F++,J=0,y++,S=S.replace(/\\n/,\"\"),Z=!0;continue}for(var ot in R)if(R.hasOwnProperty(ot)){var dt=R[ot].exec(S);dt&&be.push({value:dt[0],name:ot,matches:dt})}if(!be.length)return this.set_last_tokens([{value:S,matches:[],name:\"lexical\",line:F,start:J}]);var ie=r(be,function(Qr,mr){return Qr.value.length>=mr.value.length?Qr:mr});switch(ie.start=J,ie.line=F,S=S.replace(ie.value,\"\"),J+=ie.value.length,y+=ie.value.length,ie.name){case\"atom\":ie.raw=ie.value,ie.value.charAt(0)===\"'\"&&(ie.value=v(ie.value.substr(1,ie.value.length-2),\"'\"),ie.value===null&&(ie.name=\"lexical\",ie.value=\"unknown escape sequence\"));break;case\"number\":ie.float=ie.value.substring(0,2)!==\"0x\"&&ie.value.match(/[.eE]/)!==null&&ie.value!==\"0'.\",ie.value=C(ie.value),ie.blank=Le;break;case\"string\":var Gt=ie.value.charAt(0);ie.value=v(ie.value.substr(1,ie.value.length-2),Gt),ie.value===null&&(ie.name=\"lexical\",ie.value=\"unknown escape sequence\");break;case\"whitespace\":var $t=X[X.length-1];$t&&($t.space=!0),Le=!0;continue;case\"r_bracket\":X.length>0&&X[X.length-1].name===\"l_bracket\"&&(ie=X.pop(),ie.name=\"atom\",ie.value=\"{}\",ie.raw=\"{}\",ie.space=!1);break;case\"r_brace\":X.length>0&&X[X.length-1].name===\"l_brace\"&&(ie=X.pop(),ie.name=\"atom\",ie.value=\"[]\",ie.raw=\"[]\",ie.space=!1);break}ie.len=y,X.push(ie),Le=!1}var bt=this.set_last_tokens(X);return bt.length===0?null:bt};function V(w,S,y,F,J){if(!S[y])return{type:A,value:b.error.syntax(S[y-1],\"expression expected\",!0)};var X;if(F===\"0\"){var Z=S[y];switch(Z.name){case\"number\":return{type:p,len:y+1,value:new b.type.Num(Z.value,Z.float)};case\"variable\":return{type:p,len:y+1,value:new b.type.Var(Z.value)};case\"string\":var ie;switch(w.get_flag(\"double_quotes\").id){case\"atom\":ie=new H(Z.value,[]);break;case\"codes\":ie=new H(\"[]\",[]);for(var be=Z.value.length-1;be>=0;be--)ie=new H(\".\",[new b.type.Num(n(Z.value,be),!1),ie]);break;case\"chars\":ie=new H(\"[]\",[]);for(var be=Z.value.length-1;be>=0;be--)ie=new H(\".\",[new b.type.Term(Z.value.charAt(be),[]),ie]);break}return{type:p,len:y+1,value:ie};case\"l_paren\":var bt=V(w,S,y+1,w.__get_max_priority(),!0);return bt.type!==p?bt:S[bt.len]&&S[bt.len].name===\"r_paren\"?(bt.len++,bt):{type:A,derived:!0,value:b.error.syntax(S[bt.len]?S[bt.len]:S[bt.len-1],\") or operator expected\",!S[bt.len])};case\"l_bracket\":var bt=V(w,S,y+1,w.__get_max_priority(),!0);return bt.type!==p?bt:S[bt.len]&&S[bt.len].name===\"r_bracket\"?(bt.len++,bt.value=new H(\"{}\",[bt.value]),bt):{type:A,derived:!0,value:b.error.syntax(S[bt.len]?S[bt.len]:S[bt.len-1],\"} or operator expected\",!S[bt.len])}}var Le=te(w,S,y,J);return Le.type===p||Le.derived||(Le=ae(w,S,y),Le.type===p||Le.derived)?Le:{type:A,derived:!1,value:b.error.syntax(S[y],\"unexpected token\")}}var ot=w.__get_max_priority(),dt=w.__get_next_priority(F),Gt=y;if(S[y].name===\"atom\"&&S[y+1]&&(S[y].space||S[y+1].name!==\"l_paren\")){var Z=S[y++],$t=w.__lookup_operator_classes(F,Z.value);if($t&&$t.indexOf(\"fy\")>-1){var bt=V(w,S,y,F,J);if(bt.type!==A)return Z.value===\"-\"&&!Z.space&&b.type.is_number(bt.value)?{value:new b.type.Num(-bt.value.value,bt.value.is_float),len:bt.len,type:p}:{value:new b.type.Term(Z.value,[bt.value]),len:bt.len,type:p};X=bt}else if($t&&$t.indexOf(\"fx\")>-1){var bt=V(w,S,y,dt,J);if(bt.type!==A)return{value:new b.type.Term(Z.value,[bt.value]),len:bt.len,type:p};X=bt}}y=Gt;var bt=V(w,S,y,dt,J);if(bt.type===p){y=bt.len;var Z=S[y];if(S[y]&&(S[y].name===\"atom\"&&w.__lookup_operator_classes(F,Z.value)||S[y].name===\"bar\"&&w.__lookup_operator_classes(F,\"|\"))){var an=dt,Qr=F,$t=w.__lookup_operator_classes(F,Z.value);if($t.indexOf(\"xf\")>-1)return{value:new b.type.Term(Z.value,[bt.value]),len:++bt.len,type:p};if($t.indexOf(\"xfx\")>-1){var mr=V(w,S,y+1,an,J);return mr.type===p?{value:new b.type.Term(Z.value,[bt.value,mr.value]),len:mr.len,type:p}:(mr.derived=!0,mr)}else if($t.indexOf(\"xfy\")>-1){var mr=V(w,S,y+1,Qr,J);return mr.type===p?{value:new b.type.Term(Z.value,[bt.value,mr.value]),len:mr.len,type:p}:(mr.derived=!0,mr)}else if(bt.type!==A)for(;;){y=bt.len;var Z=S[y];if(Z&&Z.name===\"atom\"&&w.__lookup_operator_classes(F,Z.value)){var $t=w.__lookup_operator_classes(F,Z.value);if($t.indexOf(\"yf\")>-1)bt={value:new b.type.Term(Z.value,[bt.value]),len:++y,type:p};else if($t.indexOf(\"yfx\")>-1){var mr=V(w,S,++y,an,J);if(mr.type===A)return mr.derived=!0,mr;y=mr.len,bt={value:new b.type.Term(Z.value,[bt.value,mr.value]),len:y,type:p}}else break}else break}}else X={type:A,value:b.error.syntax(S[bt.len-1],\"operator expected\")};return bt}return bt}function te(w,S,y,F){if(!S[y]||S[y].name===\"atom\"&&S[y].raw===\".\"&&!F&&(S[y].space||!S[y+1]||S[y+1].name!==\"l_paren\"))return{type:A,derived:!1,value:b.error.syntax(S[y-1],\"unfounded token\")};var J=S[y],X=[];if(S[y].name===\"atom\"&&S[y].raw!==\",\"){if(y++,S[y-1].space)return{type:p,len:y,value:new b.type.Term(J.value,X)};if(S[y]&&S[y].name===\"l_paren\"){if(S[y+1]&&S[y+1].name===\"r_paren\")return{type:A,derived:!0,value:b.error.syntax(S[y+1],\"argument expected\")};var Z=V(w,S,++y,\"999\",!0);if(Z.type===A)return Z.derived?Z:{type:A,derived:!0,value:b.error.syntax(S[y]?S[y]:S[y-1],\"argument expected\",!S[y])};for(X.push(Z.value),y=Z.len;S[y]&&S[y].name===\"atom\"&&S[y].value===\",\";){if(Z=V(w,S,y+1,\"999\",!0),Z.type===A)return Z.derived?Z:{type:A,derived:!0,value:b.error.syntax(S[y+1]?S[y+1]:S[y],\"argument expected\",!S[y+1])};X.push(Z.value),y=Z.len}if(S[y]&&S[y].name===\"r_paren\")y++;else return{type:A,derived:!0,value:b.error.syntax(S[y]?S[y]:S[y-1],\", or ) expected\",!S[y])}}return{type:p,len:y,value:new b.type.Term(J.value,X)}}return{type:A,derived:!1,value:b.error.syntax(S[y],\"term expected\")}}function ae(w,S,y){if(!S[y])return{type:A,derived:!1,value:b.error.syntax(S[y-1],\"[ expected\")};if(S[y]&&S[y].name===\"l_brace\"){var F=V(w,S,++y,\"999\",!0),J=[F.value],X=void 0;if(F.type===A)return S[y]&&S[y].name===\"r_brace\"?{type:p,len:y+1,value:new b.type.Term(\"[]\",[])}:{type:A,derived:!0,value:b.error.syntax(S[y],\"] expected\")};for(y=F.len;S[y]&&S[y].name===\"atom\"&&S[y].value===\",\";){if(F=V(w,S,y+1,\"999\",!0),F.type===A)return F.derived?F:{type:A,derived:!0,value:b.error.syntax(S[y+1]?S[y+1]:S[y],\"argument expected\",!S[y+1])};J.push(F.value),y=F.len}var Z=!1;if(S[y]&&S[y].name===\"bar\"){if(Z=!0,F=V(w,S,y+1,\"999\",!0),F.type===A)return F.derived?F:{type:A,derived:!0,value:b.error.syntax(S[y+1]?S[y+1]:S[y],\"argument expected\",!S[y+1])};X=F.value,y=F.len}return S[y]&&S[y].name===\"r_brace\"?{type:p,len:y+1,value:g(J,X)}:{type:A,derived:!0,value:b.error.syntax(S[y]?S[y]:S[y-1],Z?\"] expected\":\", or | or ] expected\",!S[y])}}return{type:A,derived:!1,value:b.error.syntax(S[y],\"list expected\")}}function fe(w,S,y){var F=S[y].line,J=V(w,S,y,w.__get_max_priority(),!1),X=null,Z;if(J.type!==A)if(y=J.len,S[y]&&S[y].name===\"atom\"&&S[y].raw===\".\")if(y++,b.type.is_term(J.value)){if(J.value.indicator===\":-/2\"?(X=new b.type.Rule(J.value.args[0],we(J.value.args[1])),Z={value:X,len:y,type:p}):J.value.indicator===\"-->/2\"?(X=he(new b.type.Rule(J.value.args[0],J.value.args[1]),w),X.body=we(X.body),Z={value:X,len:y,type:b.type.is_rule(X)?p:A}):(X=new b.type.Rule(J.value,null),Z={value:X,len:y,type:p}),X){var ie=X.singleton_variables();ie.length>0&&w.throw_warning(b.warning.singleton(ie,X.head.indicator,F))}return Z}else return{type:A,value:b.error.syntax(S[y],\"callable expected\")};else return{type:A,value:b.error.syntax(S[y]?S[y]:S[y-1],\". or operator expected\")};return J}function ue(w,S,y){y=y||{},y.from=y.from?y.from:\"$tau-js\",y.reconsult=y.reconsult!==void 0?y.reconsult:!0;var F=new U(w),J={},X;F.new_text(S);var Z=0,ie=F.get_tokens(Z);do{if(ie===null||!ie[Z])break;var be=fe(w,ie,Z);if(be.type===A)return new H(\"throw\",[be.value]);if(be.value.body===null&&be.value.head.indicator===\"?-/1\"){var Le=new Ve(w.session);Le.add_goal(be.value.head.args[0]),Le.answer(function(dt){b.type.is_error(dt)?w.throw_warning(dt.args[0]):(dt===!1||dt===null)&&w.throw_warning(b.warning.failed_goal(be.value.head.args[0],be.len))}),Z=be.len;var ot=!0}else if(be.value.body===null&&be.value.head.indicator===\":-/1\"){var ot=w.run_directive(be.value.head.args[0]);Z=be.len,be.value.head.args[0].indicator===\"char_conversion/2\"&&(ie=F.get_tokens(Z),Z=0)}else{X=be.value.head.indicator,y.reconsult!==!1&&J[X]!==!0&&!w.is_multifile_predicate(X)&&(w.session.rules[X]=a(w.session.rules[X]||[],function(Gt){return Gt.dynamic}),J[X]=!0);var ot=w.add_rule(be.value,y);Z=be.len}if(!ot)return ot}while(!0);return!0}function me(w,S){var y=new U(w);y.new_text(S);var F=0;do{var J=y.get_tokens(F);if(J===null)break;var X=V(w,J,0,w.__get_max_priority(),!1);if(X.type!==A){var Z=X.len,ie=Z;if(J[Z]&&J[Z].name===\"atom\"&&J[Z].raw===\".\")w.add_goal(we(X.value));else{var be=J[Z];return new H(\"throw\",[b.error.syntax(be||J[Z-1],\". or operator expected\",!be)])}F=X.len+1}else return new H(\"throw\",[X.value])}while(!0);return!0}function he(w,S){w=w.rename(S);var y=S.next_free_variable(),F=Be(w.body,y,S);return F.error?F.value:(w.body=F.value,w.head.args=w.head.args.concat([y,F.variable]),w.head=new H(w.head.id,w.head.args),w)}function Be(w,S,y){var F;if(b.type.is_term(w)&&w.indicator===\"!/0\")return{value:w,variable:S,error:!1};if(b.type.is_term(w)&&w.indicator===\",/2\"){var J=Be(w.args[0],S,y);if(J.error)return J;var X=Be(w.args[1],J.variable,y);return X.error?X:{value:new H(\",\",[J.value,X.value]),variable:X.variable,error:!1}}else{if(b.type.is_term(w)&&w.indicator===\"{}/1\")return{value:w.args[0],variable:S,error:!1};if(b.type.is_empty_list(w))return{value:new H(\"true\",[]),variable:S,error:!1};if(b.type.is_list(w)){F=y.next_free_variable();for(var Z=w,ie;Z.indicator===\"./2\";)ie=Z,Z=Z.args[1];return b.type.is_variable(Z)?{value:b.error.instantiation(\"DCG\"),variable:S,error:!0}:b.type.is_empty_list(Z)?(ie.args[1]=F,{value:new H(\"=\",[S,w]),variable:F,error:!1}):{value:b.error.type(\"list\",w,\"DCG\"),variable:S,error:!0}}else return b.type.is_callable(w)?(F=y.next_free_variable(),w.args=w.args.concat([S,F]),w=new H(w.id,w.args),{value:w,variable:F,error:!1}):{value:b.error.type(\"callable\",w,\"DCG\"),variable:S,error:!0}}}function we(w){return b.type.is_variable(w)?new H(\"call\",[w]):b.type.is_term(w)&&[\",/2\",\";/2\",\"->/2\"].indexOf(w.indicator)!==-1?new H(w.id,[we(w.args[0]),we(w.args[1])]):w}function g(w,S){for(var y=S||new b.type.Term(\"[]\",[]),F=w.length-1;F>=0;F--)y=new b.type.Term(\".\",[w[F],y]);return y}function Ee(w,S){for(var y=w.length-1;y>=0;y--)w[y]===S&&w.splice(y,1)}function Pe(w){for(var S={},y=[],F=0;F<w.length;F++)w[F]in S||(y.push(w[F]),S[w[F]]=!0);return y}function ce(w,S,y,F){if(w.session.rules[y]!==null){for(var J=0;J<w.session.rules[y].length;J++)if(w.session.rules[y][J]===F){w.session.rules[y].splice(J,1),w.success(S);break}}}function ne(w){return function(S,y,F){var J=F.args[0],X=F.args.slice(1,w);if(b.type.is_variable(J))S.throw_error(b.error.instantiation(S.level));else if(!b.type.is_callable(J))S.throw_error(b.error.type(\"callable\",J,S.level));else{var Z=new H(J.id,J.args.concat(X));S.prepend([new xe(y.goal.replace(Z),y.substitution,y)])}}}function ee(w){for(var S=w.length-1;S>=0;S--)if(w.charAt(S)===\"/\")return new H(\"/\",[new H(w.substring(0,S)),new Fe(parseInt(w.substring(S+1)),!1)])}function Ie(w){this.id=w}function Fe(w,S){this.is_float=S!==void 0?S:parseInt(w)!==w,this.value=this.is_float?w:parseInt(w)}var At=0;function H(w,S,y){this.ref=y||++At,this.id=w,this.args=S||[],this.indicator=w+\"/\"+this.args.length}var at=0;function Re(w,S,y,F,J,X){this.id=at++,this.stream=w,this.mode=S,this.alias=y,this.type=F!==void 0?F:\"text\",this.reposition=J!==void 0?J:!0,this.eof_action=X!==void 0?X:\"eof_code\",this.position=this.mode===\"append\"?\"end_of_stream\":0,this.output=this.mode===\"write\"||this.mode===\"append\",this.input=this.mode===\"read\"}function ke(w){w=w||{},this.links=w}function xe(w,S,y){S=S||new ke,y=y||null,this.goal=w,this.substitution=S,this.parent=y}function He(w,S,y){this.head=w,this.body=S,this.dynamic=y||!1}function Te(w){w=w===void 0||w<=0?1e3:w,this.rules={},this.src_predicates={},this.rename=0,this.modules=[],this.thread=new Ve(this),this.total_threads=1,this.renamed_variables={},this.public_predicates={},this.multifile_predicates={},this.limit=w,this.streams={user_input:new Re(typeof gl<\"u\"&&gl.exports?nodejs_user_input:tau_user_input,\"read\",\"user_input\",\"text\",!1,\"reset\"),user_output:new Re(typeof gl<\"u\"&&gl.exports?nodejs_user_output:tau_user_output,\"write\",\"user_output\",\"text\",!1,\"eof_code\")},this.file_system=typeof gl<\"u\"&&gl.exports?nodejs_file_system:tau_file_system,this.standard_input=this.streams.user_input,this.standard_output=this.streams.user_output,this.current_input=this.streams.user_input,this.current_output=this.streams.user_output,this.format_success=function(S){return S.substitution},this.format_error=function(S){return S.goal},this.flag={bounded:b.flag.bounded.value,max_integer:b.flag.max_integer.value,min_integer:b.flag.min_integer.value,integer_rounding_function:b.flag.integer_rounding_function.value,char_conversion:b.flag.char_conversion.value,debug:b.flag.debug.value,max_arity:b.flag.max_arity.value,unknown:b.flag.unknown.value,double_quotes:b.flag.double_quotes.value,occurs_check:b.flag.occurs_check.value,dialect:b.flag.dialect.value,version_data:b.flag.version_data.value,nodejs:b.flag.nodejs.value},this.__loaded_modules=[],this.__char_conversion={},this.__operators={1200:{\":-\":[\"fx\",\"xfx\"],\"-->\":[\"xfx\"],\"?-\":[\"fx\"]},1100:{\";\":[\"xfy\"]},1050:{\"->\":[\"xfy\"]},1e3:{\",\":[\"xfy\"]},900:{\"\\\\+\":[\"fy\"]},700:{\"=\":[\"xfx\"],\"\\\\=\":[\"xfx\"],\"==\":[\"xfx\"],\"\\\\==\":[\"xfx\"],\"@<\":[\"xfx\"],\"@=<\":[\"xfx\"],\"@>\":[\"xfx\"],\"@>=\":[\"xfx\"],\"=..\":[\"xfx\"],is:[\"xfx\"],\"=:=\":[\"xfx\"],\"=\\\\=\":[\"xfx\"],\"<\":[\"xfx\"],\"=<\":[\"xfx\"],\">\":[\"xfx\"],\">=\":[\"xfx\"]},600:{\":\":[\"xfy\"]},500:{\"+\":[\"yfx\"],\"-\":[\"yfx\"],\"/\\\\\":[\"yfx\"],\"\\\\/\":[\"yfx\"]},400:{\"*\":[\"yfx\"],\"/\":[\"yfx\"],\"//\":[\"yfx\"],rem:[\"yfx\"],mod:[\"yfx\"],\"<<\":[\"yfx\"],\">>\":[\"yfx\"]},200:{\"**\":[\"xfx\"],\"^\":[\"xfy\"],\"-\":[\"fy\"],\"+\":[\"fy\"],\"\\\\\":[\"fy\"]}}}function Ve(w){this.epoch=Date.now(),this.session=w,this.session.total_threads++,this.total_steps=0,this.cpu_time=0,this.cpu_time_last=0,this.points=[],this.debugger=!1,this.debugger_states=[],this.level=\"top_level/0\",this.__calls=[],this.current_limit=this.session.limit,this.warnings=[]}function qe(w,S,y){this.id=w,this.rules=S,this.exports=y,b.module[w]=this}qe.prototype.exports_predicate=function(w){return this.exports.indexOf(w)!==-1},Ie.prototype.unify=function(w,S){if(S&&e(w.variables(),this.id)!==-1&&!b.type.is_variable(w))return null;var y={};return y[this.id]=w,new ke(y)},Fe.prototype.unify=function(w,S){return b.type.is_number(w)&&this.value===w.value&&this.is_float===w.is_float?new ke:null},H.prototype.unify=function(w,S){if(b.type.is_term(w)&&this.indicator===w.indicator){for(var y=new ke,F=0;F<this.args.length;F++){var J=b.unify(this.args[F].apply(y),w.args[F].apply(y),S);if(J===null)return null;for(var X in J.links)y.links[X]=J.links[X];y=y.apply(J)}return y}return null},Re.prototype.unify=function(w,S){return b.type.is_stream(w)&&this.id===w.id?new ke:null},Ie.prototype.toString=function(w){return this.id},Fe.prototype.toString=function(w){return this.is_float&&e(this.value.toString(),\".\")===-1?this.value+\".0\":this.value.toString()},H.prototype.toString=function(w,S,y){if(w=w||{},w.quoted=w.quoted===void 0?!0:w.quoted,w.ignore_ops=w.ignore_ops===void 0?!1:w.ignore_ops,w.numbervars=w.numbervars===void 0?!1:w.numbervars,S=S===void 0?1200:S,y=y===void 0?\"\":y,w.numbervars&&this.indicator===\"$VAR/1\"&&b.type.is_integer(this.args[0])&&this.args[0].value>=0){var F=this.args[0].value,J=Math.floor(F/26),X=F%26;return\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"[X]+(J!==0?J:\"\")}switch(this.indicator){case\"[]/0\":case\"{}/0\":case\"!/0\":return this.id;case\"{}/1\":return\"{\"+this.args[0].toString(w)+\"}\";case\"./2\":for(var Z=\"[\"+this.args[0].toString(w),ie=this.args[1];ie.indicator===\"./2\";)Z+=\", \"+ie.args[0].toString(w),ie=ie.args[1];return ie.indicator!==\"[]/0\"&&(Z+=\"|\"+ie.toString(w)),Z+=\"]\",Z;case\",/2\":return\"(\"+this.args[0].toString(w)+\", \"+this.args[1].toString(w)+\")\";default:var be=this.id,Le=w.session?w.session.lookup_operator(this.id,this.args.length):null;if(w.session===void 0||w.ignore_ops||Le===null)return w.quoted&&!/^(!|,|;|[a-z][0-9a-zA-Z_]*)$/.test(be)&&be!==\"{}\"&&be!==\"[]\"&&(be=\"'\"+x(be)+\"'\"),be+(this.args.length?\"(\"+o(this.args,function($t){return $t.toString(w)}).join(\", \")+\")\":\"\");var ot=Le.priority>S.priority||Le.priority===S.priority&&(Le.class===\"xfy\"&&this.indicator!==S.indicator||Le.class===\"yfx\"&&this.indicator!==S.indicator||this.indicator===S.indicator&&Le.class===\"yfx\"&&y===\"right\"||this.indicator===S.indicator&&Le.class===\"xfy\"&&y===\"left\");Le.indicator=this.indicator;var dt=ot?\"(\":\"\",Gt=ot?\")\":\"\";return this.args.length===0?\"(\"+this.id+\")\":[\"fy\",\"fx\"].indexOf(Le.class)!==-1?dt+be+\" \"+this.args[0].toString(w,Le)+Gt:[\"yf\",\"xf\"].indexOf(Le.class)!==-1?dt+this.args[0].toString(w,Le)+\" \"+be+Gt:dt+this.args[0].toString(w,Le,\"left\")+\" \"+this.id+\" \"+this.args[1].toString(w,Le,\"right\")+Gt}},Re.prototype.toString=function(w){return\"<stream>(\"+this.id+\")\"},ke.prototype.toString=function(w){var S=\"{\";for(var y in this.links)!this.links.hasOwnProperty(y)||(S!==\"{\"&&(S+=\", \"),S+=y+\"/\"+this.links[y].toString(w));return S+=\"}\",S},xe.prototype.toString=function(w){return this.goal===null?\"<\"+this.substitution.toString(w)+\">\":\"<\"+this.goal.toString(w)+\", \"+this.substitution.toString(w)+\">\"},He.prototype.toString=function(w){return this.body?this.head.toString(w)+\" :- \"+this.body.toString(w)+\".\":this.head.toString(w)+\".\"},Te.prototype.toString=function(w){for(var S=\"\",y=0;y<this.modules.length;y++)S+=\":- use_module(library(\"+this.modules[y]+`)).\n`;S+=`\n`;for(key in this.rules)for(y=0;y<this.rules[key].length;y++)S+=this.rules[key][y].toString(w),S+=`\n`;return S},Ie.prototype.clone=function(){return new Ie(this.id)},Fe.prototype.clone=function(){return new Fe(this.value,this.is_float)},H.prototype.clone=function(){return new H(this.id,o(this.args,function(w){return w.clone()}))},Re.prototype.clone=function(){return new Stram(this.stream,this.mode,this.alias,this.type,this.reposition,this.eof_action)},ke.prototype.clone=function(){var w={};for(var S in this.links)!this.links.hasOwnProperty(S)||(w[S]=this.links[S].clone());return new ke(w)},xe.prototype.clone=function(){return new xe(this.goal.clone(),this.substitution.clone(),this.parent)},He.prototype.clone=function(){return new He(this.head.clone(),this.body!==null?this.body.clone():null)},Ie.prototype.equals=function(w){return b.type.is_variable(w)&&this.id===w.id},Fe.prototype.equals=function(w){return b.type.is_number(w)&&this.value===w.value&&this.is_float===w.is_float},H.prototype.equals=function(w){if(!b.type.is_term(w)||this.indicator!==w.indicator)return!1;for(var S=0;S<this.args.length;S++)if(!this.args[S].equals(w.args[S]))return!1;return!0},Re.prototype.equals=function(w){return b.type.is_stream(w)&&this.id===w.id},ke.prototype.equals=function(w){var S;if(!b.type.is_substitution(w))return!1;for(S in this.links)if(!!this.links.hasOwnProperty(S)&&(!w.links[S]||!this.links[S].equals(w.links[S])))return!1;for(S in w.links)if(!!w.links.hasOwnProperty(S)&&!this.links[S])return!1;return!0},xe.prototype.equals=function(w){return b.type.is_state(w)&&this.goal.equals(w.goal)&&this.substitution.equals(w.substitution)&&this.parent===w.parent},He.prototype.equals=function(w){return b.type.is_rule(w)&&this.head.equals(w.head)&&(this.body===null&&w.body===null||this.body!==null&&this.body.equals(w.body))},Ie.prototype.rename=function(w){return w.get_free_variable(this)},Fe.prototype.rename=function(w){return this},H.prototype.rename=function(w){return new H(this.id,o(this.args,function(S){return S.rename(w)}))},Re.prototype.rename=function(w){return this},He.prototype.rename=function(w){return new He(this.head.rename(w),this.body!==null?this.body.rename(w):null)},Ie.prototype.variables=function(){return[this.id]},Fe.prototype.variables=function(){return[]},H.prototype.variables=function(){return[].concat.apply([],o(this.args,function(w){return w.variables()}))},Re.prototype.variables=function(){return[]},He.prototype.variables=function(){return this.body===null?this.head.variables():this.head.variables().concat(this.body.variables())},Ie.prototype.apply=function(w){return w.lookup(this.id)?w.lookup(this.id):this},Fe.prototype.apply=function(w){return this},H.prototype.apply=function(w){if(this.indicator===\"./2\"){for(var S=[],y=this;y.indicator===\"./2\";)S.push(y.args[0].apply(w)),y=y.args[1];for(var F=y.apply(w),J=S.length-1;J>=0;J--)F=new H(\".\",[S[J],F]);return F}return new H(this.id,o(this.args,function(X){return X.apply(w)}),this.ref)},Re.prototype.apply=function(w){return this},He.prototype.apply=function(w){return new He(this.head.apply(w),this.body!==null?this.body.apply(w):null)},ke.prototype.apply=function(w){var S,y={};for(S in this.links)!this.links.hasOwnProperty(S)||(y[S]=this.links[S].apply(w));return new ke(y)},H.prototype.select=function(){for(var w=this;w.indicator===\",/2\";)w=w.args[0];return w},H.prototype.replace=function(w){return this.indicator===\",/2\"?this.args[0].indicator===\",/2\"?new H(\",\",[this.args[0].replace(w),this.args[1]]):w===null?this.args[1]:new H(\",\",[w,this.args[1]]):w},H.prototype.search=function(w){if(b.type.is_term(w)&&w.ref!==void 0&&this.ref===w.ref)return!0;for(var S=0;S<this.args.length;S++)if(b.type.is_term(this.args[S])&&this.args[S].search(w))return!0;return!1},Te.prototype.get_current_input=function(){return this.current_input},Ve.prototype.get_current_input=function(){return this.session.get_current_input()},Te.prototype.get_current_output=function(){return this.current_output},Ve.prototype.get_current_output=function(){return this.session.get_current_output()},Te.prototype.set_current_input=function(w){this.current_input=w},Ve.prototype.set_current_input=function(w){return this.session.set_current_input(w)},Te.prototype.set_current_output=function(w){this.current_input=w},Ve.prototype.set_current_output=function(w){return this.session.set_current_output(w)},Te.prototype.get_stream_by_alias=function(w){return this.streams[w]},Ve.prototype.get_stream_by_alias=function(w){return this.session.get_stream_by_alias(w)},Te.prototype.file_system_open=function(w,S,y){return this.file_system.open(w,S,y)},Ve.prototype.file_system_open=function(w,S,y){return this.session.file_system_open(w,S,y)},Te.prototype.get_char_conversion=function(w){return this.__char_conversion[w]||w},Ve.prototype.get_char_conversion=function(w){return this.session.get_char_conversion(w)},Te.prototype.parse=function(w){return this.thread.parse(w)},Ve.prototype.parse=function(w){var S=new U(this);S.new_text(w);var y=S.get_tokens();if(y===null)return!1;var F=V(this,y,0,this.__get_max_priority(),!1);return F.len!==y.length?!1:{value:F.value,expr:F,tokens:y}},Te.prototype.get_flag=function(w){return this.flag[w]},Ve.prototype.get_flag=function(w){return this.session.get_flag(w)},Te.prototype.add_rule=function(w,S){return S=S||{},S.from=S.from?S.from:\"$tau-js\",this.src_predicates[w.head.indicator]=S.from,this.rules[w.head.indicator]||(this.rules[w.head.indicator]=[]),this.rules[w.head.indicator].push(w),this.public_predicates.hasOwnProperty(w.head.indicator)||(this.public_predicates[w.head.indicator]=!1),!0},Ve.prototype.add_rule=function(w,S){return this.session.add_rule(w,S)},Te.prototype.run_directive=function(w){this.thread.run_directive(w)},Ve.prototype.run_directive=function(w){return b.type.is_directive(w)?(b.directive[w.indicator](this,w),!0):!1},Te.prototype.__get_max_priority=function(){return\"1200\"},Ve.prototype.__get_max_priority=function(){return this.session.__get_max_priority()},Te.prototype.__get_next_priority=function(w){var S=0;w=parseInt(w);for(var y in this.__operators)if(!!this.__operators.hasOwnProperty(y)){var F=parseInt(y);F>S&&F<w&&(S=F)}return S.toString()},Ve.prototype.__get_next_priority=function(w){return this.session.__get_next_priority(w)},Te.prototype.__lookup_operator_classes=function(w,S){return this.__operators.hasOwnProperty(w)&&this.__operators[w][S]instanceof Array&&this.__operators[w][S]||!1},Ve.prototype.__lookup_operator_classes=function(w,S){return this.session.__lookup_operator_classes(w,S)},Te.prototype.lookup_operator=function(w,S){for(var y in this.__operators)if(this.__operators[y][w]){for(var F=0;F<this.__operators[y][w].length;F++)if(S===0||this.__operators[y][w][F].length===S+1)return{priority:y,class:this.__operators[y][w][F]}}return null},Ve.prototype.lookup_operator=function(w,S){return this.session.lookup_operator(w,S)},Te.prototype.throw_warning=function(w){this.thread.throw_warning(w)},Ve.prototype.throw_warning=function(w){this.warnings.push(w)},Te.prototype.get_warnings=function(){return this.thread.get_warnings()},Ve.prototype.get_warnings=function(){return this.warnings},Te.prototype.add_goal=function(w,S){this.thread.add_goal(w,S)},Ve.prototype.add_goal=function(w,S,y){y=y||null,S===!0&&(this.points=[]);for(var F=w.variables(),J={},X=0;X<F.length;X++)J[F[X]]=new Ie(F[X]);this.points.push(new xe(w,new ke(J),y))},Te.prototype.consult=function(w,S){return this.thread.consult(w,S)},Ve.prototype.consult=function(w,S){var y=\"\";if(typeof w==\"string\"){y=w;var F=y.length;if(y.substring(F-3,F)===\".pl\"&&document.getElementById(y)){var J=document.getElementById(y),X=J.getAttribute(\"type\");X!==null&&X.replace(/ /g,\"\").toLowerCase()===\"text/prolog\"&&(y=J.text)}}else if(w.nodeName)switch(w.nodeName.toLowerCase()){case\"input\":case\"textarea\":y=w.value;break;default:y=w.innerHTML;break}else return!1;return this.warnings=[],ue(this,y,S)},Te.prototype.query=function(w){return this.thread.query(w)},Ve.prototype.query=function(w){return this.points=[],this.debugger_points=[],me(this,w)},Te.prototype.head_point=function(){return this.thread.head_point()},Ve.prototype.head_point=function(){return this.points[this.points.length-1]},Te.prototype.get_free_variable=function(w){return this.thread.get_free_variable(w)},Ve.prototype.get_free_variable=function(w){var S=[];if(w.id===\"_\"||this.session.renamed_variables[w.id]===void 0){for(this.session.rename++,this.points.length>0&&(S=this.head_point().substitution.domain());e(S,b.format_variable(this.session.rename))!==-1;)this.session.rename++;if(w.id===\"_\")return new Ie(b.format_variable(this.session.rename));this.session.renamed_variables[w.id]=b.format_variable(this.session.rename)}return new Ie(this.session.renamed_variables[w.id])},Te.prototype.next_free_variable=function(){return this.thread.next_free_variable()},Ve.prototype.next_free_variable=function(){this.session.rename++;var w=[];for(this.points.length>0&&(w=this.head_point().substitution.domain());e(w,b.format_variable(this.session.rename))!==-1;)this.session.rename++;return new Ie(b.format_variable(this.session.rename))},Te.prototype.is_public_predicate=function(w){return!this.public_predicates.hasOwnProperty(w)||this.public_predicates[w]===!0},Ve.prototype.is_public_predicate=function(w){return this.session.is_public_predicate(w)},Te.prototype.is_multifile_predicate=function(w){return this.multifile_predicates.hasOwnProperty(w)&&this.multifile_predicates[w]===!0},Ve.prototype.is_multifile_predicate=function(w){return this.session.is_multifile_predicate(w)},Te.prototype.prepend=function(w){return this.thread.prepend(w)},Ve.prototype.prepend=function(w){for(var S=w.length-1;S>=0;S--)this.points.push(w[S])},Te.prototype.success=function(w,S){return this.thread.success(w,S)},Ve.prototype.success=function(w,y){var y=typeof y>\"u\"?w:y;this.prepend([new xe(w.goal.replace(null),w.substitution,y)])},Te.prototype.throw_error=function(w){return this.thread.throw_error(w)},Ve.prototype.throw_error=function(w){this.prepend([new xe(new H(\"throw\",[w]),new ke,null,null)])},Te.prototype.step_rule=function(w,S){return this.thread.step_rule(w,S)},Ve.prototype.step_rule=function(w,S){var y=S.indicator;if(w===\"user\"&&(w=null),w===null&&this.session.rules.hasOwnProperty(y))return this.session.rules[y];for(var F=w===null?this.session.modules:e(this.session.modules,w)===-1?[]:[w],J=0;J<F.length;J++){var X=b.module[F[J]];if(X.rules.hasOwnProperty(y)&&(X.rules.hasOwnProperty(this.level)||X.exports_predicate(y)))return b.module[F[J]].rules[y]}return null},Te.prototype.step=function(){return this.thread.step()},Ve.prototype.step=function(){if(this.points.length!==0){var w=!1,S=this.points.pop();if(this.debugger&&this.debugger_states.push(S),b.type.is_term(S.goal)){var y=S.goal.select(),F=null,J=[];if(y!==null){this.total_steps++;for(var X=S;X.parent!==null&&X.parent.goal.search(y);)X=X.parent;if(this.level=X.parent===null?\"top_level/0\":X.parent.goal.select().indicator,b.type.is_term(y)&&y.indicator===\":/2\"&&(F=y.args[0].id,y=y.args[1]),F===null&&b.type.is_builtin(y))this.__call_indicator=y.indicator,w=b.predicate[y.indicator](this,S,y);else{var Z=this.step_rule(F,y);if(Z===null)this.session.rules.hasOwnProperty(y.indicator)||(this.get_flag(\"unknown\").id===\"error\"?this.throw_error(b.error.existence(\"procedure\",y.indicator,this.level)):this.get_flag(\"unknown\").id===\"warning\"&&this.throw_warning(\"unknown procedure \"+y.indicator+\" (from \"+this.level+\")\"));else if(Z instanceof Function)w=Z(this,S,y);else{for(var ie in Z)if(!!Z.hasOwnProperty(ie)){var be=Z[ie];this.session.renamed_variables={},be=be.rename(this);var Le=this.get_flag(\"occurs_check\").indicator===\"true/0\",ot=new xe,dt=b.unify(y,be.head,Le);dt!==null&&(ot.goal=S.goal.replace(be.body),ot.goal!==null&&(ot.goal=ot.goal.apply(dt)),ot.substitution=S.substitution.apply(dt),ot.parent=S,J.push(ot))}this.prepend(J)}}}}else b.type.is_variable(S.goal)?this.throw_error(b.error.instantiation(this.level)):this.throw_error(b.error.type(\"callable\",S.goal,this.level));return w}},Te.prototype.answer=function(w){return this.thread.answer(w)},Ve.prototype.answer=function(w){w=w||function(S){},this.__calls.push(w),!(this.__calls.length>1)&&this.again()},Te.prototype.answers=function(w,S,y){return this.thread.answers(w,S,y)},Ve.prototype.answers=function(w,S,y){var F=S||1e3,J=this;if(S<=0){y&&y();return}this.answer(function(X){w(X),X!==!1?setTimeout(function(){J.answers(w,S-1,y)},1):y&&y()})},Te.prototype.again=function(w){return this.thread.again(w)},Ve.prototype.again=function(w){for(var S,y=Date.now();this.__calls.length>0;){for(this.warnings=[],w!==!1&&(this.current_limit=this.session.limit);this.current_limit>0&&this.points.length>0&&this.head_point().goal!==null&&!b.type.is_error(this.head_point().goal);)if(this.current_limit--,this.step()===!0)return;var F=Date.now();this.cpu_time_last=F-y,this.cpu_time+=this.cpu_time_last;var J=this.__calls.shift();this.current_limit<=0?J(null):this.points.length===0?J(!1):b.type.is_error(this.head_point().goal)?(S=this.session.format_error(this.points.pop()),this.points=[],J(S)):(this.debugger&&this.debugger_states.push(this.head_point()),S=this.session.format_success(this.points.pop()),J(S))}},Te.prototype.unfold=function(w){if(w.body===null)return!1;var S=w.head,y=w.body,F=y.select(),J=new Ve(this),X=[];J.add_goal(F),J.step();for(var Z=J.points.length-1;Z>=0;Z--){var ie=J.points[Z],be=S.apply(ie.substitution),Le=y.replace(ie.goal);Le!==null&&(Le=Le.apply(ie.substitution)),X.push(new He(be,Le))}var ot=this.rules[S.indicator],dt=e(ot,w);return X.length>0&&dt!==-1?(ot.splice.apply(ot,[dt,1].concat(X)),!0):!1},Ve.prototype.unfold=function(w){return this.session.unfold(w)},Ie.prototype.interpret=function(w){return b.error.instantiation(w.level)},Fe.prototype.interpret=function(w){return this},H.prototype.interpret=function(w){return b.type.is_unitary_list(this)?this.args[0].interpret(w):b.operate(w,this)},Ie.prototype.compare=function(w){return this.id<w.id?-1:this.id>w.id?1:0},Fe.prototype.compare=function(w){if(this.value===w.value&&this.is_float===w.is_float)return 0;if(this.value<w.value||this.value===w.value&&this.is_float&&!w.is_float)return-1;if(this.value>w.value)return 1},H.prototype.compare=function(w){if(this.args.length<w.args.length||this.args.length===w.args.length&&this.id<w.id)return-1;if(this.args.length>w.args.length||this.args.length===w.args.length&&this.id>w.id)return 1;for(var S=0;S<this.args.length;S++){var y=b.compare(this.args[S],w.args[S]);if(y!==0)return y}return 0},ke.prototype.lookup=function(w){return this.links[w]?this.links[w]:null},ke.prototype.filter=function(w){var S={};for(var y in this.links)if(!!this.links.hasOwnProperty(y)){var F=this.links[y];w(y,F)&&(S[y]=F)}return new ke(S)},ke.prototype.exclude=function(w){var S={};for(var y in this.links)!this.links.hasOwnProperty(y)||e(w,y)===-1&&(S[y]=this.links[y]);return new ke(S)},ke.prototype.add=function(w,S){this.links[w]=S},ke.prototype.domain=function(w){var S=w===!0?function(J){return J}:function(J){return new Ie(J)},y=[];for(var F in this.links)y.push(S(F));return y},Ie.prototype.compile=function(){return'new pl.type.Var(\"'+this.id.toString()+'\")'},Fe.prototype.compile=function(){return\"new pl.type.Num(\"+this.value.toString()+\", \"+this.is_float.toString()+\")\"},H.prototype.compile=function(){return'new pl.type.Term(\"'+this.id.replace(/\"/g,'\\\\\"')+'\", ['+o(this.args,function(w){return w.compile()})+\"])\"},He.prototype.compile=function(){return\"new pl.type.Rule(\"+this.head.compile()+\", \"+(this.body===null?\"null\":this.body.compile())+\")\"},Te.prototype.compile=function(){var w,S=[],y;for(var F in this.rules)if(!!this.rules.hasOwnProperty(F)){var J=this.rules[F];y=[],w='\"'+F+'\": [';for(var X=0;X<J.length;X++)y.push(J[X].compile());w+=y.join(),w+=\"]\",S.push(w)}return\"{\"+S.join()+\"};\"},Ie.prototype.toJavaScript=function(){},Fe.prototype.toJavaScript=function(){return this.value},H.prototype.toJavaScript=function(){if(this.args.length===0&&this.indicator!==\"[]/0\")return this.id;if(b.type.is_list(this)){for(var w=[],S=this,y;S.indicator===\"./2\";){if(y=S.args[0].toJavaScript(),y===void 0)return;w.push(y),S=S.args[1]}if(S.indicator===\"[]/0\")return w}},He.prototype.singleton_variables=function(){var w=this.head.variables(),S={},y=[];this.body!==null&&(w=w.concat(this.body.variables()));for(var F=0;F<w.length;F++)S[w[F]]===void 0&&(S[w[F]]=0),S[w[F]]++;for(var J in S)J!==\"_\"&&S[J]===1&&y.push(J);return y};var b={__env:typeof gl<\"u\"&&gl.exports?global:window,module:{},version:t,parser:{tokenizer:U,expression:V},utils:{str_indicator:ee,codePointAt:n,fromCodePoint:u},statistics:{getCountTerms:function(){return At}},fromJavaScript:{test:{boolean:function(w){return w===!0||w===!1},number:function(w){return typeof w==\"number\"},string:function(w){return typeof w==\"string\"},list:function(w){return w instanceof Array},variable:function(w){return w===void 0},any:function(w){return!0}},conversion:{boolean:function(w){return new H(w?\"true\":\"false\",[])},number:function(w){return new Fe(w,w%1!==0)},string:function(w){return new H(w,[])},list:function(w){for(var S=[],y,F=0;F<w.length;F++){if(y=b.fromJavaScript.apply(w[F]),y===void 0)return;S.push(y)}return g(S)},variable:function(w){return new Ie(\"_\")},any:function(w){}},apply:function(w){for(var S in b.fromJavaScript.test)if(S!==\"any\"&&b.fromJavaScript.test[S](w))return b.fromJavaScript.conversion[S](w);return b.fromJavaScript.conversion.any(w)}},type:{Var:Ie,Num:Fe,Term:H,Rule:He,State:xe,Stream:Re,Module:qe,Thread:Ve,Session:Te,Substitution:ke,order:[Ie,Fe,H,Re],compare:function(w,S){var y=e(b.type.order,w.constructor),F=e(b.type.order,S.constructor);if(y<F)return-1;if(y>F)return 1;if(w.constructor===Fe){if(w.is_float&&S.is_float)return 0;if(w.is_float)return-1;if(S.is_float)return 1}return 0},is_substitution:function(w){return w instanceof ke},is_state:function(w){return w instanceof xe},is_rule:function(w){return w instanceof He},is_variable:function(w){return w instanceof Ie},is_stream:function(w){return w instanceof Re},is_anonymous_var:function(w){return w instanceof Ie&&w.id===\"_\"},is_callable:function(w){return w instanceof H},is_number:function(w){return w instanceof Fe},is_integer:function(w){return w instanceof Fe&&!w.is_float},is_float:function(w){return w instanceof Fe&&w.is_float},is_term:function(w){return w instanceof H},is_atom:function(w){return w instanceof H&&w.args.length===0},is_ground:function(w){if(w instanceof Ie)return!1;if(w instanceof H){for(var S=0;S<w.args.length;S++)if(!b.type.is_ground(w.args[S]))return!1}return!0},is_atomic:function(w){return w instanceof H&&w.args.length===0||w instanceof Fe},is_compound:function(w){return w instanceof H&&w.args.length>0},is_list:function(w){return w instanceof H&&(w.indicator===\"[]/0\"||w.indicator===\"./2\")},is_empty_list:function(w){return w instanceof H&&w.indicator===\"[]/0\"},is_non_empty_list:function(w){return w instanceof H&&w.indicator===\"./2\"},is_fully_list:function(w){for(;w instanceof H&&w.indicator===\"./2\";)w=w.args[1];return w instanceof Ie||w instanceof H&&w.indicator===\"[]/0\"},is_instantiated_list:function(w){for(;w instanceof H&&w.indicator===\"./2\";)w=w.args[1];return w instanceof H&&w.indicator===\"[]/0\"},is_unitary_list:function(w){return w instanceof H&&w.indicator===\"./2\"&&w.args[1]instanceof H&&w.args[1].indicator===\"[]/0\"},is_character:function(w){return w instanceof H&&(w.id.length===1||w.id.length>0&&w.id.length<=2&&n(w.id,0)>=65536)},is_character_code:function(w){return w instanceof Fe&&!w.is_float&&w.value>=0&&w.value<=1114111},is_byte:function(w){return w instanceof Fe&&!w.is_float&&w.value>=0&&w.value<=255},is_operator:function(w){return w instanceof H&&b.arithmetic.evaluation[w.indicator]},is_directive:function(w){return w instanceof H&&b.directive[w.indicator]!==void 0},is_builtin:function(w){return w instanceof H&&b.predicate[w.indicator]!==void 0},is_error:function(w){return w instanceof H&&w.indicator===\"throw/1\"},is_predicate_indicator:function(w){return w instanceof H&&w.indicator===\"//2\"&&w.args[0]instanceof H&&w.args[0].args.length===0&&w.args[1]instanceof Fe&&w.args[1].is_float===!1},is_flag:function(w){return w instanceof H&&w.args.length===0&&b.flag[w.id]!==void 0},is_value_flag:function(w,S){if(!b.type.is_flag(w))return!1;for(var y in b.flag[w.id].allowed)if(!!b.flag[w.id].allowed.hasOwnProperty(y)&&b.flag[w.id].allowed[y].equals(S))return!0;return!1},is_io_mode:function(w){return b.type.is_atom(w)&&[\"read\",\"write\",\"append\"].indexOf(w.id)!==-1},is_stream_option:function(w){return b.type.is_term(w)&&(w.indicator===\"alias/1\"&&b.type.is_atom(w.args[0])||w.indicator===\"reposition/1\"&&b.type.is_atom(w.args[0])&&(w.args[0].id===\"true\"||w.args[0].id===\"false\")||w.indicator===\"type/1\"&&b.type.is_atom(w.args[0])&&(w.args[0].id===\"text\"||w.args[0].id===\"binary\")||w.indicator===\"eof_action/1\"&&b.type.is_atom(w.args[0])&&(w.args[0].id===\"error\"||w.args[0].id===\"eof_code\"||w.args[0].id===\"reset\"))},is_stream_position:function(w){return b.type.is_integer(w)&&w.value>=0||b.type.is_atom(w)&&(w.id===\"end_of_stream\"||w.id===\"past_end_of_stream\")},is_stream_property:function(w){return b.type.is_term(w)&&(w.indicator===\"input/0\"||w.indicator===\"output/0\"||w.indicator===\"alias/1\"&&(b.type.is_variable(w.args[0])||b.type.is_atom(w.args[0]))||w.indicator===\"file_name/1\"&&(b.type.is_variable(w.args[0])||b.type.is_atom(w.args[0]))||w.indicator===\"position/1\"&&(b.type.is_variable(w.args[0])||b.type.is_stream_position(w.args[0]))||w.indicator===\"reposition/1\"&&(b.type.is_variable(w.args[0])||b.type.is_atom(w.args[0])&&(w.args[0].id===\"true\"||w.args[0].id===\"false\"))||w.indicator===\"type/1\"&&(b.type.is_variable(w.args[0])||b.type.is_atom(w.args[0])&&(w.args[0].id===\"text\"||w.args[0].id===\"binary\"))||w.indicator===\"mode/1\"&&(b.type.is_variable(w.args[0])||b.type.is_atom(w.args[0])&&(w.args[0].id===\"read\"||w.args[0].id===\"write\"||w.args[0].id===\"append\"))||w.indicator===\"eof_action/1\"&&(b.type.is_variable(w.args[0])||b.type.is_atom(w.args[0])&&(w.args[0].id===\"error\"||w.args[0].id===\"eof_code\"||w.args[0].id===\"reset\"))||w.indicator===\"end_of_stream/1\"&&(b.type.is_variable(w.args[0])||b.type.is_atom(w.args[0])&&(w.args[0].id===\"at\"||w.args[0].id===\"past\"||w.args[0].id===\"not\")))},is_streamable:function(w){return w.__proto__.stream!==void 0},is_read_option:function(w){return b.type.is_term(w)&&[\"variables/1\",\"variable_names/1\",\"singletons/1\"].indexOf(w.indicator)!==-1},is_write_option:function(w){return b.type.is_term(w)&&(w.indicator===\"quoted/1\"&&b.type.is_atom(w.args[0])&&(w.args[0].id===\"true\"||w.args[0].id===\"false\")||w.indicator===\"ignore_ops/1\"&&b.type.is_atom(w.args[0])&&(w.args[0].id===\"true\"||w.args[0].id===\"false\")||w.indicator===\"numbervars/1\"&&b.type.is_atom(w.args[0])&&(w.args[0].id===\"true\"||w.args[0].id===\"false\"))},is_close_option:function(w){return b.type.is_term(w)&&w.indicator===\"force/1\"&&b.type.is_atom(w.args[0])&&(w.args[0].id===\"true\"||w.args[0].id===\"false\")},is_modifiable_flag:function(w){return b.type.is_flag(w)&&b.flag[w.id].changeable},is_module:function(w){return w instanceof H&&w.indicator===\"library/1\"&&w.args[0]instanceof H&&w.args[0].args.length===0&&b.module[w.args[0].id]!==void 0}},arithmetic:{evaluation:{\"e/0\":{type_args:null,type_result:!0,fn:function(w){return Math.E}},\"pi/0\":{type_args:null,type_result:!0,fn:function(w){return Math.PI}},\"tau/0\":{type_args:null,type_result:!0,fn:function(w){return 2*Math.PI}},\"epsilon/0\":{type_args:null,type_result:!0,fn:function(w){return Number.EPSILON}},\"+/1\":{type_args:null,type_result:null,fn:function(w,S){return w}},\"-/1\":{type_args:null,type_result:null,fn:function(w,S){return-w}},\"\\\\/1\":{type_args:!1,type_result:!1,fn:function(w,S){return~w}},\"abs/1\":{type_args:null,type_result:null,fn:function(w,S){return Math.abs(w)}},\"sign/1\":{type_args:null,type_result:null,fn:function(w,S){return Math.sign(w)}},\"float_integer_part/1\":{type_args:!0,type_result:!1,fn:function(w,S){return parseInt(w)}},\"float_fractional_part/1\":{type_args:!0,type_result:!0,fn:function(w,S){return w-parseInt(w)}},\"float/1\":{type_args:null,type_result:!0,fn:function(w,S){return parseFloat(w)}},\"floor/1\":{type_args:!0,type_result:!1,fn:function(w,S){return Math.floor(w)}},\"truncate/1\":{type_args:!0,type_result:!1,fn:function(w,S){return parseInt(w)}},\"round/1\":{type_args:!0,type_result:!1,fn:function(w,S){return Math.round(w)}},\"ceiling/1\":{type_args:!0,type_result:!1,fn:function(w,S){return Math.ceil(w)}},\"sin/1\":{type_args:null,type_result:!0,fn:function(w,S){return Math.sin(w)}},\"cos/1\":{type_args:null,type_result:!0,fn:function(w,S){return Math.cos(w)}},\"tan/1\":{type_args:null,type_result:!0,fn:function(w,S){return Math.tan(w)}},\"asin/1\":{type_args:null,type_result:!0,fn:function(w,S){return Math.asin(w)}},\"acos/1\":{type_args:null,type_result:!0,fn:function(w,S){return Math.acos(w)}},\"atan/1\":{type_args:null,type_result:!0,fn:function(w,S){return Math.atan(w)}},\"atan2/2\":{type_args:null,type_result:!0,fn:function(w,S,y){return Math.atan2(w,S)}},\"exp/1\":{type_args:null,type_result:!0,fn:function(w,S){return Math.exp(w)}},\"sqrt/1\":{type_args:null,type_result:!0,fn:function(w,S){return Math.sqrt(w)}},\"log/1\":{type_args:null,type_result:!0,fn:function(w,S){return w>0?Math.log(w):b.error.evaluation(\"undefined\",S.__call_indicator)}},\"+/2\":{type_args:null,type_result:null,fn:function(w,S,y){return w+S}},\"-/2\":{type_args:null,type_result:null,fn:function(w,S,y){return w-S}},\"*/2\":{type_args:null,type_result:null,fn:function(w,S,y){return w*S}},\"//2\":{type_args:null,type_result:!0,fn:function(w,S,y){return S?w/S:b.error.evaluation(\"zero_division\",y.__call_indicator)}},\"///2\":{type_args:!1,type_result:!1,fn:function(w,S,y){return S?parseInt(w/S):b.error.evaluation(\"zero_division\",y.__call_indicator)}},\"**/2\":{type_args:null,type_result:!0,fn:function(w,S,y){return Math.pow(w,S)}},\"^/2\":{type_args:null,type_result:null,fn:function(w,S,y){return Math.pow(w,S)}},\"<</2\":{type_args:!1,type_result:!1,fn:function(w,S,y){return w<<S}},\">>/2\":{type_args:!1,type_result:!1,fn:function(w,S,y){return w>>S}},\"/\\\\/2\":{type_args:!1,type_result:!1,fn:function(w,S,y){return w&S}},\"\\\\//2\":{type_args:!1,type_result:!1,fn:function(w,S,y){return w|S}},\"xor/2\":{type_args:!1,type_result:!1,fn:function(w,S,y){return w^S}},\"rem/2\":{type_args:!1,type_result:!1,fn:function(w,S,y){return S?w%S:b.error.evaluation(\"zero_division\",y.__call_indicator)}},\"mod/2\":{type_args:!1,type_result:!1,fn:function(w,S,y){return S?w-parseInt(w/S)*S:b.error.evaluation(\"zero_division\",y.__call_indicator)}},\"max/2\":{type_args:null,type_result:null,fn:function(w,S,y){return Math.max(w,S)}},\"min/2\":{type_args:null,type_result:null,fn:function(w,S,y){return Math.min(w,S)}}}},directive:{\"dynamic/1\":function(w,S){var y=S.args[0];if(b.type.is_variable(y))w.throw_error(b.error.instantiation(S.indicator));else if(!b.type.is_compound(y)||y.indicator!==\"//2\")w.throw_error(b.error.type(\"predicate_indicator\",y,S.indicator));else if(b.type.is_variable(y.args[0])||b.type.is_variable(y.args[1]))w.throw_error(b.error.instantiation(S.indicator));else if(!b.type.is_atom(y.args[0]))w.throw_error(b.error.type(\"atom\",y.args[0],S.indicator));else if(!b.type.is_integer(y.args[1]))w.throw_error(b.error.type(\"integer\",y.args[1],S.indicator));else{var F=S.args[0].args[0].id+\"/\"+S.args[0].args[1].value;w.session.public_predicates[F]=!0,w.session.rules[F]||(w.session.rules[F]=[])}},\"multifile/1\":function(w,S){var y=S.args[0];b.type.is_variable(y)?w.throw_error(b.error.instantiation(S.indicator)):!b.type.is_compound(y)||y.indicator!==\"//2\"?w.throw_error(b.error.type(\"predicate_indicator\",y,S.indicator)):b.type.is_variable(y.args[0])||b.type.is_variable(y.args[1])?w.throw_error(b.error.instantiation(S.indicator)):b.type.is_atom(y.args[0])?b.type.is_integer(y.args[1])?w.session.multifile_predicates[S.args[0].args[0].id+\"/\"+S.args[0].args[1].value]=!0:w.throw_error(b.error.type(\"integer\",y.args[1],S.indicator)):w.throw_error(b.error.type(\"atom\",y.args[0],S.indicator))},\"set_prolog_flag/2\":function(w,S){var y=S.args[0],F=S.args[1];b.type.is_variable(y)||b.type.is_variable(F)?w.throw_error(b.error.instantiation(S.indicator)):b.type.is_atom(y)?b.type.is_flag(y)?b.type.is_value_flag(y,F)?b.type.is_modifiable_flag(y)?w.session.flag[y.id]=F:w.throw_error(b.error.permission(\"modify\",\"flag\",y)):w.throw_error(b.error.domain(\"flag_value\",new H(\"+\",[y,F]),S.indicator)):w.throw_error(b.error.domain(\"prolog_flag\",y,S.indicator)):w.throw_error(b.error.type(\"atom\",y,S.indicator))},\"use_module/1\":function(w,S){var y=S.args[0];if(b.type.is_variable(y))w.throw_error(b.error.instantiation(S.indicator));else if(!b.type.is_term(y))w.throw_error(b.error.type(\"term\",y,S.indicator));else if(b.type.is_module(y)){var F=y.args[0].id;e(w.session.modules,F)===-1&&w.session.modules.push(F)}},\"char_conversion/2\":function(w,S){var y=S.args[0],F=S.args[1];b.type.is_variable(y)||b.type.is_variable(F)?w.throw_error(b.error.instantiation(S.indicator)):b.type.is_character(y)?b.type.is_character(F)?y.id===F.id?delete w.session.__char_conversion[y.id]:w.session.__char_conversion[y.id]=F.id:w.throw_error(b.error.type(\"character\",F,S.indicator)):w.throw_error(b.error.type(\"character\",y,S.indicator))},\"op/3\":function(w,S){var y=S.args[0],F=S.args[1],J=S.args[2];if(b.type.is_variable(y)||b.type.is_variable(F)||b.type.is_variable(J))w.throw_error(b.error.instantiation(S.indicator));else if(!b.type.is_integer(y))w.throw_error(b.error.type(\"integer\",y,S.indicator));else if(!b.type.is_atom(F))w.throw_error(b.error.type(\"atom\",F,S.indicator));else if(!b.type.is_atom(J))w.throw_error(b.error.type(\"atom\",J,S.indicator));else if(y.value<0||y.value>1200)w.throw_error(b.error.domain(\"operator_priority\",y,S.indicator));else if(J.id===\",\")w.throw_error(b.error.permission(\"modify\",\"operator\",J,S.indicator));else if(J.id===\"|\"&&(y.value<1001||F.id.length!==3))w.throw_error(b.error.permission(\"modify\",\"operator\",J,S.indicator));else if([\"fy\",\"fx\",\"yf\",\"xf\",\"xfx\",\"yfx\",\"xfy\"].indexOf(F.id)===-1)w.throw_error(b.error.domain(\"operator_specifier\",F,S.indicator));else{var X={prefix:null,infix:null,postfix:null};for(var Z in w.session.__operators)if(!!w.session.__operators.hasOwnProperty(Z)){var ie=w.session.__operators[Z][J.id];ie&&(e(ie,\"fx\")!==-1&&(X.prefix={priority:Z,type:\"fx\"}),e(ie,\"fy\")!==-1&&(X.prefix={priority:Z,type:\"fy\"}),e(ie,\"xf\")!==-1&&(X.postfix={priority:Z,type:\"xf\"}),e(ie,\"yf\")!==-1&&(X.postfix={priority:Z,type:\"yf\"}),e(ie,\"xfx\")!==-1&&(X.infix={priority:Z,type:\"xfx\"}),e(ie,\"xfy\")!==-1&&(X.infix={priority:Z,type:\"xfy\"}),e(ie,\"yfx\")!==-1&&(X.infix={priority:Z,type:\"yfx\"}))}var be;switch(F.id){case\"fy\":case\"fx\":be=\"prefix\";break;case\"yf\":case\"xf\":be=\"postfix\";break;default:be=\"infix\";break}if(((X.prefix&&be===\"prefix\"||X.postfix&&be===\"postfix\"||X.infix&&be===\"infix\")&&X[be].type!==F.id||X.infix&&be===\"postfix\"||X.postfix&&be===\"infix\")&&y.value!==0)w.throw_error(b.error.permission(\"create\",\"operator\",J,S.indicator));else return X[be]&&(Ee(w.session.__operators[X[be].priority][J.id],F.id),w.session.__operators[X[be].priority][J.id].length===0&&delete w.session.__operators[X[be].priority][J.id]),y.value>0&&(w.session.__operators[y.value]||(w.session.__operators[y.value.toString()]={}),w.session.__operators[y.value][J.id]||(w.session.__operators[y.value][J.id]=[]),w.session.__operators[y.value][J.id].push(F.id)),!0}}},predicate:{\"op/3\":function(w,S,y){b.directive[\"op/3\"](w,y)&&w.success(S)},\"current_op/3\":function(w,S,y){var F=y.args[0],J=y.args[1],X=y.args[2],Z=[];for(var ie in w.session.__operators)for(var be in w.session.__operators[ie])for(var Le=0;Le<w.session.__operators[ie][be].length;Le++)Z.push(new xe(S.goal.replace(new H(\",\",[new H(\"=\",[new Fe(ie,!1),F]),new H(\",\",[new H(\"=\",[new H(w.session.__operators[ie][be][Le],[]),J]),new H(\"=\",[new H(be,[]),X])])])),S.substitution,S));w.prepend(Z)},\";/2\":function(w,S,y){if(b.type.is_term(y.args[0])&&y.args[0].indicator===\"->/2\"){var F=w.points,J=w.session.format_success,X=w.session.format_error;w.session.format_success=function(Le){return Le.substitution},w.session.format_error=function(Le){return Le.goal},w.points=[new xe(y.args[0].args[0],S.substitution,S)];var Z=function(Le){w.points=F,w.session.format_success=J,w.session.format_error=X,Le===!1?w.prepend([new xe(S.goal.replace(y.args[1]),S.substitution,S)]):b.type.is_error(Le)?w.throw_error(Le.args[0]):Le===null?(w.prepend([S]),w.__calls.shift()(null)):w.prepend([new xe(S.goal.replace(y.args[0].args[1]).apply(Le),S.substitution.apply(Le),S)])};w.__calls.unshift(Z)}else{var ie=new xe(S.goal.replace(y.args[0]),S.substitution,S),be=new xe(S.goal.replace(y.args[1]),S.substitution,S);w.prepend([ie,be])}},\"!/0\":function(w,S,y){var F,J,X=[];for(F=S,J=null;F.parent!==null&&F.parent.goal.search(y);)if(J=F,F=F.parent,F.goal!==null){var Z=F.goal.select();if(Z&&Z.id===\"call\"&&Z.search(y)){F=J;break}}for(var ie=w.points.length-1;ie>=0;ie--){for(var be=w.points[ie],Le=be.parent;Le!==null&&Le!==F.parent;)Le=Le.parent;Le===null&&Le!==F.parent&&X.push(be)}w.points=X.reverse(),w.success(S)},\"\\\\+/1\":function(w,S,y){var F=y.args[0];b.type.is_variable(F)?w.throw_error(b.error.instantiation(w.level)):b.type.is_callable(F)?w.prepend([new xe(S.goal.replace(new H(\",\",[new H(\",\",[new H(\"call\",[F]),new H(\"!\",[])]),new H(\"fail\",[])])),S.substitution,S),new xe(S.goal.replace(null),S.substitution,S)]):w.throw_error(b.error.type(\"callable\",F,w.level))},\"->/2\":function(w,S,y){var F=S.goal.replace(new H(\",\",[y.args[0],new H(\",\",[new H(\"!\"),y.args[1]])]));w.prepend([new xe(F,S.substitution,S)])},\"fail/0\":function(w,S,y){},\"false/0\":function(w,S,y){},\"true/0\":function(w,S,y){w.success(S)},\"call/1\":ne(1),\"call/2\":ne(2),\"call/3\":ne(3),\"call/4\":ne(4),\"call/5\":ne(5),\"call/6\":ne(6),\"call/7\":ne(7),\"call/8\":ne(8),\"once/1\":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(\",\",[new H(\"call\",[F]),new H(\"!\",[])])),S.substitution,S)])},\"forall/2\":function(w,S,y){var F=y.args[0],J=y.args[1];w.prepend([new xe(S.goal.replace(new H(\"\\\\+\",[new H(\",\",[new H(\"call\",[F]),new H(\"\\\\+\",[new H(\"call\",[J])])])])),S.substitution,S)])},\"repeat/0\":function(w,S,y){w.prepend([new xe(S.goal.replace(null),S.substitution,S),S])},\"throw/1\":function(w,S,y){b.type.is_variable(y.args[0])?w.throw_error(b.error.instantiation(w.level)):w.throw_error(y.args[0])},\"catch/3\":function(w,S,y){var F=w.points;w.points=[],w.prepend([new xe(y.args[0],S.substitution,S)]);var J=w.session.format_success,X=w.session.format_error;w.session.format_success=function(ie){return ie.substitution},w.session.format_error=function(ie){return ie.goal};var Z=function(ie){var be=w.points;if(w.points=F,w.session.format_success=J,w.session.format_error=X,b.type.is_error(ie)){for(var Le=[],ot=w.points.length-1;ot>=0;ot--){for(var $t=w.points[ot],dt=$t.parent;dt!==null&&dt!==S.parent;)dt=dt.parent;dt===null&&dt!==S.parent&&Le.push($t)}w.points=Le;var Gt=w.get_flag(\"occurs_check\").indicator===\"true/0\",$t=new xe,bt=b.unify(ie.args[0],y.args[1],Gt);bt!==null?($t.substitution=S.substitution.apply(bt),$t.goal=S.goal.replace(y.args[2]).apply(bt),$t.parent=S,w.prepend([$t])):w.throw_error(ie.args[0])}else if(ie!==!1){for(var an=ie===null?[]:[new xe(S.goal.apply(ie).replace(null),S.substitution.apply(ie),S)],Qr=[],ot=be.length-1;ot>=0;ot--){Qr.push(be[ot]);var mr=be[ot].goal!==null?be[ot].goal.select():null;if(b.type.is_term(mr)&&mr.indicator===\"!/0\")break}var br=o(Qr,function(Wr){return Wr.goal===null&&(Wr.goal=new H(\"true\",[])),Wr=new xe(S.goal.replace(new H(\"catch\",[Wr.goal,y.args[1],y.args[2]])),S.substitution.apply(Wr.substitution),Wr.parent),Wr.exclude=y.args[0].variables(),Wr}).reverse();w.prepend(br),w.prepend(an),ie===null&&(this.current_limit=0,w.__calls.shift()(null))}};w.__calls.unshift(Z)},\"=/2\":function(w,S,y){var F=w.get_flag(\"occurs_check\").indicator===\"true/0\",J=new xe,X=b.unify(y.args[0],y.args[1],F);X!==null&&(J.goal=S.goal.apply(X).replace(null),J.substitution=S.substitution.apply(X),J.parent=S,w.prepend([J]))},\"unify_with_occurs_check/2\":function(w,S,y){var F=new xe,J=b.unify(y.args[0],y.args[1],!0);J!==null&&(F.goal=S.goal.apply(J).replace(null),F.substitution=S.substitution.apply(J),F.parent=S,w.prepend([F]))},\"\\\\=/2\":function(w,S,y){var F=w.get_flag(\"occurs_check\").indicator===\"true/0\",J=b.unify(y.args[0],y.args[1],F);J===null&&w.success(S)},\"subsumes_term/2\":function(w,S,y){var F=w.get_flag(\"occurs_check\").indicator===\"true/0\",J=b.unify(y.args[1],y.args[0],F);J!==null&&y.args[1].apply(J).equals(y.args[1])&&w.success(S)},\"findall/3\":function(w,S,y){var F=y.args[0],J=y.args[1],X=y.args[2];if(b.type.is_variable(J))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_callable(J))w.throw_error(b.error.type(\"callable\",J,y.indicator));else if(!b.type.is_variable(X)&&!b.type.is_list(X))w.throw_error(b.error.type(\"list\",X,y.indicator));else{var Z=w.next_free_variable(),ie=new H(\",\",[J,new H(\"=\",[Z,F])]),be=w.points,Le=w.session.limit,ot=w.session.format_success;w.session.format_success=function($t){return $t.substitution},w.add_goal(ie,!0,S);var dt=[],Gt=function($t){if($t!==!1&&$t!==null&&!b.type.is_error($t))w.__calls.unshift(Gt),dt.push($t.links[Z.id]),w.session.limit=w.current_limit;else if(w.points=be,w.session.limit=Le,w.session.format_success=ot,b.type.is_error($t))w.throw_error($t.args[0]);else if(w.current_limit>0){for(var bt=new H(\"[]\"),an=dt.length-1;an>=0;an--)bt=new H(\".\",[dt[an],bt]);w.prepend([new xe(S.goal.replace(new H(\"=\",[X,bt])),S.substitution,S)])}};w.__calls.unshift(Gt)}},\"bagof/3\":function(w,S,y){var F,J=y.args[0],X=y.args[1],Z=y.args[2];if(b.type.is_variable(X))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_callable(X))w.throw_error(b.error.type(\"callable\",X,y.indicator));else if(!b.type.is_variable(Z)&&!b.type.is_list(Z))w.throw_error(b.error.type(\"list\",Z,y.indicator));else{var ie=w.next_free_variable(),be;X.indicator===\"^/2\"?(be=X.args[0].variables(),X=X.args[1]):be=[],be=be.concat(J.variables());for(var Le=X.variables().filter(function(br){return e(be,br)===-1}),ot=new H(\"[]\"),dt=Le.length-1;dt>=0;dt--)ot=new H(\".\",[new Ie(Le[dt]),ot]);var Gt=new H(\",\",[X,new H(\"=\",[ie,new H(\",\",[ot,J])])]),$t=w.points,bt=w.session.limit,an=w.session.format_success;w.session.format_success=function(br){return br.substitution},w.add_goal(Gt,!0,S);var Qr=[],mr=function(br){if(br!==!1&&br!==null&&!b.type.is_error(br)){w.__calls.unshift(mr);var Wr=!1,Kn=br.links[ie.id].args[0],Ls=br.links[ie.id].args[1];for(var Ti in Qr)if(!!Qr.hasOwnProperty(Ti)){var ps=Qr[Ti];if(ps.variables.equals(Kn)){ps.answers.push(Ls),Wr=!0;break}}Wr||Qr.push({variables:Kn,answers:[Ls]}),w.session.limit=w.current_limit}else if(w.points=$t,w.session.limit=bt,w.session.format_success=an,b.type.is_error(br))w.throw_error(br.args[0]);else if(w.current_limit>0){for(var io=[],Si=0;Si<Qr.length;Si++){br=Qr[Si].answers;for(var Ns=new H(\"[]\"),so=br.length-1;so>=0;so--)Ns=new H(\".\",[br[so],Ns]);io.push(new xe(S.goal.replace(new H(\",\",[new H(\"=\",[ot,Qr[Si].variables]),new H(\"=\",[Z,Ns])])),S.substitution,S))}w.prepend(io)}};w.__calls.unshift(mr)}},\"setof/3\":function(w,S,y){var F,J=y.args[0],X=y.args[1],Z=y.args[2];if(b.type.is_variable(X))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_callable(X))w.throw_error(b.error.type(\"callable\",X,y.indicator));else if(!b.type.is_variable(Z)&&!b.type.is_list(Z))w.throw_error(b.error.type(\"list\",Z,y.indicator));else{var ie=w.next_free_variable(),be;X.indicator===\"^/2\"?(be=X.args[0].variables(),X=X.args[1]):be=[],be=be.concat(J.variables());for(var Le=X.variables().filter(function(br){return e(be,br)===-1}),ot=new H(\"[]\"),dt=Le.length-1;dt>=0;dt--)ot=new H(\".\",[new Ie(Le[dt]),ot]);var Gt=new H(\",\",[X,new H(\"=\",[ie,new H(\",\",[ot,J])])]),$t=w.points,bt=w.session.limit,an=w.session.format_success;w.session.format_success=function(br){return br.substitution},w.add_goal(Gt,!0,S);var Qr=[],mr=function(br){if(br!==!1&&br!==null&&!b.type.is_error(br)){w.__calls.unshift(mr);var Wr=!1,Kn=br.links[ie.id].args[0],Ls=br.links[ie.id].args[1];for(var Ti in Qr)if(!!Qr.hasOwnProperty(Ti)){var ps=Qr[Ti];if(ps.variables.equals(Kn)){ps.answers.push(Ls),Wr=!0;break}}Wr||Qr.push({variables:Kn,answers:[Ls]}),w.session.limit=w.current_limit}else if(w.points=$t,w.session.limit=bt,w.session.format_success=an,b.type.is_error(br))w.throw_error(br.args[0]);else if(w.current_limit>0){for(var io=[],Si=0;Si<Qr.length;Si++){br=Qr[Si].answers.sort(b.compare);for(var Ns=new H(\"[]\"),so=br.length-1;so>=0;so--)Ns=new H(\".\",[br[so],Ns]);io.push(new xe(S.goal.replace(new H(\",\",[new H(\"=\",[ot,Qr[Si].variables]),new H(\"=\",[Z,Ns])])),S.substitution,S))}w.prepend(io)}};w.__calls.unshift(mr)}},\"functor/3\":function(w,S,y){var F,J=y.args[0],X=y.args[1],Z=y.args[2];if(b.type.is_variable(J)&&(b.type.is_variable(X)||b.type.is_variable(Z)))w.throw_error(b.error.instantiation(\"functor/3\"));else if(!b.type.is_variable(Z)&&!b.type.is_integer(Z))w.throw_error(b.error.type(\"integer\",y.args[2],\"functor/3\"));else if(!b.type.is_variable(X)&&!b.type.is_atomic(X))w.throw_error(b.error.type(\"atomic\",y.args[1],\"functor/3\"));else if(b.type.is_integer(X)&&b.type.is_integer(Z)&&Z.value!==0)w.throw_error(b.error.type(\"atom\",y.args[1],\"functor/3\"));else if(b.type.is_variable(J)){if(y.args[2].value>=0){for(var ie=[],be=0;be<Z.value;be++)ie.push(w.next_free_variable());var Le=b.type.is_integer(X)?X:new H(X.id,ie);w.prepend([new xe(S.goal.replace(new H(\"=\",[J,Le])),S.substitution,S)])}}else{var ot=b.type.is_integer(J)?J:new H(J.id,[]),dt=b.type.is_integer(J)?new Fe(0,!1):new Fe(J.args.length,!1),Gt=new H(\",\",[new H(\"=\",[ot,X]),new H(\"=\",[dt,Z])]);w.prepend([new xe(S.goal.replace(Gt),S.substitution,S)])}},\"arg/3\":function(w,S,y){if(b.type.is_variable(y.args[0])||b.type.is_variable(y.args[1]))w.throw_error(b.error.instantiation(y.indicator));else if(y.args[0].value<0)w.throw_error(b.error.domain(\"not_less_than_zero\",y.args[0],y.indicator));else if(!b.type.is_compound(y.args[1]))w.throw_error(b.error.type(\"compound\",y.args[1],y.indicator));else{var F=y.args[0].value;if(F>0&&F<=y.args[1].args.length){var J=new H(\"=\",[y.args[1].args[F-1],y.args[2]]);w.prepend([new xe(S.goal.replace(J),S.substitution,S)])}}},\"=../2\":function(w,S,y){var F;if(b.type.is_variable(y.args[0])&&(b.type.is_variable(y.args[1])||b.type.is_non_empty_list(y.args[1])&&b.type.is_variable(y.args[1].args[0])))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_fully_list(y.args[1]))w.throw_error(b.error.type(\"list\",y.args[1],y.indicator));else if(b.type.is_variable(y.args[0])){if(!b.type.is_variable(y.args[1])){var X=[];for(F=y.args[1].args[1];F.indicator===\"./2\";)X.push(F.args[0]),F=F.args[1];b.type.is_variable(y.args[0])&&b.type.is_variable(F)?w.throw_error(b.error.instantiation(y.indicator)):X.length===0&&b.type.is_compound(y.args[1].args[0])?w.throw_error(b.error.type(\"atomic\",y.args[1].args[0],y.indicator)):X.length>0&&(b.type.is_compound(y.args[1].args[0])||b.type.is_number(y.args[1].args[0]))?w.throw_error(b.error.type(\"atom\",y.args[1].args[0],y.indicator)):X.length===0?w.prepend([new xe(S.goal.replace(new H(\"=\",[y.args[1].args[0],y.args[0]],S)),S.substitution,S)]):w.prepend([new xe(S.goal.replace(new H(\"=\",[new H(y.args[1].args[0].id,X),y.args[0]])),S.substitution,S)])}}else{if(b.type.is_atomic(y.args[0]))F=new H(\".\",[y.args[0],new H(\"[]\")]);else{F=new H(\"[]\");for(var J=y.args[0].args.length-1;J>=0;J--)F=new H(\".\",[y.args[0].args[J],F]);F=new H(\".\",[new H(y.args[0].id),F])}w.prepend([new xe(S.goal.replace(new H(\"=\",[F,y.args[1]])),S.substitution,S)])}},\"copy_term/2\":function(w,S,y){var F=y.args[0].rename(w);w.prepend([new xe(S.goal.replace(new H(\"=\",[F,y.args[1]])),S.substitution,S.parent)])},\"term_variables/2\":function(w,S,y){var F=y.args[0],J=y.args[1];if(!b.type.is_fully_list(J))w.throw_error(b.error.type(\"list\",J,y.indicator));else{var X=g(o(Pe(F.variables()),function(Z){return new Ie(Z)}));w.prepend([new xe(S.goal.replace(new H(\"=\",[J,X])),S.substitution,S)])}},\"clause/2\":function(w,S,y){if(b.type.is_variable(y.args[0]))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_callable(y.args[0]))w.throw_error(b.error.type(\"callable\",y.args[0],y.indicator));else if(!b.type.is_variable(y.args[1])&&!b.type.is_callable(y.args[1]))w.throw_error(b.error.type(\"callable\",y.args[1],y.indicator));else if(w.session.rules[y.args[0].indicator]!==void 0)if(w.is_public_predicate(y.args[0].indicator)){var F=[];for(var J in w.session.rules[y.args[0].indicator])if(!!w.session.rules[y.args[0].indicator].hasOwnProperty(J)){var X=w.session.rules[y.args[0].indicator][J];w.session.renamed_variables={},X=X.rename(w),X.body===null&&(X.body=new H(\"true\"));var Z=new H(\",\",[new H(\"=\",[X.head,y.args[0]]),new H(\"=\",[X.body,y.args[1]])]);F.push(new xe(S.goal.replace(Z),S.substitution,S))}w.prepend(F)}else w.throw_error(b.error.permission(\"access\",\"private_procedure\",y.args[0].indicator,y.indicator))},\"current_predicate/1\":function(w,S,y){var F=y.args[0];if(!b.type.is_variable(F)&&(!b.type.is_compound(F)||F.indicator!==\"//2\"))w.throw_error(b.error.type(\"predicate_indicator\",F,y.indicator));else if(!b.type.is_variable(F)&&!b.type.is_variable(F.args[0])&&!b.type.is_atom(F.args[0]))w.throw_error(b.error.type(\"atom\",F.args[0],y.indicator));else if(!b.type.is_variable(F)&&!b.type.is_variable(F.args[1])&&!b.type.is_integer(F.args[1]))w.throw_error(b.error.type(\"integer\",F.args[1],y.indicator));else{var J=[];for(var X in w.session.rules)if(!!w.session.rules.hasOwnProperty(X)){var Z=X.lastIndexOf(\"/\"),ie=X.substr(0,Z),be=parseInt(X.substr(Z+1,X.length-(Z+1))),Le=new H(\"/\",[new H(ie),new Fe(be,!1)]),ot=new H(\"=\",[Le,F]);J.push(new xe(S.goal.replace(ot),S.substitution,S))}w.prepend(J)}},\"asserta/1\":function(w,S,y){if(b.type.is_variable(y.args[0]))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_callable(y.args[0]))w.throw_error(b.error.type(\"callable\",y.args[0],y.indicator));else{var F,J;y.args[0].indicator===\":-/2\"?(F=y.args[0].args[0],J=we(y.args[0].args[1])):(F=y.args[0],J=null),b.type.is_callable(F)?J!==null&&!b.type.is_callable(J)?w.throw_error(b.error.type(\"callable\",J,y.indicator)):w.is_public_predicate(F.indicator)?(w.session.rules[F.indicator]===void 0&&(w.session.rules[F.indicator]=[]),w.session.public_predicates[F.indicator]=!0,w.session.rules[F.indicator]=[new He(F,J,!0)].concat(w.session.rules[F.indicator]),w.success(S)):w.throw_error(b.error.permission(\"modify\",\"static_procedure\",F.indicator,y.indicator)):w.throw_error(b.error.type(\"callable\",F,y.indicator))}},\"assertz/1\":function(w,S,y){if(b.type.is_variable(y.args[0]))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_callable(y.args[0]))w.throw_error(b.error.type(\"callable\",y.args[0],y.indicator));else{var F,J;y.args[0].indicator===\":-/2\"?(F=y.args[0].args[0],J=we(y.args[0].args[1])):(F=y.args[0],J=null),b.type.is_callable(F)?J!==null&&!b.type.is_callable(J)?w.throw_error(b.error.type(\"callable\",J,y.indicator)):w.is_public_predicate(F.indicator)?(w.session.rules[F.indicator]===void 0&&(w.session.rules[F.indicator]=[]),w.session.public_predicates[F.indicator]=!0,w.session.rules[F.indicator].push(new He(F,J,!0)),w.success(S)):w.throw_error(b.error.permission(\"modify\",\"static_procedure\",F.indicator,y.indicator)):w.throw_error(b.error.type(\"callable\",F,y.indicator))}},\"retract/1\":function(w,S,y){if(b.type.is_variable(y.args[0]))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_callable(y.args[0]))w.throw_error(b.error.type(\"callable\",y.args[0],y.indicator));else{var F,J;if(y.args[0].indicator===\":-/2\"?(F=y.args[0].args[0],J=y.args[0].args[1]):(F=y.args[0],J=new H(\"true\")),typeof S.retract>\"u\")if(w.is_public_predicate(F.indicator)){if(w.session.rules[F.indicator]!==void 0){for(var X=[],Z=0;Z<w.session.rules[F.indicator].length;Z++){w.session.renamed_variables={};var ie=w.session.rules[F.indicator][Z],be=ie.rename(w);be.body===null&&(be.body=new H(\"true\",[]));var Le=w.get_flag(\"occurs_check\").indicator===\"true/0\",ot=b.unify(new H(\",\",[F,J]),new H(\",\",[be.head,be.body]),Le);if(ot!==null){var dt=new xe(S.goal.replace(new H(\",\",[new H(\"retract\",[new H(\":-\",[F,J])]),new H(\",\",[new H(\"=\",[F,be.head]),new H(\"=\",[J,be.body])])])),S.substitution,S);dt.retract=ie,X.push(dt)}}w.prepend(X)}}else w.throw_error(b.error.permission(\"modify\",\"static_procedure\",F.indicator,y.indicator));else ce(w,S,F.indicator,S.retract)}},\"retractall/1\":function(w,S,y){var F=y.args[0];b.type.is_variable(F)?w.throw_error(b.error.instantiation(y.indicator)):b.type.is_callable(F)?w.prepend([new xe(S.goal.replace(new H(\",\",[new H(\"retract\",[new b.type.Term(\":-\",[F,new Ie(\"_\")])]),new H(\"fail\",[])])),S.substitution,S),new xe(S.goal.replace(null),S.substitution,S)]):w.throw_error(b.error.type(\"callable\",F,y.indicator))},\"abolish/1\":function(w,S,y){if(b.type.is_variable(y.args[0])||b.type.is_term(y.args[0])&&y.args[0].indicator===\"//2\"&&(b.type.is_variable(y.args[0].args[0])||b.type.is_variable(y.args[0].args[1])))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_term(y.args[0])||y.args[0].indicator!==\"//2\")w.throw_error(b.error.type(\"predicate_indicator\",y.args[0],y.indicator));else if(!b.type.is_atom(y.args[0].args[0]))w.throw_error(b.error.type(\"atom\",y.args[0].args[0],y.indicator));else if(!b.type.is_integer(y.args[0].args[1]))w.throw_error(b.error.type(\"integer\",y.args[0].args[1],y.indicator));else if(y.args[0].args[1].value<0)w.throw_error(b.error.domain(\"not_less_than_zero\",y.args[0].args[1],y.indicator));else if(b.type.is_number(w.get_flag(\"max_arity\"))&&y.args[0].args[1].value>w.get_flag(\"max_arity\").value)w.throw_error(b.error.representation(\"max_arity\",y.indicator));else{var F=y.args[0].args[0].id+\"/\"+y.args[0].args[1].value;w.is_public_predicate(F)?(delete w.session.rules[F],w.success(S)):w.throw_error(b.error.permission(\"modify\",\"static_procedure\",F,y.indicator))}},\"atom_length/2\":function(w,S,y){if(b.type.is_variable(y.args[0]))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_atom(y.args[0]))w.throw_error(b.error.type(\"atom\",y.args[0],y.indicator));else if(!b.type.is_variable(y.args[1])&&!b.type.is_integer(y.args[1]))w.throw_error(b.error.type(\"integer\",y.args[1],y.indicator));else if(b.type.is_integer(y.args[1])&&y.args[1].value<0)w.throw_error(b.error.domain(\"not_less_than_zero\",y.args[1],y.indicator));else{var F=new Fe(y.args[0].id.length,!1);w.prepend([new xe(S.goal.replace(new H(\"=\",[F,y.args[1]])),S.substitution,S)])}},\"atom_concat/3\":function(w,S,y){var F,J,X=y.args[0],Z=y.args[1],ie=y.args[2];if(b.type.is_variable(ie)&&(b.type.is_variable(X)||b.type.is_variable(Z)))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(X)&&!b.type.is_atom(X))w.throw_error(b.error.type(\"atom\",X,y.indicator));else if(!b.type.is_variable(Z)&&!b.type.is_atom(Z))w.throw_error(b.error.type(\"atom\",Z,y.indicator));else if(!b.type.is_variable(ie)&&!b.type.is_atom(ie))w.throw_error(b.error.type(\"atom\",ie,y.indicator));else{var be=b.type.is_variable(X),Le=b.type.is_variable(Z);if(!be&&!Le)J=new H(\"=\",[ie,new H(X.id+Z.id)]),w.prepend([new xe(S.goal.replace(J),S.substitution,S)]);else if(be&&!Le)F=ie.id.substr(0,ie.id.length-Z.id.length),F+Z.id===ie.id&&(J=new H(\"=\",[X,new H(F)]),w.prepend([new xe(S.goal.replace(J),S.substitution,S)]));else if(Le&&!be)F=ie.id.substr(X.id.length),X.id+F===ie.id&&(J=new H(\"=\",[Z,new H(F)]),w.prepend([new xe(S.goal.replace(J),S.substitution,S)]));else{for(var ot=[],dt=0;dt<=ie.id.length;dt++){var Gt=new H(ie.id.substr(0,dt)),$t=new H(ie.id.substr(dt));J=new H(\",\",[new H(\"=\",[Gt,X]),new H(\"=\",[$t,Z])]),ot.push(new xe(S.goal.replace(J),S.substitution,S))}w.prepend(ot)}}},\"sub_atom/5\":function(w,S,y){var F,J=y.args[0],X=y.args[1],Z=y.args[2],ie=y.args[3],be=y.args[4];if(b.type.is_variable(J))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(X)&&!b.type.is_integer(X))w.throw_error(b.error.type(\"integer\",X,y.indicator));else if(!b.type.is_variable(Z)&&!b.type.is_integer(Z))w.throw_error(b.error.type(\"integer\",Z,y.indicator));else if(!b.type.is_variable(ie)&&!b.type.is_integer(ie))w.throw_error(b.error.type(\"integer\",ie,y.indicator));else if(b.type.is_integer(X)&&X.value<0)w.throw_error(b.error.domain(\"not_less_than_zero\",X,y.indicator));else if(b.type.is_integer(Z)&&Z.value<0)w.throw_error(b.error.domain(\"not_less_than_zero\",Z,y.indicator));else if(b.type.is_integer(ie)&&ie.value<0)w.throw_error(b.error.domain(\"not_less_than_zero\",ie,y.indicator));else{var Le=[],ot=[],dt=[];if(b.type.is_variable(X))for(F=0;F<=J.id.length;F++)Le.push(F);else Le.push(X.value);if(b.type.is_variable(Z))for(F=0;F<=J.id.length;F++)ot.push(F);else ot.push(Z.value);if(b.type.is_variable(ie))for(F=0;F<=J.id.length;F++)dt.push(F);else dt.push(ie.value);var Gt=[];for(var $t in Le)if(!!Le.hasOwnProperty($t)){F=Le[$t];for(var bt in ot)if(!!ot.hasOwnProperty(bt)){var an=ot[bt],Qr=J.id.length-F-an;if(e(dt,Qr)!==-1&&F+an+Qr===J.id.length){var mr=J.id.substr(F,an);if(J.id===J.id.substr(0,F)+mr+J.id.substr(F+an,Qr)){var br=new H(\"=\",[new H(mr),be]),Wr=new H(\"=\",[X,new Fe(F)]),Kn=new H(\"=\",[Z,new Fe(an)]),Ls=new H(\"=\",[ie,new Fe(Qr)]),Ti=new H(\",\",[new H(\",\",[new H(\",\",[Wr,Kn]),Ls]),br]);Gt.push(new xe(S.goal.replace(Ti),S.substitution,S))}}}}w.prepend(Gt)}},\"atom_chars/2\":function(w,S,y){var F=y.args[0],J=y.args[1];if(b.type.is_variable(F)&&b.type.is_variable(J))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(F)&&!b.type.is_atom(F))w.throw_error(b.error.type(\"atom\",F,y.indicator));else if(b.type.is_variable(F)){for(var ie=J,be=b.type.is_variable(F),Le=\"\";ie.indicator===\"./2\";){if(b.type.is_character(ie.args[0]))Le+=ie.args[0].id;else if(b.type.is_variable(ie.args[0])&&be){w.throw_error(b.error.instantiation(y.indicator));return}else if(!b.type.is_variable(ie.args[0])){w.throw_error(b.error.type(\"character\",ie.args[0],y.indicator));return}ie=ie.args[1]}b.type.is_variable(ie)&&be?w.throw_error(b.error.instantiation(y.indicator)):!b.type.is_empty_list(ie)&&!b.type.is_variable(ie)?w.throw_error(b.error.type(\"list\",J,y.indicator)):w.prepend([new xe(S.goal.replace(new H(\"=\",[new H(Le),F])),S.substitution,S)])}else{for(var X=new H(\"[]\"),Z=F.id.length-1;Z>=0;Z--)X=new H(\".\",[new H(F.id.charAt(Z)),X]);w.prepend([new xe(S.goal.replace(new H(\"=\",[J,X])),S.substitution,S)])}},\"atom_codes/2\":function(w,S,y){var F=y.args[0],J=y.args[1];if(b.type.is_variable(F)&&b.type.is_variable(J))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(F)&&!b.type.is_atom(F))w.throw_error(b.error.type(\"atom\",F,y.indicator));else if(b.type.is_variable(F)){for(var ie=J,be=b.type.is_variable(F),Le=\"\";ie.indicator===\"./2\";){if(b.type.is_character_code(ie.args[0]))Le+=u(ie.args[0].value);else if(b.type.is_variable(ie.args[0])&&be){w.throw_error(b.error.instantiation(y.indicator));return}else if(!b.type.is_variable(ie.args[0])){w.throw_error(b.error.representation(\"character_code\",y.indicator));return}ie=ie.args[1]}b.type.is_variable(ie)&&be?w.throw_error(b.error.instantiation(y.indicator)):!b.type.is_empty_list(ie)&&!b.type.is_variable(ie)?w.throw_error(b.error.type(\"list\",J,y.indicator)):w.prepend([new xe(S.goal.replace(new H(\"=\",[new H(Le),F])),S.substitution,S)])}else{for(var X=new H(\"[]\"),Z=F.id.length-1;Z>=0;Z--)X=new H(\".\",[new Fe(n(F.id,Z),!1),X]);w.prepend([new xe(S.goal.replace(new H(\"=\",[J,X])),S.substitution,S)])}},\"char_code/2\":function(w,S,y){var F=y.args[0],J=y.args[1];if(b.type.is_variable(F)&&b.type.is_variable(J))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(F)&&!b.type.is_character(F))w.throw_error(b.error.type(\"character\",F,y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_integer(J))w.throw_error(b.error.type(\"integer\",J,y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_character_code(J))w.throw_error(b.error.representation(\"character_code\",y.indicator));else if(b.type.is_variable(J)){var X=new Fe(n(F.id,0),!1);w.prepend([new xe(S.goal.replace(new H(\"=\",[X,J])),S.substitution,S)])}else{var Z=new H(u(J.value));w.prepend([new xe(S.goal.replace(new H(\"=\",[Z,F])),S.substitution,S)])}},\"number_chars/2\":function(w,S,y){var F,J=y.args[0],X=y.args[1];if(b.type.is_variable(J)&&b.type.is_variable(X))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_number(J))w.throw_error(b.error.type(\"number\",J,y.indicator));else if(!b.type.is_variable(X)&&!b.type.is_list(X))w.throw_error(b.error.type(\"list\",X,y.indicator));else{var Z=b.type.is_variable(J);if(!b.type.is_variable(X)){var ie=X,be=!0;for(F=\"\";ie.indicator===\"./2\";){if(b.type.is_character(ie.args[0]))F+=ie.args[0].id;else if(b.type.is_variable(ie.args[0]))be=!1;else if(!b.type.is_variable(ie.args[0])){w.throw_error(b.error.type(\"character\",ie.args[0],y.indicator));return}ie=ie.args[1]}if(be=be&&b.type.is_empty_list(ie),!b.type.is_empty_list(ie)&&!b.type.is_variable(ie)){w.throw_error(b.error.type(\"list\",X,y.indicator));return}if(!be&&Z){w.throw_error(b.error.instantiation(y.indicator));return}else if(be)if(b.type.is_variable(ie)&&Z){w.throw_error(b.error.instantiation(y.indicator));return}else{var Le=w.parse(F),ot=Le.value;!b.type.is_number(ot)||Le.tokens[Le.tokens.length-1].space?w.throw_error(b.error.syntax_by_predicate(\"parseable_number\",y.indicator)):w.prepend([new xe(S.goal.replace(new H(\"=\",[J,ot])),S.substitution,S)]);return}}if(!Z){F=J.toString();for(var dt=new H(\"[]\"),Gt=F.length-1;Gt>=0;Gt--)dt=new H(\".\",[new H(F.charAt(Gt)),dt]);w.prepend([new xe(S.goal.replace(new H(\"=\",[X,dt])),S.substitution,S)])}}},\"number_codes/2\":function(w,S,y){var F,J=y.args[0],X=y.args[1];if(b.type.is_variable(J)&&b.type.is_variable(X))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_number(J))w.throw_error(b.error.type(\"number\",J,y.indicator));else if(!b.type.is_variable(X)&&!b.type.is_list(X))w.throw_error(b.error.type(\"list\",X,y.indicator));else{var Z=b.type.is_variable(J);if(!b.type.is_variable(X)){var ie=X,be=!0;for(F=\"\";ie.indicator===\"./2\";){if(b.type.is_character_code(ie.args[0]))F+=u(ie.args[0].value);else if(b.type.is_variable(ie.args[0]))be=!1;else if(!b.type.is_variable(ie.args[0])){w.throw_error(b.error.type(\"character_code\",ie.args[0],y.indicator));return}ie=ie.args[1]}if(be=be&&b.type.is_empty_list(ie),!b.type.is_empty_list(ie)&&!b.type.is_variable(ie)){w.throw_error(b.error.type(\"list\",X,y.indicator));return}if(!be&&Z){w.throw_error(b.error.instantiation(y.indicator));return}else if(be)if(b.type.is_variable(ie)&&Z){w.throw_error(b.error.instantiation(y.indicator));return}else{var Le=w.parse(F),ot=Le.value;!b.type.is_number(ot)||Le.tokens[Le.tokens.length-1].space?w.throw_error(b.error.syntax_by_predicate(\"parseable_number\",y.indicator)):w.prepend([new xe(S.goal.replace(new H(\"=\",[J,ot])),S.substitution,S)]);return}}if(!Z){F=J.toString();for(var dt=new H(\"[]\"),Gt=F.length-1;Gt>=0;Gt--)dt=new H(\".\",[new Fe(n(F,Gt),!1),dt]);w.prepend([new xe(S.goal.replace(new H(\"=\",[X,dt])),S.substitution,S)])}}},\"upcase_atom/2\":function(w,S,y){var F=y.args[0],J=y.args[1];b.type.is_variable(F)?w.throw_error(b.error.instantiation(y.indicator)):b.type.is_atom(F)?!b.type.is_variable(J)&&!b.type.is_atom(J)?w.throw_error(b.error.type(\"atom\",J,y.indicator)):w.prepend([new xe(S.goal.replace(new H(\"=\",[J,new H(F.id.toUpperCase(),[])])),S.substitution,S)]):w.throw_error(b.error.type(\"atom\",F,y.indicator))},\"downcase_atom/2\":function(w,S,y){var F=y.args[0],J=y.args[1];b.type.is_variable(F)?w.throw_error(b.error.instantiation(y.indicator)):b.type.is_atom(F)?!b.type.is_variable(J)&&!b.type.is_atom(J)?w.throw_error(b.error.type(\"atom\",J,y.indicator)):w.prepend([new xe(S.goal.replace(new H(\"=\",[J,new H(F.id.toLowerCase(),[])])),S.substitution,S)]):w.throw_error(b.error.type(\"atom\",F,y.indicator))},\"atomic_list_concat/2\":function(w,S,y){var F=y.args[0],J=y.args[1];w.prepend([new xe(S.goal.replace(new H(\"atomic_list_concat\",[F,new H(\"\",[]),J])),S.substitution,S)])},\"atomic_list_concat/3\":function(w,S,y){var F=y.args[0],J=y.args[1],X=y.args[2];if(b.type.is_variable(J)||b.type.is_variable(F)&&b.type.is_variable(X))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(F)&&!b.type.is_list(F))w.throw_error(b.error.type(\"list\",F,y.indicator));else if(!b.type.is_variable(X)&&!b.type.is_atom(X))w.throw_error(b.error.type(\"atom\",X,y.indicator));else if(b.type.is_variable(X)){for(var ie=\"\",be=F;b.type.is_term(be)&&be.indicator===\"./2\";){if(!b.type.is_atom(be.args[0])&&!b.type.is_number(be.args[0])){w.throw_error(b.error.type(\"atomic\",be.args[0],y.indicator));return}ie!==\"\"&&(ie+=J.id),b.type.is_atom(be.args[0])?ie+=be.args[0].id:ie+=\"\"+be.args[0].value,be=be.args[1]}ie=new H(ie,[]),b.type.is_variable(be)?w.throw_error(b.error.instantiation(y.indicator)):!b.type.is_term(be)||be.indicator!==\"[]/0\"?w.throw_error(b.error.type(\"list\",F,y.indicator)):w.prepend([new xe(S.goal.replace(new H(\"=\",[ie,X])),S.substitution,S)])}else{var Z=g(o(X.id.split(J.id),function(Le){return new H(Le,[])}));w.prepend([new xe(S.goal.replace(new H(\"=\",[Z,F])),S.substitution,S)])}},\"@=</2\":function(w,S,y){b.compare(y.args[0],y.args[1])<=0&&w.success(S)},\"==/2\":function(w,S,y){b.compare(y.args[0],y.args[1])===0&&w.success(S)},\"\\\\==/2\":function(w,S,y){b.compare(y.args[0],y.args[1])!==0&&w.success(S)},\"@</2\":function(w,S,y){b.compare(y.args[0],y.args[1])<0&&w.success(S)},\"@>/2\":function(w,S,y){b.compare(y.args[0],y.args[1])>0&&w.success(S)},\"@>=/2\":function(w,S,y){b.compare(y.args[0],y.args[1])>=0&&w.success(S)},\"compare/3\":function(w,S,y){var F=y.args[0],J=y.args[1],X=y.args[2];if(!b.type.is_variable(F)&&!b.type.is_atom(F))w.throw_error(b.error.type(\"atom\",F,y.indicator));else if(b.type.is_atom(F)&&[\"<\",\">\",\"=\"].indexOf(F.id)===-1)w.throw_error(b.type.domain(\"order\",F,y.indicator));else{var Z=b.compare(J,X);Z=Z===0?\"=\":Z===-1?\"<\":\">\",w.prepend([new xe(S.goal.replace(new H(\"=\",[F,new H(Z,[])])),S.substitution,S)])}},\"is/2\":function(w,S,y){var F=y.args[1].interpret(w);b.type.is_number(F)?w.prepend([new xe(S.goal.replace(new H(\"=\",[y.args[0],F],w.level)),S.substitution,S)]):w.throw_error(F)},\"between/3\":function(w,S,y){var F=y.args[0],J=y.args[1],X=y.args[2];if(b.type.is_variable(F)||b.type.is_variable(J))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_integer(F))w.throw_error(b.error.type(\"integer\",F,y.indicator));else if(!b.type.is_integer(J))w.throw_error(b.error.type(\"integer\",J,y.indicator));else if(!b.type.is_variable(X)&&!b.type.is_integer(X))w.throw_error(b.error.type(\"integer\",X,y.indicator));else if(b.type.is_variable(X)){var Z=[new xe(S.goal.replace(new H(\"=\",[X,F])),S.substitution,S)];F.value<J.value&&Z.push(new xe(S.goal.replace(new H(\"between\",[new Fe(F.value+1,!1),J,X])),S.substitution,S)),w.prepend(Z)}else F.value<=X.value&&J.value>=X.value&&w.success(S)},\"succ/2\":function(w,S,y){var F=y.args[0],J=y.args[1];b.type.is_variable(F)&&b.type.is_variable(J)?w.throw_error(b.error.instantiation(y.indicator)):!b.type.is_variable(F)&&!b.type.is_integer(F)?w.throw_error(b.error.type(\"integer\",F,y.indicator)):!b.type.is_variable(J)&&!b.type.is_integer(J)?w.throw_error(b.error.type(\"integer\",J,y.indicator)):!b.type.is_variable(F)&&F.value<0?w.throw_error(b.error.domain(\"not_less_than_zero\",F,y.indicator)):!b.type.is_variable(J)&&J.value<0?w.throw_error(b.error.domain(\"not_less_than_zero\",J,y.indicator)):(b.type.is_variable(J)||J.value>0)&&(b.type.is_variable(F)?w.prepend([new xe(S.goal.replace(new H(\"=\",[F,new Fe(J.value-1,!1)])),S.substitution,S)]):w.prepend([new xe(S.goal.replace(new H(\"=\",[J,new Fe(F.value+1,!1)])),S.substitution,S)]))},\"=:=/2\":function(w,S,y){var F=b.arithmetic_compare(w,y.args[0],y.args[1]);b.type.is_term(F)?w.throw_error(F):F===0&&w.success(S)},\"=\\\\=/2\":function(w,S,y){var F=b.arithmetic_compare(w,y.args[0],y.args[1]);b.type.is_term(F)?w.throw_error(F):F!==0&&w.success(S)},\"</2\":function(w,S,y){var F=b.arithmetic_compare(w,y.args[0],y.args[1]);b.type.is_term(F)?w.throw_error(F):F<0&&w.success(S)},\"=</2\":function(w,S,y){var F=b.arithmetic_compare(w,y.args[0],y.args[1]);b.type.is_term(F)?w.throw_error(F):F<=0&&w.success(S)},\">/2\":function(w,S,y){var F=b.arithmetic_compare(w,y.args[0],y.args[1]);b.type.is_term(F)?w.throw_error(F):F>0&&w.success(S)},\">=/2\":function(w,S,y){var F=b.arithmetic_compare(w,y.args[0],y.args[1]);b.type.is_term(F)?w.throw_error(F):F>=0&&w.success(S)},\"var/1\":function(w,S,y){b.type.is_variable(y.args[0])&&w.success(S)},\"atom/1\":function(w,S,y){b.type.is_atom(y.args[0])&&w.success(S)},\"atomic/1\":function(w,S,y){b.type.is_atomic(y.args[0])&&w.success(S)},\"compound/1\":function(w,S,y){b.type.is_compound(y.args[0])&&w.success(S)},\"integer/1\":function(w,S,y){b.type.is_integer(y.args[0])&&w.success(S)},\"float/1\":function(w,S,y){b.type.is_float(y.args[0])&&w.success(S)},\"number/1\":function(w,S,y){b.type.is_number(y.args[0])&&w.success(S)},\"nonvar/1\":function(w,S,y){b.type.is_variable(y.args[0])||w.success(S)},\"ground/1\":function(w,S,y){y.variables().length===0&&w.success(S)},\"acyclic_term/1\":function(w,S,y){for(var F=S.substitution.apply(S.substitution),J=y.args[0].variables(),X=0;X<J.length;X++)if(S.substitution.links[J[X]]!==void 0&&!S.substitution.links[J[X]].equals(F.links[J[X]]))return;w.success(S)},\"callable/1\":function(w,S,y){b.type.is_callable(y.args[0])&&w.success(S)},\"is_list/1\":function(w,S,y){for(var F=y.args[0];b.type.is_term(F)&&F.indicator===\"./2\";)F=F.args[1];b.type.is_term(F)&&F.indicator===\"[]/0\"&&w.success(S)},\"current_input/1\":function(w,S,y){var F=y.args[0];!b.type.is_variable(F)&&!b.type.is_stream(F)&&!b.type.is_atom(F)?w.throw_error(b.error.domain(\"stream\",F,y.indicator)):(b.type.is_atom(F)&&w.get_stream_by_alias(F.id)&&(F=w.get_stream_by_alias(F.id)),w.prepend([new xe(S.goal.replace(new H(\"=\",[F,w.get_current_input()])),S.substitution,S)]))},\"current_output/1\":function(w,S,y){var F=y.args[0];!b.type.is_variable(F)&&!b.type.is_stream(F)&&!b.type.is_atom(F)?w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator)):(b.type.is_atom(F)&&w.get_stream_by_alias(F.id)&&(F=w.get_stream_by_alias(F.id)),w.prepend([new xe(S.goal.replace(new H(\"=\",[F,w.get_current_output()])),S.substitution,S)]))},\"set_input/1\":function(w,S,y){var F=y.args[0],J=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);b.type.is_variable(F)?w.throw_error(b.error.instantiation(y.indicator)):!b.type.is_variable(F)&&!b.type.is_stream(F)&&!b.type.is_atom(F)?w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator)):b.type.is_stream(J)?J.output===!0?w.throw_error(b.error.permission(\"input\",\"stream\",F,y.indicator)):(w.set_current_input(J),w.success(S)):w.throw_error(b.error.existence(\"stream\",F,y.indicator))},\"set_output/1\":function(w,S,y){var F=y.args[0],J=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);b.type.is_variable(F)?w.throw_error(b.error.instantiation(y.indicator)):!b.type.is_variable(F)&&!b.type.is_stream(F)&&!b.type.is_atom(F)?w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator)):b.type.is_stream(J)?J.input===!0?w.throw_error(b.error.permission(\"output\",\"stream\",F,y.indicator)):(w.set_current_output(J),w.success(S)):w.throw_error(b.error.existence(\"stream\",F,y.indicator))},\"open/3\":function(w,S,y){var F=y.args[0],J=y.args[1],X=y.args[2];w.prepend([new xe(S.goal.replace(new H(\"open\",[F,J,X,new H(\"[]\",[])])),S.substitution,S)])},\"open/4\":function(w,S,y){var F=y.args[0],J=y.args[1],X=y.args[2],Z=y.args[3];if(b.type.is_variable(F)||b.type.is_variable(J))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_atom(J))w.throw_error(b.error.type(\"atom\",J,y.indicator));else if(!b.type.is_list(Z))w.throw_error(b.error.type(\"list\",Z,y.indicator));else if(!b.type.is_variable(X))w.throw_error(b.error.type(\"variable\",X,y.indicator));else if(!b.type.is_atom(F)&&!b.type.is_streamable(F))w.throw_error(b.error.domain(\"source_sink\",F,y.indicator));else if(!b.type.is_io_mode(J))w.throw_error(b.error.domain(\"io_mode\",J,y.indicator));else{for(var ie={},be=Z,Le;b.type.is_term(be)&&be.indicator===\"./2\";){if(Le=be.args[0],b.type.is_variable(Le)){w.throw_error(b.error.instantiation(y.indicator));return}else if(!b.type.is_stream_option(Le)){w.throw_error(b.error.domain(\"stream_option\",Le,y.indicator));return}ie[Le.id]=Le.args[0].id,be=be.args[1]}if(be.indicator!==\"[]/0\"){b.type.is_variable(be)?w.throw_error(b.error.instantiation(y.indicator)):w.throw_error(b.error.type(\"list\",Z,y.indicator));return}else{var ot=ie.alias;if(ot&&w.get_stream_by_alias(ot)){w.throw_error(b.error.permission(\"open\",\"source_sink\",new H(\"alias\",[new H(ot,[])]),y.indicator));return}ie.type||(ie.type=\"text\");var dt;if(b.type.is_atom(F)?dt=w.file_system_open(F.id,ie.type,J.id):dt=F.stream(ie.type,J.id),dt===!1){w.throw_error(b.error.permission(\"open\",\"source_sink\",F,y.indicator));return}else if(dt===null){w.throw_error(b.error.existence(\"source_sink\",F,y.indicator));return}var Gt=new Re(dt,J.id,ie.alias,ie.type,ie.reposition===\"true\",ie.eof_action);ot?w.session.streams[ot]=Gt:w.session.streams[Gt.id]=Gt,w.prepend([new xe(S.goal.replace(new H(\"=\",[X,Gt])),S.substitution,S)])}}},\"close/1\":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(\"close\",[F,new H(\"[]\",[])])),S.substitution,S)])},\"close/2\":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(b.type.is_variable(F)||b.type.is_variable(J))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_list(J))w.throw_error(b.error.type(\"list\",J,y.indicator));else if(!b.type.is_stream(F)&&!b.type.is_atom(F))w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator));else if(!b.type.is_stream(X)||X.stream===null)w.throw_error(b.error.existence(\"stream\",F,y.indicator));else{for(var Z={},ie=J,be;b.type.is_term(ie)&&ie.indicator===\"./2\";){if(be=ie.args[0],b.type.is_variable(be)){w.throw_error(b.error.instantiation(y.indicator));return}else if(!b.type.is_close_option(be)){w.throw_error(b.error.domain(\"close_option\",be,y.indicator));return}Z[be.id]=be.args[0].id===\"true\",ie=ie.args[1]}if(ie.indicator!==\"[]/0\"){b.type.is_variable(ie)?w.throw_error(b.error.instantiation(y.indicator)):w.throw_error(b.error.type(\"list\",J,y.indicator));return}else{if(X===w.session.standard_input||X===w.session.standard_output){w.success(S);return}else X===w.session.current_input?w.session.current_input=w.session.standard_input:X===w.session.current_output&&(w.session.current_output=w.session.current_output);X.alias!==null?delete w.session.streams[X.alias]:delete w.session.streams[X.id],X.output&&X.stream.flush();var Le=X.stream.close();X.stream=null,(Z.force===!0||Le===!0)&&w.success(S)}}},\"flush_output/0\":function(w,S,y){w.prepend([new xe(S.goal.replace(new H(\",\",[new H(\"current_output\",[new Ie(\"S\")]),new H(\"flush_output\",[new Ie(\"S\")])])),S.substitution,S)])},\"flush_output/1\":function(w,S,y){var F=y.args[0],J=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);b.type.is_variable(F)?w.throw_error(b.error.instantiation(y.indicator)):!b.type.is_stream(F)&&!b.type.is_atom(F)?w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator)):!b.type.is_stream(J)||J.stream===null?w.throw_error(b.error.existence(\"stream\",F,y.indicator)):F.input===!0?w.throw_error(b.error.permission(\"output\",\"stream\",output,y.indicator)):(J.stream.flush(),w.success(S))},\"stream_property/2\":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(!b.type.is_variable(F)&&!b.type.is_stream(F)&&!b.type.is_atom(F))w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator));else if(!b.type.is_variable(F)&&(!b.type.is_stream(X)||X.stream===null))w.throw_error(b.error.existence(\"stream\",F,y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_stream_property(J))w.throw_error(b.error.domain(\"stream_property\",J,y.indicator));else{var Z=[],ie=[];if(!b.type.is_variable(F))Z.push(X);else for(var be in w.session.streams)Z.push(w.session.streams[be]);for(var Le=0;Le<Z.length;Le++){var ot=[];Z[Le].filename&&ot.push(new H(\"file_name\",[new H(Z[Le].file_name,[])])),ot.push(new H(\"mode\",[new H(Z[Le].mode,[])])),ot.push(new H(Z[Le].input?\"input\":\"output\",[])),Z[Le].alias&&ot.push(new H(\"alias\",[new H(Z[Le].alias,[])])),ot.push(new H(\"position\",[typeof Z[Le].position==\"number\"?new Fe(Z[Le].position,!1):new H(Z[Le].position,[])])),ot.push(new H(\"end_of_stream\",[new H(Z[Le].position===\"end_of_stream\"?\"at\":Z[Le].position===\"past_end_of_stream\"?\"past\":\"not\",[])])),ot.push(new H(\"eof_action\",[new H(Z[Le].eof_action,[])])),ot.push(new H(\"reposition\",[new H(Z[Le].reposition?\"true\":\"false\",[])])),ot.push(new H(\"type\",[new H(Z[Le].type,[])]));for(var dt=0;dt<ot.length;dt++)ie.push(new xe(S.goal.replace(new H(\",\",[new H(\"=\",[b.type.is_variable(F)?F:X,Z[Le]]),new H(\"=\",[J,ot[dt]])])),S.substitution,S))}w.prepend(ie)}},\"at_end_of_stream/0\":function(w,S,y){w.prepend([new xe(S.goal.replace(new H(\",\",[new H(\"current_input\",[new Ie(\"S\")]),new H(\",\",[new H(\"stream_property\",[new Ie(\"S\"),new H(\"end_of_stream\",[new Ie(\"E\")])]),new H(\",\",[new H(\"!\",[]),new H(\";\",[new H(\"=\",[new Ie(\"E\"),new H(\"at\",[])]),new H(\"=\",[new Ie(\"E\"),new H(\"past\",[])])])])])])),S.substitution,S)])},\"at_end_of_stream/1\":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(\",\",[new H(\"stream_property\",[F,new H(\"end_of_stream\",[new Ie(\"E\")])]),new H(\",\",[new H(\"!\",[]),new H(\";\",[new H(\"=\",[new Ie(\"E\"),new H(\"at\",[])]),new H(\"=\",[new Ie(\"E\"),new H(\"past\",[])])])])])),S.substitution,S)])},\"set_stream_position/2\":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);b.type.is_variable(F)||b.type.is_variable(J)?w.throw_error(b.error.instantiation(y.indicator)):!b.type.is_stream(F)&&!b.type.is_atom(F)?w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator)):!b.type.is_stream(X)||X.stream===null?w.throw_error(b.error.existence(\"stream\",F,y.indicator)):b.type.is_stream_position(J)?X.reposition===!1?w.throw_error(b.error.permission(\"reposition\",\"stream\",F,y.indicator)):(b.type.is_integer(J)?X.position=J.value:X.position=J.id,w.success(S)):w.throw_error(b.error.domain(\"stream_position\",J,y.indicator))},\"get_char/1\":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(\",\",[new H(\"current_input\",[new Ie(\"S\")]),new H(\"get_char\",[new Ie(\"S\"),F])])),S.substitution,S)])},\"get_char/2\":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(b.type.is_variable(F))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_character(J))w.throw_error(b.error.type(\"in_character\",J,y.indicator));else if(!b.type.is_stream(F)&&!b.type.is_atom(F))w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator));else if(!b.type.is_stream(X)||X.stream===null)w.throw_error(b.error.existence(\"stream\",F,y.indicator));else if(X.output)w.throw_error(b.error.permission(\"input\",\"stream\",F,y.indicator));else if(X.type===\"binary\")w.throw_error(b.error.permission(\"input\",\"binary_stream\",F,y.indicator));else if(X.position===\"past_end_of_stream\"&&X.eof_action===\"error\")w.throw_error(b.error.permission(\"input\",\"past_end_of_stream\",F,y.indicator));else{var Z;if(X.position===\"end_of_stream\")Z=\"end_of_file\",X.position=\"past_end_of_stream\";else{if(Z=X.stream.get(1,X.position),Z===null){w.throw_error(b.error.representation(\"character\",y.indicator));return}X.position++}w.prepend([new xe(S.goal.replace(new H(\"=\",[new H(Z,[]),J])),S.substitution,S)])}},\"get_code/1\":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(\",\",[new H(\"current_input\",[new Ie(\"S\")]),new H(\"get_code\",[new Ie(\"S\"),F])])),S.substitution,S)])},\"get_code/2\":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(b.type.is_variable(F))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_integer(J))w.throw_error(b.error.type(\"integer\",char,y.indicator));else if(!b.type.is_variable(F)&&!b.type.is_stream(F)&&!b.type.is_atom(F))w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator));else if(!b.type.is_stream(X)||X.stream===null)w.throw_error(b.error.existence(\"stream\",F,y.indicator));else if(X.output)w.throw_error(b.error.permission(\"input\",\"stream\",F,y.indicator));else if(X.type===\"binary\")w.throw_error(b.error.permission(\"input\",\"binary_stream\",F,y.indicator));else if(X.position===\"past_end_of_stream\"&&X.eof_action===\"error\")w.throw_error(b.error.permission(\"input\",\"past_end_of_stream\",F,y.indicator));else{var Z;if(X.position===\"end_of_stream\")Z=-1,X.position=\"past_end_of_stream\";else{if(Z=X.stream.get(1,X.position),Z===null){w.throw_error(b.error.representation(\"character\",y.indicator));return}Z=n(Z,0),X.position++}w.prepend([new xe(S.goal.replace(new H(\"=\",[new Fe(Z,!1),J])),S.substitution,S)])}},\"peek_char/1\":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(\",\",[new H(\"current_input\",[new Ie(\"S\")]),new H(\"peek_char\",[new Ie(\"S\"),F])])),S.substitution,S)])},\"peek_char/2\":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(b.type.is_variable(F))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_character(J))w.throw_error(b.error.type(\"in_character\",J,y.indicator));else if(!b.type.is_stream(F)&&!b.type.is_atom(F))w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator));else if(!b.type.is_stream(X)||X.stream===null)w.throw_error(b.error.existence(\"stream\",F,y.indicator));else if(X.output)w.throw_error(b.error.permission(\"input\",\"stream\",F,y.indicator));else if(X.type===\"binary\")w.throw_error(b.error.permission(\"input\",\"binary_stream\",F,y.indicator));else if(X.position===\"past_end_of_stream\"&&X.eof_action===\"error\")w.throw_error(b.error.permission(\"input\",\"past_end_of_stream\",F,y.indicator));else{var Z;if(X.position===\"end_of_stream\")Z=\"end_of_file\",X.position=\"past_end_of_stream\";else if(Z=X.stream.get(1,X.position),Z===null){w.throw_error(b.error.representation(\"character\",y.indicator));return}w.prepend([new xe(S.goal.replace(new H(\"=\",[new H(Z,[]),J])),S.substitution,S)])}},\"peek_code/1\":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(\",\",[new H(\"current_input\",[new Ie(\"S\")]),new H(\"peek_code\",[new Ie(\"S\"),F])])),S.substitution,S)])},\"peek_code/2\":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(b.type.is_variable(F))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_integer(J))w.throw_error(b.error.type(\"integer\",char,y.indicator));else if(!b.type.is_variable(F)&&!b.type.is_stream(F)&&!b.type.is_atom(F))w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator));else if(!b.type.is_stream(X)||X.stream===null)w.throw_error(b.error.existence(\"stream\",F,y.indicator));else if(X.output)w.throw_error(b.error.permission(\"input\",\"stream\",F,y.indicator));else if(X.type===\"binary\")w.throw_error(b.error.permission(\"input\",\"binary_stream\",F,y.indicator));else if(X.position===\"past_end_of_stream\"&&X.eof_action===\"error\")w.throw_error(b.error.permission(\"input\",\"past_end_of_stream\",F,y.indicator));else{var Z;if(X.position===\"end_of_stream\")Z=-1,X.position=\"past_end_of_stream\";else{if(Z=X.stream.get(1,X.position),Z===null){w.throw_error(b.error.representation(\"character\",y.indicator));return}Z=n(Z,0)}w.prepend([new xe(S.goal.replace(new H(\"=\",[new Fe(Z,!1),J])),S.substitution,S)])}},\"put_char/1\":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(\",\",[new H(\"current_output\",[new Ie(\"S\")]),new H(\"put_char\",[new Ie(\"S\"),F])])),S.substitution,S)])},\"put_char/2\":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);b.type.is_variable(F)||b.type.is_variable(J)?w.throw_error(b.error.instantiation(y.indicator)):b.type.is_character(J)?!b.type.is_variable(F)&&!b.type.is_stream(F)&&!b.type.is_atom(F)?w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator)):!b.type.is_stream(X)||X.stream===null?w.throw_error(b.error.existence(\"stream\",F,y.indicator)):X.input?w.throw_error(b.error.permission(\"output\",\"stream\",F,y.indicator)):X.type===\"binary\"?w.throw_error(b.error.permission(\"output\",\"binary_stream\",F,y.indicator)):X.stream.put(J.id,X.position)&&(typeof X.position==\"number\"&&X.position++,w.success(S)):w.throw_error(b.error.type(\"character\",J,y.indicator))},\"put_code/1\":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(\",\",[new H(\"current_output\",[new Ie(\"S\")]),new H(\"put_code\",[new Ie(\"S\"),F])])),S.substitution,S)])},\"put_code/2\":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);b.type.is_variable(F)||b.type.is_variable(J)?w.throw_error(b.error.instantiation(y.indicator)):b.type.is_integer(J)?b.type.is_character_code(J)?!b.type.is_variable(F)&&!b.type.is_stream(F)&&!b.type.is_atom(F)?w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator)):!b.type.is_stream(X)||X.stream===null?w.throw_error(b.error.existence(\"stream\",F,y.indicator)):X.input?w.throw_error(b.error.permission(\"output\",\"stream\",F,y.indicator)):X.type===\"binary\"?w.throw_error(b.error.permission(\"output\",\"binary_stream\",F,y.indicator)):X.stream.put_char(u(J.value),X.position)&&(typeof X.position==\"number\"&&X.position++,w.success(S)):w.throw_error(b.error.representation(\"character_code\",y.indicator)):w.throw_error(b.error.type(\"integer\",J,y.indicator))},\"nl/0\":function(w,S,y){w.prepend([new xe(S.goal.replace(new H(\",\",[new H(\"current_output\",[new Ie(\"S\")]),new H(\"put_char\",[new Ie(\"S\"),new H(`\n`,[])])])),S.substitution,S)])},\"nl/1\":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(\"put_char\",[F,new H(`\n`,[])])),S.substitution,S)])},\"get_byte/1\":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(\",\",[new H(\"current_input\",[new Ie(\"S\")]),new H(\"get_byte\",[new Ie(\"S\"),F])])),S.substitution,S)])},\"get_byte/2\":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(b.type.is_variable(F))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_byte(J))w.throw_error(b.error.type(\"in_byte\",char,y.indicator));else if(!b.type.is_stream(F)&&!b.type.is_atom(F))w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator));else if(!b.type.is_stream(X)||X.stream===null)w.throw_error(b.error.existence(\"stream\",F,y.indicator));else if(X.output)w.throw_error(b.error.permission(\"input\",\"stream\",F,y.indicator));else if(X.type===\"text\")w.throw_error(b.error.permission(\"input\",\"text_stream\",F,y.indicator));else if(X.position===\"past_end_of_stream\"&&X.eof_action===\"error\")w.throw_error(b.error.permission(\"input\",\"past_end_of_stream\",F,y.indicator));else{var Z;if(X.position===\"end_of_stream\")Z=\"end_of_file\",X.position=\"past_end_of_stream\";else{if(Z=X.stream.get_byte(X.position),Z===null){w.throw_error(b.error.representation(\"byte\",y.indicator));return}X.position++}w.prepend([new xe(S.goal.replace(new H(\"=\",[new Fe(Z,!1),J])),S.substitution,S)])}},\"peek_byte/1\":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(\",\",[new H(\"current_input\",[new Ie(\"S\")]),new H(\"peek_byte\",[new Ie(\"S\"),F])])),S.substitution,S)])},\"peek_byte/2\":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(b.type.is_variable(F))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_variable(J)&&!b.type.is_byte(J))w.throw_error(b.error.type(\"in_byte\",char,y.indicator));else if(!b.type.is_stream(F)&&!b.type.is_atom(F))w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator));else if(!b.type.is_stream(X)||X.stream===null)w.throw_error(b.error.existence(\"stream\",F,y.indicator));else if(X.output)w.throw_error(b.error.permission(\"input\",\"stream\",F,y.indicator));else if(X.type===\"text\")w.throw_error(b.error.permission(\"input\",\"text_stream\",F,y.indicator));else if(X.position===\"past_end_of_stream\"&&X.eof_action===\"error\")w.throw_error(b.error.permission(\"input\",\"past_end_of_stream\",F,y.indicator));else{var Z;if(X.position===\"end_of_stream\")Z=\"end_of_file\",X.position=\"past_end_of_stream\";else if(Z=X.stream.get_byte(X.position),Z===null){w.throw_error(b.error.representation(\"byte\",y.indicator));return}w.prepend([new xe(S.goal.replace(new H(\"=\",[new Fe(Z,!1),J])),S.substitution,S)])}},\"put_byte/1\":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(\",\",[new H(\"current_output\",[new Ie(\"S\")]),new H(\"put_byte\",[new Ie(\"S\"),F])])),S.substitution,S)])},\"put_byte/2\":function(w,S,y){var F=y.args[0],J=y.args[1],X=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);b.type.is_variable(F)||b.type.is_variable(J)?w.throw_error(b.error.instantiation(y.indicator)):b.type.is_byte(J)?!b.type.is_variable(F)&&!b.type.is_stream(F)&&!b.type.is_atom(F)?w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator)):!b.type.is_stream(X)||X.stream===null?w.throw_error(b.error.existence(\"stream\",F,y.indicator)):X.input?w.throw_error(b.error.permission(\"output\",\"stream\",F,y.indicator)):X.type===\"text\"?w.throw_error(b.error.permission(\"output\",\"text_stream\",F,y.indicator)):X.stream.put_byte(J.value,X.position)&&(typeof X.position==\"number\"&&X.position++,w.success(S)):w.throw_error(b.error.type(\"byte\",J,y.indicator))},\"read/1\":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(\",\",[new H(\"current_input\",[new Ie(\"S\")]),new H(\"read_term\",[new Ie(\"S\"),F,new H(\"[]\",[])])])),S.substitution,S)])},\"read/2\":function(w,S,y){var F=y.args[0],J=y.args[1];w.prepend([new xe(S.goal.replace(new H(\"read_term\",[F,J,new H(\"[]\",[])])),S.substitution,S)])},\"read_term/2\":function(w,S,y){var F=y.args[0],J=y.args[1];w.prepend([new xe(S.goal.replace(new H(\",\",[new H(\"current_input\",[new Ie(\"S\")]),new H(\"read_term\",[new Ie(\"S\"),F,J])])),S.substitution,S)])},\"read_term/3\":function(w,S,y){var F=y.args[0],J=y.args[1],X=y.args[2],Z=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(b.type.is_variable(F)||b.type.is_variable(X))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_list(X))w.throw_error(b.error.type(\"list\",X,y.indicator));else if(!b.type.is_stream(F)&&!b.type.is_atom(F))w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator));else if(!b.type.is_stream(Z)||Z.stream===null)w.throw_error(b.error.existence(\"stream\",F,y.indicator));else if(Z.output)w.throw_error(b.error.permission(\"input\",\"stream\",F,y.indicator));else if(Z.type===\"binary\")w.throw_error(b.error.permission(\"input\",\"binary_stream\",F,y.indicator));else if(Z.position===\"past_end_of_stream\"&&Z.eof_action===\"error\")w.throw_error(b.error.permission(\"input\",\"past_end_of_stream\",F,y.indicator));else{for(var ie={},be=X,Le;b.type.is_term(be)&&be.indicator===\"./2\";){if(Le=be.args[0],b.type.is_variable(Le)){w.throw_error(b.error.instantiation(y.indicator));return}else if(!b.type.is_read_option(Le)){w.throw_error(b.error.domain(\"read_option\",Le,y.indicator));return}ie[Le.id]=Le.args[0],be=be.args[1]}if(be.indicator!==\"[]/0\"){b.type.is_variable(be)?w.throw_error(b.error.instantiation(y.indicator)):w.throw_error(b.error.type(\"list\",X,y.indicator));return}else{for(var ot,dt,Gt,$t=\"\",bt=[],an=null;an===null||an.name!==\"atom\"||an.value!==\".\"||Gt.type===A&&b.flatten_error(new H(\"throw\",[Gt.value])).found===\"token_not_found\";){if(ot=Z.stream.get(1,Z.position),ot===null){w.throw_error(b.error.representation(\"character\",y.indicator));return}if(ot===\"end_of_file\"||ot===\"past_end_of_file\"){Gt?w.throw_error(b.error.syntax(bt[Gt.len-1],\". or expression expected\",!1)):w.throw_error(b.error.syntax(null,\"token not found\",!0));return}Z.position++,$t+=ot,dt=new U(w),dt.new_text($t),bt=dt.get_tokens(),an=bt!==null&&bt.length>0?bt[bt.length-1]:null,bt!==null&&(Gt=V(w,bt,0,w.__get_max_priority(),!1))}if(Gt.type===p&&Gt.len===bt.length-1&&an.value===\".\"){Gt=Gt.value.rename(w);var Qr=new H(\"=\",[J,Gt]);if(ie.variables){var mr=g(o(Pe(Gt.variables()),function(br){return new Ie(br)}));Qr=new H(\",\",[Qr,new H(\"=\",[ie.variables,mr])])}if(ie.variable_names){var mr=g(o(Pe(Gt.variables()),function(Wr){var Kn;for(Kn in w.session.renamed_variables)if(w.session.renamed_variables.hasOwnProperty(Kn)&&w.session.renamed_variables[Kn]===Wr)break;return new H(\"=\",[new H(Kn,[]),new Ie(Wr)])}));Qr=new H(\",\",[Qr,new H(\"=\",[ie.variable_names,mr])])}if(ie.singletons){var mr=g(o(new He(Gt,null).singleton_variables(),function(Wr){var Kn;for(Kn in w.session.renamed_variables)if(w.session.renamed_variables.hasOwnProperty(Kn)&&w.session.renamed_variables[Kn]===Wr)break;return new H(\"=\",[new H(Kn,[]),new Ie(Wr)])}));Qr=new H(\",\",[Qr,new H(\"=\",[ie.singletons,mr])])}w.prepend([new xe(S.goal.replace(Qr),S.substitution,S)])}else Gt.type===p?w.throw_error(b.error.syntax(bt[Gt.len],\"unexpected token\",!1)):w.throw_error(Gt.value)}}},\"write/1\":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(\",\",[new H(\"current_output\",[new Ie(\"S\")]),new H(\"write\",[new Ie(\"S\"),F])])),S.substitution,S)])},\"write/2\":function(w,S,y){var F=y.args[0],J=y.args[1];w.prepend([new xe(S.goal.replace(new H(\"write_term\",[F,J,new H(\".\",[new H(\"quoted\",[new H(\"false\",[])]),new H(\".\",[new H(\"ignore_ops\",[new H(\"false\")]),new H(\".\",[new H(\"numbervars\",[new H(\"true\")]),new H(\"[]\",[])])])])])),S.substitution,S)])},\"writeq/1\":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(\",\",[new H(\"current_output\",[new Ie(\"S\")]),new H(\"writeq\",[new Ie(\"S\"),F])])),S.substitution,S)])},\"writeq/2\":function(w,S,y){var F=y.args[0],J=y.args[1];w.prepend([new xe(S.goal.replace(new H(\"write_term\",[F,J,new H(\".\",[new H(\"quoted\",[new H(\"true\",[])]),new H(\".\",[new H(\"ignore_ops\",[new H(\"false\")]),new H(\".\",[new H(\"numbervars\",[new H(\"true\")]),new H(\"[]\",[])])])])])),S.substitution,S)])},\"write_canonical/1\":function(w,S,y){var F=y.args[0];w.prepend([new xe(S.goal.replace(new H(\",\",[new H(\"current_output\",[new Ie(\"S\")]),new H(\"write_canonical\",[new Ie(\"S\"),F])])),S.substitution,S)])},\"write_canonical/2\":function(w,S,y){var F=y.args[0],J=y.args[1];w.prepend([new xe(S.goal.replace(new H(\"write_term\",[F,J,new H(\".\",[new H(\"quoted\",[new H(\"true\",[])]),new H(\".\",[new H(\"ignore_ops\",[new H(\"true\")]),new H(\".\",[new H(\"numbervars\",[new H(\"false\")]),new H(\"[]\",[])])])])])),S.substitution,S)])},\"write_term/2\":function(w,S,y){var F=y.args[0],J=y.args[1];w.prepend([new xe(S.goal.replace(new H(\",\",[new H(\"current_output\",[new Ie(\"S\")]),new H(\"write_term\",[new Ie(\"S\"),F,J])])),S.substitution,S)])},\"write_term/3\":function(w,S,y){var F=y.args[0],J=y.args[1],X=y.args[2],Z=b.type.is_stream(F)?F:w.get_stream_by_alias(F.id);if(b.type.is_variable(F)||b.type.is_variable(X))w.throw_error(b.error.instantiation(y.indicator));else if(!b.type.is_list(X))w.throw_error(b.error.type(\"list\",X,y.indicator));else if(!b.type.is_stream(F)&&!b.type.is_atom(F))w.throw_error(b.error.domain(\"stream_or_alias\",F,y.indicator));else if(!b.type.is_stream(Z)||Z.stream===null)w.throw_error(b.error.existence(\"stream\",F,y.indicator));else if(Z.input)w.throw_error(b.error.permission(\"output\",\"stream\",F,y.indicator));else if(Z.type===\"binary\")w.throw_error(b.error.permission(\"output\",\"binary_stream\",F,y.indicator));else if(Z.position===\"past_end_of_stream\"&&Z.eof_action===\"error\")w.throw_error(b.error.permission(\"output\",\"past_end_of_stream\",F,y.indicator));else{for(var ie={},be=X,Le;b.type.is_term(be)&&be.indicator===\"./2\";){if(Le=be.args[0],b.type.is_variable(Le)){w.throw_error(b.error.instantiation(y.indicator));return}else if(!b.type.is_write_option(Le)){w.throw_error(b.error.domain(\"write_option\",Le,y.indicator));return}ie[Le.id]=Le.args[0].id===\"true\",be=be.args[1]}if(be.indicator!==\"[]/0\"){b.type.is_variable(be)?w.throw_error(b.error.instantiation(y.indicator)):w.throw_error(b.error.type(\"list\",X,y.indicator));return}else{ie.session=w.session;var ot=J.toString(ie);Z.stream.put(ot,Z.position),typeof Z.position==\"number\"&&(Z.position+=ot.length),w.success(S)}}},\"halt/0\":function(w,S,y){w.points=[]},\"halt/1\":function(w,S,y){var F=y.args[0];b.type.is_variable(F)?w.throw_error(b.error.instantiation(y.indicator)):b.type.is_integer(F)?w.points=[]:w.throw_error(b.error.type(\"integer\",F,y.indicator))},\"current_prolog_flag/2\":function(w,S,y){var F=y.args[0],J=y.args[1];if(!b.type.is_variable(F)&&!b.type.is_atom(F))w.throw_error(b.error.type(\"atom\",F,y.indicator));else if(!b.type.is_variable(F)&&!b.type.is_flag(F))w.throw_error(b.error.domain(\"prolog_flag\",F,y.indicator));else{var X=[];for(var Z in b.flag)if(!!b.flag.hasOwnProperty(Z)){var ie=new H(\",\",[new H(\"=\",[new H(Z),F]),new H(\"=\",[w.get_flag(Z),J])]);X.push(new xe(S.goal.replace(ie),S.substitution,S))}w.prepend(X)}},\"set_prolog_flag/2\":function(w,S,y){var F=y.args[0],J=y.args[1];b.type.is_variable(F)||b.type.is_variable(J)?w.throw_error(b.error.instantiation(y.indicator)):b.type.is_atom(F)?b.type.is_flag(F)?b.type.is_value_flag(F,J)?b.type.is_modifiable_flag(F)?(w.session.flag[F.id]=J,w.success(S)):w.throw_error(b.error.permission(\"modify\",\"flag\",F)):w.throw_error(b.error.domain(\"flag_value\",new H(\"+\",[F,J]),y.indicator)):w.throw_error(b.error.domain(\"prolog_flag\",F,y.indicator)):w.throw_error(b.error.type(\"atom\",F,y.indicator))}},flag:{bounded:{allowed:[new H(\"true\"),new H(\"false\")],value:new H(\"true\"),changeable:!1},max_integer:{allowed:[new Fe(Number.MAX_SAFE_INTEGER)],value:new Fe(Number.MAX_SAFE_INTEGER),changeable:!1},min_integer:{allowed:[new Fe(Number.MIN_SAFE_INTEGER)],value:new Fe(Number.MIN_SAFE_INTEGER),changeable:!1},integer_rounding_function:{allowed:[new H(\"down\"),new H(\"toward_zero\")],value:new H(\"toward_zero\"),changeable:!1},char_conversion:{allowed:[new H(\"on\"),new H(\"off\")],value:new H(\"on\"),changeable:!0},debug:{allowed:[new H(\"on\"),new H(\"off\")],value:new H(\"off\"),changeable:!0},max_arity:{allowed:[new H(\"unbounded\")],value:new H(\"unbounded\"),changeable:!1},unknown:{allowed:[new H(\"error\"),new H(\"fail\"),new H(\"warning\")],value:new H(\"error\"),changeable:!0},double_quotes:{allowed:[new H(\"chars\"),new H(\"codes\"),new H(\"atom\")],value:new H(\"codes\"),changeable:!0},occurs_check:{allowed:[new H(\"false\"),new H(\"true\")],value:new H(\"false\"),changeable:!0},dialect:{allowed:[new H(\"tau\")],value:new H(\"tau\"),changeable:!1},version_data:{allowed:[new H(\"tau\",[new Fe(t.major,!1),new Fe(t.minor,!1),new Fe(t.patch,!1),new H(t.status)])],value:new H(\"tau\",[new Fe(t.major,!1),new Fe(t.minor,!1),new Fe(t.patch,!1),new H(t.status)]),changeable:!1},nodejs:{allowed:[new H(\"yes\"),new H(\"no\")],value:new H(typeof gl<\"u\"&&gl.exports?\"yes\":\"no\"),changeable:!1}},unify:function(w,S,y){y=y===void 0?!1:y;for(var F=[{left:w,right:S}],J={};F.length!==0;){var X=F.pop();if(w=X.left,S=X.right,b.type.is_term(w)&&b.type.is_term(S)){if(w.indicator!==S.indicator)return null;for(var Z=0;Z<w.args.length;Z++)F.push({left:w.args[Z],right:S.args[Z]})}else if(b.type.is_number(w)&&b.type.is_number(S)){if(w.value!==S.value||w.is_float!==S.is_float)return null}else if(b.type.is_variable(w)){if(b.type.is_variable(S)&&w.id===S.id)continue;if(y===!0&&S.variables().indexOf(w.id)!==-1)return null;if(w.id!==\"_\"){var ie=new ke;ie.add(w.id,S);for(var Z=0;Z<F.length;Z++)F[Z].left=F[Z].left.apply(ie),F[Z].right=F[Z].right.apply(ie);for(var Z in J)J[Z]=J[Z].apply(ie);J[w.id]=S}}else if(b.type.is_variable(S))F.push({left:S,right:w});else if(w.unify!==void 0){if(!w.unify(S))return null}else return null}return new ke(J)},compare:function(w,S){var y=b.type.compare(w,S);return y!==0?y:w.compare(S)},arithmetic_compare:function(w,S,y){var F=S.interpret(w);if(b.type.is_number(F)){var J=y.interpret(w);return b.type.is_number(J)?F.value<J.value?-1:F.value>J.value?1:0:J}else return F},operate:function(w,S){if(b.type.is_operator(S)){for(var y=b.type.is_operator(S),F=[],J,X=!1,Z=0;Z<S.args.length;Z++){if(J=S.args[Z].interpret(w),b.type.is_number(J)){if(y.type_args!==null&&J.is_float!==y.type_args)return b.error.type(y.type_args?\"float\":\"integer\",J,w.__call_indicator);F.push(J.value)}else return J;X=X||J.is_float}return F.push(w),J=b.arithmetic.evaluation[S.indicator].fn.apply(this,F),X=y.type_result===null?X:y.type_result,b.type.is_term(J)?J:J===Number.POSITIVE_INFINITY||J===Number.NEGATIVE_INFINITY?b.error.evaluation(\"overflow\",w.__call_indicator):X===!1&&w.get_flag(\"bounded\").id===\"true\"&&(J>w.get_flag(\"max_integer\").value||J<w.get_flag(\"min_integer\").value)?b.error.evaluation(\"int_overflow\",w.__call_indicator):new Fe(J,X)}else return b.error.type(\"evaluable\",S.indicator,w.__call_indicator)},error:{existence:function(w,S,y){return typeof S==\"string\"&&(S=ee(S)),new H(\"error\",[new H(\"existence_error\",[new H(w),S]),ee(y)])},type:function(w,S,y){return new H(\"error\",[new H(\"type_error\",[new H(w),S]),ee(y)])},instantiation:function(w){return new H(\"error\",[new H(\"instantiation_error\"),ee(w)])},domain:function(w,S,y){return new H(\"error\",[new H(\"domain_error\",[new H(w),S]),ee(y)])},representation:function(w,S){return new H(\"error\",[new H(\"representation_error\",[new H(w)]),ee(S)])},permission:function(w,S,y,F){return new H(\"error\",[new H(\"permission_error\",[new H(w),new H(S),y]),ee(F)])},evaluation:function(w,S){return new H(\"error\",[new H(\"evaluation_error\",[new H(w)]),ee(S)])},syntax:function(w,S,y){w=w||{value:\"\",line:0,column:0,matches:[\"\"],start:0};var F=y&&w.matches.length>0?w.start+w.matches[0].length:w.start,J=y?new H(\"token_not_found\"):new H(\"found\",[new H(w.value.toString())]),X=new H(\".\",[new H(\"line\",[new Fe(w.line+1)]),new H(\".\",[new H(\"column\",[new Fe(F+1)]),new H(\".\",[J,new H(\"[]\",[])])])]);return new H(\"error\",[new H(\"syntax_error\",[new H(S)]),X])},syntax_by_predicate:function(w,S){return new H(\"error\",[new H(\"syntax_error\",[new H(w)]),ee(S)])}},warning:{singleton:function(w,S,y){for(var F=new H(\"[]\"),J=w.length-1;J>=0;J--)F=new H(\".\",[new Ie(w[J]),F]);return new H(\"warning\",[new H(\"singleton_variables\",[F,ee(S)]),new H(\".\",[new H(\"line\",[new Fe(y,!1)]),new H(\"[]\")])])},failed_goal:function(w,S){return new H(\"warning\",[new H(\"failed_goal\",[w]),new H(\".\",[new H(\"line\",[new Fe(S,!1)]),new H(\"[]\")])])}},format_variable:function(w){return\"_\"+w},format_answer:function(w,S,F){S instanceof Te&&(S=S.thread);var F=F||{};if(F.session=S?S.session:void 0,b.type.is_error(w))return\"uncaught exception: \"+w.args[0].toString();if(w===!1)return\"false.\";if(w===null)return\"limit exceeded ;\";var J=0,X=\"\";if(b.type.is_substitution(w)){var Z=w.domain(!0);w=w.filter(function(Le,ot){return!b.type.is_variable(ot)||Z.indexOf(ot.id)!==-1&&Le!==ot.id})}for(var ie in w.links)!w.links.hasOwnProperty(ie)||(J++,X!==\"\"&&(X+=\", \"),X+=ie.toString(F)+\" = \"+w.links[ie].toString(F));var be=typeof S>\"u\"||S.points.length>0?\" ;\":\".\";return J===0?\"true\"+be:X+be},flatten_error:function(w){if(!b.type.is_error(w))return null;w=w.args[0];var S={};return S.type=w.args[0].id,S.thrown=S.type===\"syntax_error\"?null:w.args[1].id,S.expected=null,S.found=null,S.representation=null,S.existence=null,S.existence_type=null,S.line=null,S.column=null,S.permission_operation=null,S.permission_type=null,S.evaluation_type=null,S.type===\"type_error\"||S.type===\"domain_error\"?(S.expected=w.args[0].args[0].id,S.found=w.args[0].args[1].toString()):S.type===\"syntax_error\"?w.args[1].indicator===\"./2\"?(S.expected=w.args[0].args[0].id,S.found=w.args[1].args[1].args[1].args[0],S.found=S.found.id===\"token_not_found\"?S.found.id:S.found.args[0].id,S.line=w.args[1].args[0].args[0].value,S.column=w.args[1].args[1].args[0].args[0].value):S.thrown=w.args[1].id:S.type===\"permission_error\"?(S.found=w.args[0].args[2].toString(),S.permission_operation=w.args[0].args[0].id,S.permission_type=w.args[0].args[1].id):S.type===\"evaluation_error\"?S.evaluation_type=w.args[0].args[0].id:S.type===\"representation_error\"?S.representation=w.args[0].args[0].id:S.type===\"existence_error\"&&(S.existence=w.args[0].args[1].toString(),S.existence_type=w.args[0].args[0].id),S},create:function(w){return new b.type.Session(w)}};typeof gl<\"u\"?gl.exports=b:window.pl=b})()});function sme(t,e,r){t.prepend(r.map(o=>new Ta.default.type.State(e.goal.replace(o),e.substitution,e)))}function yH(t){let e=ame.get(t.session);if(e==null)throw new Error(\"Assertion failed: A project should have been registered for the active session\");return e}function lme(t,e){ame.set(t,e),t.consult(`:- use_module(library(${Xgt.id})).`)}var EH,Ta,ome,A0,Vgt,Jgt,ame,Xgt,cme=Et(()=>{Ye();EH=$e(d2()),Ta=$e(mH()),ome=$e(ve(\"vm\")),{is_atom:A0,is_variable:Vgt,is_instantiated_list:Jgt}=Ta.default.type;ame=new WeakMap;Xgt=new Ta.default.type.Module(\"constraints\",{[\"project_workspaces_by_descriptor/3\"]:(t,e,r)=>{let[o,a,n]=r.args;if(!A0(o)||!A0(a)){t.throw_error(Ta.default.error.instantiation(r.indicator));return}let u=W.parseIdent(o.id),A=W.makeDescriptor(u,a.id),h=yH(t).tryWorkspaceByDescriptor(A);Vgt(n)&&h!==null&&sme(t,e,[new Ta.default.type.Term(\"=\",[n,new Ta.default.type.Term(String(h.relativeCwd))])]),A0(n)&&h!==null&&h.relativeCwd===n.id&&t.success(e)},[\"workspace_field/3\"]:(t,e,r)=>{let[o,a,n]=r.args;if(!A0(o)||!A0(a)){t.throw_error(Ta.default.error.instantiation(r.indicator));return}let A=yH(t).tryWorkspaceByCwd(o.id);if(A==null)return;let p=(0,EH.default)(A.manifest.raw,a.id);typeof p>\"u\"||sme(t,e,[new Ta.default.type.Term(\"=\",[n,new Ta.default.type.Term(typeof p==\"object\"?JSON.stringify(p):p)])])},[\"workspace_field_test/3\"]:(t,e,r)=>{let[o,a,n]=r.args;t.prepend([new Ta.default.type.State(e.goal.replace(new Ta.default.type.Term(\"workspace_field_test\",[o,a,n,new Ta.default.type.Term(\"[]\",[])])),e.substitution,e)])},[\"workspace_field_test/4\"]:(t,e,r)=>{let[o,a,n,u]=r.args;if(!A0(o)||!A0(a)||!A0(n)||!Jgt(u)){t.throw_error(Ta.default.error.instantiation(r.indicator));return}let p=yH(t).tryWorkspaceByCwd(o.id);if(p==null)return;let h=(0,EH.default)(p.manifest.raw,a.id);if(typeof h>\"u\")return;let E={$$:h};for(let[v,x]of u.toJavaScript().entries())E[`$${v}`]=x;ome.default.runInNewContext(n.id,E)&&t.success(e)}},[\"project_workspaces_by_descriptor/3\",\"workspace_field/3\",\"workspace_field_test/3\",\"workspace_field_test/4\"])});var b2={};zt(b2,{Constraints:()=>S2,DependencyType:()=>pme});function to(t){if(t instanceof DC.default.type.Num)return t.value;if(t instanceof DC.default.type.Term)switch(t.indicator){case\"throw/1\":return to(t.args[0]);case\"error/1\":return to(t.args[0]);case\"error/2\":if(t.args[0]instanceof DC.default.type.Term&&t.args[0].indicator===\"syntax_error/1\")return Object.assign(to(t.args[0]),...to(t.args[1]));{let e=to(t.args[0]);return e.message+=` (in ${to(t.args[1])})`,e}case\"syntax_error/1\":return new Jt(43,`Syntax error: ${to(t.args[0])}`);case\"existence_error/2\":return new Jt(44,`Existence error: ${to(t.args[0])} ${to(t.args[1])} not found`);case\"instantiation_error/0\":return new Jt(75,\"Instantiation error: an argument is variable when an instantiated argument was expected\");case\"line/1\":return{line:to(t.args[0])};case\"column/1\":return{column:to(t.args[0])};case\"found/1\":return{found:to(t.args[0])};case\"./2\":return[to(t.args[0])].concat(to(t.args[1]));case\"//2\":return`${to(t.args[0])}/${to(t.args[1])}`;default:return t.id}throw`couldn't pretty print because of unsupported node ${t}`}function Ame(t){let e;try{e=to(t)}catch(r){throw typeof r==\"string\"?new Jt(42,`Unknown error: ${t} (note: ${r})`):r}return typeof e.line<\"u\"&&typeof e.column<\"u\"&&(e.message+=` at line ${e.line}, column ${e.column}`),e}function tm(t){return t.id===\"null\"?null:`${t.toJavaScript()}`}function Zgt(t){if(t.id===\"null\")return null;{let e=t.toJavaScript();if(typeof e!=\"string\")return JSON.stringify(e);try{return JSON.stringify(JSON.parse(e))}catch{return JSON.stringify(e)}}}function f0(t){return typeof t==\"string\"?`'${t}'`:\"[]\"}var fme,DC,pme,ume,CH,S2,x2=Et(()=>{Ye();Ye();Pt();fme=$e(Gde()),DC=$e(mH());v2();cme();(0,fme.default)(DC.default);pme=(o=>(o.Dependencies=\"dependencies\",o.DevDependencies=\"devDependencies\",o.PeerDependencies=\"peerDependencies\",o))(pme||{}),ume=[\"dependencies\",\"devDependencies\",\"peerDependencies\"];CH=class{constructor(e,r){let o=1e3*e.workspaces.length;this.session=DC.default.create(o),lme(this.session,e),this.session.consult(\":- use_module(library(lists)).\"),this.session.consult(r)}fetchNextAnswer(){return new Promise(e=>{this.session.answer(r=>{e(r)})})}async*makeQuery(e){let r=this.session.query(e);if(r!==!0)throw Ame(r);for(;;){let o=await this.fetchNextAnswer();if(o===null)throw new Jt(79,\"Resolution limit exceeded\");if(!o)break;if(o.id===\"throw\")throw Ame(o);yield o}}};S2=class{constructor(e){this.source=\"\";this.project=e;let r=e.configuration.get(\"constraintsPath\");oe.existsSync(r)&&(this.source=oe.readFileSync(r,\"utf8\"))}static async find(e){return new S2(e)}getProjectDatabase(){let e=\"\";for(let r of ume)e+=`dependency_type(${r}).\n`;for(let r of this.project.workspacesByCwd.values()){let o=r.relativeCwd;e+=`workspace(${f0(o)}).\n`,e+=`workspace_ident(${f0(o)}, ${f0(W.stringifyIdent(r.anchoredLocator))}).\n`,e+=`workspace_version(${f0(o)}, ${f0(r.manifest.version)}).\n`;for(let a of ume)for(let n of r.manifest[a].values())e+=`workspace_has_dependency(${f0(o)}, ${f0(W.stringifyIdent(n))}, ${f0(n.range)}, ${a}).\n`}return e+=`workspace(_) :- false.\n`,e+=`workspace_ident(_, _) :- false.\n`,e+=`workspace_version(_, _) :- false.\n`,e+=`workspace_has_dependency(_, _, _, _) :- false.\n`,e}getDeclarations(){let e=\"\";return e+=`gen_enforced_dependency(_, _, _, _) :- false.\n`,e+=`gen_enforced_field(_, _, _) :- false.\n`,e}get fullSource(){return`${this.getProjectDatabase()}\n${this.source}\n${this.getDeclarations()}`}createSession(){return new CH(this.project,this.fullSource)}async processClassic(){let e=this.createSession();return{enforcedDependencies:await this.genEnforcedDependencies(e),enforcedFields:await this.genEnforcedFields(e)}}async process(){let{enforcedDependencies:e,enforcedFields:r}=await this.processClassic(),o=new Map;for(let{workspace:a,dependencyIdent:n,dependencyRange:u,dependencyType:A}of e){let p=B2([A,W.stringifyIdent(n)]),h=_e.getMapWithDefault(o,a.cwd);_e.getMapWithDefault(h,p).set(u??void 0,new Set)}for(let{workspace:a,fieldPath:n,fieldValue:u}of r){let A=B2(n),p=_e.getMapWithDefault(o,a.cwd);_e.getMapWithDefault(p,A).set(JSON.parse(u)??void 0,new Set)}return{manifestUpdates:o,reportedErrors:new Map}}async genEnforcedDependencies(e){let r=[];for await(let o of e.makeQuery(\"workspace(WorkspaceCwd), dependency_type(DependencyType), gen_enforced_dependency(WorkspaceCwd, DependencyIdent, DependencyRange, DependencyType).\")){let a=z.resolve(this.project.cwd,tm(o.links.WorkspaceCwd)),n=tm(o.links.DependencyIdent),u=tm(o.links.DependencyRange),A=tm(o.links.DependencyType);if(a===null||n===null)throw new Error(\"Invalid rule\");let p=this.project.getWorkspaceByCwd(a),h=W.parseIdent(n);r.push({workspace:p,dependencyIdent:h,dependencyRange:u,dependencyType:A})}return _e.sortMap(r,[({dependencyRange:o})=>o!==null?\"0\":\"1\",({workspace:o})=>W.stringifyIdent(o.anchoredLocator),({dependencyIdent:o})=>W.stringifyIdent(o)])}async genEnforcedFields(e){let r=[];for await(let o of e.makeQuery(\"workspace(WorkspaceCwd), gen_enforced_field(WorkspaceCwd, FieldPath, FieldValue).\")){let a=z.resolve(this.project.cwd,tm(o.links.WorkspaceCwd)),n=tm(o.links.FieldPath),u=Zgt(o.links.FieldValue);if(a===null||n===null)throw new Error(\"Invalid rule\");let A=this.project.getWorkspaceByCwd(a);r.push({workspace:A,fieldPath:n,fieldValue:u})}return _e.sortMap(r,[({workspace:o})=>W.stringifyIdent(o.anchoredLocator),({fieldPath:o})=>o])}async*query(e){let r=this.createSession();for await(let o of r.makeQuery(e)){let a={};for(let[n,u]of Object.entries(o.links))n!==\"_\"&&(a[n]=tm(u));yield a}}}});var Ime=_(Ik=>{\"use strict\";Object.defineProperty(Ik,\"__esModule\",{value:!0});function j2(t){let e=[...t.caches],r=e.shift();return r===void 0?wme():{get(o,a,n={miss:()=>Promise.resolve()}){return r.get(o,a,n).catch(()=>j2({caches:e}).get(o,a,n))},set(o,a){return r.set(o,a).catch(()=>j2({caches:e}).set(o,a))},delete(o){return r.delete(o).catch(()=>j2({caches:e}).delete(o))},clear(){return r.clear().catch(()=>j2({caches:e}).clear())}}}function wme(){return{get(t,e,r={miss:()=>Promise.resolve()}){return e().then(a=>Promise.all([a,r.miss(a)])).then(([a])=>a)},set(t,e){return Promise.resolve(e)},delete(t){return Promise.resolve()},clear(){return Promise.resolve()}}}Ik.createFallbackableCache=j2;Ik.createNullCache=wme});var vme=_((FWt,Bme)=>{Bme.exports=Ime()});var Dme=_(TH=>{\"use strict\";Object.defineProperty(TH,\"__esModule\",{value:!0});function mdt(t={serializable:!0}){let e={};return{get(r,o,a={miss:()=>Promise.resolve()}){let n=JSON.stringify(r);if(n in e)return Promise.resolve(t.serializable?JSON.parse(e[n]):e[n]);let u=o(),A=a&&a.miss||(()=>Promise.resolve());return u.then(p=>A(p)).then(()=>u)},set(r,o){return e[JSON.stringify(r)]=t.serializable?JSON.stringify(o):o,Promise.resolve(o)},delete(r){return delete e[JSON.stringify(r)],Promise.resolve()},clear(){return e={},Promise.resolve()}}}TH.createInMemoryCache=mdt});var Sme=_((TWt,Pme)=>{Pme.exports=Dme()});var xme=_($c=>{\"use strict\";Object.defineProperty($c,\"__esModule\",{value:!0});function ydt(t,e,r){let o={\"x-algolia-api-key\":r,\"x-algolia-application-id\":e};return{headers(){return t===LH.WithinHeaders?o:{}},queryParameters(){return t===LH.WithinQueryParameters?o:{}}}}function Edt(t){let e=0,r=()=>(e++,new Promise(o=>{setTimeout(()=>{o(t(r))},Math.min(100*e,1e3))}));return t(r)}function bme(t,e=(r,o)=>Promise.resolve()){return Object.assign(t,{wait(r){return bme(t.then(o=>Promise.all([e(o,r),o])).then(o=>o[1]))}})}function Cdt(t){let e=t.length-1;for(e;e>0;e--){let r=Math.floor(Math.random()*(e+1)),o=t[e];t[e]=t[r],t[r]=o}return t}function wdt(t,e){return e&&Object.keys(e).forEach(r=>{t[r]=e[r](t)}),t}function Idt(t,...e){let r=0;return t.replace(/%s/g,()=>encodeURIComponent(e[r++]))}var Bdt=\"4.22.1\",vdt=t=>()=>t.transporter.requester.destroy(),LH={WithinQueryParameters:0,WithinHeaders:1};$c.AuthMode=LH;$c.addMethods=wdt;$c.createAuth=ydt;$c.createRetryablePromise=Edt;$c.createWaitablePromise=bme;$c.destroy=vdt;$c.encode=Idt;$c.shuffle=Cdt;$c.version=Bdt});var Y2=_((NWt,kme)=>{kme.exports=xme()});var Qme=_(NH=>{\"use strict\";Object.defineProperty(NH,\"__esModule\",{value:!0});var Ddt={Delete:\"DELETE\",Get:\"GET\",Post:\"POST\",Put:\"PUT\"};NH.MethodEnum=Ddt});var W2=_((MWt,Fme)=>{Fme.exports=Qme()});var Kme=_(Fi=>{\"use strict\";Object.defineProperty(Fi,\"__esModule\",{value:!0});var Tme=W2();function OH(t,e){let r=t||{},o=r.data||{};return Object.keys(r).forEach(a=>{[\"timeout\",\"headers\",\"queryParameters\",\"data\",\"cacheable\"].indexOf(a)===-1&&(o[a]=r[a])}),{data:Object.entries(o).length>0?o:void 0,timeout:r.timeout||e,headers:r.headers||{},queryParameters:r.queryParameters||{},cacheable:r.cacheable}}var K2={Read:1,Write:2,Any:3},xC={Up:1,Down:2,Timeouted:3},Lme=2*60*1e3;function UH(t,e=xC.Up){return{...t,status:e,lastUpdate:Date.now()}}function Nme(t){return t.status===xC.Up||Date.now()-t.lastUpdate>Lme}function Ome(t){return t.status===xC.Timeouted&&Date.now()-t.lastUpdate<=Lme}function _H(t){return typeof t==\"string\"?{protocol:\"https\",url:t,accept:K2.Any}:{protocol:t.protocol||\"https\",url:t.url,accept:t.accept||K2.Any}}function Pdt(t,e){return Promise.all(e.map(r=>t.get(r,()=>Promise.resolve(UH(r))))).then(r=>{let o=r.filter(A=>Nme(A)),a=r.filter(A=>Ome(A)),n=[...o,...a],u=n.length>0?n.map(A=>_H(A)):e;return{getTimeout(A,p){return(a.length===0&&A===0?1:a.length+3+A)*p},statelessHosts:u}})}var Sdt=({isTimedOut:t,status:e})=>!t&&~~e===0,bdt=t=>{let e=t.status;return t.isTimedOut||Sdt(t)||~~(e/100)!==2&&~~(e/100)!==4},xdt=({status:t})=>~~(t/100)===2,kdt=(t,e)=>bdt(t)?e.onRetry(t):xdt(t)?e.onSuccess(t):e.onFail(t);function Rme(t,e,r,o){let a=[],n=qme(r,o),u=Gme(t,o),A=r.method,p=r.method!==Tme.MethodEnum.Get?{}:{...r.data,...o.data},h={\"x-algolia-agent\":t.userAgent.value,...t.queryParameters,...p,...o.queryParameters},E=0,I=(v,x)=>{let C=v.pop();if(C===void 0)throw Wme(MH(a));let R={data:n,headers:u,method:A,url:_me(C,r.path,h),connectTimeout:x(E,t.timeouts.connect),responseTimeout:x(E,o.timeout)},N=V=>{let te={request:R,response:V,host:C,triesLeft:v.length};return a.push(te),te},U={onSuccess:V=>Mme(V),onRetry(V){let te=N(V);return V.isTimedOut&&E++,Promise.all([t.logger.info(\"Retryable failure\",HH(te)),t.hostsCache.set(C,UH(C,V.isTimedOut?xC.Timeouted:xC.Down))]).then(()=>I(v,x))},onFail(V){throw N(V),Ume(V,MH(a))}};return t.requester.send(R).then(V=>kdt(V,U))};return Pdt(t.hostsCache,e).then(v=>I([...v.statelessHosts].reverse(),v.getTimeout))}function Qdt(t){let{hostsCache:e,logger:r,requester:o,requestsCache:a,responsesCache:n,timeouts:u,userAgent:A,hosts:p,queryParameters:h,headers:E}=t,I={hostsCache:e,logger:r,requester:o,requestsCache:a,responsesCache:n,timeouts:u,userAgent:A,headers:E,queryParameters:h,hosts:p.map(v=>_H(v)),read(v,x){let C=OH(x,I.timeouts.read),R=()=>Rme(I,I.hosts.filter(V=>(V.accept&K2.Read)!==0),v,C);if((C.cacheable!==void 0?C.cacheable:v.cacheable)!==!0)return R();let U={request:v,mappedRequestOptions:C,transporter:{queryParameters:I.queryParameters,headers:I.headers}};return I.responsesCache.get(U,()=>I.requestsCache.get(U,()=>I.requestsCache.set(U,R()).then(V=>Promise.all([I.requestsCache.delete(U),V]),V=>Promise.all([I.requestsCache.delete(U),Promise.reject(V)])).then(([V,te])=>te)),{miss:V=>I.responsesCache.set(U,V)})},write(v,x){return Rme(I,I.hosts.filter(C=>(C.accept&K2.Write)!==0),v,OH(x,I.timeouts.write))}};return I}function Fdt(t){let e={value:`Algolia for JavaScript (${t})`,add(r){let o=`; ${r.segment}${r.version!==void 0?` (${r.version})`:\"\"}`;return e.value.indexOf(o)===-1&&(e.value=`${e.value}${o}`),e}};return e}function Mme(t){try{return JSON.parse(t.content)}catch(e){throw Yme(e.message,t)}}function Ume({content:t,status:e},r){let o=t;try{o=JSON.parse(t).message}catch{}return jme(o,e,r)}function Rdt(t,...e){let r=0;return t.replace(/%s/g,()=>encodeURIComponent(e[r++]))}function _me(t,e,r){let o=Hme(r),a=`${t.protocol}://${t.url}/${e.charAt(0)===\"/\"?e.substr(1):e}`;return o.length&&(a+=`?${o}`),a}function Hme(t){let e=r=>Object.prototype.toString.call(r)===\"[object Object]\"||Object.prototype.toString.call(r)===\"[object Array]\";return Object.keys(t).map(r=>Rdt(\"%s=%s\",r,e(t[r])?JSON.stringify(t[r]):t[r])).join(\"&\")}function qme(t,e){if(t.method===Tme.MethodEnum.Get||t.data===void 0&&e.data===void 0)return;let r=Array.isArray(t.data)?t.data:{...t.data,...e.data};return JSON.stringify(r)}function Gme(t,e){let r={...t.headers,...e.headers},o={};return Object.keys(r).forEach(a=>{let n=r[a];o[a.toLowerCase()]=n}),o}function MH(t){return t.map(e=>HH(e))}function HH(t){let e=t.request.headers[\"x-algolia-api-key\"]?{\"x-algolia-api-key\":\"*****\"}:{};return{...t,request:{...t.request,headers:{...t.request.headers,...e}}}}function jme(t,e,r){return{name:\"ApiError\",message:t,status:e,transporterStackTrace:r}}function Yme(t,e){return{name:\"DeserializationError\",message:t,response:e}}function Wme(t){return{name:\"RetryError\",message:\"Unreachable hosts - your application id may be incorrect. If the error persists, contact support@algolia.com.\",transporterStackTrace:t}}Fi.CallEnum=K2;Fi.HostStatusEnum=xC;Fi.createApiError=jme;Fi.createDeserializationError=Yme;Fi.createMappedRequestOptions=OH;Fi.createRetryError=Wme;Fi.createStatefulHost=UH;Fi.createStatelessHost=_H;Fi.createTransporter=Qdt;Fi.createUserAgent=Fdt;Fi.deserializeFailure=Ume;Fi.deserializeSuccess=Mme;Fi.isStatefulHostTimeouted=Ome;Fi.isStatefulHostUp=Nme;Fi.serializeData=qme;Fi.serializeHeaders=Gme;Fi.serializeQueryParameters=Hme;Fi.serializeUrl=_me;Fi.stackFrameWithoutCredentials=HH;Fi.stackTraceWithoutCredentials=MH});var z2=_((_Wt,zme)=>{zme.exports=Kme()});var Vme=_(y0=>{\"use strict\";Object.defineProperty(y0,\"__esModule\",{value:!0});var kC=Y2(),Tdt=z2(),V2=W2(),Ldt=t=>{let e=t.region||\"us\",r=kC.createAuth(kC.AuthMode.WithinHeaders,t.appId,t.apiKey),o=Tdt.createTransporter({hosts:[{url:`analytics.${e}.algolia.com`}],...t,headers:{...r.headers(),\"content-type\":\"application/json\",...t.headers},queryParameters:{...r.queryParameters(),...t.queryParameters}}),a=t.appId;return kC.addMethods({appId:a,transporter:o},t.methods)},Ndt=t=>(e,r)=>t.transporter.write({method:V2.MethodEnum.Post,path:\"2/abtests\",data:e},r),Odt=t=>(e,r)=>t.transporter.write({method:V2.MethodEnum.Delete,path:kC.encode(\"2/abtests/%s\",e)},r),Mdt=t=>(e,r)=>t.transporter.read({method:V2.MethodEnum.Get,path:kC.encode(\"2/abtests/%s\",e)},r),Udt=t=>e=>t.transporter.read({method:V2.MethodEnum.Get,path:\"2/abtests\"},e),_dt=t=>(e,r)=>t.transporter.write({method:V2.MethodEnum.Post,path:kC.encode(\"2/abtests/%s/stop\",e)},r);y0.addABTest=Ndt;y0.createAnalyticsClient=Ldt;y0.deleteABTest=Odt;y0.getABTest=Mdt;y0.getABTests=Udt;y0.stopABTest=_dt});var Xme=_((qWt,Jme)=>{Jme.exports=Vme()});var $me=_(J2=>{\"use strict\";Object.defineProperty(J2,\"__esModule\",{value:!0});var qH=Y2(),Hdt=z2(),Zme=W2(),qdt=t=>{let e=t.region||\"us\",r=qH.createAuth(qH.AuthMode.WithinHeaders,t.appId,t.apiKey),o=Hdt.createTransporter({hosts:[{url:`personalization.${e}.algolia.com`}],...t,headers:{...r.headers(),\"content-type\":\"application/json\",...t.headers},queryParameters:{...r.queryParameters(),...t.queryParameters}});return qH.addMethods({appId:t.appId,transporter:o},t.methods)},Gdt=t=>e=>t.transporter.read({method:Zme.MethodEnum.Get,path:\"1/strategies/personalization\"},e),jdt=t=>(e,r)=>t.transporter.write({method:Zme.MethodEnum.Post,path:\"1/strategies/personalization\",data:e},r);J2.createPersonalizationClient=qdt;J2.getPersonalizationStrategy=Gdt;J2.setPersonalizationStrategy=jdt});var tye=_((jWt,eye)=>{eye.exports=$me()});var gye=_(Ft=>{\"use strict\";Object.defineProperty(Ft,\"__esModule\",{value:!0});var jt=Y2(),La=z2(),Ir=W2(),Ydt=ve(\"crypto\");function Bk(t){let e=r=>t.request(r).then(o=>{if(t.batch!==void 0&&t.batch(o.hits),!t.shouldStop(o))return o.cursor?e({cursor:o.cursor}):e({page:(r.page||0)+1})});return e({})}var Wdt=t=>{let e=t.appId,r=jt.createAuth(t.authMode!==void 0?t.authMode:jt.AuthMode.WithinHeaders,e,t.apiKey),o=La.createTransporter({hosts:[{url:`${e}-dsn.algolia.net`,accept:La.CallEnum.Read},{url:`${e}.algolia.net`,accept:La.CallEnum.Write}].concat(jt.shuffle([{url:`${e}-1.algolianet.com`},{url:`${e}-2.algolianet.com`},{url:`${e}-3.algolianet.com`}])),...t,headers:{...r.headers(),\"content-type\":\"application/x-www-form-urlencoded\",...t.headers},queryParameters:{...r.queryParameters(),...t.queryParameters}}),a={transporter:o,appId:e,addAlgoliaAgent(n,u){o.userAgent.add({segment:n,version:u})},clearCache(){return Promise.all([o.requestsCache.clear(),o.responsesCache.clear()]).then(()=>{})}};return jt.addMethods(a,t.methods)};function rye(){return{name:\"MissingObjectIDError\",message:\"All objects must have an unique objectID (like a primary key) to be valid. Algolia is also able to generate objectIDs automatically but *it's not recommended*. To do it, use the `{'autoGenerateObjectIDIfNotExist': true}` option.\"}}function nye(){return{name:\"ObjectNotFoundError\",message:\"Object not found.\"}}function iye(){return{name:\"ValidUntilNotFoundError\",message:\"ValidUntil not found in given secured api key.\"}}var Kdt=t=>(e,r)=>{let{queryParameters:o,...a}=r||{},n={acl:e,...o!==void 0?{queryParameters:o}:{}},u=(A,p)=>jt.createRetryablePromise(h=>X2(t)(A.key,p).catch(E=>{if(E.status!==404)throw E;return h()}));return jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:\"1/keys\",data:n},a),u)},zdt=t=>(e,r,o)=>{let a=La.createMappedRequestOptions(o);return a.queryParameters[\"X-Algolia-User-ID\"]=e,t.transporter.write({method:Ir.MethodEnum.Post,path:\"1/clusters/mapping\",data:{cluster:r}},a)},Vdt=t=>(e,r,o)=>t.transporter.write({method:Ir.MethodEnum.Post,path:\"1/clusters/mapping/batch\",data:{users:e,cluster:r}},o),Jdt=t=>(e,r)=>jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:jt.encode(\"/1/dictionaries/%s/batch\",e),data:{clearExistingDictionaryEntries:!0,requests:{action:\"addEntry\",body:[]}}},r),(o,a)=>QC(t)(o.taskID,a)),vk=t=>(e,r,o)=>{let a=(n,u)=>Z2(t)(e,{methods:{waitTask:Zi}}).waitTask(n.taskID,u);return jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:jt.encode(\"1/indexes/%s/operation\",e),data:{operation:\"copy\",destination:r}},o),a)},Xdt=t=>(e,r,o)=>vk(t)(e,r,{...o,scope:[Pk.Rules]}),Zdt=t=>(e,r,o)=>vk(t)(e,r,{...o,scope:[Pk.Settings]}),$dt=t=>(e,r,o)=>vk(t)(e,r,{...o,scope:[Pk.Synonyms]}),emt=t=>(e,r)=>e.method===Ir.MethodEnum.Get?t.transporter.read(e,r):t.transporter.write(e,r),tmt=t=>(e,r)=>{let o=(a,n)=>jt.createRetryablePromise(u=>X2(t)(e,n).then(u).catch(A=>{if(A.status!==404)throw A}));return jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Delete,path:jt.encode(\"1/keys/%s\",e)},r),o)},rmt=t=>(e,r,o)=>{let a=r.map(n=>({action:\"deleteEntry\",body:{objectID:n}}));return jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:jt.encode(\"/1/dictionaries/%s/batch\",e),data:{clearExistingDictionaryEntries:!1,requests:a}},o),(n,u)=>QC(t)(n.taskID,u))},nmt=()=>(t,e)=>{let r=La.serializeQueryParameters(e),o=Ydt.createHmac(\"sha256\",t).update(r).digest(\"hex\");return Buffer.from(o+r).toString(\"base64\")},X2=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Get,path:jt.encode(\"1/keys/%s\",e)},r),sye=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Get,path:jt.encode(\"1/task/%s\",e.toString())},r),imt=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:\"/1/dictionaries/*/settings\"},e),smt=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:\"1/logs\"},e),omt=()=>t=>{let e=Buffer.from(t,\"base64\").toString(\"ascii\"),r=/validUntil=(\\d+)/,o=e.match(r);if(o===null)throw iye();return parseInt(o[1],10)-Math.round(new Date().getTime()/1e3)},amt=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:\"1/clusters/mapping/top\"},e),lmt=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Get,path:jt.encode(\"1/clusters/mapping/%s\",e)},r),cmt=t=>e=>{let{retrieveMappings:r,...o}=e||{};return r===!0&&(o.getClusters=!0),t.transporter.read({method:Ir.MethodEnum.Get,path:\"1/clusters/mapping/pending\"},o)},Z2=t=>(e,r={})=>{let o={transporter:t.transporter,appId:t.appId,indexName:e};return jt.addMethods(o,r.methods)},umt=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:\"1/keys\"},e),Amt=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:\"1/clusters\"},e),fmt=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:\"1/indexes\"},e),pmt=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:\"1/clusters/mapping\"},e),hmt=t=>(e,r,o)=>{let a=(n,u)=>Z2(t)(e,{methods:{waitTask:Zi}}).waitTask(n.taskID,u);return jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:jt.encode(\"1/indexes/%s/operation\",e),data:{operation:\"move\",destination:r}},o),a)},gmt=t=>(e,r)=>{let o=(a,n)=>Promise.all(Object.keys(a.taskID).map(u=>Z2(t)(u,{methods:{waitTask:Zi}}).waitTask(a.taskID[u],n)));return jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:\"1/indexes/*/batch\",data:{requests:e}},r),o)},dmt=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Post,path:\"1/indexes/*/objects\",data:{requests:e}},r),mmt=t=>(e,r)=>{let o=e.map(a=>({...a,params:La.serializeQueryParameters(a.params||{})}));return t.transporter.read({method:Ir.MethodEnum.Post,path:\"1/indexes/*/queries\",data:{requests:o},cacheable:!0},r)},ymt=t=>(e,r)=>Promise.all(e.map(o=>{let{facetName:a,facetQuery:n,...u}=o.params;return Z2(t)(o.indexName,{methods:{searchForFacetValues:fye}}).searchForFacetValues(a,n,{...r,...u})})),Emt=t=>(e,r)=>{let o=La.createMappedRequestOptions(r);return o.queryParameters[\"X-Algolia-User-ID\"]=e,t.transporter.write({method:Ir.MethodEnum.Delete,path:\"1/clusters/mapping\"},o)},Cmt=t=>(e,r,o)=>{let a=r.map(n=>({action:\"addEntry\",body:n}));return jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:jt.encode(\"/1/dictionaries/%s/batch\",e),data:{clearExistingDictionaryEntries:!0,requests:a}},o),(n,u)=>QC(t)(n.taskID,u))},wmt=t=>(e,r)=>{let o=(a,n)=>jt.createRetryablePromise(u=>X2(t)(e,n).catch(A=>{if(A.status!==404)throw A;return u()}));return jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:jt.encode(\"1/keys/%s/restore\",e)},r),o)},Imt=t=>(e,r,o)=>{let a=r.map(n=>({action:\"addEntry\",body:n}));return jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:jt.encode(\"/1/dictionaries/%s/batch\",e),data:{clearExistingDictionaryEntries:!1,requests:a}},o),(n,u)=>QC(t)(n.taskID,u))},Bmt=t=>(e,r,o)=>t.transporter.read({method:Ir.MethodEnum.Post,path:jt.encode(\"/1/dictionaries/%s/search\",e),data:{query:r},cacheable:!0},o),vmt=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Post,path:\"1/clusters/mapping/search\",data:{query:e}},r),Dmt=t=>(e,r)=>jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Put,path:\"/1/dictionaries/*/settings\",data:e},r),(o,a)=>QC(t)(o.taskID,a)),Pmt=t=>(e,r)=>{let o=Object.assign({},r),{queryParameters:a,...n}=r||{},u=a?{queryParameters:a}:{},A=[\"acl\",\"indexes\",\"referers\",\"restrictSources\",\"queryParameters\",\"description\",\"maxQueriesPerIPPerHour\",\"maxHitsPerQuery\"],p=E=>Object.keys(o).filter(I=>A.indexOf(I)!==-1).every(I=>{if(Array.isArray(E[I])&&Array.isArray(o[I])){let v=E[I];return v.length===o[I].length&&v.every((x,C)=>x===o[I][C])}else return E[I]===o[I]}),h=(E,I)=>jt.createRetryablePromise(v=>X2(t)(e,I).then(x=>p(x)?Promise.resolve():v()));return jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Put,path:jt.encode(\"1/keys/%s\",e),data:u},n),h)},QC=t=>(e,r)=>jt.createRetryablePromise(o=>sye(t)(e,r).then(a=>a.status!==\"published\"?o():void 0)),oye=t=>(e,r)=>{let o=(a,n)=>Zi(t)(a.taskID,n);return jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:jt.encode(\"1/indexes/%s/batch\",t.indexName),data:{requests:e}},r),o)},Smt=t=>e=>Bk({shouldStop:r=>r.cursor===void 0,...e,request:r=>t.transporter.read({method:Ir.MethodEnum.Post,path:jt.encode(\"1/indexes/%s/browse\",t.indexName),data:r},e)}),bmt=t=>e=>{let r={hitsPerPage:1e3,...e};return Bk({shouldStop:o=>o.hits.length<r.hitsPerPage,...r,request(o){return pye(t)(\"\",{...r,...o}).then(a=>({...a,hits:a.hits.map(n=>(delete n._highlightResult,n))}))}})},xmt=t=>e=>{let r={hitsPerPage:1e3,...e};return Bk({shouldStop:o=>o.hits.length<r.hitsPerPage,...r,request(o){return hye(t)(\"\",{...r,...o}).then(a=>({...a,hits:a.hits.map(n=>(delete n._highlightResult,n))}))}})},Dk=t=>(e,r,o)=>{let{batchSize:a,...n}=o||{},u={taskIDs:[],objectIDs:[]},A=(p=0)=>{let h=[],E;for(E=p;E<e.length&&(h.push(e[E]),h.length!==(a||1e3));E++);return h.length===0?Promise.resolve(u):oye(t)(h.map(I=>({action:r,body:I})),n).then(I=>(u.objectIDs=u.objectIDs.concat(I.objectIDs),u.taskIDs.push(I.taskID),E++,A(E)))};return jt.createWaitablePromise(A(),(p,h)=>Promise.all(p.taskIDs.map(E=>Zi(t)(E,h))))},kmt=t=>e=>jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:jt.encode(\"1/indexes/%s/clear\",t.indexName)},e),(r,o)=>Zi(t)(r.taskID,o)),Qmt=t=>e=>{let{forwardToReplicas:r,...o}=e||{},a=La.createMappedRequestOptions(o);return r&&(a.queryParameters.forwardToReplicas=1),jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:jt.encode(\"1/indexes/%s/rules/clear\",t.indexName)},a),(n,u)=>Zi(t)(n.taskID,u))},Fmt=t=>e=>{let{forwardToReplicas:r,...o}=e||{},a=La.createMappedRequestOptions(o);return r&&(a.queryParameters.forwardToReplicas=1),jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:jt.encode(\"1/indexes/%s/synonyms/clear\",t.indexName)},a),(n,u)=>Zi(t)(n.taskID,u))},Rmt=t=>(e,r)=>jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:jt.encode(\"1/indexes/%s/deleteByQuery\",t.indexName),data:e},r),(o,a)=>Zi(t)(o.taskID,a)),Tmt=t=>e=>jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Delete,path:jt.encode(\"1/indexes/%s\",t.indexName)},e),(r,o)=>Zi(t)(r.taskID,o)),Lmt=t=>(e,r)=>jt.createWaitablePromise(aye(t)([e],r).then(o=>({taskID:o.taskIDs[0]})),(o,a)=>Zi(t)(o.taskID,a)),aye=t=>(e,r)=>{let o=e.map(a=>({objectID:a}));return Dk(t)(o,im.DeleteObject,r)},Nmt=t=>(e,r)=>{let{forwardToReplicas:o,...a}=r||{},n=La.createMappedRequestOptions(a);return o&&(n.queryParameters.forwardToReplicas=1),jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Delete,path:jt.encode(\"1/indexes/%s/rules/%s\",t.indexName,e)},n),(u,A)=>Zi(t)(u.taskID,A))},Omt=t=>(e,r)=>{let{forwardToReplicas:o,...a}=r||{},n=La.createMappedRequestOptions(a);return o&&(n.queryParameters.forwardToReplicas=1),jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Delete,path:jt.encode(\"1/indexes/%s/synonyms/%s\",t.indexName,e)},n),(u,A)=>Zi(t)(u.taskID,A))},Mmt=t=>e=>lye(t)(e).then(()=>!0).catch(r=>{if(r.status!==404)throw r;return!1}),Umt=t=>(e,r,o)=>t.transporter.read({method:Ir.MethodEnum.Post,path:jt.encode(\"1/answers/%s/prediction\",t.indexName),data:{query:e,queryLanguages:r},cacheable:!0},o),_mt=t=>(e,r)=>{let{query:o,paginate:a,...n}=r||{},u=0,A=()=>Aye(t)(o||\"\",{...n,page:u}).then(p=>{for(let[h,E]of Object.entries(p.hits))if(e(E))return{object:E,position:parseInt(h,10),page:u};if(u++,a===!1||u>=p.nbPages)throw nye();return A()});return A()},Hmt=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Get,path:jt.encode(\"1/indexes/%s/%s\",t.indexName,e)},r),qmt=()=>(t,e)=>{for(let[r,o]of Object.entries(t.hits))if(o.objectID===e)return parseInt(r,10);return-1},Gmt=t=>(e,r)=>{let{attributesToRetrieve:o,...a}=r||{},n=e.map(u=>({indexName:t.indexName,objectID:u,...o?{attributesToRetrieve:o}:{}}));return t.transporter.read({method:Ir.MethodEnum.Post,path:\"1/indexes/*/objects\",data:{requests:n}},a)},jmt=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Get,path:jt.encode(\"1/indexes/%s/rules/%s\",t.indexName,e)},r),lye=t=>e=>t.transporter.read({method:Ir.MethodEnum.Get,path:jt.encode(\"1/indexes/%s/settings\",t.indexName),data:{getVersion:2}},e),Ymt=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Get,path:jt.encode(\"1/indexes/%s/synonyms/%s\",t.indexName,e)},r),cye=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Get,path:jt.encode(\"1/indexes/%s/task/%s\",t.indexName,e.toString())},r),Wmt=t=>(e,r)=>jt.createWaitablePromise(uye(t)([e],r).then(o=>({objectID:o.objectIDs[0],taskID:o.taskIDs[0]})),(o,a)=>Zi(t)(o.taskID,a)),uye=t=>(e,r)=>{let{createIfNotExists:o,...a}=r||{},n=o?im.PartialUpdateObject:im.PartialUpdateObjectNoCreate;return Dk(t)(e,n,a)},Kmt=t=>(e,r)=>{let{safe:o,autoGenerateObjectIDIfNotExist:a,batchSize:n,...u}=r||{},A=(C,R,N,U)=>jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:jt.encode(\"1/indexes/%s/operation\",C),data:{operation:N,destination:R}},U),(V,te)=>Zi(t)(V.taskID,te)),p=Math.random().toString(36).substring(7),h=`${t.indexName}_tmp_${p}`,E=GH({appId:t.appId,transporter:t.transporter,indexName:h}),I=[],v=A(t.indexName,h,\"copy\",{...u,scope:[\"settings\",\"synonyms\",\"rules\"]});I.push(v);let x=(o?v.wait(u):v).then(()=>{let C=E(e,{...u,autoGenerateObjectIDIfNotExist:a,batchSize:n});return I.push(C),o?C.wait(u):C}).then(()=>{let C=A(h,t.indexName,\"move\",u);return I.push(C),o?C.wait(u):C}).then(()=>Promise.all(I)).then(([C,R,N])=>({objectIDs:R.objectIDs,taskIDs:[C.taskID,...R.taskIDs,N.taskID]}));return jt.createWaitablePromise(x,(C,R)=>Promise.all(I.map(N=>N.wait(R))))},zmt=t=>(e,r)=>jH(t)(e,{...r,clearExistingRules:!0}),Vmt=t=>(e,r)=>YH(t)(e,{...r,clearExistingSynonyms:!0}),Jmt=t=>(e,r)=>jt.createWaitablePromise(GH(t)([e],r).then(o=>({objectID:o.objectIDs[0],taskID:o.taskIDs[0]})),(o,a)=>Zi(t)(o.taskID,a)),GH=t=>(e,r)=>{let{autoGenerateObjectIDIfNotExist:o,...a}=r||{},n=o?im.AddObject:im.UpdateObject;if(n===im.UpdateObject){for(let u of e)if(u.objectID===void 0)return jt.createWaitablePromise(Promise.reject(rye()))}return Dk(t)(e,n,a)},Xmt=t=>(e,r)=>jH(t)([e],r),jH=t=>(e,r)=>{let{forwardToReplicas:o,clearExistingRules:a,...n}=r||{},u=La.createMappedRequestOptions(n);return o&&(u.queryParameters.forwardToReplicas=1),a&&(u.queryParameters.clearExistingRules=1),jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:jt.encode(\"1/indexes/%s/rules/batch\",t.indexName),data:e},u),(A,p)=>Zi(t)(A.taskID,p))},Zmt=t=>(e,r)=>YH(t)([e],r),YH=t=>(e,r)=>{let{forwardToReplicas:o,clearExistingSynonyms:a,replaceExistingSynonyms:n,...u}=r||{},A=La.createMappedRequestOptions(u);return o&&(A.queryParameters.forwardToReplicas=1),(n||a)&&(A.queryParameters.replaceExistingSynonyms=1),jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Post,path:jt.encode(\"1/indexes/%s/synonyms/batch\",t.indexName),data:e},A),(p,h)=>Zi(t)(p.taskID,h))},Aye=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Post,path:jt.encode(\"1/indexes/%s/query\",t.indexName),data:{query:e},cacheable:!0},r),fye=t=>(e,r,o)=>t.transporter.read({method:Ir.MethodEnum.Post,path:jt.encode(\"1/indexes/%s/facets/%s/query\",t.indexName,e),data:{facetQuery:r},cacheable:!0},o),pye=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Post,path:jt.encode(\"1/indexes/%s/rules/search\",t.indexName),data:{query:e}},r),hye=t=>(e,r)=>t.transporter.read({method:Ir.MethodEnum.Post,path:jt.encode(\"1/indexes/%s/synonyms/search\",t.indexName),data:{query:e}},r),$mt=t=>(e,r)=>{let{forwardToReplicas:o,...a}=r||{},n=La.createMappedRequestOptions(a);return o&&(n.queryParameters.forwardToReplicas=1),jt.createWaitablePromise(t.transporter.write({method:Ir.MethodEnum.Put,path:jt.encode(\"1/indexes/%s/settings\",t.indexName),data:e},n),(u,A)=>Zi(t)(u.taskID,A))},Zi=t=>(e,r)=>jt.createRetryablePromise(o=>cye(t)(e,r).then(a=>a.status!==\"published\"?o():void 0)),eyt={AddObject:\"addObject\",Analytics:\"analytics\",Browser:\"browse\",DeleteIndex:\"deleteIndex\",DeleteObject:\"deleteObject\",EditSettings:\"editSettings\",Inference:\"inference\",ListIndexes:\"listIndexes\",Logs:\"logs\",Personalization:\"personalization\",Recommendation:\"recommendation\",Search:\"search\",SeeUnretrievableAttributes:\"seeUnretrievableAttributes\",Settings:\"settings\",Usage:\"usage\"},im={AddObject:\"addObject\",UpdateObject:\"updateObject\",PartialUpdateObject:\"partialUpdateObject\",PartialUpdateObjectNoCreate:\"partialUpdateObjectNoCreate\",DeleteObject:\"deleteObject\",DeleteIndex:\"delete\",ClearIndex:\"clear\"},Pk={Settings:\"settings\",Synonyms:\"synonyms\",Rules:\"rules\"},tyt={None:\"none\",StopIfEnoughMatches:\"stopIfEnoughMatches\"},ryt={Synonym:\"synonym\",OneWaySynonym:\"oneWaySynonym\",AltCorrection1:\"altCorrection1\",AltCorrection2:\"altCorrection2\",Placeholder:\"placeholder\"};Ft.ApiKeyACLEnum=eyt;Ft.BatchActionEnum=im;Ft.ScopeEnum=Pk;Ft.StrategyEnum=tyt;Ft.SynonymEnum=ryt;Ft.addApiKey=Kdt;Ft.assignUserID=zdt;Ft.assignUserIDs=Vdt;Ft.batch=oye;Ft.browseObjects=Smt;Ft.browseRules=bmt;Ft.browseSynonyms=xmt;Ft.chunkedBatch=Dk;Ft.clearDictionaryEntries=Jdt;Ft.clearObjects=kmt;Ft.clearRules=Qmt;Ft.clearSynonyms=Fmt;Ft.copyIndex=vk;Ft.copyRules=Xdt;Ft.copySettings=Zdt;Ft.copySynonyms=$dt;Ft.createBrowsablePromise=Bk;Ft.createMissingObjectIDError=rye;Ft.createObjectNotFoundError=nye;Ft.createSearchClient=Wdt;Ft.createValidUntilNotFoundError=iye;Ft.customRequest=emt;Ft.deleteApiKey=tmt;Ft.deleteBy=Rmt;Ft.deleteDictionaryEntries=rmt;Ft.deleteIndex=Tmt;Ft.deleteObject=Lmt;Ft.deleteObjects=aye;Ft.deleteRule=Nmt;Ft.deleteSynonym=Omt;Ft.exists=Mmt;Ft.findAnswers=Umt;Ft.findObject=_mt;Ft.generateSecuredApiKey=nmt;Ft.getApiKey=X2;Ft.getAppTask=sye;Ft.getDictionarySettings=imt;Ft.getLogs=smt;Ft.getObject=Hmt;Ft.getObjectPosition=qmt;Ft.getObjects=Gmt;Ft.getRule=jmt;Ft.getSecuredApiKeyRemainingValidity=omt;Ft.getSettings=lye;Ft.getSynonym=Ymt;Ft.getTask=cye;Ft.getTopUserIDs=amt;Ft.getUserID=lmt;Ft.hasPendingMappings=cmt;Ft.initIndex=Z2;Ft.listApiKeys=umt;Ft.listClusters=Amt;Ft.listIndices=fmt;Ft.listUserIDs=pmt;Ft.moveIndex=hmt;Ft.multipleBatch=gmt;Ft.multipleGetObjects=dmt;Ft.multipleQueries=mmt;Ft.multipleSearchForFacetValues=ymt;Ft.partialUpdateObject=Wmt;Ft.partialUpdateObjects=uye;Ft.removeUserID=Emt;Ft.replaceAllObjects=Kmt;Ft.replaceAllRules=zmt;Ft.replaceAllSynonyms=Vmt;Ft.replaceDictionaryEntries=Cmt;Ft.restoreApiKey=wmt;Ft.saveDictionaryEntries=Imt;Ft.saveObject=Jmt;Ft.saveObjects=GH;Ft.saveRule=Xmt;Ft.saveRules=jH;Ft.saveSynonym=Zmt;Ft.saveSynonyms=YH;Ft.search=Aye;Ft.searchDictionaryEntries=Bmt;Ft.searchForFacetValues=fye;Ft.searchRules=pye;Ft.searchSynonyms=hye;Ft.searchUserIDs=vmt;Ft.setDictionarySettings=Dmt;Ft.setSettings=$mt;Ft.updateApiKey=Pmt;Ft.waitAppTask=QC;Ft.waitTask=Zi});var mye=_((WWt,dye)=>{dye.exports=gye()});var yye=_(Sk=>{\"use strict\";Object.defineProperty(Sk,\"__esModule\",{value:!0});function nyt(){return{debug(t,e){return Promise.resolve()},info(t,e){return Promise.resolve()},error(t,e){return Promise.resolve()}}}var iyt={Debug:1,Info:2,Error:3};Sk.LogLevelEnum=iyt;Sk.createNullLogger=nyt});var Cye=_((zWt,Eye)=>{Eye.exports=yye()});var vye=_(WH=>{\"use strict\";Object.defineProperty(WH,\"__esModule\",{value:!0});var wye=ve(\"http\"),Iye=ve(\"https\"),syt=ve(\"url\"),Bye={keepAlive:!0},oyt=new wye.Agent(Bye),ayt=new Iye.Agent(Bye);function lyt({agent:t,httpAgent:e,httpsAgent:r,requesterOptions:o={}}={}){let a=e||t||oyt,n=r||t||ayt;return{send(u){return new Promise(A=>{let p=syt.parse(u.url),h=p.query===null?p.pathname:`${p.pathname}?${p.query}`,E={...o,agent:p.protocol===\"https:\"?n:a,hostname:p.hostname,path:h,method:u.method,headers:{...o&&o.headers?o.headers:{},...u.headers},...p.port!==void 0?{port:p.port||\"\"}:{}},I=(p.protocol===\"https:\"?Iye:wye).request(E,R=>{let N=[];R.on(\"data\",U=>{N=N.concat(U)}),R.on(\"end\",()=>{clearTimeout(x),clearTimeout(C),A({status:R.statusCode||0,content:Buffer.concat(N).toString(),isTimedOut:!1})})}),v=(R,N)=>setTimeout(()=>{I.abort(),A({status:0,content:N,isTimedOut:!0})},R*1e3),x=v(u.connectTimeout,\"Connection timeout\"),C;I.on(\"error\",R=>{clearTimeout(x),clearTimeout(C),A({status:0,content:R.message,isTimedOut:!1})}),I.once(\"response\",()=>{clearTimeout(x),C=v(u.responseTimeout,\"Socket timeout\")}),u.data!==void 0&&I.write(u.data),I.end()})},destroy(){return a.destroy(),n.destroy(),Promise.resolve()}}}WH.createNodeHttpRequester=lyt});var Pye=_((JWt,Dye)=>{Dye.exports=vye()});var kye=_((XWt,xye)=>{\"use strict\";var Sye=vme(),cyt=Sme(),FC=Xme(),zH=Y2(),KH=tye(),_t=mye(),uyt=Cye(),Ayt=Pye(),fyt=z2();function bye(t,e,r){let o={appId:t,apiKey:e,timeouts:{connect:2,read:5,write:30},requester:Ayt.createNodeHttpRequester(),logger:uyt.createNullLogger(),responsesCache:Sye.createNullCache(),requestsCache:Sye.createNullCache(),hostsCache:cyt.createInMemoryCache(),userAgent:fyt.createUserAgent(zH.version).add({segment:\"Node.js\",version:process.versions.node})},a={...o,...r},n=()=>u=>KH.createPersonalizationClient({...o,...u,methods:{getPersonalizationStrategy:KH.getPersonalizationStrategy,setPersonalizationStrategy:KH.setPersonalizationStrategy}});return _t.createSearchClient({...a,methods:{search:_t.multipleQueries,searchForFacetValues:_t.multipleSearchForFacetValues,multipleBatch:_t.multipleBatch,multipleGetObjects:_t.multipleGetObjects,multipleQueries:_t.multipleQueries,copyIndex:_t.copyIndex,copySettings:_t.copySettings,copyRules:_t.copyRules,copySynonyms:_t.copySynonyms,moveIndex:_t.moveIndex,listIndices:_t.listIndices,getLogs:_t.getLogs,listClusters:_t.listClusters,multipleSearchForFacetValues:_t.multipleSearchForFacetValues,getApiKey:_t.getApiKey,addApiKey:_t.addApiKey,listApiKeys:_t.listApiKeys,updateApiKey:_t.updateApiKey,deleteApiKey:_t.deleteApiKey,restoreApiKey:_t.restoreApiKey,assignUserID:_t.assignUserID,assignUserIDs:_t.assignUserIDs,getUserID:_t.getUserID,searchUserIDs:_t.searchUserIDs,listUserIDs:_t.listUserIDs,getTopUserIDs:_t.getTopUserIDs,removeUserID:_t.removeUserID,hasPendingMappings:_t.hasPendingMappings,generateSecuredApiKey:_t.generateSecuredApiKey,getSecuredApiKeyRemainingValidity:_t.getSecuredApiKeyRemainingValidity,destroy:zH.destroy,clearDictionaryEntries:_t.clearDictionaryEntries,deleteDictionaryEntries:_t.deleteDictionaryEntries,getDictionarySettings:_t.getDictionarySettings,getAppTask:_t.getAppTask,replaceDictionaryEntries:_t.replaceDictionaryEntries,saveDictionaryEntries:_t.saveDictionaryEntries,searchDictionaryEntries:_t.searchDictionaryEntries,setDictionarySettings:_t.setDictionarySettings,waitAppTask:_t.waitAppTask,customRequest:_t.customRequest,initIndex:u=>A=>_t.initIndex(u)(A,{methods:{batch:_t.batch,delete:_t.deleteIndex,findAnswers:_t.findAnswers,getObject:_t.getObject,getObjects:_t.getObjects,saveObject:_t.saveObject,saveObjects:_t.saveObjects,search:_t.search,searchForFacetValues:_t.searchForFacetValues,waitTask:_t.waitTask,setSettings:_t.setSettings,getSettings:_t.getSettings,partialUpdateObject:_t.partialUpdateObject,partialUpdateObjects:_t.partialUpdateObjects,deleteObject:_t.deleteObject,deleteObjects:_t.deleteObjects,deleteBy:_t.deleteBy,clearObjects:_t.clearObjects,browseObjects:_t.browseObjects,getObjectPosition:_t.getObjectPosition,findObject:_t.findObject,exists:_t.exists,saveSynonym:_t.saveSynonym,saveSynonyms:_t.saveSynonyms,getSynonym:_t.getSynonym,searchSynonyms:_t.searchSynonyms,browseSynonyms:_t.browseSynonyms,deleteSynonym:_t.deleteSynonym,clearSynonyms:_t.clearSynonyms,replaceAllObjects:_t.replaceAllObjects,replaceAllSynonyms:_t.replaceAllSynonyms,searchRules:_t.searchRules,getRule:_t.getRule,deleteRule:_t.deleteRule,saveRule:_t.saveRule,saveRules:_t.saveRules,replaceAllRules:_t.replaceAllRules,browseRules:_t.browseRules,clearRules:_t.clearRules}}),initAnalytics:()=>u=>FC.createAnalyticsClient({...o,...u,methods:{addABTest:FC.addABTest,getABTest:FC.getABTest,getABTests:FC.getABTests,stopABTest:FC.stopABTest,deleteABTest:FC.deleteABTest}}),initPersonalization:n,initRecommendation:()=>u=>(a.logger.info(\"The `initRecommendation` method is deprecated. Use `initPersonalization` instead.\"),n()(u))}})}bye.version=zH.version;xye.exports=bye});var JH=_((ZWt,VH)=>{var Qye=kye();VH.exports=Qye;VH.exports.default=Qye});var $H=_((eKt,Tye)=>{\"use strict\";var Rye=Object.getOwnPropertySymbols,hyt=Object.prototype.hasOwnProperty,gyt=Object.prototype.propertyIsEnumerable;function dyt(t){if(t==null)throw new TypeError(\"Object.assign cannot be called with null or undefined\");return Object(t)}function myt(){try{if(!Object.assign)return!1;var t=new String(\"abc\");if(t[5]=\"de\",Object.getOwnPropertyNames(t)[0]===\"5\")return!1;for(var e={},r=0;r<10;r++)e[\"_\"+String.fromCharCode(r)]=r;var o=Object.getOwnPropertyNames(e).map(function(n){return e[n]});if(o.join(\"\")!==\"0123456789\")return!1;var a={};return\"abcdefghijklmnopqrst\".split(\"\").forEach(function(n){a[n]=n}),Object.keys(Object.assign({},a)).join(\"\")===\"abcdefghijklmnopqrst\"}catch{return!1}}Tye.exports=myt()?Object.assign:function(t,e){for(var r,o=dyt(t),a,n=1;n<arguments.length;n++){r=Object(arguments[n]);for(var u in r)hyt.call(r,u)&&(o[u]=r[u]);if(Rye){a=Rye(r);for(var A=0;A<a.length;A++)gyt.call(r,a[A])&&(o[a[A]]=r[a[A]])}}return o}});var Wye=_(Ln=>{\"use strict\";var i6=$H(),eu=typeof Symbol==\"function\"&&Symbol.for,$2=eu?Symbol.for(\"react.element\"):60103,yyt=eu?Symbol.for(\"react.portal\"):60106,Eyt=eu?Symbol.for(\"react.fragment\"):60107,Cyt=eu?Symbol.for(\"react.strict_mode\"):60108,wyt=eu?Symbol.for(\"react.profiler\"):60114,Iyt=eu?Symbol.for(\"react.provider\"):60109,Byt=eu?Symbol.for(\"react.context\"):60110,vyt=eu?Symbol.for(\"react.forward_ref\"):60112,Dyt=eu?Symbol.for(\"react.suspense\"):60113,Pyt=eu?Symbol.for(\"react.memo\"):60115,Syt=eu?Symbol.for(\"react.lazy\"):60116,Lye=typeof Symbol==\"function\"&&Symbol.iterator;function eB(t){for(var e=\"https://reactjs.org/docs/error-decoder.html?invariant=\"+t,r=1;r<arguments.length;r++)e+=\"&args[]=\"+encodeURIComponent(arguments[r]);return\"Minified React error #\"+t+\"; visit \"+e+\" for the full message or use the non-minified dev environment for full errors and additional helpful warnings.\"}var Nye={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},Oye={};function RC(t,e,r){this.props=t,this.context=e,this.refs=Oye,this.updater=r||Nye}RC.prototype.isReactComponent={};RC.prototype.setState=function(t,e){if(typeof t!=\"object\"&&typeof t!=\"function\"&&t!=null)throw Error(eB(85));this.updater.enqueueSetState(this,t,e,\"setState\")};RC.prototype.forceUpdate=function(t){this.updater.enqueueForceUpdate(this,t,\"forceUpdate\")};function Mye(){}Mye.prototype=RC.prototype;function s6(t,e,r){this.props=t,this.context=e,this.refs=Oye,this.updater=r||Nye}var o6=s6.prototype=new Mye;o6.constructor=s6;i6(o6,RC.prototype);o6.isPureReactComponent=!0;var a6={current:null},Uye=Object.prototype.hasOwnProperty,_ye={key:!0,ref:!0,__self:!0,__source:!0};function Hye(t,e,r){var o,a={},n=null,u=null;if(e!=null)for(o in e.ref!==void 0&&(u=e.ref),e.key!==void 0&&(n=\"\"+e.key),e)Uye.call(e,o)&&!_ye.hasOwnProperty(o)&&(a[o]=e[o]);var A=arguments.length-2;if(A===1)a.children=r;else if(1<A){for(var p=Array(A),h=0;h<A;h++)p[h]=arguments[h+2];a.children=p}if(t&&t.defaultProps)for(o in A=t.defaultProps,A)a[o]===void 0&&(a[o]=A[o]);return{$$typeof:$2,type:t,key:n,ref:u,props:a,_owner:a6.current}}function byt(t,e){return{$$typeof:$2,type:t.type,key:e,ref:t.ref,props:t.props,_owner:t._owner}}function l6(t){return typeof t==\"object\"&&t!==null&&t.$$typeof===$2}function xyt(t){var e={\"=\":\"=0\",\":\":\"=2\"};return\"$\"+(\"\"+t).replace(/[=:]/g,function(r){return e[r]})}var qye=/\\/+/g,bk=[];function Gye(t,e,r,o){if(bk.length){var a=bk.pop();return a.result=t,a.keyPrefix=e,a.func=r,a.context=o,a.count=0,a}return{result:t,keyPrefix:e,func:r,context:o,count:0}}function jye(t){t.result=null,t.keyPrefix=null,t.func=null,t.context=null,t.count=0,10>bk.length&&bk.push(t)}function t6(t,e,r,o){var a=typeof t;(a===\"undefined\"||a===\"boolean\")&&(t=null);var n=!1;if(t===null)n=!0;else switch(a){case\"string\":case\"number\":n=!0;break;case\"object\":switch(t.$$typeof){case $2:case yyt:n=!0}}if(n)return r(o,t,e===\"\"?\".\"+e6(t,0):e),1;if(n=0,e=e===\"\"?\".\":e+\":\",Array.isArray(t))for(var u=0;u<t.length;u++){a=t[u];var A=e+e6(a,u);n+=t6(a,A,r,o)}else if(t===null||typeof t!=\"object\"?A=null:(A=Lye&&t[Lye]||t[\"@@iterator\"],A=typeof A==\"function\"?A:null),typeof A==\"function\")for(t=A.call(t),u=0;!(a=t.next()).done;)a=a.value,A=e+e6(a,u++),n+=t6(a,A,r,o);else if(a===\"object\")throw r=\"\"+t,Error(eB(31,r===\"[object Object]\"?\"object with keys {\"+Object.keys(t).join(\", \")+\"}\":r,\"\"));return n}function r6(t,e,r){return t==null?0:t6(t,\"\",e,r)}function e6(t,e){return typeof t==\"object\"&&t!==null&&t.key!=null?xyt(t.key):e.toString(36)}function kyt(t,e){t.func.call(t.context,e,t.count++)}function Qyt(t,e,r){var o=t.result,a=t.keyPrefix;t=t.func.call(t.context,e,t.count++),Array.isArray(t)?n6(t,o,r,function(n){return n}):t!=null&&(l6(t)&&(t=byt(t,a+(!t.key||e&&e.key===t.key?\"\":(\"\"+t.key).replace(qye,\"$&/\")+\"/\")+r)),o.push(t))}function n6(t,e,r,o,a){var n=\"\";r!=null&&(n=(\"\"+r).replace(qye,\"$&/\")+\"/\"),e=Gye(e,n,o,a),r6(t,Qyt,e),jye(e)}var Yye={current:null};function Xf(){var t=Yye.current;if(t===null)throw Error(eB(321));return t}var Fyt={ReactCurrentDispatcher:Yye,ReactCurrentBatchConfig:{suspense:null},ReactCurrentOwner:a6,IsSomeRendererActing:{current:!1},assign:i6};Ln.Children={map:function(t,e,r){if(t==null)return t;var o=[];return n6(t,o,null,e,r),o},forEach:function(t,e,r){if(t==null)return t;e=Gye(null,null,e,r),r6(t,kyt,e),jye(e)},count:function(t){return r6(t,function(){return null},null)},toArray:function(t){var e=[];return n6(t,e,null,function(r){return r}),e},only:function(t){if(!l6(t))throw Error(eB(143));return t}};Ln.Component=RC;Ln.Fragment=Eyt;Ln.Profiler=wyt;Ln.PureComponent=s6;Ln.StrictMode=Cyt;Ln.Suspense=Dyt;Ln.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=Fyt;Ln.cloneElement=function(t,e,r){if(t==null)throw Error(eB(267,t));var o=i6({},t.props),a=t.key,n=t.ref,u=t._owner;if(e!=null){if(e.ref!==void 0&&(n=e.ref,u=a6.current),e.key!==void 0&&(a=\"\"+e.key),t.type&&t.type.defaultProps)var A=t.type.defaultProps;for(p in e)Uye.call(e,p)&&!_ye.hasOwnProperty(p)&&(o[p]=e[p]===void 0&&A!==void 0?A[p]:e[p])}var p=arguments.length-2;if(p===1)o.children=r;else if(1<p){A=Array(p);for(var h=0;h<p;h++)A[h]=arguments[h+2];o.children=A}return{$$typeof:$2,type:t.type,key:a,ref:n,props:o,_owner:u}};Ln.createContext=function(t,e){return e===void 0&&(e=null),t={$$typeof:Byt,_calculateChangedBits:e,_currentValue:t,_currentValue2:t,_threadCount:0,Provider:null,Consumer:null},t.Provider={$$typeof:Iyt,_context:t},t.Consumer=t};Ln.createElement=Hye;Ln.createFactory=function(t){var e=Hye.bind(null,t);return e.type=t,e};Ln.createRef=function(){return{current:null}};Ln.forwardRef=function(t){return{$$typeof:vyt,render:t}};Ln.isValidElement=l6;Ln.lazy=function(t){return{$$typeof:Syt,_ctor:t,_status:-1,_result:null}};Ln.memo=function(t,e){return{$$typeof:Pyt,type:t,compare:e===void 0?null:e}};Ln.useCallback=function(t,e){return Xf().useCallback(t,e)};Ln.useContext=function(t,e){return Xf().useContext(t,e)};Ln.useDebugValue=function(){};Ln.useEffect=function(t,e){return Xf().useEffect(t,e)};Ln.useImperativeHandle=function(t,e,r){return Xf().useImperativeHandle(t,e,r)};Ln.useLayoutEffect=function(t,e){return Xf().useLayoutEffect(t,e)};Ln.useMemo=function(t,e){return Xf().useMemo(t,e)};Ln.useReducer=function(t,e,r){return Xf().useReducer(t,e,r)};Ln.useRef=function(t){return Xf().useRef(t)};Ln.useState=function(t){return Xf().useState(t)};Ln.version=\"16.13.1\"});var on=_((rKt,Kye)=>{\"use strict\";Kye.exports=Wye()});var u6=_((nKt,c6)=>{\"use strict\";var An=c6.exports;c6.exports.default=An;var Nn=\"\\x1B[\",tB=\"\\x1B]\",TC=\"\\x07\",xk=\";\",zye=process.env.TERM_PROGRAM===\"Apple_Terminal\";An.cursorTo=(t,e)=>{if(typeof t!=\"number\")throw new TypeError(\"The `x` argument is required\");return typeof e!=\"number\"?Nn+(t+1)+\"G\":Nn+(e+1)+\";\"+(t+1)+\"H\"};An.cursorMove=(t,e)=>{if(typeof t!=\"number\")throw new TypeError(\"The `x` argument is required\");let r=\"\";return t<0?r+=Nn+-t+\"D\":t>0&&(r+=Nn+t+\"C\"),e<0?r+=Nn+-e+\"A\":e>0&&(r+=Nn+e+\"B\"),r};An.cursorUp=(t=1)=>Nn+t+\"A\";An.cursorDown=(t=1)=>Nn+t+\"B\";An.cursorForward=(t=1)=>Nn+t+\"C\";An.cursorBackward=(t=1)=>Nn+t+\"D\";An.cursorLeft=Nn+\"G\";An.cursorSavePosition=zye?\"\\x1B7\":Nn+\"s\";An.cursorRestorePosition=zye?\"\\x1B8\":Nn+\"u\";An.cursorGetPosition=Nn+\"6n\";An.cursorNextLine=Nn+\"E\";An.cursorPrevLine=Nn+\"F\";An.cursorHide=Nn+\"?25l\";An.cursorShow=Nn+\"?25h\";An.eraseLines=t=>{let e=\"\";for(let r=0;r<t;r++)e+=An.eraseLine+(r<t-1?An.cursorUp():\"\");return t&&(e+=An.cursorLeft),e};An.eraseEndLine=Nn+\"K\";An.eraseStartLine=Nn+\"1K\";An.eraseLine=Nn+\"2K\";An.eraseDown=Nn+\"J\";An.eraseUp=Nn+\"1J\";An.eraseScreen=Nn+\"2J\";An.scrollUp=Nn+\"S\";An.scrollDown=Nn+\"T\";An.clearScreen=\"\\x1Bc\";An.clearTerminal=process.platform===\"win32\"?`${An.eraseScreen}${Nn}0f`:`${An.eraseScreen}${Nn}3J${Nn}H`;An.beep=TC;An.link=(t,e)=>[tB,\"8\",xk,xk,e,TC,t,tB,\"8\",xk,xk,TC].join(\"\");An.image=(t,e={})=>{let r=`${tB}1337;File=inline=1`;return e.width&&(r+=`;width=${e.width}`),e.height&&(r+=`;height=${e.height}`),e.preserveAspectRatio===!1&&(r+=\";preserveAspectRatio=0\"),r+\":\"+t.toString(\"base64\")+TC};An.iTerm={setCwd:(t=process.cwd())=>`${tB}50;CurrentDir=${t}${TC}`,annotation:(t,e={})=>{let r=`${tB}1337;`,o=typeof e.x<\"u\",a=typeof e.y<\"u\";if((o||a)&&!(o&&a&&typeof e.length<\"u\"))throw new Error(\"`x`, `y` and `length` must be defined when `x` or `y` is defined\");return t=t.replace(/\\|/g,\"\"),r+=e.isHidden?\"AddHiddenAnnotation=\":\"AddAnnotation=\",e.length>0?r+=(o?[t,e.length,e.x,e.y]:[e.length,t]).join(\"|\"):r+=t,r+TC}}});var Jye=_((iKt,A6)=>{\"use strict\";var Vye=(t,e)=>{for(let r of Reflect.ownKeys(e))Object.defineProperty(t,r,Object.getOwnPropertyDescriptor(e,r));return t};A6.exports=Vye;A6.exports.default=Vye});var Zye=_((sKt,Qk)=>{\"use strict\";var Ryt=Jye(),kk=new WeakMap,Xye=(t,e={})=>{if(typeof t!=\"function\")throw new TypeError(\"Expected a function\");let r,o=0,a=t.displayName||t.name||\"<anonymous>\",n=function(...u){if(kk.set(n,++o),o===1)r=t.apply(this,u),t=null;else if(e.throw===!0)throw new Error(`Function \\`${a}\\` can only be called once`);return r};return Ryt(n,t),kk.set(n,o),n};Qk.exports=Xye;Qk.exports.default=Xye;Qk.exports.callCount=t=>{if(!kk.has(t))throw new Error(`The given function \\`${t.name}\\` is not wrapped by the \\`onetime\\` package`);return kk.get(t)}});var $ye=_((oKt,Fk)=>{Fk.exports=[\"SIGABRT\",\"SIGALRM\",\"SIGHUP\",\"SIGINT\",\"SIGTERM\"];process.platform!==\"win32\"&&Fk.exports.push(\"SIGVTALRM\",\"SIGXCPU\",\"SIGXFSZ\",\"SIGUSR2\",\"SIGTRAP\",\"SIGSYS\",\"SIGQUIT\",\"SIGIOT\");process.platform===\"linux\"&&Fk.exports.push(\"SIGIO\",\"SIGPOLL\",\"SIGPWR\",\"SIGSTKFLT\",\"SIGUNUSED\")});var h6=_((aKt,OC)=>{var Ei=global.process,sm=function(t){return t&&typeof t==\"object\"&&typeof t.removeListener==\"function\"&&typeof t.emit==\"function\"&&typeof t.reallyExit==\"function\"&&typeof t.listeners==\"function\"&&typeof t.kill==\"function\"&&typeof t.pid==\"number\"&&typeof t.on==\"function\"};sm(Ei)?(eEe=ve(\"assert\"),LC=$ye(),tEe=/^win/i.test(Ei.platform),rB=ve(\"events\"),typeof rB!=\"function\"&&(rB=rB.EventEmitter),Ei.__signal_exit_emitter__?Ts=Ei.__signal_exit_emitter__:(Ts=Ei.__signal_exit_emitter__=new rB,Ts.count=0,Ts.emitted={}),Ts.infinite||(Ts.setMaxListeners(1/0),Ts.infinite=!0),OC.exports=function(t,e){if(!sm(global.process))return function(){};eEe.equal(typeof t,\"function\",\"a callback must be provided for exit handler\"),NC===!1&&f6();var r=\"exit\";e&&e.alwaysLast&&(r=\"afterexit\");var o=function(){Ts.removeListener(r,t),Ts.listeners(\"exit\").length===0&&Ts.listeners(\"afterexit\").length===0&&Rk()};return Ts.on(r,t),o},Rk=function(){!NC||!sm(global.process)||(NC=!1,LC.forEach(function(e){try{Ei.removeListener(e,Tk[e])}catch{}}),Ei.emit=Lk,Ei.reallyExit=p6,Ts.count-=1)},OC.exports.unload=Rk,om=function(e,r,o){Ts.emitted[e]||(Ts.emitted[e]=!0,Ts.emit(e,r,o))},Tk={},LC.forEach(function(t){Tk[t]=function(){if(!!sm(global.process)){var r=Ei.listeners(t);r.length===Ts.count&&(Rk(),om(\"exit\",null,t),om(\"afterexit\",null,t),tEe&&t===\"SIGHUP\"&&(t=\"SIGINT\"),Ei.kill(Ei.pid,t))}}}),OC.exports.signals=function(){return LC},NC=!1,f6=function(){NC||!sm(global.process)||(NC=!0,Ts.count+=1,LC=LC.filter(function(e){try{return Ei.on(e,Tk[e]),!0}catch{return!1}}),Ei.emit=nEe,Ei.reallyExit=rEe)},OC.exports.load=f6,p6=Ei.reallyExit,rEe=function(e){!sm(global.process)||(Ei.exitCode=e||0,om(\"exit\",Ei.exitCode,null),om(\"afterexit\",Ei.exitCode,null),p6.call(Ei,Ei.exitCode))},Lk=Ei.emit,nEe=function(e,r){if(e===\"exit\"&&sm(global.process)){r!==void 0&&(Ei.exitCode=r);var o=Lk.apply(this,arguments);return om(\"exit\",Ei.exitCode,null),om(\"afterexit\",Ei.exitCode,null),o}else return Lk.apply(this,arguments)}):OC.exports=function(){return function(){}};var eEe,LC,tEe,rB,Ts,Rk,om,Tk,NC,f6,p6,rEe,Lk,nEe});var sEe=_((lKt,iEe)=>{\"use strict\";var Tyt=Zye(),Lyt=h6();iEe.exports=Tyt(()=>{Lyt(()=>{process.stderr.write(\"\\x1B[?25h\")},{alwaysLast:!0})})});var g6=_(MC=>{\"use strict\";var Nyt=sEe(),Nk=!1;MC.show=(t=process.stderr)=>{!t.isTTY||(Nk=!1,t.write(\"\\x1B[?25h\"))};MC.hide=(t=process.stderr)=>{!t.isTTY||(Nyt(),Nk=!0,t.write(\"\\x1B[?25l\"))};MC.toggle=(t,e)=>{t!==void 0&&(Nk=t),Nk?MC.show(e):MC.hide(e)}});var cEe=_(nB=>{\"use strict\";var lEe=nB&&nB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(nB,\"__esModule\",{value:!0});var oEe=lEe(u6()),aEe=lEe(g6()),Oyt=(t,{showCursor:e=!1}={})=>{let r=0,o=\"\",a=!1,n=u=>{!e&&!a&&(aEe.default.hide(),a=!0);let A=u+`\n`;A!==o&&(o=A,t.write(oEe.default.eraseLines(r)+A),r=A.split(`\n`).length)};return n.clear=()=>{t.write(oEe.default.eraseLines(r)),o=\"\",r=0},n.done=()=>{o=\"\",r=0,e||(aEe.default.show(),a=!1)},n};nB.default={create:Oyt}});var uEe=_((AKt,Myt)=>{Myt.exports=[{name:\"AppVeyor\",constant:\"APPVEYOR\",env:\"APPVEYOR\",pr:\"APPVEYOR_PULL_REQUEST_NUMBER\"},{name:\"Azure Pipelines\",constant:\"AZURE_PIPELINES\",env:\"SYSTEM_TEAMFOUNDATIONCOLLECTIONURI\",pr:\"SYSTEM_PULLREQUEST_PULLREQUESTID\"},{name:\"Bamboo\",constant:\"BAMBOO\",env:\"bamboo_planKey\"},{name:\"Bitbucket Pipelines\",constant:\"BITBUCKET\",env:\"BITBUCKET_COMMIT\",pr:\"BITBUCKET_PR_ID\"},{name:\"Bitrise\",constant:\"BITRISE\",env:\"BITRISE_IO\",pr:\"BITRISE_PULL_REQUEST\"},{name:\"Buddy\",constant:\"BUDDY\",env:\"BUDDY_WORKSPACE_ID\",pr:\"BUDDY_EXECUTION_PULL_REQUEST_ID\"},{name:\"Buildkite\",constant:\"BUILDKITE\",env:\"BUILDKITE\",pr:{env:\"BUILDKITE_PULL_REQUEST\",ne:\"false\"}},{name:\"CircleCI\",constant:\"CIRCLE\",env:\"CIRCLECI\",pr:\"CIRCLE_PULL_REQUEST\"},{name:\"Cirrus CI\",constant:\"CIRRUS\",env:\"CIRRUS_CI\",pr:\"CIRRUS_PR\"},{name:\"AWS CodeBuild\",constant:\"CODEBUILD\",env:\"CODEBUILD_BUILD_ARN\"},{name:\"Codeship\",constant:\"CODESHIP\",env:{CI_NAME:\"codeship\"}},{name:\"Drone\",constant:\"DRONE\",env:\"DRONE\",pr:{DRONE_BUILD_EVENT:\"pull_request\"}},{name:\"dsari\",constant:\"DSARI\",env:\"DSARI\"},{name:\"GitLab CI\",constant:\"GITLAB\",env:\"GITLAB_CI\"},{name:\"GoCD\",constant:\"GOCD\",env:\"GO_PIPELINE_LABEL\"},{name:\"Hudson\",constant:\"HUDSON\",env:\"HUDSON_URL\"},{name:\"Jenkins\",constant:\"JENKINS\",env:[\"JENKINS_URL\",\"BUILD_ID\"],pr:{any:[\"ghprbPullId\",\"CHANGE_ID\"]}},{name:\"Magnum CI\",constant:\"MAGNUM\",env:\"MAGNUM\"},{name:\"Netlify CI\",constant:\"NETLIFY\",env:\"NETLIFY_BUILD_BASE\",pr:{env:\"PULL_REQUEST\",ne:\"false\"}},{name:\"Sail CI\",constant:\"SAIL\",env:\"SAILCI\",pr:\"SAIL_PULL_REQUEST_NUMBER\"},{name:\"Semaphore\",constant:\"SEMAPHORE\",env:\"SEMAPHORE\",pr:\"PULL_REQUEST_NUMBER\"},{name:\"Shippable\",constant:\"SHIPPABLE\",env:\"SHIPPABLE\",pr:{IS_PULL_REQUEST:\"true\"}},{name:\"Solano CI\",constant:\"SOLANO\",env:\"TDDIUM\",pr:\"TDDIUM_PR_ID\"},{name:\"Strider CD\",constant:\"STRIDER\",env:\"STRIDER\"},{name:\"TaskCluster\",constant:\"TASKCLUSTER\",env:[\"TASK_ID\",\"RUN_ID\"]},{name:\"TeamCity\",constant:\"TEAMCITY\",env:\"TEAMCITY_VERSION\"},{name:\"Travis CI\",constant:\"TRAVIS\",env:\"TRAVIS\",pr:{env:\"TRAVIS_PULL_REQUEST\",ne:\"false\"}}]});var pEe=_(dl=>{\"use strict\";var fEe=uEe(),hA=process.env;Object.defineProperty(dl,\"_vendors\",{value:fEe.map(function(t){return t.constant})});dl.name=null;dl.isPR=null;fEe.forEach(function(t){var e=Array.isArray(t.env)?t.env:[t.env],r=e.every(function(o){return AEe(o)});if(dl[t.constant]=r,r)switch(dl.name=t.name,typeof t.pr){case\"string\":dl.isPR=!!hA[t.pr];break;case\"object\":\"env\"in t.pr?dl.isPR=t.pr.env in hA&&hA[t.pr.env]!==t.pr.ne:\"any\"in t.pr?dl.isPR=t.pr.any.some(function(o){return!!hA[o]}):dl.isPR=AEe(t.pr);break;default:dl.isPR=null}});dl.isCI=!!(hA.CI||hA.CONTINUOUS_INTEGRATION||hA.BUILD_NUMBER||hA.RUN_ID||dl.name);function AEe(t){return typeof t==\"string\"?!!hA[t]:Object.keys(t).every(function(e){return hA[e]===t[e]})}});var gEe=_((pKt,hEe)=>{\"use strict\";hEe.exports=pEe().isCI});var mEe=_((hKt,dEe)=>{\"use strict\";var Uyt=t=>{let e=new Set;do for(let r of Reflect.ownKeys(t))e.add([t,r]);while((t=Reflect.getPrototypeOf(t))&&t!==Object.prototype);return e};dEe.exports=(t,{include:e,exclude:r}={})=>{let o=a=>{let n=u=>typeof u==\"string\"?a===u:u.test(a);return e?e.some(n):r?!r.some(n):!0};for(let[a,n]of Uyt(t.constructor.prototype)){if(n===\"constructor\"||!o(n))continue;let u=Reflect.getOwnPropertyDescriptor(a,n);u&&typeof u.value==\"function\"&&(t[n]=t[n].bind(t))}return t}});var vEe=_(kn=>{\"use strict\";Object.defineProperty(kn,\"__esModule\",{value:!0});var _C,oB,Hk,qk,I6;typeof window>\"u\"||typeof MessageChannel!=\"function\"?(UC=null,d6=null,m6=function(){if(UC!==null)try{var t=kn.unstable_now();UC(!0,t),UC=null}catch(e){throw setTimeout(m6,0),e}},yEe=Date.now(),kn.unstable_now=function(){return Date.now()-yEe},_C=function(t){UC!==null?setTimeout(_C,0,t):(UC=t,setTimeout(m6,0))},oB=function(t,e){d6=setTimeout(t,e)},Hk=function(){clearTimeout(d6)},qk=function(){return!1},I6=kn.unstable_forceFrameRate=function(){}):(Ok=window.performance,y6=window.Date,EEe=window.setTimeout,CEe=window.clearTimeout,typeof console<\"u\"&&(wEe=window.cancelAnimationFrame,typeof window.requestAnimationFrame!=\"function\"&&console.error(\"This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills\"),typeof wEe!=\"function\"&&console.error(\"This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills\")),typeof Ok==\"object\"&&typeof Ok.now==\"function\"?kn.unstable_now=function(){return Ok.now()}:(IEe=y6.now(),kn.unstable_now=function(){return y6.now()-IEe}),iB=!1,sB=null,Mk=-1,E6=5,C6=0,qk=function(){return kn.unstable_now()>=C6},I6=function(){},kn.unstable_forceFrameRate=function(t){0>t||125<t?console.error(\"forceFrameRate takes a positive int between 0 and 125, forcing framerates higher than 125 fps is not unsupported\"):E6=0<t?Math.floor(1e3/t):5},w6=new MessageChannel,Uk=w6.port2,w6.port1.onmessage=function(){if(sB!==null){var t=kn.unstable_now();C6=t+E6;try{sB(!0,t)?Uk.postMessage(null):(iB=!1,sB=null)}catch(e){throw Uk.postMessage(null),e}}else iB=!1},_C=function(t){sB=t,iB||(iB=!0,Uk.postMessage(null))},oB=function(t,e){Mk=EEe(function(){t(kn.unstable_now())},e)},Hk=function(){CEe(Mk),Mk=-1});var UC,d6,m6,yEe,Ok,y6,EEe,CEe,wEe,IEe,iB,sB,Mk,E6,C6,w6,Uk;function B6(t,e){var r=t.length;t.push(e);e:for(;;){var o=Math.floor((r-1)/2),a=t[o];if(a!==void 0&&0<_k(a,e))t[o]=e,t[r]=a,r=o;else break e}}function ic(t){return t=t[0],t===void 0?null:t}function Gk(t){var e=t[0];if(e!==void 0){var r=t.pop();if(r!==e){t[0]=r;e:for(var o=0,a=t.length;o<a;){var n=2*(o+1)-1,u=t[n],A=n+1,p=t[A];if(u!==void 0&&0>_k(u,r))p!==void 0&&0>_k(p,u)?(t[o]=p,t[A]=r,o=A):(t[o]=u,t[n]=r,o=n);else if(p!==void 0&&0>_k(p,r))t[o]=p,t[A]=r,o=A;else break e}}return e}return null}function _k(t,e){var r=t.sortIndex-e.sortIndex;return r!==0?r:t.id-e.id}var tu=[],E0=[],_yt=1,na=null,No=3,jk=!1,am=!1,aB=!1;function Yk(t){for(var e=ic(E0);e!==null;){if(e.callback===null)Gk(E0);else if(e.startTime<=t)Gk(E0),e.sortIndex=e.expirationTime,B6(tu,e);else break;e=ic(E0)}}function v6(t){if(aB=!1,Yk(t),!am)if(ic(tu)!==null)am=!0,_C(D6);else{var e=ic(E0);e!==null&&oB(v6,e.startTime-t)}}function D6(t,e){am=!1,aB&&(aB=!1,Hk()),jk=!0;var r=No;try{for(Yk(e),na=ic(tu);na!==null&&(!(na.expirationTime>e)||t&&!qk());){var o=na.callback;if(o!==null){na.callback=null,No=na.priorityLevel;var a=o(na.expirationTime<=e);e=kn.unstable_now(),typeof a==\"function\"?na.callback=a:na===ic(tu)&&Gk(tu),Yk(e)}else Gk(tu);na=ic(tu)}if(na!==null)var n=!0;else{var u=ic(E0);u!==null&&oB(v6,u.startTime-e),n=!1}return n}finally{na=null,No=r,jk=!1}}function BEe(t){switch(t){case 1:return-1;case 2:return 250;case 5:return 1073741823;case 4:return 1e4;default:return 5e3}}var Hyt=I6;kn.unstable_ImmediatePriority=1;kn.unstable_UserBlockingPriority=2;kn.unstable_NormalPriority=3;kn.unstable_IdlePriority=5;kn.unstable_LowPriority=4;kn.unstable_runWithPriority=function(t,e){switch(t){case 1:case 2:case 3:case 4:case 5:break;default:t=3}var r=No;No=t;try{return e()}finally{No=r}};kn.unstable_next=function(t){switch(No){case 1:case 2:case 3:var e=3;break;default:e=No}var r=No;No=e;try{return t()}finally{No=r}};kn.unstable_scheduleCallback=function(t,e,r){var o=kn.unstable_now();if(typeof r==\"object\"&&r!==null){var a=r.delay;a=typeof a==\"number\"&&0<a?o+a:o,r=typeof r.timeout==\"number\"?r.timeout:BEe(t)}else r=BEe(t),a=o;return r=a+r,t={id:_yt++,callback:e,priorityLevel:t,startTime:a,expirationTime:r,sortIndex:-1},a>o?(t.sortIndex=a,B6(E0,t),ic(tu)===null&&t===ic(E0)&&(aB?Hk():aB=!0,oB(v6,a-o))):(t.sortIndex=r,B6(tu,t),am||jk||(am=!0,_C(D6))),t};kn.unstable_cancelCallback=function(t){t.callback=null};kn.unstable_wrapCallback=function(t){var e=No;return function(){var r=No;No=e;try{return t.apply(this,arguments)}finally{No=r}}};kn.unstable_getCurrentPriorityLevel=function(){return No};kn.unstable_shouldYield=function(){var t=kn.unstable_now();Yk(t);var e=ic(tu);return e!==na&&na!==null&&e!==null&&e.callback!==null&&e.startTime<=t&&e.expirationTime<na.expirationTime||qk()};kn.unstable_requestPaint=Hyt;kn.unstable_continueExecution=function(){am||jk||(am=!0,_C(D6))};kn.unstable_pauseExecution=function(){};kn.unstable_getFirstCallbackNode=function(){return ic(tu)};kn.unstable_Profiling=null});var P6=_((dKt,DEe)=>{\"use strict\";DEe.exports=vEe()});var PEe=_((mKt,lB)=>{lB.exports=function t(e){\"use strict\";var r=$H(),o=on(),a=P6();function n(P){for(var D=\"https://reactjs.org/docs/error-decoder.html?invariant=\"+P,T=1;T<arguments.length;T++)D+=\"&args[]=\"+encodeURIComponent(arguments[T]);return\"Minified React error #\"+P+\"; visit \"+D+\" for the full message or use the non-minified dev environment for full errors and additional helpful warnings.\"}var u=o.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;u.hasOwnProperty(\"ReactCurrentDispatcher\")||(u.ReactCurrentDispatcher={current:null}),u.hasOwnProperty(\"ReactCurrentBatchConfig\")||(u.ReactCurrentBatchConfig={suspense:null});var A=typeof Symbol==\"function\"&&Symbol.for,p=A?Symbol.for(\"react.element\"):60103,h=A?Symbol.for(\"react.portal\"):60106,E=A?Symbol.for(\"react.fragment\"):60107,I=A?Symbol.for(\"react.strict_mode\"):60108,v=A?Symbol.for(\"react.profiler\"):60114,x=A?Symbol.for(\"react.provider\"):60109,C=A?Symbol.for(\"react.context\"):60110,R=A?Symbol.for(\"react.concurrent_mode\"):60111,N=A?Symbol.for(\"react.forward_ref\"):60112,U=A?Symbol.for(\"react.suspense\"):60113,V=A?Symbol.for(\"react.suspense_list\"):60120,te=A?Symbol.for(\"react.memo\"):60115,ae=A?Symbol.for(\"react.lazy\"):60116;A&&Symbol.for(\"react.fundamental\"),A&&Symbol.for(\"react.responder\"),A&&Symbol.for(\"react.scope\");var fe=typeof Symbol==\"function\"&&Symbol.iterator;function ue(P){return P===null||typeof P!=\"object\"?null:(P=fe&&P[fe]||P[\"@@iterator\"],typeof P==\"function\"?P:null)}function me(P){if(P._status===-1){P._status=0;var D=P._ctor;D=D(),P._result=D,D.then(function(T){P._status===0&&(T=T.default,P._status=1,P._result=T)},function(T){P._status===0&&(P._status=2,P._result=T)})}}function he(P){if(P==null)return null;if(typeof P==\"function\")return P.displayName||P.name||null;if(typeof P==\"string\")return P;switch(P){case E:return\"Fragment\";case h:return\"Portal\";case v:return\"Profiler\";case I:return\"StrictMode\";case U:return\"Suspense\";case V:return\"SuspenseList\"}if(typeof P==\"object\")switch(P.$$typeof){case C:return\"Context.Consumer\";case x:return\"Context.Provider\";case N:var D=P.render;return D=D.displayName||D.name||\"\",P.displayName||(D!==\"\"?\"ForwardRef(\"+D+\")\":\"ForwardRef\");case te:return he(P.type);case ae:if(P=P._status===1?P._result:null)return he(P)}return null}function Be(P){var D=P,T=P;if(P.alternate)for(;D.return;)D=D.return;else{P=D;do D=P,(D.effectTag&1026)!==0&&(T=D.return),P=D.return;while(P)}return D.tag===3?T:null}function we(P){if(Be(P)!==P)throw Error(n(188))}function g(P){var D=P.alternate;if(!D){if(D=Be(P),D===null)throw Error(n(188));return D!==P?null:P}for(var T=P,q=D;;){var Y=T.return;if(Y===null)break;var Ae=Y.alternate;if(Ae===null){if(q=Y.return,q!==null){T=q;continue}break}if(Y.child===Ae.child){for(Ae=Y.child;Ae;){if(Ae===T)return we(Y),P;if(Ae===q)return we(Y),D;Ae=Ae.sibling}throw Error(n(188))}if(T.return!==q.return)T=Y,q=Ae;else{for(var De=!1,vt=Y.child;vt;){if(vt===T){De=!0,T=Y,q=Ae;break}if(vt===q){De=!0,q=Y,T=Ae;break}vt=vt.sibling}if(!De){for(vt=Ae.child;vt;){if(vt===T){De=!0,T=Ae,q=Y;break}if(vt===q){De=!0,q=Ae,T=Y;break}vt=vt.sibling}if(!De)throw Error(n(189))}}if(T.alternate!==q)throw Error(n(190))}if(T.tag!==3)throw Error(n(188));return T.stateNode.current===T?P:D}function Ee(P){if(P=g(P),!P)return null;for(var D=P;;){if(D.tag===5||D.tag===6)return D;if(D.child)D.child.return=D,D=D.child;else{if(D===P)break;for(;!D.sibling;){if(!D.return||D.return===P)return null;D=D.return}D.sibling.return=D.return,D=D.sibling}}return null}function Pe(P){if(P=g(P),!P)return null;for(var D=P;;){if(D.tag===5||D.tag===6)return D;if(D.child&&D.tag!==4)D.child.return=D,D=D.child;else{if(D===P)break;for(;!D.sibling;){if(!D.return||D.return===P)return null;D=D.return}D.sibling.return=D.return,D=D.sibling}}return null}var ce=e.getPublicInstance,ne=e.getRootHostContext,ee=e.getChildHostContext,Ie=e.prepareForCommit,Fe=e.resetAfterCommit,At=e.createInstance,H=e.appendInitialChild,at=e.finalizeInitialChildren,Re=e.prepareUpdate,ke=e.shouldSetTextContent,xe=e.shouldDeprioritizeSubtree,He=e.createTextInstance,Te=e.setTimeout,Ve=e.clearTimeout,qe=e.noTimeout,b=e.isPrimaryRenderer,w=e.supportsMutation,S=e.supportsPersistence,y=e.supportsHydration,F=e.appendChild,J=e.appendChildToContainer,X=e.commitTextUpdate,Z=e.commitMount,ie=e.commitUpdate,be=e.insertBefore,Le=e.insertInContainerBefore,ot=e.removeChild,dt=e.removeChildFromContainer,Gt=e.resetTextContent,$t=e.hideInstance,bt=e.hideTextInstance,an=e.unhideInstance,Qr=e.unhideTextInstance,mr=e.cloneInstance,br=e.createContainerChildSet,Wr=e.appendChildToContainerChildSet,Kn=e.finalizeContainerChildren,Ls=e.replaceContainerChildren,Ti=e.cloneHiddenInstance,ps=e.cloneHiddenTextInstance,io=e.canHydrateInstance,Si=e.canHydrateTextInstance,Ns=e.isSuspenseInstancePending,so=e.isSuspenseInstanceFallback,uc=e.getNextHydratableSibling,uu=e.getFirstHydratableChild,cp=e.hydrateInstance,up=e.hydrateTextInstance,Os=e.getNextHydratableInstanceAfterSuspenseInstance,Dn=e.commitHydratedContainer,oo=e.commitHydratedSuspenseInstance,Ms=/^(.*)[\\\\\\/]/;function yl(P){var D=\"\";do{e:switch(P.tag){case 3:case 4:case 6:case 7:case 10:case 9:var T=\"\";break e;default:var q=P._debugOwner,Y=P._debugSource,Ae=he(P.type);T=null,q&&(T=he(q.type)),q=Ae,Ae=\"\",Y?Ae=\" (at \"+Y.fileName.replace(Ms,\"\")+\":\"+Y.lineNumber+\")\":T&&(Ae=\" (created by \"+T+\")\"),T=`\n    in `+(q||\"Unknown\")+Ae}D+=T,P=P.return}while(P);return D}var El=[],ao=-1;function zn(P){0>ao||(P.current=El[ao],El[ao]=null,ao--)}function On(P,D){ao++,El[ao]=P.current,P.current=D}var Li={},Mn={current:Li},_i={current:!1},rr=Li;function Oe(P,D){var T=P.type.contextTypes;if(!T)return Li;var q=P.stateNode;if(q&&q.__reactInternalMemoizedUnmaskedChildContext===D)return q.__reactInternalMemoizedMaskedChildContext;var Y={},Ae;for(Ae in T)Y[Ae]=D[Ae];return q&&(P=P.stateNode,P.__reactInternalMemoizedUnmaskedChildContext=D,P.__reactInternalMemoizedMaskedChildContext=Y),Y}function ii(P){return P=P.childContextTypes,P!=null}function Ua(P){zn(_i,P),zn(Mn,P)}function hr(P){zn(_i,P),zn(Mn,P)}function Ac(P,D,T){if(Mn.current!==Li)throw Error(n(168));On(Mn,D,P),On(_i,T,P)}function Au(P,D,T){var q=P.stateNode;if(P=D.childContextTypes,typeof q.getChildContext!=\"function\")return T;q=q.getChildContext();for(var Y in q)if(!(Y in P))throw Error(n(108,he(D)||\"Unknown\",Y));return r({},T,{},q)}function fc(P){var D=P.stateNode;return D=D&&D.__reactInternalMemoizedMergedChildContext||Li,rr=Mn.current,On(Mn,D,P),On(_i,_i.current,P),!0}function Cl(P,D,T){var q=P.stateNode;if(!q)throw Error(n(169));T?(D=Au(P,D,rr),q.__reactInternalMemoizedMergedChildContext=D,zn(_i,P),zn(Mn,P),On(Mn,D,P)):zn(_i,P),On(_i,T,P)}var DA=a.unstable_runWithPriority,fu=a.unstable_scheduleCallback,Ce=a.unstable_cancelCallback,Rt=a.unstable_shouldYield,pc=a.unstable_requestPaint,Hi=a.unstable_now,pu=a.unstable_getCurrentPriorityLevel,Yt=a.unstable_ImmediatePriority,wl=a.unstable_UserBlockingPriority,PA=a.unstable_NormalPriority,Ap=a.unstable_LowPriority,hc=a.unstable_IdlePriority,SA={},Qn=pc!==void 0?pc:function(){},hi=null,gc=null,bA=!1,sa=Hi(),Ni=1e4>sa?Hi:function(){return Hi()-sa};function _o(){switch(pu()){case Yt:return 99;case wl:return 98;case PA:return 97;case Ap:return 96;case hc:return 95;default:throw Error(n(332))}}function Ze(P){switch(P){case 99:return Yt;case 98:return wl;case 97:return PA;case 96:return Ap;case 95:return hc;default:throw Error(n(332))}}function lo(P,D){return P=Ze(P),DA(P,D)}function dc(P,D,T){return P=Ze(P),fu(P,D,T)}function hu(P){return hi===null?(hi=[P],gc=fu(Yt,gu)):hi.push(P),SA}function qi(){if(gc!==null){var P=gc;gc=null,Ce(P)}gu()}function gu(){if(!bA&&hi!==null){bA=!0;var P=0;try{var D=hi;lo(99,function(){for(;P<D.length;P++){var T=D[P];do T=T(!0);while(T!==null)}}),hi=null}catch(T){throw hi!==null&&(hi=hi.slice(P+1)),fu(Yt,qi),T}finally{bA=!1}}}var xA=3;function Ha(P,D,T){return T/=10,1073741821-(((1073741821-P+D/10)/T|0)+1)*T}function mc(P,D){return P===D&&(P!==0||1/P===1/D)||P!==P&&D!==D}var hs=typeof Object.is==\"function\"?Object.is:mc,Ht=Object.prototype.hasOwnProperty;function Fn(P,D){if(hs(P,D))return!0;if(typeof P!=\"object\"||P===null||typeof D!=\"object\"||D===null)return!1;var T=Object.keys(P),q=Object.keys(D);if(T.length!==q.length)return!1;for(q=0;q<T.length;q++)if(!Ht.call(D,T[q])||!hs(P[T[q]],D[T[q]]))return!1;return!0}function Ci(P,D){if(P&&P.defaultProps){D=r({},D),P=P.defaultProps;for(var T in P)D[T]===void 0&&(D[T]=P[T])}return D}var oa={current:null},co=null,Us=null,aa=null;function la(){aa=Us=co=null}function Ho(P,D){var T=P.type._context;b?(On(oa,T._currentValue,P),T._currentValue=D):(On(oa,T._currentValue2,P),T._currentValue2=D)}function wi(P){var D=oa.current;zn(oa,P),P=P.type._context,b?P._currentValue=D:P._currentValue2=D}function gs(P,D){for(;P!==null;){var T=P.alternate;if(P.childExpirationTime<D)P.childExpirationTime=D,T!==null&&T.childExpirationTime<D&&(T.childExpirationTime=D);else if(T!==null&&T.childExpirationTime<D)T.childExpirationTime=D;else break;P=P.return}}function ds(P,D){co=P,aa=Us=null,P=P.dependencies,P!==null&&P.firstContext!==null&&(P.expirationTime>=D&&(Go=!0),P.firstContext=null)}function ms(P,D){if(aa!==P&&D!==!1&&D!==0)if((typeof D!=\"number\"||D===1073741823)&&(aa=P,D=1073741823),D={context:P,observedBits:D,next:null},Us===null){if(co===null)throw Error(n(308));Us=D,co.dependencies={expirationTime:0,firstContext:D,responders:null}}else Us=Us.next=D;return b?P._currentValue:P._currentValue2}var _s=!1;function Un(P){return{baseState:P,firstUpdate:null,lastUpdate:null,firstCapturedUpdate:null,lastCapturedUpdate:null,firstEffect:null,lastEffect:null,firstCapturedEffect:null,lastCapturedEffect:null}}function Pn(P){return{baseState:P.baseState,firstUpdate:P.firstUpdate,lastUpdate:P.lastUpdate,firstCapturedUpdate:null,lastCapturedUpdate:null,firstEffect:null,lastEffect:null,firstCapturedEffect:null,lastCapturedEffect:null}}function ys(P,D){return{expirationTime:P,suspenseConfig:D,tag:0,payload:null,callback:null,next:null,nextEffect:null}}function We(P,D){P.lastUpdate===null?P.firstUpdate=P.lastUpdate=D:(P.lastUpdate.next=D,P.lastUpdate=D)}function tt(P,D){var T=P.alternate;if(T===null){var q=P.updateQueue,Y=null;q===null&&(q=P.updateQueue=Un(P.memoizedState))}else q=P.updateQueue,Y=T.updateQueue,q===null?Y===null?(q=P.updateQueue=Un(P.memoizedState),Y=T.updateQueue=Un(T.memoizedState)):q=P.updateQueue=Pn(Y):Y===null&&(Y=T.updateQueue=Pn(q));Y===null||q===Y?We(q,D):q.lastUpdate===null||Y.lastUpdate===null?(We(q,D),We(Y,D)):(We(q,D),Y.lastUpdate=D)}function It(P,D){var T=P.updateQueue;T=T===null?P.updateQueue=Un(P.memoizedState):ir(P,T),T.lastCapturedUpdate===null?T.firstCapturedUpdate=T.lastCapturedUpdate=D:(T.lastCapturedUpdate.next=D,T.lastCapturedUpdate=D)}function ir(P,D){var T=P.alternate;return T!==null&&D===T.updateQueue&&(D=P.updateQueue=Pn(D)),D}function $(P,D,T,q,Y,Ae){switch(T.tag){case 1:return P=T.payload,typeof P==\"function\"?P.call(Ae,q,Y):P;case 3:P.effectTag=P.effectTag&-4097|64;case 0:if(P=T.payload,Y=typeof P==\"function\"?P.call(Ae,q,Y):P,Y==null)break;return r({},q,Y);case 2:_s=!0}return q}function ye(P,D,T,q,Y){_s=!1,D=ir(P,D);for(var Ae=D.baseState,De=null,vt=0,wt=D.firstUpdate,xt=Ae;wt!==null;){var _r=wt.expirationTime;_r<Y?(De===null&&(De=wt,Ae=xt),vt<_r&&(vt=_r)):(Sw(_r,wt.suspenseConfig),xt=$(P,D,wt,xt,T,q),wt.callback!==null&&(P.effectTag|=32,wt.nextEffect=null,D.lastEffect===null?D.firstEffect=D.lastEffect=wt:(D.lastEffect.nextEffect=wt,D.lastEffect=wt))),wt=wt.next}for(_r=null,wt=D.firstCapturedUpdate;wt!==null;){var is=wt.expirationTime;is<Y?(_r===null&&(_r=wt,De===null&&(Ae=xt)),vt<is&&(vt=is)):(xt=$(P,D,wt,xt,T,q),wt.callback!==null&&(P.effectTag|=32,wt.nextEffect=null,D.lastCapturedEffect===null?D.firstCapturedEffect=D.lastCapturedEffect=wt:(D.lastCapturedEffect.nextEffect=wt,D.lastCapturedEffect=wt))),wt=wt.next}De===null&&(D.lastUpdate=null),_r===null?D.lastCapturedUpdate=null:P.effectTag|=32,De===null&&_r===null&&(Ae=xt),D.baseState=Ae,D.firstUpdate=De,D.firstCapturedUpdate=_r,Hm(vt),P.expirationTime=vt,P.memoizedState=xt}function Ne(P,D,T){D.firstCapturedUpdate!==null&&(D.lastUpdate!==null&&(D.lastUpdate.next=D.firstCapturedUpdate,D.lastUpdate=D.lastCapturedUpdate),D.firstCapturedUpdate=D.lastCapturedUpdate=null),pt(D.firstEffect,T),D.firstEffect=D.lastEffect=null,pt(D.firstCapturedEffect,T),D.firstCapturedEffect=D.lastCapturedEffect=null}function pt(P,D){for(;P!==null;){var T=P.callback;if(T!==null){P.callback=null;var q=D;if(typeof T!=\"function\")throw Error(n(191,T));T.call(q)}P=P.nextEffect}}var ht=u.ReactCurrentBatchConfig,Tt=new o.Component().refs;function er(P,D,T,q){D=P.memoizedState,T=T(q,D),T=T==null?D:r({},D,T),P.memoizedState=T,q=P.updateQueue,q!==null&&P.expirationTime===0&&(q.baseState=T)}var $r={isMounted:function(P){return(P=P._reactInternalFiber)?Be(P)===P:!1},enqueueSetState:function(P,D,T){P=P._reactInternalFiber;var q=ga(),Y=ht.suspense;q=qA(q,P,Y),Y=ys(q,Y),Y.payload=D,T!=null&&(Y.callback=T),tt(P,Y),bc(P,q)},enqueueReplaceState:function(P,D,T){P=P._reactInternalFiber;var q=ga(),Y=ht.suspense;q=qA(q,P,Y),Y=ys(q,Y),Y.tag=1,Y.payload=D,T!=null&&(Y.callback=T),tt(P,Y),bc(P,q)},enqueueForceUpdate:function(P,D){P=P._reactInternalFiber;var T=ga(),q=ht.suspense;T=qA(T,P,q),q=ys(T,q),q.tag=2,D!=null&&(q.callback=D),tt(P,q),bc(P,T)}};function Gi(P,D,T,q,Y,Ae,De){return P=P.stateNode,typeof P.shouldComponentUpdate==\"function\"?P.shouldComponentUpdate(q,Ae,De):D.prototype&&D.prototype.isPureReactComponent?!Fn(T,q)||!Fn(Y,Ae):!0}function es(P,D,T){var q=!1,Y=Li,Ae=D.contextType;return typeof Ae==\"object\"&&Ae!==null?Ae=ms(Ae):(Y=ii(D)?rr:Mn.current,q=D.contextTypes,Ae=(q=q!=null)?Oe(P,Y):Li),D=new D(T,Ae),P.memoizedState=D.state!==null&&D.state!==void 0?D.state:null,D.updater=$r,P.stateNode=D,D._reactInternalFiber=P,q&&(P=P.stateNode,P.__reactInternalMemoizedUnmaskedChildContext=Y,P.__reactInternalMemoizedMaskedChildContext=Ae),D}function bi(P,D,T,q){P=D.state,typeof D.componentWillReceiveProps==\"function\"&&D.componentWillReceiveProps(T,q),typeof D.UNSAFE_componentWillReceiveProps==\"function\"&&D.UNSAFE_componentWillReceiveProps(T,q),D.state!==P&&$r.enqueueReplaceState(D,D.state,null)}function qo(P,D,T,q){var Y=P.stateNode;Y.props=T,Y.state=P.memoizedState,Y.refs=Tt;var Ae=D.contextType;typeof Ae==\"object\"&&Ae!==null?Y.context=ms(Ae):(Ae=ii(D)?rr:Mn.current,Y.context=Oe(P,Ae)),Ae=P.updateQueue,Ae!==null&&(ye(P,Ae,T,Y,q),Y.state=P.memoizedState),Ae=D.getDerivedStateFromProps,typeof Ae==\"function\"&&(er(P,D,Ae,T),Y.state=P.memoizedState),typeof D.getDerivedStateFromProps==\"function\"||typeof Y.getSnapshotBeforeUpdate==\"function\"||typeof Y.UNSAFE_componentWillMount!=\"function\"&&typeof Y.componentWillMount!=\"function\"||(D=Y.state,typeof Y.componentWillMount==\"function\"&&Y.componentWillMount(),typeof Y.UNSAFE_componentWillMount==\"function\"&&Y.UNSAFE_componentWillMount(),D!==Y.state&&$r.enqueueReplaceState(Y,Y.state,null),Ae=P.updateQueue,Ae!==null&&(ye(P,Ae,T,Y,q),Y.state=P.memoizedState)),typeof Y.componentDidMount==\"function\"&&(P.effectTag|=4)}var kA=Array.isArray;function QA(P,D,T){if(P=T.ref,P!==null&&typeof P!=\"function\"&&typeof P!=\"object\"){if(T._owner){if(T=T._owner,T){if(T.tag!==1)throw Error(n(309));var q=T.stateNode}if(!q)throw Error(n(147,P));var Y=\"\"+P;return D!==null&&D.ref!==null&&typeof D.ref==\"function\"&&D.ref._stringRef===Y?D.ref:(D=function(Ae){var De=q.refs;De===Tt&&(De=q.refs={}),Ae===null?delete De[Y]:De[Y]=Ae},D._stringRef=Y,D)}if(typeof P!=\"string\")throw Error(n(284));if(!T._owner)throw Error(n(290,P))}return P}function fp(P,D){if(P.type!==\"textarea\")throw Error(n(31,Object.prototype.toString.call(D)===\"[object Object]\"?\"object with keys {\"+Object.keys(D).join(\", \")+\"}\":D,\"\"))}function sg(P){function D(rt,ze){if(P){var ft=rt.lastEffect;ft!==null?(ft.nextEffect=ze,rt.lastEffect=ze):rt.firstEffect=rt.lastEffect=ze,ze.nextEffect=null,ze.effectTag=8}}function T(rt,ze){if(!P)return null;for(;ze!==null;)D(rt,ze),ze=ze.sibling;return null}function q(rt,ze){for(rt=new Map;ze!==null;)ze.key!==null?rt.set(ze.key,ze):rt.set(ze.index,ze),ze=ze.sibling;return rt}function Y(rt,ze,ft){return rt=WA(rt,ze,ft),rt.index=0,rt.sibling=null,rt}function Ae(rt,ze,ft){return rt.index=ft,P?(ft=rt.alternate,ft!==null?(ft=ft.index,ft<ze?(rt.effectTag=2,ze):ft):(rt.effectTag=2,ze)):ze}function De(rt){return P&&rt.alternate===null&&(rt.effectTag=2),rt}function vt(rt,ze,ft,Wt){return ze===null||ze.tag!==6?(ze=Fw(ft,rt.mode,Wt),ze.return=rt,ze):(ze=Y(ze,ft,Wt),ze.return=rt,ze)}function wt(rt,ze,ft,Wt){return ze!==null&&ze.elementType===ft.type?(Wt=Y(ze,ft.props,Wt),Wt.ref=QA(rt,ze,ft),Wt.return=rt,Wt):(Wt=qm(ft.type,ft.key,ft.props,null,rt.mode,Wt),Wt.ref=QA(rt,ze,ft),Wt.return=rt,Wt)}function xt(rt,ze,ft,Wt){return ze===null||ze.tag!==4||ze.stateNode.containerInfo!==ft.containerInfo||ze.stateNode.implementation!==ft.implementation?(ze=Rw(ft,rt.mode,Wt),ze.return=rt,ze):(ze=Y(ze,ft.children||[],Wt),ze.return=rt,ze)}function _r(rt,ze,ft,Wt,vr){return ze===null||ze.tag!==7?(ze=xu(ft,rt.mode,Wt,vr),ze.return=rt,ze):(ze=Y(ze,ft,Wt),ze.return=rt,ze)}function is(rt,ze,ft){if(typeof ze==\"string\"||typeof ze==\"number\")return ze=Fw(\"\"+ze,rt.mode,ft),ze.return=rt,ze;if(typeof ze==\"object\"&&ze!==null){switch(ze.$$typeof){case p:return ft=qm(ze.type,ze.key,ze.props,null,rt.mode,ft),ft.ref=QA(rt,null,ze),ft.return=rt,ft;case h:return ze=Rw(ze,rt.mode,ft),ze.return=rt,ze}if(kA(ze)||ue(ze))return ze=xu(ze,rt.mode,ft,null),ze.return=rt,ze;fp(rt,ze)}return null}function di(rt,ze,ft,Wt){var vr=ze!==null?ze.key:null;if(typeof ft==\"string\"||typeof ft==\"number\")return vr!==null?null:vt(rt,ze,\"\"+ft,Wt);if(typeof ft==\"object\"&&ft!==null){switch(ft.$$typeof){case p:return ft.key===vr?ft.type===E?_r(rt,ze,ft.props.children,Wt,vr):wt(rt,ze,ft,Wt):null;case h:return ft.key===vr?xt(rt,ze,ft,Wt):null}if(kA(ft)||ue(ft))return vr!==null?null:_r(rt,ze,ft,Wt,null);fp(rt,ft)}return null}function po(rt,ze,ft,Wt,vr){if(typeof Wt==\"string\"||typeof Wt==\"number\")return rt=rt.get(ft)||null,vt(ze,rt,\"\"+Wt,vr);if(typeof Wt==\"object\"&&Wt!==null){switch(Wt.$$typeof){case p:return rt=rt.get(Wt.key===null?ft:Wt.key)||null,Wt.type===E?_r(ze,rt,Wt.props.children,vr,Wt.key):wt(ze,rt,Wt,vr);case h:return rt=rt.get(Wt.key===null?ft:Wt.key)||null,xt(ze,rt,Wt,vr)}if(kA(Wt)||ue(Wt))return rt=rt.get(ft)||null,_r(ze,rt,Wt,vr,null);fp(ze,Wt)}return null}function zA(rt,ze,ft,Wt){for(var vr=null,Sn=null,Fr=ze,bn=ze=0,ai=null;Fr!==null&&bn<ft.length;bn++){Fr.index>bn?(ai=Fr,Fr=null):ai=Fr.sibling;var tn=di(rt,Fr,ft[bn],Wt);if(tn===null){Fr===null&&(Fr=ai);break}P&&Fr&&tn.alternate===null&&D(rt,Fr),ze=Ae(tn,ze,bn),Sn===null?vr=tn:Sn.sibling=tn,Sn=tn,Fr=ai}if(bn===ft.length)return T(rt,Fr),vr;if(Fr===null){for(;bn<ft.length;bn++)Fr=is(rt,ft[bn],Wt),Fr!==null&&(ze=Ae(Fr,ze,bn),Sn===null?vr=Fr:Sn.sibling=Fr,Sn=Fr);return vr}for(Fr=q(rt,Fr);bn<ft.length;bn++)ai=po(Fr,rt,bn,ft[bn],Wt),ai!==null&&(P&&ai.alternate!==null&&Fr.delete(ai.key===null?bn:ai.key),ze=Ae(ai,ze,bn),Sn===null?vr=ai:Sn.sibling=ai,Sn=ai);return P&&Fr.forEach(function(ho){return D(rt,ho)}),vr}function Yo(rt,ze,ft,Wt){var vr=ue(ft);if(typeof vr!=\"function\")throw Error(n(150));if(ft=vr.call(ft),ft==null)throw Error(n(151));for(var Sn=vr=null,Fr=ze,bn=ze=0,ai=null,tn=ft.next();Fr!==null&&!tn.done;bn++,tn=ft.next()){Fr.index>bn?(ai=Fr,Fr=null):ai=Fr.sibling;var ho=di(rt,Fr,tn.value,Wt);if(ho===null){Fr===null&&(Fr=ai);break}P&&Fr&&ho.alternate===null&&D(rt,Fr),ze=Ae(ho,ze,bn),Sn===null?vr=ho:Sn.sibling=ho,Sn=ho,Fr=ai}if(tn.done)return T(rt,Fr),vr;if(Fr===null){for(;!tn.done;bn++,tn=ft.next())tn=is(rt,tn.value,Wt),tn!==null&&(ze=Ae(tn,ze,bn),Sn===null?vr=tn:Sn.sibling=tn,Sn=tn);return vr}for(Fr=q(rt,Fr);!tn.done;bn++,tn=ft.next())tn=po(Fr,rt,bn,tn.value,Wt),tn!==null&&(P&&tn.alternate!==null&&Fr.delete(tn.key===null?bn:tn.key),ze=Ae(tn,ze,bn),Sn===null?vr=tn:Sn.sibling=tn,Sn=tn);return P&&Fr.forEach(function(vF){return D(rt,vF)}),vr}return function(rt,ze,ft,Wt){var vr=typeof ft==\"object\"&&ft!==null&&ft.type===E&&ft.key===null;vr&&(ft=ft.props.children);var Sn=typeof ft==\"object\"&&ft!==null;if(Sn)switch(ft.$$typeof){case p:e:{for(Sn=ft.key,vr=ze;vr!==null;){if(vr.key===Sn)if(vr.tag===7?ft.type===E:vr.elementType===ft.type){T(rt,vr.sibling),ze=Y(vr,ft.type===E?ft.props.children:ft.props,Wt),ze.ref=QA(rt,vr,ft),ze.return=rt,rt=ze;break e}else{T(rt,vr);break}else D(rt,vr);vr=vr.sibling}ft.type===E?(ze=xu(ft.props.children,rt.mode,Wt,ft.key),ze.return=rt,rt=ze):(Wt=qm(ft.type,ft.key,ft.props,null,rt.mode,Wt),Wt.ref=QA(rt,ze,ft),Wt.return=rt,rt=Wt)}return De(rt);case h:e:{for(vr=ft.key;ze!==null;){if(ze.key===vr)if(ze.tag===4&&ze.stateNode.containerInfo===ft.containerInfo&&ze.stateNode.implementation===ft.implementation){T(rt,ze.sibling),ze=Y(ze,ft.children||[],Wt),ze.return=rt,rt=ze;break e}else{T(rt,ze);break}else D(rt,ze);ze=ze.sibling}ze=Rw(ft,rt.mode,Wt),ze.return=rt,rt=ze}return De(rt)}if(typeof ft==\"string\"||typeof ft==\"number\")return ft=\"\"+ft,ze!==null&&ze.tag===6?(T(rt,ze.sibling),ze=Y(ze,ft,Wt),ze.return=rt,rt=ze):(T(rt,ze),ze=Fw(ft,rt.mode,Wt),ze.return=rt,rt=ze),De(rt);if(kA(ft))return zA(rt,ze,ft,Wt);if(ue(ft))return Yo(rt,ze,ft,Wt);if(Sn&&fp(rt,ft),typeof ft>\"u\"&&!vr)switch(rt.tag){case 1:case 0:throw rt=rt.type,Error(n(152,rt.displayName||rt.name||\"Component\"))}return T(rt,ze)}}var du=sg(!0),og=sg(!1),mu={},uo={current:mu},FA={current:mu},yc={current:mu};function ca(P){if(P===mu)throw Error(n(174));return P}function ag(P,D){On(yc,D,P),On(FA,P,P),On(uo,mu,P),D=ne(D),zn(uo,P),On(uo,D,P)}function Ec(P){zn(uo,P),zn(FA,P),zn(yc,P)}function Sm(P){var D=ca(yc.current),T=ca(uo.current);D=ee(T,P.type,D),T!==D&&(On(FA,P,P),On(uo,D,P))}function lg(P){FA.current===P&&(zn(uo,P),zn(FA,P))}var ei={current:0};function pp(P){for(var D=P;D!==null;){if(D.tag===13){var T=D.memoizedState;if(T!==null&&(T=T.dehydrated,T===null||Ns(T)||so(T)))return D}else if(D.tag===19&&D.memoizedProps.revealOrder!==void 0){if((D.effectTag&64)!==0)return D}else if(D.child!==null){D.child.return=D,D=D.child;continue}if(D===P)break;for(;D.sibling===null;){if(D.return===null||D.return===P)return null;D=D.return}D.sibling.return=D.return,D=D.sibling}return null}function cg(P,D){return{responder:P,props:D}}var RA=u.ReactCurrentDispatcher,Hs=u.ReactCurrentBatchConfig,yu=0,qa=null,ji=null,ua=null,Eu=null,Es=null,Cc=null,wc=0,j=null,Dt=0,Il=!1,xi=null,Ic=0;function ct(){throw Error(n(321))}function Cu(P,D){if(D===null)return!1;for(var T=0;T<D.length&&T<P.length;T++)if(!hs(P[T],D[T]))return!1;return!0}function ug(P,D,T,q,Y,Ae){if(yu=Ae,qa=D,ua=P!==null?P.memoizedState:null,RA.current=ua===null?Ew:km,D=T(q,Y),Il){do Il=!1,Ic+=1,ua=P!==null?P.memoizedState:null,Cc=Eu,j=Es=ji=null,RA.current=km,D=T(q,Y);while(Il);xi=null,Ic=0}if(RA.current=Iu,P=qa,P.memoizedState=Eu,P.expirationTime=wc,P.updateQueue=j,P.effectTag|=Dt,P=ji!==null&&ji.next!==null,yu=0,Cc=Es=Eu=ua=ji=qa=null,wc=0,j=null,Dt=0,P)throw Error(n(300));return D}function yw(){RA.current=Iu,yu=0,Cc=Es=Eu=ua=ji=qa=null,wc=0,j=null,Dt=0,Il=!1,xi=null,Ic=0}function TA(){var P={memoizedState:null,baseState:null,queue:null,baseUpdate:null,next:null};return Es===null?Eu=Es=P:Es=Es.next=P,Es}function hp(){if(Cc!==null)Es=Cc,Cc=Es.next,ji=ua,ua=ji!==null?ji.next:null;else{if(ua===null)throw Error(n(310));ji=ua;var P={memoizedState:ji.memoizedState,baseState:ji.baseState,queue:ji.queue,baseUpdate:ji.baseUpdate,next:null};Es=Es===null?Eu=P:Es.next=P,ua=ji.next}return Es}function Br(P,D){return typeof D==\"function\"?D(P):D}function Cs(P){var D=hp(),T=D.queue;if(T===null)throw Error(n(311));if(T.lastRenderedReducer=P,0<Ic){var q=T.dispatch;if(xi!==null){var Y=xi.get(T);if(Y!==void 0){xi.delete(T);var Ae=D.memoizedState;do Ae=P(Ae,Y.action),Y=Y.next;while(Y!==null);return hs(Ae,D.memoizedState)||(Go=!0),D.memoizedState=Ae,D.baseUpdate===T.last&&(D.baseState=Ae),T.lastRenderedState=Ae,[Ae,q]}}return[D.memoizedState,q]}q=T.last;var De=D.baseUpdate;if(Ae=D.baseState,De!==null?(q!==null&&(q.next=null),q=De.next):q=q!==null?q.next:null,q!==null){var vt=Y=null,wt=q,xt=!1;do{var _r=wt.expirationTime;_r<yu?(xt||(xt=!0,vt=De,Y=Ae),_r>wc&&(wc=_r,Hm(wc))):(Sw(_r,wt.suspenseConfig),Ae=wt.eagerReducer===P?wt.eagerState:P(Ae,wt.action)),De=wt,wt=wt.next}while(wt!==null&&wt!==q);xt||(vt=De,Y=Ae),hs(Ae,D.memoizedState)||(Go=!0),D.memoizedState=Ae,D.baseUpdate=vt,D.baseState=Y,T.lastRenderedState=Ae}return[D.memoizedState,T.dispatch]}function Ag(P){var D=TA();return typeof P==\"function\"&&(P=P()),D.memoizedState=D.baseState=P,P=D.queue={last:null,dispatch:null,lastRenderedReducer:Br,lastRenderedState:P},P=P.dispatch=dg.bind(null,qa,P),[D.memoizedState,P]}function fg(P){return Cs(Br,P)}function pg(P,D,T,q){return P={tag:P,create:D,destroy:T,deps:q,next:null},j===null?(j={lastEffect:null},j.lastEffect=P.next=P):(D=j.lastEffect,D===null?j.lastEffect=P.next=P:(T=D.next,D.next=P,P.next=T,j.lastEffect=P)),P}function gp(P,D,T,q){var Y=TA();Dt|=P,Y.memoizedState=pg(D,T,void 0,q===void 0?null:q)}function Bc(P,D,T,q){var Y=hp();q=q===void 0?null:q;var Ae=void 0;if(ji!==null){var De=ji.memoizedState;if(Ae=De.destroy,q!==null&&Cu(q,De.deps)){pg(0,T,Ae,q);return}}Dt|=P,Y.memoizedState=pg(D,T,Ae,q)}function Ct(P,D){return gp(516,192,P,D)}function bm(P,D){return Bc(516,192,P,D)}function hg(P,D){if(typeof D==\"function\")return P=P(),D(P),function(){D(null)};if(D!=null)return P=P(),D.current=P,function(){D.current=null}}function gg(){}function wu(P,D){return TA().memoizedState=[P,D===void 0?null:D],P}function xm(P,D){var T=hp();D=D===void 0?null:D;var q=T.memoizedState;return q!==null&&D!==null&&Cu(D,q[1])?q[0]:(T.memoizedState=[P,D],P)}function dg(P,D,T){if(!(25>Ic))throw Error(n(301));var q=P.alternate;if(P===qa||q!==null&&q===qa)if(Il=!0,P={expirationTime:yu,suspenseConfig:null,action:T,eagerReducer:null,eagerState:null,next:null},xi===null&&(xi=new Map),T=xi.get(D),T===void 0)xi.set(D,P);else{for(D=T;D.next!==null;)D=D.next;D.next=P}else{var Y=ga(),Ae=ht.suspense;Y=qA(Y,P,Ae),Ae={expirationTime:Y,suspenseConfig:Ae,action:T,eagerReducer:null,eagerState:null,next:null};var De=D.last;if(De===null)Ae.next=Ae;else{var vt=De.next;vt!==null&&(Ae.next=vt),De.next=Ae}if(D.last=Ae,P.expirationTime===0&&(q===null||q.expirationTime===0)&&(q=D.lastRenderedReducer,q!==null))try{var wt=D.lastRenderedState,xt=q(wt,T);if(Ae.eagerReducer=q,Ae.eagerState=xt,hs(xt,wt))return}catch{}finally{}bc(P,Y)}}var Iu={readContext:ms,useCallback:ct,useContext:ct,useEffect:ct,useImperativeHandle:ct,useLayoutEffect:ct,useMemo:ct,useReducer:ct,useRef:ct,useState:ct,useDebugValue:ct,useResponder:ct,useDeferredValue:ct,useTransition:ct},Ew={readContext:ms,useCallback:wu,useContext:ms,useEffect:Ct,useImperativeHandle:function(P,D,T){return T=T!=null?T.concat([P]):null,gp(4,36,hg.bind(null,D,P),T)},useLayoutEffect:function(P,D){return gp(4,36,P,D)},useMemo:function(P,D){var T=TA();return D=D===void 0?null:D,P=P(),T.memoizedState=[P,D],P},useReducer:function(P,D,T){var q=TA();return D=T!==void 0?T(D):D,q.memoizedState=q.baseState=D,P=q.queue={last:null,dispatch:null,lastRenderedReducer:P,lastRenderedState:D},P=P.dispatch=dg.bind(null,qa,P),[q.memoizedState,P]},useRef:function(P){var D=TA();return P={current:P},D.memoizedState=P},useState:Ag,useDebugValue:gg,useResponder:cg,useDeferredValue:function(P,D){var T=Ag(P),q=T[0],Y=T[1];return Ct(function(){a.unstable_next(function(){var Ae=Hs.suspense;Hs.suspense=D===void 0?null:D;try{Y(P)}finally{Hs.suspense=Ae}})},[P,D]),q},useTransition:function(P){var D=Ag(!1),T=D[0],q=D[1];return[wu(function(Y){q(!0),a.unstable_next(function(){var Ae=Hs.suspense;Hs.suspense=P===void 0?null:P;try{q(!1),Y()}finally{Hs.suspense=Ae}})},[P,T]),T]}},km={readContext:ms,useCallback:xm,useContext:ms,useEffect:bm,useImperativeHandle:function(P,D,T){return T=T!=null?T.concat([P]):null,Bc(4,36,hg.bind(null,D,P),T)},useLayoutEffect:function(P,D){return Bc(4,36,P,D)},useMemo:function(P,D){var T=hp();D=D===void 0?null:D;var q=T.memoizedState;return q!==null&&D!==null&&Cu(D,q[1])?q[0]:(P=P(),T.memoizedState=[P,D],P)},useReducer:Cs,useRef:function(){return hp().memoizedState},useState:fg,useDebugValue:gg,useResponder:cg,useDeferredValue:function(P,D){var T=fg(P),q=T[0],Y=T[1];return bm(function(){a.unstable_next(function(){var Ae=Hs.suspense;Hs.suspense=D===void 0?null:D;try{Y(P)}finally{Hs.suspense=Ae}})},[P,D]),q},useTransition:function(P){var D=fg(!1),T=D[0],q=D[1];return[xm(function(Y){q(!0),a.unstable_next(function(){var Ae=Hs.suspense;Hs.suspense=P===void 0?null:P;try{q(!1),Y()}finally{Hs.suspense=Ae}})},[P,T]),T]}},Aa=null,vc=null,Bl=!1;function Bu(P,D){var T=Pl(5,null,null,0);T.elementType=\"DELETED\",T.type=\"DELETED\",T.stateNode=D,T.return=P,T.effectTag=8,P.lastEffect!==null?(P.lastEffect.nextEffect=T,P.lastEffect=T):P.firstEffect=P.lastEffect=T}function mg(P,D){switch(P.tag){case 5:return D=io(D,P.type,P.pendingProps),D!==null?(P.stateNode=D,!0):!1;case 6:return D=Si(D,P.pendingProps),D!==null?(P.stateNode=D,!0):!1;case 13:return!1;default:return!1}}function LA(P){if(Bl){var D=vc;if(D){var T=D;if(!mg(P,D)){if(D=uc(T),!D||!mg(P,D)){P.effectTag=P.effectTag&-1025|2,Bl=!1,Aa=P;return}Bu(Aa,T)}Aa=P,vc=uu(D)}else P.effectTag=P.effectTag&-1025|2,Bl=!1,Aa=P}}function dp(P){for(P=P.return;P!==null&&P.tag!==5&&P.tag!==3&&P.tag!==13;)P=P.return;Aa=P}function Ga(P){if(!y||P!==Aa)return!1;if(!Bl)return dp(P),Bl=!0,!1;var D=P.type;if(P.tag!==5||D!==\"head\"&&D!==\"body\"&&!ke(D,P.memoizedProps))for(D=vc;D;)Bu(P,D),D=uc(D);if(dp(P),P.tag===13){if(!y)throw Error(n(316));if(P=P.memoizedState,P=P!==null?P.dehydrated:null,!P)throw Error(n(317));vc=Os(P)}else vc=Aa?uc(P.stateNode):null;return!0}function yg(){y&&(vc=Aa=null,Bl=!1)}var mp=u.ReactCurrentOwner,Go=!1;function ws(P,D,T,q){D.child=P===null?og(D,null,T,q):du(D,P.child,T,q)}function Ii(P,D,T,q,Y){T=T.render;var Ae=D.ref;return ds(D,Y),q=ug(P,D,T,q,Ae,Y),P!==null&&!Go?(D.updateQueue=P.updateQueue,D.effectTag&=-517,P.expirationTime<=Y&&(P.expirationTime=0),si(P,D,Y)):(D.effectTag|=1,ws(P,D,q,Y),D.child)}function Qm(P,D,T,q,Y,Ae){if(P===null){var De=T.type;return typeof De==\"function\"&&!Qw(De)&&De.defaultProps===void 0&&T.compare===null&&T.defaultProps===void 0?(D.tag=15,D.type=De,Fm(P,D,De,q,Y,Ae)):(P=qm(T.type,null,q,null,D.mode,Ae),P.ref=D.ref,P.return=D,D.child=P)}return De=P.child,Y<Ae&&(Y=De.memoizedProps,T=T.compare,T=T!==null?T:Fn,T(Y,q)&&P.ref===D.ref)?si(P,D,Ae):(D.effectTag|=1,P=WA(De,q,Ae),P.ref=D.ref,P.return=D,D.child=P)}function Fm(P,D,T,q,Y,Ae){return P!==null&&Fn(P.memoizedProps,q)&&P.ref===D.ref&&(Go=!1,Y<Ae)?si(P,D,Ae):NA(P,D,T,q,Ae)}function jo(P,D){var T=D.ref;(P===null&&T!==null||P!==null&&P.ref!==T)&&(D.effectTag|=128)}function NA(P,D,T,q,Y){var Ae=ii(T)?rr:Mn.current;return Ae=Oe(D,Ae),ds(D,Y),T=ug(P,D,T,q,Ae,Y),P!==null&&!Go?(D.updateQueue=P.updateQueue,D.effectTag&=-517,P.expirationTime<=Y&&(P.expirationTime=0),si(P,D,Y)):(D.effectTag|=1,ws(P,D,T,Y),D.child)}function yp(P,D,T,q,Y){if(ii(T)){var Ae=!0;fc(D)}else Ae=!1;if(ds(D,Y),D.stateNode===null)P!==null&&(P.alternate=null,D.alternate=null,D.effectTag|=2),es(D,T,q,Y),qo(D,T,q,Y),q=!0;else if(P===null){var De=D.stateNode,vt=D.memoizedProps;De.props=vt;var wt=De.context,xt=T.contextType;typeof xt==\"object\"&&xt!==null?xt=ms(xt):(xt=ii(T)?rr:Mn.current,xt=Oe(D,xt));var _r=T.getDerivedStateFromProps,is=typeof _r==\"function\"||typeof De.getSnapshotBeforeUpdate==\"function\";is||typeof De.UNSAFE_componentWillReceiveProps!=\"function\"&&typeof De.componentWillReceiveProps!=\"function\"||(vt!==q||wt!==xt)&&bi(D,De,q,xt),_s=!1;var di=D.memoizedState;wt=De.state=di;var po=D.updateQueue;po!==null&&(ye(D,po,q,De,Y),wt=D.memoizedState),vt!==q||di!==wt||_i.current||_s?(typeof _r==\"function\"&&(er(D,T,_r,q),wt=D.memoizedState),(vt=_s||Gi(D,T,vt,q,di,wt,xt))?(is||typeof De.UNSAFE_componentWillMount!=\"function\"&&typeof De.componentWillMount!=\"function\"||(typeof De.componentWillMount==\"function\"&&De.componentWillMount(),typeof De.UNSAFE_componentWillMount==\"function\"&&De.UNSAFE_componentWillMount()),typeof De.componentDidMount==\"function\"&&(D.effectTag|=4)):(typeof De.componentDidMount==\"function\"&&(D.effectTag|=4),D.memoizedProps=q,D.memoizedState=wt),De.props=q,De.state=wt,De.context=xt,q=vt):(typeof De.componentDidMount==\"function\"&&(D.effectTag|=4),q=!1)}else De=D.stateNode,vt=D.memoizedProps,De.props=D.type===D.elementType?vt:Ci(D.type,vt),wt=De.context,xt=T.contextType,typeof xt==\"object\"&&xt!==null?xt=ms(xt):(xt=ii(T)?rr:Mn.current,xt=Oe(D,xt)),_r=T.getDerivedStateFromProps,(is=typeof _r==\"function\"||typeof De.getSnapshotBeforeUpdate==\"function\")||typeof De.UNSAFE_componentWillReceiveProps!=\"function\"&&typeof De.componentWillReceiveProps!=\"function\"||(vt!==q||wt!==xt)&&bi(D,De,q,xt),_s=!1,wt=D.memoizedState,di=De.state=wt,po=D.updateQueue,po!==null&&(ye(D,po,q,De,Y),di=D.memoizedState),vt!==q||wt!==di||_i.current||_s?(typeof _r==\"function\"&&(er(D,T,_r,q),di=D.memoizedState),(_r=_s||Gi(D,T,vt,q,wt,di,xt))?(is||typeof De.UNSAFE_componentWillUpdate!=\"function\"&&typeof De.componentWillUpdate!=\"function\"||(typeof De.componentWillUpdate==\"function\"&&De.componentWillUpdate(q,di,xt),typeof De.UNSAFE_componentWillUpdate==\"function\"&&De.UNSAFE_componentWillUpdate(q,di,xt)),typeof De.componentDidUpdate==\"function\"&&(D.effectTag|=4),typeof De.getSnapshotBeforeUpdate==\"function\"&&(D.effectTag|=256)):(typeof De.componentDidUpdate!=\"function\"||vt===P.memoizedProps&&wt===P.memoizedState||(D.effectTag|=4),typeof De.getSnapshotBeforeUpdate!=\"function\"||vt===P.memoizedProps&&wt===P.memoizedState||(D.effectTag|=256),D.memoizedProps=q,D.memoizedState=di),De.props=q,De.state=di,De.context=xt,q=_r):(typeof De.componentDidUpdate!=\"function\"||vt===P.memoizedProps&&wt===P.memoizedState||(D.effectTag|=4),typeof De.getSnapshotBeforeUpdate!=\"function\"||vt===P.memoizedProps&&wt===P.memoizedState||(D.effectTag|=256),q=!1);return Ep(P,D,T,q,Ae,Y)}function Ep(P,D,T,q,Y,Ae){jo(P,D);var De=(D.effectTag&64)!==0;if(!q&&!De)return Y&&Cl(D,T,!1),si(P,D,Ae);q=D.stateNode,mp.current=D;var vt=De&&typeof T.getDerivedStateFromError!=\"function\"?null:q.render();return D.effectTag|=1,P!==null&&De?(D.child=du(D,P.child,null,Ae),D.child=du(D,null,vt,Ae)):ws(P,D,vt,Ae),D.memoizedState=q.state,Y&&Cl(D,T,!0),D.child}function Eg(P){var D=P.stateNode;D.pendingContext?Ac(P,D.pendingContext,D.pendingContext!==D.context):D.context&&Ac(P,D.context,!1),ag(P,D.containerInfo)}var fa={dehydrated:null,retryTime:0};function ln(P,D,T){var q=D.mode,Y=D.pendingProps,Ae=ei.current,De=!1,vt;if((vt=(D.effectTag&64)!==0)||(vt=(Ae&2)!==0&&(P===null||P.memoizedState!==null)),vt?(De=!0,D.effectTag&=-65):P!==null&&P.memoizedState===null||Y.fallback===void 0||Y.unstable_avoidThisFallback===!0||(Ae|=1),On(ei,Ae&1,D),P===null){if(Y.fallback!==void 0&&LA(D),De){if(De=Y.fallback,Y=xu(null,q,0,null),Y.return=D,(D.mode&2)===0)for(P=D.memoizedState!==null?D.child.child:D.child,Y.child=P;P!==null;)P.return=Y,P=P.sibling;return T=xu(De,q,T,null),T.return=D,Y.sibling=T,D.memoizedState=fa,D.child=Y,T}return q=Y.children,D.memoizedState=null,D.child=og(D,null,q,T)}if(P.memoizedState!==null){if(P=P.child,q=P.sibling,De){if(Y=Y.fallback,T=WA(P,P.pendingProps,0),T.return=D,(D.mode&2)===0&&(De=D.memoizedState!==null?D.child.child:D.child,De!==P.child))for(T.child=De;De!==null;)De.return=T,De=De.sibling;return q=WA(q,Y,q.expirationTime),q.return=D,T.sibling=q,T.childExpirationTime=0,D.memoizedState=fa,D.child=T,q}return T=du(D,P.child,Y.children,T),D.memoizedState=null,D.child=T}if(P=P.child,De){if(De=Y.fallback,Y=xu(null,q,0,null),Y.return=D,Y.child=P,P!==null&&(P.return=Y),(D.mode&2)===0)for(P=D.memoizedState!==null?D.child.child:D.child,Y.child=P;P!==null;)P.return=Y,P=P.sibling;return T=xu(De,q,T,null),T.return=D,Y.sibling=T,T.effectTag|=2,Y.childExpirationTime=0,D.memoizedState=fa,D.child=Y,T}return D.memoizedState=null,D.child=du(D,P,Y.children,T)}function Ao(P,D){P.expirationTime<D&&(P.expirationTime=D);var T=P.alternate;T!==null&&T.expirationTime<D&&(T.expirationTime=D),gs(P.return,D)}function OA(P,D,T,q,Y,Ae){var De=P.memoizedState;De===null?P.memoizedState={isBackwards:D,rendering:null,last:q,tail:T,tailExpiration:0,tailMode:Y,lastEffect:Ae}:(De.isBackwards=D,De.rendering=null,De.last=q,De.tail=T,De.tailExpiration=0,De.tailMode=Y,De.lastEffect=Ae)}function ja(P,D,T){var q=D.pendingProps,Y=q.revealOrder,Ae=q.tail;if(ws(P,D,q.children,T),q=ei.current,(q&2)!==0)q=q&1|2,D.effectTag|=64;else{if(P!==null&&(P.effectTag&64)!==0)e:for(P=D.child;P!==null;){if(P.tag===13)P.memoizedState!==null&&Ao(P,T);else if(P.tag===19)Ao(P,T);else if(P.child!==null){P.child.return=P,P=P.child;continue}if(P===D)break e;for(;P.sibling===null;){if(P.return===null||P.return===D)break e;P=P.return}P.sibling.return=P.return,P=P.sibling}q&=1}if(On(ei,q,D),(D.mode&2)===0)D.memoizedState=null;else switch(Y){case\"forwards\":for(T=D.child,Y=null;T!==null;)P=T.alternate,P!==null&&pp(P)===null&&(Y=T),T=T.sibling;T=Y,T===null?(Y=D.child,D.child=null):(Y=T.sibling,T.sibling=null),OA(D,!1,Y,T,Ae,D.lastEffect);break;case\"backwards\":for(T=null,Y=D.child,D.child=null;Y!==null;){if(P=Y.alternate,P!==null&&pp(P)===null){D.child=Y;break}P=Y.sibling,Y.sibling=T,T=Y,Y=P}OA(D,!0,T,null,Ae,D.lastEffect);break;case\"together\":OA(D,!1,null,null,void 0,D.lastEffect);break;default:D.memoizedState=null}return D.child}function si(P,D,T){P!==null&&(D.dependencies=P.dependencies);var q=D.expirationTime;if(q!==0&&Hm(q),D.childExpirationTime<T)return null;if(P!==null&&D.child!==P.child)throw Error(n(153));if(D.child!==null){for(P=D.child,T=WA(P,P.pendingProps,P.expirationTime),D.child=T,T.return=D;P.sibling!==null;)P=P.sibling,T=T.sibling=WA(P,P.pendingProps,P.expirationTime),T.return=D;T.sibling=null}return D.child}function pa(P){P.effectTag|=4}var Dc,vl,ts,jr;if(w)Dc=function(P,D){for(var T=D.child;T!==null;){if(T.tag===5||T.tag===6)H(P,T.stateNode);else if(T.tag!==4&&T.child!==null){T.child.return=T,T=T.child;continue}if(T===D)break;for(;T.sibling===null;){if(T.return===null||T.return===D)return;T=T.return}T.sibling.return=T.return,T=T.sibling}},vl=function(){},ts=function(P,D,T,q,Y){if(P=P.memoizedProps,P!==q){var Ae=D.stateNode,De=ca(uo.current);T=Re(Ae,T,P,q,Y,De),(D.updateQueue=T)&&pa(D)}},jr=function(P,D,T,q){T!==q&&pa(D)};else if(S){Dc=function(P,D,T,q){for(var Y=D.child;Y!==null;){if(Y.tag===5){var Ae=Y.stateNode;T&&q&&(Ae=Ti(Ae,Y.type,Y.memoizedProps,Y)),H(P,Ae)}else if(Y.tag===6)Ae=Y.stateNode,T&&q&&(Ae=ps(Ae,Y.memoizedProps,Y)),H(P,Ae);else if(Y.tag!==4){if(Y.tag===13&&(Y.effectTag&4)!==0&&(Ae=Y.memoizedState!==null)){var De=Y.child;if(De!==null&&(De.child!==null&&(De.child.return=De,Dc(P,De,!0,Ae)),Ae=De.sibling,Ae!==null)){Ae.return=Y,Y=Ae;continue}}if(Y.child!==null){Y.child.return=Y,Y=Y.child;continue}}if(Y===D)break;for(;Y.sibling===null;){if(Y.return===null||Y.return===D)return;Y=Y.return}Y.sibling.return=Y.return,Y=Y.sibling}};var Cp=function(P,D,T,q){for(var Y=D.child;Y!==null;){if(Y.tag===5){var Ae=Y.stateNode;T&&q&&(Ae=Ti(Ae,Y.type,Y.memoizedProps,Y)),Wr(P,Ae)}else if(Y.tag===6)Ae=Y.stateNode,T&&q&&(Ae=ps(Ae,Y.memoizedProps,Y)),Wr(P,Ae);else if(Y.tag!==4){if(Y.tag===13&&(Y.effectTag&4)!==0&&(Ae=Y.memoizedState!==null)){var De=Y.child;if(De!==null&&(De.child!==null&&(De.child.return=De,Cp(P,De,!0,Ae)),Ae=De.sibling,Ae!==null)){Ae.return=Y,Y=Ae;continue}}if(Y.child!==null){Y.child.return=Y,Y=Y.child;continue}}if(Y===D)break;for(;Y.sibling===null;){if(Y.return===null||Y.return===D)return;Y=Y.return}Y.sibling.return=Y.return,Y=Y.sibling}};vl=function(P){var D=P.stateNode;if(P.firstEffect!==null){var T=D.containerInfo,q=br(T);Cp(q,P,!1,!1),D.pendingChildren=q,pa(P),Kn(T,q)}},ts=function(P,D,T,q,Y){var Ae=P.stateNode,De=P.memoizedProps;if((P=D.firstEffect===null)&&De===q)D.stateNode=Ae;else{var vt=D.stateNode,wt=ca(uo.current),xt=null;De!==q&&(xt=Re(vt,T,De,q,Y,wt)),P&&xt===null?D.stateNode=Ae:(Ae=mr(Ae,xt,T,De,q,D,P,vt),at(Ae,T,q,Y,wt)&&pa(D),D.stateNode=Ae,P?pa(D):Dc(Ae,D,!1,!1))}},jr=function(P,D,T,q){T!==q&&(P=ca(yc.current),T=ca(uo.current),D.stateNode=He(q,P,T,D),pa(D))}}else vl=function(){},ts=function(){},jr=function(){};function Pc(P,D){switch(P.tailMode){case\"hidden\":D=P.tail;for(var T=null;D!==null;)D.alternate!==null&&(T=D),D=D.sibling;T===null?P.tail=null:T.sibling=null;break;case\"collapsed\":T=P.tail;for(var q=null;T!==null;)T.alternate!==null&&(q=T),T=T.sibling;q===null?D||P.tail===null?P.tail=null:P.tail.sibling=null:q.sibling=null}}function Cw(P){switch(P.tag){case 1:ii(P.type)&&Ua(P);var D=P.effectTag;return D&4096?(P.effectTag=D&-4097|64,P):null;case 3:if(Ec(P),hr(P),D=P.effectTag,(D&64)!==0)throw Error(n(285));return P.effectTag=D&-4097|64,P;case 5:return lg(P),null;case 13:return zn(ei,P),D=P.effectTag,D&4096?(P.effectTag=D&-4097|64,P):null;case 19:return zn(ei,P),null;case 4:return Ec(P),null;case 10:return wi(P),null;default:return null}}function Cg(P,D){return{value:P,source:D,stack:yl(D)}}var wg=typeof WeakSet==\"function\"?WeakSet:Set;function Ya(P,D){var T=D.source,q=D.stack;q===null&&T!==null&&(q=yl(T)),T!==null&&he(T.type),D=D.value,P!==null&&P.tag===1&&he(P.type);try{console.error(D)}catch(Y){setTimeout(function(){throw Y})}}function Rm(P,D){try{D.props=P.memoizedProps,D.state=P.memoizedState,D.componentWillUnmount()}catch(T){YA(P,T)}}function Ig(P){var D=P.ref;if(D!==null)if(typeof D==\"function\")try{D(null)}catch(T){YA(P,T)}else D.current=null}function Qt(P,D){switch(D.tag){case 0:case 11:case 15:L(2,0,D);break;case 1:if(D.effectTag&256&&P!==null){var T=P.memoizedProps,q=P.memoizedState;P=D.stateNode,D=P.getSnapshotBeforeUpdate(D.elementType===D.type?T:Ci(D.type,T),q),P.__reactInternalSnapshotBeforeUpdate=D}break;case 3:case 5:case 6:case 4:case 17:break;default:throw Error(n(163))}}function L(P,D,T){if(T=T.updateQueue,T=T!==null?T.lastEffect:null,T!==null){var q=T=T.next;do{if((q.tag&P)!==0){var Y=q.destroy;q.destroy=void 0,Y!==void 0&&Y()}(q.tag&D)!==0&&(Y=q.create,q.destroy=Y()),q=q.next}while(q!==T)}}function K(P,D,T){switch(typeof kw==\"function\"&&kw(D),D.tag){case 0:case 11:case 14:case 15:if(P=D.updateQueue,P!==null&&(P=P.lastEffect,P!==null)){var q=P.next;lo(97<T?97:T,function(){var Y=q;do{var Ae=Y.destroy;if(Ae!==void 0){var De=D;try{Ae()}catch(vt){YA(De,vt)}}Y=Y.next}while(Y!==q)})}break;case 1:Ig(D),T=D.stateNode,typeof T.componentWillUnmount==\"function\"&&Rm(D,T);break;case 5:Ig(D);break;case 4:w?Cr(P,D,T):S&&Je(D)}}function re(P,D,T){for(var q=D;;)if(K(P,q,T),q.child===null||w&&q.tag===4){if(q===D)break;for(;q.sibling===null;){if(q.return===null||q.return===D)return;q=q.return}q.sibling.return=q.return,q=q.sibling}else q.child.return=q,q=q.child}function pe(P){var D=P.alternate;P.return=null,P.child=null,P.memoizedState=null,P.updateQueue=null,P.dependencies=null,P.alternate=null,P.firstEffect=null,P.lastEffect=null,P.pendingProps=null,P.memoizedProps=null,D!==null&&pe(D)}function Je(P){if(S){P=P.stateNode.containerInfo;var D=br(P);Ls(P,D)}}function mt(P){return P.tag===5||P.tag===3||P.tag===4}function fr(P){if(w){e:{for(var D=P.return;D!==null;){if(mt(D)){var T=D;break e}D=D.return}throw Error(n(160))}switch(D=T.stateNode,T.tag){case 5:var q=!1;break;case 3:D=D.containerInfo,q=!0;break;case 4:D=D.containerInfo,q=!0;break;default:throw Error(n(161))}T.effectTag&16&&(Gt(D),T.effectTag&=-17);e:t:for(T=P;;){for(;T.sibling===null;){if(T.return===null||mt(T.return)){T=null;break e}T=T.return}for(T.sibling.return=T.return,T=T.sibling;T.tag!==5&&T.tag!==6&&T.tag!==18;){if(T.effectTag&2||T.child===null||T.tag===4)continue t;T.child.return=T,T=T.child}if(!(T.effectTag&2)){T=T.stateNode;break e}}for(var Y=P;;){var Ae=Y.tag===5||Y.tag===6;if(Ae)Ae=Ae?Y.stateNode:Y.stateNode.instance,T?q?Le(D,Ae,T):be(D,Ae,T):q?J(D,Ae):F(D,Ae);else if(Y.tag!==4&&Y.child!==null){Y.child.return=Y,Y=Y.child;continue}if(Y===P)break;for(;Y.sibling===null;){if(Y.return===null||Y.return===P)return;Y=Y.return}Y.sibling.return=Y.return,Y=Y.sibling}}}function Cr(P,D,T){for(var q=D,Y=!1,Ae,De;;){if(!Y){Y=q.return;e:for(;;){if(Y===null)throw Error(n(160));switch(Ae=Y.stateNode,Y.tag){case 5:De=!1;break e;case 3:Ae=Ae.containerInfo,De=!0;break e;case 4:Ae=Ae.containerInfo,De=!0;break e}Y=Y.return}Y=!0}if(q.tag===5||q.tag===6)re(P,q,T),De?dt(Ae,q.stateNode):ot(Ae,q.stateNode);else if(q.tag===4){if(q.child!==null){Ae=q.stateNode.containerInfo,De=!0,q.child.return=q,q=q.child;continue}}else if(K(P,q,T),q.child!==null){q.child.return=q,q=q.child;continue}if(q===D)break;for(;q.sibling===null;){if(q.return===null||q.return===D)return;q=q.return,q.tag===4&&(Y=!1)}q.sibling.return=q.return,q=q.sibling}}function yn(P,D){if(w)switch(D.tag){case 0:case 11:case 14:case 15:L(4,8,D);break;case 1:break;case 5:var T=D.stateNode;if(T!=null){var q=D.memoizedProps;P=P!==null?P.memoizedProps:q;var Y=D.type,Ae=D.updateQueue;D.updateQueue=null,Ae!==null&&ie(T,Ae,Y,P,q,D)}break;case 6:if(D.stateNode===null)throw Error(n(162));T=D.memoizedProps,X(D.stateNode,P!==null?P.memoizedProps:T,T);break;case 3:y&&(D=D.stateNode,D.hydrate&&(D.hydrate=!1,Dn(D.containerInfo)));break;case 12:break;case 13:oi(D),Oi(D);break;case 19:Oi(D);break;case 17:break;case 20:break;case 21:break;default:throw Error(n(163))}else{switch(D.tag){case 0:case 11:case 14:case 15:L(4,8,D);return;case 12:return;case 13:oi(D),Oi(D);return;case 19:Oi(D);return;case 3:y&&(T=D.stateNode,T.hydrate&&(T.hydrate=!1,Dn(T.containerInfo)))}e:if(S)switch(D.tag){case 1:case 5:case 6:case 20:break e;case 3:case 4:D=D.stateNode,Ls(D.containerInfo,D.pendingChildren);break e;default:throw Error(n(163))}}}function oi(P){var D=P;if(P.memoizedState===null)var T=!1;else T=!0,D=P.child,Bw=Ni();if(w&&D!==null){e:if(P=D,w)for(D=P;;){if(D.tag===5){var q=D.stateNode;T?$t(q):an(D.stateNode,D.memoizedProps)}else if(D.tag===6)q=D.stateNode,T?bt(q):Qr(q,D.memoizedProps);else if(D.tag===13&&D.memoizedState!==null&&D.memoizedState.dehydrated===null){q=D.child.sibling,q.return=D,D=q;continue}else if(D.child!==null){D.child.return=D,D=D.child;continue}if(D===P)break e;for(;D.sibling===null;){if(D.return===null||D.return===P)break e;D=D.return}D.sibling.return=D.return,D=D.sibling}}}function Oi(P){var D=P.updateQueue;if(D!==null){P.updateQueue=null;var T=P.stateNode;T===null&&(T=P.stateNode=new wg),D.forEach(function(q){var Y=yF.bind(null,P,q);T.has(q)||(T.add(q),q.then(Y,Y))})}}var Bg=typeof WeakMap==\"function\"?WeakMap:Map;function jv(P,D,T){T=ys(T,null),T.tag=3,T.payload={element:null};var q=D.value;return T.callback=function(){Du||(Du=!0,Mm=q),Ya(P,D)},T}function Yv(P,D,T){T=ys(T,null),T.tag=3;var q=P.type.getDerivedStateFromError;if(typeof q==\"function\"){var Y=D.value;T.payload=function(){return Ya(P,D),q(Y)}}var Ae=P.stateNode;return Ae!==null&&typeof Ae.componentDidCatch==\"function\"&&(T.callback=function(){typeof q!=\"function\"&&(Pu===null?Pu=new Set([this]):Pu.add(this),Ya(P,D));var De=D.stack;this.componentDidCatch(D.value,{componentStack:De!==null?De:\"\"})}),T}var ww=Math.ceil,wp=u.ReactCurrentDispatcher,Iw=u.ReactCurrentOwner,En=0,Tm=8,rs=16,qs=32,vu=0,Lm=1,Bi=2,ha=3,Dl=4,Sc=5,yr=En,gi=null,Or=null,ns=0,Yi=vu,Nm=null,Wa=1073741823,MA=1073741823,Om=null,Ip=0,UA=!1,Bw=0,vw=500,or=null,Du=!1,Mm=null,Pu=null,Bp=!1,vg=null,_A=90,HA=null,Dg=0,Dw=null,Um=0;function ga(){return(yr&(rs|qs))!==En?1073741821-(Ni()/10|0):Um!==0?Um:Um=1073741821-(Ni()/10|0)}function qA(P,D,T){if(D=D.mode,(D&2)===0)return 1073741823;var q=_o();if((D&4)===0)return q===99?1073741823:1073741822;if((yr&rs)!==En)return ns;if(T!==null)P=Ha(P,T.timeoutMs|0||5e3,250);else switch(q){case 99:P=1073741823;break;case 98:P=Ha(P,150,100);break;case 97:case 96:P=Ha(P,5e3,250);break;case 95:P=2;break;default:throw Error(n(326))}return gi!==null&&P===ns&&--P,P}function bc(P,D){if(50<Dg)throw Dg=0,Dw=null,Error(n(185));if(P=Pg(P,D),P!==null){var T=_o();D===1073741823?(yr&Tm)!==En&&(yr&(rs|qs))===En?Pw(P):(fo(P),yr===En&&qi()):fo(P),(yr&4)===En||T!==98&&T!==99||(HA===null?HA=new Map([[P,D]]):(T=HA.get(P),(T===void 0||T>D)&&HA.set(P,D)))}}function Pg(P,D){P.expirationTime<D&&(P.expirationTime=D);var T=P.alternate;T!==null&&T.expirationTime<D&&(T.expirationTime=D);var q=P.return,Y=null;if(q===null&&P.tag===3)Y=P.stateNode;else for(;q!==null;){if(T=q.alternate,q.childExpirationTime<D&&(q.childExpirationTime=D),T!==null&&T.childExpirationTime<D&&(T.childExpirationTime=D),q.return===null&&q.tag===3){Y=q.stateNode;break}q=q.return}return Y!==null&&(gi===Y&&(Hm(D),Yi===Dl&&KA(Y,ns)),eD(Y,D)),Y}function _m(P){var D=P.lastExpiredTime;return D!==0||(D=P.firstPendingTime,!$v(P,D))?D:(D=P.lastPingedTime,P=P.nextKnownPendingLevel,D>P?D:P)}function fo(P){if(P.lastExpiredTime!==0)P.callbackExpirationTime=1073741823,P.callbackPriority=99,P.callbackNode=hu(Pw.bind(null,P));else{var D=_m(P),T=P.callbackNode;if(D===0)T!==null&&(P.callbackNode=null,P.callbackExpirationTime=0,P.callbackPriority=90);else{var q=ga();if(D===1073741823?q=99:D===1||D===2?q=95:(q=10*(1073741821-D)-10*(1073741821-q),q=0>=q?99:250>=q?98:5250>=q?97:95),T!==null){var Y=P.callbackPriority;if(P.callbackExpirationTime===D&&Y>=q)return;T!==SA&&Ce(T)}P.callbackExpirationTime=D,P.callbackPriority=q,D=D===1073741823?hu(Pw.bind(null,P)):dc(q,Wv.bind(null,P),{timeout:10*(1073741821-D)-Ni()}),P.callbackNode=D}}}function Wv(P,D){if(Um=0,D)return D=ga(),Gm(P,D),fo(P),null;var T=_m(P);if(T!==0){if(D=P.callbackNode,(yr&(rs|qs))!==En)throw Error(n(327));if(vp(),P===gi&&T===ns||Su(P,T),Or!==null){var q=yr;yr|=rs;var Y=jA(P);do try{pF();break}catch(vt){GA(P,vt)}while(1);if(la(),yr=q,wp.current=Y,Yi===Lm)throw D=Nm,Su(P,T),KA(P,T),fo(P),D;if(Or===null)switch(Y=P.finishedWork=P.current.alternate,P.finishedExpirationTime=T,q=Yi,gi=null,q){case vu:case Lm:throw Error(n(345));case Bi:Gm(P,2<T?2:T);break;case ha:if(KA(P,T),q=P.lastSuspendedTime,T===q&&(P.nextKnownPendingLevel=bw(Y)),Wa===1073741823&&(Y=Bw+vw-Ni(),10<Y)){if(UA){var Ae=P.lastPingedTime;if(Ae===0||Ae>=T){P.lastPingedTime=T,Su(P,T);break}}if(Ae=_m(P),Ae!==0&&Ae!==T)break;if(q!==0&&q!==T){P.lastPingedTime=q;break}P.timeoutHandle=Te(bu.bind(null,P),Y);break}bu(P);break;case Dl:if(KA(P,T),q=P.lastSuspendedTime,T===q&&(P.nextKnownPendingLevel=bw(Y)),UA&&(Y=P.lastPingedTime,Y===0||Y>=T)){P.lastPingedTime=T,Su(P,T);break}if(Y=_m(P),Y!==0&&Y!==T)break;if(q!==0&&q!==T){P.lastPingedTime=q;break}if(MA!==1073741823?q=10*(1073741821-MA)-Ni():Wa===1073741823?q=0:(q=10*(1073741821-Wa)-5e3,Y=Ni(),T=10*(1073741821-T)-Y,q=Y-q,0>q&&(q=0),q=(120>q?120:480>q?480:1080>q?1080:1920>q?1920:3e3>q?3e3:4320>q?4320:1960*ww(q/1960))-q,T<q&&(q=T)),10<q){P.timeoutHandle=Te(bu.bind(null,P),q);break}bu(P);break;case Sc:if(Wa!==1073741823&&Om!==null){Ae=Wa;var De=Om;if(q=De.busyMinDurationMs|0,0>=q?q=0:(Y=De.busyDelayMs|0,Ae=Ni()-(10*(1073741821-Ae)-(De.timeoutMs|0||5e3)),q=Ae<=Y?0:Y+q-Ae),10<q){KA(P,T),P.timeoutHandle=Te(bu.bind(null,P),q);break}}bu(P);break;default:throw Error(n(329))}if(fo(P),P.callbackNode===D)return Wv.bind(null,P)}}return null}function Pw(P){var D=P.lastExpiredTime;if(D=D!==0?D:1073741823,P.finishedExpirationTime===D)bu(P);else{if((yr&(rs|qs))!==En)throw Error(n(327));if(vp(),P===gi&&D===ns||Su(P,D),Or!==null){var T=yr;yr|=rs;var q=jA(P);do try{fF();break}catch(Y){GA(P,Y)}while(1);if(la(),yr=T,wp.current=q,Yi===Lm)throw T=Nm,Su(P,D),KA(P,D),fo(P),T;if(Or!==null)throw Error(n(261));P.finishedWork=P.current.alternate,P.finishedExpirationTime=D,gi=null,bu(P),fo(P)}}return null}function Kv(P,D){Gm(P,D),fo(P),(yr&(rs|qs))===En&&qi()}function AF(){if(HA!==null){var P=HA;HA=null,P.forEach(function(D,T){Gm(T,D),fo(T)}),qi()}}function zv(P,D){if((yr&(rs|qs))!==En)throw Error(n(187));var T=yr;yr|=1;try{return lo(99,P.bind(null,D))}finally{yr=T,qi()}}function Su(P,D){P.finishedWork=null,P.finishedExpirationTime=0;var T=P.timeoutHandle;if(T!==qe&&(P.timeoutHandle=qe,Ve(T)),Or!==null)for(T=Or.return;T!==null;){var q=T;switch(q.tag){case 1:var Y=q.type.childContextTypes;Y!=null&&Ua(q);break;case 3:Ec(q),hr(q);break;case 5:lg(q);break;case 4:Ec(q);break;case 13:zn(ei,q);break;case 19:zn(ei,q);break;case 10:wi(q)}T=T.return}gi=P,Or=WA(P.current,null,D),ns=D,Yi=vu,Nm=null,MA=Wa=1073741823,Om=null,Ip=0,UA=!1}function GA(P,D){do{try{if(la(),yw(),Or===null||Or.return===null)return Yi=Lm,Nm=D,null;e:{var T=P,q=Or.return,Y=Or,Ae=D;if(D=ns,Y.effectTag|=2048,Y.firstEffect=Y.lastEffect=null,Ae!==null&&typeof Ae==\"object\"&&typeof Ae.then==\"function\"){var De=Ae,vt=(ei.current&1)!==0,wt=q;do{var xt;if(xt=wt.tag===13){var _r=wt.memoizedState;if(_r!==null)xt=_r.dehydrated!==null;else{var is=wt.memoizedProps;xt=is.fallback===void 0?!1:is.unstable_avoidThisFallback!==!0?!0:!vt}}if(xt){var di=wt.updateQueue;if(di===null){var po=new Set;po.add(De),wt.updateQueue=po}else di.add(De);if((wt.mode&2)===0){if(wt.effectTag|=64,Y.effectTag&=-2981,Y.tag===1)if(Y.alternate===null)Y.tag=17;else{var zA=ys(1073741823,null);zA.tag=2,tt(Y,zA)}Y.expirationTime=1073741823;break e}Ae=void 0,Y=D;var Yo=T.pingCache;if(Yo===null?(Yo=T.pingCache=new Bg,Ae=new Set,Yo.set(De,Ae)):(Ae=Yo.get(De),Ae===void 0&&(Ae=new Set,Yo.set(De,Ae))),!Ae.has(Y)){Ae.add(Y);var rt=mF.bind(null,T,De,Y);De.then(rt,rt)}wt.effectTag|=4096,wt.expirationTime=D;break e}wt=wt.return}while(wt!==null);Ae=Error((he(Y.type)||\"A React component\")+` suspended while rendering, but no fallback UI was specified.\n\nAdd a <Suspense fallback=...> component higher in the tree to provide a loading indicator or placeholder to display.`+yl(Y))}Yi!==Sc&&(Yi=Bi),Ae=Cg(Ae,Y),wt=q;do{switch(wt.tag){case 3:De=Ae,wt.effectTag|=4096,wt.expirationTime=D;var ze=jv(wt,De,D);It(wt,ze);break e;case 1:De=Ae;var ft=wt.type,Wt=wt.stateNode;if((wt.effectTag&64)===0&&(typeof ft.getDerivedStateFromError==\"function\"||Wt!==null&&typeof Wt.componentDidCatch==\"function\"&&(Pu===null||!Pu.has(Wt)))){wt.effectTag|=4096,wt.expirationTime=D;var vr=Yv(wt,De,D);It(wt,vr);break e}}wt=wt.return}while(wt!==null)}Or=Jv(Or)}catch(Sn){D=Sn;continue}break}while(1)}function jA(){var P=wp.current;return wp.current=Iu,P===null?Iu:P}function Sw(P,D){P<Wa&&2<P&&(Wa=P),D!==null&&P<MA&&2<P&&(MA=P,Om=D)}function Hm(P){P>Ip&&(Ip=P)}function fF(){for(;Or!==null;)Or=Vv(Or)}function pF(){for(;Or!==null&&!Rt();)Or=Vv(Or)}function Vv(P){var D=Zv(P.alternate,P,ns);return P.memoizedProps=P.pendingProps,D===null&&(D=Jv(P)),Iw.current=null,D}function Jv(P){Or=P;do{var D=Or.alternate;if(P=Or.return,(Or.effectTag&2048)===0){e:{var T=D;D=Or;var q=ns,Y=D.pendingProps;switch(D.tag){case 2:break;case 16:break;case 15:case 0:break;case 1:ii(D.type)&&Ua(D);break;case 3:Ec(D),hr(D),Y=D.stateNode,Y.pendingContext&&(Y.context=Y.pendingContext,Y.pendingContext=null),(T===null||T.child===null)&&Ga(D)&&pa(D),vl(D);break;case 5:lg(D);var Ae=ca(yc.current);if(q=D.type,T!==null&&D.stateNode!=null)ts(T,D,q,Y,Ae),T.ref!==D.ref&&(D.effectTag|=128);else if(Y){if(T=ca(uo.current),Ga(D)){if(Y=D,!y)throw Error(n(175));T=cp(Y.stateNode,Y.type,Y.memoizedProps,Ae,T,Y),Y.updateQueue=T,T=T!==null,T&&pa(D)}else{var De=At(q,Y,Ae,T,D);Dc(De,D,!1,!1),D.stateNode=De,at(De,q,Y,Ae,T)&&pa(D)}D.ref!==null&&(D.effectTag|=128)}else if(D.stateNode===null)throw Error(n(166));break;case 6:if(T&&D.stateNode!=null)jr(T,D,T.memoizedProps,Y);else{if(typeof Y!=\"string\"&&D.stateNode===null)throw Error(n(166));if(T=ca(yc.current),Ae=ca(uo.current),Ga(D)){if(T=D,!y)throw Error(n(176));(T=up(T.stateNode,T.memoizedProps,T))&&pa(D)}else D.stateNode=He(Y,T,Ae,D)}break;case 11:break;case 13:if(zn(ei,D),Y=D.memoizedState,(D.effectTag&64)!==0){D.expirationTime=q;break e}Y=Y!==null,Ae=!1,T===null?D.memoizedProps.fallback!==void 0&&Ga(D):(q=T.memoizedState,Ae=q!==null,Y||q===null||(q=T.child.sibling,q!==null&&(De=D.firstEffect,De!==null?(D.firstEffect=q,q.nextEffect=De):(D.firstEffect=D.lastEffect=q,q.nextEffect=null),q.effectTag=8))),Y&&!Ae&&(D.mode&2)!==0&&(T===null&&D.memoizedProps.unstable_avoidThisFallback!==!0||(ei.current&1)!==0?Yi===vu&&(Yi=ha):((Yi===vu||Yi===ha)&&(Yi=Dl),Ip!==0&&gi!==null&&(KA(gi,ns),eD(gi,Ip)))),S&&Y&&(D.effectTag|=4),w&&(Y||Ae)&&(D.effectTag|=4);break;case 7:break;case 8:break;case 12:break;case 4:Ec(D),vl(D);break;case 10:wi(D);break;case 9:break;case 14:break;case 17:ii(D.type)&&Ua(D);break;case 19:if(zn(ei,D),Y=D.memoizedState,Y===null)break;if(Ae=(D.effectTag&64)!==0,De=Y.rendering,De===null){if(Ae)Pc(Y,!1);else if(Yi!==vu||T!==null&&(T.effectTag&64)!==0)for(T=D.child;T!==null;){if(De=pp(T),De!==null){for(D.effectTag|=64,Pc(Y,!1),T=De.updateQueue,T!==null&&(D.updateQueue=T,D.effectTag|=4),Y.lastEffect===null&&(D.firstEffect=null),D.lastEffect=Y.lastEffect,T=q,Y=D.child;Y!==null;)Ae=Y,q=T,Ae.effectTag&=2,Ae.nextEffect=null,Ae.firstEffect=null,Ae.lastEffect=null,De=Ae.alternate,De===null?(Ae.childExpirationTime=0,Ae.expirationTime=q,Ae.child=null,Ae.memoizedProps=null,Ae.memoizedState=null,Ae.updateQueue=null,Ae.dependencies=null):(Ae.childExpirationTime=De.childExpirationTime,Ae.expirationTime=De.expirationTime,Ae.child=De.child,Ae.memoizedProps=De.memoizedProps,Ae.memoizedState=De.memoizedState,Ae.updateQueue=De.updateQueue,q=De.dependencies,Ae.dependencies=q===null?null:{expirationTime:q.expirationTime,firstContext:q.firstContext,responders:q.responders}),Y=Y.sibling;On(ei,ei.current&1|2,D),D=D.child;break e}T=T.sibling}}else{if(!Ae)if(T=pp(De),T!==null){if(D.effectTag|=64,Ae=!0,T=T.updateQueue,T!==null&&(D.updateQueue=T,D.effectTag|=4),Pc(Y,!0),Y.tail===null&&Y.tailMode===\"hidden\"&&!De.alternate){D=D.lastEffect=Y.lastEffect,D!==null&&(D.nextEffect=null);break}}else Ni()>Y.tailExpiration&&1<q&&(D.effectTag|=64,Ae=!0,Pc(Y,!1),D.expirationTime=D.childExpirationTime=q-1);Y.isBackwards?(De.sibling=D.child,D.child=De):(T=Y.last,T!==null?T.sibling=De:D.child=De,Y.last=De)}if(Y.tail!==null){Y.tailExpiration===0&&(Y.tailExpiration=Ni()+500),T=Y.tail,Y.rendering=T,Y.tail=T.sibling,Y.lastEffect=D.lastEffect,T.sibling=null,Y=ei.current,Y=Ae?Y&1|2:Y&1,On(ei,Y,D),D=T;break e}break;case 20:break;case 21:break;default:throw Error(n(156,D.tag))}D=null}if(T=Or,ns===1||T.childExpirationTime!==1){for(Y=0,Ae=T.child;Ae!==null;)q=Ae.expirationTime,De=Ae.childExpirationTime,q>Y&&(Y=q),De>Y&&(Y=De),Ae=Ae.sibling;T.childExpirationTime=Y}if(D!==null)return D;P!==null&&(P.effectTag&2048)===0&&(P.firstEffect===null&&(P.firstEffect=Or.firstEffect),Or.lastEffect!==null&&(P.lastEffect!==null&&(P.lastEffect.nextEffect=Or.firstEffect),P.lastEffect=Or.lastEffect),1<Or.effectTag&&(P.lastEffect!==null?P.lastEffect.nextEffect=Or:P.firstEffect=Or,P.lastEffect=Or))}else{if(D=Cw(Or,ns),D!==null)return D.effectTag&=2047,D;P!==null&&(P.firstEffect=P.lastEffect=null,P.effectTag|=2048)}if(D=Or.sibling,D!==null)return D;Or=P}while(Or!==null);return Yi===vu&&(Yi=Sc),null}function bw(P){var D=P.expirationTime;return P=P.childExpirationTime,D>P?D:P}function bu(P){var D=_o();return lo(99,hF.bind(null,P,D)),null}function hF(P,D){do vp();while(vg!==null);if((yr&(rs|qs))!==En)throw Error(n(327));var T=P.finishedWork,q=P.finishedExpirationTime;if(T===null)return null;if(P.finishedWork=null,P.finishedExpirationTime=0,T===P.current)throw Error(n(177));P.callbackNode=null,P.callbackExpirationTime=0,P.callbackPriority=90,P.nextKnownPendingLevel=0;var Y=bw(T);if(P.firstPendingTime=Y,q<=P.lastSuspendedTime?P.firstSuspendedTime=P.lastSuspendedTime=P.nextKnownPendingLevel=0:q<=P.firstSuspendedTime&&(P.firstSuspendedTime=q-1),q<=P.lastPingedTime&&(P.lastPingedTime=0),q<=P.lastExpiredTime&&(P.lastExpiredTime=0),P===gi&&(Or=gi=null,ns=0),1<T.effectTag?T.lastEffect!==null?(T.lastEffect.nextEffect=T,Y=T.firstEffect):Y=T:Y=T.firstEffect,Y!==null){var Ae=yr;yr|=qs,Iw.current=null,Ie(P.containerInfo),or=Y;do try{gF()}catch(ho){if(or===null)throw Error(n(330));YA(or,ho),or=or.nextEffect}while(or!==null);or=Y;do try{for(var De=P,vt=D;or!==null;){var wt=or.effectTag;if(wt&16&&w&&Gt(or.stateNode),wt&128){var xt=or.alternate;if(xt!==null){var _r=xt.ref;_r!==null&&(typeof _r==\"function\"?_r(null):_r.current=null)}}switch(wt&1038){case 2:fr(or),or.effectTag&=-3;break;case 6:fr(or),or.effectTag&=-3,yn(or.alternate,or);break;case 1024:or.effectTag&=-1025;break;case 1028:or.effectTag&=-1025,yn(or.alternate,or);break;case 4:yn(or.alternate,or);break;case 8:var is=De,di=or,po=vt;w?Cr(is,di,po):re(is,di,po),pe(di)}or=or.nextEffect}}catch(ho){if(or===null)throw Error(n(330));YA(or,ho),or=or.nextEffect}while(or!==null);Fe(P.containerInfo),P.current=T,or=Y;do try{for(wt=q;or!==null;){var zA=or.effectTag;if(zA&36){var Yo=or.alternate;switch(xt=or,_r=wt,xt.tag){case 0:case 11:case 15:L(16,32,xt);break;case 1:var rt=xt.stateNode;if(xt.effectTag&4)if(Yo===null)rt.componentDidMount();else{var ze=xt.elementType===xt.type?Yo.memoizedProps:Ci(xt.type,Yo.memoizedProps);rt.componentDidUpdate(ze,Yo.memoizedState,rt.__reactInternalSnapshotBeforeUpdate)}var ft=xt.updateQueue;ft!==null&&Ne(xt,ft,rt,_r);break;case 3:var Wt=xt.updateQueue;if(Wt!==null){if(De=null,xt.child!==null)switch(xt.child.tag){case 5:De=ce(xt.child.stateNode);break;case 1:De=xt.child.stateNode}Ne(xt,Wt,De,_r)}break;case 5:var vr=xt.stateNode;Yo===null&&xt.effectTag&4&&Z(vr,xt.type,xt.memoizedProps,xt);break;case 6:break;case 4:break;case 12:break;case 13:if(y&&xt.memoizedState===null){var Sn=xt.alternate;if(Sn!==null){var Fr=Sn.memoizedState;if(Fr!==null){var bn=Fr.dehydrated;bn!==null&&oo(bn)}}}break;case 19:case 17:case 20:case 21:break;default:throw Error(n(163))}}if(zA&128){xt=void 0;var ai=or.ref;if(ai!==null){var tn=or.stateNode;switch(or.tag){case 5:xt=ce(tn);break;default:xt=tn}typeof ai==\"function\"?ai(xt):ai.current=xt}}or=or.nextEffect}}catch(ho){if(or===null)throw Error(n(330));YA(or,ho),or=or.nextEffect}while(or!==null);or=null,Qn(),yr=Ae}else P.current=T;if(Bp)Bp=!1,vg=P,_A=D;else for(or=Y;or!==null;)D=or.nextEffect,or.nextEffect=null,or=D;if(D=P.firstPendingTime,D===0&&(Pu=null),D===1073741823?P===Dw?Dg++:(Dg=0,Dw=P):Dg=0,typeof xw==\"function\"&&xw(T.stateNode,q),fo(P),Du)throw Du=!1,P=Mm,Mm=null,P;return(yr&Tm)!==En||qi(),null}function gF(){for(;or!==null;){var P=or.effectTag;(P&256)!==0&&Qt(or.alternate,or),(P&512)===0||Bp||(Bp=!0,dc(97,function(){return vp(),null})),or=or.nextEffect}}function vp(){if(_A!==90){var P=97<_A?97:_A;return _A=90,lo(P,dF)}}function dF(){if(vg===null)return!1;var P=vg;if(vg=null,(yr&(rs|qs))!==En)throw Error(n(331));var D=yr;for(yr|=qs,P=P.current.firstEffect;P!==null;){try{var T=P;if((T.effectTag&512)!==0)switch(T.tag){case 0:case 11:case 15:L(128,0,T),L(0,64,T)}}catch(q){if(P===null)throw Error(n(330));YA(P,q)}T=P.nextEffect,P.nextEffect=null,P=T}return yr=D,qi(),!0}function Xv(P,D,T){D=Cg(T,D),D=jv(P,D,1073741823),tt(P,D),P=Pg(P,1073741823),P!==null&&fo(P)}function YA(P,D){if(P.tag===3)Xv(P,P,D);else for(var T=P.return;T!==null;){if(T.tag===3){Xv(T,P,D);break}else if(T.tag===1){var q=T.stateNode;if(typeof T.type.getDerivedStateFromError==\"function\"||typeof q.componentDidCatch==\"function\"&&(Pu===null||!Pu.has(q))){P=Cg(D,P),P=Yv(T,P,1073741823),tt(T,P),T=Pg(T,1073741823),T!==null&&fo(T);break}}T=T.return}}function mF(P,D,T){var q=P.pingCache;q!==null&&q.delete(D),gi===P&&ns===T?Yi===Dl||Yi===ha&&Wa===1073741823&&Ni()-Bw<vw?Su(P,ns):UA=!0:$v(P,T)&&(D=P.lastPingedTime,D!==0&&D<T||(P.lastPingedTime=T,P.finishedExpirationTime===T&&(P.finishedExpirationTime=0,P.finishedWork=null),fo(P)))}function yF(P,D){var T=P.stateNode;T!==null&&T.delete(D),D=0,D===0&&(D=ga(),D=qA(D,P,null)),P=Pg(P,D),P!==null&&fo(P)}var Zv;Zv=function(P,D,T){var q=D.expirationTime;if(P!==null){var Y=D.pendingProps;if(P.memoizedProps!==Y||_i.current)Go=!0;else{if(q<T){switch(Go=!1,D.tag){case 3:Eg(D),yg();break;case 5:if(Sm(D),D.mode&4&&T!==1&&xe(D.type,Y))return D.expirationTime=D.childExpirationTime=1,null;break;case 1:ii(D.type)&&fc(D);break;case 4:ag(D,D.stateNode.containerInfo);break;case 10:Ho(D,D.memoizedProps.value);break;case 13:if(D.memoizedState!==null)return q=D.child.childExpirationTime,q!==0&&q>=T?ln(P,D,T):(On(ei,ei.current&1,D),D=si(P,D,T),D!==null?D.sibling:null);On(ei,ei.current&1,D);break;case 19:if(q=D.childExpirationTime>=T,(P.effectTag&64)!==0){if(q)return ja(P,D,T);D.effectTag|=64}if(Y=D.memoizedState,Y!==null&&(Y.rendering=null,Y.tail=null),On(ei,ei.current,D),!q)return null}return si(P,D,T)}Go=!1}}else Go=!1;switch(D.expirationTime=0,D.tag){case 2:if(q=D.type,P!==null&&(P.alternate=null,D.alternate=null,D.effectTag|=2),P=D.pendingProps,Y=Oe(D,Mn.current),ds(D,T),Y=ug(null,D,q,P,Y,T),D.effectTag|=1,typeof Y==\"object\"&&Y!==null&&typeof Y.render==\"function\"&&Y.$$typeof===void 0){if(D.tag=1,yw(),ii(q)){var Ae=!0;fc(D)}else Ae=!1;D.memoizedState=Y.state!==null&&Y.state!==void 0?Y.state:null;var De=q.getDerivedStateFromProps;typeof De==\"function\"&&er(D,q,De,P),Y.updater=$r,D.stateNode=Y,Y._reactInternalFiber=D,qo(D,q,P,T),D=Ep(null,D,q,!0,Ae,T)}else D.tag=0,ws(null,D,Y,T),D=D.child;return D;case 16:if(Y=D.elementType,P!==null&&(P.alternate=null,D.alternate=null,D.effectTag|=2),P=D.pendingProps,me(Y),Y._status!==1)throw Y._result;switch(Y=Y._result,D.type=Y,Ae=D.tag=wF(Y),P=Ci(Y,P),Ae){case 0:D=NA(null,D,Y,P,T);break;case 1:D=yp(null,D,Y,P,T);break;case 11:D=Ii(null,D,Y,P,T);break;case 14:D=Qm(null,D,Y,Ci(Y.type,P),q,T);break;default:throw Error(n(306,Y,\"\"))}return D;case 0:return q=D.type,Y=D.pendingProps,Y=D.elementType===q?Y:Ci(q,Y),NA(P,D,q,Y,T);case 1:return q=D.type,Y=D.pendingProps,Y=D.elementType===q?Y:Ci(q,Y),yp(P,D,q,Y,T);case 3:if(Eg(D),q=D.updateQueue,q===null)throw Error(n(282));if(Y=D.memoizedState,Y=Y!==null?Y.element:null,ye(D,q,D.pendingProps,null,T),q=D.memoizedState.element,q===Y)yg(),D=si(P,D,T);else{if((Y=D.stateNode.hydrate)&&(y?(vc=uu(D.stateNode.containerInfo),Aa=D,Y=Bl=!0):Y=!1),Y)for(T=og(D,null,q,T),D.child=T;T;)T.effectTag=T.effectTag&-3|1024,T=T.sibling;else ws(P,D,q,T),yg();D=D.child}return D;case 5:return Sm(D),P===null&&LA(D),q=D.type,Y=D.pendingProps,Ae=P!==null?P.memoizedProps:null,De=Y.children,ke(q,Y)?De=null:Ae!==null&&ke(q,Ae)&&(D.effectTag|=16),jo(P,D),D.mode&4&&T!==1&&xe(q,Y)?(D.expirationTime=D.childExpirationTime=1,D=null):(ws(P,D,De,T),D=D.child),D;case 6:return P===null&&LA(D),null;case 13:return ln(P,D,T);case 4:return ag(D,D.stateNode.containerInfo),q=D.pendingProps,P===null?D.child=du(D,null,q,T):ws(P,D,q,T),D.child;case 11:return q=D.type,Y=D.pendingProps,Y=D.elementType===q?Y:Ci(q,Y),Ii(P,D,q,Y,T);case 7:return ws(P,D,D.pendingProps,T),D.child;case 8:return ws(P,D,D.pendingProps.children,T),D.child;case 12:return ws(P,D,D.pendingProps.children,T),D.child;case 10:e:{if(q=D.type._context,Y=D.pendingProps,De=D.memoizedProps,Ae=Y.value,Ho(D,Ae),De!==null){var vt=De.value;if(Ae=hs(vt,Ae)?0:(typeof q._calculateChangedBits==\"function\"?q._calculateChangedBits(vt,Ae):1073741823)|0,Ae===0){if(De.children===Y.children&&!_i.current){D=si(P,D,T);break e}}else for(vt=D.child,vt!==null&&(vt.return=D);vt!==null;){var wt=vt.dependencies;if(wt!==null){De=vt.child;for(var xt=wt.firstContext;xt!==null;){if(xt.context===q&&(xt.observedBits&Ae)!==0){vt.tag===1&&(xt=ys(T,null),xt.tag=2,tt(vt,xt)),vt.expirationTime<T&&(vt.expirationTime=T),xt=vt.alternate,xt!==null&&xt.expirationTime<T&&(xt.expirationTime=T),gs(vt.return,T),wt.expirationTime<T&&(wt.expirationTime=T);break}xt=xt.next}}else De=vt.tag===10&&vt.type===D.type?null:vt.child;if(De!==null)De.return=vt;else for(De=vt;De!==null;){if(De===D){De=null;break}if(vt=De.sibling,vt!==null){vt.return=De.return,De=vt;break}De=De.return}vt=De}}ws(P,D,Y.children,T),D=D.child}return D;case 9:return Y=D.type,Ae=D.pendingProps,q=Ae.children,ds(D,T),Y=ms(Y,Ae.unstable_observedBits),q=q(Y),D.effectTag|=1,ws(P,D,q,T),D.child;case 14:return Y=D.type,Ae=Ci(Y,D.pendingProps),Ae=Ci(Y.type,Ae),Qm(P,D,Y,Ae,q,T);case 15:return Fm(P,D,D.type,D.pendingProps,q,T);case 17:return q=D.type,Y=D.pendingProps,Y=D.elementType===q?Y:Ci(q,Y),P!==null&&(P.alternate=null,D.alternate=null,D.effectTag|=2),D.tag=1,ii(q)?(P=!0,fc(D)):P=!1,ds(D,T),es(D,q,Y,T),qo(D,q,Y,T),Ep(null,D,q,!0,P,T);case 19:return ja(P,D,T)}throw Error(n(156,D.tag))};var xw=null,kw=null;function EF(P){if(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>\"u\")return!1;var D=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(D.isDisabled||!D.supportsFiber)return!0;try{var T=D.inject(P);xw=function(q){try{D.onCommitFiberRoot(T,q,void 0,(q.current.effectTag&64)===64)}catch{}},kw=function(q){try{D.onCommitFiberUnmount(T,q)}catch{}}}catch{}return!0}function CF(P,D,T,q){this.tag=P,this.key=T,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=D,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=q,this.effectTag=0,this.lastEffect=this.firstEffect=this.nextEffect=null,this.childExpirationTime=this.expirationTime=0,this.alternate=null}function Pl(P,D,T,q){return new CF(P,D,T,q)}function Qw(P){return P=P.prototype,!(!P||!P.isReactComponent)}function wF(P){if(typeof P==\"function\")return Qw(P)?1:0;if(P!=null){if(P=P.$$typeof,P===N)return 11;if(P===te)return 14}return 2}function WA(P,D){var T=P.alternate;return T===null?(T=Pl(P.tag,D,P.key,P.mode),T.elementType=P.elementType,T.type=P.type,T.stateNode=P.stateNode,T.alternate=P,P.alternate=T):(T.pendingProps=D,T.effectTag=0,T.nextEffect=null,T.firstEffect=null,T.lastEffect=null),T.childExpirationTime=P.childExpirationTime,T.expirationTime=P.expirationTime,T.child=P.child,T.memoizedProps=P.memoizedProps,T.memoizedState=P.memoizedState,T.updateQueue=P.updateQueue,D=P.dependencies,T.dependencies=D===null?null:{expirationTime:D.expirationTime,firstContext:D.firstContext,responders:D.responders},T.sibling=P.sibling,T.index=P.index,T.ref=P.ref,T}function qm(P,D,T,q,Y,Ae){var De=2;if(q=P,typeof P==\"function\")Qw(P)&&(De=1);else if(typeof P==\"string\")De=5;else e:switch(P){case E:return xu(T.children,Y,Ae,D);case R:De=8,Y|=7;break;case I:De=8,Y|=1;break;case v:return P=Pl(12,T,D,Y|8),P.elementType=v,P.type=v,P.expirationTime=Ae,P;case U:return P=Pl(13,T,D,Y),P.type=U,P.elementType=U,P.expirationTime=Ae,P;case V:return P=Pl(19,T,D,Y),P.elementType=V,P.expirationTime=Ae,P;default:if(typeof P==\"object\"&&P!==null)switch(P.$$typeof){case x:De=10;break e;case C:De=9;break e;case N:De=11;break e;case te:De=14;break e;case ae:De=16,q=null;break e}throw Error(n(130,P==null?P:typeof P,\"\"))}return D=Pl(De,T,D,Y),D.elementType=P,D.type=q,D.expirationTime=Ae,D}function xu(P,D,T,q){return P=Pl(7,P,q,D),P.expirationTime=T,P}function Fw(P,D,T){return P=Pl(6,P,null,D),P.expirationTime=T,P}function Rw(P,D,T){return D=Pl(4,P.children!==null?P.children:[],P.key,D),D.expirationTime=T,D.stateNode={containerInfo:P.containerInfo,pendingChildren:null,implementation:P.implementation},D}function IF(P,D,T){this.tag=D,this.current=null,this.containerInfo=P,this.pingCache=this.pendingChildren=null,this.finishedExpirationTime=0,this.finishedWork=null,this.timeoutHandle=qe,this.pendingContext=this.context=null,this.hydrate=T,this.callbackNode=null,this.callbackPriority=90,this.lastExpiredTime=this.lastPingedTime=this.nextKnownPendingLevel=this.lastSuspendedTime=this.firstSuspendedTime=this.firstPendingTime=0}function $v(P,D){var T=P.firstSuspendedTime;return P=P.lastSuspendedTime,T!==0&&T>=D&&P<=D}function KA(P,D){var T=P.firstSuspendedTime,q=P.lastSuspendedTime;T<D&&(P.firstSuspendedTime=D),(q>D||T===0)&&(P.lastSuspendedTime=D),D<=P.lastPingedTime&&(P.lastPingedTime=0),D<=P.lastExpiredTime&&(P.lastExpiredTime=0)}function eD(P,D){D>P.firstPendingTime&&(P.firstPendingTime=D);var T=P.firstSuspendedTime;T!==0&&(D>=T?P.firstSuspendedTime=P.lastSuspendedTime=P.nextKnownPendingLevel=0:D>=P.lastSuspendedTime&&(P.lastSuspendedTime=D+1),D>P.nextKnownPendingLevel&&(P.nextKnownPendingLevel=D))}function Gm(P,D){var T=P.lastExpiredTime;(T===0||T>D)&&(P.lastExpiredTime=D)}function tD(P){var D=P._reactInternalFiber;if(D===void 0)throw typeof P.render==\"function\"?Error(n(188)):Error(n(268,Object.keys(P)));return P=Ee(D),P===null?null:P.stateNode}function rD(P,D){P=P.memoizedState,P!==null&&P.dehydrated!==null&&P.retryTime<D&&(P.retryTime=D)}function jm(P,D){rD(P,D),(P=P.alternate)&&rD(P,D)}var nD={createContainer:function(P,D,T){return P=new IF(P,D,T),D=Pl(3,null,null,D===2?7:D===1?3:0),P.current=D,D.stateNode=P},updateContainer:function(P,D,T,q){var Y=D.current,Ae=ga(),De=ht.suspense;Ae=qA(Ae,Y,De);e:if(T){T=T._reactInternalFiber;t:{if(Be(T)!==T||T.tag!==1)throw Error(n(170));var vt=T;do{switch(vt.tag){case 3:vt=vt.stateNode.context;break t;case 1:if(ii(vt.type)){vt=vt.stateNode.__reactInternalMemoizedMergedChildContext;break t}}vt=vt.return}while(vt!==null);throw Error(n(171))}if(T.tag===1){var wt=T.type;if(ii(wt)){T=Au(T,wt,vt);break e}}T=vt}else T=Li;return D.context===null?D.context=T:D.pendingContext=T,D=ys(Ae,De),D.payload={element:P},q=q===void 0?null:q,q!==null&&(D.callback=q),tt(Y,D),bc(Y,Ae),Ae},batchedEventUpdates:function(P,D){var T=yr;yr|=2;try{return P(D)}finally{yr=T,yr===En&&qi()}},batchedUpdates:function(P,D){var T=yr;yr|=1;try{return P(D)}finally{yr=T,yr===En&&qi()}},unbatchedUpdates:function(P,D){var T=yr;yr&=-2,yr|=Tm;try{return P(D)}finally{yr=T,yr===En&&qi()}},deferredUpdates:function(P){return lo(97,P)},syncUpdates:function(P,D,T,q){return lo(99,P.bind(null,D,T,q))},discreteUpdates:function(P,D,T,q){var Y=yr;yr|=4;try{return lo(98,P.bind(null,D,T,q))}finally{yr=Y,yr===En&&qi()}},flushDiscreteUpdates:function(){(yr&(1|rs|qs))===En&&(AF(),vp())},flushControlled:function(P){var D=yr;yr|=1;try{lo(99,P)}finally{yr=D,yr===En&&qi()}},flushSync:zv,flushPassiveEffects:vp,IsThisRendererActing:{current:!1},getPublicRootInstance:function(P){if(P=P.current,!P.child)return null;switch(P.child.tag){case 5:return ce(P.child.stateNode);default:return P.child.stateNode}},attemptSynchronousHydration:function(P){switch(P.tag){case 3:var D=P.stateNode;D.hydrate&&Kv(D,D.firstPendingTime);break;case 13:zv(function(){return bc(P,1073741823)}),D=Ha(ga(),150,100),jm(P,D)}},attemptUserBlockingHydration:function(P){if(P.tag===13){var D=Ha(ga(),150,100);bc(P,D),jm(P,D)}},attemptContinuousHydration:function(P){if(P.tag===13){ga();var D=xA++;bc(P,D),jm(P,D)}},attemptHydrationAtCurrentPriority:function(P){if(P.tag===13){var D=ga();D=qA(D,P,null),bc(P,D),jm(P,D)}},findHostInstance:tD,findHostInstanceWithWarning:function(P){return tD(P)},findHostInstanceWithNoPortals:function(P){return P=Pe(P),P===null?null:P.tag===20?P.stateNode.instance:P.stateNode},shouldSuspend:function(){return!1},injectIntoDevTools:function(P){var D=P.findFiberByHostInstance;return EF(r({},P,{overrideHookState:null,overrideProps:null,setSuspenseHandler:null,scheduleUpdate:null,currentDispatcherRef:u.ReactCurrentDispatcher,findHostInstanceByFiber:function(T){return T=Ee(T),T===null?null:T.stateNode},findFiberByHostInstance:function(T){return D?D(T):null},findHostInstancesForRefresh:null,scheduleRefresh:null,scheduleRoot:null,setRefreshHandler:null,getCurrentFiber:null}))}};lB.exports=nD.default||nD;var BF=lB.exports;return lB.exports=t,BF}});var bEe=_((yKt,SEe)=>{\"use strict\";SEe.exports=PEe()});var kEe=_((EKt,xEe)=>{\"use strict\";var qyt={ALIGN_COUNT:8,ALIGN_AUTO:0,ALIGN_FLEX_START:1,ALIGN_CENTER:2,ALIGN_FLEX_END:3,ALIGN_STRETCH:4,ALIGN_BASELINE:5,ALIGN_SPACE_BETWEEN:6,ALIGN_SPACE_AROUND:7,DIMENSION_COUNT:2,DIMENSION_WIDTH:0,DIMENSION_HEIGHT:1,DIRECTION_COUNT:3,DIRECTION_INHERIT:0,DIRECTION_LTR:1,DIRECTION_RTL:2,DISPLAY_COUNT:2,DISPLAY_FLEX:0,DISPLAY_NONE:1,EDGE_COUNT:9,EDGE_LEFT:0,EDGE_TOP:1,EDGE_RIGHT:2,EDGE_BOTTOM:3,EDGE_START:4,EDGE_END:5,EDGE_HORIZONTAL:6,EDGE_VERTICAL:7,EDGE_ALL:8,EXPERIMENTAL_FEATURE_COUNT:1,EXPERIMENTAL_FEATURE_WEB_FLEX_BASIS:0,FLEX_DIRECTION_COUNT:4,FLEX_DIRECTION_COLUMN:0,FLEX_DIRECTION_COLUMN_REVERSE:1,FLEX_DIRECTION_ROW:2,FLEX_DIRECTION_ROW_REVERSE:3,JUSTIFY_COUNT:6,JUSTIFY_FLEX_START:0,JUSTIFY_CENTER:1,JUSTIFY_FLEX_END:2,JUSTIFY_SPACE_BETWEEN:3,JUSTIFY_SPACE_AROUND:4,JUSTIFY_SPACE_EVENLY:5,LOG_LEVEL_COUNT:6,LOG_LEVEL_ERROR:0,LOG_LEVEL_WARN:1,LOG_LEVEL_INFO:2,LOG_LEVEL_DEBUG:3,LOG_LEVEL_VERBOSE:4,LOG_LEVEL_FATAL:5,MEASURE_MODE_COUNT:3,MEASURE_MODE_UNDEFINED:0,MEASURE_MODE_EXACTLY:1,MEASURE_MODE_AT_MOST:2,NODE_TYPE_COUNT:2,NODE_TYPE_DEFAULT:0,NODE_TYPE_TEXT:1,OVERFLOW_COUNT:3,OVERFLOW_VISIBLE:0,OVERFLOW_HIDDEN:1,OVERFLOW_SCROLL:2,POSITION_TYPE_COUNT:2,POSITION_TYPE_RELATIVE:0,POSITION_TYPE_ABSOLUTE:1,PRINT_OPTIONS_COUNT:3,PRINT_OPTIONS_LAYOUT:1,PRINT_OPTIONS_STYLE:2,PRINT_OPTIONS_CHILDREN:4,UNIT_COUNT:4,UNIT_UNDEFINED:0,UNIT_POINT:1,UNIT_PERCENT:2,UNIT_AUTO:3,WRAP_COUNT:3,WRAP_NO_WRAP:0,WRAP_WRAP:1,WRAP_WRAP_REVERSE:2};xEe.exports=qyt});var TEe=_((CKt,REe)=>{\"use strict\";var Gyt=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var r=arguments[e];for(var o in r)Object.prototype.hasOwnProperty.call(r,o)&&(t[o]=r[o])}return t},Wk=function(){function t(e,r){for(var o=0;o<r.length;o++){var a=r[o];a.enumerable=a.enumerable||!1,a.configurable=!0,\"value\"in a&&(a.writable=!0),Object.defineProperty(e,a.key,a)}}return function(e,r,o){return r&&t(e.prototype,r),o&&t(e,o),e}}();function S6(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function b6(t,e){if(!(t instanceof e))throw new TypeError(\"Cannot call a class as a function\")}var ru=kEe(),jyt=function(){function t(e,r,o,a,n,u){b6(this,t),this.left=e,this.right=r,this.top=o,this.bottom=a,this.width=n,this.height=u}return Wk(t,[{key:\"fromJS\",value:function(r){r(this.left,this.right,this.top,this.bottom,this.width,this.height)}},{key:\"toString\",value:function(){return\"<Layout#\"+this.left+\":\"+this.right+\";\"+this.top+\":\"+this.bottom+\";\"+this.width+\":\"+this.height+\">\"}}]),t}(),QEe=function(){Wk(t,null,[{key:\"fromJS\",value:function(r){var o=r.width,a=r.height;return new t(o,a)}}]);function t(e,r){b6(this,t),this.width=e,this.height=r}return Wk(t,[{key:\"fromJS\",value:function(r){r(this.width,this.height)}},{key:\"toString\",value:function(){return\"<Size#\"+this.width+\"x\"+this.height+\">\"}}]),t}(),FEe=function(){function t(e,r){b6(this,t),this.unit=e,this.value=r}return Wk(t,[{key:\"fromJS\",value:function(r){r(this.unit,this.value)}},{key:\"toString\",value:function(){switch(this.unit){case ru.UNIT_POINT:return String(this.value);case ru.UNIT_PERCENT:return this.value+\"%\";case ru.UNIT_AUTO:return\"auto\";default:return this.value+\"?\"}}},{key:\"valueOf\",value:function(){return this.value}}]),t}();REe.exports=function(t,e){function r(u,A,p){var h=u[A];u[A]=function(){for(var E=arguments.length,I=Array(E),v=0;v<E;v++)I[v]=arguments[v];return p.call.apply(p,[this,h].concat(I))}}for(var o=[\"setPosition\",\"setMargin\",\"setFlexBasis\",\"setWidth\",\"setHeight\",\"setMinWidth\",\"setMinHeight\",\"setMaxWidth\",\"setMaxHeight\",\"setPadding\"],a=function(){var A,p=o[n],h=(A={},S6(A,ru.UNIT_POINT,e.Node.prototype[p]),S6(A,ru.UNIT_PERCENT,e.Node.prototype[p+\"Percent\"]),S6(A,ru.UNIT_AUTO,e.Node.prototype[p+\"Auto\"]),A);r(e.Node.prototype,p,function(E){for(var I=arguments.length,v=Array(I>1?I-1:0),x=1;x<I;x++)v[x-1]=arguments[x];var C=v.pop(),R=void 0,N=void 0;if(C===\"auto\")R=ru.UNIT_AUTO,N=void 0;else if(C instanceof FEe)R=C.unit,N=C.valueOf();else if(R=typeof C==\"string\"&&C.endsWith(\"%\")?ru.UNIT_PERCENT:ru.UNIT_POINT,N=parseFloat(C),!Number.isNaN(C)&&Number.isNaN(N))throw new Error(\"Invalid value \"+C+\" for \"+p);if(!h[R])throw new Error('Failed to execute \"'+p+`\": Unsupported unit '`+C+\"'\");if(N!==void 0){var U;return(U=h[R]).call.apply(U,[this].concat(v,[N]))}else{var V;return(V=h[R]).call.apply(V,[this].concat(v))}})},n=0;n<o.length;n++)a();return r(e.Config.prototype,\"free\",function(){e.Config.destroy(this)}),r(e.Node,\"create\",function(u,A){return A?e.Node.createWithConfig(A):e.Node.createDefault()}),r(e.Node.prototype,\"free\",function(){e.Node.destroy(this)}),r(e.Node.prototype,\"freeRecursive\",function(){for(var u=0,A=this.getChildCount();u<A;++u)this.getChild(0).freeRecursive();this.free()}),r(e.Node.prototype,\"setMeasureFunc\",function(u,A){return A?u.call(this,function(){return QEe.fromJS(A.apply(void 0,arguments))}):this.unsetMeasureFunc()}),r(e.Node.prototype,\"calculateLayout\",function(u){var A=arguments.length>1&&arguments[1]!==void 0?arguments[1]:NaN,p=arguments.length>2&&arguments[2]!==void 0?arguments[2]:NaN,h=arguments.length>3&&arguments[3]!==void 0?arguments[3]:ru.DIRECTION_LTR;return u.call(this,A,p,h)}),Gyt({Config:e.Config,Node:e.Node,Layout:t(\"Layout\",jyt),Size:t(\"Size\",QEe),Value:t(\"Value\",FEe),getInstanceCount:function(){return e.getInstanceCount.apply(e,arguments)}},ru)}});var LEe=_((exports,module)=>{(function(t,e){typeof define==\"function\"&&define.amd?define([],function(){return e}):typeof module==\"object\"&&module.exports?module.exports=e:(t.nbind=t.nbind||{}).init=e})(exports,function(Module,cb){typeof Module==\"function\"&&(cb=Module,Module={}),Module.onRuntimeInitialized=function(t,e){return function(){t&&t.apply(this,arguments);try{Module.ccall(\"nbind_init\")}catch(r){e(r);return}e(null,{bind:Module._nbind_value,reflect:Module.NBind.reflect,queryType:Module.NBind.queryType,toggleLightGC:Module.toggleLightGC,lib:Module})}}(Module.onRuntimeInitialized,cb);var Module;Module||(Module=(typeof Module<\"u\"?Module:null)||{});var moduleOverrides={};for(var key in Module)Module.hasOwnProperty(key)&&(moduleOverrides[key]=Module[key]);var ENVIRONMENT_IS_WEB=!1,ENVIRONMENT_IS_WORKER=!1,ENVIRONMENT_IS_NODE=!1,ENVIRONMENT_IS_SHELL=!1;if(Module.ENVIRONMENT)if(Module.ENVIRONMENT===\"WEB\")ENVIRONMENT_IS_WEB=!0;else if(Module.ENVIRONMENT===\"WORKER\")ENVIRONMENT_IS_WORKER=!0;else if(Module.ENVIRONMENT===\"NODE\")ENVIRONMENT_IS_NODE=!0;else if(Module.ENVIRONMENT===\"SHELL\")ENVIRONMENT_IS_SHELL=!0;else throw new Error(\"The provided Module['ENVIRONMENT'] value is not valid. It must be one of: WEB|WORKER|NODE|SHELL.\");else ENVIRONMENT_IS_WEB=typeof window==\"object\",ENVIRONMENT_IS_WORKER=typeof importScripts==\"function\",ENVIRONMENT_IS_NODE=typeof process==\"object\"&&typeof ve==\"function\"&&!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_WORKER,ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;if(ENVIRONMENT_IS_NODE){Module.print||(Module.print=console.log),Module.printErr||(Module.printErr=console.warn);var nodeFS,nodePath;Module.read=function(e,r){nodeFS||(nodeFS={}(\"\")),nodePath||(nodePath={}(\"\")),e=nodePath.normalize(e);var o=nodeFS.readFileSync(e);return r?o:o.toString()},Module.readBinary=function(e){var r=Module.read(e,!0);return r.buffer||(r=new Uint8Array(r)),assert(r.buffer),r},Module.load=function(e){globalEval(read(e))},Module.thisProgram||(process.argv.length>1?Module.thisProgram=process.argv[1].replace(/\\\\/g,\"/\"):Module.thisProgram=\"unknown-program\"),Module.arguments=process.argv.slice(2),typeof module<\"u\"&&(module.exports=Module),Module.inspect=function(){return\"[Emscripten Module object]\"}}else if(ENVIRONMENT_IS_SHELL)Module.print||(Module.print=print),typeof printErr<\"u\"&&(Module.printErr=printErr),typeof read<\"u\"?Module.read=read:Module.read=function(){throw\"no read() available\"},Module.readBinary=function(e){if(typeof readbuffer==\"function\")return new Uint8Array(readbuffer(e));var r=read(e,\"binary\");return assert(typeof r==\"object\"),r},typeof scriptArgs<\"u\"?Module.arguments=scriptArgs:typeof arguments<\"u\"&&(Module.arguments=arguments),typeof quit==\"function\"&&(Module.quit=function(t,e){quit(t)});else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(Module.read=function(e){var r=new XMLHttpRequest;return r.open(\"GET\",e,!1),r.send(null),r.responseText},ENVIRONMENT_IS_WORKER&&(Module.readBinary=function(e){var r=new XMLHttpRequest;return r.open(\"GET\",e,!1),r.responseType=\"arraybuffer\",r.send(null),new Uint8Array(r.response)}),Module.readAsync=function(e,r,o){var a=new XMLHttpRequest;a.open(\"GET\",e,!0),a.responseType=\"arraybuffer\",a.onload=function(){a.status==200||a.status==0&&a.response?r(a.response):o()},a.onerror=o,a.send(null)},typeof arguments<\"u\"&&(Module.arguments=arguments),typeof console<\"u\")Module.print||(Module.print=function(e){console.log(e)}),Module.printErr||(Module.printErr=function(e){console.warn(e)});else{var TRY_USE_DUMP=!1;Module.print||(Module.print=TRY_USE_DUMP&&typeof dump<\"u\"?function(t){dump(t)}:function(t){})}ENVIRONMENT_IS_WORKER&&(Module.load=importScripts),typeof Module.setWindowTitle>\"u\"&&(Module.setWindowTitle=function(t){document.title=t})}else throw\"Unknown runtime environment. Where are we?\";function globalEval(t){eval.call(null,t)}!Module.load&&Module.read&&(Module.load=function(e){globalEval(Module.read(e))}),Module.print||(Module.print=function(){}),Module.printErr||(Module.printErr=Module.print),Module.arguments||(Module.arguments=[]),Module.thisProgram||(Module.thisProgram=\"./this.program\"),Module.quit||(Module.quit=function(t,e){throw e}),Module.print=Module.print,Module.printErr=Module.printErr,Module.preRun=[],Module.postRun=[];for(var key in moduleOverrides)moduleOverrides.hasOwnProperty(key)&&(Module[key]=moduleOverrides[key]);moduleOverrides=void 0;var Runtime={setTempRet0:function(t){return tempRet0=t,t},getTempRet0:function(){return tempRet0},stackSave:function(){return STACKTOP},stackRestore:function(t){STACKTOP=t},getNativeTypeSize:function(t){switch(t){case\"i1\":case\"i8\":return 1;case\"i16\":return 2;case\"i32\":return 4;case\"i64\":return 8;case\"float\":return 4;case\"double\":return 8;default:{if(t[t.length-1]===\"*\")return Runtime.QUANTUM_SIZE;if(t[0]===\"i\"){var e=parseInt(t.substr(1));return assert(e%8===0),e/8}else return 0}}},getNativeFieldSize:function(t){return Math.max(Runtime.getNativeTypeSize(t),Runtime.QUANTUM_SIZE)},STACK_ALIGN:16,prepVararg:function(t,e){return e===\"double\"||e===\"i64\"?t&7&&(assert((t&7)===4),t+=4):assert((t&3)===0),t},getAlignSize:function(t,e,r){return!r&&(t==\"i64\"||t==\"double\")?8:t?Math.min(e||(t?Runtime.getNativeFieldSize(t):0),Runtime.QUANTUM_SIZE):Math.min(e,8)},dynCall:function(t,e,r){return r&&r.length?Module[\"dynCall_\"+t].apply(null,[e].concat(r)):Module[\"dynCall_\"+t].call(null,e)},functionPointers:[],addFunction:function(t){for(var e=0;e<Runtime.functionPointers.length;e++)if(!Runtime.functionPointers[e])return Runtime.functionPointers[e]=t,2*(1+e);throw\"Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.\"},removeFunction:function(t){Runtime.functionPointers[(t-2)/2]=null},warnOnce:function(t){Runtime.warnOnce.shown||(Runtime.warnOnce.shown={}),Runtime.warnOnce.shown[t]||(Runtime.warnOnce.shown[t]=1,Module.printErr(t))},funcWrappers:{},getFuncWrapper:function(t,e){if(!!t){assert(e),Runtime.funcWrappers[e]||(Runtime.funcWrappers[e]={});var r=Runtime.funcWrappers[e];return r[t]||(e.length===1?r[t]=function(){return Runtime.dynCall(e,t)}:e.length===2?r[t]=function(a){return Runtime.dynCall(e,t,[a])}:r[t]=function(){return Runtime.dynCall(e,t,Array.prototype.slice.call(arguments))}),r[t]}},getCompilerSetting:function(t){throw\"You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work\"},stackAlloc:function(t){var e=STACKTOP;return STACKTOP=STACKTOP+t|0,STACKTOP=STACKTOP+15&-16,e},staticAlloc:function(t){var e=STATICTOP;return STATICTOP=STATICTOP+t|0,STATICTOP=STATICTOP+15&-16,e},dynamicAlloc:function(t){var e=HEAP32[DYNAMICTOP_PTR>>2],r=(e+t+15|0)&-16;if(HEAP32[DYNAMICTOP_PTR>>2]=r,r>=TOTAL_MEMORY){var o=enlargeMemory();if(!o)return HEAP32[DYNAMICTOP_PTR>>2]=e,0}return e},alignMemory:function(t,e){var r=t=Math.ceil(t/(e||16))*(e||16);return r},makeBigInt:function(t,e,r){var o=r?+(t>>>0)+ +(e>>>0)*4294967296:+(t>>>0)+ +(e|0)*4294967296;return o},GLOBAL_BASE:8,QUANTUM_SIZE:4,__dummy__:0};Module.Runtime=Runtime;var ABORT=0,EXITSTATUS=0;function assert(t,e){t||abort(\"Assertion failed: \"+e)}function getCFunc(ident){var func=Module[\"_\"+ident];if(!func)try{func=eval(\"_\"+ident)}catch(t){}return assert(func,\"Cannot call unknown function \"+ident+\" (perhaps LLVM optimizations or closure removed it?)\"),func}var cwrap,ccall;(function(){var JSfuncs={stackSave:function(){Runtime.stackSave()},stackRestore:function(){Runtime.stackRestore()},arrayToC:function(t){var e=Runtime.stackAlloc(t.length);return writeArrayToMemory(t,e),e},stringToC:function(t){var e=0;if(t!=null&&t!==0){var r=(t.length<<2)+1;e=Runtime.stackAlloc(r),stringToUTF8(t,e,r)}return e}},toC={string:JSfuncs.stringToC,array:JSfuncs.arrayToC};ccall=function(e,r,o,a,n){var u=getCFunc(e),A=[],p=0;if(a)for(var h=0;h<a.length;h++){var E=toC[o[h]];E?(p===0&&(p=Runtime.stackSave()),A[h]=E(a[h])):A[h]=a[h]}var I=u.apply(null,A);if(r===\"string\"&&(I=Pointer_stringify(I)),p!==0){if(n&&n.async){EmterpreterAsync.asyncFinalizers.push(function(){Runtime.stackRestore(p)});return}Runtime.stackRestore(p)}return I};var sourceRegex=/^function\\s*[a-zA-Z$_0-9]*\\s*\\(([^)]*)\\)\\s*{\\s*([^*]*?)[\\s;]*(?:return\\s*(.*?)[;\\s]*)?}$/;function parseJSFunc(t){var e=t.toString().match(sourceRegex).slice(1);return{arguments:e[0],body:e[1],returnValue:e[2]}}var JSsource=null;function ensureJSsource(){if(!JSsource){JSsource={};for(var t in JSfuncs)JSfuncs.hasOwnProperty(t)&&(JSsource[t]=parseJSFunc(JSfuncs[t]))}}cwrap=function cwrap(ident,returnType,argTypes){argTypes=argTypes||[];var cfunc=getCFunc(ident),numericArgs=argTypes.every(function(t){return t===\"number\"}),numericRet=returnType!==\"string\";if(numericRet&&numericArgs)return cfunc;var argNames=argTypes.map(function(t,e){return\"$\"+e}),funcstr=\"(function(\"+argNames.join(\",\")+\") {\",nargs=argTypes.length;if(!numericArgs){ensureJSsource(),funcstr+=\"var stack = \"+JSsource.stackSave.body+\";\";for(var i=0;i<nargs;i++){var arg=argNames[i],type=argTypes[i];if(type!==\"number\"){var convertCode=JSsource[type+\"ToC\"];funcstr+=\"var \"+convertCode.arguments+\" = \"+arg+\";\",funcstr+=convertCode.body+\";\",funcstr+=arg+\"=(\"+convertCode.returnValue+\");\"}}}var cfuncname=parseJSFunc(function(){return cfunc}).returnValue;if(funcstr+=\"var ret = \"+cfuncname+\"(\"+argNames.join(\",\")+\");\",!numericRet){var strgfy=parseJSFunc(function(){return Pointer_stringify}).returnValue;funcstr+=\"ret = \"+strgfy+\"(ret);\"}return numericArgs||(ensureJSsource(),funcstr+=JSsource.stackRestore.body.replace(\"()\",\"(stack)\")+\";\"),funcstr+=\"return ret})\",eval(funcstr)}})(),Module.ccall=ccall,Module.cwrap=cwrap;function setValue(t,e,r,o){switch(r=r||\"i8\",r.charAt(r.length-1)===\"*\"&&(r=\"i32\"),r){case\"i1\":HEAP8[t>>0]=e;break;case\"i8\":HEAP8[t>>0]=e;break;case\"i16\":HEAP16[t>>1]=e;break;case\"i32\":HEAP32[t>>2]=e;break;case\"i64\":tempI64=[e>>>0,(tempDouble=e,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[t>>2]=tempI64[0],HEAP32[t+4>>2]=tempI64[1];break;case\"float\":HEAPF32[t>>2]=e;break;case\"double\":HEAPF64[t>>3]=e;break;default:abort(\"invalid type for setValue: \"+r)}}Module.setValue=setValue;function getValue(t,e,r){switch(e=e||\"i8\",e.charAt(e.length-1)===\"*\"&&(e=\"i32\"),e){case\"i1\":return HEAP8[t>>0];case\"i8\":return HEAP8[t>>0];case\"i16\":return HEAP16[t>>1];case\"i32\":return HEAP32[t>>2];case\"i64\":return HEAP32[t>>2];case\"float\":return HEAPF32[t>>2];case\"double\":return HEAPF64[t>>3];default:abort(\"invalid type for setValue: \"+e)}return null}Module.getValue=getValue;var ALLOC_NORMAL=0,ALLOC_STACK=1,ALLOC_STATIC=2,ALLOC_DYNAMIC=3,ALLOC_NONE=4;Module.ALLOC_NORMAL=ALLOC_NORMAL,Module.ALLOC_STACK=ALLOC_STACK,Module.ALLOC_STATIC=ALLOC_STATIC,Module.ALLOC_DYNAMIC=ALLOC_DYNAMIC,Module.ALLOC_NONE=ALLOC_NONE;function allocate(t,e,r,o){var a,n;typeof t==\"number\"?(a=!0,n=t):(a=!1,n=t.length);var u=typeof e==\"string\"?e:null,A;if(r==ALLOC_NONE?A=o:A=[typeof _malloc==\"function\"?_malloc:Runtime.staticAlloc,Runtime.stackAlloc,Runtime.staticAlloc,Runtime.dynamicAlloc][r===void 0?ALLOC_STATIC:r](Math.max(n,u?1:e.length)),a){var o=A,p;for(assert((A&3)==0),p=A+(n&-4);o<p;o+=4)HEAP32[o>>2]=0;for(p=A+n;o<p;)HEAP8[o++>>0]=0;return A}if(u===\"i8\")return t.subarray||t.slice?HEAPU8.set(t,A):HEAPU8.set(new Uint8Array(t),A),A;for(var h=0,E,I,v;h<n;){var x=t[h];if(typeof x==\"function\"&&(x=Runtime.getFunctionIndex(x)),E=u||e[h],E===0){h++;continue}E==\"i64\"&&(E=\"i32\"),setValue(A+h,x,E),v!==E&&(I=Runtime.getNativeTypeSize(E),v=E),h+=I}return A}Module.allocate=allocate;function getMemory(t){return staticSealed?runtimeInitialized?_malloc(t):Runtime.dynamicAlloc(t):Runtime.staticAlloc(t)}Module.getMemory=getMemory;function Pointer_stringify(t,e){if(e===0||!t)return\"\";for(var r=0,o,a=0;o=HEAPU8[t+a>>0],r|=o,!(o==0&&!e||(a++,e&&a==e)););e||(e=a);var n=\"\";if(r<128){for(var u=1024,A;e>0;)A=String.fromCharCode.apply(String,HEAPU8.subarray(t,t+Math.min(e,u))),n=n?n+A:A,t+=u,e-=u;return n}return Module.UTF8ToString(t)}Module.Pointer_stringify=Pointer_stringify;function AsciiToString(t){for(var e=\"\";;){var r=HEAP8[t++>>0];if(!r)return e;e+=String.fromCharCode(r)}}Module.AsciiToString=AsciiToString;function stringToAscii(t,e){return writeAsciiToMemory(t,e,!1)}Module.stringToAscii=stringToAscii;var UTF8Decoder=typeof TextDecoder<\"u\"?new TextDecoder(\"utf8\"):void 0;function UTF8ArrayToString(t,e){for(var r=e;t[r];)++r;if(r-e>16&&t.subarray&&UTF8Decoder)return UTF8Decoder.decode(t.subarray(e,r));for(var o,a,n,u,A,p,h=\"\";;){if(o=t[e++],!o)return h;if(!(o&128)){h+=String.fromCharCode(o);continue}if(a=t[e++]&63,(o&224)==192){h+=String.fromCharCode((o&31)<<6|a);continue}if(n=t[e++]&63,(o&240)==224?o=(o&15)<<12|a<<6|n:(u=t[e++]&63,(o&248)==240?o=(o&7)<<18|a<<12|n<<6|u:(A=t[e++]&63,(o&252)==248?o=(o&3)<<24|a<<18|n<<12|u<<6|A:(p=t[e++]&63,o=(o&1)<<30|a<<24|n<<18|u<<12|A<<6|p))),o<65536)h+=String.fromCharCode(o);else{var E=o-65536;h+=String.fromCharCode(55296|E>>10,56320|E&1023)}}}Module.UTF8ArrayToString=UTF8ArrayToString;function UTF8ToString(t){return UTF8ArrayToString(HEAPU8,t)}Module.UTF8ToString=UTF8ToString;function stringToUTF8Array(t,e,r,o){if(!(o>0))return 0;for(var a=r,n=r+o-1,u=0;u<t.length;++u){var A=t.charCodeAt(u);if(A>=55296&&A<=57343&&(A=65536+((A&1023)<<10)|t.charCodeAt(++u)&1023),A<=127){if(r>=n)break;e[r++]=A}else if(A<=2047){if(r+1>=n)break;e[r++]=192|A>>6,e[r++]=128|A&63}else if(A<=65535){if(r+2>=n)break;e[r++]=224|A>>12,e[r++]=128|A>>6&63,e[r++]=128|A&63}else if(A<=2097151){if(r+3>=n)break;e[r++]=240|A>>18,e[r++]=128|A>>12&63,e[r++]=128|A>>6&63,e[r++]=128|A&63}else if(A<=67108863){if(r+4>=n)break;e[r++]=248|A>>24,e[r++]=128|A>>18&63,e[r++]=128|A>>12&63,e[r++]=128|A>>6&63,e[r++]=128|A&63}else{if(r+5>=n)break;e[r++]=252|A>>30,e[r++]=128|A>>24&63,e[r++]=128|A>>18&63,e[r++]=128|A>>12&63,e[r++]=128|A>>6&63,e[r++]=128|A&63}}return e[r]=0,r-a}Module.stringToUTF8Array=stringToUTF8Array;function stringToUTF8(t,e,r){return stringToUTF8Array(t,HEAPU8,e,r)}Module.stringToUTF8=stringToUTF8;function lengthBytesUTF8(t){for(var e=0,r=0;r<t.length;++r){var o=t.charCodeAt(r);o>=55296&&o<=57343&&(o=65536+((o&1023)<<10)|t.charCodeAt(++r)&1023),o<=127?++e:o<=2047?e+=2:o<=65535?e+=3:o<=2097151?e+=4:o<=67108863?e+=5:e+=6}return e}Module.lengthBytesUTF8=lengthBytesUTF8;var UTF16Decoder=typeof TextDecoder<\"u\"?new TextDecoder(\"utf-16le\"):void 0;function demangle(t){var e=Module.___cxa_demangle||Module.__cxa_demangle;if(e){try{var r=t.substr(1),o=lengthBytesUTF8(r)+1,a=_malloc(o);stringToUTF8(r,a,o);var n=_malloc(4),u=e(a,0,0,n);if(getValue(n,\"i32\")===0&&u)return Pointer_stringify(u)}catch{}finally{a&&_free(a),n&&_free(n),u&&_free(u)}return t}return Runtime.warnOnce(\"warning: build with  -s DEMANGLE_SUPPORT=1  to link in libcxxabi demangling\"),t}function demangleAll(t){var e=/__Z[\\w\\d_]+/g;return t.replace(e,function(r){var o=demangle(r);return r===o?r:r+\" [\"+o+\"]\"})}function jsStackTrace(){var t=new Error;if(!t.stack){try{throw new Error(0)}catch(e){t=e}if(!t.stack)return\"(no stack trace available)\"}return t.stack.toString()}function stackTrace(){var t=jsStackTrace();return Module.extraStackTrace&&(t+=`\n`+Module.extraStackTrace()),demangleAll(t)}Module.stackTrace=stackTrace;var HEAP,buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBufferViews(){Module.HEAP8=HEAP8=new Int8Array(buffer),Module.HEAP16=HEAP16=new Int16Array(buffer),Module.HEAP32=HEAP32=new Int32Array(buffer),Module.HEAPU8=HEAPU8=new Uint8Array(buffer),Module.HEAPU16=HEAPU16=new Uint16Array(buffer),Module.HEAPU32=HEAPU32=new Uint32Array(buffer),Module.HEAPF32=HEAPF32=new Float32Array(buffer),Module.HEAPF64=HEAPF64=new Float64Array(buffer)}var STATIC_BASE,STATICTOP,staticSealed,STACK_BASE,STACKTOP,STACK_MAX,DYNAMIC_BASE,DYNAMICTOP_PTR;STATIC_BASE=STATICTOP=STACK_BASE=STACKTOP=STACK_MAX=DYNAMIC_BASE=DYNAMICTOP_PTR=0,staticSealed=!1;function abortOnCannotGrowMemory(){abort(\"Cannot enlarge memory arrays. Either (1) compile with  -s TOTAL_MEMORY=X  with X higher than the current value \"+TOTAL_MEMORY+\", (2) compile with  -s ALLOW_MEMORY_GROWTH=1  which allows increasing the size at runtime but prevents some optimizations, (3) set Module.TOTAL_MEMORY to a higher value before the program runs, or (4) if you want malloc to return NULL (0) instead of this abort, compile with  -s ABORTING_MALLOC=0 \")}function enlargeMemory(){abortOnCannotGrowMemory()}var TOTAL_STACK=Module.TOTAL_STACK||5242880,TOTAL_MEMORY=Module.TOTAL_MEMORY||134217728;TOTAL_MEMORY<TOTAL_STACK&&Module.printErr(\"TOTAL_MEMORY should be larger than TOTAL_STACK, was \"+TOTAL_MEMORY+\"! (TOTAL_STACK=\"+TOTAL_STACK+\")\"),Module.buffer?buffer=Module.buffer:buffer=new ArrayBuffer(TOTAL_MEMORY),updateGlobalBufferViews();function getTotalMemory(){return TOTAL_MEMORY}if(HEAP32[0]=1668509029,HEAP16[1]=25459,HEAPU8[2]!==115||HEAPU8[3]!==99)throw\"Runtime error: expected the system to be little-endian!\";Module.HEAP=HEAP,Module.buffer=buffer,Module.HEAP8=HEAP8,Module.HEAP16=HEAP16,Module.HEAP32=HEAP32,Module.HEAPU8=HEAPU8,Module.HEAPU16=HEAPU16,Module.HEAPU32=HEAPU32,Module.HEAPF32=HEAPF32,Module.HEAPF64=HEAPF64;function callRuntimeCallbacks(t){for(;t.length>0;){var e=t.shift();if(typeof e==\"function\"){e();continue}var r=e.func;typeof r==\"number\"?e.arg===void 0?Module.dynCall_v(r):Module.dynCall_vi(r,e.arg):r(e.arg===void 0?null:e.arg)}}var __ATPRERUN__=[],__ATINIT__=[],__ATMAIN__=[],__ATEXIT__=[],__ATPOSTRUN__=[],runtimeInitialized=!1,runtimeExited=!1;function preRun(){if(Module.preRun)for(typeof Module.preRun==\"function\"&&(Module.preRun=[Module.preRun]);Module.preRun.length;)addOnPreRun(Module.preRun.shift());callRuntimeCallbacks(__ATPRERUN__)}function ensureInitRuntime(){runtimeInitialized||(runtimeInitialized=!0,callRuntimeCallbacks(__ATINIT__))}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function exitRuntime(){callRuntimeCallbacks(__ATEXIT__),runtimeExited=!0}function postRun(){if(Module.postRun)for(typeof Module.postRun==\"function\"&&(Module.postRun=[Module.postRun]);Module.postRun.length;)addOnPostRun(Module.postRun.shift());callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(t){__ATPRERUN__.unshift(t)}Module.addOnPreRun=addOnPreRun;function addOnInit(t){__ATINIT__.unshift(t)}Module.addOnInit=addOnInit;function addOnPreMain(t){__ATMAIN__.unshift(t)}Module.addOnPreMain=addOnPreMain;function addOnExit(t){__ATEXIT__.unshift(t)}Module.addOnExit=addOnExit;function addOnPostRun(t){__ATPOSTRUN__.unshift(t)}Module.addOnPostRun=addOnPostRun;function intArrayFromString(t,e,r){var o=r>0?r:lengthBytesUTF8(t)+1,a=new Array(o),n=stringToUTF8Array(t,a,0,a.length);return e&&(a.length=n),a}Module.intArrayFromString=intArrayFromString;function intArrayToString(t){for(var e=[],r=0;r<t.length;r++){var o=t[r];o>255&&(o&=255),e.push(String.fromCharCode(o))}return e.join(\"\")}Module.intArrayToString=intArrayToString;function writeStringToMemory(t,e,r){Runtime.warnOnce(\"writeStringToMemory is deprecated and should not be called! Use stringToUTF8() instead!\");var o,a;r&&(a=e+lengthBytesUTF8(t),o=HEAP8[a]),stringToUTF8(t,e,1/0),r&&(HEAP8[a]=o)}Module.writeStringToMemory=writeStringToMemory;function writeArrayToMemory(t,e){HEAP8.set(t,e)}Module.writeArrayToMemory=writeArrayToMemory;function writeAsciiToMemory(t,e,r){for(var o=0;o<t.length;++o)HEAP8[e++>>0]=t.charCodeAt(o);r||(HEAP8[e>>0]=0)}if(Module.writeAsciiToMemory=writeAsciiToMemory,(!Math.imul||Math.imul(4294967295,5)!==-5)&&(Math.imul=function t(e,r){var o=e>>>16,a=e&65535,n=r>>>16,u=r&65535;return a*u+(o*u+a*n<<16)|0}),Math.imul=Math.imul,!Math.fround){var froundBuffer=new Float32Array(1);Math.fround=function(t){return froundBuffer[0]=t,froundBuffer[0]}}Math.fround=Math.fround,Math.clz32||(Math.clz32=function(t){t=t>>>0;for(var e=0;e<32;e++)if(t&1<<31-e)return e;return 32}),Math.clz32=Math.clz32,Math.trunc||(Math.trunc=function(t){return t<0?Math.ceil(t):Math.floor(t)}),Math.trunc=Math.trunc;var Math_abs=Math.abs,Math_cos=Math.cos,Math_sin=Math.sin,Math_tan=Math.tan,Math_acos=Math.acos,Math_asin=Math.asin,Math_atan=Math.atan,Math_atan2=Math.atan2,Math_exp=Math.exp,Math_log=Math.log,Math_sqrt=Math.sqrt,Math_ceil=Math.ceil,Math_floor=Math.floor,Math_pow=Math.pow,Math_imul=Math.imul,Math_fround=Math.fround,Math_round=Math.round,Math_min=Math.min,Math_clz32=Math.clz32,Math_trunc=Math.trunc,runDependencies=0,runDependencyWatcher=null,dependenciesFulfilled=null;function getUniqueRunDependency(t){return t}function addRunDependency(t){runDependencies++,Module.monitorRunDependencies&&Module.monitorRunDependencies(runDependencies)}Module.addRunDependency=addRunDependency;function removeRunDependency(t){if(runDependencies--,Module.monitorRunDependencies&&Module.monitorRunDependencies(runDependencies),runDependencies==0&&(runDependencyWatcher!==null&&(clearInterval(runDependencyWatcher),runDependencyWatcher=null),dependenciesFulfilled)){var e=dependenciesFulfilled;dependenciesFulfilled=null,e()}}Module.removeRunDependency=removeRunDependency,Module.preloadedImages={},Module.preloadedAudios={};var ASM_CONSTS=[function(t,e,r,o,a,n,u,A){return _nbind.callbackSignatureList[t].apply(this,arguments)}];function _emscripten_asm_const_iiiiiiii(t,e,r,o,a,n,u,A){return ASM_CONSTS[t](e,r,o,a,n,u,A)}function _emscripten_asm_const_iiiii(t,e,r,o,a){return ASM_CONSTS[t](e,r,o,a)}function _emscripten_asm_const_iiidddddd(t,e,r,o,a,n,u,A,p){return ASM_CONSTS[t](e,r,o,a,n,u,A,p)}function _emscripten_asm_const_iiididi(t,e,r,o,a,n,u){return ASM_CONSTS[t](e,r,o,a,n,u)}function _emscripten_asm_const_iiii(t,e,r,o){return ASM_CONSTS[t](e,r,o)}function _emscripten_asm_const_iiiid(t,e,r,o,a){return ASM_CONSTS[t](e,r,o,a)}function _emscripten_asm_const_iiiiii(t,e,r,o,a,n){return ASM_CONSTS[t](e,r,o,a,n)}STATIC_BASE=Runtime.GLOBAL_BASE,STATICTOP=STATIC_BASE+12800,__ATINIT__.push({func:function(){__GLOBAL__sub_I_Yoga_cpp()}},{func:function(){__GLOBAL__sub_I_nbind_cc()}},{func:function(){__GLOBAL__sub_I_common_cc()}},{func:function(){__GLOBAL__sub_I_Binding_cc()}}),allocate([0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,127,0,0,192,127,0,0,192,127,0,0,192,127,3,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,3,0,0,0,0,0,192,127,3,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,192,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,127,0,0,192,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,127,0,0,0,0,0,0,0,0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,127,0,0,192,127,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,0,0,128,191,0,0,128,191,0,0,192,127,0,0,0,0,0,0,0,0,0,0,128,63,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,3,0,0,0,1,0,0,0,2,0,0,0,0,0,0,0,190,12,0,0,200,12,0,0,208,12,0,0,216,12,0,0,230,12,0,0,242,12,0,0,1,0,0,0,3,0,0,0,0,0,0,0,2,0,0,0,0,0,192,127,3,0,0,0,180,45,0,0,181,45,0,0,182,45,0,0,181,45,0,0,182,45,0,0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,3,0,0,0,1,0,0,0,4,0,0,0,183,45,0,0,181,45,0,0,181,45,0,0,181,45,0,0,181,45,0,0,181,45,0,0,181,45,0,0,184,45,0,0,185,45,0,0,181,45,0,0,181,45,0,0,182,45,0,0,186,45,0,0,185,45,0,0,148,4,0,0,3,0,0,0,187,45,0,0,164,4,0,0,188,45,0,0,2,0,0,0,189,45,0,0,164,4,0,0,188,45,0,0,185,45,0,0,164,4,0,0,185,45,0,0,164,4,0,0,188,45,0,0,181,45,0,0,182,45,0,0,181,45,0,0,0,0,0,0,0,0,0,0,1,0,0,0,5,0,0,0,6,0,0,0,1,0,0,0,7,0,0,0,183,45,0,0,182,45,0,0,181,45,0,0,190,45,0,0,190,45,0,0,182,45,0,0,182,45,0,0,185,45,0,0,181,45,0,0,185,45,0,0,182,45,0,0,181,45,0,0,185,45,0,0,182,45,0,0,185,45,0,0,48,5,0,0,3,0,0,0,56,5,0,0,1,0,0,0,189,45,0,0,185,45,0,0,164,4,0,0,76,5,0,0,2,0,0,0,191,45,0,0,186,45,0,0,182,45,0,0,185,45,0,0,192,45,0,0,185,45,0,0,182,45,0,0,186,45,0,0,185,45,0,0,76,5,0,0,76,5,0,0,136,5,0,0,182,45,0,0,181,45,0,0,2,0,0,0,190,45,0,0,136,5,0,0,56,19,0,0,156,5,0,0,2,0,0,0,184,45,0,0,0,0,0,0,0,0,0,0,1,0,0,0,8,0,0,0,9,0,0,0,1,0,0,0,10,0,0,0,204,5,0,0,181,45,0,0,181,45,0,0,2,0,0,0,180,45,0,0,204,5,0,0,2,0,0,0,195,45,0,0,236,5,0,0,97,19,0,0,198,45,0,0,211,45,0,0,212,45,0,0,213,45,0,0,214,45,0,0,215,45,0,0,188,45,0,0,182,45,0,0,216,45,0,0,217,45,0,0,218,45,0,0,219,45,0,0,192,45,0,0,181,45,0,0,0,0,0,0,185,45,0,0,110,19,0,0,186,45,0,0,115,19,0,0,221,45,0,0,120,19,0,0,148,4,0,0,132,19,0,0,96,6,0,0,145,19,0,0,222,45,0,0,164,19,0,0,223,45,0,0,173,19,0,0,0,0,0,0,3,0,0,0,104,6,0,0,1,0,0,0,187,45,0,0,0,0,0,0,0,0,0,0,1,0,0,0,11,0,0,0,12,0,0,0,1,0,0,0,13,0,0,0,185,45,0,0,224,45,0,0,164,6,0,0,188,45,0,0,172,6,0,0,180,6,0,0,2,0,0,0,188,6,0,0,7,0,0,0,224,45,0,0,7,0,0,0,164,6,0,0,1,0,0,0,213,45,0,0,185,45,0,0,224,45,0,0,172,6,0,0,185,45,0,0,224,45,0,0,164,6,0,0,185,45,0,0,224,45,0,0,211,45,0,0,211,45,0,0,222,45,0,0,211,45,0,0,224,45,0,0,222,45,0,0,211,45,0,0,224,45,0,0,172,6,0,0,222,45,0,0,211,45,0,0,224,45,0,0,188,45,0,0,222,45,0,0,211,45,0,0,40,7,0,0,188,45,0,0,2,0,0,0,224,45,0,0,185,45,0,0,188,45,0,0,188,45,0,0,188,45,0,0,188,45,0,0,222,45,0,0,224,45,0,0,148,4,0,0,185,45,0,0,148,4,0,0,148,4,0,0,148,4,0,0,148,4,0,0,148,4,0,0,185,45,0,0,164,6,0,0,148,4,0,0,0,0,0,0,0,0,0,0,1,0,0,0,14,0,0,0,15,0,0,0,1,0,0,0,16,0,0,0,148,7,0,0,2,0,0,0,225,45,0,0,183,45,0,0,188,45,0,0,168,7,0,0,5,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,234,45,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,148,45,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,9,0,0,5,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,2,0,0,0,242,45,0,0,0,4,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67,111,117,108,100,32,110,111,116,32,97,108,108,111,99,97,116,101,32,109,101,109,111,114,121,32,102,111,114,32,110,111,100,101,0,67,97,110,110,111,116,32,114,101,115,101,116,32,97,32,110,111,100,101,32,119,104,105,99,104,32,115,116,105,108,108,32,104,97,115,32,99,104,105,108,100,114,101,110,32,97,116,116,97,99,104,101,100,0,67,97,110,110,111,116,32,114,101,115,101,116,32,97,32,110,111,100,101,32,115,116,105,108,108,32,97,116,116,97,99,104,101,100,32,116,111,32,97,32,112,97,114,101,110,116,0,67,111,117,108,100,32,110,111,116,32,97,108,108,111,99,97,116,101,32,109,101,109,111,114,121,32,102,111,114,32,99,111,110,102,105,103,0,67,97,110,110,111,116,32,115,101,116,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,58,32,78,111,100,101,115,32,119,105,116,104,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,115,32,99,97,110,110,111,116,32,104,97,118,101,32,99,104,105,108,100,114,101,110,46,0,67,104,105,108,100,32,97,108,114,101,97,100,121,32,104,97,115,32,97,32,112,97,114,101,110,116,44,32,105,116,32,109,117,115,116,32,98,101,32,114,101,109,111,118,101,100,32,102,105,114,115,116,46,0,67,97,110,110,111,116,32,97,100,100,32,99,104,105,108,100,58,32,78,111,100,101,115,32,119,105,116,104,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,115,32,99,97,110,110,111,116,32,104,97,118,101,32,99,104,105,108,100,114,101,110,46,0,79,110,108,121,32,108,101,97,102,32,110,111,100,101,115,32,119,105,116,104,32,99,117,115,116,111,109,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,115,115,104,111,117,108,100,32,109,97,110,117,97,108,108,121,32,109,97,114,107,32,116,104,101,109,115,101,108,118,101,115,32,97,115,32,100,105,114,116,121,0,67,97,110,110,111,116,32,103,101,116,32,108,97,121,111,117,116,32,112,114,111,112,101,114,116,105,101,115,32,111,102,32,109,117,108,116,105,45,101,100,103,101,32,115,104,111,114,116,104,97,110,100,115,0,37,115,37,100,46,123,91,115,107,105,112,112,101,100,93,32,0,119,109,58,32,37,115,44,32,104,109,58,32,37,115,44,32,97,119,58,32,37,102,32,97,104,58,32,37,102,32,61,62,32,100,58,32,40,37,102,44,32,37,102,41,32,37,115,10,0,37,115,37,100,46,123,37,115,0,42,0,119,109,58,32,37,115,44,32,104,109,58,32,37,115,44,32,97,119,58,32,37,102,32,97,104,58,32,37,102,32,37,115,10,0,37,115,37,100,46,125,37,115,0,119,109,58,32,37,115,44,32,104,109,58,32,37,115,44,32,100,58,32,40,37,102,44,32,37,102,41,32,37,115,10,0,79,117,116,32,111,102,32,99,97,99,104,101,32,101,110,116,114,105,101,115,33,10,0,83,99,97,108,101,32,102,97,99,116,111,114,32,115,104,111,117,108,100,32,110,111,116,32,98,101,32,108,101,115,115,32,116,104,97,110,32,122,101,114,111,0,105,110,105,116,105,97,108,0,37,115,10,0,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,0,85,78,68,69,70,73,78,69,68,0,69,88,65,67,84,76,89,0,65,84,95,77,79,83,84,0,76,65,89,95,85,78,68,69,70,73,78,69,68,0,76,65,89,95,69,88,65,67,84,76,89,0,76,65,89,95,65,84,95,77,79,83,84,0,97,118,97,105,108,97,98,108,101,87,105,100,116,104,32,105,115,32,105,110,100,101,102,105,110,105,116,101,32,115,111,32,119,105,100,116,104,77,101,97,115,117,114,101,77,111,100,101,32,109,117,115,116,32,98,101,32,89,71,77,101,97,115,117,114,101,77,111,100,101,85,110,100,101,102,105,110,101,100,0,97,118,97,105,108,97,98,108,101,72,101,105,103,104,116,32,105,115,32,105,110,100,101,102,105,110,105,116,101,32,115,111,32,104,101,105,103,104,116,77,101,97,115,117,114,101,77,111,100,101,32,109,117,115,116,32,98,101,32,89,71,77,101,97,115,117,114,101,77,111,100,101,85,110,100,101,102,105,110,101,100,0,102,108,101,120,0,115,116,114,101,116,99,104,0,109,117,108,116,105,108,105,110,101,45,115,116,114,101,116,99,104,0,69,120,112,101,99,116,101,100,32,110,111,100,101,32,116,111,32,104,97,118,101,32,99,117,115,116,111,109,32,109,101,97,115,117,114,101,32,102,117,110,99,116,105,111,110,0,109,101,97,115,117,114,101,0,69,120,112,101,99,116,32,99,117,115,116,111,109,32,98,97,115,101,108,105,110,101,32,102,117,110,99,116,105,111,110,32,116,111,32,110,111,116,32,114,101,116,117,114,110,32,78,97,78,0,97,98,115,45,109,101,97,115,117,114,101,0,97,98,115,45,108,97,121,111,117,116,0,78,111,100,101,0,99,114,101,97,116,101,68,101,102,97,117,108,116,0,99,114,101,97,116,101,87,105,116,104,67,111,110,102,105,103,0,100,101,115,116,114,111,121,0,114,101,115,101,116,0,99,111,112,121,83,116,121,108,101,0,115,101,116,80,111,115,105,116,105,111,110,84,121,112,101,0,115,101,116,80,111,115,105,116,105,111,110,0,115,101,116,80,111,115,105,116,105,111,110,80,101,114,99,101,110,116,0,115,101,116,65,108,105,103,110,67,111,110,116,101,110,116,0,115,101,116,65,108,105,103,110,73,116,101,109,115,0,115,101,116,65,108,105,103,110,83,101,108,102,0,115,101,116,70,108,101,120,68,105,114,101,99,116,105,111,110,0,115,101,116,70,108,101,120,87,114,97,112,0,115,101,116,74,117,115,116,105,102,121,67,111,110,116,101,110,116,0,115,101,116,77,97,114,103,105,110,0,115,101,116,77,97,114,103,105,110,80,101,114,99,101,110,116,0,115,101,116,77,97,114,103,105,110,65,117,116,111,0,115,101,116,79,118,101,114,102,108,111,119,0,115,101,116,68,105,115,112,108,97,121,0,115,101,116,70,108,101,120,0,115,101,116,70,108,101,120,66,97,115,105,115,0,115,101,116,70,108,101,120,66,97,115,105,115,80,101,114,99,101,110,116,0,115,101,116,70,108,101,120,71,114,111,119,0,115,101,116,70,108,101,120,83,104,114,105,110,107,0,115,101,116,87,105,100,116,104,0,115,101,116,87,105,100,116,104,80,101,114,99,101,110,116,0,115,101,116,87,105,100,116,104,65,117,116,111,0,115,101,116,72,101,105,103,104,116,0,115,101,116,72,101,105,103,104,116,80,101,114,99,101,110,116,0,115,101,116,72,101,105,103,104,116,65,117,116,111,0,115,101,116,77,105,110,87,105,100,116,104,0,115,101,116,77,105,110,87,105,100,116,104,80,101,114,99,101,110,116,0,115,101,116,77,105,110,72,101,105,103,104,116,0,115,101,116,77,105,110,72,101,105,103,104,116,80,101,114,99,101,110,116,0,115,101,116,77,97,120,87,105,100,116,104,0,115,101,116,77,97,120,87,105,100,116,104,80,101,114,99,101,110,116,0,115,101,116,77,97,120,72,101,105,103,104,116,0,115,101,116,77,97,120,72,101,105,103,104,116,80,101,114,99,101,110,116,0,115,101,116,65,115,112,101,99,116,82,97,116,105,111,0,115,101,116,66,111,114,100,101,114,0,115,101,116,80,97,100,100,105,110,103,0,115,101,116,80,97,100,100,105,110,103,80,101,114,99,101,110,116,0,103,101,116,80,111,115,105,116,105,111,110,84,121,112,101,0,103,101,116,80,111,115,105,116,105,111,110,0,103,101,116,65,108,105,103,110,67,111,110,116,101,110,116,0,103,101,116,65,108,105,103,110,73,116,101,109,115,0,103,101,116,65,108,105,103,110,83,101,108,102,0,103,101,116,70,108,101,120,68,105,114,101,99,116,105,111,110,0,103,101,116,70,108,101,120,87,114,97,112,0,103,101,116,74,117,115,116,105,102,121,67,111,110,116,101,110,116,0,103,101,116,77,97,114,103,105,110,0,103,101,116,70,108,101,120,66,97,115,105,115,0,103,101,116,70,108,101,120,71,114,111,119,0,103,101,116,70,108,101,120,83,104,114,105,110,107,0,103,101,116,87,105,100,116,104,0,103,101,116,72,101,105,103,104,116,0,103,101,116,77,105,110,87,105,100,116,104,0,103,101,116,77,105,110,72,101,105,103,104,116,0,103,101,116,77,97,120,87,105,100,116,104,0,103,101,116,77,97,120,72,101,105,103,104,116,0,103,101,116,65,115,112,101,99,116,82,97,116,105,111,0,103,101,116,66,111,114,100,101,114,0,103,101,116,79,118,101,114,102,108,111,119,0,103,101,116,68,105,115,112,108,97,121,0,103,101,116,80,97,100,100,105,110,103,0,105,110,115,101,114,116,67,104,105,108,100,0,114,101,109,111,118,101,67,104,105,108,100,0,103,101,116,67,104,105,108,100,67,111,117,110,116,0,103,101,116,80,97,114,101,110,116,0,103,101,116,67,104,105,108,100,0,115,101,116,77,101,97,115,117,114,101,70,117,110,99,0,117,110,115,101,116,77,101,97,115,117,114,101,70,117,110,99,0,109,97,114,107,68,105,114,116,121,0,105,115,68,105,114,116,121,0,99,97,108,99,117,108,97,116,101,76,97,121,111,117,116,0,103,101,116,67,111,109,112,117,116,101,100,76,101,102,116,0,103,101,116,67,111,109,112,117,116,101,100,82,105,103,104,116,0,103,101,116,67,111,109,112,117,116,101,100,84,111,112,0,103,101,116,67,111,109,112,117,116,101,100,66,111,116,116,111,109,0,103,101,116,67,111,109,112,117,116,101,100,87,105,100,116,104,0,103,101,116,67,111,109,112,117,116,101,100,72,101,105,103,104,116,0,103,101,116,67,111,109,112,117,116,101,100,76,97,121,111,117,116,0,103,101,116,67,111,109,112,117,116,101,100,77,97,114,103,105,110,0,103,101,116,67,111,109,112,117,116,101,100,66,111,114,100,101,114,0,103,101,116,67,111,109,112,117,116,101,100,80,97,100,100,105,110,103,0,67,111,110,102,105,103,0,99,114,101,97,116,101,0,115,101,116,69,120,112,101,114,105,109,101,110,116,97,108,70,101,97,116,117,114,101,69,110,97,98,108,101,100,0,115,101,116,80,111,105,110,116,83,99,97,108,101,70,97,99,116,111,114,0,105,115,69,120,112,101,114,105,109,101,110,116,97,108,70,101,97,116,117,114,101,69,110,97,98,108,101,100,0,86,97,108,117,101,0,76,97,121,111,117,116,0,83,105,122,101,0,103,101,116,73,110,115,116,97,110,99,101,67,111,117,110,116,0,73,110,116,54,52,0,1,1,1,2,2,4,4,4,4,8,8,4,8,118,111,105,100,0,98,111,111,108,0,115,116,100,58,58,115,116,114,105,110,103,0,99,98,70,117,110,99,116,105,111,110,32,38,0,99,111,110,115,116,32,99,98,70,117,110,99,116,105,111,110,32,38,0,69,120,116,101,114,110,97,108,0,66,117,102,102,101,114,0,78,66,105,110,100,73,68,0,78,66,105,110,100,0,98,105,110,100,95,118,97,108,117,101,0,114,101,102,108,101,99,116,0,113,117,101,114,121,84,121,112,101,0,108,97,108,108,111,99,0,108,114,101,115,101,116,0,123,114,101,116,117,114,110,40,95,110,98,105,110,100,46,99,97,108,108,98,97,99,107,83,105,103,110,97,116,117,114,101,76,105,115,116,91,36,48,93,46,97,112,112,108,121,40,116,104,105,115,44,97,114,103,117,109,101,110,116,115,41,41,59,125,0,95,110,98,105,110,100,95,110,101,119,0,17,0,10,0,17,17,17,0,0,0,0,5,0,0,0,0,0,0,9,0,0,0,0,11,0,0,0,0,0,0,0,0,17,0,15,10,17,17,17,3,10,7,0,1,19,9,11,11,0,0,9,6,11,0,0,11,0,6,17,0,0,0,17,17,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,17,0,10,10,17,17,17,0,10,0,0,2,0,9,11,0,0,0,9,0,11,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,12,0,0,0,0,9,12,0,0,0,0,0,12,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,13,0,0,0,4,13,0,0,0,0,9,14,0,0,0,0,0,14,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,15,0,0,0,0,9,16,0,0,0,0,0,16,0,0,16,0,0,18,0,0,0,18,18,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,0,0,0,18,18,18,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,10,0,0,0,0,9,11,0,0,0,0,0,11,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,12,0,0,0,0,9,12,0,0,0,0,0,12,0,0,12,0,0,45,43,32,32,32,48,88,48,120,0,40,110,117,108,108,41,0,45,48,88,43,48,88,32,48,88,45,48,120,43,48,120,32,48,120,0,105,110,102,0,73,78,70,0,110,97,110,0,78,65,78,0,48,49,50,51,52,53,54,55,56,57,65,66,67,68,69,70,46,0,84,33,34,25,13,1,2,3,17,75,28,12,16,4,11,29,18,30,39,104,110,111,112,113,98,32,5,6,15,19,20,21,26,8,22,7,40,36,23,24,9,10,14,27,31,37,35,131,130,125,38,42,43,60,61,62,63,67,71,74,77,88,89,90,91,92,93,94,95,96,97,99,100,101,102,103,105,106,107,108,114,115,116,121,122,123,124,0,73,108,108,101,103,97,108,32,98,121,116,101,32,115,101,113,117,101,110,99,101,0,68,111,109,97,105,110,32,101,114,114,111,114,0,82,101,115,117,108,116,32,110,111,116,32,114,101,112,114,101,115,101,110,116,97,98,108,101,0,78,111,116,32,97,32,116,116,121,0,80,101,114,109,105,115,115,105,111,110,32,100,101,110,105,101,100,0,79,112,101,114,97,116,105,111,110,32,110,111,116,32,112,101,114,109,105,116,116,101,100,0,78,111,32,115,117,99,104,32,102,105,108,101,32,111,114,32,100,105,114,101,99,116,111,114,121,0,78,111,32,115,117,99,104,32,112,114,111,99,101,115,115,0,70,105,108,101,32,101,120,105,115,116,115,0,86,97,108,117,101,32,116,111,111,32,108,97,114,103,101,32,102,111,114,32,100,97,116,97,32,116,121,112,101,0,78,111,32,115,112,97,99,101,32,108,101,102,116,32,111,110,32,100,101,118,105,99,101,0,79,117,116,32,111,102,32,109,101,109,111,114,121,0,82,101,115,111,117,114,99,101,32,98,117,115,121,0,73,110,116,101,114,114,117,112,116,101,100,32,115,121,115,116,101,109,32,99,97,108,108,0,82,101,115,111,117,114,99,101,32,116,101,109,112,111,114,97,114,105,108,121,32,117,110,97,118,97,105,108,97,98,108,101,0,73,110,118,97,108,105,100,32,115,101,101,107,0,67,114,111,115,115,45,100,101,118,105,99,101,32,108,105,110,107,0,82,101,97,100,45,111,110,108,121,32,102,105,108,101,32,115,121,115,116,101,109,0,68,105,114,101,99,116,111,114,121,32,110,111,116,32,101,109,112,116,121,0,67,111,110,110,101,99,116,105,111,110,32,114,101,115,101,116,32,98,121,32,112,101,101,114,0,79,112,101,114,97,116,105,111,110,32,116,105,109,101,100,32,111,117,116,0,67,111,110,110,101,99,116,105,111,110,32,114,101,102,117,115,101,100,0,72,111,115,116,32,105,115,32,100,111,119,110,0,72,111,115,116,32,105,115,32,117,110,114,101,97,99,104,97,98,108,101,0,65,100,100,114,101,115,115,32,105,110,32,117,115,101,0,66,114,111,107,101,110,32,112,105,112,101,0,73,47,79,32,101,114,114,111,114,0,78,111,32,115,117,99,104,32,100,101,118,105,99,101,32,111,114,32,97,100,100,114,101,115,115,0,66,108,111,99,107,32,100,101,118,105,99,101,32,114,101,113,117,105,114,101,100,0,78,111,32,115,117,99,104,32,100,101,118,105,99,101,0,78,111,116,32,97,32,100,105,114,101,99,116,111,114,121,0,73,115,32,97,32,100,105,114,101,99,116,111,114,121,0,84,101,120,116,32,102,105,108,101,32,98,117,115,121,0,69,120,101,99,32,102,111,114,109,97,116,32,101,114,114,111,114,0,73,110,118,97,108,105,100,32,97,114,103,117,109,101,110,116,0,65,114,103,117,109,101,110,116,32,108,105,115,116,32,116,111,111,32,108,111,110,103,0,83,121,109,98,111,108,105,99,32,108,105,110,107,32,108,111,111,112,0,70,105,108,101,110,97,109,101,32,116,111,111,32,108,111,110,103,0,84,111,111,32,109,97,110,121,32,111,112,101,110,32,102,105,108,101,115,32,105,110,32,115,121,115,116,101,109,0,78,111,32,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,115,32,97,118,97,105,108,97,98,108,101,0,66,97,100,32,102,105,108,101,32,100,101,115,99,114,105,112,116,111,114,0,78,111,32,99,104,105,108,100,32,112,114,111,99,101,115,115,0,66,97,100,32,97,100,100,114,101,115,115,0,70,105,108,101,32,116,111,111,32,108,97,114,103,101,0,84,111,111,32,109,97,110,121,32,108,105,110,107,115,0,78,111,32,108,111,99,107,115,32,97,118,97,105,108,97,98,108,101,0,82,101,115,111,117,114,99,101,32,100,101,97,100,108,111,99,107,32,119,111,117,108,100,32,111,99,99,117,114,0,83,116,97,116,101,32,110,111,116,32,114,101,99,111,118,101,114,97,98,108,101,0,80,114,101,118,105,111,117,115,32,111,119,110,101,114,32,100,105,101,100,0,79,112,101,114,97,116,105,111,110,32,99,97,110,99,101,108,101,100,0,70,117,110,99,116,105,111,110,32,110,111,116,32,105,109,112,108,101,109,101,110,116,101,100,0,78,111,32,109,101,115,115,97,103,101,32,111,102,32,100,101,115,105,114,101,100,32,116,121,112,101,0,73,100,101,110,116,105,102,105,101,114,32,114,101,109,111,118,101,100,0,68,101,118,105,99,101,32,110,111,116,32,97,32,115,116,114,101,97,109,0,78,111,32,100,97,116,97,32,97,118,97,105,108,97,98,108,101,0,68,101,118,105,99,101,32,116,105,109,101,111,117,116,0,79,117,116,32,111,102,32,115,116,114,101,97,109,115,32,114,101,115,111,117,114,99,101,115,0,76,105,110,107,32,104,97,115,32,98,101,101,110,32,115,101,118,101,114,101,100,0,80,114,111,116,111,99,111,108,32,101,114,114,111,114,0,66,97,100,32,109,101,115,115,97,103,101,0,70,105,108,101,32,100,101,115,99,114,105,112,116,111,114,32,105,110,32,98,97,100,32,115,116,97,116,101,0,78,111,116,32,97,32,115,111,99,107,101,116,0,68,101,115,116,105,110,97,116,105,111,110,32,97,100,100,114,101,115,115,32,114,101,113,117,105,114,101,100,0,77,101,115,115,97,103,101,32,116,111,111,32,108,97,114,103,101,0,80,114,111,116,111,99,111,108,32,119,114,111,110,103,32,116,121,112,101,32,102,111,114,32,115,111,99,107,101,116,0,80,114,111,116,111,99,111,108,32,110,111,116,32,97,118,97,105,108,97,98,108,101,0,80,114,111,116,111,99,111,108,32,110,111,116,32,115,117,112,112,111,114,116,101,100,0,83,111,99,107,101,116,32,116,121,112,101,32,110,111,116,32,115,117,112,112,111,114,116,101,100,0,78,111,116,32,115,117,112,112,111,114,116,101,100,0,80,114,111,116,111,99,111,108,32,102,97,109,105,108,121,32,110,111,116,32,115,117,112,112,111,114,116,101,100,0,65,100,100,114,101,115,115,32,102,97,109,105,108,121,32,110,111,116,32,115,117,112,112,111,114,116,101,100,32,98,121,32,112,114,111,116,111,99,111,108,0,65,100,100,114,101,115,115,32,110,111,116,32,97,118,97,105,108,97,98,108,101,0,78,101,116,119,111,114,107,32,105,115,32,100,111,119,110,0,78,101,116,119,111,114,107,32,117,110,114,101,97,99,104,97,98,108,101,0,67,111,110,110,101,99,116,105,111,110,32,114,101,115,101,116,32,98,121,32,110,101,116,119,111,114,107,0,67,111,110,110,101,99,116,105,111,110,32,97,98,111,114,116,101,100,0,78,111,32,98,117,102,102,101,114,32,115,112,97,99,101,32,97,118,97,105,108,97,98,108,101,0,83,111,99,107,101,116,32,105,115,32,99,111,110,110,101,99,116,101,100,0,83,111,99,107,101,116,32,110,111,116,32,99,111,110,110,101,99,116,101,100,0,67,97,110,110,111,116,32,115,101,110,100,32,97,102,116,101,114,32,115,111,99,107,101,116,32,115,104,117,116,100,111,119,110,0,79,112,101,114,97,116,105,111,110,32,97,108,114,101,97,100,121,32,105,110,32,112,114,111,103,114,101,115,115,0,79,112,101,114,97,116,105,111,110,32,105,110,32,112,114,111,103,114,101,115,115,0,83,116,97,108,101,32,102,105,108,101,32,104,97,110,100,108,101,0,82,101,109,111,116,101,32,73,47,79,32,101,114,114,111,114,0,81,117,111,116,97,32,101,120,99,101,101,100,101,100,0,78,111,32,109,101,100,105,117,109,32,102,111,117,110,100,0,87,114,111,110,103,32,109,101,100,105,117,109,32,116,121,112,101,0,78,111,32,101,114,114,111,114,32,105,110,102,111,114,109,97,116,105,111,110,0,0],\"i8\",ALLOC_NONE,Runtime.GLOBAL_BASE);var tempDoublePtr=STATICTOP;STATICTOP+=16;function _atexit(t,e){__ATEXIT__.unshift({func:t,arg:e})}function ___cxa_atexit(){return _atexit.apply(null,arguments)}function _abort(){Module.abort()}function __ZN8facebook4yoga14YGNodeToStringEPNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP6YGNode14YGPrintOptionsj(){Module.printErr(\"missing function: _ZN8facebook4yoga14YGNodeToStringEPNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP6YGNode14YGPrintOptionsj\"),abort(-1)}function __decorate(t,e,r,o){var a=arguments.length,n=a<3?e:o===null?o=Object.getOwnPropertyDescriptor(e,r):o,u;if(typeof Reflect==\"object\"&&typeof Reflect.decorate==\"function\")n=Reflect.decorate(t,e,r,o);else for(var A=t.length-1;A>=0;A--)(u=t[A])&&(n=(a<3?u(n):a>3?u(e,r,n):u(e,r))||n);return a>3&&n&&Object.defineProperty(e,r,n),n}function _defineHidden(t){return function(e,r){Object.defineProperty(e,r,{configurable:!1,enumerable:!1,value:t,writable:!0})}}var _nbind={};function __nbind_free_external(t){_nbind.externalList[t].dereference(t)}function __nbind_reference_external(t){_nbind.externalList[t].reference()}function _llvm_stackrestore(t){var e=_llvm_stacksave,r=e.LLVM_SAVEDSTACKS[t];e.LLVM_SAVEDSTACKS.splice(t,1),Runtime.stackRestore(r)}function __nbind_register_pool(t,e,r,o){_nbind.Pool.pageSize=t,_nbind.Pool.usedPtr=e/4,_nbind.Pool.rootPtr=r,_nbind.Pool.pagePtr=o/4,HEAP32[e/4]=16909060,HEAP8[e]==1&&(_nbind.bigEndian=!0),HEAP32[e/4]=0,_nbind.makeTypeKindTbl=(n={},n[1024]=_nbind.PrimitiveType,n[64]=_nbind.Int64Type,n[2048]=_nbind.BindClass,n[3072]=_nbind.BindClassPtr,n[4096]=_nbind.SharedClassPtr,n[5120]=_nbind.ArrayType,n[6144]=_nbind.ArrayType,n[7168]=_nbind.CStringType,n[9216]=_nbind.CallbackType,n[10240]=_nbind.BindType,n),_nbind.makeTypeNameTbl={Buffer:_nbind.BufferType,External:_nbind.ExternalType,Int64:_nbind.Int64Type,_nbind_new:_nbind.CreateValueType,bool:_nbind.BooleanType,\"cbFunction &\":_nbind.CallbackType,\"const cbFunction &\":_nbind.CallbackType,\"const std::string &\":_nbind.StringType,\"std::string\":_nbind.StringType},Module.toggleLightGC=_nbind.toggleLightGC,_nbind.callUpcast=Module.dynCall_ii;var a=_nbind.makeType(_nbind.constructType,{flags:2048,id:0,name:\"\"});a.proto=Module,_nbind.BindClass.list.push(a);var n}function _emscripten_set_main_loop_timing(t,e){if(Browser.mainLoop.timingMode=t,Browser.mainLoop.timingValue=e,!Browser.mainLoop.func)return 1;if(t==0)Browser.mainLoop.scheduler=function(){var u=Math.max(0,Browser.mainLoop.tickStartTime+e-_emscripten_get_now())|0;setTimeout(Browser.mainLoop.runner,u)},Browser.mainLoop.method=\"timeout\";else if(t==1)Browser.mainLoop.scheduler=function(){Browser.requestAnimationFrame(Browser.mainLoop.runner)},Browser.mainLoop.method=\"rAF\";else if(t==2){if(!window.setImmediate){let n=function(u){u.source===window&&u.data===o&&(u.stopPropagation(),r.shift()())};var a=n,r=[],o=\"setimmediate\";window.addEventListener(\"message\",n,!0),window.setImmediate=function(A){r.push(A),ENVIRONMENT_IS_WORKER?(Module.setImmediates===void 0&&(Module.setImmediates=[]),Module.setImmediates.push(A),window.postMessage({target:o})):window.postMessage(o,\"*\")}}Browser.mainLoop.scheduler=function(){window.setImmediate(Browser.mainLoop.runner)},Browser.mainLoop.method=\"immediate\"}return 0}function _emscripten_get_now(){abort()}function _emscripten_set_main_loop(t,e,r,o,a){Module.noExitRuntime=!0,assert(!Browser.mainLoop.func,\"emscripten_set_main_loop: there can only be one main loop function at once: call emscripten_cancel_main_loop to cancel the previous one before setting a new one with different parameters.\"),Browser.mainLoop.func=t,Browser.mainLoop.arg=o;var n;typeof o<\"u\"?n=function(){Module.dynCall_vi(t,o)}:n=function(){Module.dynCall_v(t)};var u=Browser.mainLoop.currentlyRunningMainloop;if(Browser.mainLoop.runner=function(){if(!ABORT){if(Browser.mainLoop.queue.length>0){var p=Date.now(),h=Browser.mainLoop.queue.shift();if(h.func(h.arg),Browser.mainLoop.remainingBlockers){var E=Browser.mainLoop.remainingBlockers,I=E%1==0?E-1:Math.floor(E);h.counted?Browser.mainLoop.remainingBlockers=I:(I=I+.5,Browser.mainLoop.remainingBlockers=(8*E+I)/9)}if(console.log('main loop blocker \"'+h.name+'\" took '+(Date.now()-p)+\" ms\"),Browser.mainLoop.updateStatus(),u<Browser.mainLoop.currentlyRunningMainloop)return;setTimeout(Browser.mainLoop.runner,0);return}if(!(u<Browser.mainLoop.currentlyRunningMainloop)){if(Browser.mainLoop.currentFrameNumber=Browser.mainLoop.currentFrameNumber+1|0,Browser.mainLoop.timingMode==1&&Browser.mainLoop.timingValue>1&&Browser.mainLoop.currentFrameNumber%Browser.mainLoop.timingValue!=0){Browser.mainLoop.scheduler();return}else Browser.mainLoop.timingMode==0&&(Browser.mainLoop.tickStartTime=_emscripten_get_now());Browser.mainLoop.method===\"timeout\"&&Module.ctx&&(Module.printErr(\"Looks like you are rendering without using requestAnimationFrame for the main loop. You should use 0 for the frame rate in emscripten_set_main_loop in order to use requestAnimationFrame, as that can greatly improve your frame rates!\"),Browser.mainLoop.method=\"\"),Browser.mainLoop.runIter(n),!(u<Browser.mainLoop.currentlyRunningMainloop)&&(typeof SDL==\"object\"&&SDL.audio&&SDL.audio.queueNewAudioData&&SDL.audio.queueNewAudioData(),Browser.mainLoop.scheduler())}}},a||(e&&e>0?_emscripten_set_main_loop_timing(0,1e3/e):_emscripten_set_main_loop_timing(1,1),Browser.mainLoop.scheduler()),r)throw\"SimulateInfiniteLoop\"}var Browser={mainLoop:{scheduler:null,method:\"\",currentlyRunningMainloop:0,func:null,arg:0,timingMode:0,timingValue:0,currentFrameNumber:0,queue:[],pause:function(){Browser.mainLoop.scheduler=null,Browser.mainLoop.currentlyRunningMainloop++},resume:function(){Browser.mainLoop.currentlyRunningMainloop++;var t=Browser.mainLoop.timingMode,e=Browser.mainLoop.timingValue,r=Browser.mainLoop.func;Browser.mainLoop.func=null,_emscripten_set_main_loop(r,0,!1,Browser.mainLoop.arg,!0),_emscripten_set_main_loop_timing(t,e),Browser.mainLoop.scheduler()},updateStatus:function(){if(Module.setStatus){var t=Module.statusMessage||\"Please wait...\",e=Browser.mainLoop.remainingBlockers,r=Browser.mainLoop.expectedBlockers;e?e<r?Module.setStatus(t+\" (\"+(r-e)+\"/\"+r+\")\"):Module.setStatus(t):Module.setStatus(\"\")}},runIter:function(t){if(!ABORT){if(Module.preMainLoop){var e=Module.preMainLoop();if(e===!1)return}try{t()}catch(r){if(r instanceof ExitStatus)return;throw r&&typeof r==\"object\"&&r.stack&&Module.printErr(\"exception thrown: \"+[r,r.stack]),r}Module.postMainLoop&&Module.postMainLoop()}}},isFullscreen:!1,pointerLock:!1,moduleContextCreatedCallbacks:[],workers:[],init:function(){if(Module.preloadPlugins||(Module.preloadPlugins=[]),Browser.initted)return;Browser.initted=!0;try{new Blob,Browser.hasBlobConstructor=!0}catch{Browser.hasBlobConstructor=!1,console.log(\"warning: no blob constructor, cannot create blobs with mimetypes\")}Browser.BlobBuilder=typeof MozBlobBuilder<\"u\"?MozBlobBuilder:typeof WebKitBlobBuilder<\"u\"?WebKitBlobBuilder:Browser.hasBlobConstructor?null:console.log(\"warning: no BlobBuilder\"),Browser.URLObject=typeof window<\"u\"?window.URL?window.URL:window.webkitURL:void 0,!Module.noImageDecoding&&typeof Browser.URLObject>\"u\"&&(console.log(\"warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available.\"),Module.noImageDecoding=!0);var t={};t.canHandle=function(n){return!Module.noImageDecoding&&/\\.(jpg|jpeg|png|bmp)$/i.test(n)},t.handle=function(n,u,A,p){var h=null;if(Browser.hasBlobConstructor)try{h=new Blob([n],{type:Browser.getMimetype(u)}),h.size!==n.length&&(h=new Blob([new Uint8Array(n).buffer],{type:Browser.getMimetype(u)}))}catch(x){Runtime.warnOnce(\"Blob constructor present but fails: \"+x+\"; falling back to blob builder\")}if(!h){var E=new Browser.BlobBuilder;E.append(new Uint8Array(n).buffer),h=E.getBlob()}var I=Browser.URLObject.createObjectURL(h),v=new Image;v.onload=function(){assert(v.complete,\"Image \"+u+\" could not be decoded\");var C=document.createElement(\"canvas\");C.width=v.width,C.height=v.height;var R=C.getContext(\"2d\");R.drawImage(v,0,0),Module.preloadedImages[u]=C,Browser.URLObject.revokeObjectURL(I),A&&A(n)},v.onerror=function(C){console.log(\"Image \"+I+\" could not be decoded\"),p&&p()},v.src=I},Module.preloadPlugins.push(t);var e={};e.canHandle=function(n){return!Module.noAudioDecoding&&n.substr(-4)in{\".ogg\":1,\".wav\":1,\".mp3\":1}},e.handle=function(n,u,A,p){var h=!1;function E(R){h||(h=!0,Module.preloadedAudios[u]=R,A&&A(n))}function I(){h||(h=!0,Module.preloadedAudios[u]=new Audio,p&&p())}if(Browser.hasBlobConstructor){try{var v=new Blob([n],{type:Browser.getMimetype(u)})}catch{return I()}var x=Browser.URLObject.createObjectURL(v),C=new Audio;C.addEventListener(\"canplaythrough\",function(){E(C)},!1),C.onerror=function(N){if(h)return;console.log(\"warning: browser could not fully decode audio \"+u+\", trying slower base64 approach\");function U(V){for(var te=\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\",ae=\"=\",fe=\"\",ue=0,me=0,he=0;he<V.length;he++)for(ue=ue<<8|V[he],me+=8;me>=6;){var Be=ue>>me-6&63;me-=6,fe+=te[Be]}return me==2?(fe+=te[(ue&3)<<4],fe+=ae+ae):me==4&&(fe+=te[(ue&15)<<2],fe+=ae),fe}C.src=\"data:audio/x-\"+u.substr(-3)+\";base64,\"+U(n),E(C)},C.src=x,Browser.safeSetTimeout(function(){E(C)},1e4)}else return I()},Module.preloadPlugins.push(e);function r(){Browser.pointerLock=document.pointerLockElement===Module.canvas||document.mozPointerLockElement===Module.canvas||document.webkitPointerLockElement===Module.canvas||document.msPointerLockElement===Module.canvas}var o=Module.canvas;o&&(o.requestPointerLock=o.requestPointerLock||o.mozRequestPointerLock||o.webkitRequestPointerLock||o.msRequestPointerLock||function(){},o.exitPointerLock=document.exitPointerLock||document.mozExitPointerLock||document.webkitExitPointerLock||document.msExitPointerLock||function(){},o.exitPointerLock=o.exitPointerLock.bind(document),document.addEventListener(\"pointerlockchange\",r,!1),document.addEventListener(\"mozpointerlockchange\",r,!1),document.addEventListener(\"webkitpointerlockchange\",r,!1),document.addEventListener(\"mspointerlockchange\",r,!1),Module.elementPointerLock&&o.addEventListener(\"click\",function(a){!Browser.pointerLock&&Module.canvas.requestPointerLock&&(Module.canvas.requestPointerLock(),a.preventDefault())},!1))},createContext:function(t,e,r,o){if(e&&Module.ctx&&t==Module.canvas)return Module.ctx;var a,n;if(e){var u={antialias:!1,alpha:!1};if(o)for(var A in o)u[A]=o[A];n=GL.createContext(t,u),n&&(a=GL.getContext(n).GLctx)}else a=t.getContext(\"2d\");return a?(r&&(e||assert(typeof GLctx>\"u\",\"cannot set in module if GLctx is used, but we are a non-GL context that would replace it\"),Module.ctx=a,e&&GL.makeContextCurrent(n),Module.useWebGL=e,Browser.moduleContextCreatedCallbacks.forEach(function(p){p()}),Browser.init()),a):null},destroyContext:function(t,e,r){},fullscreenHandlersInstalled:!1,lockPointer:void 0,resizeCanvas:void 0,requestFullscreen:function(t,e,r){Browser.lockPointer=t,Browser.resizeCanvas=e,Browser.vrDevice=r,typeof Browser.lockPointer>\"u\"&&(Browser.lockPointer=!0),typeof Browser.resizeCanvas>\"u\"&&(Browser.resizeCanvas=!1),typeof Browser.vrDevice>\"u\"&&(Browser.vrDevice=null);var o=Module.canvas;function a(){Browser.isFullscreen=!1;var u=o.parentNode;(document.fullscreenElement||document.mozFullScreenElement||document.msFullscreenElement||document.webkitFullscreenElement||document.webkitCurrentFullScreenElement)===u?(o.exitFullscreen=document.exitFullscreen||document.cancelFullScreen||document.mozCancelFullScreen||document.msExitFullscreen||document.webkitCancelFullScreen||function(){},o.exitFullscreen=o.exitFullscreen.bind(document),Browser.lockPointer&&o.requestPointerLock(),Browser.isFullscreen=!0,Browser.resizeCanvas&&Browser.setFullscreenCanvasSize()):(u.parentNode.insertBefore(o,u),u.parentNode.removeChild(u),Browser.resizeCanvas&&Browser.setWindowedCanvasSize()),Module.onFullScreen&&Module.onFullScreen(Browser.isFullscreen),Module.onFullscreen&&Module.onFullscreen(Browser.isFullscreen),Browser.updateCanvasDimensions(o)}Browser.fullscreenHandlersInstalled||(Browser.fullscreenHandlersInstalled=!0,document.addEventListener(\"fullscreenchange\",a,!1),document.addEventListener(\"mozfullscreenchange\",a,!1),document.addEventListener(\"webkitfullscreenchange\",a,!1),document.addEventListener(\"MSFullscreenChange\",a,!1));var n=document.createElement(\"div\");o.parentNode.insertBefore(n,o),n.appendChild(o),n.requestFullscreen=n.requestFullscreen||n.mozRequestFullScreen||n.msRequestFullscreen||(n.webkitRequestFullscreen?function(){n.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT)}:null)||(n.webkitRequestFullScreen?function(){n.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT)}:null),r?n.requestFullscreen({vrDisplay:r}):n.requestFullscreen()},requestFullScreen:function(t,e,r){return Module.printErr(\"Browser.requestFullScreen() is deprecated. Please call Browser.requestFullscreen instead.\"),Browser.requestFullScreen=function(o,a,n){return Browser.requestFullscreen(o,a,n)},Browser.requestFullscreen(t,e,r)},nextRAF:0,fakeRequestAnimationFrame:function(t){var e=Date.now();if(Browser.nextRAF===0)Browser.nextRAF=e+1e3/60;else for(;e+2>=Browser.nextRAF;)Browser.nextRAF+=1e3/60;var r=Math.max(Browser.nextRAF-e,0);setTimeout(t,r)},requestAnimationFrame:function t(e){typeof window>\"u\"?Browser.fakeRequestAnimationFrame(e):(window.requestAnimationFrame||(window.requestAnimationFrame=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame||window.oRequestAnimationFrame||Browser.fakeRequestAnimationFrame),window.requestAnimationFrame(e))},safeCallback:function(t){return function(){if(!ABORT)return t.apply(null,arguments)}},allowAsyncCallbacks:!0,queuedAsyncCallbacks:[],pauseAsyncCallbacks:function(){Browser.allowAsyncCallbacks=!1},resumeAsyncCallbacks:function(){if(Browser.allowAsyncCallbacks=!0,Browser.queuedAsyncCallbacks.length>0){var t=Browser.queuedAsyncCallbacks;Browser.queuedAsyncCallbacks=[],t.forEach(function(e){e()})}},safeRequestAnimationFrame:function(t){return Browser.requestAnimationFrame(function(){ABORT||(Browser.allowAsyncCallbacks?t():Browser.queuedAsyncCallbacks.push(t))})},safeSetTimeout:function(t,e){return Module.noExitRuntime=!0,setTimeout(function(){ABORT||(Browser.allowAsyncCallbacks?t():Browser.queuedAsyncCallbacks.push(t))},e)},safeSetInterval:function(t,e){return Module.noExitRuntime=!0,setInterval(function(){ABORT||Browser.allowAsyncCallbacks&&t()},e)},getMimetype:function(t){return{jpg:\"image/jpeg\",jpeg:\"image/jpeg\",png:\"image/png\",bmp:\"image/bmp\",ogg:\"audio/ogg\",wav:\"audio/wav\",mp3:\"audio/mpeg\"}[t.substr(t.lastIndexOf(\".\")+1)]},getUserMedia:function(t){window.getUserMedia||(window.getUserMedia=navigator.getUserMedia||navigator.mozGetUserMedia),window.getUserMedia(t)},getMovementX:function(t){return t.movementX||t.mozMovementX||t.webkitMovementX||0},getMovementY:function(t){return t.movementY||t.mozMovementY||t.webkitMovementY||0},getMouseWheelDelta:function(t){var e=0;switch(t.type){case\"DOMMouseScroll\":e=t.detail;break;case\"mousewheel\":e=t.wheelDelta;break;case\"wheel\":e=t.deltaY;break;default:throw\"unrecognized mouse wheel event: \"+t.type}return e},mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,touches:{},lastTouches:{},calculateMouseEvent:function(t){if(Browser.pointerLock)t.type!=\"mousemove\"&&\"mozMovementX\"in t?Browser.mouseMovementX=Browser.mouseMovementY=0:(Browser.mouseMovementX=Browser.getMovementX(t),Browser.mouseMovementY=Browser.getMovementY(t)),typeof SDL<\"u\"?(Browser.mouseX=SDL.mouseX+Browser.mouseMovementX,Browser.mouseY=SDL.mouseY+Browser.mouseMovementY):(Browser.mouseX+=Browser.mouseMovementX,Browser.mouseY+=Browser.mouseMovementY);else{var e=Module.canvas.getBoundingClientRect(),r=Module.canvas.width,o=Module.canvas.height,a=typeof window.scrollX<\"u\"?window.scrollX:window.pageXOffset,n=typeof window.scrollY<\"u\"?window.scrollY:window.pageYOffset;if(t.type===\"touchstart\"||t.type===\"touchend\"||t.type===\"touchmove\"){var u=t.touch;if(u===void 0)return;var A=u.pageX-(a+e.left),p=u.pageY-(n+e.top);A=A*(r/e.width),p=p*(o/e.height);var h={x:A,y:p};if(t.type===\"touchstart\")Browser.lastTouches[u.identifier]=h,Browser.touches[u.identifier]=h;else if(t.type===\"touchend\"||t.type===\"touchmove\"){var E=Browser.touches[u.identifier];E||(E=h),Browser.lastTouches[u.identifier]=E,Browser.touches[u.identifier]=h}return}var I=t.pageX-(a+e.left),v=t.pageY-(n+e.top);I=I*(r/e.width),v=v*(o/e.height),Browser.mouseMovementX=I-Browser.mouseX,Browser.mouseMovementY=v-Browser.mouseY,Browser.mouseX=I,Browser.mouseY=v}},asyncLoad:function(t,e,r,o){var a=o?\"\":\"al \"+t;Module.readAsync(t,function(n){assert(n,'Loading data file \"'+t+'\" failed (no arrayBuffer).'),e(new Uint8Array(n)),a&&removeRunDependency(a)},function(n){if(r)r();else throw'Loading data file \"'+t+'\" failed.'}),a&&addRunDependency(a)},resizeListeners:[],updateResizeListeners:function(){var t=Module.canvas;Browser.resizeListeners.forEach(function(e){e(t.width,t.height)})},setCanvasSize:function(t,e,r){var o=Module.canvas;Browser.updateCanvasDimensions(o,t,e),r||Browser.updateResizeListeners()},windowedWidth:0,windowedHeight:0,setFullscreenCanvasSize:function(){if(typeof SDL<\"u\"){var t=HEAPU32[SDL.screen+Runtime.QUANTUM_SIZE*0>>2];t=t|8388608,HEAP32[SDL.screen+Runtime.QUANTUM_SIZE*0>>2]=t}Browser.updateResizeListeners()},setWindowedCanvasSize:function(){if(typeof SDL<\"u\"){var t=HEAPU32[SDL.screen+Runtime.QUANTUM_SIZE*0>>2];t=t&-8388609,HEAP32[SDL.screen+Runtime.QUANTUM_SIZE*0>>2]=t}Browser.updateResizeListeners()},updateCanvasDimensions:function(t,e,r){e&&r?(t.widthNative=e,t.heightNative=r):(e=t.widthNative,r=t.heightNative);var o=e,a=r;if(Module.forcedAspectRatio&&Module.forcedAspectRatio>0&&(o/a<Module.forcedAspectRatio?o=Math.round(a*Module.forcedAspectRatio):a=Math.round(o/Module.forcedAspectRatio)),(document.fullscreenElement||document.mozFullScreenElement||document.msFullscreenElement||document.webkitFullscreenElement||document.webkitCurrentFullScreenElement)===t.parentNode&&typeof screen<\"u\"){var n=Math.min(screen.width/o,screen.height/a);o=Math.round(o*n),a=Math.round(a*n)}Browser.resizeCanvas?(t.width!=o&&(t.width=o),t.height!=a&&(t.height=a),typeof t.style<\"u\"&&(t.style.removeProperty(\"width\"),t.style.removeProperty(\"height\"))):(t.width!=e&&(t.width=e),t.height!=r&&(t.height=r),typeof t.style<\"u\"&&(o!=e||a!=r?(t.style.setProperty(\"width\",o+\"px\",\"important\"),t.style.setProperty(\"height\",a+\"px\",\"important\")):(t.style.removeProperty(\"width\"),t.style.removeProperty(\"height\"))))},wgetRequests:{},nextWgetRequestHandle:0,getNextWgetRequestHandle:function(){var t=Browser.nextWgetRequestHandle;return Browser.nextWgetRequestHandle++,t}},SYSCALLS={varargs:0,get:function(t){SYSCALLS.varargs+=4;var e=HEAP32[SYSCALLS.varargs-4>>2];return e},getStr:function(){var t=Pointer_stringify(SYSCALLS.get());return t},get64:function(){var t=SYSCALLS.get(),e=SYSCALLS.get();return t>=0?assert(e===0):assert(e===-1),t},getZero:function(){assert(SYSCALLS.get()===0)}};function ___syscall6(t,e){SYSCALLS.varargs=e;try{var r=SYSCALLS.getStreamFromFD();return FS.close(r),0}catch(o){return(typeof FS>\"u\"||!(o instanceof FS.ErrnoError))&&abort(o),-o.errno}}function ___syscall54(t,e){SYSCALLS.varargs=e;try{return 0}catch(r){return(typeof FS>\"u\"||!(r instanceof FS.ErrnoError))&&abort(r),-r.errno}}function _typeModule(t){var e=[[0,1,\"X\"],[1,1,\"const X\"],[128,1,\"X *\"],[256,1,\"X &\"],[384,1,\"X &&\"],[512,1,\"std::shared_ptr<X>\"],[640,1,\"std::unique_ptr<X>\"],[5120,1,\"std::vector<X>\"],[6144,2,\"std::array<X, Y>\"],[9216,-1,\"std::function<X (Y)>\"]];function r(p,h,E,I,v,x){if(h==1){var C=I&896;(C==128||C==256||C==384)&&(p=\"X const\")}var R;return x?R=E.replace(\"X\",p).replace(\"Y\",v):R=p.replace(\"X\",E).replace(\"Y\",v),R.replace(/([*&]) (?=[*&])/g,\"$1\")}function o(p,h,E,I,v){throw new Error(p+\" type \"+E.replace(\"X\",h+\"?\")+(I?\" with flag \"+I:\"\")+\" in \"+v)}function a(p,h,E,I,v,x,C,R){x===void 0&&(x=\"X\"),R===void 0&&(R=1);var N=E(p);if(N)return N;var U=I(p),V=U.placeholderFlag,te=e[V];C&&te&&(x=r(C[2],C[0],x,te[0],\"?\",!0));var ae;V==0&&(ae=\"Unbound\"),V>=10&&(ae=\"Corrupt\"),R>20&&(ae=\"Deeply nested\"),ae&&o(ae,p,x,V,v||\"?\");var fe=U.paramList[0],ue=a(fe,h,E,I,v,x,te,R+1),me,he={flags:te[0],id:p,name:\"\",paramList:[ue]},Be=[],we=\"?\";switch(U.placeholderFlag){case 1:me=ue.spec;break;case 2:if((ue.flags&15360)==1024&&ue.spec.ptrSize==1){he.flags=7168;break}case 3:case 6:case 5:me=ue.spec,ue.flags&15360;break;case 8:we=\"\"+U.paramList[1],he.paramList.push(U.paramList[1]);break;case 9:for(var g=0,Ee=U.paramList[1];g<Ee.length;g++){var Pe=Ee[g],ce=a(Pe,h,E,I,v,x,te,R+1);Be.push(ce.name),he.paramList.push(ce)}we=Be.join(\", \");break;default:break}if(he.name=r(te[2],te[0],ue.name,ue.flags,we),me){for(var ne=0,ee=Object.keys(me);ne<ee.length;ne++){var Ie=ee[ne];he[Ie]=he[Ie]||me[Ie]}he.flags|=me.flags}return n(h,he)}function n(p,h){var E=h.flags,I=E&896,v=E&15360;return!h.name&&v==1024&&(h.ptrSize==1?h.name=(E&16?\"\":(E&8?\"un\":\"\")+\"signed \")+\"char\":h.name=(E&8?\"u\":\"\")+(E&32?\"float\":\"int\")+(h.ptrSize*8+\"_t\")),h.ptrSize==8&&!(E&32)&&(v=64),v==2048&&(I==512||I==640?v=4096:I&&(v=3072)),p(v,h)}var u=function(){function p(h){this.id=h.id,this.name=h.name,this.flags=h.flags,this.spec=h}return p.prototype.toString=function(){return this.name},p}(),A={Type:u,getComplexType:a,makeType:n,structureList:e};return t.output=A,t.output||A}function __nbind_register_type(t,e){var r=_nbind.readAsciiString(e),o={flags:10240,id:t,name:r};_nbind.makeType(_nbind.constructType,o)}function __nbind_register_callback_signature(t,e){var r=_nbind.readTypeIdList(t,e),o=_nbind.callbackSignatureList.length;return _nbind.callbackSignatureList[o]=_nbind.makeJSCaller(r),o}function __extends(t,e){for(var r in e)e.hasOwnProperty(r)&&(t[r]=e[r]);function o(){this.constructor=t}o.prototype=e.prototype,t.prototype=new o}function __nbind_register_class(t,e,r,o,a,n,u){var A=_nbind.readAsciiString(u),p=_nbind.readPolicyList(e),h=HEAPU32.subarray(t/4,t/4+2),E={flags:2048|(p.Value?2:0),id:h[0],name:A},I=_nbind.makeType(_nbind.constructType,E);I.ptrType=_nbind.getComplexType(h[1],_nbind.constructType,_nbind.getType,_nbind.queryType),I.destroy=_nbind.makeMethodCaller(I.ptrType,{boundID:E.id,flags:0,name:\"destroy\",num:0,ptr:n,title:I.name+\".free\",typeList:[\"void\",\"uint32_t\",\"uint32_t\"]}),a&&(I.superIdList=Array.prototype.slice.call(HEAPU32.subarray(r/4,r/4+a)),I.upcastList=Array.prototype.slice.call(HEAPU32.subarray(o/4,o/4+a))),Module[I.name]=I.makeBound(p),_nbind.BindClass.list.push(I)}function _removeAccessorPrefix(t){var e=/^[Gg]et_?([A-Z]?([A-Z]?))/;return t.replace(e,function(r,o,a){return a?o:o.toLowerCase()})}function __nbind_register_function(t,e,r,o,a,n,u,A,p,h){var E=_nbind.getType(t),I=_nbind.readPolicyList(e),v=_nbind.readTypeIdList(r,o),x;if(u==5)x=[{direct:a,name:\"__nbindConstructor\",ptr:0,title:E.name+\" constructor\",typeList:[\"uint32_t\"].concat(v.slice(1))},{direct:n,name:\"__nbindValueConstructor\",ptr:0,title:E.name+\" value constructor\",typeList:[\"void\",\"uint32_t\"].concat(v.slice(1))}];else{var C=_nbind.readAsciiString(A),R=(E.name&&E.name+\".\")+C;(u==3||u==4)&&(C=_removeAccessorPrefix(C)),x=[{boundID:t,direct:n,name:C,ptr:a,title:R,typeList:v}]}for(var N=0,U=x;N<U.length;N++){var V=U[N];V.signatureType=u,V.policyTbl=I,V.num=p,V.flags=h,E.addMethod(V)}}function _nbind_value(t,e){_nbind.typeNameTbl[t]||_nbind.throwError(\"Unknown value type \"+t),Module.NBind.bind_value(t,e),_defineHidden(_nbind.typeNameTbl[t].proto.prototype.__nbindValueConstructor)(e.prototype,\"__nbindValueConstructor\")}Module._nbind_value=_nbind_value;function __nbind_get_value_object(t,e){var r=_nbind.popValue(t);if(!r.fromJS)throw new Error(\"Object \"+r+\" has no fromJS function\");r.fromJS(function(){r.__nbindValueConstructor.apply(this,Array.prototype.concat.apply([e],arguments))})}function _emscripten_memcpy_big(t,e,r){return HEAPU8.set(HEAPU8.subarray(e,e+r),t),t}function __nbind_register_primitive(t,e,r){var o={flags:1024|r,id:t,ptrSize:e};_nbind.makeType(_nbind.constructType,o)}var cttz_i8=allocate([8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0],\"i8\",ALLOC_STATIC);function ___setErrNo(t){return Module.___errno_location&&(HEAP32[Module.___errno_location()>>2]=t),t}function _llvm_stacksave(){var t=_llvm_stacksave;return t.LLVM_SAVEDSTACKS||(t.LLVM_SAVEDSTACKS=[]),t.LLVM_SAVEDSTACKS.push(Runtime.stackSave()),t.LLVM_SAVEDSTACKS.length-1}function ___syscall140(t,e){SYSCALLS.varargs=e;try{var r=SYSCALLS.getStreamFromFD(),o=SYSCALLS.get(),a=SYSCALLS.get(),n=SYSCALLS.get(),u=SYSCALLS.get(),A=a;return FS.llseek(r,A,u),HEAP32[n>>2]=r.position,r.getdents&&A===0&&u===0&&(r.getdents=null),0}catch(p){return(typeof FS>\"u\"||!(p instanceof FS.ErrnoError))&&abort(p),-p.errno}}function ___syscall146(t,e){SYSCALLS.varargs=e;try{var r=SYSCALLS.get(),o=SYSCALLS.get(),a=SYSCALLS.get(),n=0;___syscall146.buffer||(___syscall146.buffers=[null,[],[]],___syscall146.printChar=function(E,I){var v=___syscall146.buffers[E];assert(v),I===0||I===10?((E===1?Module.print:Module.printErr)(UTF8ArrayToString(v,0)),v.length=0):v.push(I)});for(var u=0;u<a;u++){for(var A=HEAP32[o+u*8>>2],p=HEAP32[o+(u*8+4)>>2],h=0;h<p;h++)___syscall146.printChar(r,HEAPU8[A+h]);n+=p}return n}catch(E){return(typeof FS>\"u\"||!(E instanceof FS.ErrnoError))&&abort(E),-E.errno}}function __nbind_finish(){for(var t=0,e=_nbind.BindClass.list;t<e.length;t++){var r=e[t];r.finish()}}var ___dso_handle=STATICTOP;STATICTOP+=16,function(_nbind){var typeIdTbl={};_nbind.typeNameTbl={};var Pool=function(){function t(){}return t.lalloc=function(e){e=e+7&-8;var r=HEAPU32[t.usedPtr];if(e>t.pageSize/2||e>t.pageSize-r){var o=_nbind.typeNameTbl.NBind.proto;return o.lalloc(e)}else return HEAPU32[t.usedPtr]=r+e,t.rootPtr+r},t.lreset=function(e,r){var o=HEAPU32[t.pagePtr];if(o){var a=_nbind.typeNameTbl.NBind.proto;a.lreset(e,r)}else HEAPU32[t.usedPtr]=e},t}();_nbind.Pool=Pool;function constructType(t,e){var r=t==10240?_nbind.makeTypeNameTbl[e.name]||_nbind.BindType:_nbind.makeTypeKindTbl[t],o=new r(e);return typeIdTbl[e.id]=o,_nbind.typeNameTbl[e.name]=o,o}_nbind.constructType=constructType;function getType(t){return typeIdTbl[t]}_nbind.getType=getType;function queryType(t){var e=HEAPU8[t],r=_nbind.structureList[e][1];t/=4,r<0&&(++t,r=HEAPU32[t]+1);var o=Array.prototype.slice.call(HEAPU32.subarray(t+1,t+1+r));return e==9&&(o=[o[0],o.slice(1)]),{paramList:o,placeholderFlag:e}}_nbind.queryType=queryType;function getTypes(t,e){return t.map(function(r){return typeof r==\"number\"?_nbind.getComplexType(r,constructType,getType,queryType,e):_nbind.typeNameTbl[r]})}_nbind.getTypes=getTypes;function readTypeIdList(t,e){return Array.prototype.slice.call(HEAPU32,t/4,t/4+e)}_nbind.readTypeIdList=readTypeIdList;function readAsciiString(t){for(var e=t;HEAPU8[e++];);return String.fromCharCode.apply(\"\",HEAPU8.subarray(t,e-1))}_nbind.readAsciiString=readAsciiString;function readPolicyList(t){var e={};if(t)for(;;){var r=HEAPU32[t/4];if(!r)break;e[readAsciiString(r)]=!0,t+=4}return e}_nbind.readPolicyList=readPolicyList;function getDynCall(t,e){var r={float32_t:\"d\",float64_t:\"d\",int64_t:\"d\",uint64_t:\"d\",void:\"v\"},o=t.map(function(n){return r[n.name]||\"i\"}).join(\"\"),a=Module[\"dynCall_\"+o];if(!a)throw new Error(\"dynCall_\"+o+\" not found for \"+e+\"(\"+t.map(function(n){return n.name}).join(\", \")+\")\");return a}_nbind.getDynCall=getDynCall;function addMethod(t,e,r,o){var a=t[e];t.hasOwnProperty(e)&&a?((a.arity||a.arity===0)&&(a=_nbind.makeOverloader(a,a.arity),t[e]=a),a.addMethod(r,o)):(r.arity=o,t[e]=r)}_nbind.addMethod=addMethod;function throwError(t){throw new Error(t)}_nbind.throwError=throwError,_nbind.bigEndian=!1,_a=_typeModule(_typeModule),_nbind.Type=_a.Type,_nbind.makeType=_a.makeType,_nbind.getComplexType=_a.getComplexType,_nbind.structureList=_a.structureList;var BindType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.heap=HEAPU32,r.ptrSize=4,r}return e.prototype.needsWireRead=function(r){return!!this.wireRead||!!this.makeWireRead},e.prototype.needsWireWrite=function(r){return!!this.wireWrite||!!this.makeWireWrite},e}(_nbind.Type);_nbind.BindType=BindType;var PrimitiveType=function(t){__extends(e,t);function e(r){var o=t.call(this,r)||this,a=r.flags&32?{32:HEAPF32,64:HEAPF64}:r.flags&8?{8:HEAPU8,16:HEAPU16,32:HEAPU32}:{8:HEAP8,16:HEAP16,32:HEAP32};return o.heap=a[r.ptrSize*8],o.ptrSize=r.ptrSize,o}return e.prototype.needsWireWrite=function(r){return!!r&&!!r.Strict},e.prototype.makeWireWrite=function(r,o){return o&&o.Strict&&function(a){if(typeof a==\"number\")return a;throw new Error(\"Type mismatch\")}},e}(BindType);_nbind.PrimitiveType=PrimitiveType;function pushCString(t,e){if(t==null){if(e&&e.Nullable)return 0;throw new Error(\"Type mismatch\")}if(e&&e.Strict){if(typeof t!=\"string\")throw new Error(\"Type mismatch\")}else t=t.toString();var r=Module.lengthBytesUTF8(t)+1,o=_nbind.Pool.lalloc(r);return Module.stringToUTF8Array(t,HEAPU8,o,r),o}_nbind.pushCString=pushCString;function popCString(t){return t===0?null:Module.Pointer_stringify(t)}_nbind.popCString=popCString;var CStringType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireRead=popCString,r.wireWrite=pushCString,r.readResources=[_nbind.resources.pool],r.writeResources=[_nbind.resources.pool],r}return e.prototype.makeWireWrite=function(r,o){return function(a){return pushCString(a,o)}},e}(BindType);_nbind.CStringType=CStringType;var BooleanType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireRead=function(o){return!!o},r}return e.prototype.needsWireWrite=function(r){return!!r&&!!r.Strict},e.prototype.makeWireRead=function(r){return\"!!(\"+r+\")\"},e.prototype.makeWireWrite=function(r,o){return o&&o.Strict&&function(a){if(typeof a==\"boolean\")return a;throw new Error(\"Type mismatch\")}||r},e}(BindType);_nbind.BooleanType=BooleanType;var Wrapper=function(){function t(){}return t.prototype.persist=function(){this.__nbindState|=1},t}();_nbind.Wrapper=Wrapper;function makeBound(t,e){var r=function(o){__extends(a,o);function a(n,u,A,p){var h=o.call(this)||this;if(!(h instanceof a))return new(Function.prototype.bind.apply(a,Array.prototype.concat.apply([null],arguments)));var E=u,I=A,v=p;if(n!==_nbind.ptrMarker){var x=h.__nbindConstructor.apply(h,arguments);E=4608,v=HEAPU32[x/4],I=HEAPU32[x/4+1]}var C={configurable:!0,enumerable:!1,value:null,writable:!1},R={__nbindFlags:E,__nbindPtr:I};v&&(R.__nbindShared=v,_nbind.mark(h));for(var N=0,U=Object.keys(R);N<U.length;N++){var V=U[N];C.value=R[V],Object.defineProperty(h,V,C)}return _defineHidden(0)(h,\"__nbindState\"),h}return a.prototype.free=function(){e.destroy.call(this,this.__nbindShared,this.__nbindFlags),this.__nbindState|=2,disableMember(this,\"__nbindShared\"),disableMember(this,\"__nbindPtr\")},a}(Wrapper);return __decorate([_defineHidden()],r.prototype,\"__nbindConstructor\",void 0),__decorate([_defineHidden()],r.prototype,\"__nbindValueConstructor\",void 0),__decorate([_defineHidden(t)],r.prototype,\"__nbindPolicies\",void 0),r}_nbind.makeBound=makeBound;function disableMember(t,e){function r(){throw new Error(\"Accessing deleted object\")}Object.defineProperty(t,e,{configurable:!1,enumerable:!1,get:r,set:r})}_nbind.ptrMarker={};var BindClass=function(t){__extends(e,t);function e(r){var o=t.call(this,r)||this;return o.wireRead=function(a){return _nbind.popValue(a,o.ptrType)},o.wireWrite=function(a){return pushPointer(a,o.ptrType,!0)},o.pendingSuperCount=0,o.ready=!1,o.methodTbl={},r.paramList?(o.classType=r.paramList[0].classType,o.proto=o.classType.proto):o.classType=o,o}return e.prototype.makeBound=function(r){var o=_nbind.makeBound(r,this);return this.proto=o,this.ptrType.proto=o,o},e.prototype.addMethod=function(r){var o=this.methodTbl[r.name]||[];o.push(r),this.methodTbl[r.name]=o},e.prototype.registerMethods=function(r,o){for(var a,n=0,u=Object.keys(r.methodTbl);n<u.length;n++)for(var A=u[n],p=r.methodTbl[A],h=0,E=p;h<E.length;h++){var I=E[h],v=void 0,x=void 0;if(v=this.proto.prototype,!(o&&I.signatureType!=1))switch(I.signatureType){case 1:v=this.proto;case 5:x=_nbind.makeCaller(I),_nbind.addMethod(v,I.name,x,I.typeList.length-1);break;case 4:a=_nbind.makeMethodCaller(r.ptrType,I);break;case 3:Object.defineProperty(v,I.name,{configurable:!0,enumerable:!1,get:_nbind.makeMethodCaller(r.ptrType,I),set:a});break;case 2:x=_nbind.makeMethodCaller(r.ptrType,I),_nbind.addMethod(v,I.name,x,I.typeList.length-1);break;default:break}}},e.prototype.registerSuperMethods=function(r,o,a){if(!a[r.name]){a[r.name]=!0;for(var n=0,u,A=0,p=r.superIdList||[];A<p.length;A++){var h=p[A],E=_nbind.getType(h);n++<o||o<0?u=-1:u=0,this.registerSuperMethods(E,u,a)}this.registerMethods(r,o<0)}},e.prototype.finish=function(){if(this.ready)return this;this.ready=!0,this.superList=(this.superIdList||[]).map(function(a){return _nbind.getType(a).finish()});var r=this.proto;if(this.superList.length){var o=function(){this.constructor=r};o.prototype=this.superList[0].proto.prototype,r.prototype=new o}return r!=Module&&(r.prototype.__nbindType=this),this.registerSuperMethods(this,1,{}),this},e.prototype.upcastStep=function(r,o){if(r==this)return o;for(var a=0;a<this.superList.length;++a){var n=this.superList[a].upcastStep(r,_nbind.callUpcast(this.upcastList[a],o));if(n)return n}return 0},e}(_nbind.BindType);BindClass.list=[],_nbind.BindClass=BindClass;function popPointer(t,e){return t?new e.proto(_nbind.ptrMarker,e.flags,t):null}_nbind.popPointer=popPointer;function pushPointer(t,e,r){if(!(t instanceof _nbind.Wrapper)){if(r)return _nbind.pushValue(t);throw new Error(\"Type mismatch\")}var o=t.__nbindPtr,a=t.__nbindType.classType,n=e.classType;if(t instanceof e.proto)for(;a!=n;)o=_nbind.callUpcast(a.upcastList[0],o),a=a.superList[0];else if(o=a.upcastStep(n,o),!o)throw new Error(\"Type mismatch\");return o}_nbind.pushPointer=pushPointer;function pushMutablePointer(t,e){var r=pushPointer(t,e);if(t.__nbindFlags&1)throw new Error(\"Passing a const value as a non-const argument\");return r}var BindClassPtr=function(t){__extends(e,t);function e(r){var o=t.call(this,r)||this;o.classType=r.paramList[0].classType,o.proto=o.classType.proto;var a=r.flags&1,n=(o.flags&896)==256&&r.flags&2,u=a?pushPointer:pushMutablePointer,A=n?_nbind.popValue:popPointer;return o.makeWireWrite=function(p,h){return h.Nullable?function(E){return E?u(E,o):0}:function(E){return u(E,o)}},o.wireRead=function(p){return A(p,o)},o.wireWrite=function(p){return u(p,o)},o}return e}(_nbind.BindType);_nbind.BindClassPtr=BindClassPtr;function popShared(t,e){var r=HEAPU32[t/4],o=HEAPU32[t/4+1];return o?new e.proto(_nbind.ptrMarker,e.flags,o,r):null}_nbind.popShared=popShared;function pushShared(t,e){if(!(t instanceof e.proto))throw new Error(\"Type mismatch\");return t.__nbindShared}function pushMutableShared(t,e){if(!(t instanceof e.proto))throw new Error(\"Type mismatch\");if(t.__nbindFlags&1)throw new Error(\"Passing a const value as a non-const argument\");return t.__nbindShared}var SharedClassPtr=function(t){__extends(e,t);function e(r){var o=t.call(this,r)||this;o.readResources=[_nbind.resources.pool],o.classType=r.paramList[0].classType,o.proto=o.classType.proto;var a=r.flags&1,n=a?pushShared:pushMutableShared;return o.wireRead=function(u){return popShared(u,o)},o.wireWrite=function(u){return n(u,o)},o}return e}(_nbind.BindType);_nbind.SharedClassPtr=SharedClassPtr,_nbind.externalList=[0];var firstFreeExternal=0,External=function(){function t(e){this.refCount=1,this.data=e}return t.prototype.register=function(){var e=firstFreeExternal;return e?firstFreeExternal=_nbind.externalList[e]:e=_nbind.externalList.length,_nbind.externalList[e]=this,e},t.prototype.reference=function(){++this.refCount},t.prototype.dereference=function(e){--this.refCount==0&&(this.free&&this.free(),_nbind.externalList[e]=firstFreeExternal,firstFreeExternal=e)},t}();_nbind.External=External;function popExternal(t){var e=_nbind.externalList[t];return e.dereference(t),e.data}function pushExternal(t){var e=new External(t);return e.reference(),e.register()}var ExternalType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireRead=popExternal,r.wireWrite=pushExternal,r}return e}(_nbind.BindType);_nbind.ExternalType=ExternalType,_nbind.callbackSignatureList=[];var CallbackType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireWrite=function(o){return typeof o!=\"function\"&&_nbind.throwError(\"Type mismatch\"),new _nbind.External(o).register()},r}return e}(_nbind.BindType);_nbind.CallbackType=CallbackType,_nbind.valueList=[0];var firstFreeValue=0;function pushValue(t){var e=firstFreeValue;return e?firstFreeValue=_nbind.valueList[e]:e=_nbind.valueList.length,_nbind.valueList[e]=t,e*2+1}_nbind.pushValue=pushValue;function popValue(t,e){if(t||_nbind.throwError(\"Value type JavaScript class is missing or not registered\"),t&1){t>>=1;var r=_nbind.valueList[t];return _nbind.valueList[t]=firstFreeValue,firstFreeValue=t,r}else{if(e)return _nbind.popShared(t,e);throw new Error(\"Invalid value slot \"+t)}}_nbind.popValue=popValue;var valueBase=18446744073709552e3;function push64(t){return typeof t==\"number\"?t:pushValue(t)*4096+valueBase}function pop64(t){return t<valueBase?t:popValue((t-valueBase)/4096)}var CreateValueType=function(t){__extends(e,t);function e(){return t!==null&&t.apply(this,arguments)||this}return e.prototype.makeWireWrite=function(r){return\"(_nbind.pushValue(new \"+r+\"))\"},e}(_nbind.BindType);_nbind.CreateValueType=CreateValueType;var Int64Type=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireWrite=push64,r.wireRead=pop64,r}return e}(_nbind.BindType);_nbind.Int64Type=Int64Type;function pushArray(t,e){if(!t)return 0;var r=t.length;if((e.size||e.size===0)&&r<e.size)throw new Error(\"Type mismatch\");var o=e.memberType.ptrSize,a=_nbind.Pool.lalloc(4+r*o);HEAPU32[a/4]=r;var n=e.memberType.heap,u=(a+4)/o,A=e.memberType.wireWrite,p=0;if(A)for(;p<r;)n[u++]=A(t[p++]);else for(;p<r;)n[u++]=t[p++];return a}_nbind.pushArray=pushArray;function popArray(t,e){if(t===0)return null;var r=HEAPU32[t/4],o=new Array(r),a=e.memberType.heap;t=(t+4)/e.memberType.ptrSize;var n=e.memberType.wireRead,u=0;if(n)for(;u<r;)o[u++]=n(a[t++]);else for(;u<r;)o[u++]=a[t++];return o}_nbind.popArray=popArray;var ArrayType=function(t){__extends(e,t);function e(r){var o=t.call(this,r)||this;return o.wireRead=function(a){return popArray(a,o)},o.wireWrite=function(a){return pushArray(a,o)},o.readResources=[_nbind.resources.pool],o.writeResources=[_nbind.resources.pool],o.memberType=r.paramList[0],r.paramList[1]&&(o.size=r.paramList[1]),o}return e}(_nbind.BindType);_nbind.ArrayType=ArrayType;function pushString(t,e){if(t==null)if(e&&e.Nullable)t=\"\";else throw new Error(\"Type mismatch\");if(e&&e.Strict){if(typeof t!=\"string\")throw new Error(\"Type mismatch\")}else t=t.toString();var r=Module.lengthBytesUTF8(t),o=_nbind.Pool.lalloc(4+r+1);return HEAPU32[o/4]=r,Module.stringToUTF8Array(t,HEAPU8,o+4,r+1),o}_nbind.pushString=pushString;function popString(t){if(t===0)return null;var e=HEAPU32[t/4];return Module.Pointer_stringify(t+4,e)}_nbind.popString=popString;var StringType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireRead=popString,r.wireWrite=pushString,r.readResources=[_nbind.resources.pool],r.writeResources=[_nbind.resources.pool],r}return e.prototype.makeWireWrite=function(r,o){return function(a){return pushString(a,o)}},e}(_nbind.BindType);_nbind.StringType=StringType;function makeArgList(t){return Array.apply(null,Array(t)).map(function(e,r){return\"a\"+(r+1)})}function anyNeedsWireWrite(t,e){return t.reduce(function(r,o){return r||o.needsWireWrite(e)},!1)}function anyNeedsWireRead(t,e){return t.reduce(function(r,o){return r||!!o.needsWireRead(e)},!1)}function makeWireRead(t,e,r,o){var a=t.length;return r.makeWireRead?r.makeWireRead(o,t,a):r.wireRead?(t[a]=r.wireRead,\"(convertParamList[\"+a+\"](\"+o+\"))\"):o}function makeWireWrite(t,e,r,o){var a,n=t.length;return r.makeWireWrite?a=r.makeWireWrite(o,e,t,n):a=r.wireWrite,a?typeof a==\"string\"?a:(t[n]=a,\"(convertParamList[\"+n+\"](\"+o+\"))\"):o}function buildCallerFunction(dynCall,ptrType,ptr,num,policyTbl,needsWireWrite,prefix,returnType,argTypeList,mask,err){var argList=makeArgList(argTypeList.length),convertParamList=[],callExpression=makeWireRead(convertParamList,policyTbl,returnType,\"dynCall(\"+[prefix].concat(argList.map(function(t,e){return makeWireWrite(convertParamList,policyTbl,argTypeList[e],t)})).join(\",\")+\")\"),resourceSet=_nbind.listResources([returnType],argTypeList),sourceCode=\"function(\"+argList.join(\",\")+\"){\"+(mask?\"this.__nbindFlags&mask&&err();\":\"\")+resourceSet.makeOpen()+\"var r=\"+callExpression+\";\"+resourceSet.makeClose()+\"return r;}\";return eval(\"(\"+sourceCode+\")\")}function buildJSCallerFunction(returnType,argTypeList){var argList=makeArgList(argTypeList.length),convertParamList=[],callExpression=makeWireWrite(convertParamList,null,returnType,\"_nbind.externalList[num].data(\"+argList.map(function(t,e){return makeWireRead(convertParamList,null,argTypeList[e],t)}).join(\",\")+\")\"),resourceSet=_nbind.listResources(argTypeList,[returnType]);resourceSet.remove(_nbind.resources.pool);var sourceCode=\"function(\"+[\"dummy\",\"num\"].concat(argList).join(\",\")+\"){\"+resourceSet.makeOpen()+\"var r=\"+callExpression+\";\"+resourceSet.makeClose()+\"return r;}\";return eval(\"(\"+sourceCode+\")\")}_nbind.buildJSCallerFunction=buildJSCallerFunction;function makeJSCaller(t){var e=t.length-1,r=_nbind.getTypes(t,\"callback\"),o=r[0],a=r.slice(1),n=anyNeedsWireRead(a,null),u=o.needsWireWrite(null);if(!u&&!n)switch(e){case 0:return function(A,p){return _nbind.externalList[p].data()};case 1:return function(A,p,h){return _nbind.externalList[p].data(h)};case 2:return function(A,p,h,E){return _nbind.externalList[p].data(h,E)};case 3:return function(A,p,h,E,I){return _nbind.externalList[p].data(h,E,I)};default:break}return buildJSCallerFunction(o,a)}_nbind.makeJSCaller=makeJSCaller;function makeMethodCaller(t,e){var r=e.typeList.length-1,o=e.typeList.slice(0);o.splice(1,0,\"uint32_t\",e.boundID);var a=_nbind.getTypes(o,e.title),n=a[0],u=a.slice(3),A=n.needsWireRead(e.policyTbl),p=anyNeedsWireWrite(u,e.policyTbl),h=e.ptr,E=e.num,I=_nbind.getDynCall(a,e.title),v=~e.flags&1;function x(){throw new Error(\"Calling a non-const method on a const object\")}if(!A&&!p)switch(r){case 0:return function(){return this.__nbindFlags&v?x():I(h,E,_nbind.pushPointer(this,t))};case 1:return function(C){return this.__nbindFlags&v?x():I(h,E,_nbind.pushPointer(this,t),C)};case 2:return function(C,R){return this.__nbindFlags&v?x():I(h,E,_nbind.pushPointer(this,t),C,R)};case 3:return function(C,R,N){return this.__nbindFlags&v?x():I(h,E,_nbind.pushPointer(this,t),C,R,N)};default:break}return buildCallerFunction(I,t,h,E,e.policyTbl,p,\"ptr,num,pushPointer(this,ptrType)\",n,u,v,x)}_nbind.makeMethodCaller=makeMethodCaller;function makeCaller(t){var e=t.typeList.length-1,r=_nbind.getTypes(t.typeList,t.title),o=r[0],a=r.slice(1),n=o.needsWireRead(t.policyTbl),u=anyNeedsWireWrite(a,t.policyTbl),A=t.direct,p=t.ptr;if(t.direct&&!n&&!u){var h=_nbind.getDynCall(r,t.title);switch(e){case 0:return function(){return h(A)};case 1:return function(x){return h(A,x)};case 2:return function(x,C){return h(A,x,C)};case 3:return function(x,C,R){return h(A,x,C,R)};default:break}p=0}var E;if(p){var I=t.typeList.slice(0);I.splice(1,0,\"uint32_t\"),r=_nbind.getTypes(I,t.title),E=\"ptr,num\"}else p=A,E=\"ptr\";var v=_nbind.getDynCall(r,t.title);return buildCallerFunction(v,null,p,t.num,t.policyTbl,u,E,o,a)}_nbind.makeCaller=makeCaller;function makeOverloader(t,e){var r=[];function o(){return r[arguments.length].apply(this,arguments)}return o.addMethod=function(a,n){r[n]=a},o.addMethod(t,e),o}_nbind.makeOverloader=makeOverloader;var Resource=function(){function t(e,r){var o=this;this.makeOpen=function(){return Object.keys(o.openTbl).join(\"\")},this.makeClose=function(){return Object.keys(o.closeTbl).join(\"\")},this.openTbl={},this.closeTbl={},e&&(this.openTbl[e]=!0),r&&(this.closeTbl[r]=!0)}return t.prototype.add=function(e){for(var r=0,o=Object.keys(e.openTbl);r<o.length;r++){var a=o[r];this.openTbl[a]=!0}for(var n=0,u=Object.keys(e.closeTbl);n<u.length;n++){var a=u[n];this.closeTbl[a]=!0}},t.prototype.remove=function(e){for(var r=0,o=Object.keys(e.openTbl);r<o.length;r++){var a=o[r];delete this.openTbl[a]}for(var n=0,u=Object.keys(e.closeTbl);n<u.length;n++){var a=u[n];delete this.closeTbl[a]}},t}();_nbind.Resource=Resource;function listResources(t,e){for(var r=new Resource,o=0,a=t;o<a.length;o++)for(var n=a[o],u=0,A=n.readResources||[];u<A.length;u++){var p=A[u];r.add(p)}for(var h=0,E=e;h<E.length;h++)for(var n=E[h],I=0,v=n.writeResources||[];I<v.length;I++){var p=v[I];r.add(p)}return r}_nbind.listResources=listResources,_nbind.resources={pool:new Resource(\"var used=HEAPU32[_nbind.Pool.usedPtr],page=HEAPU32[_nbind.Pool.pagePtr];\",\"_nbind.Pool.lreset(used,page);\")};var ExternalBuffer=function(t){__extends(e,t);function e(r,o){var a=t.call(this,r)||this;return a.ptr=o,a}return e.prototype.free=function(){_free(this.ptr)},e}(_nbind.External);function getBuffer(t){return t instanceof ArrayBuffer?new Uint8Array(t):t instanceof DataView?new Uint8Array(t.buffer,t.byteOffset,t.byteLength):t}function pushBuffer(t,e){if(t==null&&e&&e.Nullable&&(t=[]),typeof t!=\"object\")throw new Error(\"Type mismatch\");var r=t,o=r.byteLength||r.length;if(!o&&o!==0&&r.byteLength!==0)throw new Error(\"Type mismatch\");var a=_nbind.Pool.lalloc(8),n=_malloc(o),u=a/4;return HEAPU32[u++]=o,HEAPU32[u++]=n,HEAPU32[u++]=new ExternalBuffer(t,n).register(),HEAPU8.set(getBuffer(t),n),a}var BufferType=function(t){__extends(e,t);function e(){var r=t!==null&&t.apply(this,arguments)||this;return r.wireWrite=pushBuffer,r.readResources=[_nbind.resources.pool],r.writeResources=[_nbind.resources.pool],r}return e.prototype.makeWireWrite=function(r,o){return function(a){return pushBuffer(a,o)}},e}(_nbind.BindType);_nbind.BufferType=BufferType;function commitBuffer(t,e,r){var o=_nbind.externalList[t].data,a=Buffer;if(typeof Buffer!=\"function\"&&(a=function(){}),!(o instanceof Array)){var n=HEAPU8.subarray(e,e+r);if(o instanceof a){var u=void 0;typeof Buffer.from==\"function\"&&Buffer.from.length>=3?u=Buffer.from(n):u=new Buffer(n),u.copy(o)}else getBuffer(o).set(n)}}_nbind.commitBuffer=commitBuffer;var dirtyList=[],gcTimer=0;function sweep(){for(var t=0,e=dirtyList;t<e.length;t++){var r=e[t];r.__nbindState&3||r.free()}dirtyList=[],gcTimer=0}_nbind.mark=function(t){};function toggleLightGC(t){t?_nbind.mark=function(e){dirtyList.push(e),gcTimer||(gcTimer=setTimeout(sweep,0))}:_nbind.mark=function(e){}}_nbind.toggleLightGC=toggleLightGC}(_nbind),Module.requestFullScreen=function t(e,r,o){Module.printErr(\"Module.requestFullScreen is deprecated. Please call Module.requestFullscreen instead.\"),Module.requestFullScreen=Module.requestFullscreen,Browser.requestFullScreen(e,r,o)},Module.requestFullscreen=function t(e,r,o){Browser.requestFullscreen(e,r,o)},Module.requestAnimationFrame=function t(e){Browser.requestAnimationFrame(e)},Module.setCanvasSize=function t(e,r,o){Browser.setCanvasSize(e,r,o)},Module.pauseMainLoop=function t(){Browser.mainLoop.pause()},Module.resumeMainLoop=function t(){Browser.mainLoop.resume()},Module.getUserMedia=function t(){Browser.getUserMedia()},Module.createContext=function t(e,r,o,a){return Browser.createContext(e,r,o,a)},ENVIRONMENT_IS_NODE?_emscripten_get_now=function(){var e=process.hrtime();return e[0]*1e3+e[1]/1e6}:typeof dateNow<\"u\"?_emscripten_get_now=dateNow:typeof self==\"object\"&&self.performance&&typeof self.performance.now==\"function\"?_emscripten_get_now=function(){return self.performance.now()}:typeof performance==\"object\"&&typeof performance.now==\"function\"?_emscripten_get_now=function(){return performance.now()}:_emscripten_get_now=Date.now,__ATEXIT__.push(function(){var t=Module._fflush;t&&t(0);var e=___syscall146.printChar;if(!!e){var r=___syscall146.buffers;r[1].length&&e(1,10),r[2].length&&e(2,10)}}),DYNAMICTOP_PTR=allocate(1,\"i32\",ALLOC_STATIC),STACK_BASE=STACKTOP=Runtime.alignMemory(STATICTOP),STACK_MAX=STACK_BASE+TOTAL_STACK,DYNAMIC_BASE=Runtime.alignMemory(STACK_MAX),HEAP32[DYNAMICTOP_PTR>>2]=DYNAMIC_BASE,staticSealed=!0;function invoke_viiiii(t,e,r,o,a,n){try{Module.dynCall_viiiii(t,e,r,o,a,n)}catch(u){if(typeof u!=\"number\"&&u!==\"longjmp\")throw u;Module.setThrew(1,0)}}function invoke_vif(t,e,r){try{Module.dynCall_vif(t,e,r)}catch(o){if(typeof o!=\"number\"&&o!==\"longjmp\")throw o;Module.setThrew(1,0)}}function invoke_vid(t,e,r){try{Module.dynCall_vid(t,e,r)}catch(o){if(typeof o!=\"number\"&&o!==\"longjmp\")throw o;Module.setThrew(1,0)}}function invoke_fiff(t,e,r,o){try{return Module.dynCall_fiff(t,e,r,o)}catch(a){if(typeof a!=\"number\"&&a!==\"longjmp\")throw a;Module.setThrew(1,0)}}function invoke_vi(t,e){try{Module.dynCall_vi(t,e)}catch(r){if(typeof r!=\"number\"&&r!==\"longjmp\")throw r;Module.setThrew(1,0)}}function invoke_vii(t,e,r){try{Module.dynCall_vii(t,e,r)}catch(o){if(typeof o!=\"number\"&&o!==\"longjmp\")throw o;Module.setThrew(1,0)}}function invoke_ii(t,e){try{return Module.dynCall_ii(t,e)}catch(r){if(typeof r!=\"number\"&&r!==\"longjmp\")throw r;Module.setThrew(1,0)}}function invoke_viddi(t,e,r,o,a){try{Module.dynCall_viddi(t,e,r,o,a)}catch(n){if(typeof n!=\"number\"&&n!==\"longjmp\")throw n;Module.setThrew(1,0)}}function invoke_vidd(t,e,r,o){try{Module.dynCall_vidd(t,e,r,o)}catch(a){if(typeof a!=\"number\"&&a!==\"longjmp\")throw a;Module.setThrew(1,0)}}function invoke_iiii(t,e,r,o){try{return Module.dynCall_iiii(t,e,r,o)}catch(a){if(typeof a!=\"number\"&&a!==\"longjmp\")throw a;Module.setThrew(1,0)}}function invoke_diii(t,e,r,o){try{return Module.dynCall_diii(t,e,r,o)}catch(a){if(typeof a!=\"number\"&&a!==\"longjmp\")throw a;Module.setThrew(1,0)}}function invoke_di(t,e){try{return Module.dynCall_di(t,e)}catch(r){if(typeof r!=\"number\"&&r!==\"longjmp\")throw r;Module.setThrew(1,0)}}function invoke_iid(t,e,r){try{return Module.dynCall_iid(t,e,r)}catch(o){if(typeof o!=\"number\"&&o!==\"longjmp\")throw o;Module.setThrew(1,0)}}function invoke_iii(t,e,r){try{return Module.dynCall_iii(t,e,r)}catch(o){if(typeof o!=\"number\"&&o!==\"longjmp\")throw o;Module.setThrew(1,0)}}function invoke_viiddi(t,e,r,o,a,n){try{Module.dynCall_viiddi(t,e,r,o,a,n)}catch(u){if(typeof u!=\"number\"&&u!==\"longjmp\")throw u;Module.setThrew(1,0)}}function invoke_viiiiii(t,e,r,o,a,n,u){try{Module.dynCall_viiiiii(t,e,r,o,a,n,u)}catch(A){if(typeof A!=\"number\"&&A!==\"longjmp\")throw A;Module.setThrew(1,0)}}function invoke_dii(t,e,r){try{return Module.dynCall_dii(t,e,r)}catch(o){if(typeof o!=\"number\"&&o!==\"longjmp\")throw o;Module.setThrew(1,0)}}function invoke_i(t){try{return Module.dynCall_i(t)}catch(e){if(typeof e!=\"number\"&&e!==\"longjmp\")throw e;Module.setThrew(1,0)}}function invoke_iiiiii(t,e,r,o,a,n){try{return Module.dynCall_iiiiii(t,e,r,o,a,n)}catch(u){if(typeof u!=\"number\"&&u!==\"longjmp\")throw u;Module.setThrew(1,0)}}function invoke_viiid(t,e,r,o,a){try{Module.dynCall_viiid(t,e,r,o,a)}catch(n){if(typeof n!=\"number\"&&n!==\"longjmp\")throw n;Module.setThrew(1,0)}}function invoke_viififi(t,e,r,o,a,n,u){try{Module.dynCall_viififi(t,e,r,o,a,n,u)}catch(A){if(typeof A!=\"number\"&&A!==\"longjmp\")throw A;Module.setThrew(1,0)}}function invoke_viii(t,e,r,o){try{Module.dynCall_viii(t,e,r,o)}catch(a){if(typeof a!=\"number\"&&a!==\"longjmp\")throw a;Module.setThrew(1,0)}}function invoke_v(t){try{Module.dynCall_v(t)}catch(e){if(typeof e!=\"number\"&&e!==\"longjmp\")throw e;Module.setThrew(1,0)}}function invoke_viid(t,e,r,o){try{Module.dynCall_viid(t,e,r,o)}catch(a){if(typeof a!=\"number\"&&a!==\"longjmp\")throw a;Module.setThrew(1,0)}}function invoke_idd(t,e,r){try{return Module.dynCall_idd(t,e,r)}catch(o){if(typeof o!=\"number\"&&o!==\"longjmp\")throw o;Module.setThrew(1,0)}}function invoke_viiii(t,e,r,o,a){try{Module.dynCall_viiii(t,e,r,o,a)}catch(n){if(typeof n!=\"number\"&&n!==\"longjmp\")throw n;Module.setThrew(1,0)}}Module.asmGlobalArg={Math,Int8Array,Int16Array,Int32Array,Uint8Array,Uint16Array,Uint32Array,Float32Array,Float64Array,NaN:NaN,Infinity:1/0},Module.asmLibraryArg={abort,assert,enlargeMemory,getTotalMemory,abortOnCannotGrowMemory,invoke_viiiii,invoke_vif,invoke_vid,invoke_fiff,invoke_vi,invoke_vii,invoke_ii,invoke_viddi,invoke_vidd,invoke_iiii,invoke_diii,invoke_di,invoke_iid,invoke_iii,invoke_viiddi,invoke_viiiiii,invoke_dii,invoke_i,invoke_iiiiii,invoke_viiid,invoke_viififi,invoke_viii,invoke_v,invoke_viid,invoke_idd,invoke_viiii,_emscripten_asm_const_iiiii,_emscripten_asm_const_iiidddddd,_emscripten_asm_const_iiiid,__nbind_reference_external,_emscripten_asm_const_iiiiiiii,_removeAccessorPrefix,_typeModule,__nbind_register_pool,__decorate,_llvm_stackrestore,___cxa_atexit,__extends,__nbind_get_value_object,__ZN8facebook4yoga14YGNodeToStringEPNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP6YGNode14YGPrintOptionsj,_emscripten_set_main_loop_timing,__nbind_register_primitive,__nbind_register_type,_emscripten_memcpy_big,__nbind_register_function,___setErrNo,__nbind_register_class,__nbind_finish,_abort,_nbind_value,_llvm_stacksave,___syscall54,_defineHidden,_emscripten_set_main_loop,_emscripten_get_now,__nbind_register_callback_signature,_emscripten_asm_const_iiiiii,__nbind_free_external,_emscripten_asm_const_iiii,_emscripten_asm_const_iiididi,___syscall6,_atexit,___syscall140,___syscall146,DYNAMICTOP_PTR,tempDoublePtr,ABORT,STACKTOP,STACK_MAX,cttz_i8,___dso_handle};var asm=function(t,e,r){var o=new t.Int8Array(r),a=new t.Int16Array(r),n=new t.Int32Array(r),u=new t.Uint8Array(r),A=new t.Uint16Array(r),p=new t.Uint32Array(r),h=new t.Float32Array(r),E=new t.Float64Array(r),I=e.DYNAMICTOP_PTR|0,v=e.tempDoublePtr|0,x=e.ABORT|0,C=e.STACKTOP|0,R=e.STACK_MAX|0,N=e.cttz_i8|0,U=e.___dso_handle|0,V=0,te=0,ae=0,fe=0,ue=t.NaN,me=t.Infinity,he=0,Be=0,we=0,g=0,Ee=0,Pe=0,ce=t.Math.floor,ne=t.Math.abs,ee=t.Math.sqrt,Ie=t.Math.pow,Fe=t.Math.cos,At=t.Math.sin,H=t.Math.tan,at=t.Math.acos,Re=t.Math.asin,ke=t.Math.atan,xe=t.Math.atan2,He=t.Math.exp,Te=t.Math.log,Ve=t.Math.ceil,qe=t.Math.imul,b=t.Math.min,w=t.Math.max,S=t.Math.clz32,y=t.Math.fround,F=e.abort,J=e.assert,X=e.enlargeMemory,Z=e.getTotalMemory,ie=e.abortOnCannotGrowMemory,be=e.invoke_viiiii,Le=e.invoke_vif,ot=e.invoke_vid,dt=e.invoke_fiff,Gt=e.invoke_vi,$t=e.invoke_vii,bt=e.invoke_ii,an=e.invoke_viddi,Qr=e.invoke_vidd,mr=e.invoke_iiii,br=e.invoke_diii,Wr=e.invoke_di,Kn=e.invoke_iid,Ls=e.invoke_iii,Ti=e.invoke_viiddi,ps=e.invoke_viiiiii,io=e.invoke_dii,Si=e.invoke_i,Ns=e.invoke_iiiiii,so=e.invoke_viiid,uc=e.invoke_viififi,uu=e.invoke_viii,cp=e.invoke_v,up=e.invoke_viid,Os=e.invoke_idd,Dn=e.invoke_viiii,oo=e._emscripten_asm_const_iiiii,Ms=e._emscripten_asm_const_iiidddddd,yl=e._emscripten_asm_const_iiiid,El=e.__nbind_reference_external,ao=e._emscripten_asm_const_iiiiiiii,zn=e._removeAccessorPrefix,On=e._typeModule,Li=e.__nbind_register_pool,Mn=e.__decorate,_i=e._llvm_stackrestore,rr=e.___cxa_atexit,Oe=e.__extends,ii=e.__nbind_get_value_object,Ua=e.__ZN8facebook4yoga14YGNodeToStringEPNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP6YGNode14YGPrintOptionsj,hr=e._emscripten_set_main_loop_timing,Ac=e.__nbind_register_primitive,Au=e.__nbind_register_type,fc=e._emscripten_memcpy_big,Cl=e.__nbind_register_function,DA=e.___setErrNo,fu=e.__nbind_register_class,Ce=e.__nbind_finish,Rt=e._abort,pc=e._nbind_value,Hi=e._llvm_stacksave,pu=e.___syscall54,Yt=e._defineHidden,wl=e._emscripten_set_main_loop,PA=e._emscripten_get_now,Ap=e.__nbind_register_callback_signature,hc=e._emscripten_asm_const_iiiiii,SA=e.__nbind_free_external,Qn=e._emscripten_asm_const_iiii,hi=e._emscripten_asm_const_iiididi,gc=e.___syscall6,bA=e._atexit,sa=e.___syscall140,Ni=e.___syscall146,_o=y(0);let Ze=y(0);function lo(s){s=s|0;var l=0;return l=C,C=C+s|0,C=C+15&-16,l|0}function dc(){return C|0}function hu(s){s=s|0,C=s}function qi(s,l){s=s|0,l=l|0,C=s,R=l}function gu(s,l){s=s|0,l=l|0,V||(V=s,te=l)}function xA(s){s=s|0,Pe=s}function Ha(){return Pe|0}function mc(){var s=0,l=0;Dr(8104,8,400)|0,Dr(8504,408,540)|0,s=9044,l=s+44|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));o[9088]=0,o[9089]=1,n[2273]=0,n[2274]=948,n[2275]=948,rr(17,8104,U|0)|0}function hs(s){s=s|0,pt(s+948|0)}function Ht(s){return s=y(s),((Pu(s)|0)&2147483647)>>>0>2139095040|0}function Fn(s,l,c){s=s|0,l=l|0,c=c|0;e:do if(n[s+(l<<3)+4>>2]|0)s=s+(l<<3)|0;else{if((l|2|0)==3&&n[s+60>>2]|0){s=s+56|0;break}switch(l|0){case 0:case 2:case 4:case 5:{if(n[s+52>>2]|0){s=s+48|0;break e}break}default:}if(n[s+68>>2]|0){s=s+64|0;break}else{s=(l|1|0)==5?948:c;break}}while(0);return s|0}function Ci(s){s=s|0;var l=0;return l=pD(1e3)|0,oa(s,(l|0)!=0,2456),n[2276]=(n[2276]|0)+1,Dr(l|0,8104,1e3)|0,o[s+2>>0]|0&&(n[l+4>>2]=2,n[l+12>>2]=4),n[l+976>>2]=s,l|0}function oa(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;d=C,C=C+16|0,f=d,l||(n[f>>2]=c,Cg(s,5,3197,f)),C=d}function co(){return Ci(956)|0}function Us(s){s=s|0;var l=0;return l=Kt(1e3)|0,aa(l,s),oa(n[s+976>>2]|0,1,2456),n[2276]=(n[2276]|0)+1,n[l+944>>2]=0,l|0}function aa(s,l){s=s|0,l=l|0;var c=0;Dr(s|0,l|0,948)|0,Rm(s+948|0,l+948|0),c=s+960|0,s=l+960|0,l=c+40|0;do n[c>>2]=n[s>>2],c=c+4|0,s=s+4|0;while((c|0)<(l|0))}function la(s){s=s|0;var l=0,c=0,f=0,d=0;if(l=s+944|0,c=n[l>>2]|0,c|0&&(Ho(c+948|0,s)|0,n[l>>2]=0),c=wi(s)|0,c|0){l=0;do n[(gs(s,l)|0)+944>>2]=0,l=l+1|0;while((l|0)!=(c|0))}c=s+948|0,f=n[c>>2]|0,d=s+952|0,l=n[d>>2]|0,(l|0)!=(f|0)&&(n[d>>2]=l+(~((l+-4-f|0)>>>2)<<2)),ds(c),hD(s),n[2276]=(n[2276]|0)+-1}function Ho(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0;f=n[s>>2]|0,k=s+4|0,c=n[k>>2]|0,m=c;e:do if((f|0)==(c|0))d=f,B=4;else for(s=f;;){if((n[s>>2]|0)==(l|0)){d=s,B=4;break e}if(s=s+4|0,(s|0)==(c|0)){s=0;break}}while(0);return(B|0)==4&&((d|0)!=(c|0)?(f=d+4|0,s=m-f|0,l=s>>2,l&&(Mw(d|0,f|0,s|0)|0,c=n[k>>2]|0),s=d+(l<<2)|0,(c|0)==(s|0)||(n[k>>2]=c+(~((c+-4-s|0)>>>2)<<2)),s=1):s=0),s|0}function wi(s){return s=s|0,(n[s+952>>2]|0)-(n[s+948>>2]|0)>>2|0}function gs(s,l){s=s|0,l=l|0;var c=0;return c=n[s+948>>2]|0,(n[s+952>>2]|0)-c>>2>>>0>l>>>0?s=n[c+(l<<2)>>2]|0:s=0,s|0}function ds(s){s=s|0;var l=0,c=0,f=0,d=0;f=C,C=C+32|0,l=f,d=n[s>>2]|0,c=(n[s+4>>2]|0)-d|0,((n[s+8>>2]|0)-d|0)>>>0>c>>>0&&(d=c>>2,Bp(l,d,d,s+8|0),vg(s,l),_A(l)),C=f}function ms(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0;M=wi(s)|0;do if(M|0){if((n[(gs(s,0)|0)+944>>2]|0)==(s|0)){if(!(Ho(s+948|0,l)|0))break;Dr(l+400|0,8504,540)|0,n[l+944>>2]=0,Ne(s);break}B=n[(n[s+976>>2]|0)+12>>2]|0,k=s+948|0,Q=(B|0)==0,c=0,m=0;do f=n[(n[k>>2]|0)+(m<<2)>>2]|0,(f|0)==(l|0)?Ne(s):(d=Us(f)|0,n[(n[k>>2]|0)+(c<<2)>>2]=d,n[d+944>>2]=s,Q||TR[B&15](f,d,s,c),c=c+1|0),m=m+1|0;while((m|0)!=(M|0));if(c>>>0<M>>>0){Q=s+948|0,k=s+952|0,B=c,c=n[k>>2]|0;do m=(n[Q>>2]|0)+(B<<2)|0,f=m+4|0,d=c-f|0,l=d>>2,l&&(Mw(m|0,f|0,d|0)|0,c=n[k>>2]|0),d=c,f=m+(l<<2)|0,(d|0)!=(f|0)&&(c=d+(~((d+-4-f|0)>>>2)<<2)|0,n[k>>2]=c),B=B+1|0;while((B|0)!=(M|0))}}while(0)}function _s(s){s=s|0;var l=0,c=0,f=0,d=0;Un(s,(wi(s)|0)==0,2491),Un(s,(n[s+944>>2]|0)==0,2545),l=s+948|0,c=n[l>>2]|0,f=s+952|0,d=n[f>>2]|0,(d|0)!=(c|0)&&(n[f>>2]=d+(~((d+-4-c|0)>>>2)<<2)),ds(l),l=s+976|0,c=n[l>>2]|0,Dr(s|0,8104,1e3)|0,o[c+2>>0]|0&&(n[s+4>>2]=2,n[s+12>>2]=4),n[l>>2]=c}function Un(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;d=C,C=C+16|0,f=d,l||(n[f>>2]=c,Ao(s,5,3197,f)),C=d}function Pn(){return n[2276]|0}function ys(){var s=0;return s=pD(20)|0,We((s|0)!=0,2592),n[2277]=(n[2277]|0)+1,n[s>>2]=n[239],n[s+4>>2]=n[240],n[s+8>>2]=n[241],n[s+12>>2]=n[242],n[s+16>>2]=n[243],s|0}function We(s,l){s=s|0,l=l|0;var c=0,f=0;f=C,C=C+16|0,c=f,s||(n[c>>2]=l,Ao(0,5,3197,c)),C=f}function tt(s){s=s|0,hD(s),n[2277]=(n[2277]|0)+-1}function It(s,l){s=s|0,l=l|0;var c=0;l?(Un(s,(wi(s)|0)==0,2629),c=1):(c=0,l=0),n[s+964>>2]=l,n[s+988>>2]=c}function ir(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=C,C=C+16|0,m=f+8|0,d=f+4|0,B=f,n[d>>2]=l,Un(s,(n[l+944>>2]|0)==0,2709),Un(s,(n[s+964>>2]|0)==0,2763),$(s),l=s+948|0,n[B>>2]=(n[l>>2]|0)+(c<<2),n[m>>2]=n[B>>2],ye(l,m,d)|0,n[(n[d>>2]|0)+944>>2]=s,Ne(s),C=f}function $(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0;if(c=wi(s)|0,c|0&&(n[(gs(s,0)|0)+944>>2]|0)!=(s|0)){f=n[(n[s+976>>2]|0)+12>>2]|0,d=s+948|0,m=(f|0)==0,l=0;do B=n[(n[d>>2]|0)+(l<<2)>>2]|0,k=Us(B)|0,n[(n[d>>2]|0)+(l<<2)>>2]=k,n[k+944>>2]=s,m||TR[f&15](B,k,s,l),l=l+1|0;while((l|0)!=(c|0))}}function ye(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0,je=0,Me=0,Qe=0,et=0,Xe=0;et=C,C=C+64|0,G=et+52|0,k=et+48|0,se=et+28|0,je=et+24|0,Me=et+20|0,Qe=et,f=n[s>>2]|0,m=f,l=f+((n[l>>2]|0)-m>>2<<2)|0,f=s+4|0,d=n[f>>2]|0,B=s+8|0;do if(d>>>0<(n[B>>2]|0)>>>0){if((l|0)==(d|0)){n[l>>2]=n[c>>2],n[f>>2]=(n[f>>2]|0)+4;break}HA(s,l,d,l+4|0),l>>>0<=c>>>0&&(c=(n[f>>2]|0)>>>0>c>>>0?c+4|0:c),n[l>>2]=n[c>>2]}else{f=(d-m>>2)+1|0,d=L(s)|0,d>>>0<f>>>0&&Jr(s),O=n[s>>2]|0,M=(n[B>>2]|0)-O|0,m=M>>1,Bp(Qe,M>>2>>>0<d>>>1>>>0?m>>>0<f>>>0?f:m:d,l-O>>2,s+8|0),O=Qe+8|0,f=n[O>>2]|0,m=Qe+12|0,M=n[m>>2]|0,B=M,Q=f;do if((f|0)==(M|0)){if(M=Qe+4|0,f=n[M>>2]|0,Xe=n[Qe>>2]|0,d=Xe,f>>>0<=Xe>>>0){f=B-d>>1,f=(f|0)==0?1:f,Bp(se,f,f>>>2,n[Qe+16>>2]|0),n[je>>2]=n[M>>2],n[Me>>2]=n[O>>2],n[k>>2]=n[je>>2],n[G>>2]=n[Me>>2],Dw(se,k,G),f=n[Qe>>2]|0,n[Qe>>2]=n[se>>2],n[se>>2]=f,f=se+4|0,Xe=n[M>>2]|0,n[M>>2]=n[f>>2],n[f>>2]=Xe,f=se+8|0,Xe=n[O>>2]|0,n[O>>2]=n[f>>2],n[f>>2]=Xe,f=se+12|0,Xe=n[m>>2]|0,n[m>>2]=n[f>>2],n[f>>2]=Xe,_A(se),f=n[O>>2]|0;break}m=f,B=((m-d>>2)+1|0)/-2|0,k=f+(B<<2)|0,d=Q-m|0,m=d>>2,m&&(Mw(k|0,f|0,d|0)|0,f=n[M>>2]|0),Xe=k+(m<<2)|0,n[O>>2]=Xe,n[M>>2]=f+(B<<2),f=Xe}while(0);n[f>>2]=n[c>>2],n[O>>2]=(n[O>>2]|0)+4,l=Dg(s,Qe,l)|0,_A(Qe)}while(0);return C=et,l|0}function Ne(s){s=s|0;var l=0;do{if(l=s+984|0,o[l>>0]|0)break;o[l>>0]=1,h[s+504>>2]=y(ue),s=n[s+944>>2]|0}while((s|0)!=0)}function pt(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-4-f|0)>>>2)<<2)),gt(c))}function ht(s){return s=s|0,n[s+944>>2]|0}function Tt(s){s=s|0,Un(s,(n[s+964>>2]|0)!=0,2832),Ne(s)}function er(s){return s=s|0,(o[s+984>>0]|0)!=0|0}function $r(s,l){s=s|0,l=l|0,FUe(s,l,400)|0&&(Dr(s|0,l|0,400)|0,Ne(s))}function Gi(s){s=s|0;var l=Ze;return l=y(h[s+44>>2]),s=Ht(l)|0,y(s?y(0):l)}function es(s){s=s|0;var l=Ze;return l=y(h[s+48>>2]),Ht(l)|0&&(l=o[(n[s+976>>2]|0)+2>>0]|0?y(1):y(0)),y(l)}function bi(s,l){s=s|0,l=l|0,n[s+980>>2]=l}function qo(s){return s=s|0,n[s+980>>2]|0}function kA(s,l){s=s|0,l=l|0;var c=0;c=s+4|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Ne(s))}function QA(s){return s=s|0,n[s+4>>2]|0}function fp(s,l){s=s|0,l=l|0;var c=0;c=s+8|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Ne(s))}function sg(s){return s=s|0,n[s+8>>2]|0}function du(s,l){s=s|0,l=l|0;var c=0;c=s+12|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Ne(s))}function og(s){return s=s|0,n[s+12>>2]|0}function mu(s,l){s=s|0,l=l|0;var c=0;c=s+16|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Ne(s))}function uo(s){return s=s|0,n[s+16>>2]|0}function FA(s,l){s=s|0,l=l|0;var c=0;c=s+20|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Ne(s))}function yc(s){return s=s|0,n[s+20>>2]|0}function ca(s,l){s=s|0,l=l|0;var c=0;c=s+24|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Ne(s))}function ag(s){return s=s|0,n[s+24>>2]|0}function Ec(s,l){s=s|0,l=l|0;var c=0;c=s+28|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Ne(s))}function Sm(s){return s=s|0,n[s+28>>2]|0}function lg(s,l){s=s|0,l=l|0;var c=0;c=s+32|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Ne(s))}function ei(s){return s=s|0,n[s+32>>2]|0}function pp(s,l){s=s|0,l=l|0;var c=0;c=s+36|0,(n[c>>2]|0)!=(l|0)&&(n[c>>2]=l,Ne(s))}function cg(s){return s=s|0,n[s+36>>2]|0}function RA(s,l){s=s|0,l=y(l);var c=0;c=s+40|0,y(h[c>>2])!=l&&(h[c>>2]=l,Ne(s))}function Hs(s,l){s=s|0,l=y(l);var c=0;c=s+44|0,y(h[c>>2])!=l&&(h[c>>2]=l,Ne(s))}function yu(s,l){s=s|0,l=y(l);var c=0;c=s+48|0,y(h[c>>2])!=l&&(h[c>>2]=l,Ne(s))}function qa(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=Ht(l)|0,c=(m^1)&1,f=s+52|0,d=s+56|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Ne(s))}function ji(s,l){s=s|0,l=y(l);var c=0,f=0;f=s+52|0,c=s+56|0,y(h[f>>2])==l&&(n[c>>2]|0)==2||(h[f>>2]=l,f=Ht(l)|0,n[c>>2]=f?3:2,Ne(s))}function ua(s,l){s=s|0,l=l|0;var c=0,f=0;f=l+52|0,c=n[f+4>>2]|0,l=s,n[l>>2]=n[f>>2],n[l+4>>2]=c}function Eu(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0,m=0;m=Ht(c)|0,f=(m^1)&1,d=s+132+(l<<3)|0,l=s+132+(l<<3)+4|0,m|y(h[d>>2])==c&&(n[l>>2]|0)==(f|0)||(h[d>>2]=c,n[l>>2]=f,Ne(s))}function Es(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0,m=0;m=Ht(c)|0,f=m?0:2,d=s+132+(l<<3)|0,l=s+132+(l<<3)+4|0,m|y(h[d>>2])==c&&(n[l>>2]|0)==(f|0)||(h[d>>2]=c,n[l>>2]=f,Ne(s))}function Cc(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=l+132+(c<<3)|0,l=n[f+4>>2]|0,c=s,n[c>>2]=n[f>>2],n[c+4>>2]=l}function wc(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0,m=0;m=Ht(c)|0,f=(m^1)&1,d=s+60+(l<<3)|0,l=s+60+(l<<3)+4|0,m|y(h[d>>2])==c&&(n[l>>2]|0)==(f|0)||(h[d>>2]=c,n[l>>2]=f,Ne(s))}function j(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0,m=0;m=Ht(c)|0,f=m?0:2,d=s+60+(l<<3)|0,l=s+60+(l<<3)+4|0,m|y(h[d>>2])==c&&(n[l>>2]|0)==(f|0)||(h[d>>2]=c,n[l>>2]=f,Ne(s))}function Dt(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=l+60+(c<<3)|0,l=n[f+4>>2]|0,c=s,n[c>>2]=n[f>>2],n[c+4>>2]=l}function Il(s,l){s=s|0,l=l|0;var c=0;c=s+60+(l<<3)+4|0,(n[c>>2]|0)!=3&&(h[s+60+(l<<3)>>2]=y(ue),n[c>>2]=3,Ne(s))}function xi(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0,m=0;m=Ht(c)|0,f=(m^1)&1,d=s+204+(l<<3)|0,l=s+204+(l<<3)+4|0,m|y(h[d>>2])==c&&(n[l>>2]|0)==(f|0)||(h[d>>2]=c,n[l>>2]=f,Ne(s))}function Ic(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0,m=0;m=Ht(c)|0,f=m?0:2,d=s+204+(l<<3)|0,l=s+204+(l<<3)+4|0,m|y(h[d>>2])==c&&(n[l>>2]|0)==(f|0)||(h[d>>2]=c,n[l>>2]=f,Ne(s))}function ct(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=l+204+(c<<3)|0,l=n[f+4>>2]|0,c=s,n[c>>2]=n[f>>2],n[c+4>>2]=l}function Cu(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0,m=0;m=Ht(c)|0,f=(m^1)&1,d=s+276+(l<<3)|0,l=s+276+(l<<3)+4|0,m|y(h[d>>2])==c&&(n[l>>2]|0)==(f|0)||(h[d>>2]=c,n[l>>2]=f,Ne(s))}function ug(s,l){return s=s|0,l=l|0,y(h[s+276+(l<<3)>>2])}function yw(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=Ht(l)|0,c=(m^1)&1,f=s+348|0,d=s+352|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Ne(s))}function TA(s,l){s=s|0,l=y(l);var c=0,f=0;f=s+348|0,c=s+352|0,y(h[f>>2])==l&&(n[c>>2]|0)==2||(h[f>>2]=l,f=Ht(l)|0,n[c>>2]=f?3:2,Ne(s))}function hp(s){s=s|0;var l=0;l=s+352|0,(n[l>>2]|0)!=3&&(h[s+348>>2]=y(ue),n[l>>2]=3,Ne(s))}function Br(s,l){s=s|0,l=l|0;var c=0,f=0;f=l+348|0,c=n[f+4>>2]|0,l=s,n[l>>2]=n[f>>2],n[l+4>>2]=c}function Cs(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=Ht(l)|0,c=(m^1)&1,f=s+356|0,d=s+360|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Ne(s))}function Ag(s,l){s=s|0,l=y(l);var c=0,f=0;f=s+356|0,c=s+360|0,y(h[f>>2])==l&&(n[c>>2]|0)==2||(h[f>>2]=l,f=Ht(l)|0,n[c>>2]=f?3:2,Ne(s))}function fg(s){s=s|0;var l=0;l=s+360|0,(n[l>>2]|0)!=3&&(h[s+356>>2]=y(ue),n[l>>2]=3,Ne(s))}function pg(s,l){s=s|0,l=l|0;var c=0,f=0;f=l+356|0,c=n[f+4>>2]|0,l=s,n[l>>2]=n[f>>2],n[l+4>>2]=c}function gp(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=Ht(l)|0,c=(m^1)&1,f=s+364|0,d=s+368|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Ne(s))}function Bc(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=Ht(l)|0,c=m?0:2,f=s+364|0,d=s+368|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Ne(s))}function Ct(s,l){s=s|0,l=l|0;var c=0,f=0;f=l+364|0,c=n[f+4>>2]|0,l=s,n[l>>2]=n[f>>2],n[l+4>>2]=c}function bm(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=Ht(l)|0,c=(m^1)&1,f=s+372|0,d=s+376|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Ne(s))}function hg(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=Ht(l)|0,c=m?0:2,f=s+372|0,d=s+376|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Ne(s))}function gg(s,l){s=s|0,l=l|0;var c=0,f=0;f=l+372|0,c=n[f+4>>2]|0,l=s,n[l>>2]=n[f>>2],n[l+4>>2]=c}function wu(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=Ht(l)|0,c=(m^1)&1,f=s+380|0,d=s+384|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Ne(s))}function xm(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=Ht(l)|0,c=m?0:2,f=s+380|0,d=s+384|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Ne(s))}function dg(s,l){s=s|0,l=l|0;var c=0,f=0;f=l+380|0,c=n[f+4>>2]|0,l=s,n[l>>2]=n[f>>2],n[l+4>>2]=c}function Iu(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=Ht(l)|0,c=(m^1)&1,f=s+388|0,d=s+392|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Ne(s))}function Ew(s,l){s=s|0,l=y(l);var c=0,f=0,d=0,m=0;m=Ht(l)|0,c=m?0:2,f=s+388|0,d=s+392|0,m|y(h[f>>2])==l&&(n[d>>2]|0)==(c|0)||(h[f>>2]=l,n[d>>2]=c,Ne(s))}function km(s,l){s=s|0,l=l|0;var c=0,f=0;f=l+388|0,c=n[f+4>>2]|0,l=s,n[l>>2]=n[f>>2],n[l+4>>2]=c}function Aa(s,l){s=s|0,l=y(l);var c=0;c=s+396|0,y(h[c>>2])!=l&&(h[c>>2]=l,Ne(s))}function vc(s){return s=s|0,y(h[s+396>>2])}function Bl(s){return s=s|0,y(h[s+400>>2])}function Bu(s){return s=s|0,y(h[s+404>>2])}function mg(s){return s=s|0,y(h[s+408>>2])}function LA(s){return s=s|0,y(h[s+412>>2])}function dp(s){return s=s|0,y(h[s+416>>2])}function Ga(s){return s=s|0,y(h[s+420>>2])}function yg(s,l){switch(s=s|0,l=l|0,Un(s,(l|0)<6,2918),l|0){case 0:{l=(n[s+496>>2]|0)==2?5:4;break}case 2:{l=(n[s+496>>2]|0)==2?4:5;break}default:}return y(h[s+424+(l<<2)>>2])}function mp(s,l){switch(s=s|0,l=l|0,Un(s,(l|0)<6,2918),l|0){case 0:{l=(n[s+496>>2]|0)==2?5:4;break}case 2:{l=(n[s+496>>2]|0)==2?4:5;break}default:}return y(h[s+448+(l<<2)>>2])}function Go(s,l){switch(s=s|0,l=l|0,Un(s,(l|0)<6,2918),l|0){case 0:{l=(n[s+496>>2]|0)==2?5:4;break}case 2:{l=(n[s+496>>2]|0)==2?4:5;break}default:}return y(h[s+472+(l<<2)>>2])}function ws(s,l){s=s|0,l=l|0;var c=0,f=Ze;return c=n[s+4>>2]|0,(c|0)==(n[l+4>>2]|0)?c?(f=y(h[s>>2]),s=y(ne(y(f-y(h[l>>2]))))<y(999999974e-13)):s=1:s=0,s|0}function Ii(s,l){s=y(s),l=y(l);var c=0;return Ht(s)|0?c=Ht(l)|0:c=y(ne(y(s-l)))<y(999999974e-13),c|0}function Qm(s,l){s=s|0,l=l|0,Fm(s,l)}function Fm(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c+4|0,n[f>>2]=0,n[f+4>>2]=0,n[f+8>>2]=0,Ua(f|0,s|0,l|0,0),Ao(s,3,(o[f+11>>0]|0)<0?n[f>>2]|0:f,c),t3e(f),C=c}function jo(s,l,c,f){s=y(s),l=y(l),c=c|0,f=f|0;var d=Ze;s=y(s*l),d=y(bR(s,y(1)));do if(Ii(d,y(0))|0)s=y(s-d);else{if(s=y(s-d),Ii(d,y(1))|0){s=y(s+y(1));break}if(c){s=y(s+y(1));break}f||(d>y(.5)?d=y(1):(f=Ii(d,y(.5))|0,d=y(f?1:0)),s=y(s+d))}while(0);return y(s/l)}function NA(s,l,c,f,d,m,B,k,Q,M,O,G,se){s=s|0,l=y(l),c=c|0,f=y(f),d=d|0,m=y(m),B=B|0,k=y(k),Q=y(Q),M=y(M),O=y(O),G=y(G),se=se|0;var je=0,Me=Ze,Qe=Ze,et=Ze,Xe=Ze,lt=Ze,Ue=Ze;return Q<y(0)|M<y(0)?se=0:((se|0)!=0&&(Me=y(h[se+4>>2]),Me!=y(0))?(et=y(jo(l,Me,0,0)),Xe=y(jo(f,Me,0,0)),Qe=y(jo(m,Me,0,0)),Me=y(jo(k,Me,0,0))):(Qe=m,et=l,Me=k,Xe=f),(d|0)==(s|0)?je=Ii(Qe,et)|0:je=0,(B|0)==(c|0)?se=Ii(Me,Xe)|0:se=0,!je&&(lt=y(l-O),!(yp(s,lt,Q)|0))&&!(Ep(s,lt,d,Q)|0)?je=Eg(s,lt,d,m,Q)|0:je=1,!se&&(Ue=y(f-G),!(yp(c,Ue,M)|0))&&!(Ep(c,Ue,B,M)|0)?se=Eg(c,Ue,B,k,M)|0:se=1,se=je&se),se|0}function yp(s,l,c){return s=s|0,l=y(l),c=y(c),(s|0)==1?s=Ii(l,c)|0:s=0,s|0}function Ep(s,l,c,f){return s=s|0,l=y(l),c=c|0,f=y(f),(s|0)==2&(c|0)==0?l>=f?s=1:s=Ii(l,f)|0:s=0,s|0}function Eg(s,l,c,f,d){return s=s|0,l=y(l),c=c|0,f=y(f),d=y(d),(s|0)==2&(c|0)==2&f>l?d<=l?s=1:s=Ii(l,d)|0:s=0,s|0}function fa(s,l,c,f,d,m,B,k,Q,M,O){s=s|0,l=y(l),c=y(c),f=f|0,d=d|0,m=m|0,B=y(B),k=y(k),Q=Q|0,M=M|0,O=O|0;var G=0,se=0,je=0,Me=0,Qe=Ze,et=Ze,Xe=0,lt=0,Ue=0,Ge=0,Nt=0,Mr=0,ar=0,Xt=0,Pr=0,Lr=0,sr=0,xn=Ze,go=Ze,mo=Ze,yo=0,ya=0;sr=C,C=C+160|0,Xt=sr+152|0,ar=sr+120|0,Mr=sr+104|0,Ue=sr+72|0,Me=sr+56|0,Nt=sr+8|0,lt=sr,Ge=(n[2279]|0)+1|0,n[2279]=Ge,Pr=s+984|0,(o[Pr>>0]|0)!=0&&(n[s+512>>2]|0)!=(n[2278]|0)?Xe=4:(n[s+516>>2]|0)==(f|0)?Lr=0:Xe=4,(Xe|0)==4&&(n[s+520>>2]=0,n[s+924>>2]=-1,n[s+928>>2]=-1,h[s+932>>2]=y(-1),h[s+936>>2]=y(-1),Lr=1);e:do if(n[s+964>>2]|0)if(Qe=y(ln(s,2,B)),et=y(ln(s,0,B)),G=s+916|0,mo=y(h[G>>2]),go=y(h[s+920>>2]),xn=y(h[s+932>>2]),NA(d,l,m,c,n[s+924>>2]|0,mo,n[s+928>>2]|0,go,xn,y(h[s+936>>2]),Qe,et,O)|0)Xe=22;else if(je=n[s+520>>2]|0,!je)Xe=21;else for(se=0;;){if(G=s+524+(se*24|0)|0,xn=y(h[G>>2]),go=y(h[s+524+(se*24|0)+4>>2]),mo=y(h[s+524+(se*24|0)+16>>2]),NA(d,l,m,c,n[s+524+(se*24|0)+8>>2]|0,xn,n[s+524+(se*24|0)+12>>2]|0,go,mo,y(h[s+524+(se*24|0)+20>>2]),Qe,et,O)|0){Xe=22;break e}if(se=se+1|0,se>>>0>=je>>>0){Xe=21;break}}else{if(Q){if(G=s+916|0,!(Ii(y(h[G>>2]),l)|0)){Xe=21;break}if(!(Ii(y(h[s+920>>2]),c)|0)){Xe=21;break}if((n[s+924>>2]|0)!=(d|0)){Xe=21;break}G=(n[s+928>>2]|0)==(m|0)?G:0,Xe=22;break}if(je=n[s+520>>2]|0,!je)Xe=21;else for(se=0;;){if(G=s+524+(se*24|0)|0,Ii(y(h[G>>2]),l)|0&&Ii(y(h[s+524+(se*24|0)+4>>2]),c)|0&&(n[s+524+(se*24|0)+8>>2]|0)==(d|0)&&(n[s+524+(se*24|0)+12>>2]|0)==(m|0)){Xe=22;break e}if(se=se+1|0,se>>>0>=je>>>0){Xe=21;break}}}while(0);do if((Xe|0)==21)o[11697]|0?(G=0,Xe=28):(G=0,Xe=31);else if((Xe|0)==22){if(se=(o[11697]|0)!=0,!((G|0)!=0&(Lr^1)))if(se){Xe=28;break}else{Xe=31;break}Me=G+16|0,n[s+908>>2]=n[Me>>2],je=G+20|0,n[s+912>>2]=n[je>>2],(o[11698]|0)==0|se^1||(n[lt>>2]=OA(Ge)|0,n[lt+4>>2]=Ge,Ao(s,4,2972,lt),se=n[s+972>>2]|0,se|0&&tf[se&127](s),d=ja(d,Q)|0,m=ja(m,Q)|0,ya=+y(h[Me>>2]),yo=+y(h[je>>2]),n[Nt>>2]=d,n[Nt+4>>2]=m,E[Nt+8>>3]=+l,E[Nt+16>>3]=+c,E[Nt+24>>3]=ya,E[Nt+32>>3]=yo,n[Nt+40>>2]=M,Ao(s,4,2989,Nt))}while(0);return(Xe|0)==28&&(se=OA(Ge)|0,n[Me>>2]=se,n[Me+4>>2]=Ge,n[Me+8>>2]=Lr?3047:11699,Ao(s,4,3038,Me),se=n[s+972>>2]|0,se|0&&tf[se&127](s),Nt=ja(d,Q)|0,Xe=ja(m,Q)|0,n[Ue>>2]=Nt,n[Ue+4>>2]=Xe,E[Ue+8>>3]=+l,E[Ue+16>>3]=+c,n[Ue+24>>2]=M,Ao(s,4,3049,Ue),Xe=31),(Xe|0)==31&&(si(s,l,c,f,d,m,B,k,Q,O),o[11697]|0&&(se=n[2279]|0,Nt=OA(se)|0,n[Mr>>2]=Nt,n[Mr+4>>2]=se,n[Mr+8>>2]=Lr?3047:11699,Ao(s,4,3083,Mr),se=n[s+972>>2]|0,se|0&&tf[se&127](s),Nt=ja(d,Q)|0,Mr=ja(m,Q)|0,yo=+y(h[s+908>>2]),ya=+y(h[s+912>>2]),n[ar>>2]=Nt,n[ar+4>>2]=Mr,E[ar+8>>3]=yo,E[ar+16>>3]=ya,n[ar+24>>2]=M,Ao(s,4,3092,ar)),n[s+516>>2]=f,G||(se=s+520|0,G=n[se>>2]|0,(G|0)==16&&(o[11697]|0&&Ao(s,4,3124,Xt),n[se>>2]=0,G=0),Q?G=s+916|0:(n[se>>2]=G+1,G=s+524+(G*24|0)|0),h[G>>2]=l,h[G+4>>2]=c,n[G+8>>2]=d,n[G+12>>2]=m,n[G+16>>2]=n[s+908>>2],n[G+20>>2]=n[s+912>>2],G=0)),Q&&(n[s+416>>2]=n[s+908>>2],n[s+420>>2]=n[s+912>>2],o[s+985>>0]=1,o[Pr>>0]=0),n[2279]=(n[2279]|0)+-1,n[s+512>>2]=n[2278],C=sr,Lr|(G|0)==0|0}function ln(s,l,c){s=s|0,l=l|0,c=y(c);var f=Ze;return f=y(K(s,l,c)),y(f+y(re(s,l,c)))}function Ao(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=C,C=C+16|0,d=m,n[d>>2]=f,s?f=n[s+976>>2]|0:f=0,wg(f,s,l,c,d),C=m}function OA(s){return s=s|0,(s>>>0>60?3201:3201+(60-s)|0)|0}function ja(s,l){s=s|0,l=l|0;var c=0,f=0,d=0;return d=C,C=C+32|0,c=d+12|0,f=d,n[c>>2]=n[254],n[c+4>>2]=n[255],n[c+8>>2]=n[256],n[f>>2]=n[257],n[f+4>>2]=n[258],n[f+8>>2]=n[259],(s|0)>2?s=11699:s=n[(l?f:c)+(s<<2)>>2]|0,C=d,s|0}function si(s,l,c,f,d,m,B,k,Q,M){s=s|0,l=y(l),c=y(c),f=f|0,d=d|0,m=m|0,B=y(B),k=y(k),Q=Q|0,M=M|0;var O=0,G=0,se=0,je=0,Me=Ze,Qe=Ze,et=Ze,Xe=Ze,lt=Ze,Ue=Ze,Ge=Ze,Nt=0,Mr=0,ar=0,Xt=Ze,Pr=Ze,Lr=0,sr=Ze,xn=0,go=0,mo=0,yo=0,ya=0,Rp=0,Tp=0,xl=0,Lp=0,Ru=0,Tu=0,Np=0,Op=0,Mp=0,Xr=0,kl=0,Up=0,kc=0,_p=Ze,Hp=Ze,Lu=Ze,Nu=Ze,Qc=Ze,Gs=0,Xa=0,Wo=0,Ql=0,nf=0,sf=Ze,Ou=Ze,of=Ze,af=Ze,js=Ze,vs=Ze,Fl=0,Rn=Ze,lf=Ze,Eo=Ze,Fc=Ze,Co=Ze,Rc=Ze,cf=0,uf=0,Tc=Ze,Ys=Ze,Rl=0,Af=0,ff=0,pf=0,xr=Ze,Vn=0,Ds=0,wo=0,Ws=0,Rr=0,ur=0,Tl=0,Vt=Ze,hf=0,li=0;Tl=C,C=C+16|0,Gs=Tl+12|0,Xa=Tl+8|0,Wo=Tl+4|0,Ql=Tl,Un(s,(d|0)==0|(Ht(l)|0)^1,3326),Un(s,(m|0)==0|(Ht(c)|0)^1,3406),Ds=mt(s,f)|0,n[s+496>>2]=Ds,Rr=fr(2,Ds)|0,ur=fr(0,Ds)|0,h[s+440>>2]=y(K(s,Rr,B)),h[s+444>>2]=y(re(s,Rr,B)),h[s+428>>2]=y(K(s,ur,B)),h[s+436>>2]=y(re(s,ur,B)),h[s+464>>2]=y(Cr(s,Rr)),h[s+468>>2]=y(yn(s,Rr)),h[s+452>>2]=y(Cr(s,ur)),h[s+460>>2]=y(yn(s,ur)),h[s+488>>2]=y(oi(s,Rr,B)),h[s+492>>2]=y(Oi(s,Rr,B)),h[s+476>>2]=y(oi(s,ur,B)),h[s+484>>2]=y(Oi(s,ur,B));do if(n[s+964>>2]|0)Bg(s,l,c,d,m,B,k);else{if(wo=s+948|0,Ws=(n[s+952>>2]|0)-(n[wo>>2]|0)>>2,!Ws){jv(s,l,c,d,m,B,k);break}if(!Q&&Yv(s,l,c,d,m,B,k)|0)break;$(s),kl=s+508|0,o[kl>>0]=0,Rr=fr(n[s+4>>2]|0,Ds)|0,ur=ww(Rr,Ds)|0,Vn=pe(Rr)|0,Up=n[s+8>>2]|0,Af=s+28|0,kc=(n[Af>>2]|0)!=0,Co=Vn?B:k,Tc=Vn?k:B,_p=y(wp(s,Rr,B)),Hp=y(Iw(s,Rr,B)),Me=y(wp(s,ur,B)),Rc=y(En(s,Rr,B)),Ys=y(En(s,ur,B)),ar=Vn?d:m,Rl=Vn?m:d,xr=Vn?Rc:Ys,lt=Vn?Ys:Rc,Fc=y(ln(s,2,B)),Xe=y(ln(s,0,B)),Qe=y(y(jr(s+364|0,B))-xr),et=y(y(jr(s+380|0,B))-xr),Ue=y(y(jr(s+372|0,k))-lt),Ge=y(y(jr(s+388|0,k))-lt),Lu=Vn?Qe:Ue,Nu=Vn?et:Ge,Fc=y(l-Fc),l=y(Fc-xr),Ht(l)|0?xr=l:xr=y(_n(y(Lg(l,et)),Qe)),lf=y(c-Xe),l=y(lf-lt),Ht(l)|0?Eo=l:Eo=y(_n(y(Lg(l,Ge)),Ue)),Qe=Vn?xr:Eo,Rn=Vn?Eo:xr;e:do if((ar|0)==1)for(f=0,G=0;;){if(O=gs(s,G)|0,!f)y(rs(O))>y(0)&&y(qs(O))>y(0)?f=O:f=0;else if(Tm(O)|0){je=0;break e}if(G=G+1|0,G>>>0>=Ws>>>0){je=f;break}}else je=0;while(0);Nt=je+500|0,Mr=je+504|0,f=0,O=0,l=y(0),se=0;do{if(G=n[(n[wo>>2]|0)+(se<<2)>>2]|0,(n[G+36>>2]|0)==1)vu(G),o[G+985>>0]=1,o[G+984>>0]=0;else{vl(G),Q&&Cp(G,mt(G,Ds)|0,Qe,Rn,xr);do if((n[G+24>>2]|0)!=1)if((G|0)==(je|0)){n[Nt>>2]=n[2278],h[Mr>>2]=y(0);break}else{Lm(s,G,xr,d,Eo,xr,Eo,m,Ds,M);break}else O|0&&(n[O+960>>2]=G),n[G+960>>2]=0,O=G,f=(f|0)==0?G:f;while(0);vs=y(h[G+504>>2]),l=y(l+y(vs+y(ln(G,Rr,xr))))}se=se+1|0}while((se|0)!=(Ws|0));for(mo=l>Qe,Fl=kc&((ar|0)==2&mo)?1:ar,xn=(Rl|0)==1,ya=xn&(Q^1),Rp=(Fl|0)==1,Tp=(Fl|0)==2,xl=976+(Rr<<2)|0,Lp=(Rl|2|0)==2,Mp=xn&(kc^1),Ru=1040+(ur<<2)|0,Tu=1040+(Rr<<2)|0,Np=976+(ur<<2)|0,Op=(Rl|0)!=1,mo=kc&((ar|0)!=0&mo),go=s+976|0,xn=xn^1,l=Qe,Lr=0,yo=0,vs=y(0),Qc=y(0);;){e:do if(Lr>>>0<Ws>>>0)for(Mr=n[wo>>2]|0,se=0,Ge=y(0),Ue=y(0),et=y(0),Qe=y(0),G=0,O=0,je=Lr;;){if(Nt=n[Mr+(je<<2)>>2]|0,(n[Nt+36>>2]|0)!=1&&(n[Nt+940>>2]=yo,(n[Nt+24>>2]|0)!=1)){if(Xe=y(ln(Nt,Rr,xr)),Xr=n[xl>>2]|0,c=y(jr(Nt+380+(Xr<<3)|0,Co)),lt=y(h[Nt+504>>2]),c=y(Lg(c,lt)),c=y(_n(y(jr(Nt+364+(Xr<<3)|0,Co)),c)),kc&(se|0)!=0&y(Xe+y(Ue+c))>l){m=se,Xe=Ge,ar=je;break e}Xe=y(Xe+c),c=y(Ue+Xe),Xe=y(Ge+Xe),Tm(Nt)|0&&(et=y(et+y(rs(Nt))),Qe=y(Qe-y(lt*y(qs(Nt))))),O|0&&(n[O+960>>2]=Nt),n[Nt+960>>2]=0,se=se+1|0,O=Nt,G=(G|0)==0?Nt:G}else Xe=Ge,c=Ue;if(je=je+1|0,je>>>0<Ws>>>0)Ge=Xe,Ue=c;else{m=se,ar=je;break}}else m=0,Xe=y(0),et=y(0),Qe=y(0),G=0,ar=Lr;while(0);Xr=et>y(0)&et<y(1),Xt=Xr?y(1):et,Xr=Qe>y(0)&Qe<y(1),Ge=Xr?y(1):Qe;do if(Rp)Xr=51;else if(Xe<Lu&((Ht(Lu)|0)^1))l=Lu,Xr=51;else if(Xe>Nu&((Ht(Nu)|0)^1))l=Nu,Xr=51;else if(o[(n[go>>2]|0)+3>>0]|0)Xr=51;else{if(Xt!=y(0)&&y(rs(s))!=y(0)){Xr=53;break}l=Xe,Xr=53}while(0);if((Xr|0)==51&&(Xr=0,Ht(l)|0?Xr=53:(Pr=y(l-Xe),sr=l)),(Xr|0)==53&&(Xr=0,Xe<y(0)?(Pr=y(-Xe),sr=l):(Pr=y(0),sr=l)),!ya&&(nf=(G|0)==0,!nf)){se=n[xl>>2]|0,je=Pr<y(0),lt=y(Pr/Ge),Nt=Pr>y(0),Ue=y(Pr/Xt),et=y(0),Xe=y(0),l=y(0),O=G;do c=y(jr(O+380+(se<<3)|0,Co)),Qe=y(jr(O+364+(se<<3)|0,Co)),Qe=y(Lg(c,y(_n(Qe,y(h[O+504>>2]))))),je?(c=y(Qe*y(qs(O))),c!=y(-0)&&(Vt=y(Qe-y(lt*c)),sf=y(Bi(O,Rr,Vt,sr,xr)),Vt!=sf)&&(et=y(et-y(sf-Qe)),l=y(l+c))):Nt&&(Ou=y(rs(O)),Ou!=y(0))&&(Vt=y(Qe+y(Ue*Ou)),of=y(Bi(O,Rr,Vt,sr,xr)),Vt!=of)&&(et=y(et-y(of-Qe)),Xe=y(Xe-Ou)),O=n[O+960>>2]|0;while((O|0)!=0);if(l=y(Ge+l),Qe=y(Pr+et),nf)l=y(0);else{lt=y(Xt+Xe),je=n[xl>>2]|0,Nt=Qe<y(0),Mr=l==y(0),Ue=y(Qe/l),se=Qe>y(0),lt=y(Qe/lt),l=y(0);do{Vt=y(jr(G+380+(je<<3)|0,Co)),et=y(jr(G+364+(je<<3)|0,Co)),et=y(Lg(Vt,y(_n(et,y(h[G+504>>2]))))),Nt?(Vt=y(et*y(qs(G))),Qe=y(-Vt),Vt!=y(-0)?(Vt=y(Ue*Qe),Qe=y(Bi(G,Rr,y(et+(Mr?Qe:Vt)),sr,xr))):Qe=et):se&&(af=y(rs(G)),af!=y(0))?Qe=y(Bi(G,Rr,y(et+y(lt*af)),sr,xr)):Qe=et,l=y(l-y(Qe-et)),Xe=y(ln(G,Rr,xr)),c=y(ln(G,ur,xr)),Qe=y(Qe+Xe),h[Xa>>2]=Qe,n[Ql>>2]=1,et=y(h[G+396>>2]);e:do if(Ht(et)|0){O=Ht(Rn)|0;do if(!O){if(mo|(ts(G,ur,Rn)|0|xn)||(ha(s,G)|0)!=4||(n[(Dl(G,ur)|0)+4>>2]|0)==3||(n[(Sc(G,ur)|0)+4>>2]|0)==3)break;h[Gs>>2]=Rn,n[Wo>>2]=1;break e}while(0);if(ts(G,ur,Rn)|0){O=n[G+992+(n[Np>>2]<<2)>>2]|0,Vt=y(c+y(jr(O,Rn))),h[Gs>>2]=Vt,O=Op&(n[O+4>>2]|0)==2,n[Wo>>2]=((Ht(Vt)|0|O)^1)&1;break}else{h[Gs>>2]=Rn,n[Wo>>2]=O?0:2;break}}else Vt=y(Qe-Xe),Xt=y(Vt/et),Vt=y(et*Vt),n[Wo>>2]=1,h[Gs>>2]=y(c+(Vn?Xt:Vt));while(0);yr(G,Rr,sr,xr,Ql,Xa),yr(G,ur,Rn,xr,Wo,Gs);do if(!(ts(G,ur,Rn)|0)&&(ha(s,G)|0)==4){if((n[(Dl(G,ur)|0)+4>>2]|0)==3){O=0;break}O=(n[(Sc(G,ur)|0)+4>>2]|0)!=3}else O=0;while(0);Vt=y(h[Xa>>2]),Xt=y(h[Gs>>2]),hf=n[Ql>>2]|0,li=n[Wo>>2]|0,fa(G,Vn?Vt:Xt,Vn?Xt:Vt,Ds,Vn?hf:li,Vn?li:hf,xr,Eo,Q&(O^1),3488,M)|0,o[kl>>0]=o[kl>>0]|o[G+508>>0],G=n[G+960>>2]|0}while((G|0)!=0)}}else l=y(0);if(l=y(Pr+l),li=l<y(0)&1,o[kl>>0]=li|u[kl>>0],Tp&l>y(0)?(O=n[xl>>2]|0,(n[s+364+(O<<3)+4>>2]|0)!=0&&(js=y(jr(s+364+(O<<3)|0,Co)),js>=y(0))?Qe=y(_n(y(0),y(js-y(sr-l)))):Qe=y(0)):Qe=l,Nt=Lr>>>0<ar>>>0,Nt){je=n[wo>>2]|0,se=Lr,O=0;do G=n[je+(se<<2)>>2]|0,n[G+24>>2]|0||(O=((n[(Dl(G,Rr)|0)+4>>2]|0)==3&1)+O|0,O=O+((n[(Sc(G,Rr)|0)+4>>2]|0)==3&1)|0),se=se+1|0;while((se|0)!=(ar|0));O?(Xe=y(0),c=y(0)):Xr=101}else Xr=101;e:do if((Xr|0)==101)switch(Xr=0,Up|0){case 1:{O=0,Xe=y(Qe*y(.5)),c=y(0);break e}case 2:{O=0,Xe=Qe,c=y(0);break e}case 3:{if(m>>>0<=1){O=0,Xe=y(0),c=y(0);break e}c=y((m+-1|0)>>>0),O=0,Xe=y(0),c=y(y(_n(Qe,y(0)))/c);break e}case 5:{c=y(Qe/y((m+1|0)>>>0)),O=0,Xe=c;break e}case 4:{c=y(Qe/y(m>>>0)),O=0,Xe=y(c*y(.5));break e}default:{O=0,Xe=y(0),c=y(0);break e}}while(0);if(l=y(_p+Xe),Nt){et=y(Qe/y(O|0)),se=n[wo>>2]|0,G=Lr,Qe=y(0);do{O=n[se+(G<<2)>>2]|0;e:do if((n[O+36>>2]|0)!=1){switch(n[O+24>>2]|0){case 1:{if(gi(O,Rr)|0){if(!Q)break e;Vt=y(Or(O,Rr,sr)),Vt=y(Vt+y(Cr(s,Rr))),Vt=y(Vt+y(K(O,Rr,xr))),h[O+400+(n[Tu>>2]<<2)>>2]=Vt;break e}break}case 0:if(li=(n[(Dl(O,Rr)|0)+4>>2]|0)==3,Vt=y(et+l),l=li?Vt:l,Q&&(li=O+400+(n[Tu>>2]<<2)|0,h[li>>2]=y(l+y(h[li>>2]))),li=(n[(Sc(O,Rr)|0)+4>>2]|0)==3,Vt=y(et+l),l=li?Vt:l,ya){Vt=y(c+y(ln(O,Rr,xr))),Qe=Rn,l=y(l+y(Vt+y(h[O+504>>2])));break e}else{l=y(l+y(c+y(ns(O,Rr,xr)))),Qe=y(_n(Qe,y(ns(O,ur,xr))));break e}default:}Q&&(Vt=y(Xe+y(Cr(s,Rr))),li=O+400+(n[Tu>>2]<<2)|0,h[li>>2]=y(Vt+y(h[li>>2])))}while(0);G=G+1|0}while((G|0)!=(ar|0))}else Qe=y(0);if(c=y(Hp+l),Lp?Xe=y(y(Bi(s,ur,y(Ys+Qe),Tc,B))-Ys):Xe=Rn,et=y(y(Bi(s,ur,y(Ys+(Mp?Rn:Qe)),Tc,B))-Ys),Nt&Q){G=Lr;do{se=n[(n[wo>>2]|0)+(G<<2)>>2]|0;do if((n[se+36>>2]|0)!=1){if((n[se+24>>2]|0)==1){if(gi(se,ur)|0){if(Vt=y(Or(se,ur,Rn)),Vt=y(Vt+y(Cr(s,ur))),Vt=y(Vt+y(K(se,ur,xr))),O=n[Ru>>2]|0,h[se+400+(O<<2)>>2]=Vt,!(Ht(Vt)|0))break}else O=n[Ru>>2]|0;Vt=y(Cr(s,ur)),h[se+400+(O<<2)>>2]=y(Vt+y(K(se,ur,xr)));break}O=ha(s,se)|0;do if((O|0)==4){if((n[(Dl(se,ur)|0)+4>>2]|0)==3){Xr=139;break}if((n[(Sc(se,ur)|0)+4>>2]|0)==3){Xr=139;break}if(ts(se,ur,Rn)|0){l=Me;break}hf=n[se+908+(n[xl>>2]<<2)>>2]|0,n[Gs>>2]=hf,l=y(h[se+396>>2]),li=Ht(l)|0,Qe=(n[v>>2]=hf,y(h[v>>2])),li?l=et:(Pr=y(ln(se,ur,xr)),Vt=y(Qe/l),l=y(l*Qe),l=y(Pr+(Vn?Vt:l))),h[Xa>>2]=l,h[Gs>>2]=y(y(ln(se,Rr,xr))+Qe),n[Wo>>2]=1,n[Ql>>2]=1,yr(se,Rr,sr,xr,Wo,Gs),yr(se,ur,Rn,xr,Ql,Xa),l=y(h[Gs>>2]),Pr=y(h[Xa>>2]),Vt=Vn?l:Pr,l=Vn?Pr:l,li=((Ht(Vt)|0)^1)&1,fa(se,Vt,l,Ds,li,((Ht(l)|0)^1)&1,xr,Eo,1,3493,M)|0,l=Me}else Xr=139;while(0);e:do if((Xr|0)==139){Xr=0,l=y(Xe-y(ns(se,ur,xr)));do if((n[(Dl(se,ur)|0)+4>>2]|0)==3){if((n[(Sc(se,ur)|0)+4>>2]|0)!=3)break;l=y(Me+y(_n(y(0),y(l*y(.5)))));break e}while(0);if((n[(Sc(se,ur)|0)+4>>2]|0)==3){l=Me;break}if((n[(Dl(se,ur)|0)+4>>2]|0)==3){l=y(Me+y(_n(y(0),l)));break}switch(O|0){case 1:{l=Me;break e}case 2:{l=y(Me+y(l*y(.5)));break e}default:{l=y(Me+l);break e}}}while(0);Vt=y(vs+l),li=se+400+(n[Ru>>2]<<2)|0,h[li>>2]=y(Vt+y(h[li>>2]))}while(0);G=G+1|0}while((G|0)!=(ar|0))}if(vs=y(vs+et),Qc=y(_n(Qc,c)),m=yo+1|0,ar>>>0>=Ws>>>0)break;l=sr,Lr=ar,yo=m}do if(Q){if(O=m>>>0>1,!O&&!(Yi(s)|0))break;if(!(Ht(Rn)|0)){l=y(Rn-vs);e:do switch(n[s+12>>2]|0){case 3:{Me=y(Me+l),Ue=y(0);break}case 2:{Me=y(Me+y(l*y(.5))),Ue=y(0);break}case 4:{Rn>vs?Ue=y(l/y(m>>>0)):Ue=y(0);break}case 7:if(Rn>vs){Me=y(Me+y(l/y(m<<1>>>0))),Ue=y(l/y(m>>>0)),Ue=O?Ue:y(0);break e}else{Me=y(Me+y(l*y(.5))),Ue=y(0);break e}case 6:{Ue=y(l/y(yo>>>0)),Ue=Rn>vs&O?Ue:y(0);break}default:Ue=y(0)}while(0);if(m|0)for(Nt=1040+(ur<<2)|0,Mr=976+(ur<<2)|0,je=0,G=0;;){e:do if(G>>>0<Ws>>>0)for(Qe=y(0),et=y(0),l=y(0),se=G;;){O=n[(n[wo>>2]|0)+(se<<2)>>2]|0;do if((n[O+36>>2]|0)!=1&&(n[O+24>>2]|0)==0){if((n[O+940>>2]|0)!=(je|0))break e;if(Nm(O,ur)|0&&(Vt=y(h[O+908+(n[Mr>>2]<<2)>>2]),l=y(_n(l,y(Vt+y(ln(O,ur,xr)))))),(ha(s,O)|0)!=5)break;js=y(Wa(O)),js=y(js+y(K(O,0,xr))),Vt=y(h[O+912>>2]),Vt=y(y(Vt+y(ln(O,0,xr)))-js),js=y(_n(et,js)),Vt=y(_n(Qe,Vt)),Qe=Vt,et=js,l=y(_n(l,y(js+Vt)))}while(0);if(O=se+1|0,O>>>0<Ws>>>0)se=O;else{se=O;break}}else et=y(0),l=y(0),se=G;while(0);if(lt=y(Ue+l),c=Me,Me=y(Me+lt),G>>>0<se>>>0){Xe=y(c+et),O=G;do{G=n[(n[wo>>2]|0)+(O<<2)>>2]|0;e:do if((n[G+36>>2]|0)!=1&&(n[G+24>>2]|0)==0)switch(ha(s,G)|0){case 1:{Vt=y(c+y(K(G,ur,xr))),h[G+400+(n[Nt>>2]<<2)>>2]=Vt;break e}case 3:{Vt=y(y(Me-y(re(G,ur,xr)))-y(h[G+908+(n[Mr>>2]<<2)>>2])),h[G+400+(n[Nt>>2]<<2)>>2]=Vt;break e}case 2:{Vt=y(c+y(y(lt-y(h[G+908+(n[Mr>>2]<<2)>>2]))*y(.5))),h[G+400+(n[Nt>>2]<<2)>>2]=Vt;break e}case 4:{if(Vt=y(c+y(K(G,ur,xr))),h[G+400+(n[Nt>>2]<<2)>>2]=Vt,ts(G,ur,Rn)|0||(Vn?(Qe=y(h[G+908>>2]),l=y(Qe+y(ln(G,Rr,xr))),et=lt):(et=y(h[G+912>>2]),et=y(et+y(ln(G,ur,xr))),l=lt,Qe=y(h[G+908>>2])),Ii(l,Qe)|0&&Ii(et,y(h[G+912>>2]))|0))break e;fa(G,l,et,Ds,1,1,xr,Eo,1,3501,M)|0;break e}case 5:{h[G+404>>2]=y(y(Xe-y(Wa(G)))+y(Or(G,0,Rn)));break e}default:break e}while(0);O=O+1|0}while((O|0)!=(se|0))}if(je=je+1|0,(je|0)==(m|0))break;G=se}}}while(0);if(h[s+908>>2]=y(Bi(s,2,Fc,B,B)),h[s+912>>2]=y(Bi(s,0,lf,k,B)),(Fl|0)!=0&&(cf=n[s+32>>2]|0,uf=(Fl|0)==2,!(uf&(cf|0)!=2))?uf&(cf|0)==2&&(l=y(Rc+sr),l=y(_n(y(Lg(l,y(MA(s,Rr,Qc,Co)))),Rc)),Xr=198):(l=y(Bi(s,Rr,Qc,Co,B)),Xr=198),(Xr|0)==198&&(h[s+908+(n[976+(Rr<<2)>>2]<<2)>>2]=l),(Rl|0)!=0&&(ff=n[s+32>>2]|0,pf=(Rl|0)==2,!(pf&(ff|0)!=2))?pf&(ff|0)==2&&(l=y(Ys+Rn),l=y(_n(y(Lg(l,y(MA(s,ur,y(Ys+vs),Tc)))),Ys)),Xr=204):(l=y(Bi(s,ur,y(Ys+vs),Tc,B)),Xr=204),(Xr|0)==204&&(h[s+908+(n[976+(ur<<2)>>2]<<2)>>2]=l),Q){if((n[Af>>2]|0)==2){G=976+(ur<<2)|0,se=1040+(ur<<2)|0,O=0;do je=gs(s,O)|0,n[je+24>>2]|0||(hf=n[G>>2]|0,Vt=y(h[s+908+(hf<<2)>>2]),li=je+400+(n[se>>2]<<2)|0,Vt=y(Vt-y(h[li>>2])),h[li>>2]=y(Vt-y(h[je+908+(hf<<2)>>2]))),O=O+1|0;while((O|0)!=(Ws|0))}if(f|0){O=Vn?Fl:d;do Om(s,f,xr,O,Eo,Ds,M),f=n[f+960>>2]|0;while((f|0)!=0)}if(O=(Rr|2|0)==3,G=(ur|2|0)==3,O|G){f=0;do se=n[(n[wo>>2]|0)+(f<<2)>>2]|0,(n[se+36>>2]|0)!=1&&(O&&Ip(s,se,Rr),G&&Ip(s,se,ur)),f=f+1|0;while((f|0)!=(Ws|0))}}}while(0);C=Tl}function pa(s,l){s=s|0,l=y(l);var c=0;oa(s,l>=y(0),3147),c=l==y(0),h[s+4>>2]=c?y(0):l}function Dc(s,l,c,f){s=s|0,l=y(l),c=y(c),f=f|0;var d=Ze,m=Ze,B=0,k=0,Q=0;n[2278]=(n[2278]|0)+1,vl(s),ts(s,2,l)|0?(d=y(jr(n[s+992>>2]|0,l)),Q=1,d=y(d+y(ln(s,2,l)))):(d=y(jr(s+380|0,l)),d>=y(0)?Q=2:(Q=((Ht(l)|0)^1)&1,d=l)),ts(s,0,c)|0?(m=y(jr(n[s+996>>2]|0,c)),k=1,m=y(m+y(ln(s,0,l)))):(m=y(jr(s+388|0,c)),m>=y(0)?k=2:(k=((Ht(c)|0)^1)&1,m=c)),B=s+976|0,fa(s,d,m,f,Q,k,l,c,1,3189,n[B>>2]|0)|0&&(Cp(s,n[s+496>>2]|0,l,c,l),Pc(s,y(h[(n[B>>2]|0)+4>>2]),y(0),y(0)),o[11696]|0)&&Qm(s,7)}function vl(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;k=C,C=C+32|0,B=k+24|0,m=k+16|0,f=k+8|0,d=k,c=0;do l=s+380+(c<<3)|0,(n[s+380+(c<<3)+4>>2]|0)!=0&&(Q=l,M=n[Q+4>>2]|0,O=f,n[O>>2]=n[Q>>2],n[O+4>>2]=M,O=s+364+(c<<3)|0,M=n[O+4>>2]|0,Q=d,n[Q>>2]=n[O>>2],n[Q+4>>2]=M,n[m>>2]=n[f>>2],n[m+4>>2]=n[f+4>>2],n[B>>2]=n[d>>2],n[B+4>>2]=n[d+4>>2],ws(m,B)|0)||(l=s+348+(c<<3)|0),n[s+992+(c<<2)>>2]=l,c=c+1|0;while((c|0)!=2);C=k}function ts(s,l,c){s=s|0,l=l|0,c=y(c);var f=0;switch(s=n[s+992+(n[976+(l<<2)>>2]<<2)>>2]|0,n[s+4>>2]|0){case 0:case 3:{s=0;break}case 1:{y(h[s>>2])<y(0)?s=0:f=5;break}case 2:{y(h[s>>2])<y(0)?s=0:s=(Ht(c)|0)^1;break}default:f=5}return(f|0)==5&&(s=1),s|0}function jr(s,l){switch(s=s|0,l=y(l),n[s+4>>2]|0){case 2:{l=y(y(y(h[s>>2])*l)/y(100));break}case 1:{l=y(h[s>>2]);break}default:l=y(ue)}return y(l)}function Cp(s,l,c,f,d){s=s|0,l=l|0,c=y(c),f=y(f),d=y(d);var m=0,B=Ze;l=n[s+944>>2]|0?l:1,m=fr(n[s+4>>2]|0,l)|0,l=ww(m,l)|0,c=y(Mm(s,m,c)),f=y(Mm(s,l,f)),B=y(c+y(K(s,m,d))),h[s+400+(n[1040+(m<<2)>>2]<<2)>>2]=B,c=y(c+y(re(s,m,d))),h[s+400+(n[1e3+(m<<2)>>2]<<2)>>2]=c,c=y(f+y(K(s,l,d))),h[s+400+(n[1040+(l<<2)>>2]<<2)>>2]=c,d=y(f+y(re(s,l,d))),h[s+400+(n[1e3+(l<<2)>>2]<<2)>>2]=d}function Pc(s,l,c,f){s=s|0,l=y(l),c=y(c),f=y(f);var d=0,m=0,B=Ze,k=Ze,Q=0,M=0,O=Ze,G=0,se=Ze,je=Ze,Me=Ze,Qe=Ze;if(l!=y(0)&&(d=s+400|0,Qe=y(h[d>>2]),m=s+404|0,Me=y(h[m>>2]),G=s+416|0,je=y(h[G>>2]),M=s+420|0,B=y(h[M>>2]),se=y(Qe+c),O=y(Me+f),f=y(se+je),k=y(O+B),Q=(n[s+988>>2]|0)==1,h[d>>2]=y(jo(Qe,l,0,Q)),h[m>>2]=y(jo(Me,l,0,Q)),c=y(bR(y(je*l),y(1))),Ii(c,y(0))|0?m=0:m=(Ii(c,y(1))|0)^1,c=y(bR(y(B*l),y(1))),Ii(c,y(0))|0?d=0:d=(Ii(c,y(1))|0)^1,Qe=y(jo(f,l,Q&m,Q&(m^1))),h[G>>2]=y(Qe-y(jo(se,l,0,Q))),Qe=y(jo(k,l,Q&d,Q&(d^1))),h[M>>2]=y(Qe-y(jo(O,l,0,Q))),m=(n[s+952>>2]|0)-(n[s+948>>2]|0)>>2,m|0)){d=0;do Pc(gs(s,d)|0,l,se,O),d=d+1|0;while((d|0)!=(m|0))}}function Cw(s,l,c,f,d){switch(s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,c|0){case 5:case 0:{s=i7(n[489]|0,f,d)|0;break}default:s=XUe(f,d)|0}return s|0}function Cg(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;d=C,C=C+16|0,m=d,n[m>>2]=f,wg(s,0,l,c,m),C=d}function wg(s,l,c,f,d){if(s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,s=s|0?s:956,D7[n[s+8>>2]&1](s,l,c,f,d)|0,(c|0)==5)Rt();else return}function Ya(s,l,c){s=s|0,l=l|0,c=c|0,o[s+l>>0]=c&1}function Rm(s,l){s=s|0,l=l|0;var c=0,f=0;n[s>>2]=0,n[s+4>>2]=0,n[s+8>>2]=0,c=l+4|0,f=(n[c>>2]|0)-(n[l>>2]|0)>>2,f|0&&(Ig(s,f),Qt(s,n[l>>2]|0,n[c>>2]|0,f))}function Ig(s,l){s=s|0,l=l|0;var c=0;if((L(s)|0)>>>0<l>>>0&&Jr(s),l>>>0>1073741823)Rt();else{c=Kt(l<<2)|0,n[s+4>>2]=c,n[s>>2]=c,n[s+8>>2]=c+(l<<2);return}}function Qt(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,f=s+4|0,s=c-l|0,(s|0)>0&&(Dr(n[f>>2]|0,l|0,s|0)|0,n[f>>2]=(n[f>>2]|0)+(s>>>2<<2))}function L(s){return s=s|0,1073741823}function K(s,l,c){return s=s|0,l=l|0,c=y(c),pe(l)|0&&(n[s+96>>2]|0)!=0?s=s+92|0:s=Fn(s+60|0,n[1040+(l<<2)>>2]|0,992)|0,y(Je(s,c))}function re(s,l,c){return s=s|0,l=l|0,c=y(c),pe(l)|0&&(n[s+104>>2]|0)!=0?s=s+100|0:s=Fn(s+60|0,n[1e3+(l<<2)>>2]|0,992)|0,y(Je(s,c))}function pe(s){return s=s|0,(s|1|0)==3|0}function Je(s,l){return s=s|0,l=y(l),(n[s+4>>2]|0)==3?l=y(0):l=y(jr(s,l)),y(l)}function mt(s,l){return s=s|0,l=l|0,s=n[s>>2]|0,((s|0)==0?(l|0)>1?l:1:s)|0}function fr(s,l){s=s|0,l=l|0;var c=0;e:do if((l|0)==2){switch(s|0){case 2:{s=3;break e}case 3:break;default:{c=4;break e}}s=2}else c=4;while(0);return s|0}function Cr(s,l){s=s|0,l=l|0;var c=Ze;return pe(l)|0&&(n[s+312>>2]|0)!=0&&(c=y(h[s+308>>2]),c>=y(0))||(c=y(_n(y(h[(Fn(s+276|0,n[1040+(l<<2)>>2]|0,992)|0)>>2]),y(0)))),y(c)}function yn(s,l){s=s|0,l=l|0;var c=Ze;return pe(l)|0&&(n[s+320>>2]|0)!=0&&(c=y(h[s+316>>2]),c>=y(0))||(c=y(_n(y(h[(Fn(s+276|0,n[1e3+(l<<2)>>2]|0,992)|0)>>2]),y(0)))),y(c)}function oi(s,l,c){s=s|0,l=l|0,c=y(c);var f=Ze;return pe(l)|0&&(n[s+240>>2]|0)!=0&&(f=y(jr(s+236|0,c)),f>=y(0))||(f=y(_n(y(jr(Fn(s+204|0,n[1040+(l<<2)>>2]|0,992)|0,c)),y(0)))),y(f)}function Oi(s,l,c){s=s|0,l=l|0,c=y(c);var f=Ze;return pe(l)|0&&(n[s+248>>2]|0)!=0&&(f=y(jr(s+244|0,c)),f>=y(0))||(f=y(_n(y(jr(Fn(s+204|0,n[1e3+(l<<2)>>2]|0,992)|0,c)),y(0)))),y(f)}function Bg(s,l,c,f,d,m,B){s=s|0,l=y(l),c=y(c),f=f|0,d=d|0,m=y(m),B=y(B);var k=Ze,Q=Ze,M=Ze,O=Ze,G=Ze,se=Ze,je=0,Me=0,Qe=0;Qe=C,C=C+16|0,je=Qe,Me=s+964|0,Un(s,(n[Me>>2]|0)!=0,3519),k=y(En(s,2,l)),Q=y(En(s,0,l)),M=y(ln(s,2,l)),O=y(ln(s,0,l)),Ht(l)|0?G=l:G=y(_n(y(0),y(y(l-M)-k))),Ht(c)|0?se=c:se=y(_n(y(0),y(y(c-O)-Q))),(f|0)==1&(d|0)==1?(h[s+908>>2]=y(Bi(s,2,y(l-M),m,m)),l=y(Bi(s,0,y(c-O),B,m))):(P7[n[Me>>2]&1](je,s,G,f,se,d),G=y(k+y(h[je>>2])),se=y(l-M),h[s+908>>2]=y(Bi(s,2,(f|2|0)==2?G:se,m,m)),se=y(Q+y(h[je+4>>2])),l=y(c-O),l=y(Bi(s,0,(d|2|0)==2?se:l,B,m))),h[s+912>>2]=l,C=Qe}function jv(s,l,c,f,d,m,B){s=s|0,l=y(l),c=y(c),f=f|0,d=d|0,m=y(m),B=y(B);var k=Ze,Q=Ze,M=Ze,O=Ze;M=y(En(s,2,m)),k=y(En(s,0,m)),O=y(ln(s,2,m)),Q=y(ln(s,0,m)),l=y(l-O),h[s+908>>2]=y(Bi(s,2,(f|2|0)==2?M:l,m,m)),c=y(c-Q),h[s+912>>2]=y(Bi(s,0,(d|2|0)==2?k:c,B,m))}function Yv(s,l,c,f,d,m,B){s=s|0,l=y(l),c=y(c),f=f|0,d=d|0,m=y(m),B=y(B);var k=0,Q=Ze,M=Ze;return k=(f|0)==2,!(l<=y(0)&k)&&!(c<=y(0)&(d|0)==2)&&!((f|0)==1&(d|0)==1)?s=0:(Q=y(ln(s,0,m)),M=y(ln(s,2,m)),k=l<y(0)&k|(Ht(l)|0),l=y(l-M),h[s+908>>2]=y(Bi(s,2,k?y(0):l,m,m)),l=y(c-Q),k=c<y(0)&(d|0)==2|(Ht(c)|0),h[s+912>>2]=y(Bi(s,0,k?y(0):l,B,m)),s=1),s|0}function ww(s,l){return s=s|0,l=l|0,UA(s)|0?s=fr(2,l)|0:s=0,s|0}function wp(s,l,c){return s=s|0,l=l|0,c=y(c),c=y(oi(s,l,c)),y(c+y(Cr(s,l)))}function Iw(s,l,c){return s=s|0,l=l|0,c=y(c),c=y(Oi(s,l,c)),y(c+y(yn(s,l)))}function En(s,l,c){s=s|0,l=l|0,c=y(c);var f=Ze;return f=y(wp(s,l,c)),y(f+y(Iw(s,l,c)))}function Tm(s){return s=s|0,n[s+24>>2]|0?s=0:y(rs(s))!=y(0)?s=1:s=y(qs(s))!=y(0),s|0}function rs(s){s=s|0;var l=Ze;if(n[s+944>>2]|0){if(l=y(h[s+44>>2]),Ht(l)|0)return l=y(h[s+40>>2]),s=l>y(0)&((Ht(l)|0)^1),y(s?l:y(0))}else l=y(0);return y(l)}function qs(s){s=s|0;var l=Ze,c=0,f=Ze;do if(n[s+944>>2]|0){if(l=y(h[s+48>>2]),Ht(l)|0){if(c=o[(n[s+976>>2]|0)+2>>0]|0,c<<24>>24==0&&(f=y(h[s+40>>2]),f<y(0)&((Ht(f)|0)^1))){l=y(-f);break}l=c<<24>>24?y(1):y(0)}}else l=y(0);while(0);return y(l)}function vu(s){s=s|0;var l=0,c=0;if(Xm(s+400|0,0,540)|0,o[s+985>>0]=1,$(s),c=wi(s)|0,c|0){l=s+948|0,s=0;do vu(n[(n[l>>2]|0)+(s<<2)>>2]|0),s=s+1|0;while((s|0)!=(c|0))}}function Lm(s,l,c,f,d,m,B,k,Q,M){s=s|0,l=l|0,c=y(c),f=f|0,d=y(d),m=y(m),B=y(B),k=k|0,Q=Q|0,M=M|0;var O=0,G=Ze,se=0,je=0,Me=Ze,Qe=Ze,et=0,Xe=Ze,lt=0,Ue=Ze,Ge=0,Nt=0,Mr=0,ar=0,Xt=0,Pr=0,Lr=0,sr=0,xn=0,go=0;xn=C,C=C+16|0,Mr=xn+12|0,ar=xn+8|0,Xt=xn+4|0,Pr=xn,sr=fr(n[s+4>>2]|0,Q)|0,Ge=pe(sr)|0,G=y(jr(Bw(l)|0,Ge?m:B)),Nt=ts(l,2,m)|0,Lr=ts(l,0,B)|0;do if(!(Ht(G)|0)&&!(Ht(Ge?c:d)|0)){if(O=l+504|0,!(Ht(y(h[O>>2]))|0)&&(!(vw(n[l+976>>2]|0,0)|0)||(n[l+500>>2]|0)==(n[2278]|0)))break;h[O>>2]=y(_n(G,y(En(l,sr,m))))}else se=7;while(0);do if((se|0)==7){if(lt=Ge^1,!(lt|Nt^1)){B=y(jr(n[l+992>>2]|0,m)),h[l+504>>2]=y(_n(B,y(En(l,2,m))));break}if(!(Ge|Lr^1)){B=y(jr(n[l+996>>2]|0,B)),h[l+504>>2]=y(_n(B,y(En(l,0,m))));break}h[Mr>>2]=y(ue),h[ar>>2]=y(ue),n[Xt>>2]=0,n[Pr>>2]=0,Xe=y(ln(l,2,m)),Ue=y(ln(l,0,m)),Nt?(Me=y(Xe+y(jr(n[l+992>>2]|0,m))),h[Mr>>2]=Me,n[Xt>>2]=1,je=1):(je=0,Me=y(ue)),Lr?(G=y(Ue+y(jr(n[l+996>>2]|0,B))),h[ar>>2]=G,n[Pr>>2]=1,O=1):(O=0,G=y(ue)),se=n[s+32>>2]|0,Ge&(se|0)==2?se=2:Ht(Me)|0&&!(Ht(c)|0)&&(h[Mr>>2]=c,n[Xt>>2]=2,je=2,Me=c),!((se|0)==2&lt)&&Ht(G)|0&&!(Ht(d)|0)&&(h[ar>>2]=d,n[Pr>>2]=2,O=2,G=d),Qe=y(h[l+396>>2]),et=Ht(Qe)|0;do if(et)se=je;else{if((je|0)==1&lt){h[ar>>2]=y(y(Me-Xe)/Qe),n[Pr>>2]=1,O=1,se=1;break}Ge&(O|0)==1?(h[Mr>>2]=y(Qe*y(G-Ue)),n[Xt>>2]=1,O=1,se=1):se=je}while(0);go=Ht(c)|0,je=(ha(s,l)|0)!=4,!(Ge|Nt|((f|0)!=1|go)|(je|(se|0)==1))&&(h[Mr>>2]=c,n[Xt>>2]=1,!et)&&(h[ar>>2]=y(y(c-Xe)/Qe),n[Pr>>2]=1,O=1),!(Lr|lt|((k|0)!=1|(Ht(d)|0))|(je|(O|0)==1))&&(h[ar>>2]=d,n[Pr>>2]=1,!et)&&(h[Mr>>2]=y(Qe*y(d-Ue)),n[Xt>>2]=1),yr(l,2,m,m,Xt,Mr),yr(l,0,B,m,Pr,ar),c=y(h[Mr>>2]),d=y(h[ar>>2]),fa(l,c,d,Q,n[Xt>>2]|0,n[Pr>>2]|0,m,B,0,3565,M)|0,B=y(h[l+908+(n[976+(sr<<2)>>2]<<2)>>2]),h[l+504>>2]=y(_n(B,y(En(l,sr,m))))}while(0);n[l+500>>2]=n[2278],C=xn}function Bi(s,l,c,f,d){return s=s|0,l=l|0,c=y(c),f=y(f),d=y(d),f=y(MA(s,l,c,f)),y(_n(f,y(En(s,l,d))))}function ha(s,l){return s=s|0,l=l|0,l=l+20|0,l=n[((n[l>>2]|0)==0?s+16|0:l)>>2]|0,(l|0)==5&&UA(n[s+4>>2]|0)|0&&(l=1),l|0}function Dl(s,l){return s=s|0,l=l|0,pe(l)|0&&(n[s+96>>2]|0)!=0?l=4:l=n[1040+(l<<2)>>2]|0,s+60+(l<<3)|0}function Sc(s,l){return s=s|0,l=l|0,pe(l)|0&&(n[s+104>>2]|0)!=0?l=5:l=n[1e3+(l<<2)>>2]|0,s+60+(l<<3)|0}function yr(s,l,c,f,d,m){switch(s=s|0,l=l|0,c=y(c),f=y(f),d=d|0,m=m|0,c=y(jr(s+380+(n[976+(l<<2)>>2]<<3)|0,c)),c=y(c+y(ln(s,l,f))),n[d>>2]|0){case 2:case 1:{d=Ht(c)|0,f=y(h[m>>2]),h[m>>2]=d|f<c?f:c;break}case 0:{Ht(c)|0||(n[d>>2]=2,h[m>>2]=c);break}default:}}function gi(s,l){return s=s|0,l=l|0,s=s+132|0,pe(l)|0&&(n[(Fn(s,4,948)|0)+4>>2]|0)!=0?s=1:s=(n[(Fn(s,n[1040+(l<<2)>>2]|0,948)|0)+4>>2]|0)!=0,s|0}function Or(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0;return s=s+132|0,pe(l)|0&&(f=Fn(s,4,948)|0,(n[f+4>>2]|0)!=0)?d=4:(f=Fn(s,n[1040+(l<<2)>>2]|0,948)|0,n[f+4>>2]|0?d=4:c=y(0)),(d|0)==4&&(c=y(jr(f,c))),y(c)}function ns(s,l,c){s=s|0,l=l|0,c=y(c);var f=Ze;return f=y(h[s+908+(n[976+(l<<2)>>2]<<2)>>2]),f=y(f+y(K(s,l,c))),y(f+y(re(s,l,c)))}function Yi(s){s=s|0;var l=0,c=0,f=0;e:do if(UA(n[s+4>>2]|0)|0)l=0;else if((n[s+16>>2]|0)!=5)if(c=wi(s)|0,!c)l=0;else for(l=0;;){if(f=gs(s,l)|0,(n[f+24>>2]|0)==0&&(n[f+20>>2]|0)==5){l=1;break e}if(l=l+1|0,l>>>0>=c>>>0){l=0;break}}else l=1;while(0);return l|0}function Nm(s,l){s=s|0,l=l|0;var c=Ze;return c=y(h[s+908+(n[976+(l<<2)>>2]<<2)>>2]),c>=y(0)&((Ht(c)|0)^1)|0}function Wa(s){s=s|0;var l=Ze,c=0,f=0,d=0,m=0,B=0,k=0,Q=Ze;if(c=n[s+968>>2]|0,c)Q=y(h[s+908>>2]),l=y(h[s+912>>2]),l=y(w7[c&0](s,Q,l)),Un(s,(Ht(l)|0)^1,3573);else{m=wi(s)|0;do if(m|0){for(c=0,d=0;;){if(f=gs(s,d)|0,n[f+940>>2]|0){B=8;break}if((n[f+24>>2]|0)!=1)if(k=(ha(s,f)|0)==5,k){c=f;break}else c=(c|0)==0?f:c;if(d=d+1|0,d>>>0>=m>>>0){B=8;break}}if((B|0)==8&&!c)break;return l=y(Wa(c)),y(l+y(h[c+404>>2]))}while(0);l=y(h[s+912>>2])}return y(l)}function MA(s,l,c,f){s=s|0,l=l|0,c=y(c),f=y(f);var d=Ze,m=0;return UA(l)|0?(l=1,m=3):pe(l)|0?(l=0,m=3):(f=y(ue),d=y(ue)),(m|0)==3&&(d=y(jr(s+364+(l<<3)|0,f)),f=y(jr(s+380+(l<<3)|0,f))),m=f<c&(f>=y(0)&((Ht(f)|0)^1)),c=m?f:c,m=d>=y(0)&((Ht(d)|0)^1)&c<d,y(m?d:c)}function Om(s,l,c,f,d,m,B){s=s|0,l=l|0,c=y(c),f=f|0,d=y(d),m=m|0,B=B|0;var k=Ze,Q=Ze,M=0,O=0,G=Ze,se=Ze,je=Ze,Me=0,Qe=0,et=0,Xe=0,lt=Ze,Ue=0;et=fr(n[s+4>>2]|0,m)|0,Me=ww(et,m)|0,Qe=pe(et)|0,G=y(ln(l,2,c)),se=y(ln(l,0,c)),ts(l,2,c)|0?k=y(G+y(jr(n[l+992>>2]|0,c))):gi(l,2)|0&&or(l,2)|0?(k=y(h[s+908>>2]),Q=y(Cr(s,2)),Q=y(k-y(Q+y(yn(s,2)))),k=y(Or(l,2,c)),k=y(Bi(l,2,y(Q-y(k+y(Du(l,2,c)))),c,c))):k=y(ue),ts(l,0,d)|0?Q=y(se+y(jr(n[l+996>>2]|0,d))):gi(l,0)|0&&or(l,0)|0?(Q=y(h[s+912>>2]),lt=y(Cr(s,0)),lt=y(Q-y(lt+y(yn(s,0)))),Q=y(Or(l,0,d)),Q=y(Bi(l,0,y(lt-y(Q+y(Du(l,0,d)))),d,c))):Q=y(ue),M=Ht(k)|0,O=Ht(Q)|0;do if(M^O&&(je=y(h[l+396>>2]),!(Ht(je)|0)))if(M){k=y(G+y(y(Q-se)*je));break}else{lt=y(se+y(y(k-G)/je)),Q=O?lt:Q;break}while(0);O=Ht(k)|0,M=Ht(Q)|0,O|M&&(Ue=(O^1)&1,f=c>y(0)&((f|0)!=0&O),k=Qe?k:f?c:k,fa(l,k,Q,m,Qe?Ue:f?2:Ue,O&(M^1)&1,k,Q,0,3623,B)|0,k=y(h[l+908>>2]),k=y(k+y(ln(l,2,c))),Q=y(h[l+912>>2]),Q=y(Q+y(ln(l,0,c)))),fa(l,k,Q,m,1,1,k,Q,1,3635,B)|0,or(l,et)|0&&!(gi(l,et)|0)?(Ue=n[976+(et<<2)>>2]|0,lt=y(h[s+908+(Ue<<2)>>2]),lt=y(lt-y(h[l+908+(Ue<<2)>>2])),lt=y(lt-y(yn(s,et))),lt=y(lt-y(re(l,et,c))),lt=y(lt-y(Du(l,et,Qe?c:d))),h[l+400+(n[1040+(et<<2)>>2]<<2)>>2]=lt):Xe=21;do if((Xe|0)==21){if(!(gi(l,et)|0)&&(n[s+8>>2]|0)==1){Ue=n[976+(et<<2)>>2]|0,lt=y(h[s+908+(Ue<<2)>>2]),lt=y(y(lt-y(h[l+908+(Ue<<2)>>2]))*y(.5)),h[l+400+(n[1040+(et<<2)>>2]<<2)>>2]=lt;break}!(gi(l,et)|0)&&(n[s+8>>2]|0)==2&&(Ue=n[976+(et<<2)>>2]|0,lt=y(h[s+908+(Ue<<2)>>2]),lt=y(lt-y(h[l+908+(Ue<<2)>>2])),h[l+400+(n[1040+(et<<2)>>2]<<2)>>2]=lt)}while(0);or(l,Me)|0&&!(gi(l,Me)|0)?(Ue=n[976+(Me<<2)>>2]|0,lt=y(h[s+908+(Ue<<2)>>2]),lt=y(lt-y(h[l+908+(Ue<<2)>>2])),lt=y(lt-y(yn(s,Me))),lt=y(lt-y(re(l,Me,c))),lt=y(lt-y(Du(l,Me,Qe?d:c))),h[l+400+(n[1040+(Me<<2)>>2]<<2)>>2]=lt):Xe=30;do if((Xe|0)==30&&!(gi(l,Me)|0)){if((ha(s,l)|0)==2){Ue=n[976+(Me<<2)>>2]|0,lt=y(h[s+908+(Ue<<2)>>2]),lt=y(y(lt-y(h[l+908+(Ue<<2)>>2]))*y(.5)),h[l+400+(n[1040+(Me<<2)>>2]<<2)>>2]=lt;break}Ue=(ha(s,l)|0)==3,Ue^(n[s+28>>2]|0)==2&&(Ue=n[976+(Me<<2)>>2]|0,lt=y(h[s+908+(Ue<<2)>>2]),lt=y(lt-y(h[l+908+(Ue<<2)>>2])),h[l+400+(n[1040+(Me<<2)>>2]<<2)>>2]=lt)}while(0)}function Ip(s,l,c){s=s|0,l=l|0,c=c|0;var f=Ze,d=0;d=n[976+(c<<2)>>2]|0,f=y(h[l+908+(d<<2)>>2]),f=y(y(h[s+908+(d<<2)>>2])-f),f=y(f-y(h[l+400+(n[1040+(c<<2)>>2]<<2)>>2])),h[l+400+(n[1e3+(c<<2)>>2]<<2)>>2]=f}function UA(s){return s=s|0,(s|1|0)==1|0}function Bw(s){s=s|0;var l=Ze;switch(n[s+56>>2]|0){case 0:case 3:{l=y(h[s+40>>2]),l>y(0)&((Ht(l)|0)^1)?s=o[(n[s+976>>2]|0)+2>>0]|0?1056:992:s=1056;break}default:s=s+52|0}return s|0}function vw(s,l){return s=s|0,l=l|0,(o[s+l>>0]|0)!=0|0}function or(s,l){return s=s|0,l=l|0,s=s+132|0,pe(l)|0&&(n[(Fn(s,5,948)|0)+4>>2]|0)!=0?s=1:s=(n[(Fn(s,n[1e3+(l<<2)>>2]|0,948)|0)+4>>2]|0)!=0,s|0}function Du(s,l,c){s=s|0,l=l|0,c=y(c);var f=0,d=0;return s=s+132|0,pe(l)|0&&(f=Fn(s,5,948)|0,(n[f+4>>2]|0)!=0)?d=4:(f=Fn(s,n[1e3+(l<<2)>>2]|0,948)|0,n[f+4>>2]|0?d=4:c=y(0)),(d|0)==4&&(c=y(jr(f,c))),y(c)}function Mm(s,l,c){return s=s|0,l=l|0,c=y(c),gi(s,l)|0?c=y(Or(s,l,c)):c=y(-y(Du(s,l,c))),y(c)}function Pu(s){return s=y(s),h[v>>2]=s,n[v>>2]|0|0}function Bp(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>1073741823)Rt();else{d=Kt(l<<2)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<2)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<2)}function vg(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>2)<<2)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function _A(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-4-l|0)>>>2)<<2)),s=n[s>>2]|0,s|0&&gt(s)}function HA(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;if(B=s+4|0,k=n[B>>2]|0,d=k-f|0,m=d>>2,s=l+(m<<2)|0,s>>>0<c>>>0){f=k;do n[f>>2]=n[s>>2],s=s+4|0,f=(n[B>>2]|0)+4|0,n[B>>2]=f;while(s>>>0<c>>>0)}m|0&&Mw(k+(0-m<<2)|0,l|0,d|0)|0}function Dg(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0;return k=l+4|0,Q=n[k>>2]|0,d=n[s>>2]|0,B=c,m=B-d|0,f=Q+(0-(m>>2)<<2)|0,n[k>>2]=f,(m|0)>0&&Dr(f|0,d|0,m|0)|0,d=s+4|0,m=l+8|0,f=(n[d>>2]|0)-B|0,(f|0)>0&&(Dr(n[m>>2]|0,c|0,f|0)|0,n[m>>2]=(n[m>>2]|0)+(f>>>2<<2)),B=n[s>>2]|0,n[s>>2]=n[k>>2],n[k>>2]=B,B=n[d>>2]|0,n[d>>2]=n[m>>2],n[m>>2]=B,B=s+8|0,c=l+12|0,s=n[B>>2]|0,n[B>>2]=n[c>>2],n[c>>2]=s,n[l>>2]=n[k>>2],Q|0}function Dw(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;if(B=n[l>>2]|0,m=n[c>>2]|0,(B|0)!=(m|0)){d=s+8|0,c=((m+-4-B|0)>>>2)+1|0,s=B,f=n[d>>2]|0;do n[f>>2]=n[s>>2],f=(n[d>>2]|0)+4|0,n[d>>2]=f,s=s+4|0;while((s|0)!=(m|0));n[l>>2]=B+(c<<2)}}function Um(){mc()}function ga(){var s=0;return s=Kt(4)|0,qA(s),s|0}function qA(s){s=s|0,n[s>>2]=ys()|0}function bc(s){s=s|0,s|0&&(Pg(s),gt(s))}function Pg(s){s=s|0,tt(n[s>>2]|0)}function _m(s,l,c){s=s|0,l=l|0,c=c|0,Ya(n[s>>2]|0,l,c)}function fo(s,l){s=s|0,l=y(l),pa(n[s>>2]|0,l)}function Wv(s,l){return s=s|0,l=l|0,vw(n[s>>2]|0,l)|0}function Pw(){var s=0;return s=Kt(8)|0,Kv(s,0),s|0}function Kv(s,l){s=s|0,l=l|0,l?l=Ci(n[l>>2]|0)|0:l=co()|0,n[s>>2]=l,n[s+4>>2]=0,bi(l,s)}function AF(s){s=s|0;var l=0;return l=Kt(8)|0,Kv(l,s),l|0}function zv(s){s=s|0,s|0&&(Su(s),gt(s))}function Su(s){s=s|0;var l=0;la(n[s>>2]|0),l=s+4|0,s=n[l>>2]|0,n[l>>2]=0,s|0&&(GA(s),gt(s))}function GA(s){s=s|0,jA(s)}function jA(s){s=s|0,s=n[s>>2]|0,s|0&&SA(s|0)}function Sw(s){return s=s|0,qo(s)|0}function Hm(s){s=s|0;var l=0,c=0;c=s+4|0,l=n[c>>2]|0,n[c>>2]=0,l|0&&(GA(l),gt(l)),_s(n[s>>2]|0)}function fF(s,l){s=s|0,l=l|0,$r(n[s>>2]|0,n[l>>2]|0)}function pF(s,l){s=s|0,l=l|0,ca(n[s>>2]|0,l)}function Vv(s,l,c){s=s|0,l=l|0,c=+c,Eu(n[s>>2]|0,l,y(c))}function Jv(s,l,c){s=s|0,l=l|0,c=+c,Es(n[s>>2]|0,l,y(c))}function bw(s,l){s=s|0,l=l|0,du(n[s>>2]|0,l)}function bu(s,l){s=s|0,l=l|0,mu(n[s>>2]|0,l)}function hF(s,l){s=s|0,l=l|0,FA(n[s>>2]|0,l)}function gF(s,l){s=s|0,l=l|0,kA(n[s>>2]|0,l)}function vp(s,l){s=s|0,l=l|0,Ec(n[s>>2]|0,l)}function dF(s,l){s=s|0,l=l|0,fp(n[s>>2]|0,l)}function Xv(s,l,c){s=s|0,l=l|0,c=+c,wc(n[s>>2]|0,l,y(c))}function YA(s,l,c){s=s|0,l=l|0,c=+c,j(n[s>>2]|0,l,y(c))}function mF(s,l){s=s|0,l=l|0,Il(n[s>>2]|0,l)}function yF(s,l){s=s|0,l=l|0,lg(n[s>>2]|0,l)}function Zv(s,l){s=s|0,l=l|0,pp(n[s>>2]|0,l)}function xw(s,l){s=s|0,l=+l,RA(n[s>>2]|0,y(l))}function kw(s,l){s=s|0,l=+l,qa(n[s>>2]|0,y(l))}function EF(s,l){s=s|0,l=+l,ji(n[s>>2]|0,y(l))}function CF(s,l){s=s|0,l=+l,Hs(n[s>>2]|0,y(l))}function Pl(s,l){s=s|0,l=+l,yu(n[s>>2]|0,y(l))}function Qw(s,l){s=s|0,l=+l,yw(n[s>>2]|0,y(l))}function wF(s,l){s=s|0,l=+l,TA(n[s>>2]|0,y(l))}function WA(s){s=s|0,hp(n[s>>2]|0)}function qm(s,l){s=s|0,l=+l,Cs(n[s>>2]|0,y(l))}function xu(s,l){s=s|0,l=+l,Ag(n[s>>2]|0,y(l))}function Fw(s){s=s|0,fg(n[s>>2]|0)}function Rw(s,l){s=s|0,l=+l,gp(n[s>>2]|0,y(l))}function IF(s,l){s=s|0,l=+l,Bc(n[s>>2]|0,y(l))}function $v(s,l){s=s|0,l=+l,bm(n[s>>2]|0,y(l))}function KA(s,l){s=s|0,l=+l,hg(n[s>>2]|0,y(l))}function eD(s,l){s=s|0,l=+l,wu(n[s>>2]|0,y(l))}function Gm(s,l){s=s|0,l=+l,xm(n[s>>2]|0,y(l))}function tD(s,l){s=s|0,l=+l,Iu(n[s>>2]|0,y(l))}function rD(s,l){s=s|0,l=+l,Ew(n[s>>2]|0,y(l))}function jm(s,l){s=s|0,l=+l,Aa(n[s>>2]|0,y(l))}function nD(s,l,c){s=s|0,l=l|0,c=+c,Cu(n[s>>2]|0,l,y(c))}function BF(s,l,c){s=s|0,l=l|0,c=+c,xi(n[s>>2]|0,l,y(c))}function P(s,l,c){s=s|0,l=l|0,c=+c,Ic(n[s>>2]|0,l,y(c))}function D(s){return s=s|0,ag(n[s>>2]|0)|0}function T(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;f=C,C=C+16|0,d=f,Cc(d,n[l>>2]|0,c),q(s,d),C=f}function q(s,l){s=s|0,l=l|0,Y(s,n[l+4>>2]|0,+y(h[l>>2]))}function Y(s,l,c){s=s|0,l=l|0,c=+c,n[s>>2]=l,E[s+8>>3]=c}function Ae(s){return s=s|0,og(n[s>>2]|0)|0}function De(s){return s=s|0,uo(n[s>>2]|0)|0}function vt(s){return s=s|0,yc(n[s>>2]|0)|0}function wt(s){return s=s|0,QA(n[s>>2]|0)|0}function xt(s){return s=s|0,Sm(n[s>>2]|0)|0}function _r(s){return s=s|0,sg(n[s>>2]|0)|0}function is(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;f=C,C=C+16|0,d=f,Dt(d,n[l>>2]|0,c),q(s,d),C=f}function di(s){return s=s|0,ei(n[s>>2]|0)|0}function po(s){return s=s|0,cg(n[s>>2]|0)|0}function zA(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c,ua(f,n[l>>2]|0),q(s,f),C=c}function Yo(s){return s=s|0,+ +y(Gi(n[s>>2]|0))}function rt(s){return s=s|0,+ +y(es(n[s>>2]|0))}function ze(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c,Br(f,n[l>>2]|0),q(s,f),C=c}function ft(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c,pg(f,n[l>>2]|0),q(s,f),C=c}function Wt(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c,Ct(f,n[l>>2]|0),q(s,f),C=c}function vr(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c,gg(f,n[l>>2]|0),q(s,f),C=c}function Sn(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c,dg(f,n[l>>2]|0),q(s,f),C=c}function Fr(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c,km(f,n[l>>2]|0),q(s,f),C=c}function bn(s){return s=s|0,+ +y(vc(n[s>>2]|0))}function ai(s,l){return s=s|0,l=l|0,+ +y(ug(n[s>>2]|0,l))}function tn(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;f=C,C=C+16|0,d=f,ct(d,n[l>>2]|0,c),q(s,d),C=f}function ho(s,l,c){s=s|0,l=l|0,c=c|0,ir(n[s>>2]|0,n[l>>2]|0,c)}function vF(s,l){s=s|0,l=l|0,ms(n[s>>2]|0,n[l>>2]|0)}function tve(s){return s=s|0,wi(n[s>>2]|0)|0}function rve(s){return s=s|0,s=ht(n[s>>2]|0)|0,s?s=Sw(s)|0:s=0,s|0}function nve(s,l){return s=s|0,l=l|0,s=gs(n[s>>2]|0,l)|0,s?s=Sw(s)|0:s=0,s|0}function ive(s,l){s=s|0,l=l|0;var c=0,f=0;f=Kt(4)|0,Jj(f,l),c=s+4|0,l=n[c>>2]|0,n[c>>2]=f,l|0&&(GA(l),gt(l)),It(n[s>>2]|0,1)}function Jj(s,l){s=s|0,l=l|0,dve(s,l)}function sve(s,l,c,f,d,m){s=s|0,l=l|0,c=y(c),f=f|0,d=y(d),m=m|0;var B=0,k=0;B=C,C=C+16|0,k=B,ove(k,qo(l)|0,+c,f,+d,m),h[s>>2]=y(+E[k>>3]),h[s+4>>2]=y(+E[k+8>>3]),C=B}function ove(s,l,c,f,d,m){s=s|0,l=l|0,c=+c,f=f|0,d=+d,m=m|0;var B=0,k=0,Q=0,M=0,O=0;B=C,C=C+32|0,O=B+8|0,M=B+20|0,Q=B,k=B+16|0,E[O>>3]=c,n[M>>2]=f,E[Q>>3]=d,n[k>>2]=m,ave(s,n[l+4>>2]|0,O,M,Q,k),C=B}function ave(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0;var B=0,k=0;B=C,C=C+16|0,k=B,za(k),l=da(l)|0,lve(s,l,+E[c>>3],n[f>>2]|0,+E[d>>3],n[m>>2]|0),Va(k),C=B}function da(s){return s=s|0,n[s>>2]|0}function lve(s,l,c,f,d,m){s=s|0,l=l|0,c=+c,f=f|0,d=+d,m=m|0;var B=0;B=Sl(cve()|0)|0,c=+VA(c),f=DF(f)|0,d=+VA(d),uve(s,hi(0,B|0,l|0,+c,f|0,+d,DF(m)|0)|0)}function cve(){var s=0;return o[7608]|0||(hve(9120),s=7608,n[s>>2]=1,n[s+4>>2]=0),9120}function Sl(s){return s=s|0,n[s+8>>2]|0}function VA(s){return s=+s,+ +PF(s)}function DF(s){return s=s|0,Zj(s)|0}function uve(s,l){s=s|0,l=l|0;var c=0,f=0,d=0;d=C,C=C+32|0,c=d,f=l,f&1?(Ave(c,0),ii(f|0,c|0)|0,fve(s,c),pve(c)):(n[s>>2]=n[l>>2],n[s+4>>2]=n[l+4>>2],n[s+8>>2]=n[l+8>>2],n[s+12>>2]=n[l+12>>2]),C=d}function Ave(s,l){s=s|0,l=l|0,Xj(s,l),n[s+8>>2]=0,o[s+24>>0]=0}function fve(s,l){s=s|0,l=l|0,l=l+8|0,n[s>>2]=n[l>>2],n[s+4>>2]=n[l+4>>2],n[s+8>>2]=n[l+8>>2],n[s+12>>2]=n[l+12>>2]}function pve(s){s=s|0,o[s+24>>0]=0}function Xj(s,l){s=s|0,l=l|0,n[s>>2]=l}function Zj(s){return s=s|0,s|0}function PF(s){return s=+s,+s}function hve(s){s=s|0,bl(s,gve()|0,4)}function gve(){return 1064}function bl(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c,n[s+8>>2]=Ap(l|0,c+1|0)|0}function dve(s,l){s=s|0,l=l|0,l=n[l>>2]|0,n[s>>2]=l,El(l|0)}function mve(s){s=s|0;var l=0,c=0;c=s+4|0,l=n[c>>2]|0,n[c>>2]=0,l|0&&(GA(l),gt(l)),It(n[s>>2]|0,0)}function yve(s){s=s|0,Tt(n[s>>2]|0)}function Eve(s){return s=s|0,er(n[s>>2]|0)|0}function Cve(s,l,c,f){s=s|0,l=+l,c=+c,f=f|0,Dc(n[s>>2]|0,y(l),y(c),f)}function wve(s){return s=s|0,+ +y(Bl(n[s>>2]|0))}function Ive(s){return s=s|0,+ +y(mg(n[s>>2]|0))}function Bve(s){return s=s|0,+ +y(Bu(n[s>>2]|0))}function vve(s){return s=s|0,+ +y(LA(n[s>>2]|0))}function Dve(s){return s=s|0,+ +y(dp(n[s>>2]|0))}function Pve(s){return s=s|0,+ +y(Ga(n[s>>2]|0))}function Sve(s,l){s=s|0,l=l|0,E[s>>3]=+y(Bl(n[l>>2]|0)),E[s+8>>3]=+y(mg(n[l>>2]|0)),E[s+16>>3]=+y(Bu(n[l>>2]|0)),E[s+24>>3]=+y(LA(n[l>>2]|0)),E[s+32>>3]=+y(dp(n[l>>2]|0)),E[s+40>>3]=+y(Ga(n[l>>2]|0))}function bve(s,l){return s=s|0,l=l|0,+ +y(yg(n[s>>2]|0,l))}function xve(s,l){return s=s|0,l=l|0,+ +y(mp(n[s>>2]|0,l))}function kve(s,l){return s=s|0,l=l|0,+ +y(Go(n[s>>2]|0,l))}function Qve(){return Pn()|0}function Fve(){Rve(),Tve(),Lve(),Nve(),Ove(),Mve()}function Rve(){OLe(11713,4938,1)}function Tve(){rLe(10448)}function Lve(){OTe(10408)}function Nve(){oTe(10324)}function Ove(){hFe(10096)}function Mve(){Uve(9132)}function Uve(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0,je=0,Me=0,Qe=0,et=0,Xe=0,lt=0,Ue=0,Ge=0,Nt=0,Mr=0,ar=0,Xt=0,Pr=0,Lr=0,sr=0,xn=0,go=0,mo=0,yo=0,ya=0,Rp=0,Tp=0,xl=0,Lp=0,Ru=0,Tu=0,Np=0,Op=0,Mp=0,Xr=0,kl=0,Up=0,kc=0,_p=0,Hp=0,Lu=0,Nu=0,Qc=0,Gs=0,Xa=0,Wo=0,Ql=0,nf=0,sf=0,Ou=0,of=0,af=0,js=0,vs=0,Fl=0,Rn=0,lf=0,Eo=0,Fc=0,Co=0,Rc=0,cf=0,uf=0,Tc=0,Ys=0,Rl=0,Af=0,ff=0,pf=0,xr=0,Vn=0,Ds=0,wo=0,Ws=0,Rr=0,ur=0,Tl=0;l=C,C=C+672|0,c=l+656|0,Tl=l+648|0,ur=l+640|0,Rr=l+632|0,Ws=l+624|0,wo=l+616|0,Ds=l+608|0,Vn=l+600|0,xr=l+592|0,pf=l+584|0,ff=l+576|0,Af=l+568|0,Rl=l+560|0,Ys=l+552|0,Tc=l+544|0,uf=l+536|0,cf=l+528|0,Rc=l+520|0,Co=l+512|0,Fc=l+504|0,Eo=l+496|0,lf=l+488|0,Rn=l+480|0,Fl=l+472|0,vs=l+464|0,js=l+456|0,af=l+448|0,of=l+440|0,Ou=l+432|0,sf=l+424|0,nf=l+416|0,Ql=l+408|0,Wo=l+400|0,Xa=l+392|0,Gs=l+384|0,Qc=l+376|0,Nu=l+368|0,Lu=l+360|0,Hp=l+352|0,_p=l+344|0,kc=l+336|0,Up=l+328|0,kl=l+320|0,Xr=l+312|0,Mp=l+304|0,Op=l+296|0,Np=l+288|0,Tu=l+280|0,Ru=l+272|0,Lp=l+264|0,xl=l+256|0,Tp=l+248|0,Rp=l+240|0,ya=l+232|0,yo=l+224|0,mo=l+216|0,go=l+208|0,xn=l+200|0,sr=l+192|0,Lr=l+184|0,Pr=l+176|0,Xt=l+168|0,ar=l+160|0,Mr=l+152|0,Nt=l+144|0,Ge=l+136|0,Ue=l+128|0,lt=l+120|0,Xe=l+112|0,et=l+104|0,Qe=l+96|0,Me=l+88|0,je=l+80|0,se=l+72|0,G=l+64|0,O=l+56|0,M=l+48|0,Q=l+40|0,k=l+32|0,B=l+24|0,m=l+16|0,d=l+8|0,f=l,_ve(s,3646),Hve(s,3651,2)|0,qve(s,3665,2)|0,Gve(s,3682,18)|0,n[Tl>>2]=19,n[Tl+4>>2]=0,n[c>>2]=n[Tl>>2],n[c+4>>2]=n[Tl+4>>2],Tw(s,3690,c)|0,n[ur>>2]=1,n[ur+4>>2]=0,n[c>>2]=n[ur>>2],n[c+4>>2]=n[ur+4>>2],jve(s,3696,c)|0,n[Rr>>2]=2,n[Rr+4>>2]=0,n[c>>2]=n[Rr>>2],n[c+4>>2]=n[Rr+4>>2],ku(s,3706,c)|0,n[Ws>>2]=1,n[Ws+4>>2]=0,n[c>>2]=n[Ws>>2],n[c+4>>2]=n[Ws+4>>2],Sg(s,3722,c)|0,n[wo>>2]=2,n[wo+4>>2]=0,n[c>>2]=n[wo>>2],n[c+4>>2]=n[wo+4>>2],Sg(s,3734,c)|0,n[Ds>>2]=3,n[Ds+4>>2]=0,n[c>>2]=n[Ds>>2],n[c+4>>2]=n[Ds+4>>2],ku(s,3753,c)|0,n[Vn>>2]=4,n[Vn+4>>2]=0,n[c>>2]=n[Vn>>2],n[c+4>>2]=n[Vn+4>>2],ku(s,3769,c)|0,n[xr>>2]=5,n[xr+4>>2]=0,n[c>>2]=n[xr>>2],n[c+4>>2]=n[xr+4>>2],ku(s,3783,c)|0,n[pf>>2]=6,n[pf+4>>2]=0,n[c>>2]=n[pf>>2],n[c+4>>2]=n[pf+4>>2],ku(s,3796,c)|0,n[ff>>2]=7,n[ff+4>>2]=0,n[c>>2]=n[ff>>2],n[c+4>>2]=n[ff+4>>2],ku(s,3813,c)|0,n[Af>>2]=8,n[Af+4>>2]=0,n[c>>2]=n[Af>>2],n[c+4>>2]=n[Af+4>>2],ku(s,3825,c)|0,n[Rl>>2]=3,n[Rl+4>>2]=0,n[c>>2]=n[Rl>>2],n[c+4>>2]=n[Rl+4>>2],Sg(s,3843,c)|0,n[Ys>>2]=4,n[Ys+4>>2]=0,n[c>>2]=n[Ys>>2],n[c+4>>2]=n[Ys+4>>2],Sg(s,3853,c)|0,n[Tc>>2]=9,n[Tc+4>>2]=0,n[c>>2]=n[Tc>>2],n[c+4>>2]=n[Tc+4>>2],ku(s,3870,c)|0,n[uf>>2]=10,n[uf+4>>2]=0,n[c>>2]=n[uf>>2],n[c+4>>2]=n[uf+4>>2],ku(s,3884,c)|0,n[cf>>2]=11,n[cf+4>>2]=0,n[c>>2]=n[cf>>2],n[c+4>>2]=n[cf+4>>2],ku(s,3896,c)|0,n[Rc>>2]=1,n[Rc+4>>2]=0,n[c>>2]=n[Rc>>2],n[c+4>>2]=n[Rc+4>>2],Is(s,3907,c)|0,n[Co>>2]=2,n[Co+4>>2]=0,n[c>>2]=n[Co>>2],n[c+4>>2]=n[Co+4>>2],Is(s,3915,c)|0,n[Fc>>2]=3,n[Fc+4>>2]=0,n[c>>2]=n[Fc>>2],n[c+4>>2]=n[Fc+4>>2],Is(s,3928,c)|0,n[Eo>>2]=4,n[Eo+4>>2]=0,n[c>>2]=n[Eo>>2],n[c+4>>2]=n[Eo+4>>2],Is(s,3948,c)|0,n[lf>>2]=5,n[lf+4>>2]=0,n[c>>2]=n[lf>>2],n[c+4>>2]=n[lf+4>>2],Is(s,3960,c)|0,n[Rn>>2]=6,n[Rn+4>>2]=0,n[c>>2]=n[Rn>>2],n[c+4>>2]=n[Rn+4>>2],Is(s,3974,c)|0,n[Fl>>2]=7,n[Fl+4>>2]=0,n[c>>2]=n[Fl>>2],n[c+4>>2]=n[Fl+4>>2],Is(s,3983,c)|0,n[vs>>2]=20,n[vs+4>>2]=0,n[c>>2]=n[vs>>2],n[c+4>>2]=n[vs+4>>2],Tw(s,3999,c)|0,n[js>>2]=8,n[js+4>>2]=0,n[c>>2]=n[js>>2],n[c+4>>2]=n[js+4>>2],Is(s,4012,c)|0,n[af>>2]=9,n[af+4>>2]=0,n[c>>2]=n[af>>2],n[c+4>>2]=n[af+4>>2],Is(s,4022,c)|0,n[of>>2]=21,n[of+4>>2]=0,n[c>>2]=n[of>>2],n[c+4>>2]=n[of+4>>2],Tw(s,4039,c)|0,n[Ou>>2]=10,n[Ou+4>>2]=0,n[c>>2]=n[Ou>>2],n[c+4>>2]=n[Ou+4>>2],Is(s,4053,c)|0,n[sf>>2]=11,n[sf+4>>2]=0,n[c>>2]=n[sf>>2],n[c+4>>2]=n[sf+4>>2],Is(s,4065,c)|0,n[nf>>2]=12,n[nf+4>>2]=0,n[c>>2]=n[nf>>2],n[c+4>>2]=n[nf+4>>2],Is(s,4084,c)|0,n[Ql>>2]=13,n[Ql+4>>2]=0,n[c>>2]=n[Ql>>2],n[c+4>>2]=n[Ql+4>>2],Is(s,4097,c)|0,n[Wo>>2]=14,n[Wo+4>>2]=0,n[c>>2]=n[Wo>>2],n[c+4>>2]=n[Wo+4>>2],Is(s,4117,c)|0,n[Xa>>2]=15,n[Xa+4>>2]=0,n[c>>2]=n[Xa>>2],n[c+4>>2]=n[Xa+4>>2],Is(s,4129,c)|0,n[Gs>>2]=16,n[Gs+4>>2]=0,n[c>>2]=n[Gs>>2],n[c+4>>2]=n[Gs+4>>2],Is(s,4148,c)|0,n[Qc>>2]=17,n[Qc+4>>2]=0,n[c>>2]=n[Qc>>2],n[c+4>>2]=n[Qc+4>>2],Is(s,4161,c)|0,n[Nu>>2]=18,n[Nu+4>>2]=0,n[c>>2]=n[Nu>>2],n[c+4>>2]=n[Nu+4>>2],Is(s,4181,c)|0,n[Lu>>2]=5,n[Lu+4>>2]=0,n[c>>2]=n[Lu>>2],n[c+4>>2]=n[Lu+4>>2],Sg(s,4196,c)|0,n[Hp>>2]=6,n[Hp+4>>2]=0,n[c>>2]=n[Hp>>2],n[c+4>>2]=n[Hp+4>>2],Sg(s,4206,c)|0,n[_p>>2]=7,n[_p+4>>2]=0,n[c>>2]=n[_p>>2],n[c+4>>2]=n[_p+4>>2],Sg(s,4217,c)|0,n[kc>>2]=3,n[kc+4>>2]=0,n[c>>2]=n[kc>>2],n[c+4>>2]=n[kc+4>>2],JA(s,4235,c)|0,n[Up>>2]=1,n[Up+4>>2]=0,n[c>>2]=n[Up>>2],n[c+4>>2]=n[Up+4>>2],SF(s,4251,c)|0,n[kl>>2]=4,n[kl+4>>2]=0,n[c>>2]=n[kl>>2],n[c+4>>2]=n[kl+4>>2],JA(s,4263,c)|0,n[Xr>>2]=5,n[Xr+4>>2]=0,n[c>>2]=n[Xr>>2],n[c+4>>2]=n[Xr+4>>2],JA(s,4279,c)|0,n[Mp>>2]=6,n[Mp+4>>2]=0,n[c>>2]=n[Mp>>2],n[c+4>>2]=n[Mp+4>>2],JA(s,4293,c)|0,n[Op>>2]=7,n[Op+4>>2]=0,n[c>>2]=n[Op>>2],n[c+4>>2]=n[Op+4>>2],JA(s,4306,c)|0,n[Np>>2]=8,n[Np+4>>2]=0,n[c>>2]=n[Np>>2],n[c+4>>2]=n[Np+4>>2],JA(s,4323,c)|0,n[Tu>>2]=9,n[Tu+4>>2]=0,n[c>>2]=n[Tu>>2],n[c+4>>2]=n[Tu+4>>2],JA(s,4335,c)|0,n[Ru>>2]=2,n[Ru+4>>2]=0,n[c>>2]=n[Ru>>2],n[c+4>>2]=n[Ru+4>>2],SF(s,4353,c)|0,n[Lp>>2]=12,n[Lp+4>>2]=0,n[c>>2]=n[Lp>>2],n[c+4>>2]=n[Lp+4>>2],bg(s,4363,c)|0,n[xl>>2]=1,n[xl+4>>2]=0,n[c>>2]=n[xl>>2],n[c+4>>2]=n[xl+4>>2],XA(s,4376,c)|0,n[Tp>>2]=2,n[Tp+4>>2]=0,n[c>>2]=n[Tp>>2],n[c+4>>2]=n[Tp+4>>2],XA(s,4388,c)|0,n[Rp>>2]=13,n[Rp+4>>2]=0,n[c>>2]=n[Rp>>2],n[c+4>>2]=n[Rp+4>>2],bg(s,4402,c)|0,n[ya>>2]=14,n[ya+4>>2]=0,n[c>>2]=n[ya>>2],n[c+4>>2]=n[ya+4>>2],bg(s,4411,c)|0,n[yo>>2]=15,n[yo+4>>2]=0,n[c>>2]=n[yo>>2],n[c+4>>2]=n[yo+4>>2],bg(s,4421,c)|0,n[mo>>2]=16,n[mo+4>>2]=0,n[c>>2]=n[mo>>2],n[c+4>>2]=n[mo+4>>2],bg(s,4433,c)|0,n[go>>2]=17,n[go+4>>2]=0,n[c>>2]=n[go>>2],n[c+4>>2]=n[go+4>>2],bg(s,4446,c)|0,n[xn>>2]=18,n[xn+4>>2]=0,n[c>>2]=n[xn>>2],n[c+4>>2]=n[xn+4>>2],bg(s,4458,c)|0,n[sr>>2]=3,n[sr+4>>2]=0,n[c>>2]=n[sr>>2],n[c+4>>2]=n[sr+4>>2],XA(s,4471,c)|0,n[Lr>>2]=1,n[Lr+4>>2]=0,n[c>>2]=n[Lr>>2],n[c+4>>2]=n[Lr+4>>2],iD(s,4486,c)|0,n[Pr>>2]=10,n[Pr+4>>2]=0,n[c>>2]=n[Pr>>2],n[c+4>>2]=n[Pr+4>>2],JA(s,4496,c)|0,n[Xt>>2]=11,n[Xt+4>>2]=0,n[c>>2]=n[Xt>>2],n[c+4>>2]=n[Xt+4>>2],JA(s,4508,c)|0,n[ar>>2]=3,n[ar+4>>2]=0,n[c>>2]=n[ar>>2],n[c+4>>2]=n[ar+4>>2],SF(s,4519,c)|0,n[Mr>>2]=4,n[Mr+4>>2]=0,n[c>>2]=n[Mr>>2],n[c+4>>2]=n[Mr+4>>2],Yve(s,4530,c)|0,n[Nt>>2]=19,n[Nt+4>>2]=0,n[c>>2]=n[Nt>>2],n[c+4>>2]=n[Nt+4>>2],Wve(s,4542,c)|0,n[Ge>>2]=12,n[Ge+4>>2]=0,n[c>>2]=n[Ge>>2],n[c+4>>2]=n[Ge+4>>2],Kve(s,4554,c)|0,n[Ue>>2]=13,n[Ue+4>>2]=0,n[c>>2]=n[Ue>>2],n[c+4>>2]=n[Ue+4>>2],zve(s,4568,c)|0,n[lt>>2]=2,n[lt+4>>2]=0,n[c>>2]=n[lt>>2],n[c+4>>2]=n[lt+4>>2],Vve(s,4578,c)|0,n[Xe>>2]=20,n[Xe+4>>2]=0,n[c>>2]=n[Xe>>2],n[c+4>>2]=n[Xe+4>>2],Jve(s,4587,c)|0,n[et>>2]=22,n[et+4>>2]=0,n[c>>2]=n[et>>2],n[c+4>>2]=n[et+4>>2],Tw(s,4602,c)|0,n[Qe>>2]=23,n[Qe+4>>2]=0,n[c>>2]=n[Qe>>2],n[c+4>>2]=n[Qe+4>>2],Tw(s,4619,c)|0,n[Me>>2]=14,n[Me+4>>2]=0,n[c>>2]=n[Me>>2],n[c+4>>2]=n[Me+4>>2],Xve(s,4629,c)|0,n[je>>2]=1,n[je+4>>2]=0,n[c>>2]=n[je>>2],n[c+4>>2]=n[je+4>>2],Zve(s,4637,c)|0,n[se>>2]=4,n[se+4>>2]=0,n[c>>2]=n[se>>2],n[c+4>>2]=n[se+4>>2],XA(s,4653,c)|0,n[G>>2]=5,n[G+4>>2]=0,n[c>>2]=n[G>>2],n[c+4>>2]=n[G+4>>2],XA(s,4669,c)|0,n[O>>2]=6,n[O+4>>2]=0,n[c>>2]=n[O>>2],n[c+4>>2]=n[O+4>>2],XA(s,4686,c)|0,n[M>>2]=7,n[M+4>>2]=0,n[c>>2]=n[M>>2],n[c+4>>2]=n[M+4>>2],XA(s,4701,c)|0,n[Q>>2]=8,n[Q+4>>2]=0,n[c>>2]=n[Q>>2],n[c+4>>2]=n[Q+4>>2],XA(s,4719,c)|0,n[k>>2]=9,n[k+4>>2]=0,n[c>>2]=n[k>>2],n[c+4>>2]=n[k+4>>2],XA(s,4736,c)|0,n[B>>2]=21,n[B+4>>2]=0,n[c>>2]=n[B>>2],n[c+4>>2]=n[B+4>>2],$ve(s,4754,c)|0,n[m>>2]=2,n[m+4>>2]=0,n[c>>2]=n[m>>2],n[c+4>>2]=n[m+4>>2],iD(s,4772,c)|0,n[d>>2]=3,n[d+4>>2]=0,n[c>>2]=n[d>>2],n[c+4>>2]=n[d+4>>2],iD(s,4790,c)|0,n[f>>2]=4,n[f+4>>2]=0,n[c>>2]=n[f>>2],n[c+4>>2]=n[f+4>>2],iD(s,4808,c)|0,C=l}function _ve(s,l){s=s|0,l=l|0;var c=0;c=sFe()|0,n[s>>2]=c,oFe(c,l),kp(n[s>>2]|0)}function Hve(s,l,c){return s=s|0,l=l|0,c=c|0,YQe(s,pn(l)|0,c,0),s|0}function qve(s,l,c){return s=s|0,l=l|0,c=c|0,xQe(s,pn(l)|0,c,0),s|0}function Gve(s,l,c){return s=s|0,l=l|0,c=c|0,gQe(s,pn(l)|0,c,0),s|0}function Tw(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],$ke(s,l,d),C=f,s|0}function jve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Tke(s,l,d),C=f,s|0}function ku(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],yke(s,l,d),C=f,s|0}function Sg(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],rke(s,l,d),C=f,s|0}function Is(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],_xe(s,l,d),C=f,s|0}function JA(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],vxe(s,l,d),C=f,s|0}function SF(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],lxe(s,l,d),C=f,s|0}function bg(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Tbe(s,l,d),C=f,s|0}function XA(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],ybe(s,l,d),C=f,s|0}function iD(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],rbe(s,l,d),C=f,s|0}function Yve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],_Se(s,l,d),C=f,s|0}function Wve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],vSe(s,l,d),C=f,s|0}function Kve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],cSe(s,l,d),C=f,s|0}function zve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],zPe(s,l,d),C=f,s|0}function Vve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],QPe(s,l,d),C=f,s|0}function Jve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],hPe(s,l,d),C=f,s|0}function Xve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],ZDe(s,l,d),C=f,s|0}function Zve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],TDe(s,l,d),C=f,s|0}function $ve(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],eDe(s,l,d),C=f,s|0}function eDe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],tDe(s,c,d,1),C=f}function pn(s){return s=s|0,s|0}function tDe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=bF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=rDe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,nDe(m,f)|0,f),C=d}function bF(){var s=0,l=0;if(o[7616]|0||(t9(9136),rr(24,9136,U|0)|0,l=7616,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9136)|0)){s=9136,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));t9(9136)}return 9136}function rDe(s){return s=s|0,0}function nDe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=bF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],e9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(oDe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function hn(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0;var B=0,k=0,Q=0,M=0,O=0,G=0,se=0,je=0;B=C,C=C+32|0,se=B+24|0,G=B+20|0,Q=B+16|0,O=B+12|0,M=B+8|0,k=B+4|0,je=B,n[G>>2]=l,n[Q>>2]=c,n[O>>2]=f,n[M>>2]=d,n[k>>2]=m,m=s+28|0,n[je>>2]=n[m>>2],n[se>>2]=n[je>>2],iDe(s+24|0,se,G,O,M,Q,k)|0,n[m>>2]=n[n[m>>2]>>2],C=B}function iDe(s,l,c,f,d,m,B){return s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,B=B|0,s=sDe(l)|0,l=Kt(24)|0,$j(l+4|0,n[c>>2]|0,n[f>>2]|0,n[d>>2]|0,n[m>>2]|0,n[B>>2]|0),n[l>>2]=n[s>>2],n[s>>2]=l,l|0}function sDe(s){return s=s|0,n[s>>2]|0}function $j(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,n[s>>2]=l,n[s+4>>2]=c,n[s+8>>2]=f,n[s+12>>2]=d,n[s+16>>2]=m}function gr(s,l){return s=s|0,l=l|0,l|s|0}function e9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function oDe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=aDe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,lDe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],e9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,cDe(s,k),uDe(k),C=M;return}}function aDe(s){return s=s|0,357913941}function lDe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function cDe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function uDe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function t9(s){s=s|0,pDe(s)}function ADe(s){s=s|0,fDe(s+24|0)}function Tr(s){return s=s|0,n[s>>2]|0}function fDe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function pDe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,3,l,hDe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function Kr(){return 9228}function hDe(){return 1140}function gDe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0;return c=C,C=C+16|0,f=c+8|0,d=c,m=dDe(s)|0,s=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=s,n[f>>2]=n[d>>2],n[f+4>>2]=n[d+4>>2],l=mDe(l,f)|0,C=c,l|0}function zr(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,n[s>>2]=l,n[s+4>>2]=c,n[s+8>>2]=f,n[s+12>>2]=d,n[s+16>>2]=m}function dDe(s){return s=s|0,(n[(bF()|0)+24>>2]|0)+(s*12|0)|0}function mDe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0;return d=C,C=C+48|0,f=d,c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),rf[c&31](f,s),f=yDe(f)|0,C=d,f|0}function yDe(s){s=s|0;var l=0,c=0,f=0,d=0;return d=C,C=C+32|0,l=d+12|0,c=d,f=xF(r9()|0)|0,f?(kF(l,f),QF(c,l),EDe(s,c),s=FF(l)|0):s=CDe(s)|0,C=d,s|0}function r9(){var s=0;return o[7632]|0||(kDe(9184),rr(25,9184,U|0)|0,s=7632,n[s>>2]=1,n[s+4>>2]=0),9184}function xF(s){return s=s|0,n[s+36>>2]|0}function kF(s,l){s=s|0,l=l|0,n[s>>2]=l,n[s+4>>2]=s,n[s+8>>2]=0}function QF(s,l){s=s|0,l=l|0,n[s>>2]=n[l>>2],n[s+4>>2]=n[l+4>>2],n[s+8>>2]=0}function EDe(s,l){s=s|0,l=l|0,vDe(l,s,s+8|0,s+16|0,s+24|0,s+32|0,s+40|0)|0}function FF(s){return s=s|0,n[(n[s+4>>2]|0)+8>>2]|0}function CDe(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0,Q=0;Q=C,C=C+16|0,c=Q+4|0,f=Q,d=Ka(8)|0,m=d,B=Kt(48)|0,k=B,l=k+48|0;do n[k>>2]=n[s>>2],k=k+4|0,s=s+4|0;while((k|0)<(l|0));return l=m+4|0,n[l>>2]=B,k=Kt(8)|0,B=n[l>>2]|0,n[f>>2]=0,n[c>>2]=n[f>>2],n9(k,B,c),n[d>>2]=k,C=Q,m|0}function n9(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,c=Kt(16)|0,n[c+4>>2]=0,n[c+8>>2]=0,n[c>>2]=1092,n[c+12>>2]=l,n[s+4>>2]=c}function wDe(s){s=s|0,Jm(s),gt(s)}function IDe(s){s=s|0,s=n[s+12>>2]|0,s|0&&gt(s)}function BDe(s){s=s|0,gt(s)}function vDe(s,l,c,f,d,m,B){return s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,B=B|0,m=DDe(n[s>>2]|0,l,c,f,d,m,B)|0,B=s+4|0,n[(n[B>>2]|0)+8>>2]=m,n[(n[B>>2]|0)+8>>2]|0}function DDe(s,l,c,f,d,m,B){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,B=B|0;var k=0,Q=0;return k=C,C=C+16|0,Q=k,za(Q),s=da(s)|0,B=PDe(s,+E[l>>3],+E[c>>3],+E[f>>3],+E[d>>3],+E[m>>3],+E[B>>3])|0,Va(Q),C=k,B|0}function PDe(s,l,c,f,d,m,B){s=s|0,l=+l,c=+c,f=+f,d=+d,m=+m,B=+B;var k=0;return k=Sl(SDe()|0)|0,l=+VA(l),c=+VA(c),f=+VA(f),d=+VA(d),m=+VA(m),Ms(0,k|0,s|0,+l,+c,+f,+d,+m,+ +VA(B))|0}function SDe(){var s=0;return o[7624]|0||(bDe(9172),s=7624,n[s>>2]=1,n[s+4>>2]=0),9172}function bDe(s){s=s|0,bl(s,xDe()|0,6)}function xDe(){return 1112}function kDe(s){s=s|0,Dp(s)}function QDe(s){s=s|0,i9(s+24|0),s9(s+16|0)}function i9(s){s=s|0,RDe(s)}function s9(s){s=s|0,FDe(s)}function FDe(s){s=s|0;var l=0,c=0;if(l=n[s>>2]|0,l|0)do c=l,l=n[l>>2]|0,gt(c);while((l|0)!=0);n[s>>2]=0}function RDe(s){s=s|0;var l=0,c=0;if(l=n[s>>2]|0,l|0)do c=l,l=n[l>>2]|0,gt(c);while((l|0)!=0);n[s>>2]=0}function Dp(s){s=s|0;var l=0;n[s+16>>2]=0,n[s+20>>2]=0,l=s+24|0,n[l>>2]=0,n[s+28>>2]=l,n[s+36>>2]=0,o[s+40>>0]=0,o[s+41>>0]=0}function TDe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],LDe(s,c,d,0),C=f}function LDe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=RF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=NDe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,ODe(m,f)|0,f),C=d}function RF(){var s=0,l=0;if(o[7640]|0||(a9(9232),rr(26,9232,U|0)|0,l=7640,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9232)|0)){s=9232,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));a9(9232)}return 9232}function NDe(s){return s=s|0,0}function ODe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=RF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],o9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(MDe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function o9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function MDe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=UDe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,_De(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],o9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,HDe(s,k),qDe(k),C=M;return}}function UDe(s){return s=s|0,357913941}function _De(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function HDe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function qDe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function a9(s){s=s|0,YDe(s)}function GDe(s){s=s|0,jDe(s+24|0)}function jDe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function YDe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,1,l,WDe()|0,3),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function WDe(){return 1144}function KDe(s,l,c,f,d){s=s|0,l=l|0,c=+c,f=+f,d=d|0;var m=0,B=0,k=0,Q=0;m=C,C=C+16|0,B=m+8|0,k=m,Q=zDe(s)|0,s=n[Q+4>>2]|0,n[k>>2]=n[Q>>2],n[k+4>>2]=s,n[B>>2]=n[k>>2],n[B+4>>2]=n[k+4>>2],VDe(l,B,c,f,d),C=m}function zDe(s){return s=s|0,(n[(RF()|0)+24>>2]|0)+(s*12|0)|0}function VDe(s,l,c,f,d){s=s|0,l=l|0,c=+c,f=+f,d=d|0;var m=0,B=0,k=0,Q=0,M=0;M=C,C=C+16|0,B=M+2|0,k=M+1|0,Q=M,m=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(m=n[(n[s>>2]|0)+m>>2]|0),Qu(B,c),c=+Fu(B,c),Qu(k,f),f=+Fu(k,f),ZA(Q,d),Q=$A(Q,d)|0,I7[m&1](s,c,f,Q),C=M}function Qu(s,l){s=s|0,l=+l}function Fu(s,l){return s=s|0,l=+l,+ +XDe(l)}function ZA(s,l){s=s|0,l=l|0}function $A(s,l){return s=s|0,l=l|0,JDe(l)|0}function JDe(s){return s=s|0,s|0}function XDe(s){return s=+s,+s}function ZDe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],$De(s,c,d,1),C=f}function $De(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=TF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=ePe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,tPe(m,f)|0,f),C=d}function TF(){var s=0,l=0;if(o[7648]|0||(c9(9268),rr(27,9268,U|0)|0,l=7648,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9268)|0)){s=9268,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));c9(9268)}return 9268}function ePe(s){return s=s|0,0}function tPe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=TF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],l9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(rPe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function l9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function rPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=nPe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,iPe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],l9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,sPe(s,k),oPe(k),C=M;return}}function nPe(s){return s=s|0,357913941}function iPe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function sPe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function oPe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function c9(s){s=s|0,cPe(s)}function aPe(s){s=s|0,lPe(s+24|0)}function lPe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function cPe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,4,l,uPe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function uPe(){return 1160}function APe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0;return c=C,C=C+16|0,f=c+8|0,d=c,m=fPe(s)|0,s=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=s,n[f>>2]=n[d>>2],n[f+4>>2]=n[d+4>>2],l=pPe(l,f)|0,C=c,l|0}function fPe(s){return s=s|0,(n[(TF()|0)+24>>2]|0)+(s*12|0)|0}function pPe(s,l){s=s|0,l=l|0;var c=0;return c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),u9(Og[c&31](s)|0)|0}function u9(s){return s=s|0,s&1|0}function hPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],gPe(s,c,d,0),C=f}function gPe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=LF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=dPe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,mPe(m,f)|0,f),C=d}function LF(){var s=0,l=0;if(o[7656]|0||(f9(9304),rr(28,9304,U|0)|0,l=7656,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9304)|0)){s=9304,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));f9(9304)}return 9304}function dPe(s){return s=s|0,0}function mPe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=LF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],A9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(yPe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function A9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function yPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=EPe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,CPe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],A9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,wPe(s,k),IPe(k),C=M;return}}function EPe(s){return s=s|0,357913941}function CPe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function wPe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function IPe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function f9(s){s=s|0,DPe(s)}function BPe(s){s=s|0,vPe(s+24|0)}function vPe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function DPe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,5,l,PPe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function PPe(){return 1164}function SPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=C,C=C+16|0,d=f+8|0,m=f,B=bPe(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],xPe(l,d,c),C=f}function bPe(s){return s=s|0,(n[(LF()|0)+24>>2]|0)+(s*12|0)|0}function xPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;m=C,C=C+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),Pp(d,c),c=Sp(d,c)|0,rf[f&31](s,c),bp(d),C=m}function Pp(s,l){s=s|0,l=l|0,kPe(s,l)}function Sp(s,l){return s=s|0,l=l|0,s|0}function bp(s){s=s|0,GA(s)}function kPe(s,l){s=s|0,l=l|0,NF(s,l)}function NF(s,l){s=s|0,l=l|0,n[s>>2]=l}function QPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],FPe(s,c,d,0),C=f}function FPe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=OF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=RPe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,TPe(m,f)|0,f),C=d}function OF(){var s=0,l=0;if(o[7664]|0||(h9(9340),rr(29,9340,U|0)|0,l=7664,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9340)|0)){s=9340,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));h9(9340)}return 9340}function RPe(s){return s=s|0,0}function TPe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=OF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],p9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(LPe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function p9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function LPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=NPe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,OPe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],p9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,MPe(s,k),UPe(k),C=M;return}}function NPe(s){return s=s|0,357913941}function OPe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function MPe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function UPe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function h9(s){s=s|0,qPe(s)}function _Pe(s){s=s|0,HPe(s+24|0)}function HPe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function qPe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,4,l,GPe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function GPe(){return 1180}function jPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=YPe(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],c=WPe(l,d,c)|0,C=f,c|0}function YPe(s){return s=s|0,(n[(OF()|0)+24>>2]|0)+(s*12|0)|0}function WPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;return m=C,C=C+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),xg(d,c),d=kg(d,c)|0,d=sD(RR[f&15](s,d)|0)|0,C=m,d|0}function xg(s,l){s=s|0,l=l|0}function kg(s,l){return s=s|0,l=l|0,KPe(l)|0}function sD(s){return s=s|0,s|0}function KPe(s){return s=s|0,s|0}function zPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],VPe(s,c,d,0),C=f}function VPe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=MF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=JPe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,XPe(m,f)|0,f),C=d}function MF(){var s=0,l=0;if(o[7672]|0||(d9(9376),rr(30,9376,U|0)|0,l=7672,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9376)|0)){s=9376,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));d9(9376)}return 9376}function JPe(s){return s=s|0,0}function XPe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=MF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],g9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(ZPe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function g9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function ZPe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=$Pe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,eSe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],g9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,tSe(s,k),rSe(k),C=M;return}}function $Pe(s){return s=s|0,357913941}function eSe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function tSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function rSe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function d9(s){s=s|0,sSe(s)}function nSe(s){s=s|0,iSe(s+24|0)}function iSe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function sSe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,5,l,m9()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function m9(){return 1196}function oSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0;return c=C,C=C+16|0,f=c+8|0,d=c,m=aSe(s)|0,s=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=s,n[f>>2]=n[d>>2],n[f+4>>2]=n[d+4>>2],l=lSe(l,f)|0,C=c,l|0}function aSe(s){return s=s|0,(n[(MF()|0)+24>>2]|0)+(s*12|0)|0}function lSe(s,l){s=s|0,l=l|0;var c=0;return c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),sD(Og[c&31](s)|0)|0}function cSe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],uSe(s,c,d,1),C=f}function uSe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=UF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=ASe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,fSe(m,f)|0,f),C=d}function UF(){var s=0,l=0;if(o[7680]|0||(E9(9412),rr(31,9412,U|0)|0,l=7680,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9412)|0)){s=9412,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));E9(9412)}return 9412}function ASe(s){return s=s|0,0}function fSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=UF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],y9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(pSe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function y9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function pSe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=hSe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,gSe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],y9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,dSe(s,k),mSe(k),C=M;return}}function hSe(s){return s=s|0,357913941}function gSe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function dSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function mSe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function E9(s){s=s|0,CSe(s)}function ySe(s){s=s|0,ESe(s+24|0)}function ESe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function CSe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,6,l,C9()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function C9(){return 1200}function wSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0;return c=C,C=C+16|0,f=c+8|0,d=c,m=ISe(s)|0,s=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=s,n[f>>2]=n[d>>2],n[f+4>>2]=n[d+4>>2],l=BSe(l,f)|0,C=c,l|0}function ISe(s){return s=s|0,(n[(UF()|0)+24>>2]|0)+(s*12|0)|0}function BSe(s,l){s=s|0,l=l|0;var c=0;return c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),oD(Og[c&31](s)|0)|0}function oD(s){return s=s|0,s|0}function vSe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],DSe(s,c,d,0),C=f}function DSe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=_F()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=PSe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,SSe(m,f)|0,f),C=d}function _F(){var s=0,l=0;if(o[7688]|0||(I9(9448),rr(32,9448,U|0)|0,l=7688,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9448)|0)){s=9448,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));I9(9448)}return 9448}function PSe(s){return s=s|0,0}function SSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=_F()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],w9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(bSe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function w9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function bSe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=xSe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,kSe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],w9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,QSe(s,k),FSe(k),C=M;return}}function xSe(s){return s=s|0,357913941}function kSe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function QSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function FSe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function I9(s){s=s|0,LSe(s)}function RSe(s){s=s|0,TSe(s+24|0)}function TSe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function LSe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,6,l,B9()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function B9(){return 1204}function NSe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=C,C=C+16|0,d=f+8|0,m=f,B=OSe(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],MSe(l,d,c),C=f}function OSe(s){return s=s|0,(n[(_F()|0)+24>>2]|0)+(s*12|0)|0}function MSe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;m=C,C=C+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),HF(d,c),d=qF(d,c)|0,rf[f&31](s,d),C=m}function HF(s,l){s=s|0,l=l|0}function qF(s,l){return s=s|0,l=l|0,USe(l)|0}function USe(s){return s=s|0,s|0}function _Se(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],HSe(s,c,d,0),C=f}function HSe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=GF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=qSe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,GSe(m,f)|0,f),C=d}function GF(){var s=0,l=0;if(o[7696]|0||(D9(9484),rr(33,9484,U|0)|0,l=7696,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9484)|0)){s=9484,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));D9(9484)}return 9484}function qSe(s){return s=s|0,0}function GSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=GF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],v9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(jSe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function v9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function jSe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=YSe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,WSe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],v9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,KSe(s,k),zSe(k),C=M;return}}function YSe(s){return s=s|0,357913941}function WSe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function KSe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function zSe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function D9(s){s=s|0,XSe(s)}function VSe(s){s=s|0,JSe(s+24|0)}function JSe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function XSe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,1,l,ZSe()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function ZSe(){return 1212}function $Se(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;d=C,C=C+16|0,m=d+8|0,B=d,k=ebe(s)|0,s=n[k+4>>2]|0,n[B>>2]=n[k>>2],n[B+4>>2]=s,n[m>>2]=n[B>>2],n[m+4>>2]=n[B+4>>2],tbe(l,m,c,f),C=d}function ebe(s){return s=s|0,(n[(GF()|0)+24>>2]|0)+(s*12|0)|0}function tbe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;k=C,C=C+16|0,m=k+1|0,B=k,d=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(d=n[(n[s>>2]|0)+d>>2]|0),HF(m,c),m=qF(m,c)|0,xg(B,f),B=kg(B,f)|0,Hw[d&15](s,m,B),C=k}function rbe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],nbe(s,c,d,1),C=f}function nbe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=jF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=ibe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,sbe(m,f)|0,f),C=d}function jF(){var s=0,l=0;if(o[7704]|0||(S9(9520),rr(34,9520,U|0)|0,l=7704,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9520)|0)){s=9520,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));S9(9520)}return 9520}function ibe(s){return s=s|0,0}function sbe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=jF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],P9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(obe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function P9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function obe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=abe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,lbe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],P9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,cbe(s,k),ube(k),C=M;return}}function abe(s){return s=s|0,357913941}function lbe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function cbe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function ube(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function S9(s){s=s|0,pbe(s)}function Abe(s){s=s|0,fbe(s+24|0)}function fbe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function pbe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,1,l,hbe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function hbe(){return 1224}function gbe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;return d=C,C=C+16|0,m=d+8|0,B=d,k=dbe(s)|0,s=n[k+4>>2]|0,n[B>>2]=n[k>>2],n[B+4>>2]=s,n[m>>2]=n[B>>2],n[m+4>>2]=n[B+4>>2],f=+mbe(l,m,c),C=d,+f}function dbe(s){return s=s|0,(n[(jF()|0)+24>>2]|0)+(s*12|0)|0}function mbe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return m=C,C=C+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),ZA(d,c),d=$A(d,c)|0,B=+PF(+v7[f&7](s,d)),C=m,+B}function ybe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Ebe(s,c,d,1),C=f}function Ebe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=YF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=Cbe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,wbe(m,f)|0,f),C=d}function YF(){var s=0,l=0;if(o[7712]|0||(x9(9556),rr(35,9556,U|0)|0,l=7712,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9556)|0)){s=9556,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));x9(9556)}return 9556}function Cbe(s){return s=s|0,0}function wbe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=YF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],b9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(Ibe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function b9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function Ibe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=Bbe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,vbe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],b9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,Dbe(s,k),Pbe(k),C=M;return}}function Bbe(s){return s=s|0,357913941}function vbe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function Dbe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function Pbe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function x9(s){s=s|0,xbe(s)}function Sbe(s){s=s|0,bbe(s+24|0)}function bbe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function xbe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,5,l,kbe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function kbe(){return 1232}function Qbe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=Fbe(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],c=+Rbe(l,d),C=f,+c}function Fbe(s){return s=s|0,(n[(YF()|0)+24>>2]|0)+(s*12|0)|0}function Rbe(s,l){s=s|0,l=l|0;var c=0;return c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),+ +PF(+B7[c&15](s))}function Tbe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Lbe(s,c,d,1),C=f}function Lbe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=WF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=Nbe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,Obe(m,f)|0,f),C=d}function WF(){var s=0,l=0;if(o[7720]|0||(Q9(9592),rr(36,9592,U|0)|0,l=7720,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9592)|0)){s=9592,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));Q9(9592)}return 9592}function Nbe(s){return s=s|0,0}function Obe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=WF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],k9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(Mbe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function k9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function Mbe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=Ube(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,_be(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],k9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,Hbe(s,k),qbe(k),C=M;return}}function Ube(s){return s=s|0,357913941}function _be(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function Hbe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function qbe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function Q9(s){s=s|0,Ybe(s)}function Gbe(s){s=s|0,jbe(s+24|0)}function jbe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function Ybe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,7,l,Wbe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function Wbe(){return 1276}function Kbe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0;return c=C,C=C+16|0,f=c+8|0,d=c,m=zbe(s)|0,s=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=s,n[f>>2]=n[d>>2],n[f+4>>2]=n[d+4>>2],l=Vbe(l,f)|0,C=c,l|0}function zbe(s){return s=s|0,(n[(WF()|0)+24>>2]|0)+(s*12|0)|0}function Vbe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0;return d=C,C=C+16|0,f=d,c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),rf[c&31](f,s),f=F9(f)|0,C=d,f|0}function F9(s){s=s|0;var l=0,c=0,f=0,d=0;return d=C,C=C+32|0,l=d+12|0,c=d,f=xF(R9()|0)|0,f?(kF(l,f),QF(c,l),Jbe(s,c),s=FF(l)|0):s=Xbe(s)|0,C=d,s|0}function R9(){var s=0;return o[7736]|0||(axe(9640),rr(25,9640,U|0)|0,s=7736,n[s>>2]=1,n[s+4>>2]=0),9640}function Jbe(s,l){s=s|0,l=l|0,txe(l,s,s+8|0)|0}function Xbe(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0;return c=C,C=C+16|0,d=c+4|0,B=c,f=Ka(8)|0,l=f,k=Kt(16)|0,n[k>>2]=n[s>>2],n[k+4>>2]=n[s+4>>2],n[k+8>>2]=n[s+8>>2],n[k+12>>2]=n[s+12>>2],m=l+4|0,n[m>>2]=k,s=Kt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],KF(s,m,d),n[f>>2]=s,C=c,l|0}function KF(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,c=Kt(16)|0,n[c+4>>2]=0,n[c+8>>2]=0,n[c>>2]=1244,n[c+12>>2]=l,n[s+4>>2]=c}function Zbe(s){s=s|0,Jm(s),gt(s)}function $be(s){s=s|0,s=n[s+12>>2]|0,s|0&&gt(s)}function exe(s){s=s|0,gt(s)}function txe(s,l,c){return s=s|0,l=l|0,c=c|0,l=rxe(n[s>>2]|0,l,c)|0,c=s+4|0,n[(n[c>>2]|0)+8>>2]=l,n[(n[c>>2]|0)+8>>2]|0}function rxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;return f=C,C=C+16|0,d=f,za(d),s=da(s)|0,c=nxe(s,n[l>>2]|0,+E[c>>3])|0,Va(d),C=f,c|0}function nxe(s,l,c){s=s|0,l=l|0,c=+c;var f=0;return f=Sl(ixe()|0)|0,l=DF(l)|0,yl(0,f|0,s|0,l|0,+ +VA(c))|0}function ixe(){var s=0;return o[7728]|0||(sxe(9628),s=7728,n[s>>2]=1,n[s+4>>2]=0),9628}function sxe(s){s=s|0,bl(s,oxe()|0,2)}function oxe(){return 1264}function axe(s){s=s|0,Dp(s)}function lxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],cxe(s,c,d,1),C=f}function cxe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=zF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=uxe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,Axe(m,f)|0,f),C=d}function zF(){var s=0,l=0;if(o[7744]|0||(L9(9684),rr(37,9684,U|0)|0,l=7744,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9684)|0)){s=9684,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));L9(9684)}return 9684}function uxe(s){return s=s|0,0}function Axe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=zF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],T9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(fxe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function T9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function fxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=pxe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,hxe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],T9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,gxe(s,k),dxe(k),C=M;return}}function pxe(s){return s=s|0,357913941}function hxe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function gxe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function dxe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function L9(s){s=s|0,Exe(s)}function mxe(s){s=s|0,yxe(s+24|0)}function yxe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function Exe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,5,l,Cxe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function Cxe(){return 1280}function wxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=Ixe(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],c=Bxe(l,d,c)|0,C=f,c|0}function Ixe(s){return s=s|0,(n[(zF()|0)+24>>2]|0)+(s*12|0)|0}function Bxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return B=C,C=C+32|0,d=B,m=B+16|0,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),ZA(m,c),m=$A(m,c)|0,Hw[f&15](d,s,m),m=F9(d)|0,C=B,m|0}function vxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Dxe(s,c,d,1),C=f}function Dxe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=VF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=Pxe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,Sxe(m,f)|0,f),C=d}function VF(){var s=0,l=0;if(o[7752]|0||(O9(9720),rr(38,9720,U|0)|0,l=7752,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9720)|0)){s=9720,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));O9(9720)}return 9720}function Pxe(s){return s=s|0,0}function Sxe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=VF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],N9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(bxe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function N9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function bxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=xxe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,kxe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],N9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,Qxe(s,k),Fxe(k),C=M;return}}function xxe(s){return s=s|0,357913941}function kxe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function Qxe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function Fxe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function O9(s){s=s|0,Lxe(s)}function Rxe(s){s=s|0,Txe(s+24|0)}function Txe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function Lxe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,8,l,Nxe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function Nxe(){return 1288}function Oxe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0;return c=C,C=C+16|0,f=c+8|0,d=c,m=Mxe(s)|0,s=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=s,n[f>>2]=n[d>>2],n[f+4>>2]=n[d+4>>2],l=Uxe(l,f)|0,C=c,l|0}function Mxe(s){return s=s|0,(n[(VF()|0)+24>>2]|0)+(s*12|0)|0}function Uxe(s,l){s=s|0,l=l|0;var c=0;return c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),Zj(Og[c&31](s)|0)|0}function _xe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Hxe(s,c,d,0),C=f}function Hxe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=JF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=qxe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,Gxe(m,f)|0,f),C=d}function JF(){var s=0,l=0;if(o[7760]|0||(U9(9756),rr(39,9756,U|0)|0,l=7760,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9756)|0)){s=9756,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));U9(9756)}return 9756}function qxe(s){return s=s|0,0}function Gxe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=JF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],M9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(jxe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function M9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function jxe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=Yxe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,Wxe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],M9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,Kxe(s,k),zxe(k),C=M;return}}function Yxe(s){return s=s|0,357913941}function Wxe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function Kxe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function zxe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function U9(s){s=s|0,Xxe(s)}function Vxe(s){s=s|0,Jxe(s+24|0)}function Jxe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function Xxe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,8,l,Zxe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function Zxe(){return 1292}function $xe(s,l,c){s=s|0,l=l|0,c=+c;var f=0,d=0,m=0,B=0;f=C,C=C+16|0,d=f+8|0,m=f,B=eke(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],tke(l,d,c),C=f}function eke(s){return s=s|0,(n[(JF()|0)+24>>2]|0)+(s*12|0)|0}function tke(s,l,c){s=s|0,l=l|0,c=+c;var f=0,d=0,m=0;m=C,C=C+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),Qu(d,c),c=+Fu(d,c),C7[f&31](s,c),C=m}function rke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],nke(s,c,d,0),C=f}function nke(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=XF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=ike(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,ske(m,f)|0,f),C=d}function XF(){var s=0,l=0;if(o[7768]|0||(H9(9792),rr(40,9792,U|0)|0,l=7768,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9792)|0)){s=9792,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));H9(9792)}return 9792}function ike(s){return s=s|0,0}function ske(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=XF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],_9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(oke(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function _9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function oke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=ake(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,lke(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],_9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,cke(s,k),uke(k),C=M;return}}function ake(s){return s=s|0,357913941}function lke(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function cke(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function uke(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function H9(s){s=s|0,pke(s)}function Ake(s){s=s|0,fke(s+24|0)}function fke(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function pke(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,1,l,hke()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function hke(){return 1300}function gke(s,l,c,f){s=s|0,l=l|0,c=c|0,f=+f;var d=0,m=0,B=0,k=0;d=C,C=C+16|0,m=d+8|0,B=d,k=dke(s)|0,s=n[k+4>>2]|0,n[B>>2]=n[k>>2],n[B+4>>2]=s,n[m>>2]=n[B>>2],n[m+4>>2]=n[B+4>>2],mke(l,m,c,f),C=d}function dke(s){return s=s|0,(n[(XF()|0)+24>>2]|0)+(s*12|0)|0}function mke(s,l,c,f){s=s|0,l=l|0,c=c|0,f=+f;var d=0,m=0,B=0,k=0;k=C,C=C+16|0,m=k+1|0,B=k,d=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(d=n[(n[s>>2]|0)+d>>2]|0),ZA(m,c),m=$A(m,c)|0,Qu(B,f),f=+Fu(B,f),b7[d&15](s,m,f),C=k}function yke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Eke(s,c,d,0),C=f}function Eke(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=ZF()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=Cke(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,wke(m,f)|0,f),C=d}function ZF(){var s=0,l=0;if(o[7776]|0||(G9(9828),rr(41,9828,U|0)|0,l=7776,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9828)|0)){s=9828,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));G9(9828)}return 9828}function Cke(s){return s=s|0,0}function wke(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=ZF()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],q9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(Ike(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function q9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function Ike(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=Bke(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,vke(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],q9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,Dke(s,k),Pke(k),C=M;return}}function Bke(s){return s=s|0,357913941}function vke(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function Dke(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function Pke(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function G9(s){s=s|0,xke(s)}function Ske(s){s=s|0,bke(s+24|0)}function bke(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function xke(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,7,l,kke()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function kke(){return 1312}function Qke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=C,C=C+16|0,d=f+8|0,m=f,B=Fke(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Rke(l,d,c),C=f}function Fke(s){return s=s|0,(n[(ZF()|0)+24>>2]|0)+(s*12|0)|0}function Rke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;m=C,C=C+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),ZA(d,c),d=$A(d,c)|0,rf[f&31](s,d),C=m}function Tke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Lke(s,c,d,0),C=f}function Lke(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=$F()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=Nke(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,Oke(m,f)|0,f),C=d}function $F(){var s=0,l=0;if(o[7784]|0||(Y9(9864),rr(42,9864,U|0)|0,l=7784,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9864)|0)){s=9864,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));Y9(9864)}return 9864}function Nke(s){return s=s|0,0}function Oke(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=$F()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],j9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(Mke(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function j9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function Mke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=Uke(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,_ke(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],j9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,Hke(s,k),qke(k),C=M;return}}function Uke(s){return s=s|0,357913941}function _ke(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function Hke(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function qke(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function Y9(s){s=s|0,Yke(s)}function Gke(s){s=s|0,jke(s+24|0)}function jke(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function Yke(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,8,l,Wke()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function Wke(){return 1320}function Kke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=C,C=C+16|0,d=f+8|0,m=f,B=zke(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],Vke(l,d,c),C=f}function zke(s){return s=s|0,(n[($F()|0)+24>>2]|0)+(s*12|0)|0}function Vke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;m=C,C=C+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),Jke(d,c),d=Xke(d,c)|0,rf[f&31](s,d),C=m}function Jke(s,l){s=s|0,l=l|0}function Xke(s,l){return s=s|0,l=l|0,Zke(l)|0}function Zke(s){return s=s|0,s|0}function $ke(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],eQe(s,c,d,0),C=f}function eQe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=eR()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=tQe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,rQe(m,f)|0,f),C=d}function eR(){var s=0,l=0;if(o[7792]|0||(K9(9900),rr(43,9900,U|0)|0,l=7792,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9900)|0)){s=9900,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));K9(9900)}return 9900}function tQe(s){return s=s|0,0}function rQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=eR()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],W9(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(nQe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function W9(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function nQe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=iQe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,sQe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],W9(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,oQe(s,k),aQe(k),C=M;return}}function iQe(s){return s=s|0,357913941}function sQe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function oQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function aQe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function K9(s){s=s|0,uQe(s)}function lQe(s){s=s|0,cQe(s+24|0)}function cQe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function uQe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,22,l,AQe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function AQe(){return 1344}function fQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0;c=C,C=C+16|0,f=c+8|0,d=c,m=pQe(s)|0,s=n[m+4>>2]|0,n[d>>2]=n[m>>2],n[d+4>>2]=s,n[f>>2]=n[d>>2],n[f+4>>2]=n[d+4>>2],hQe(l,f),C=c}function pQe(s){return s=s|0,(n[(eR()|0)+24>>2]|0)+(s*12|0)|0}function hQe(s,l){s=s|0,l=l|0;var c=0;c=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(c=n[(n[s>>2]|0)+c>>2]|0),tf[c&127](s)}function gQe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=tR()|0,s=dQe(c)|0,hn(m,l,d,s,mQe(c,f)|0,f)}function tR(){var s=0,l=0;if(o[7800]|0||(V9(9936),rr(44,9936,U|0)|0,l=7800,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9936)|0)){s=9936,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));V9(9936)}return 9936}function dQe(s){return s=s|0,s|0}function mQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=tR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(z9(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(yQe(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function z9(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function yQe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=EQe(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,CQe(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,z9(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,wQe(s,d),IQe(d),C=k;return}}function EQe(s){return s=s|0,536870911}function CQe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function wQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function IQe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function V9(s){s=s|0,DQe(s)}function BQe(s){s=s|0,vQe(s+24|0)}function vQe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function DQe(s){s=s|0;var l=0;l=Kr()|0,zr(s,1,23,l,B9()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function PQe(s,l){s=s|0,l=l|0,bQe(n[(SQe(s)|0)>>2]|0,l)}function SQe(s){return s=s|0,(n[(tR()|0)+24>>2]|0)+(s<<3)|0}function bQe(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c,HF(f,l),l=qF(f,l)|0,tf[s&127](l),C=c}function xQe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=rR()|0,s=kQe(c)|0,hn(m,l,d,s,QQe(c,f)|0,f)}function rR(){var s=0,l=0;if(o[7808]|0||(X9(9972),rr(45,9972,U|0)|0,l=7808,n[l>>2]=1,n[l+4>>2]=0),!(Tr(9972)|0)){s=9972,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));X9(9972)}return 9972}function kQe(s){return s=s|0,s|0}function QQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=rR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(J9(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(FQe(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function J9(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function FQe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=RQe(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,TQe(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,J9(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,LQe(s,d),NQe(d),C=k;return}}function RQe(s){return s=s|0,536870911}function TQe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function LQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function NQe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function X9(s){s=s|0,UQe(s)}function OQe(s){s=s|0,MQe(s+24|0)}function MQe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function UQe(s){s=s|0;var l=0;l=Kr()|0,zr(s,1,9,l,_Qe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function _Qe(){return 1348}function HQe(s,l){return s=s|0,l=l|0,GQe(n[(qQe(s)|0)>>2]|0,l)|0}function qQe(s){return s=s|0,(n[(rR()|0)+24>>2]|0)+(s<<3)|0}function GQe(s,l){s=s|0,l=l|0;var c=0,f=0;return c=C,C=C+16|0,f=c,Z9(f,l),l=$9(f,l)|0,l=sD(Og[s&31](l)|0)|0,C=c,l|0}function Z9(s,l){s=s|0,l=l|0}function $9(s,l){return s=s|0,l=l|0,jQe(l)|0}function jQe(s){return s=s|0,s|0}function YQe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=nR()|0,s=WQe(c)|0,hn(m,l,d,s,KQe(c,f)|0,f)}function nR(){var s=0,l=0;if(o[7816]|0||(t5(10008),rr(46,10008,U|0)|0,l=7816,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10008)|0)){s=10008,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));t5(10008)}return 10008}function WQe(s){return s=s|0,s|0}function KQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=nR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(e5(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(zQe(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function e5(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function zQe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=VQe(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,JQe(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,e5(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,XQe(s,d),ZQe(d),C=k;return}}function VQe(s){return s=s|0,536870911}function JQe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function XQe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function ZQe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function t5(s){s=s|0,tFe(s)}function $Qe(s){s=s|0,eFe(s+24|0)}function eFe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function tFe(s){s=s|0;var l=0;l=Kr()|0,zr(s,1,15,l,m9()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function rFe(s){return s=s|0,iFe(n[(nFe(s)|0)>>2]|0)|0}function nFe(s){return s=s|0,(n[(nR()|0)+24>>2]|0)+(s<<3)|0}function iFe(s){return s=s|0,sD(CD[s&7]()|0)|0}function sFe(){var s=0;return o[7832]|0||(pFe(10052),rr(25,10052,U|0)|0,s=7832,n[s>>2]=1,n[s+4>>2]=0),10052}function oFe(s,l){s=s|0,l=l|0,n[s>>2]=aFe()|0,n[s+4>>2]=lFe()|0,n[s+12>>2]=l,n[s+8>>2]=cFe()|0,n[s+32>>2]=2}function aFe(){return 11709}function lFe(){return 1188}function cFe(){return aD()|0}function uFe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(xp(f,896)|0)==512?c|0&&(AFe(c),gt(c)):l|0&&(Su(l),gt(l))}function xp(s,l){return s=s|0,l=l|0,l&s|0}function AFe(s){s=s|0,s=n[s+4>>2]|0,s|0&&Qp(s)}function aD(){var s=0;return o[7824]|0||(n[2511]=fFe()|0,n[2512]=0,s=7824,n[s>>2]=1,n[s+4>>2]=0),10044}function fFe(){return 0}function pFe(s){s=s|0,Dp(s)}function hFe(s){s=s|0;var l=0,c=0,f=0,d=0,m=0;l=C,C=C+32|0,c=l+24|0,m=l+16|0,d=l+8|0,f=l,gFe(s,4827),dFe(s,4834,3)|0,mFe(s,3682,47)|0,n[m>>2]=9,n[m+4>>2]=0,n[c>>2]=n[m>>2],n[c+4>>2]=n[m+4>>2],yFe(s,4841,c)|0,n[d>>2]=1,n[d+4>>2]=0,n[c>>2]=n[d>>2],n[c+4>>2]=n[d+4>>2],EFe(s,4871,c)|0,n[f>>2]=10,n[f+4>>2]=0,n[c>>2]=n[f>>2],n[c+4>>2]=n[f+4>>2],CFe(s,4891,c)|0,C=l}function gFe(s,l){s=s|0,l=l|0;var c=0;c=ZRe()|0,n[s>>2]=c,$Re(c,l),kp(n[s>>2]|0)}function dFe(s,l,c){return s=s|0,l=l|0,c=c|0,NRe(s,pn(l)|0,c,0),s|0}function mFe(s,l,c){return s=s|0,l=l|0,c=c|0,wRe(s,pn(l)|0,c,0),s|0}function yFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],rRe(s,l,d),C=f,s|0}function EFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],OFe(s,l,d),C=f,s|0}function CFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=n[c+4>>2]|0,n[m>>2]=n[c>>2],n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],wFe(s,l,d),C=f,s|0}function wFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],IFe(s,c,d,1),C=f}function IFe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=iR()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=BFe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,vFe(m,f)|0,f),C=d}function iR(){var s=0,l=0;if(o[7840]|0||(n5(10100),rr(48,10100,U|0)|0,l=7840,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10100)|0)){s=10100,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));n5(10100)}return 10100}function BFe(s){return s=s|0,0}function vFe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=iR()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],r5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(DFe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function r5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function DFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=PFe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,SFe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],r5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,bFe(s,k),xFe(k),C=M;return}}function PFe(s){return s=s|0,357913941}function SFe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function bFe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function xFe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function n5(s){s=s|0,FFe(s)}function kFe(s){s=s|0,QFe(s+24|0)}function QFe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function FFe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,6,l,RFe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function RFe(){return 1364}function TFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;return f=C,C=C+16|0,d=f+8|0,m=f,B=LFe(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],c=NFe(l,d,c)|0,C=f,c|0}function LFe(s){return s=s|0,(n[(iR()|0)+24>>2]|0)+(s*12|0)|0}function NFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;return m=C,C=C+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),ZA(d,c),d=$A(d,c)|0,d=u9(RR[f&15](s,d)|0)|0,C=m,d|0}function OFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],MFe(s,c,d,0),C=f}function MFe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=sR()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=UFe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,_Fe(m,f)|0,f),C=d}function sR(){var s=0,l=0;if(o[7848]|0||(s5(10136),rr(49,10136,U|0)|0,l=7848,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10136)|0)){s=10136,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));s5(10136)}return 10136}function UFe(s){return s=s|0,0}function _Fe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=sR()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],i5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(HFe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function i5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function HFe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=qFe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,GFe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],i5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,jFe(s,k),YFe(k),C=M;return}}function qFe(s){return s=s|0,357913941}function GFe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function jFe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function YFe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function s5(s){s=s|0,zFe(s)}function WFe(s){s=s|0,KFe(s+24|0)}function KFe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function zFe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,9,l,VFe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function VFe(){return 1372}function JFe(s,l,c){s=s|0,l=l|0,c=+c;var f=0,d=0,m=0,B=0;f=C,C=C+16|0,d=f+8|0,m=f,B=XFe(s)|0,s=n[B+4>>2]|0,n[m>>2]=n[B>>2],n[m+4>>2]=s,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],ZFe(l,d,c),C=f}function XFe(s){return s=s|0,(n[(sR()|0)+24>>2]|0)+(s*12|0)|0}function ZFe(s,l,c){s=s|0,l=l|0,c=+c;var f=0,d=0,m=0,B=Ze;m=C,C=C+16|0,d=m,f=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(f=n[(n[s>>2]|0)+f>>2]|0),$Fe(d,c),B=y(eRe(d,c)),E7[f&1](s,B),C=m}function $Fe(s,l){s=s|0,l=+l}function eRe(s,l){return s=s|0,l=+l,y(tRe(l))}function tRe(s){return s=+s,y(s)}function rRe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,d=f+8|0,m=f,k=n[c>>2]|0,B=n[c+4>>2]|0,c=pn(l)|0,n[m>>2]=k,n[m+4>>2]=B,n[d>>2]=n[m>>2],n[d+4>>2]=n[m+4>>2],nRe(s,c,d,0),C=f}function nRe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0,Q=0,M=0,O=0;d=C,C=C+32|0,m=d+16|0,O=d+8|0,k=d,M=n[c>>2]|0,Q=n[c+4>>2]|0,B=n[s>>2]|0,s=oR()|0,n[O>>2]=M,n[O+4>>2]=Q,n[m>>2]=n[O>>2],n[m+4>>2]=n[O+4>>2],c=iRe(m)|0,n[k>>2]=M,n[k+4>>2]=Q,n[m>>2]=n[k>>2],n[m+4>>2]=n[k+4>>2],hn(B,l,s,c,sRe(m,f)|0,f),C=d}function oR(){var s=0,l=0;if(o[7856]|0||(a5(10172),rr(50,10172,U|0)|0,l=7856,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10172)|0)){s=10172,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));a5(10172)}return 10172}function iRe(s){return s=s|0,0}function sRe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0;return O=C,C=C+32|0,d=O+24|0,B=O+16|0,k=O,Q=O+8|0,m=n[s>>2]|0,f=n[s+4>>2]|0,n[k>>2]=m,n[k+4>>2]=f,G=oR()|0,M=G+24|0,s=gr(l,4)|0,n[Q>>2]=s,l=G+28|0,c=n[l>>2]|0,c>>>0<(n[G+32>>2]|0)>>>0?(n[B>>2]=m,n[B+4>>2]=f,n[d>>2]=n[B>>2],n[d+4>>2]=n[B+4>>2],o5(c,d,s),s=(n[l>>2]|0)+12|0,n[l>>2]=s):(oRe(M,k,Q),s=n[l>>2]|0),C=O,((s-(n[M>>2]|0)|0)/12|0)+-1|0}function o5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=n[l+4>>2]|0,n[s>>2]=n[l>>2],n[s+4>>2]=f,n[s+8>>2]=c}function oRe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;if(M=C,C=C+48|0,f=M+32|0,B=M+24|0,k=M,Q=s+4|0,d=(((n[Q>>2]|0)-(n[s>>2]|0)|0)/12|0)+1|0,m=aRe(s)|0,m>>>0<d>>>0)Jr(s);else{O=n[s>>2]|0,se=((n[s+8>>2]|0)-O|0)/12|0,G=se<<1,lRe(k,se>>>0<m>>>1>>>0?G>>>0<d>>>0?d:G:m,((n[Q>>2]|0)-O|0)/12|0,s+8|0),Q=k+8|0,m=n[Q>>2]|0,d=n[l+4>>2]|0,c=n[c>>2]|0,n[B>>2]=n[l>>2],n[B+4>>2]=d,n[f>>2]=n[B>>2],n[f+4>>2]=n[B+4>>2],o5(m,f,c),n[Q>>2]=(n[Q>>2]|0)+12,cRe(s,k),uRe(k),C=M;return}}function aRe(s){return s=s|0,357913941}function lRe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>357913941)Rt();else{d=Kt(l*12|0)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c*12|0)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l*12|0)}function cRe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(((d|0)/-12|0)*12|0)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function uRe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~(((f+-12-l|0)>>>0)/12|0)*12|0)),s=n[s>>2]|0,s|0&&gt(s)}function a5(s){s=s|0,pRe(s)}function ARe(s){s=s|0,fRe(s+24|0)}function fRe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~(((l+-12-f|0)>>>0)/12|0)*12|0)),gt(c))}function pRe(s){s=s|0;var l=0;l=Kr()|0,zr(s,2,3,l,hRe()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function hRe(){return 1380}function gRe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;d=C,C=C+16|0,m=d+8|0,B=d,k=dRe(s)|0,s=n[k+4>>2]|0,n[B>>2]=n[k>>2],n[B+4>>2]=s,n[m>>2]=n[B>>2],n[m+4>>2]=n[B+4>>2],mRe(l,m,c,f),C=d}function dRe(s){return s=s|0,(n[(oR()|0)+24>>2]|0)+(s*12|0)|0}function mRe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;k=C,C=C+16|0,m=k+1|0,B=k,d=n[l>>2]|0,l=n[l+4>>2]|0,s=s+(l>>1)|0,l&1&&(d=n[(n[s>>2]|0)+d>>2]|0),ZA(m,c),m=$A(m,c)|0,yRe(B,f),B=ERe(B,f)|0,Hw[d&15](s,m,B),C=k}function yRe(s,l){s=s|0,l=l|0}function ERe(s,l){return s=s|0,l=l|0,CRe(l)|0}function CRe(s){return s=s|0,(s|0)!=0|0}function wRe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=aR()|0,s=IRe(c)|0,hn(m,l,d,s,BRe(c,f)|0,f)}function aR(){var s=0,l=0;if(o[7864]|0||(c5(10208),rr(51,10208,U|0)|0,l=7864,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10208)|0)){s=10208,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));c5(10208)}return 10208}function IRe(s){return s=s|0,s|0}function BRe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=aR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(l5(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(vRe(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function l5(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function vRe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=DRe(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,PRe(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,l5(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,SRe(s,d),bRe(d),C=k;return}}function DRe(s){return s=s|0,536870911}function PRe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function SRe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function bRe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function c5(s){s=s|0,QRe(s)}function xRe(s){s=s|0,kRe(s+24|0)}function kRe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function QRe(s){s=s|0;var l=0;l=Kr()|0,zr(s,1,24,l,FRe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function FRe(){return 1392}function RRe(s,l){s=s|0,l=l|0,LRe(n[(TRe(s)|0)>>2]|0,l)}function TRe(s){return s=s|0,(n[(aR()|0)+24>>2]|0)+(s<<3)|0}function LRe(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c,Z9(f,l),l=$9(f,l)|0,tf[s&127](l),C=c}function NRe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=lR()|0,s=ORe(c)|0,hn(m,l,d,s,MRe(c,f)|0,f)}function lR(){var s=0,l=0;if(o[7872]|0||(A5(10244),rr(52,10244,U|0)|0,l=7872,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10244)|0)){s=10244,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));A5(10244)}return 10244}function ORe(s){return s=s|0,s|0}function MRe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=lR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(u5(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(URe(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function u5(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function URe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=_Re(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,HRe(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,u5(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,qRe(s,d),GRe(d),C=k;return}}function _Re(s){return s=s|0,536870911}function HRe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function qRe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function GRe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function A5(s){s=s|0,WRe(s)}function jRe(s){s=s|0,YRe(s+24|0)}function YRe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function WRe(s){s=s|0;var l=0;l=Kr()|0,zr(s,1,16,l,KRe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function KRe(){return 1400}function zRe(s){return s=s|0,JRe(n[(VRe(s)|0)>>2]|0)|0}function VRe(s){return s=s|0,(n[(lR()|0)+24>>2]|0)+(s<<3)|0}function JRe(s){return s=s|0,XRe(CD[s&7]()|0)|0}function XRe(s){return s=s|0,s|0}function ZRe(){var s=0;return o[7880]|0||(sTe(10280),rr(25,10280,U|0)|0,s=7880,n[s>>2]=1,n[s+4>>2]=0),10280}function $Re(s,l){s=s|0,l=l|0,n[s>>2]=eTe()|0,n[s+4>>2]=tTe()|0,n[s+12>>2]=l,n[s+8>>2]=rTe()|0,n[s+32>>2]=4}function eTe(){return 11711}function tTe(){return 1356}function rTe(){return aD()|0}function nTe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(xp(f,896)|0)==512?c|0&&(iTe(c),gt(c)):l|0&&(Pg(l),gt(l))}function iTe(s){s=s|0,s=n[s+4>>2]|0,s|0&&Qp(s)}function sTe(s){s=s|0,Dp(s)}function oTe(s){s=s|0,aTe(s,4920),lTe(s)|0,cTe(s)|0}function aTe(s,l){s=s|0,l=l|0;var c=0;c=R9()|0,n[s>>2]=c,kTe(c,l),kp(n[s>>2]|0)}function lTe(s){s=s|0;var l=0;return l=n[s>>2]|0,Qg(l,CTe()|0),s|0}function cTe(s){s=s|0;var l=0;return l=n[s>>2]|0,Qg(l,uTe()|0),s|0}function uTe(){var s=0;return o[7888]|0||(f5(10328),rr(53,10328,U|0)|0,s=7888,n[s>>2]=1,n[s+4>>2]=0),Tr(10328)|0||f5(10328),10328}function Qg(s,l){s=s|0,l=l|0,hn(s,0,l,0,0,0)}function f5(s){s=s|0,pTe(s),Fg(s,10)}function ATe(s){s=s|0,fTe(s+24|0)}function fTe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function pTe(s){s=s|0;var l=0;l=Kr()|0,zr(s,5,1,l,mTe()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function hTe(s,l,c){s=s|0,l=l|0,c=+c,gTe(s,l,c)}function Fg(s,l){s=s|0,l=l|0,n[s+20>>2]=l}function gTe(s,l,c){s=s|0,l=l|0,c=+c;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+16|0,m=f+8|0,k=f+13|0,d=f,B=f+12|0,ZA(k,l),n[m>>2]=$A(k,l)|0,Qu(B,c),E[d>>3]=+Fu(B,c),dTe(s,m,d),C=f}function dTe(s,l,c){s=s|0,l=l|0,c=c|0,Y(s+8|0,n[l>>2]|0,+E[c>>3]),o[s+24>>0]=1}function mTe(){return 1404}function yTe(s,l){return s=s|0,l=+l,ETe(s,l)|0}function ETe(s,l){s=s|0,l=+l;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return f=C,C=C+16|0,m=f+4|0,B=f+8|0,k=f,d=Ka(8)|0,c=d,Q=Kt(16)|0,ZA(m,s),s=$A(m,s)|0,Qu(B,l),Y(Q,s,+Fu(B,l)),B=c+4|0,n[B>>2]=Q,s=Kt(8)|0,B=n[B>>2]|0,n[k>>2]=0,n[m>>2]=n[k>>2],KF(s,B,m),n[d>>2]=s,C=f,c|0}function CTe(){var s=0;return o[7896]|0||(p5(10364),rr(54,10364,U|0)|0,s=7896,n[s>>2]=1,n[s+4>>2]=0),Tr(10364)|0||p5(10364),10364}function p5(s){s=s|0,BTe(s),Fg(s,55)}function wTe(s){s=s|0,ITe(s+24|0)}function ITe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function BTe(s){s=s|0;var l=0;l=Kr()|0,zr(s,5,4,l,STe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function vTe(s){s=s|0,DTe(s)}function DTe(s){s=s|0,PTe(s)}function PTe(s){s=s|0,h5(s+8|0),o[s+24>>0]=1}function h5(s){s=s|0,n[s>>2]=0,E[s+8>>3]=0}function STe(){return 1424}function bTe(){return xTe()|0}function xTe(){var s=0,l=0,c=0,f=0,d=0,m=0,B=0;return l=C,C=C+16|0,d=l+4|0,B=l,c=Ka(8)|0,s=c,f=Kt(16)|0,h5(f),m=s+4|0,n[m>>2]=f,f=Kt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],KF(f,m,d),n[c>>2]=f,C=l,s|0}function kTe(s,l){s=s|0,l=l|0,n[s>>2]=QTe()|0,n[s+4>>2]=FTe()|0,n[s+12>>2]=l,n[s+8>>2]=RTe()|0,n[s+32>>2]=5}function QTe(){return 11710}function FTe(){return 1416}function RTe(){return lD()|0}function TTe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(xp(f,896)|0)==512?c|0&&(LTe(c),gt(c)):l|0&&gt(l)}function LTe(s){s=s|0,s=n[s+4>>2]|0,s|0&&Qp(s)}function lD(){var s=0;return o[7904]|0||(n[2600]=NTe()|0,n[2601]=0,s=7904,n[s>>2]=1,n[s+4>>2]=0),10400}function NTe(){return n[357]|0}function OTe(s){s=s|0,MTe(s,4926),UTe(s)|0}function MTe(s,l){s=s|0,l=l|0;var c=0;c=r9()|0,n[s>>2]=c,JTe(c,l),kp(n[s>>2]|0)}function UTe(s){s=s|0;var l=0;return l=n[s>>2]|0,Qg(l,_Te()|0),s|0}function _Te(){var s=0;return o[7912]|0||(g5(10412),rr(56,10412,U|0)|0,s=7912,n[s>>2]=1,n[s+4>>2]=0),Tr(10412)|0||g5(10412),10412}function g5(s){s=s|0,GTe(s),Fg(s,57)}function HTe(s){s=s|0,qTe(s+24|0)}function qTe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function GTe(s){s=s|0;var l=0;l=Kr()|0,zr(s,5,5,l,KTe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function jTe(s){s=s|0,YTe(s)}function YTe(s){s=s|0,WTe(s)}function WTe(s){s=s|0;var l=0,c=0;l=s+8|0,c=l+48|0;do n[l>>2]=0,l=l+4|0;while((l|0)<(c|0));o[s+56>>0]=1}function KTe(){return 1432}function zTe(){return VTe()|0}function VTe(){var s=0,l=0,c=0,f=0,d=0,m=0,B=0,k=0;B=C,C=C+16|0,s=B+4|0,l=B,c=Ka(8)|0,f=c,d=Kt(48)|0,m=d,k=m+48|0;do n[m>>2]=0,m=m+4|0;while((m|0)<(k|0));return m=f+4|0,n[m>>2]=d,k=Kt(8)|0,m=n[m>>2]|0,n[l>>2]=0,n[s>>2]=n[l>>2],n9(k,m,s),n[c>>2]=k,C=B,f|0}function JTe(s,l){s=s|0,l=l|0,n[s>>2]=XTe()|0,n[s+4>>2]=ZTe()|0,n[s+12>>2]=l,n[s+8>>2]=$Te()|0,n[s+32>>2]=6}function XTe(){return 11704}function ZTe(){return 1436}function $Te(){return lD()|0}function eLe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(xp(f,896)|0)==512?c|0&&(tLe(c),gt(c)):l|0&&gt(l)}function tLe(s){s=s|0,s=n[s+4>>2]|0,s|0&&Qp(s)}function rLe(s){s=s|0,nLe(s,4933),iLe(s)|0,sLe(s)|0}function nLe(s,l){s=s|0,l=l|0;var c=0;c=xLe()|0,n[s>>2]=c,kLe(c,l),kp(n[s>>2]|0)}function iLe(s){s=s|0;var l=0;return l=n[s>>2]|0,Qg(l,ELe()|0),s|0}function sLe(s){s=s|0;var l=0;return l=n[s>>2]|0,Qg(l,oLe()|0),s|0}function oLe(){var s=0;return o[7920]|0||(d5(10452),rr(58,10452,U|0)|0,s=7920,n[s>>2]=1,n[s+4>>2]=0),Tr(10452)|0||d5(10452),10452}function d5(s){s=s|0,cLe(s),Fg(s,1)}function aLe(s){s=s|0,lLe(s+24|0)}function lLe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function cLe(s){s=s|0;var l=0;l=Kr()|0,zr(s,5,1,l,pLe()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function uLe(s,l,c){s=s|0,l=+l,c=+c,ALe(s,l,c)}function ALe(s,l,c){s=s|0,l=+l,c=+c;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+32|0,m=f+8|0,k=f+17|0,d=f,B=f+16|0,Qu(k,l),E[m>>3]=+Fu(k,l),Qu(B,c),E[d>>3]=+Fu(B,c),fLe(s,m,d),C=f}function fLe(s,l,c){s=s|0,l=l|0,c=c|0,m5(s+8|0,+E[l>>3],+E[c>>3]),o[s+24>>0]=1}function m5(s,l,c){s=s|0,l=+l,c=+c,E[s>>3]=l,E[s+8>>3]=c}function pLe(){return 1472}function hLe(s,l){return s=+s,l=+l,gLe(s,l)|0}function gLe(s,l){s=+s,l=+l;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return f=C,C=C+16|0,B=f+4|0,k=f+8|0,Q=f,d=Ka(8)|0,c=d,m=Kt(16)|0,Qu(B,s),s=+Fu(B,s),Qu(k,l),m5(m,s,+Fu(k,l)),k=c+4|0,n[k>>2]=m,m=Kt(8)|0,k=n[k>>2]|0,n[Q>>2]=0,n[B>>2]=n[Q>>2],y5(m,k,B),n[d>>2]=m,C=f,c|0}function y5(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,c=Kt(16)|0,n[c+4>>2]=0,n[c+8>>2]=0,n[c>>2]=1452,n[c+12>>2]=l,n[s+4>>2]=c}function dLe(s){s=s|0,Jm(s),gt(s)}function mLe(s){s=s|0,s=n[s+12>>2]|0,s|0&&gt(s)}function yLe(s){s=s|0,gt(s)}function ELe(){var s=0;return o[7928]|0||(E5(10488),rr(59,10488,U|0)|0,s=7928,n[s>>2]=1,n[s+4>>2]=0),Tr(10488)|0||E5(10488),10488}function E5(s){s=s|0,ILe(s),Fg(s,60)}function CLe(s){s=s|0,wLe(s+24|0)}function wLe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function ILe(s){s=s|0;var l=0;l=Kr()|0,zr(s,5,6,l,PLe()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function BLe(s){s=s|0,vLe(s)}function vLe(s){s=s|0,DLe(s)}function DLe(s){s=s|0,C5(s+8|0),o[s+24>>0]=1}function C5(s){s=s|0,n[s>>2]=0,n[s+4>>2]=0,n[s+8>>2]=0,n[s+12>>2]=0}function PLe(){return 1492}function SLe(){return bLe()|0}function bLe(){var s=0,l=0,c=0,f=0,d=0,m=0,B=0;return l=C,C=C+16|0,d=l+4|0,B=l,c=Ka(8)|0,s=c,f=Kt(16)|0,C5(f),m=s+4|0,n[m>>2]=f,f=Kt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],y5(f,m,d),n[c>>2]=f,C=l,s|0}function xLe(){var s=0;return o[7936]|0||(NLe(10524),rr(25,10524,U|0)|0,s=7936,n[s>>2]=1,n[s+4>>2]=0),10524}function kLe(s,l){s=s|0,l=l|0,n[s>>2]=QLe()|0,n[s+4>>2]=FLe()|0,n[s+12>>2]=l,n[s+8>>2]=RLe()|0,n[s+32>>2]=7}function QLe(){return 11700}function FLe(){return 1484}function RLe(){return lD()|0}function TLe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(xp(f,896)|0)==512?c|0&&(LLe(c),gt(c)):l|0&&gt(l)}function LLe(s){s=s|0,s=n[s+4>>2]|0,s|0&&Qp(s)}function NLe(s){s=s|0,Dp(s)}function OLe(s,l,c){s=s|0,l=l|0,c=c|0,s=pn(l)|0,l=MLe(c)|0,c=ULe(c,0)|0,gNe(s,l,c,cR()|0,0)}function MLe(s){return s=s|0,s|0}function ULe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=cR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(I5(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(WLe(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function cR(){var s=0,l=0;if(o[7944]|0||(w5(10568),rr(61,10568,U|0)|0,l=7944,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10568)|0)){s=10568,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));w5(10568)}return 10568}function w5(s){s=s|0,qLe(s)}function _Le(s){s=s|0,HLe(s+24|0)}function HLe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function qLe(s){s=s|0;var l=0;l=Kr()|0,zr(s,1,17,l,C9()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function GLe(s){return s=s|0,YLe(n[(jLe(s)|0)>>2]|0)|0}function jLe(s){return s=s|0,(n[(cR()|0)+24>>2]|0)+(s<<3)|0}function YLe(s){return s=s|0,oD(CD[s&7]()|0)|0}function I5(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function WLe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=KLe(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,zLe(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,I5(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,VLe(s,d),JLe(d),C=k;return}}function KLe(s){return s=s|0,536870911}function zLe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function VLe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function JLe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function XLe(){ZLe()}function ZLe(){$Le(10604)}function $Le(s){s=s|0,eNe(s,4955)}function eNe(s,l){s=s|0,l=l|0;var c=0;c=tNe()|0,n[s>>2]=c,rNe(c,l),kp(n[s>>2]|0)}function tNe(){var s=0;return o[7952]|0||(ANe(10612),rr(25,10612,U|0)|0,s=7952,n[s>>2]=1,n[s+4>>2]=0),10612}function rNe(s,l){s=s|0,l=l|0,n[s>>2]=oNe()|0,n[s+4>>2]=aNe()|0,n[s+12>>2]=l,n[s+8>>2]=lNe()|0,n[s+32>>2]=8}function kp(s){s=s|0;var l=0,c=0;l=C,C=C+16|0,c=l,Ym()|0,n[c>>2]=s,nNe(10608,c),C=l}function Ym(){return o[11714]|0||(n[2652]=0,rr(62,10608,U|0)|0,o[11714]=1),10608}function nNe(s,l){s=s|0,l=l|0;var c=0;c=Kt(8)|0,n[c+4>>2]=n[l>>2],n[c>>2]=n[s>>2],n[s>>2]=c}function iNe(s){s=s|0,sNe(s)}function sNe(s){s=s|0;var l=0,c=0;if(l=n[s>>2]|0,l|0)do c=l,l=n[l>>2]|0,gt(c);while((l|0)!=0);n[s>>2]=0}function oNe(){return 11715}function aNe(){return 1496}function lNe(){return aD()|0}function cNe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(xp(f,896)|0)==512?c|0&&(uNe(c),gt(c)):l|0&&gt(l)}function uNe(s){s=s|0,s=n[s+4>>2]|0,s|0&&Qp(s)}function ANe(s){s=s|0,Dp(s)}function fNe(s,l){s=s|0,l=l|0;var c=0,f=0;Ym()|0,c=n[2652]|0;e:do if(c|0){for(;f=n[c+4>>2]|0,!(f|0&&(n7(uR(f)|0,s)|0)==0);)if(c=n[c>>2]|0,!c)break e;pNe(f,l)}while(0)}function uR(s){return s=s|0,n[s+12>>2]|0}function pNe(s,l){s=s|0,l=l|0;var c=0;s=s+36|0,c=n[s>>2]|0,c|0&&(GA(c),gt(c)),c=Kt(4)|0,Jj(c,l),n[s>>2]=c}function AR(){return o[11716]|0||(n[2664]=0,rr(63,10656,U|0)|0,o[11716]=1),10656}function B5(){var s=0;return o[11717]|0?s=n[2665]|0:(hNe(),n[2665]=1504,o[11717]=1,s=1504),s|0}function hNe(){o[11740]|0||(o[11718]=gr(gr(8,0)|0,0)|0,o[11719]=gr(gr(0,0)|0,0)|0,o[11720]=gr(gr(0,16)|0,0)|0,o[11721]=gr(gr(8,0)|0,0)|0,o[11722]=gr(gr(0,0)|0,0)|0,o[11723]=gr(gr(8,0)|0,0)|0,o[11724]=gr(gr(0,0)|0,0)|0,o[11725]=gr(gr(8,0)|0,0)|0,o[11726]=gr(gr(0,0)|0,0)|0,o[11727]=gr(gr(8,0)|0,0)|0,o[11728]=gr(gr(0,0)|0,0)|0,o[11729]=gr(gr(0,0)|0,32)|0,o[11730]=gr(gr(0,0)|0,32)|0,o[11740]=1)}function v5(){return 1572}function gNe(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0,M=0,O=0;m=C,C=C+32|0,O=m+16|0,M=m+12|0,Q=m+8|0,k=m+4|0,B=m,n[O>>2]=s,n[M>>2]=l,n[Q>>2]=c,n[k>>2]=f,n[B>>2]=d,AR()|0,dNe(10656,O,M,Q,k,B),C=m}function dNe(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0;var B=0;B=Kt(24)|0,$j(B+4|0,n[l>>2]|0,n[c>>2]|0,n[f>>2]|0,n[d>>2]|0,n[m>>2]|0),n[B>>2]=n[s>>2],n[s>>2]=B}function D5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0,je=0,Me=0,Qe=0,et=0,Xe=0,lt=0;if(lt=C,C=C+32|0,Me=lt+20|0,Qe=lt+8|0,et=lt+4|0,Xe=lt,l=n[l>>2]|0,l|0){je=Me+4|0,Q=Me+8|0,M=Qe+4|0,O=Qe+8|0,G=Qe+8|0,se=Me+8|0;do{if(B=l+4|0,k=fR(B)|0,k|0){if(d=Lw(k)|0,n[Me>>2]=0,n[je>>2]=0,n[Q>>2]=0,f=(Nw(k)|0)+1|0,mNe(Me,f),f|0)for(;f=f+-1|0,xc(Qe,n[d>>2]|0),m=n[je>>2]|0,m>>>0<(n[se>>2]|0)>>>0?(n[m>>2]=n[Qe>>2],n[je>>2]=(n[je>>2]|0)+4):pR(Me,Qe),f;)d=d+4|0;f=Ow(k)|0,n[Qe>>2]=0,n[M>>2]=0,n[O>>2]=0;e:do if(n[f>>2]|0)for(d=0,m=0;;){if((d|0)==(m|0)?yNe(Qe,f):(n[d>>2]=n[f>>2],n[M>>2]=(n[M>>2]|0)+4),f=f+4|0,!(n[f>>2]|0))break e;d=n[M>>2]|0,m=n[G>>2]|0}while(0);n[et>>2]=cD(B)|0,n[Xe>>2]=Tr(k)|0,ENe(c,s,et,Xe,Me,Qe),hR(Qe),ef(Me)}l=n[l>>2]|0}while((l|0)!=0)}C=lt}function fR(s){return s=s|0,n[s+12>>2]|0}function Lw(s){return s=s|0,n[s+12>>2]|0}function Nw(s){return s=s|0,n[s+16>>2]|0}function mNe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0;d=C,C=C+32|0,c=d,f=n[s>>2]|0,(n[s+8>>2]|0)-f>>2>>>0<l>>>0&&(R5(c,l,(n[s+4>>2]|0)-f>>2,s+8|0),T5(s,c),L5(c)),C=d}function pR(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0;if(B=C,C=C+32|0,c=B,f=s+4|0,d=((n[f>>2]|0)-(n[s>>2]|0)>>2)+1|0,m=F5(s)|0,m>>>0<d>>>0)Jr(s);else{k=n[s>>2]|0,M=(n[s+8>>2]|0)-k|0,Q=M>>1,R5(c,M>>2>>>0<m>>>1>>>0?Q>>>0<d>>>0?d:Q:m,(n[f>>2]|0)-k>>2,s+8|0),m=c+8|0,n[n[m>>2]>>2]=n[l>>2],n[m>>2]=(n[m>>2]|0)+4,T5(s,c),L5(c),C=B;return}}function Ow(s){return s=s|0,n[s+8>>2]|0}function yNe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0;if(B=C,C=C+32|0,c=B,f=s+4|0,d=((n[f>>2]|0)-(n[s>>2]|0)>>2)+1|0,m=Q5(s)|0,m>>>0<d>>>0)Jr(s);else{k=n[s>>2]|0,M=(n[s+8>>2]|0)-k|0,Q=M>>1,MNe(c,M>>2>>>0<m>>>1>>>0?Q>>>0<d>>>0?d:Q:m,(n[f>>2]|0)-k>>2,s+8|0),m=c+8|0,n[n[m>>2]>>2]=n[l>>2],n[m>>2]=(n[m>>2]|0)+4,UNe(s,c),_Ne(c),C=B;return}}function cD(s){return s=s|0,n[s>>2]|0}function ENe(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,CNe(s,l,c,f,d,m)}function hR(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-4-f|0)>>>2)<<2)),gt(c))}function ef(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-4-f|0)>>>2)<<2)),gt(c))}function CNe(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0;var B=0,k=0,Q=0,M=0,O=0,G=0;B=C,C=C+48|0,O=B+40|0,k=B+32|0,G=B+24|0,Q=B+12|0,M=B,za(k),s=da(s)|0,n[G>>2]=n[l>>2],c=n[c>>2]|0,f=n[f>>2]|0,gR(Q,d),wNe(M,m),n[O>>2]=n[G>>2],INe(s,O,c,f,Q,M),hR(M),ef(Q),Va(k),C=B}function gR(s,l){s=s|0,l=l|0;var c=0,f=0;n[s>>2]=0,n[s+4>>2]=0,n[s+8>>2]=0,c=l+4|0,f=(n[c>>2]|0)-(n[l>>2]|0)>>2,f|0&&(NNe(s,f),ONe(s,n[l>>2]|0,n[c>>2]|0,f))}function wNe(s,l){s=s|0,l=l|0;var c=0,f=0;n[s>>2]=0,n[s+4>>2]=0,n[s+8>>2]=0,c=l+4|0,f=(n[c>>2]|0)-(n[l>>2]|0)>>2,f|0&&(TNe(s,f),LNe(s,n[l>>2]|0,n[c>>2]|0,f))}function INe(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0;var B=0,k=0,Q=0,M=0,O=0,G=0;B=C,C=C+32|0,O=B+28|0,G=B+24|0,k=B+12|0,Q=B,M=Sl(BNe()|0)|0,n[G>>2]=n[l>>2],n[O>>2]=n[G>>2],l=Rg(O)|0,c=P5(c)|0,f=dR(f)|0,n[k>>2]=n[d>>2],O=d+4|0,n[k+4>>2]=n[O>>2],G=d+8|0,n[k+8>>2]=n[G>>2],n[G>>2]=0,n[O>>2]=0,n[d>>2]=0,d=mR(k)|0,n[Q>>2]=n[m>>2],O=m+4|0,n[Q+4>>2]=n[O>>2],G=m+8|0,n[Q+8>>2]=n[G>>2],n[G>>2]=0,n[O>>2]=0,n[m>>2]=0,ao(0,M|0,s|0,l|0,c|0,f|0,d|0,vNe(Q)|0)|0,hR(Q),ef(k),C=B}function BNe(){var s=0;return o[7968]|0||(FNe(10708),s=7968,n[s>>2]=1,n[s+4>>2]=0),10708}function Rg(s){return s=s|0,b5(s)|0}function P5(s){return s=s|0,S5(s)|0}function dR(s){return s=s|0,oD(s)|0}function mR(s){return s=s|0,PNe(s)|0}function vNe(s){return s=s|0,DNe(s)|0}function DNe(s){s=s|0;var l=0,c=0,f=0;if(f=(n[s+4>>2]|0)-(n[s>>2]|0)|0,c=f>>2,f=Ka(f+4|0)|0,n[f>>2]=c,c|0){l=0;do n[f+4+(l<<2)>>2]=S5(n[(n[s>>2]|0)+(l<<2)>>2]|0)|0,l=l+1|0;while((l|0)!=(c|0))}return f|0}function S5(s){return s=s|0,s|0}function PNe(s){s=s|0;var l=0,c=0,f=0;if(f=(n[s+4>>2]|0)-(n[s>>2]|0)|0,c=f>>2,f=Ka(f+4|0)|0,n[f>>2]=c,c|0){l=0;do n[f+4+(l<<2)>>2]=b5((n[s>>2]|0)+(l<<2)|0)|0,l=l+1|0;while((l|0)!=(c|0))}return f|0}function b5(s){s=s|0;var l=0,c=0,f=0,d=0;return d=C,C=C+32|0,l=d+12|0,c=d,f=xF(x5()|0)|0,f?(kF(l,f),QF(c,l),lUe(s,c),s=FF(l)|0):s=SNe(s)|0,C=d,s|0}function x5(){var s=0;return o[7960]|0||(QNe(10664),rr(25,10664,U|0)|0,s=7960,n[s>>2]=1,n[s+4>>2]=0),10664}function SNe(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0;return c=C,C=C+16|0,d=c+4|0,B=c,f=Ka(8)|0,l=f,k=Kt(4)|0,n[k>>2]=n[s>>2],m=l+4|0,n[m>>2]=k,s=Kt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],k5(s,m,d),n[f>>2]=s,C=c,l|0}function k5(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,c=Kt(16)|0,n[c+4>>2]=0,n[c+8>>2]=0,n[c>>2]=1656,n[c+12>>2]=l,n[s+4>>2]=c}function bNe(s){s=s|0,Jm(s),gt(s)}function xNe(s){s=s|0,s=n[s+12>>2]|0,s|0&&gt(s)}function kNe(s){s=s|0,gt(s)}function QNe(s){s=s|0,Dp(s)}function FNe(s){s=s|0,bl(s,RNe()|0,5)}function RNe(){return 1676}function TNe(s,l){s=s|0,l=l|0;var c=0;if((Q5(s)|0)>>>0<l>>>0&&Jr(s),l>>>0>1073741823)Rt();else{c=Kt(l<<2)|0,n[s+4>>2]=c,n[s>>2]=c,n[s+8>>2]=c+(l<<2);return}}function LNe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,f=s+4|0,s=c-l|0,(s|0)>0&&(Dr(n[f>>2]|0,l|0,s|0)|0,n[f>>2]=(n[f>>2]|0)+(s>>>2<<2))}function Q5(s){return s=s|0,1073741823}function NNe(s,l){s=s|0,l=l|0;var c=0;if((F5(s)|0)>>>0<l>>>0&&Jr(s),l>>>0>1073741823)Rt();else{c=Kt(l<<2)|0,n[s+4>>2]=c,n[s>>2]=c,n[s+8>>2]=c+(l<<2);return}}function ONe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,f=s+4|0,s=c-l|0,(s|0)>0&&(Dr(n[f>>2]|0,l|0,s|0)|0,n[f>>2]=(n[f>>2]|0)+(s>>>2<<2))}function F5(s){return s=s|0,1073741823}function MNe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>1073741823)Rt();else{d=Kt(l<<2)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<2)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<2)}function UNe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>2)<<2)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function _Ne(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-4-l|0)>>>2)<<2)),s=n[s>>2]|0,s|0&&gt(s)}function R5(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>1073741823)Rt();else{d=Kt(l<<2)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<2)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<2)}function T5(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>2)<<2)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function L5(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-4-l|0)>>>2)<<2)),s=n[s>>2]|0,s|0&&gt(s)}function HNe(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0,je=0,Me=0,Qe=0;if(Qe=C,C=C+32|0,O=Qe+20|0,G=Qe+12|0,M=Qe+16|0,se=Qe+4|0,je=Qe,Me=Qe+8|0,k=B5()|0,m=n[k>>2]|0,B=n[m>>2]|0,B|0)for(Q=n[k+8>>2]|0,k=n[k+4>>2]|0;xc(O,B),qNe(s,O,k,Q),m=m+4|0,B=n[m>>2]|0,B;)Q=Q+1|0,k=k+1|0;if(m=v5()|0,B=n[m>>2]|0,B|0)do xc(O,B),n[G>>2]=n[m+4>>2],GNe(l,O,G),m=m+8|0,B=n[m>>2]|0;while((B|0)!=0);if(m=n[(Ym()|0)>>2]|0,m|0)do l=n[m+4>>2]|0,xc(O,n[(Wm(l)|0)>>2]|0),n[G>>2]=uR(l)|0,jNe(c,O,G),m=n[m>>2]|0;while((m|0)!=0);if(xc(M,0),m=AR()|0,n[O>>2]=n[M>>2],D5(O,m,d),m=n[(Ym()|0)>>2]|0,m|0){s=O+4|0,l=O+8|0,c=O+8|0;do{if(Q=n[m+4>>2]|0,xc(G,n[(Wm(Q)|0)>>2]|0),YNe(se,N5(Q)|0),B=n[se>>2]|0,B|0){n[O>>2]=0,n[s>>2]=0,n[l>>2]=0;do xc(je,n[(Wm(n[B+4>>2]|0)|0)>>2]|0),k=n[s>>2]|0,k>>>0<(n[c>>2]|0)>>>0?(n[k>>2]=n[je>>2],n[s>>2]=(n[s>>2]|0)+4):pR(O,je),B=n[B>>2]|0;while((B|0)!=0);WNe(f,G,O),ef(O)}n[Me>>2]=n[G>>2],M=O5(Q)|0,n[O>>2]=n[Me>>2],D5(O,M,d),s9(se),m=n[m>>2]|0}while((m|0)!=0)}C=Qe}function qNe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,iOe(s,l,c,f)}function GNe(s,l,c){s=s|0,l=l|0,c=c|0,nOe(s,l,c)}function Wm(s){return s=s|0,s|0}function jNe(s,l,c){s=s|0,l=l|0,c=c|0,$Ne(s,l,c)}function N5(s){return s=s|0,s+16|0}function YNe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;if(m=C,C=C+16|0,d=m+8|0,c=m,n[s>>2]=0,f=n[l>>2]|0,n[d>>2]=f,n[c>>2]=s,c=ZNe(c)|0,f|0){if(f=Kt(12)|0,B=(M5(d)|0)+4|0,s=n[B+4>>2]|0,l=f+4|0,n[l>>2]=n[B>>2],n[l+4>>2]=s,l=n[n[d>>2]>>2]|0,n[d>>2]=l,!l)s=f;else for(l=f;s=Kt(12)|0,Q=(M5(d)|0)+4|0,k=n[Q+4>>2]|0,B=s+4|0,n[B>>2]=n[Q>>2],n[B+4>>2]=k,n[l>>2]=s,B=n[n[d>>2]>>2]|0,n[d>>2]=B,B;)l=s;n[s>>2]=n[c>>2],n[c>>2]=f}C=m}function WNe(s,l,c){s=s|0,l=l|0,c=c|0,KNe(s,l,c)}function O5(s){return s=s|0,s+24|0}function KNe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+32|0,B=f+24|0,d=f+16|0,k=f+12|0,m=f,za(d),s=da(s)|0,n[k>>2]=n[l>>2],gR(m,c),n[B>>2]=n[k>>2],zNe(s,B,m),ef(m),Va(d),C=f}function zNe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=C,C=C+32|0,B=f+16|0,k=f+12|0,d=f,m=Sl(VNe()|0)|0,n[k>>2]=n[l>>2],n[B>>2]=n[k>>2],l=Rg(B)|0,n[d>>2]=n[c>>2],B=c+4|0,n[d+4>>2]=n[B>>2],k=c+8|0,n[d+8>>2]=n[k>>2],n[k>>2]=0,n[B>>2]=0,n[c>>2]=0,oo(0,m|0,s|0,l|0,mR(d)|0)|0,ef(d),C=f}function VNe(){var s=0;return o[7976]|0||(JNe(10720),s=7976,n[s>>2]=1,n[s+4>>2]=0),10720}function JNe(s){s=s|0,bl(s,XNe()|0,2)}function XNe(){return 1732}function ZNe(s){return s=s|0,n[s>>2]|0}function M5(s){return s=s|0,n[s>>2]|0}function $Ne(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=C,C=C+32|0,m=f+16|0,d=f+8|0,B=f,za(d),s=da(s)|0,n[B>>2]=n[l>>2],c=n[c>>2]|0,n[m>>2]=n[B>>2],U5(s,m,c),Va(d),C=f}function U5(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=C,C=C+16|0,m=f+4|0,B=f,d=Sl(eOe()|0)|0,n[B>>2]=n[l>>2],n[m>>2]=n[B>>2],l=Rg(m)|0,oo(0,d|0,s|0,l|0,P5(c)|0)|0,C=f}function eOe(){var s=0;return o[7984]|0||(tOe(10732),s=7984,n[s>>2]=1,n[s+4>>2]=0),10732}function tOe(s){s=s|0,bl(s,rOe()|0,2)}function rOe(){return 1744}function nOe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;f=C,C=C+32|0,m=f+16|0,d=f+8|0,B=f,za(d),s=da(s)|0,n[B>>2]=n[l>>2],c=n[c>>2]|0,n[m>>2]=n[B>>2],U5(s,m,c),Va(d),C=f}function iOe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;d=C,C=C+32|0,B=d+16|0,m=d+8|0,k=d,za(m),s=da(s)|0,n[k>>2]=n[l>>2],c=o[c>>0]|0,f=o[f>>0]|0,n[B>>2]=n[k>>2],sOe(s,B,c,f),Va(m),C=d}function sOe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;d=C,C=C+16|0,B=d+4|0,k=d,m=Sl(oOe()|0)|0,n[k>>2]=n[l>>2],n[B>>2]=n[k>>2],l=Rg(B)|0,c=Km(c)|0,hc(0,m|0,s|0,l|0,c|0,Km(f)|0)|0,C=d}function oOe(){var s=0;return o[7992]|0||(lOe(10744),s=7992,n[s>>2]=1,n[s+4>>2]=0),10744}function Km(s){return s=s|0,aOe(s)|0}function aOe(s){return s=s|0,s&255|0}function lOe(s){s=s|0,bl(s,cOe()|0,3)}function cOe(){return 1756}function uOe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;switch(se=C,C=C+32|0,k=se+8|0,Q=se+4|0,M=se+20|0,O=se,NF(s,0),f=aUe(l)|0,n[k>>2]=0,G=k+4|0,n[G>>2]=0,n[k+8>>2]=0,f<<24>>24){case 0:{o[M>>0]=0,AOe(Q,c,M),uD(s,Q)|0,jA(Q);break}case 8:{G=BR(l)|0,o[M>>0]=8,xc(O,n[G+4>>2]|0),fOe(Q,c,M,O,G+8|0),uD(s,Q)|0,jA(Q);break}case 9:{if(m=BR(l)|0,l=n[m+4>>2]|0,l|0)for(B=k+8|0,d=m+12|0;l=l+-1|0,xc(Q,n[d>>2]|0),f=n[G>>2]|0,f>>>0<(n[B>>2]|0)>>>0?(n[f>>2]=n[Q>>2],n[G>>2]=(n[G>>2]|0)+4):pR(k,Q),l;)d=d+4|0;o[M>>0]=9,xc(O,n[m+8>>2]|0),pOe(Q,c,M,O,k),uD(s,Q)|0,jA(Q);break}default:G=BR(l)|0,o[M>>0]=f,xc(O,n[G+4>>2]|0),hOe(Q,c,M,O),uD(s,Q)|0,jA(Q)}ef(k),C=se}function AOe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;f=C,C=C+16|0,d=f,za(d),l=da(l)|0,SOe(s,l,o[c>>0]|0),Va(d),C=f}function uD(s,l){s=s|0,l=l|0;var c=0;return c=n[s>>2]|0,c|0&&SA(c|0),n[s>>2]=n[l>>2],n[l>>2]=0,s|0}function fOe(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0;m=C,C=C+32|0,k=m+16|0,B=m+8|0,Q=m,za(B),l=da(l)|0,c=o[c>>0]|0,n[Q>>2]=n[f>>2],d=n[d>>2]|0,n[k>>2]=n[Q>>2],BOe(s,l,c,k,d),Va(B),C=m}function pOe(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0,M=0;m=C,C=C+32|0,Q=m+24|0,B=m+16|0,M=m+12|0,k=m,za(B),l=da(l)|0,c=o[c>>0]|0,n[M>>2]=n[f>>2],gR(k,d),n[Q>>2]=n[M>>2],EOe(s,l,c,Q,k),ef(k),Va(B),C=m}function hOe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;d=C,C=C+32|0,B=d+16|0,m=d+8|0,k=d,za(m),l=da(l)|0,c=o[c>>0]|0,n[k>>2]=n[f>>2],n[B>>2]=n[k>>2],gOe(s,l,c,B),Va(m),C=d}function gOe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0,B=0,k=0;d=C,C=C+16|0,m=d+4|0,k=d,B=Sl(dOe()|0)|0,c=Km(c)|0,n[k>>2]=n[f>>2],n[m>>2]=n[k>>2],AD(s,oo(0,B|0,l|0,c|0,Rg(m)|0)|0),C=d}function dOe(){var s=0;return o[8e3]|0||(mOe(10756),s=8e3,n[s>>2]=1,n[s+4>>2]=0),10756}function AD(s,l){s=s|0,l=l|0,NF(s,l)}function mOe(s){s=s|0,bl(s,yOe()|0,2)}function yOe(){return 1772}function EOe(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0,M=0;m=C,C=C+32|0,Q=m+16|0,M=m+12|0,B=m,k=Sl(COe()|0)|0,c=Km(c)|0,n[M>>2]=n[f>>2],n[Q>>2]=n[M>>2],f=Rg(Q)|0,n[B>>2]=n[d>>2],Q=d+4|0,n[B+4>>2]=n[Q>>2],M=d+8|0,n[B+8>>2]=n[M>>2],n[M>>2]=0,n[Q>>2]=0,n[d>>2]=0,AD(s,hc(0,k|0,l|0,c|0,f|0,mR(B)|0)|0),ef(B),C=m}function COe(){var s=0;return o[8008]|0||(wOe(10768),s=8008,n[s>>2]=1,n[s+4>>2]=0),10768}function wOe(s){s=s|0,bl(s,IOe()|0,3)}function IOe(){return 1784}function BOe(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0;m=C,C=C+16|0,k=m+4|0,Q=m,B=Sl(vOe()|0)|0,c=Km(c)|0,n[Q>>2]=n[f>>2],n[k>>2]=n[Q>>2],f=Rg(k)|0,AD(s,hc(0,B|0,l|0,c|0,f|0,dR(d)|0)|0),C=m}function vOe(){var s=0;return o[8016]|0||(DOe(10780),s=8016,n[s>>2]=1,n[s+4>>2]=0),10780}function DOe(s){s=s|0,bl(s,POe()|0,3)}function POe(){return 1800}function SOe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;f=Sl(bOe()|0)|0,AD(s,Qn(0,f|0,l|0,Km(c)|0)|0)}function bOe(){var s=0;return o[8024]|0||(xOe(10792),s=8024,n[s>>2]=1,n[s+4>>2]=0),10792}function xOe(s){s=s|0,bl(s,kOe()|0,1)}function kOe(){return 1816}function QOe(){FOe(),ROe(),TOe()}function FOe(){n[2702]=p7(65536)|0}function ROe(){eMe(10856)}function TOe(){LOe(10816)}function LOe(s){s=s|0,NOe(s,5044),OOe(s)|0}function NOe(s,l){s=s|0,l=l|0;var c=0;c=x5()|0,n[s>>2]=c,zOe(c,l),kp(n[s>>2]|0)}function OOe(s){s=s|0;var l=0;return l=n[s>>2]|0,Qg(l,MOe()|0),s|0}function MOe(){var s=0;return o[8032]|0||(_5(10820),rr(64,10820,U|0)|0,s=8032,n[s>>2]=1,n[s+4>>2]=0),Tr(10820)|0||_5(10820),10820}function _5(s){s=s|0,HOe(s),Fg(s,25)}function UOe(s){s=s|0,_Oe(s+24|0)}function _Oe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function HOe(s){s=s|0;var l=0;l=Kr()|0,zr(s,5,18,l,YOe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function qOe(s,l){s=s|0,l=l|0,GOe(s,l)}function GOe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0;c=C,C=C+16|0,f=c,d=c+4|0,xg(d,l),n[f>>2]=kg(d,l)|0,jOe(s,f),C=c}function jOe(s,l){s=s|0,l=l|0,H5(s+4|0,n[l>>2]|0),o[s+8>>0]=1}function H5(s,l){s=s|0,l=l|0,n[s>>2]=l}function YOe(){return 1824}function WOe(s){return s=s|0,KOe(s)|0}function KOe(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0;return c=C,C=C+16|0,d=c+4|0,B=c,f=Ka(8)|0,l=f,k=Kt(4)|0,xg(d,s),H5(k,kg(d,s)|0),m=l+4|0,n[m>>2]=k,s=Kt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],k5(s,m,d),n[f>>2]=s,C=c,l|0}function Ka(s){s=s|0;var l=0,c=0;return s=s+7&-8,s>>>0<=32768&&(l=n[2701]|0,s>>>0<=(65536-l|0)>>>0)?(c=(n[2702]|0)+l|0,n[2701]=l+s,s=c):(s=p7(s+8|0)|0,n[s>>2]=n[2703],n[2703]=s,s=s+8|0),s|0}function zOe(s,l){s=s|0,l=l|0,n[s>>2]=VOe()|0,n[s+4>>2]=JOe()|0,n[s+12>>2]=l,n[s+8>>2]=XOe()|0,n[s+32>>2]=9}function VOe(){return 11744}function JOe(){return 1832}function XOe(){return lD()|0}function ZOe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(xp(f,896)|0)==512?c|0&&($Oe(c),gt(c)):l|0&&gt(l)}function $Oe(s){s=s|0,s=n[s+4>>2]|0,s|0&&Qp(s)}function eMe(s){s=s|0,tMe(s,5052),rMe(s)|0,nMe(s,5058,26)|0,iMe(s,5069,1)|0,sMe(s,5077,10)|0,oMe(s,5087,19)|0,aMe(s,5094,27)|0}function tMe(s,l){s=s|0,l=l|0;var c=0;c=$4e()|0,n[s>>2]=c,eUe(c,l),kp(n[s>>2]|0)}function rMe(s){s=s|0;var l=0;return l=n[s>>2]|0,Qg(l,U4e()|0),s|0}function nMe(s,l,c){return s=s|0,l=l|0,c=c|0,w4e(s,pn(l)|0,c,0),s|0}function iMe(s,l,c){return s=s|0,l=l|0,c=c|0,o4e(s,pn(l)|0,c,0),s|0}function sMe(s,l,c){return s=s|0,l=l|0,c=c|0,MMe(s,pn(l)|0,c,0),s|0}function oMe(s,l,c){return s=s|0,l=l|0,c=c|0,BMe(s,pn(l)|0,c,0),s|0}function q5(s,l){s=s|0,l=l|0;var c=0,f=0;e:for(;;){for(c=n[2703]|0;;){if((c|0)==(l|0))break e;if(f=n[c>>2]|0,n[2703]=f,!c)c=f;else break}gt(c)}n[2701]=s}function aMe(s,l,c){return s=s|0,l=l|0,c=c|0,lMe(s,pn(l)|0,c,0),s|0}function lMe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=yR()|0,s=cMe(c)|0,hn(m,l,d,s,uMe(c,f)|0,f)}function yR(){var s=0,l=0;if(o[8040]|0||(j5(10860),rr(65,10860,U|0)|0,l=8040,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10860)|0)){s=10860,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));j5(10860)}return 10860}function cMe(s){return s=s|0,s|0}function uMe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=yR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(G5(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(AMe(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function G5(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function AMe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=fMe(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,pMe(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,G5(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,hMe(s,d),gMe(d),C=k;return}}function fMe(s){return s=s|0,536870911}function pMe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function hMe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function gMe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function j5(s){s=s|0,yMe(s)}function dMe(s){s=s|0,mMe(s+24|0)}function mMe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function yMe(s){s=s|0;var l=0;l=Kr()|0,zr(s,1,11,l,EMe()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function EMe(){return 1840}function CMe(s,l,c){s=s|0,l=l|0,c=c|0,IMe(n[(wMe(s)|0)>>2]|0,l,c)}function wMe(s){return s=s|0,(n[(yR()|0)+24>>2]|0)+(s<<3)|0}function IMe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;f=C,C=C+16|0,m=f+1|0,d=f,xg(m,l),l=kg(m,l)|0,xg(d,c),c=kg(d,c)|0,rf[s&31](l,c),C=f}function BMe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=ER()|0,s=vMe(c)|0,hn(m,l,d,s,DMe(c,f)|0,f)}function ER(){var s=0,l=0;if(o[8048]|0||(W5(10896),rr(66,10896,U|0)|0,l=8048,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10896)|0)){s=10896,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));W5(10896)}return 10896}function vMe(s){return s=s|0,s|0}function DMe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=ER()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(Y5(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(PMe(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function Y5(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function PMe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=SMe(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,bMe(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,Y5(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,xMe(s,d),kMe(d),C=k;return}}function SMe(s){return s=s|0,536870911}function bMe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function xMe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function kMe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function W5(s){s=s|0,RMe(s)}function QMe(s){s=s|0,FMe(s+24|0)}function FMe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function RMe(s){s=s|0;var l=0;l=Kr()|0,zr(s,1,11,l,TMe()|0,1),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function TMe(){return 1852}function LMe(s,l){return s=s|0,l=l|0,OMe(n[(NMe(s)|0)>>2]|0,l)|0}function NMe(s){return s=s|0,(n[(ER()|0)+24>>2]|0)+(s<<3)|0}function OMe(s,l){s=s|0,l=l|0;var c=0,f=0;return c=C,C=C+16|0,f=c,xg(f,l),l=kg(f,l)|0,l=oD(Og[s&31](l)|0)|0,C=c,l|0}function MMe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=CR()|0,s=UMe(c)|0,hn(m,l,d,s,_Me(c,f)|0,f)}function CR(){var s=0,l=0;if(o[8056]|0||(z5(10932),rr(67,10932,U|0)|0,l=8056,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10932)|0)){s=10932,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));z5(10932)}return 10932}function UMe(s){return s=s|0,s|0}function _Me(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=CR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(K5(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(HMe(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function K5(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function HMe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=qMe(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,GMe(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,K5(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,jMe(s,d),YMe(d),C=k;return}}function qMe(s){return s=s|0,536870911}function GMe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function jMe(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function YMe(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function z5(s){s=s|0,zMe(s)}function WMe(s){s=s|0,KMe(s+24|0)}function KMe(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function zMe(s){s=s|0;var l=0;l=Kr()|0,zr(s,1,7,l,VMe()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function VMe(){return 1860}function JMe(s,l,c){return s=s|0,l=l|0,c=c|0,ZMe(n[(XMe(s)|0)>>2]|0,l,c)|0}function XMe(s){return s=s|0,(n[(CR()|0)+24>>2]|0)+(s<<3)|0}function ZMe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0;return f=C,C=C+32|0,B=f+12|0,m=f+8|0,k=f,Q=f+16|0,d=f+4|0,$Me(Q,l),e4e(k,Q,l),Pp(d,c),c=Sp(d,c)|0,n[B>>2]=n[k>>2],Hw[s&15](m,B,c),c=t4e(m)|0,jA(m),bp(d),C=f,c|0}function $Me(s,l){s=s|0,l=l|0}function e4e(s,l,c){s=s|0,l=l|0,c=c|0,r4e(s,c)}function t4e(s){return s=s|0,da(s)|0}function r4e(s,l){s=s|0,l=l|0;var c=0,f=0,d=0;d=C,C=C+16|0,c=d,f=l,f&1?(n4e(c,0),ii(f|0,c|0)|0,i4e(s,c),s4e(c)):n[s>>2]=n[l>>2],C=d}function n4e(s,l){s=s|0,l=l|0,Xj(s,l),n[s+4>>2]=0,o[s+8>>0]=0}function i4e(s,l){s=s|0,l=l|0,n[s>>2]=n[l+4>>2]}function s4e(s){s=s|0,o[s+8>>0]=0}function o4e(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=wR()|0,s=a4e(c)|0,hn(m,l,d,s,l4e(c,f)|0,f)}function wR(){var s=0,l=0;if(o[8064]|0||(J5(10968),rr(68,10968,U|0)|0,l=8064,n[l>>2]=1,n[l+4>>2]=0),!(Tr(10968)|0)){s=10968,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));J5(10968)}return 10968}function a4e(s){return s=s|0,s|0}function l4e(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=wR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(V5(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(c4e(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function V5(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function c4e(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=u4e(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,A4e(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,V5(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,f4e(s,d),p4e(d),C=k;return}}function u4e(s){return s=s|0,536870911}function A4e(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function f4e(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function p4e(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function J5(s){s=s|0,d4e(s)}function h4e(s){s=s|0,g4e(s+24|0)}function g4e(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function d4e(s){s=s|0;var l=0;l=Kr()|0,zr(s,1,1,l,m4e()|0,5),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function m4e(){return 1872}function y4e(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,C4e(n[(E4e(s)|0)>>2]|0,l,c,f,d,m)}function E4e(s){return s=s|0,(n[(wR()|0)+24>>2]|0)+(s<<3)|0}function C4e(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0;var B=0,k=0,Q=0,M=0,O=0,G=0;B=C,C=C+32|0,k=B+16|0,Q=B+12|0,M=B+8|0,O=B+4|0,G=B,Pp(k,l),l=Sp(k,l)|0,Pp(Q,c),c=Sp(Q,c)|0,Pp(M,f),f=Sp(M,f)|0,Pp(O,d),d=Sp(O,d)|0,Pp(G,m),m=Sp(G,m)|0,y7[s&1](l,c,f,d,m),bp(G),bp(O),bp(M),bp(Q),bp(k),C=B}function w4e(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;m=n[s>>2]|0,d=IR()|0,s=I4e(c)|0,hn(m,l,d,s,B4e(c,f)|0,f)}function IR(){var s=0,l=0;if(o[8072]|0||(Z5(11004),rr(69,11004,U|0)|0,l=8072,n[l>>2]=1,n[l+4>>2]=0),!(Tr(11004)|0)){s=11004,l=s+36|0;do n[s>>2]=0,s=s+4|0;while((s|0)<(l|0));Z5(11004)}return 11004}function I4e(s){return s=s|0,s|0}function B4e(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0,k=0,Q=0;return k=C,C=C+16|0,d=k,m=k+4|0,n[d>>2]=s,Q=IR()|0,B=Q+24|0,l=gr(l,4)|0,n[m>>2]=l,c=Q+28|0,f=n[c>>2]|0,f>>>0<(n[Q+32>>2]|0)>>>0?(X5(f,s,l),l=(n[c>>2]|0)+8|0,n[c>>2]=l):(v4e(B,d,m),l=n[c>>2]|0),C=k,(l-(n[B>>2]|0)>>3)+-1|0}function X5(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,n[s+4>>2]=c}function v4e(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0;if(k=C,C=C+32|0,d=k,m=s+4|0,B=((n[m>>2]|0)-(n[s>>2]|0)>>3)+1|0,f=D4e(s)|0,f>>>0<B>>>0)Jr(s);else{Q=n[s>>2]|0,O=(n[s+8>>2]|0)-Q|0,M=O>>2,P4e(d,O>>3>>>0<f>>>1>>>0?M>>>0<B>>>0?B:M:f,(n[m>>2]|0)-Q>>3,s+8|0),B=d+8|0,X5(n[B>>2]|0,n[l>>2]|0,n[c>>2]|0),n[B>>2]=(n[B>>2]|0)+8,S4e(s,d),b4e(d),C=k;return}}function D4e(s){return s=s|0,536870911}function P4e(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0;n[s+12>>2]=0,n[s+16>>2]=f;do if(l)if(l>>>0>536870911)Rt();else{d=Kt(l<<3)|0;break}else d=0;while(0);n[s>>2]=d,f=d+(c<<3)|0,n[s+8>>2]=f,n[s+4>>2]=f,n[s+12>>2]=d+(l<<3)}function S4e(s,l){s=s|0,l=l|0;var c=0,f=0,d=0,m=0,B=0;f=n[s>>2]|0,B=s+4|0,m=l+4|0,d=(n[B>>2]|0)-f|0,c=(n[m>>2]|0)+(0-(d>>3)<<3)|0,n[m>>2]=c,(d|0)>0?(Dr(c|0,f|0,d|0)|0,f=m,c=n[m>>2]|0):f=m,m=n[s>>2]|0,n[s>>2]=c,n[f>>2]=m,m=l+8|0,d=n[B>>2]|0,n[B>>2]=n[m>>2],n[m>>2]=d,m=s+8|0,B=l+12|0,s=n[m>>2]|0,n[m>>2]=n[B>>2],n[B>>2]=s,n[l>>2]=n[f>>2]}function b4e(s){s=s|0;var l=0,c=0,f=0;l=n[s+4>>2]|0,c=s+8|0,f=n[c>>2]|0,(f|0)!=(l|0)&&(n[c>>2]=f+(~((f+-8-l|0)>>>3)<<3)),s=n[s>>2]|0,s|0&&gt(s)}function Z5(s){s=s|0,Q4e(s)}function x4e(s){s=s|0,k4e(s+24|0)}function k4e(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function Q4e(s){s=s|0;var l=0;l=Kr()|0,zr(s,1,12,l,F4e()|0,2),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function F4e(){return 1896}function R4e(s,l,c){s=s|0,l=l|0,c=c|0,L4e(n[(T4e(s)|0)>>2]|0,l,c)}function T4e(s){return s=s|0,(n[(IR()|0)+24>>2]|0)+(s<<3)|0}function L4e(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;f=C,C=C+16|0,m=f+4|0,d=f,N4e(m,l),l=O4e(m,l)|0,Pp(d,c),c=Sp(d,c)|0,rf[s&31](l,c),bp(d),C=f}function N4e(s,l){s=s|0,l=l|0}function O4e(s,l){return s=s|0,l=l|0,M4e(l)|0}function M4e(s){return s=s|0,s|0}function U4e(){var s=0;return o[8080]|0||($5(11040),rr(70,11040,U|0)|0,s=8080,n[s>>2]=1,n[s+4>>2]=0),Tr(11040)|0||$5(11040),11040}function $5(s){s=s|0,q4e(s),Fg(s,71)}function _4e(s){s=s|0,H4e(s+24|0)}function H4e(s){s=s|0;var l=0,c=0,f=0;c=n[s>>2]|0,f=c,c|0&&(s=s+4|0,l=n[s>>2]|0,(l|0)!=(c|0)&&(n[s>>2]=l+(~((l+-8-f|0)>>>3)<<3)),gt(c))}function q4e(s){s=s|0;var l=0;l=Kr()|0,zr(s,5,7,l,W4e()|0,0),n[s+24>>2]=0,n[s+28>>2]=0,n[s+32>>2]=0}function G4e(s){s=s|0,j4e(s)}function j4e(s){s=s|0,Y4e(s)}function Y4e(s){s=s|0,o[s+8>>0]=1}function W4e(){return 1936}function K4e(){return z4e()|0}function z4e(){var s=0,l=0,c=0,f=0,d=0,m=0,B=0;return l=C,C=C+16|0,d=l+4|0,B=l,c=Ka(8)|0,s=c,m=s+4|0,n[m>>2]=Kt(1)|0,f=Kt(8)|0,m=n[m>>2]|0,n[B>>2]=0,n[d>>2]=n[B>>2],V4e(f,m,d),n[c>>2]=f,C=l,s|0}function V4e(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]=l,c=Kt(16)|0,n[c+4>>2]=0,n[c+8>>2]=0,n[c>>2]=1916,n[c+12>>2]=l,n[s+4>>2]=c}function J4e(s){s=s|0,Jm(s),gt(s)}function X4e(s){s=s|0,s=n[s+12>>2]|0,s|0&&gt(s)}function Z4e(s){s=s|0,gt(s)}function $4e(){var s=0;return o[8088]|0||(oUe(11076),rr(25,11076,U|0)|0,s=8088,n[s>>2]=1,n[s+4>>2]=0),11076}function eUe(s,l){s=s|0,l=l|0,n[s>>2]=tUe()|0,n[s+4>>2]=rUe()|0,n[s+12>>2]=l,n[s+8>>2]=nUe()|0,n[s+32>>2]=10}function tUe(){return 11745}function rUe(){return 1940}function nUe(){return aD()|0}function iUe(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,(xp(f,896)|0)==512?c|0&&(sUe(c),gt(c)):l|0&&gt(l)}function sUe(s){s=s|0,s=n[s+4>>2]|0,s|0&&Qp(s)}function oUe(s){s=s|0,Dp(s)}function xc(s,l){s=s|0,l=l|0,n[s>>2]=l}function BR(s){return s=s|0,n[s>>2]|0}function aUe(s){return s=s|0,o[n[s>>2]>>0]|0}function lUe(s,l){s=s|0,l=l|0;var c=0,f=0;c=C,C=C+16|0,f=c,n[f>>2]=n[s>>2],cUe(l,f)|0,C=c}function cUe(s,l){s=s|0,l=l|0;var c=0;return c=uUe(n[s>>2]|0,l)|0,l=s+4|0,n[(n[l>>2]|0)+8>>2]=c,n[(n[l>>2]|0)+8>>2]|0}function uUe(s,l){s=s|0,l=l|0;var c=0,f=0;return c=C,C=C+16|0,f=c,za(f),s=da(s)|0,l=AUe(s,n[l>>2]|0)|0,Va(f),C=c,l|0}function za(s){s=s|0,n[s>>2]=n[2701],n[s+4>>2]=n[2703]}function AUe(s,l){s=s|0,l=l|0;var c=0;return c=Sl(fUe()|0)|0,Qn(0,c|0,s|0,dR(l)|0)|0}function Va(s){s=s|0,q5(n[s>>2]|0,n[s+4>>2]|0)}function fUe(){var s=0;return o[8096]|0||(pUe(11120),s=8096,n[s>>2]=1,n[s+4>>2]=0),11120}function pUe(s){s=s|0,bl(s,hUe()|0,1)}function hUe(){return 1948}function gUe(){dUe()}function dUe(){var s=0,l=0,c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0,je=0,Me=0,Qe=0;if(Me=C,C=C+16|0,O=Me+4|0,G=Me,Li(65536,10804,n[2702]|0,10812),c=B5()|0,l=n[c>>2]|0,s=n[l>>2]|0,s|0)for(f=n[c+8>>2]|0,c=n[c+4>>2]|0;Ac(s|0,u[c>>0]|0|0,o[f>>0]|0),l=l+4|0,s=n[l>>2]|0,s;)f=f+1|0,c=c+1|0;if(s=v5()|0,l=n[s>>2]|0,l|0)do Au(l|0,n[s+4>>2]|0),s=s+8|0,l=n[s>>2]|0;while((l|0)!=0);Au(mUe()|0,5167),M=Ym()|0,s=n[M>>2]|0;e:do if(s|0){do yUe(n[s+4>>2]|0),s=n[s>>2]|0;while((s|0)!=0);if(s=n[M>>2]|0,s|0){Q=M;do{for(;d=s,s=n[s>>2]|0,d=n[d+4>>2]|0,!!(EUe(d)|0);)if(n[G>>2]=Q,n[O>>2]=n[G>>2],CUe(M,O)|0,!s)break e;if(wUe(d),Q=n[Q>>2]|0,l=e7(d)|0,m=Hi()|0,B=C,C=C+((1*(l<<2)|0)+15&-16)|0,k=C,C=C+((1*(l<<2)|0)+15&-16)|0,l=n[(N5(d)|0)>>2]|0,l|0)for(c=B,f=k;n[c>>2]=n[(Wm(n[l+4>>2]|0)|0)>>2],n[f>>2]=n[l+8>>2],l=n[l>>2]|0,l;)c=c+4|0,f=f+4|0;Qe=Wm(d)|0,l=IUe(d)|0,c=e7(d)|0,f=BUe(d)|0,fu(Qe|0,l|0,B|0,k|0,c|0,f|0,uR(d)|0),_i(m|0)}while((s|0)!=0)}}while(0);if(s=n[(AR()|0)>>2]|0,s|0)do Qe=s+4|0,M=fR(Qe)|0,d=Ow(M)|0,m=Lw(M)|0,B=(Nw(M)|0)+1|0,k=fD(M)|0,Q=t7(Qe)|0,M=Tr(M)|0,O=cD(Qe)|0,G=vR(Qe)|0,Cl(0,d|0,m|0,B|0,k|0,Q|0,M|0,O|0,G|0,DR(Qe)|0),s=n[s>>2]|0;while((s|0)!=0);s=n[(Ym()|0)>>2]|0;e:do if(s|0){t:for(;;){if(l=n[s+4>>2]|0,l|0&&(se=n[(Wm(l)|0)>>2]|0,je=n[(O5(l)|0)>>2]|0,je|0)){c=je;do{l=c+4|0,f=fR(l)|0;r:do if(f|0)switch(Tr(f)|0){case 0:break t;case 4:case 3:case 2:{k=Ow(f)|0,Q=Lw(f)|0,M=(Nw(f)|0)+1|0,O=fD(f)|0,G=Tr(f)|0,Qe=cD(l)|0,Cl(se|0,k|0,Q|0,M|0,O|0,0,G|0,Qe|0,vR(l)|0,DR(l)|0);break r}case 1:{B=Ow(f)|0,k=Lw(f)|0,Q=(Nw(f)|0)+1|0,M=fD(f)|0,O=t7(l)|0,G=Tr(f)|0,Qe=cD(l)|0,Cl(se|0,B|0,k|0,Q|0,M|0,O|0,G|0,Qe|0,vR(l)|0,DR(l)|0);break r}case 5:{M=Ow(f)|0,O=Lw(f)|0,G=(Nw(f)|0)+1|0,Qe=fD(f)|0,Cl(se|0,M|0,O|0,G|0,Qe|0,vUe(f)|0,Tr(f)|0,0,0,0);break r}default:break r}while(0);c=n[c>>2]|0}while((c|0)!=0)}if(s=n[s>>2]|0,!s)break e}Rt()}while(0);Ce(),C=Me}function mUe(){return 11703}function yUe(s){s=s|0,o[s+40>>0]=0}function EUe(s){return s=s|0,(o[s+40>>0]|0)!=0|0}function CUe(s,l){return s=s|0,l=l|0,l=DUe(l)|0,s=n[l>>2]|0,n[l>>2]=n[s>>2],gt(s),n[l>>2]|0}function wUe(s){s=s|0,o[s+40>>0]=1}function e7(s){return s=s|0,n[s+20>>2]|0}function IUe(s){return s=s|0,n[s+8>>2]|0}function BUe(s){return s=s|0,n[s+32>>2]|0}function fD(s){return s=s|0,n[s+4>>2]|0}function t7(s){return s=s|0,n[s+4>>2]|0}function vR(s){return s=s|0,n[s+8>>2]|0}function DR(s){return s=s|0,n[s+16>>2]|0}function vUe(s){return s=s|0,n[s+20>>2]|0}function DUe(s){return s=s|0,n[s>>2]|0}function pD(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0,je=0,Me=0,Qe=0,et=0,Xe=0,lt=0,Ue=0,Ge=0,Nt=0;Nt=C,C=C+16|0,se=Nt;do if(s>>>0<245){if(M=s>>>0<11?16:s+11&-8,s=M>>>3,G=n[2783]|0,c=G>>>s,c&3|0)return l=(c&1^1)+s|0,s=11172+(l<<1<<2)|0,c=s+8|0,f=n[c>>2]|0,d=f+8|0,m=n[d>>2]|0,(s|0)==(m|0)?n[2783]=G&~(1<<l):(n[m+12>>2]=s,n[c>>2]=m),Ge=l<<3,n[f+4>>2]=Ge|3,Ge=f+Ge+4|0,n[Ge>>2]=n[Ge>>2]|1,Ge=d,C=Nt,Ge|0;if(O=n[2785]|0,M>>>0>O>>>0){if(c|0)return l=2<<s,l=c<<s&(l|0-l),l=(l&0-l)+-1|0,B=l>>>12&16,l=l>>>B,c=l>>>5&8,l=l>>>c,d=l>>>2&4,l=l>>>d,s=l>>>1&2,l=l>>>s,f=l>>>1&1,f=(c|B|d|s|f)+(l>>>f)|0,l=11172+(f<<1<<2)|0,s=l+8|0,d=n[s>>2]|0,B=d+8|0,c=n[B>>2]|0,(l|0)==(c|0)?(s=G&~(1<<f),n[2783]=s):(n[c+12>>2]=l,n[s>>2]=c,s=G),m=(f<<3)-M|0,n[d+4>>2]=M|3,f=d+M|0,n[f+4>>2]=m|1,n[f+m>>2]=m,O|0&&(d=n[2788]|0,l=O>>>3,c=11172+(l<<1<<2)|0,l=1<<l,s&l?(s=c+8|0,l=n[s>>2]|0):(n[2783]=s|l,l=c,s=c+8|0),n[s>>2]=d,n[l+12>>2]=d,n[d+8>>2]=l,n[d+12>>2]=c),n[2785]=m,n[2788]=f,Ge=B,C=Nt,Ge|0;if(k=n[2784]|0,k){if(c=(k&0-k)+-1|0,B=c>>>12&16,c=c>>>B,m=c>>>5&8,c=c>>>m,Q=c>>>2&4,c=c>>>Q,f=c>>>1&2,c=c>>>f,s=c>>>1&1,s=n[11436+((m|B|Q|f|s)+(c>>>s)<<2)>>2]|0,c=(n[s+4>>2]&-8)-M|0,f=n[s+16+(((n[s+16>>2]|0)==0&1)<<2)>>2]|0,!f)Q=s,m=c;else{do B=(n[f+4>>2]&-8)-M|0,Q=B>>>0<c>>>0,c=Q?B:c,s=Q?f:s,f=n[f+16+(((n[f+16>>2]|0)==0&1)<<2)>>2]|0;while((f|0)!=0);Q=s,m=c}if(B=Q+M|0,Q>>>0<B>>>0){d=n[Q+24>>2]|0,l=n[Q+12>>2]|0;do if((l|0)==(Q|0)){if(s=Q+20|0,l=n[s>>2]|0,!l&&(s=Q+16|0,l=n[s>>2]|0,!l)){c=0;break}for(;;){if(c=l+20|0,f=n[c>>2]|0,f|0){l=f,s=c;continue}if(c=l+16|0,f=n[c>>2]|0,f)l=f,s=c;else break}n[s>>2]=0,c=l}else c=n[Q+8>>2]|0,n[c+12>>2]=l,n[l+8>>2]=c,c=l;while(0);do if(d|0){if(l=n[Q+28>>2]|0,s=11436+(l<<2)|0,(Q|0)==(n[s>>2]|0)){if(n[s>>2]=c,!c){n[2784]=k&~(1<<l);break}}else if(n[d+16+(((n[d+16>>2]|0)!=(Q|0)&1)<<2)>>2]=c,!c)break;n[c+24>>2]=d,l=n[Q+16>>2]|0,l|0&&(n[c+16>>2]=l,n[l+24>>2]=c),l=n[Q+20>>2]|0,l|0&&(n[c+20>>2]=l,n[l+24>>2]=c)}while(0);return m>>>0<16?(Ge=m+M|0,n[Q+4>>2]=Ge|3,Ge=Q+Ge+4|0,n[Ge>>2]=n[Ge>>2]|1):(n[Q+4>>2]=M|3,n[B+4>>2]=m|1,n[B+m>>2]=m,O|0&&(f=n[2788]|0,l=O>>>3,c=11172+(l<<1<<2)|0,l=1<<l,G&l?(s=c+8|0,l=n[s>>2]|0):(n[2783]=G|l,l=c,s=c+8|0),n[s>>2]=f,n[l+12>>2]=f,n[f+8>>2]=l,n[f+12>>2]=c),n[2785]=m,n[2788]=B),Ge=Q+8|0,C=Nt,Ge|0}else G=M}else G=M}else G=M}else if(s>>>0<=4294967231)if(s=s+11|0,M=s&-8,Q=n[2784]|0,Q){f=0-M|0,s=s>>>8,s?M>>>0>16777215?k=31:(G=(s+1048320|0)>>>16&8,Ue=s<<G,O=(Ue+520192|0)>>>16&4,Ue=Ue<<O,k=(Ue+245760|0)>>>16&2,k=14-(O|G|k)+(Ue<<k>>>15)|0,k=M>>>(k+7|0)&1|k<<1):k=0,c=n[11436+(k<<2)>>2]|0;e:do if(!c)c=0,s=0,Ue=57;else for(s=0,B=M<<((k|0)==31?0:25-(k>>>1)|0),m=0;;){if(d=(n[c+4>>2]&-8)-M|0,d>>>0<f>>>0)if(d)s=c,f=d;else{s=c,f=0,d=c,Ue=61;break e}if(d=n[c+20>>2]|0,c=n[c+16+(B>>>31<<2)>>2]|0,m=(d|0)==0|(d|0)==(c|0)?m:d,d=(c|0)==0,d){c=m,Ue=57;break}else B=B<<((d^1)&1)}while(0);if((Ue|0)==57){if((c|0)==0&(s|0)==0){if(s=2<<k,s=Q&(s|0-s),!s){G=M;break}G=(s&0-s)+-1|0,B=G>>>12&16,G=G>>>B,m=G>>>5&8,G=G>>>m,k=G>>>2&4,G=G>>>k,O=G>>>1&2,G=G>>>O,c=G>>>1&1,s=0,c=n[11436+((m|B|k|O|c)+(G>>>c)<<2)>>2]|0}c?(d=c,Ue=61):(k=s,B=f)}if((Ue|0)==61)for(;;)if(Ue=0,c=(n[d+4>>2]&-8)-M|0,G=c>>>0<f>>>0,c=G?c:f,s=G?d:s,d=n[d+16+(((n[d+16>>2]|0)==0&1)<<2)>>2]|0,d)f=c,Ue=61;else{k=s,B=c;break}if((k|0)!=0&&B>>>0<((n[2785]|0)-M|0)>>>0){if(m=k+M|0,k>>>0>=m>>>0)return Ge=0,C=Nt,Ge|0;d=n[k+24>>2]|0,l=n[k+12>>2]|0;do if((l|0)==(k|0)){if(s=k+20|0,l=n[s>>2]|0,!l&&(s=k+16|0,l=n[s>>2]|0,!l)){l=0;break}for(;;){if(c=l+20|0,f=n[c>>2]|0,f|0){l=f,s=c;continue}if(c=l+16|0,f=n[c>>2]|0,f)l=f,s=c;else break}n[s>>2]=0}else Ge=n[k+8>>2]|0,n[Ge+12>>2]=l,n[l+8>>2]=Ge;while(0);do if(d){if(s=n[k+28>>2]|0,c=11436+(s<<2)|0,(k|0)==(n[c>>2]|0)){if(n[c>>2]=l,!l){f=Q&~(1<<s),n[2784]=f;break}}else if(n[d+16+(((n[d+16>>2]|0)!=(k|0)&1)<<2)>>2]=l,!l){f=Q;break}n[l+24>>2]=d,s=n[k+16>>2]|0,s|0&&(n[l+16>>2]=s,n[s+24>>2]=l),s=n[k+20>>2]|0,s&&(n[l+20>>2]=s,n[s+24>>2]=l),f=Q}else f=Q;while(0);do if(B>>>0>=16){if(n[k+4>>2]=M|3,n[m+4>>2]=B|1,n[m+B>>2]=B,l=B>>>3,B>>>0<256){c=11172+(l<<1<<2)|0,s=n[2783]|0,l=1<<l,s&l?(s=c+8|0,l=n[s>>2]|0):(n[2783]=s|l,l=c,s=c+8|0),n[s>>2]=m,n[l+12>>2]=m,n[m+8>>2]=l,n[m+12>>2]=c;break}if(l=B>>>8,l?B>>>0>16777215?l=31:(Ue=(l+1048320|0)>>>16&8,Ge=l<<Ue,lt=(Ge+520192|0)>>>16&4,Ge=Ge<<lt,l=(Ge+245760|0)>>>16&2,l=14-(lt|Ue|l)+(Ge<<l>>>15)|0,l=B>>>(l+7|0)&1|l<<1):l=0,c=11436+(l<<2)|0,n[m+28>>2]=l,s=m+16|0,n[s+4>>2]=0,n[s>>2]=0,s=1<<l,!(f&s)){n[2784]=f|s,n[c>>2]=m,n[m+24>>2]=c,n[m+12>>2]=m,n[m+8>>2]=m;break}for(s=B<<((l|0)==31?0:25-(l>>>1)|0),c=n[c>>2]|0;;){if((n[c+4>>2]&-8|0)==(B|0)){Ue=97;break}if(f=c+16+(s>>>31<<2)|0,l=n[f>>2]|0,l)s=s<<1,c=l;else{Ue=96;break}}if((Ue|0)==96){n[f>>2]=m,n[m+24>>2]=c,n[m+12>>2]=m,n[m+8>>2]=m;break}else if((Ue|0)==97){Ue=c+8|0,Ge=n[Ue>>2]|0,n[Ge+12>>2]=m,n[Ue>>2]=m,n[m+8>>2]=Ge,n[m+12>>2]=c,n[m+24>>2]=0;break}}else Ge=B+M|0,n[k+4>>2]=Ge|3,Ge=k+Ge+4|0,n[Ge>>2]=n[Ge>>2]|1;while(0);return Ge=k+8|0,C=Nt,Ge|0}else G=M}else G=M;else G=-1;while(0);if(c=n[2785]|0,c>>>0>=G>>>0)return l=c-G|0,s=n[2788]|0,l>>>0>15?(Ge=s+G|0,n[2788]=Ge,n[2785]=l,n[Ge+4>>2]=l|1,n[Ge+l>>2]=l,n[s+4>>2]=G|3):(n[2785]=0,n[2788]=0,n[s+4>>2]=c|3,Ge=s+c+4|0,n[Ge>>2]=n[Ge>>2]|1),Ge=s+8|0,C=Nt,Ge|0;if(B=n[2786]|0,B>>>0>G>>>0)return lt=B-G|0,n[2786]=lt,Ge=n[2789]|0,Ue=Ge+G|0,n[2789]=Ue,n[Ue+4>>2]=lt|1,n[Ge+4>>2]=G|3,Ge=Ge+8|0,C=Nt,Ge|0;if(n[2901]|0?s=n[2903]|0:(n[2903]=4096,n[2902]=4096,n[2904]=-1,n[2905]=-1,n[2906]=0,n[2894]=0,s=se&-16^1431655768,n[se>>2]=s,n[2901]=s,s=4096),k=G+48|0,Q=G+47|0,m=s+Q|0,d=0-s|0,M=m&d,M>>>0<=G>>>0||(s=n[2893]|0,s|0&&(O=n[2891]|0,se=O+M|0,se>>>0<=O>>>0|se>>>0>s>>>0)))return Ge=0,C=Nt,Ge|0;e:do if(n[2894]&4)l=0,Ue=133;else{c=n[2789]|0;t:do if(c){for(f=11580;s=n[f>>2]|0,!(s>>>0<=c>>>0&&(Qe=f+4|0,(s+(n[Qe>>2]|0)|0)>>>0>c>>>0));)if(s=n[f+8>>2]|0,s)f=s;else{Ue=118;break t}if(l=m-B&d,l>>>0<2147483647)if(s=Fp(l|0)|0,(s|0)==((n[f>>2]|0)+(n[Qe>>2]|0)|0)){if((s|0)!=-1){B=l,m=s,Ue=135;break e}}else f=s,Ue=126;else l=0}else Ue=118;while(0);do if((Ue|0)==118)if(c=Fp(0)|0,(c|0)!=-1&&(l=c,je=n[2902]|0,Me=je+-1|0,l=((Me&l|0)==0?0:(Me+l&0-je)-l|0)+M|0,je=n[2891]|0,Me=l+je|0,l>>>0>G>>>0&l>>>0<2147483647)){if(Qe=n[2893]|0,Qe|0&&Me>>>0<=je>>>0|Me>>>0>Qe>>>0){l=0;break}if(s=Fp(l|0)|0,(s|0)==(c|0)){B=l,m=c,Ue=135;break e}else f=s,Ue=126}else l=0;while(0);do if((Ue|0)==126){if(c=0-l|0,!(k>>>0>l>>>0&(l>>>0<2147483647&(f|0)!=-1)))if((f|0)==-1){l=0;break}else{B=l,m=f,Ue=135;break e}if(s=n[2903]|0,s=Q-l+s&0-s,s>>>0>=2147483647){B=l,m=f,Ue=135;break e}if((Fp(s|0)|0)==-1){Fp(c|0)|0,l=0;break}else{B=s+l|0,m=f,Ue=135;break e}}while(0);n[2894]=n[2894]|4,Ue=133}while(0);if((Ue|0)==133&&M>>>0<2147483647&&(lt=Fp(M|0)|0,Qe=Fp(0)|0,et=Qe-lt|0,Xe=et>>>0>(G+40|0)>>>0,!((lt|0)==-1|Xe^1|lt>>>0<Qe>>>0&((lt|0)!=-1&(Qe|0)!=-1)^1))&&(B=Xe?et:l,m=lt,Ue=135),(Ue|0)==135){l=(n[2891]|0)+B|0,n[2891]=l,l>>>0>(n[2892]|0)>>>0&&(n[2892]=l),Q=n[2789]|0;do if(Q){for(l=11580;;){if(s=n[l>>2]|0,c=l+4|0,f=n[c>>2]|0,(m|0)==(s+f|0)){Ue=145;break}if(d=n[l+8>>2]|0,d)l=d;else break}if((Ue|0)==145&&(n[l+12>>2]&8|0)==0&&Q>>>0<m>>>0&Q>>>0>=s>>>0){n[c>>2]=f+B,Ge=Q+8|0,Ge=(Ge&7|0)==0?0:0-Ge&7,Ue=Q+Ge|0,Ge=(n[2786]|0)+(B-Ge)|0,n[2789]=Ue,n[2786]=Ge,n[Ue+4>>2]=Ge|1,n[Ue+Ge+4>>2]=40,n[2790]=n[2905];break}for(m>>>0<(n[2787]|0)>>>0&&(n[2787]=m),c=m+B|0,l=11580;;){if((n[l>>2]|0)==(c|0)){Ue=153;break}if(s=n[l+8>>2]|0,s)l=s;else break}if((Ue|0)==153&&(n[l+12>>2]&8|0)==0){n[l>>2]=m,O=l+4|0,n[O>>2]=(n[O>>2]|0)+B,O=m+8|0,O=m+((O&7|0)==0?0:0-O&7)|0,l=c+8|0,l=c+((l&7|0)==0?0:0-l&7)|0,M=O+G|0,k=l-O-G|0,n[O+4>>2]=G|3;do if((l|0)!=(Q|0)){if((l|0)==(n[2788]|0)){Ge=(n[2785]|0)+k|0,n[2785]=Ge,n[2788]=M,n[M+4>>2]=Ge|1,n[M+Ge>>2]=Ge;break}if(s=n[l+4>>2]|0,(s&3|0)==1){B=s&-8,f=s>>>3;e:do if(s>>>0<256)if(s=n[l+8>>2]|0,c=n[l+12>>2]|0,(c|0)==(s|0)){n[2783]=n[2783]&~(1<<f);break}else{n[s+12>>2]=c,n[c+8>>2]=s;break}else{m=n[l+24>>2]|0,s=n[l+12>>2]|0;do if((s|0)==(l|0)){if(f=l+16|0,c=f+4|0,s=n[c>>2]|0,!s)if(s=n[f>>2]|0,s)c=f;else{s=0;break}for(;;){if(f=s+20|0,d=n[f>>2]|0,d|0){s=d,c=f;continue}if(f=s+16|0,d=n[f>>2]|0,d)s=d,c=f;else break}n[c>>2]=0}else Ge=n[l+8>>2]|0,n[Ge+12>>2]=s,n[s+8>>2]=Ge;while(0);if(!m)break;c=n[l+28>>2]|0,f=11436+(c<<2)|0;do if((l|0)!=(n[f>>2]|0)){if(n[m+16+(((n[m+16>>2]|0)!=(l|0)&1)<<2)>>2]=s,!s)break e}else{if(n[f>>2]=s,s|0)break;n[2784]=n[2784]&~(1<<c);break e}while(0);if(n[s+24>>2]=m,c=l+16|0,f=n[c>>2]|0,f|0&&(n[s+16>>2]=f,n[f+24>>2]=s),c=n[c+4>>2]|0,!c)break;n[s+20>>2]=c,n[c+24>>2]=s}while(0);l=l+B|0,d=B+k|0}else d=k;if(l=l+4|0,n[l>>2]=n[l>>2]&-2,n[M+4>>2]=d|1,n[M+d>>2]=d,l=d>>>3,d>>>0<256){c=11172+(l<<1<<2)|0,s=n[2783]|0,l=1<<l,s&l?(s=c+8|0,l=n[s>>2]|0):(n[2783]=s|l,l=c,s=c+8|0),n[s>>2]=M,n[l+12>>2]=M,n[M+8>>2]=l,n[M+12>>2]=c;break}l=d>>>8;do if(!l)l=0;else{if(d>>>0>16777215){l=31;break}Ue=(l+1048320|0)>>>16&8,Ge=l<<Ue,lt=(Ge+520192|0)>>>16&4,Ge=Ge<<lt,l=(Ge+245760|0)>>>16&2,l=14-(lt|Ue|l)+(Ge<<l>>>15)|0,l=d>>>(l+7|0)&1|l<<1}while(0);if(f=11436+(l<<2)|0,n[M+28>>2]=l,s=M+16|0,n[s+4>>2]=0,n[s>>2]=0,s=n[2784]|0,c=1<<l,!(s&c)){n[2784]=s|c,n[f>>2]=M,n[M+24>>2]=f,n[M+12>>2]=M,n[M+8>>2]=M;break}for(s=d<<((l|0)==31?0:25-(l>>>1)|0),c=n[f>>2]|0;;){if((n[c+4>>2]&-8|0)==(d|0)){Ue=194;break}if(f=c+16+(s>>>31<<2)|0,l=n[f>>2]|0,l)s=s<<1,c=l;else{Ue=193;break}}if((Ue|0)==193){n[f>>2]=M,n[M+24>>2]=c,n[M+12>>2]=M,n[M+8>>2]=M;break}else if((Ue|0)==194){Ue=c+8|0,Ge=n[Ue>>2]|0,n[Ge+12>>2]=M,n[Ue>>2]=M,n[M+8>>2]=Ge,n[M+12>>2]=c,n[M+24>>2]=0;break}}else Ge=(n[2786]|0)+k|0,n[2786]=Ge,n[2789]=M,n[M+4>>2]=Ge|1;while(0);return Ge=O+8|0,C=Nt,Ge|0}for(l=11580;s=n[l>>2]|0,!(s>>>0<=Q>>>0&&(Ge=s+(n[l+4>>2]|0)|0,Ge>>>0>Q>>>0));)l=n[l+8>>2]|0;d=Ge+-47|0,s=d+8|0,s=d+((s&7|0)==0?0:0-s&7)|0,d=Q+16|0,s=s>>>0<d>>>0?Q:s,l=s+8|0,c=m+8|0,c=(c&7|0)==0?0:0-c&7,Ue=m+c|0,c=B+-40-c|0,n[2789]=Ue,n[2786]=c,n[Ue+4>>2]=c|1,n[Ue+c+4>>2]=40,n[2790]=n[2905],c=s+4|0,n[c>>2]=27,n[l>>2]=n[2895],n[l+4>>2]=n[2896],n[l+8>>2]=n[2897],n[l+12>>2]=n[2898],n[2895]=m,n[2896]=B,n[2898]=0,n[2897]=l,l=s+24|0;do Ue=l,l=l+4|0,n[l>>2]=7;while((Ue+8|0)>>>0<Ge>>>0);if((s|0)!=(Q|0)){if(m=s-Q|0,n[c>>2]=n[c>>2]&-2,n[Q+4>>2]=m|1,n[s>>2]=m,l=m>>>3,m>>>0<256){c=11172+(l<<1<<2)|0,s=n[2783]|0,l=1<<l,s&l?(s=c+8|0,l=n[s>>2]|0):(n[2783]=s|l,l=c,s=c+8|0),n[s>>2]=Q,n[l+12>>2]=Q,n[Q+8>>2]=l,n[Q+12>>2]=c;break}if(l=m>>>8,l?m>>>0>16777215?c=31:(Ue=(l+1048320|0)>>>16&8,Ge=l<<Ue,lt=(Ge+520192|0)>>>16&4,Ge=Ge<<lt,c=(Ge+245760|0)>>>16&2,c=14-(lt|Ue|c)+(Ge<<c>>>15)|0,c=m>>>(c+7|0)&1|c<<1):c=0,f=11436+(c<<2)|0,n[Q+28>>2]=c,n[Q+20>>2]=0,n[d>>2]=0,l=n[2784]|0,s=1<<c,!(l&s)){n[2784]=l|s,n[f>>2]=Q,n[Q+24>>2]=f,n[Q+12>>2]=Q,n[Q+8>>2]=Q;break}for(s=m<<((c|0)==31?0:25-(c>>>1)|0),c=n[f>>2]|0;;){if((n[c+4>>2]&-8|0)==(m|0)){Ue=216;break}if(f=c+16+(s>>>31<<2)|0,l=n[f>>2]|0,l)s=s<<1,c=l;else{Ue=215;break}}if((Ue|0)==215){n[f>>2]=Q,n[Q+24>>2]=c,n[Q+12>>2]=Q,n[Q+8>>2]=Q;break}else if((Ue|0)==216){Ue=c+8|0,Ge=n[Ue>>2]|0,n[Ge+12>>2]=Q,n[Ue>>2]=Q,n[Q+8>>2]=Ge,n[Q+12>>2]=c,n[Q+24>>2]=0;break}}}else{Ge=n[2787]|0,(Ge|0)==0|m>>>0<Ge>>>0&&(n[2787]=m),n[2895]=m,n[2896]=B,n[2898]=0,n[2792]=n[2901],n[2791]=-1,l=0;do Ge=11172+(l<<1<<2)|0,n[Ge+12>>2]=Ge,n[Ge+8>>2]=Ge,l=l+1|0;while((l|0)!=32);Ge=m+8|0,Ge=(Ge&7|0)==0?0:0-Ge&7,Ue=m+Ge|0,Ge=B+-40-Ge|0,n[2789]=Ue,n[2786]=Ge,n[Ue+4>>2]=Ge|1,n[Ue+Ge+4>>2]=40,n[2790]=n[2905]}while(0);if(l=n[2786]|0,l>>>0>G>>>0)return lt=l-G|0,n[2786]=lt,Ge=n[2789]|0,Ue=Ge+G|0,n[2789]=Ue,n[Ue+4>>2]=lt|1,n[Ge+4>>2]=G|3,Ge=Ge+8|0,C=Nt,Ge|0}return n[(zm()|0)>>2]=12,Ge=0,C=Nt,Ge|0}function hD(s){s=s|0;var l=0,c=0,f=0,d=0,m=0,B=0,k=0,Q=0;if(!!s){c=s+-8|0,d=n[2787]|0,s=n[s+-4>>2]|0,l=s&-8,Q=c+l|0;do if(s&1)k=c,B=c;else{if(f=n[c>>2]|0,!(s&3)||(B=c+(0-f)|0,m=f+l|0,B>>>0<d>>>0))return;if((B|0)==(n[2788]|0)){if(s=Q+4|0,l=n[s>>2]|0,(l&3|0)!=3){k=B,l=m;break}n[2785]=m,n[s>>2]=l&-2,n[B+4>>2]=m|1,n[B+m>>2]=m;return}if(c=f>>>3,f>>>0<256)if(s=n[B+8>>2]|0,l=n[B+12>>2]|0,(l|0)==(s|0)){n[2783]=n[2783]&~(1<<c),k=B,l=m;break}else{n[s+12>>2]=l,n[l+8>>2]=s,k=B,l=m;break}d=n[B+24>>2]|0,s=n[B+12>>2]|0;do if((s|0)==(B|0)){if(c=B+16|0,l=c+4|0,s=n[l>>2]|0,!s)if(s=n[c>>2]|0,s)l=c;else{s=0;break}for(;;){if(c=s+20|0,f=n[c>>2]|0,f|0){s=f,l=c;continue}if(c=s+16|0,f=n[c>>2]|0,f)s=f,l=c;else break}n[l>>2]=0}else k=n[B+8>>2]|0,n[k+12>>2]=s,n[s+8>>2]=k;while(0);if(d){if(l=n[B+28>>2]|0,c=11436+(l<<2)|0,(B|0)==(n[c>>2]|0)){if(n[c>>2]=s,!s){n[2784]=n[2784]&~(1<<l),k=B,l=m;break}}else if(n[d+16+(((n[d+16>>2]|0)!=(B|0)&1)<<2)>>2]=s,!s){k=B,l=m;break}n[s+24>>2]=d,l=B+16|0,c=n[l>>2]|0,c|0&&(n[s+16>>2]=c,n[c+24>>2]=s),l=n[l+4>>2]|0,l?(n[s+20>>2]=l,n[l+24>>2]=s,k=B,l=m):(k=B,l=m)}else k=B,l=m}while(0);if(!(B>>>0>=Q>>>0)&&(s=Q+4|0,f=n[s>>2]|0,!!(f&1))){if(f&2)n[s>>2]=f&-2,n[k+4>>2]=l|1,n[B+l>>2]=l,d=l;else{if(s=n[2788]|0,(Q|0)==(n[2789]|0)){if(Q=(n[2786]|0)+l|0,n[2786]=Q,n[2789]=k,n[k+4>>2]=Q|1,(k|0)!=(s|0))return;n[2788]=0,n[2785]=0;return}if((Q|0)==(s|0)){Q=(n[2785]|0)+l|0,n[2785]=Q,n[2788]=B,n[k+4>>2]=Q|1,n[B+Q>>2]=Q;return}d=(f&-8)+l|0,c=f>>>3;do if(f>>>0<256)if(l=n[Q+8>>2]|0,s=n[Q+12>>2]|0,(s|0)==(l|0)){n[2783]=n[2783]&~(1<<c);break}else{n[l+12>>2]=s,n[s+8>>2]=l;break}else{m=n[Q+24>>2]|0,s=n[Q+12>>2]|0;do if((s|0)==(Q|0)){if(c=Q+16|0,l=c+4|0,s=n[l>>2]|0,!s)if(s=n[c>>2]|0,s)l=c;else{c=0;break}for(;;){if(c=s+20|0,f=n[c>>2]|0,f|0){s=f,l=c;continue}if(c=s+16|0,f=n[c>>2]|0,f)s=f,l=c;else break}n[l>>2]=0,c=s}else c=n[Q+8>>2]|0,n[c+12>>2]=s,n[s+8>>2]=c,c=s;while(0);if(m|0){if(s=n[Q+28>>2]|0,l=11436+(s<<2)|0,(Q|0)==(n[l>>2]|0)){if(n[l>>2]=c,!c){n[2784]=n[2784]&~(1<<s);break}}else if(n[m+16+(((n[m+16>>2]|0)!=(Q|0)&1)<<2)>>2]=c,!c)break;n[c+24>>2]=m,s=Q+16|0,l=n[s>>2]|0,l|0&&(n[c+16>>2]=l,n[l+24>>2]=c),s=n[s+4>>2]|0,s|0&&(n[c+20>>2]=s,n[s+24>>2]=c)}}while(0);if(n[k+4>>2]=d|1,n[B+d>>2]=d,(k|0)==(n[2788]|0)){n[2785]=d;return}}if(s=d>>>3,d>>>0<256){c=11172+(s<<1<<2)|0,l=n[2783]|0,s=1<<s,l&s?(l=c+8|0,s=n[l>>2]|0):(n[2783]=l|s,s=c,l=c+8|0),n[l>>2]=k,n[s+12>>2]=k,n[k+8>>2]=s,n[k+12>>2]=c;return}s=d>>>8,s?d>>>0>16777215?s=31:(B=(s+1048320|0)>>>16&8,Q=s<<B,m=(Q+520192|0)>>>16&4,Q=Q<<m,s=(Q+245760|0)>>>16&2,s=14-(m|B|s)+(Q<<s>>>15)|0,s=d>>>(s+7|0)&1|s<<1):s=0,f=11436+(s<<2)|0,n[k+28>>2]=s,n[k+20>>2]=0,n[k+16>>2]=0,l=n[2784]|0,c=1<<s;do if(l&c){for(l=d<<((s|0)==31?0:25-(s>>>1)|0),c=n[f>>2]|0;;){if((n[c+4>>2]&-8|0)==(d|0)){s=73;break}if(f=c+16+(l>>>31<<2)|0,s=n[f>>2]|0,s)l=l<<1,c=s;else{s=72;break}}if((s|0)==72){n[f>>2]=k,n[k+24>>2]=c,n[k+12>>2]=k,n[k+8>>2]=k;break}else if((s|0)==73){B=c+8|0,Q=n[B>>2]|0,n[Q+12>>2]=k,n[B>>2]=k,n[k+8>>2]=Q,n[k+12>>2]=c,n[k+24>>2]=0;break}}else n[2784]=l|c,n[f>>2]=k,n[k+24>>2]=f,n[k+12>>2]=k,n[k+8>>2]=k;while(0);if(Q=(n[2791]|0)+-1|0,n[2791]=Q,!Q)s=11588;else return;for(;s=n[s>>2]|0,s;)s=s+8|0;n[2791]=-1}}}function PUe(){return 11628}function SUe(s){s=s|0;var l=0,c=0;return l=C,C=C+16|0,c=l,n[c>>2]=kUe(n[s+60>>2]|0)|0,s=gD(gc(6,c|0)|0)|0,C=l,s|0}function r7(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0,je=0;G=C,C=C+48|0,M=G+16|0,m=G,d=G+32|0,k=s+28|0,f=n[k>>2]|0,n[d>>2]=f,Q=s+20|0,f=(n[Q>>2]|0)-f|0,n[d+4>>2]=f,n[d+8>>2]=l,n[d+12>>2]=c,f=f+c|0,B=s+60|0,n[m>>2]=n[B>>2],n[m+4>>2]=d,n[m+8>>2]=2,m=gD(Ni(146,m|0)|0)|0;e:do if((f|0)!=(m|0)){for(l=2;!((m|0)<0);)if(f=f-m|0,je=n[d+4>>2]|0,se=m>>>0>je>>>0,d=se?d+8|0:d,l=(se<<31>>31)+l|0,je=m-(se?je:0)|0,n[d>>2]=(n[d>>2]|0)+je,se=d+4|0,n[se>>2]=(n[se>>2]|0)-je,n[M>>2]=n[B>>2],n[M+4>>2]=d,n[M+8>>2]=l,m=gD(Ni(146,M|0)|0)|0,(f|0)==(m|0)){O=3;break e}n[s+16>>2]=0,n[k>>2]=0,n[Q>>2]=0,n[s>>2]=n[s>>2]|32,(l|0)==2?c=0:c=c-(n[d+4>>2]|0)|0}else O=3;while(0);return(O|0)==3&&(je=n[s+44>>2]|0,n[s+16>>2]=je+(n[s+48>>2]|0),n[k>>2]=je,n[Q>>2]=je),C=G,c|0}function bUe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;return d=C,C=C+32|0,m=d,f=d+20|0,n[m>>2]=n[s+60>>2],n[m+4>>2]=0,n[m+8>>2]=l,n[m+12>>2]=f,n[m+16>>2]=c,(gD(sa(140,m|0)|0)|0)<0?(n[f>>2]=-1,s=-1):s=n[f>>2]|0,C=d,s|0}function gD(s){return s=s|0,s>>>0>4294963200&&(n[(zm()|0)>>2]=0-s,s=-1),s|0}function zm(){return(xUe()|0)+64|0}function xUe(){return PR()|0}function PR(){return 2084}function kUe(s){return s=s|0,s|0}function QUe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;return d=C,C=C+32|0,f=d,n[s+36>>2]=1,(n[s>>2]&64|0)==0&&(n[f>>2]=n[s+60>>2],n[f+4>>2]=21523,n[f+8>>2]=d+16,pu(54,f|0)|0)&&(o[s+75>>0]=-1),f=r7(s,l,c)|0,C=d,f|0}function n7(s,l){s=s|0,l=l|0;var c=0,f=0;if(c=o[s>>0]|0,f=o[l>>0]|0,c<<24>>24==0||c<<24>>24!=f<<24>>24)s=f;else{do s=s+1|0,l=l+1|0,c=o[s>>0]|0,f=o[l>>0]|0;while(!(c<<24>>24==0||c<<24>>24!=f<<24>>24));s=f}return(c&255)-(s&255)|0}function FUe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0;e:do if(!c)s=0;else{for(;f=o[s>>0]|0,d=o[l>>0]|0,f<<24>>24==d<<24>>24;)if(c=c+-1|0,c)s=s+1|0,l=l+1|0;else{s=0;break e}s=(f&255)-(d&255)|0}while(0);return s|0}function i7(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0,je=0,Me=0,Qe=0;Qe=C,C=C+224|0,O=Qe+120|0,G=Qe+80|0,je=Qe,Me=Qe+136|0,f=G,d=f+40|0;do n[f>>2]=0,f=f+4|0;while((f|0)<(d|0));return n[O>>2]=n[c>>2],(SR(0,l,O,je,G)|0)<0?c=-1:((n[s+76>>2]|0)>-1?se=RUe(s)|0:se=0,c=n[s>>2]|0,M=c&32,(o[s+74>>0]|0)<1&&(n[s>>2]=c&-33),f=s+48|0,n[f>>2]|0?c=SR(s,l,O,je,G)|0:(d=s+44|0,m=n[d>>2]|0,n[d>>2]=Me,B=s+28|0,n[B>>2]=Me,k=s+20|0,n[k>>2]=Me,n[f>>2]=80,Q=s+16|0,n[Q>>2]=Me+80,c=SR(s,l,O,je,G)|0,m&&(ED[n[s+36>>2]&7](s,0,0)|0,c=(n[k>>2]|0)==0?-1:c,n[d>>2]=m,n[f>>2]=0,n[Q>>2]=0,n[B>>2]=0,n[k>>2]=0)),f=n[s>>2]|0,n[s>>2]=f|M,se|0&&TUe(s),c=(f&32|0)==0?c:-1),C=Qe,c|0}function SR(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0,je=0,Me=0,Qe=0,et=0,Xe=0,lt=0,Ue=0,Ge=0,Nt=0,Mr=0,ar=0,Xt=0,Pr=0,Lr=0,sr=0;sr=C,C=C+64|0,ar=sr+16|0,Xt=sr,Nt=sr+24|0,Pr=sr+8|0,Lr=sr+20|0,n[ar>>2]=l,lt=(s|0)!=0,Ue=Nt+40|0,Ge=Ue,Nt=Nt+39|0,Mr=Pr+4|0,B=0,m=0,O=0;e:for(;;){do if((m|0)>-1)if((B|0)>(2147483647-m|0)){n[(zm()|0)>>2]=75,m=-1;break}else{m=B+m|0;break}while(0);if(B=o[l>>0]|0,B<<24>>24)k=l;else{Xe=87;break}t:for(;;){switch(B<<24>>24){case 37:{B=k,Xe=9;break t}case 0:{B=k;break t}default:}et=k+1|0,n[ar>>2]=et,B=o[et>>0]|0,k=et}t:do if((Xe|0)==9)for(;;){if(Xe=0,(o[k+1>>0]|0)!=37)break t;if(B=B+1|0,k=k+2|0,n[ar>>2]=k,(o[k>>0]|0)==37)Xe=9;else break}while(0);if(B=B-l|0,lt&&ss(s,l,B),B|0){l=k;continue}Q=k+1|0,B=(o[Q>>0]|0)+-48|0,B>>>0<10?(et=(o[k+2>>0]|0)==36,Qe=et?B:-1,O=et?1:O,Q=et?k+3|0:Q):Qe=-1,n[ar>>2]=Q,B=o[Q>>0]|0,k=(B<<24>>24)+-32|0;t:do if(k>>>0<32)for(M=0,G=B;;){if(B=1<<k,!(B&75913)){B=G;break t}if(M=B|M,Q=Q+1|0,n[ar>>2]=Q,B=o[Q>>0]|0,k=(B<<24>>24)+-32|0,k>>>0>=32)break;G=B}else M=0;while(0);if(B<<24>>24==42){if(k=Q+1|0,B=(o[k>>0]|0)+-48|0,B>>>0<10&&(o[Q+2>>0]|0)==36)n[d+(B<<2)>>2]=10,B=n[f+((o[k>>0]|0)+-48<<3)>>2]|0,O=1,Q=Q+3|0;else{if(O|0){m=-1;break}lt?(O=(n[c>>2]|0)+(4-1)&~(4-1),B=n[O>>2]|0,n[c>>2]=O+4,O=0,Q=k):(B=0,O=0,Q=k)}n[ar>>2]=Q,et=(B|0)<0,B=et?0-B|0:B,M=et?M|8192:M}else{if(B=s7(ar)|0,(B|0)<0){m=-1;break}Q=n[ar>>2]|0}do if((o[Q>>0]|0)==46){if((o[Q+1>>0]|0)!=42){n[ar>>2]=Q+1,k=s7(ar)|0,Q=n[ar>>2]|0;break}if(G=Q+2|0,k=(o[G>>0]|0)+-48|0,k>>>0<10&&(o[Q+3>>0]|0)==36){n[d+(k<<2)>>2]=10,k=n[f+((o[G>>0]|0)+-48<<3)>>2]|0,Q=Q+4|0,n[ar>>2]=Q;break}if(O|0){m=-1;break e}lt?(et=(n[c>>2]|0)+(4-1)&~(4-1),k=n[et>>2]|0,n[c>>2]=et+4):k=0,n[ar>>2]=G,Q=G}else k=-1;while(0);for(Me=0;;){if(((o[Q>>0]|0)+-65|0)>>>0>57){m=-1;break e}if(et=Q+1|0,n[ar>>2]=et,G=o[(o[Q>>0]|0)+-65+(5178+(Me*58|0))>>0]|0,se=G&255,(se+-1|0)>>>0<8)Me=se,Q=et;else break}if(!(G<<24>>24)){m=-1;break}je=(Qe|0)>-1;do if(G<<24>>24==19)if(je){m=-1;break e}else Xe=49;else{if(je){n[d+(Qe<<2)>>2]=se,je=f+(Qe<<3)|0,Qe=n[je+4>>2]|0,Xe=Xt,n[Xe>>2]=n[je>>2],n[Xe+4>>2]=Qe,Xe=49;break}if(!lt){m=0;break e}o7(Xt,se,c)}while(0);if((Xe|0)==49&&(Xe=0,!lt)){B=0,l=et;continue}Q=o[Q>>0]|0,Q=(Me|0)!=0&(Q&15|0)==3?Q&-33:Q,je=M&-65537,Qe=(M&8192|0)==0?M:je;t:do switch(Q|0){case 110:switch((Me&255)<<24>>24){case 0:{n[n[Xt>>2]>>2]=m,B=0,l=et;continue e}case 1:{n[n[Xt>>2]>>2]=m,B=0,l=et;continue e}case 2:{B=n[Xt>>2]|0,n[B>>2]=m,n[B+4>>2]=((m|0)<0)<<31>>31,B=0,l=et;continue e}case 3:{a[n[Xt>>2]>>1]=m,B=0,l=et;continue e}case 4:{o[n[Xt>>2]>>0]=m,B=0,l=et;continue e}case 6:{n[n[Xt>>2]>>2]=m,B=0,l=et;continue e}case 7:{B=n[Xt>>2]|0,n[B>>2]=m,n[B+4>>2]=((m|0)<0)<<31>>31,B=0,l=et;continue e}default:{B=0,l=et;continue e}}case 112:{Q=120,k=k>>>0>8?k:8,l=Qe|8,Xe=61;break}case 88:case 120:{l=Qe,Xe=61;break}case 111:{Q=Xt,l=n[Q>>2]|0,Q=n[Q+4>>2]|0,se=NUe(l,Q,Ue)|0,je=Ge-se|0,M=0,G=5642,k=(Qe&8|0)==0|(k|0)>(je|0)?k:je+1|0,je=Qe,Xe=67;break}case 105:case 100:if(Q=Xt,l=n[Q>>2]|0,Q=n[Q+4>>2]|0,(Q|0)<0){l=dD(0,0,l|0,Q|0)|0,Q=Pe,M=Xt,n[M>>2]=l,n[M+4>>2]=Q,M=1,G=5642,Xe=66;break t}else{M=(Qe&2049|0)!=0&1,G=(Qe&2048|0)==0?(Qe&1|0)==0?5642:5644:5643,Xe=66;break t}case 117:{Q=Xt,M=0,G=5642,l=n[Q>>2]|0,Q=n[Q+4>>2]|0,Xe=66;break}case 99:{o[Nt>>0]=n[Xt>>2],l=Nt,M=0,G=5642,se=Ue,Q=1,k=je;break}case 109:{Q=OUe(n[(zm()|0)>>2]|0)|0,Xe=71;break}case 115:{Q=n[Xt>>2]|0,Q=Q|0?Q:5652,Xe=71;break}case 67:{n[Pr>>2]=n[Xt>>2],n[Mr>>2]=0,n[Xt>>2]=Pr,se=-1,Q=Pr,Xe=75;break}case 83:{l=n[Xt>>2]|0,k?(se=k,Q=l,Xe=75):(Bs(s,32,B,0,Qe),l=0,Xe=84);break}case 65:case 71:case 70:case 69:case 97:case 103:case 102:case 101:{B=UUe(s,+E[Xt>>3],B,k,Qe,Q)|0,l=et;continue e}default:M=0,G=5642,se=Ue,Q=k,k=Qe}while(0);t:do if((Xe|0)==61)Qe=Xt,Me=n[Qe>>2]|0,Qe=n[Qe+4>>2]|0,se=LUe(Me,Qe,Ue,Q&32)|0,G=(l&8|0)==0|(Me|0)==0&(Qe|0)==0,M=G?0:2,G=G?5642:5642+(Q>>4)|0,je=l,l=Me,Q=Qe,Xe=67;else if((Xe|0)==66)se=Vm(l,Q,Ue)|0,je=Qe,Xe=67;else if((Xe|0)==71)Xe=0,Qe=MUe(Q,0,k)|0,Me=(Qe|0)==0,l=Q,M=0,G=5642,se=Me?Q+k|0:Qe,Q=Me?k:Qe-Q|0,k=je;else if((Xe|0)==75){for(Xe=0,G=Q,l=0,k=0;M=n[G>>2]|0,!(!M||(k=a7(Lr,M)|0,(k|0)<0|k>>>0>(se-l|0)>>>0));)if(l=k+l|0,se>>>0>l>>>0)G=G+4|0;else break;if((k|0)<0){m=-1;break e}if(Bs(s,32,B,l,Qe),!l)l=0,Xe=84;else for(M=0;;){if(k=n[Q>>2]|0,!k){Xe=84;break t}if(k=a7(Lr,k)|0,M=k+M|0,(M|0)>(l|0)){Xe=84;break t}if(ss(s,Lr,k),M>>>0>=l>>>0){Xe=84;break}else Q=Q+4|0}}while(0);if((Xe|0)==67)Xe=0,Q=(l|0)!=0|(Q|0)!=0,Qe=(k|0)!=0|Q,Q=((Q^1)&1)+(Ge-se)|0,l=Qe?se:Ue,se=Ue,Q=Qe?(k|0)>(Q|0)?k:Q:k,k=(k|0)>-1?je&-65537:je;else if((Xe|0)==84){Xe=0,Bs(s,32,B,l,Qe^8192),B=(B|0)>(l|0)?B:l,l=et;continue}Me=se-l|0,je=(Q|0)<(Me|0)?Me:Q,Qe=je+M|0,B=(B|0)<(Qe|0)?Qe:B,Bs(s,32,B,Qe,k),ss(s,G,M),Bs(s,48,B,Qe,k^65536),Bs(s,48,je,Me,0),ss(s,l,Me),Bs(s,32,B,Qe,k^8192),l=et}e:do if((Xe|0)==87&&!s)if(!O)m=0;else{for(m=1;l=n[d+(m<<2)>>2]|0,!!l;)if(o7(f+(m<<3)|0,l,c),m=m+1|0,(m|0)>=10){m=1;break e}for(;;){if(n[d+(m<<2)>>2]|0){m=-1;break e}if(m=m+1|0,(m|0)>=10){m=1;break}}}while(0);return C=sr,m|0}function RUe(s){return s=s|0,0}function TUe(s){s=s|0}function ss(s,l,c){s=s|0,l=l|0,c=c|0,n[s>>2]&32||zUe(l,c,s)|0}function s7(s){s=s|0;var l=0,c=0,f=0;if(c=n[s>>2]|0,f=(o[c>>0]|0)+-48|0,f>>>0<10){l=0;do l=f+(l*10|0)|0,c=c+1|0,n[s>>2]=c,f=(o[c>>0]|0)+-48|0;while(f>>>0<10)}else l=0;return l|0}function o7(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;e:do if(l>>>0<=20)do switch(l|0){case 9:{f=(n[c>>2]|0)+(4-1)&~(4-1),l=n[f>>2]|0,n[c>>2]=f+4,n[s>>2]=l;break e}case 10:{f=(n[c>>2]|0)+(4-1)&~(4-1),l=n[f>>2]|0,n[c>>2]=f+4,f=s,n[f>>2]=l,n[f+4>>2]=((l|0)<0)<<31>>31;break e}case 11:{f=(n[c>>2]|0)+(4-1)&~(4-1),l=n[f>>2]|0,n[c>>2]=f+4,f=s,n[f>>2]=l,n[f+4>>2]=0;break e}case 12:{f=(n[c>>2]|0)+(8-1)&~(8-1),l=f,d=n[l>>2]|0,l=n[l+4>>2]|0,n[c>>2]=f+8,f=s,n[f>>2]=d,n[f+4>>2]=l;break e}case 13:{d=(n[c>>2]|0)+(4-1)&~(4-1),f=n[d>>2]|0,n[c>>2]=d+4,f=(f&65535)<<16>>16,d=s,n[d>>2]=f,n[d+4>>2]=((f|0)<0)<<31>>31;break e}case 14:{d=(n[c>>2]|0)+(4-1)&~(4-1),f=n[d>>2]|0,n[c>>2]=d+4,d=s,n[d>>2]=f&65535,n[d+4>>2]=0;break e}case 15:{d=(n[c>>2]|0)+(4-1)&~(4-1),f=n[d>>2]|0,n[c>>2]=d+4,f=(f&255)<<24>>24,d=s,n[d>>2]=f,n[d+4>>2]=((f|0)<0)<<31>>31;break e}case 16:{d=(n[c>>2]|0)+(4-1)&~(4-1),f=n[d>>2]|0,n[c>>2]=d+4,d=s,n[d>>2]=f&255,n[d+4>>2]=0;break e}case 17:{d=(n[c>>2]|0)+(8-1)&~(8-1),m=+E[d>>3],n[c>>2]=d+8,E[s>>3]=m;break e}case 18:{d=(n[c>>2]|0)+(8-1)&~(8-1),m=+E[d>>3],n[c>>2]=d+8,E[s>>3]=m;break e}default:break e}while(0);while(0)}function LUe(s,l,c,f){if(s=s|0,l=l|0,c=c|0,f=f|0,!((s|0)==0&(l|0)==0))do c=c+-1|0,o[c>>0]=u[5694+(s&15)>>0]|0|f,s=mD(s|0,l|0,4)|0,l=Pe;while(!((s|0)==0&(l|0)==0));return c|0}function NUe(s,l,c){if(s=s|0,l=l|0,c=c|0,!((s|0)==0&(l|0)==0))do c=c+-1|0,o[c>>0]=s&7|48,s=mD(s|0,l|0,3)|0,l=Pe;while(!((s|0)==0&(l|0)==0));return c|0}function Vm(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;if(l>>>0>0|(l|0)==0&s>>>0>4294967295){for(;f=QR(s|0,l|0,10,0)|0,c=c+-1|0,o[c>>0]=f&255|48,f=s,s=kR(s|0,l|0,10,0)|0,l>>>0>9|(l|0)==9&f>>>0>4294967295;)l=Pe;l=s}else l=s;if(l)for(;c=c+-1|0,o[c>>0]=(l>>>0)%10|0|48,!(l>>>0<10);)l=(l>>>0)/10|0;return c|0}function OUe(s){return s=s|0,jUe(s,n[(GUe()|0)+188>>2]|0)|0}function MUe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;m=l&255,f=(c|0)!=0;e:do if(f&(s&3|0)!=0)for(d=l&255;;){if((o[s>>0]|0)==d<<24>>24){B=6;break e}if(s=s+1|0,c=c+-1|0,f=(c|0)!=0,!(f&(s&3|0)!=0)){B=5;break}}else B=5;while(0);(B|0)==5&&(f?B=6:c=0);e:do if((B|0)==6&&(d=l&255,(o[s>>0]|0)!=d<<24>>24)){f=qe(m,16843009)|0;t:do if(c>>>0>3){for(;m=n[s>>2]^f,!((m&-2139062144^-2139062144)&m+-16843009|0);)if(s=s+4|0,c=c+-4|0,c>>>0<=3){B=11;break t}}else B=11;while(0);if((B|0)==11&&!c){c=0;break}for(;;){if((o[s>>0]|0)==d<<24>>24)break e;if(s=s+1|0,c=c+-1|0,!c){c=0;break}}}while(0);return(c|0?s:0)|0}function Bs(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0;if(B=C,C=C+256|0,m=B,(c|0)>(f|0)&(d&73728|0)==0){if(d=c-f|0,Xm(m|0,l|0,(d>>>0<256?d:256)|0)|0,d>>>0>255){l=c-f|0;do ss(s,m,256),d=d+-256|0;while(d>>>0>255);d=l&255}ss(s,m,d)}C=B}function a7(s,l){return s=s|0,l=l|0,s?s=HUe(s,l,0)|0:s=0,s|0}function UUe(s,l,c,f,d,m){s=s|0,l=+l,c=c|0,f=f|0,d=d|0,m=m|0;var B=0,k=0,Q=0,M=0,O=0,G=0,se=0,je=0,Me=0,Qe=0,et=0,Xe=0,lt=0,Ue=0,Ge=0,Nt=0,Mr=0,ar=0,Xt=0,Pr=0,Lr=0,sr=0,xn=0;xn=C,C=C+560|0,Q=xn+8|0,et=xn,sr=xn+524|0,Lr=sr,M=xn+512|0,n[et>>2]=0,Pr=M+12|0,l7(l)|0,(Pe|0)<0?(l=-l,ar=1,Mr=5659):(ar=(d&2049|0)!=0&1,Mr=(d&2048|0)==0?(d&1|0)==0?5660:5665:5662),l7(l)|0,Xt=Pe&2146435072;do if(Xt>>>0<2146435072|(Xt|0)==2146435072&0<0){if(je=+_Ue(l,et)*2,B=je!=0,B&&(n[et>>2]=(n[et>>2]|0)+-1),lt=m|32,(lt|0)==97){Me=m&32,se=(Me|0)==0?Mr:Mr+9|0,G=ar|2,B=12-f|0;do if(f>>>0>11|(B|0)==0)l=je;else{l=8;do B=B+-1|0,l=l*16;while((B|0)!=0);if((o[se>>0]|0)==45){l=-(l+(-je-l));break}else{l=je+l-l;break}}while(0);k=n[et>>2]|0,B=(k|0)<0?0-k|0:k,B=Vm(B,((B|0)<0)<<31>>31,Pr)|0,(B|0)==(Pr|0)&&(B=M+11|0,o[B>>0]=48),o[B+-1>>0]=(k>>31&2)+43,O=B+-2|0,o[O>>0]=m+15,M=(f|0)<1,Q=(d&8|0)==0,B=sr;do Xt=~~l,k=B+1|0,o[B>>0]=u[5694+Xt>>0]|Me,l=(l-+(Xt|0))*16,(k-Lr|0)==1&&!(Q&(M&l==0))?(o[k>>0]=46,B=B+2|0):B=k;while(l!=0);Xt=B-Lr|0,Lr=Pr-O|0,Pr=(f|0)!=0&(Xt+-2|0)<(f|0)?f+2|0:Xt,B=Lr+G+Pr|0,Bs(s,32,c,B,d),ss(s,se,G),Bs(s,48,c,B,d^65536),ss(s,sr,Xt),Bs(s,48,Pr-Xt|0,0,0),ss(s,O,Lr),Bs(s,32,c,B,d^8192);break}k=(f|0)<0?6:f,B?(B=(n[et>>2]|0)+-28|0,n[et>>2]=B,l=je*268435456):(l=je,B=n[et>>2]|0),Xt=(B|0)<0?Q:Q+288|0,Q=Xt;do Ge=~~l>>>0,n[Q>>2]=Ge,Q=Q+4|0,l=(l-+(Ge>>>0))*1e9;while(l!=0);if((B|0)>0)for(M=Xt,G=Q;;){if(O=(B|0)<29?B:29,B=G+-4|0,B>>>0>=M>>>0){Q=0;do Ue=h7(n[B>>2]|0,0,O|0)|0,Ue=xR(Ue|0,Pe|0,Q|0,0)|0,Ge=Pe,Xe=QR(Ue|0,Ge|0,1e9,0)|0,n[B>>2]=Xe,Q=kR(Ue|0,Ge|0,1e9,0)|0,B=B+-4|0;while(B>>>0>=M>>>0);Q&&(M=M+-4|0,n[M>>2]=Q)}for(Q=G;!(Q>>>0<=M>>>0);)if(B=Q+-4|0,!(n[B>>2]|0))Q=B;else break;if(B=(n[et>>2]|0)-O|0,n[et>>2]=B,(B|0)>0)G=Q;else break}else M=Xt;if((B|0)<0){f=((k+25|0)/9|0)+1|0,Qe=(lt|0)==102;do{if(Me=0-B|0,Me=(Me|0)<9?Me:9,M>>>0<Q>>>0){O=(1<<Me)+-1|0,G=1e9>>>Me,se=0,B=M;do Ge=n[B>>2]|0,n[B>>2]=(Ge>>>Me)+se,se=qe(Ge&O,G)|0,B=B+4|0;while(B>>>0<Q>>>0);B=(n[M>>2]|0)==0?M+4|0:M,se?(n[Q>>2]=se,M=B,B=Q+4|0):(M=B,B=Q)}else M=(n[M>>2]|0)==0?M+4|0:M,B=Q;Q=Qe?Xt:M,Q=(B-Q>>2|0)>(f|0)?Q+(f<<2)|0:B,B=(n[et>>2]|0)+Me|0,n[et>>2]=B}while((B|0)<0);B=M,f=Q}else B=M,f=Q;if(Ge=Xt,B>>>0<f>>>0){if(Q=(Ge-B>>2)*9|0,O=n[B>>2]|0,O>>>0>=10){M=10;do M=M*10|0,Q=Q+1|0;while(O>>>0>=M>>>0)}}else Q=0;if(Qe=(lt|0)==103,Xe=(k|0)!=0,M=k-((lt|0)!=102?Q:0)+((Xe&Qe)<<31>>31)|0,(M|0)<(((f-Ge>>2)*9|0)+-9|0)){if(M=M+9216|0,Me=Xt+4+(((M|0)/9|0)+-1024<<2)|0,M=((M|0)%9|0)+1|0,(M|0)<9){O=10;do O=O*10|0,M=M+1|0;while((M|0)!=9)}else O=10;if(G=n[Me>>2]|0,se=(G>>>0)%(O>>>0)|0,M=(Me+4|0)==(f|0),M&(se|0)==0)M=Me;else if(je=(((G>>>0)/(O>>>0)|0)&1|0)==0?9007199254740992:9007199254740994,Ue=(O|0)/2|0,l=se>>>0<Ue>>>0?.5:M&(se|0)==(Ue|0)?1:1.5,ar&&(Ue=(o[Mr>>0]|0)==45,l=Ue?-l:l,je=Ue?-je:je),M=G-se|0,n[Me>>2]=M,je+l!=je){if(Ue=M+O|0,n[Me>>2]=Ue,Ue>>>0>999999999)for(Q=Me;M=Q+-4|0,n[Q>>2]=0,M>>>0<B>>>0&&(B=B+-4|0,n[B>>2]=0),Ue=(n[M>>2]|0)+1|0,n[M>>2]=Ue,Ue>>>0>999999999;)Q=M;else M=Me;if(Q=(Ge-B>>2)*9|0,G=n[B>>2]|0,G>>>0>=10){O=10;do O=O*10|0,Q=Q+1|0;while(G>>>0>=O>>>0)}}else M=Me;M=M+4|0,M=f>>>0>M>>>0?M:f,Ue=B}else M=f,Ue=B;for(lt=M;;){if(lt>>>0<=Ue>>>0){et=0;break}if(B=lt+-4|0,!(n[B>>2]|0))lt=B;else{et=1;break}}f=0-Q|0;do if(Qe)if(B=((Xe^1)&1)+k|0,(B|0)>(Q|0)&(Q|0)>-5?(O=m+-1|0,k=B+-1-Q|0):(O=m+-2|0,k=B+-1|0),B=d&8,B)Me=B;else{if(et&&(Nt=n[lt+-4>>2]|0,(Nt|0)!=0))if((Nt>>>0)%10|0)M=0;else{M=0,B=10;do B=B*10|0,M=M+1|0;while(!((Nt>>>0)%(B>>>0)|0|0))}else M=9;if(B=((lt-Ge>>2)*9|0)+-9|0,(O|32|0)==102){Me=B-M|0,Me=(Me|0)>0?Me:0,k=(k|0)<(Me|0)?k:Me,Me=0;break}else{Me=B+Q-M|0,Me=(Me|0)>0?Me:0,k=(k|0)<(Me|0)?k:Me,Me=0;break}}else O=m,Me=d&8;while(0);if(Qe=k|Me,G=(Qe|0)!=0&1,se=(O|32|0)==102,se)Xe=0,B=(Q|0)>0?Q:0;else{if(B=(Q|0)<0?f:Q,B=Vm(B,((B|0)<0)<<31>>31,Pr)|0,M=Pr,(M-B|0)<2)do B=B+-1|0,o[B>>0]=48;while((M-B|0)<2);o[B+-1>>0]=(Q>>31&2)+43,B=B+-2|0,o[B>>0]=O,Xe=B,B=M-B|0}if(B=ar+1+k+G+B|0,Bs(s,32,c,B,d),ss(s,Mr,ar),Bs(s,48,c,B,d^65536),se){O=Ue>>>0>Xt>>>0?Xt:Ue,Me=sr+9|0,G=Me,se=sr+8|0,M=O;do{if(Q=Vm(n[M>>2]|0,0,Me)|0,(M|0)==(O|0))(Q|0)==(Me|0)&&(o[se>>0]=48,Q=se);else if(Q>>>0>sr>>>0){Xm(sr|0,48,Q-Lr|0)|0;do Q=Q+-1|0;while(Q>>>0>sr>>>0)}ss(s,Q,G-Q|0),M=M+4|0}while(M>>>0<=Xt>>>0);if(Qe|0&&ss(s,5710,1),M>>>0<lt>>>0&(k|0)>0)for(;;){if(Q=Vm(n[M>>2]|0,0,Me)|0,Q>>>0>sr>>>0){Xm(sr|0,48,Q-Lr|0)|0;do Q=Q+-1|0;while(Q>>>0>sr>>>0)}if(ss(s,Q,(k|0)<9?k:9),M=M+4|0,Q=k+-9|0,M>>>0<lt>>>0&(k|0)>9)k=Q;else{k=Q;break}}Bs(s,48,k+9|0,9,0)}else{if(Qe=et?lt:Ue+4|0,(k|0)>-1){et=sr+9|0,Me=(Me|0)==0,f=et,G=0-Lr|0,se=sr+8|0,O=Ue;do{Q=Vm(n[O>>2]|0,0,et)|0,(Q|0)==(et|0)&&(o[se>>0]=48,Q=se);do if((O|0)==(Ue|0)){if(M=Q+1|0,ss(s,Q,1),Me&(k|0)<1){Q=M;break}ss(s,5710,1),Q=M}else{if(Q>>>0<=sr>>>0)break;Xm(sr|0,48,Q+G|0)|0;do Q=Q+-1|0;while(Q>>>0>sr>>>0)}while(0);Lr=f-Q|0,ss(s,Q,(k|0)>(Lr|0)?Lr:k),k=k-Lr|0,O=O+4|0}while(O>>>0<Qe>>>0&(k|0)>-1)}Bs(s,48,k+18|0,18,0),ss(s,Xe,Pr-Xe|0)}Bs(s,32,c,B,d^8192)}else sr=(m&32|0)!=0,B=ar+3|0,Bs(s,32,c,B,d&-65537),ss(s,Mr,ar),ss(s,l!=l|!1?sr?5686:5690:sr?5678:5682,3),Bs(s,32,c,B,d^8192);while(0);return C=xn,((B|0)<(c|0)?c:B)|0}function l7(s){s=+s;var l=0;return E[v>>3]=s,l=n[v>>2]|0,Pe=n[v+4>>2]|0,l|0}function _Ue(s,l){return s=+s,l=l|0,+ +c7(s,l)}function c7(s,l){s=+s,l=l|0;var c=0,f=0,d=0;switch(E[v>>3]=s,c=n[v>>2]|0,f=n[v+4>>2]|0,d=mD(c|0,f|0,52)|0,d&2047){case 0:{s!=0?(s=+c7(s*18446744073709552e3,l),c=(n[l>>2]|0)+-64|0):c=0,n[l>>2]=c;break}case 2047:break;default:n[l>>2]=(d&2047)+-1022,n[v>>2]=c,n[v+4>>2]=f&-2146435073|1071644672,s=+E[v>>3]}return+s}function HUe(s,l,c){s=s|0,l=l|0,c=c|0;do if(s){if(l>>>0<128){o[s>>0]=l,s=1;break}if(!(n[n[(qUe()|0)+188>>2]>>2]|0))if((l&-128|0)==57216){o[s>>0]=l,s=1;break}else{n[(zm()|0)>>2]=84,s=-1;break}if(l>>>0<2048){o[s>>0]=l>>>6|192,o[s+1>>0]=l&63|128,s=2;break}if(l>>>0<55296|(l&-8192|0)==57344){o[s>>0]=l>>>12|224,o[s+1>>0]=l>>>6&63|128,o[s+2>>0]=l&63|128,s=3;break}if((l+-65536|0)>>>0<1048576){o[s>>0]=l>>>18|240,o[s+1>>0]=l>>>12&63|128,o[s+2>>0]=l>>>6&63|128,o[s+3>>0]=l&63|128,s=4;break}else{n[(zm()|0)>>2]=84,s=-1;break}}else s=1;while(0);return s|0}function qUe(){return PR()|0}function GUe(){return PR()|0}function jUe(s,l){s=s|0,l=l|0;var c=0,f=0;for(f=0;;){if((u[5712+f>>0]|0)==(s|0)){s=2;break}if(c=f+1|0,(c|0)==87){c=5800,f=87,s=5;break}else f=c}if((s|0)==2&&(f?(c=5800,s=5):c=5800),(s|0)==5)for(;;){do s=c,c=c+1|0;while((o[s>>0]|0)!=0);if(f=f+-1|0,f)s=5;else break}return YUe(c,n[l+20>>2]|0)|0}function YUe(s,l){return s=s|0,l=l|0,WUe(s,l)|0}function WUe(s,l){return s=s|0,l=l|0,l?l=KUe(n[l>>2]|0,n[l+4>>2]|0,s)|0:l=0,(l|0?l:s)|0}function KUe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0;se=(n[s>>2]|0)+1794895138|0,m=Tg(n[s+8>>2]|0,se)|0,f=Tg(n[s+12>>2]|0,se)|0,d=Tg(n[s+16>>2]|0,se)|0;e:do if(m>>>0<l>>>2>>>0&&(G=l-(m<<2)|0,f>>>0<G>>>0&d>>>0<G>>>0)&&((d|f)&3|0)==0){for(G=f>>>2,O=d>>>2,M=0;;){if(k=m>>>1,Q=M+k|0,B=Q<<1,d=B+G|0,f=Tg(n[s+(d<<2)>>2]|0,se)|0,d=Tg(n[s+(d+1<<2)>>2]|0,se)|0,!(d>>>0<l>>>0&f>>>0<(l-d|0)>>>0)){f=0;break e}if(o[s+(d+f)>>0]|0){f=0;break e}if(f=n7(c,s+d|0)|0,!f)break;if(f=(f|0)<0,(m|0)==1){f=0;break e}else M=f?M:Q,m=f?k:m-k|0}f=B+O|0,d=Tg(n[s+(f<<2)>>2]|0,se)|0,f=Tg(n[s+(f+1<<2)>>2]|0,se)|0,f>>>0<l>>>0&d>>>0<(l-f|0)>>>0?f=(o[s+(f+d)>>0]|0)==0?s+f|0:0:f=0}else f=0;while(0);return f|0}function Tg(s,l){s=s|0,l=l|0;var c=0;return c=m7(s|0)|0,((l|0)==0?s:c)|0}function zUe(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0,k=0;f=c+16|0,d=n[f>>2]|0,d?m=5:VUe(c)|0?f=0:(d=n[f>>2]|0,m=5);e:do if((m|0)==5){if(k=c+20|0,B=n[k>>2]|0,f=B,(d-B|0)>>>0<l>>>0){f=ED[n[c+36>>2]&7](c,s,l)|0;break}t:do if((o[c+75>>0]|0)>-1){for(B=l;;){if(!B){m=0,d=s;break t}if(d=B+-1|0,(o[s+d>>0]|0)==10)break;B=d}if(f=ED[n[c+36>>2]&7](c,s,B)|0,f>>>0<B>>>0)break e;m=B,d=s+B|0,l=l-B|0,f=n[k>>2]|0}else m=0,d=s;while(0);Dr(f|0,d|0,l|0)|0,n[k>>2]=(n[k>>2]|0)+l,f=m+l|0}while(0);return f|0}function VUe(s){s=s|0;var l=0,c=0;return l=s+74|0,c=o[l>>0]|0,o[l>>0]=c+255|c,l=n[s>>2]|0,l&8?(n[s>>2]=l|32,s=-1):(n[s+8>>2]=0,n[s+4>>2]=0,c=n[s+44>>2]|0,n[s+28>>2]=c,n[s+20>>2]=c,n[s+16>>2]=c+(n[s+48>>2]|0),s=0),s|0}function _n(s,l){s=y(s),l=y(l);var c=0,f=0;c=u7(s)|0;do if((c&2147483647)>>>0<=2139095040){if(f=u7(l)|0,(f&2147483647)>>>0<=2139095040)if((f^c|0)<0){s=(c|0)<0?l:s;break}else{s=s<l?l:s;break}}else s=l;while(0);return y(s)}function u7(s){return s=y(s),h[v>>2]=s,n[v>>2]|0|0}function Lg(s,l){s=y(s),l=y(l);var c=0,f=0;c=A7(s)|0;do if((c&2147483647)>>>0<=2139095040){if(f=A7(l)|0,(f&2147483647)>>>0<=2139095040)if((f^c|0)<0){s=(c|0)<0?s:l;break}else{s=s<l?s:l;break}}else s=l;while(0);return y(s)}function A7(s){return s=y(s),h[v>>2]=s,n[v>>2]|0|0}function bR(s,l){s=y(s),l=y(l);var c=0,f=0,d=0,m=0,B=0,k=0,Q=0,M=0;m=(h[v>>2]=s,n[v>>2]|0),k=(h[v>>2]=l,n[v>>2]|0),c=m>>>23&255,B=k>>>23&255,Q=m&-2147483648,d=k<<1;e:do if((d|0)!=0&&!((c|0)==255|((JUe(l)|0)&2147483647)>>>0>2139095040)){if(f=m<<1,f>>>0<=d>>>0)return l=y(s*y(0)),y((f|0)==(d|0)?l:s);if(c)f=m&8388607|8388608;else{if(c=m<<9,(c|0)>-1){f=c,c=0;do c=c+-1|0,f=f<<1;while((f|0)>-1)}else c=0;f=m<<1-c}if(B)k=k&8388607|8388608;else{if(m=k<<9,(m|0)>-1){d=0;do d=d+-1|0,m=m<<1;while((m|0)>-1)}else d=0;B=d,k=k<<1-d}d=f-k|0,m=(d|0)>-1;t:do if((c|0)>(B|0)){for(;;){if(m)if(d)f=d;else break;if(f=f<<1,c=c+-1|0,d=f-k|0,m=(d|0)>-1,(c|0)<=(B|0))break t}l=y(s*y(0));break e}while(0);if(m)if(d)f=d;else{l=y(s*y(0));break}if(f>>>0<8388608)do f=f<<1,c=c+-1|0;while(f>>>0<8388608);(c|0)>0?c=f+-8388608|c<<23:c=f>>>(1-c|0),l=(n[v>>2]=c|Q,y(h[v>>2]))}else M=3;while(0);return(M|0)==3&&(l=y(s*l),l=y(l/l)),y(l)}function JUe(s){return s=y(s),h[v>>2]=s,n[v>>2]|0|0}function XUe(s,l){return s=s|0,l=l|0,i7(n[582]|0,s,l)|0}function Jr(s){s=s|0,Rt()}function Jm(s){s=s|0}function ZUe(s,l){return s=s|0,l=l|0,0}function $Ue(s){return s=s|0,(f7(s+4|0)|0)==-1?(tf[n[(n[s>>2]|0)+8>>2]&127](s),s=1):s=0,s|0}function f7(s){s=s|0;var l=0;return l=n[s>>2]|0,n[s>>2]=l+-1,l+-1|0}function Qp(s){s=s|0,$Ue(s)|0&&e3e(s)}function e3e(s){s=s|0;var l=0;l=s+8|0,(n[l>>2]|0)!=0&&(f7(l)|0)!=-1||tf[n[(n[s>>2]|0)+16>>2]&127](s)}function Kt(s){s=s|0;var l=0;for(l=(s|0)==0?1:s;s=pD(l)|0,!(s|0);){if(s=r3e()|0,!s){s=0;break}S7[s&0]()}return s|0}function p7(s){return s=s|0,Kt(s)|0}function gt(s){s=s|0,hD(s)}function t3e(s){s=s|0,(o[s+11>>0]|0)<0&&gt(n[s>>2]|0)}function r3e(){var s=0;return s=n[2923]|0,n[2923]=s+0,s|0}function n3e(){}function dD(s,l,c,f){return s=s|0,l=l|0,c=c|0,f=f|0,f=l-f-(c>>>0>s>>>0|0)>>>0,Pe=f,s-c>>>0|0|0}function xR(s,l,c,f){return s=s|0,l=l|0,c=c|0,f=f|0,c=s+c>>>0,Pe=l+f+(c>>>0<s>>>0|0)>>>0,c|0|0}function Xm(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0,B=0;if(m=s+c|0,l=l&255,(c|0)>=67){for(;s&3;)o[s>>0]=l,s=s+1|0;for(f=m&-4|0,d=f-64|0,B=l|l<<8|l<<16|l<<24;(s|0)<=(d|0);)n[s>>2]=B,n[s+4>>2]=B,n[s+8>>2]=B,n[s+12>>2]=B,n[s+16>>2]=B,n[s+20>>2]=B,n[s+24>>2]=B,n[s+28>>2]=B,n[s+32>>2]=B,n[s+36>>2]=B,n[s+40>>2]=B,n[s+44>>2]=B,n[s+48>>2]=B,n[s+52>>2]=B,n[s+56>>2]=B,n[s+60>>2]=B,s=s+64|0;for(;(s|0)<(f|0);)n[s>>2]=B,s=s+4|0}for(;(s|0)<(m|0);)o[s>>0]=l,s=s+1|0;return m-c|0}function h7(s,l,c){return s=s|0,l=l|0,c=c|0,(c|0)<32?(Pe=l<<c|(s&(1<<c)-1<<32-c)>>>32-c,s<<c):(Pe=s<<c-32,0)}function mD(s,l,c){return s=s|0,l=l|0,c=c|0,(c|0)<32?(Pe=l>>>c,s>>>c|(l&(1<<c)-1)<<32-c):(Pe=0,l>>>c-32|0)}function Dr(s,l,c){s=s|0,l=l|0,c=c|0;var f=0,d=0,m=0;if((c|0)>=8192)return fc(s|0,l|0,c|0)|0;if(m=s|0,d=s+c|0,(s&3)==(l&3)){for(;s&3;){if(!c)return m|0;o[s>>0]=o[l>>0]|0,s=s+1|0,l=l+1|0,c=c-1|0}for(c=d&-4|0,f=c-64|0;(s|0)<=(f|0);)n[s>>2]=n[l>>2],n[s+4>>2]=n[l+4>>2],n[s+8>>2]=n[l+8>>2],n[s+12>>2]=n[l+12>>2],n[s+16>>2]=n[l+16>>2],n[s+20>>2]=n[l+20>>2],n[s+24>>2]=n[l+24>>2],n[s+28>>2]=n[l+28>>2],n[s+32>>2]=n[l+32>>2],n[s+36>>2]=n[l+36>>2],n[s+40>>2]=n[l+40>>2],n[s+44>>2]=n[l+44>>2],n[s+48>>2]=n[l+48>>2],n[s+52>>2]=n[l+52>>2],n[s+56>>2]=n[l+56>>2],n[s+60>>2]=n[l+60>>2],s=s+64|0,l=l+64|0;for(;(s|0)<(c|0);)n[s>>2]=n[l>>2],s=s+4|0,l=l+4|0}else for(c=d-4|0;(s|0)<(c|0);)o[s>>0]=o[l>>0]|0,o[s+1>>0]=o[l+1>>0]|0,o[s+2>>0]=o[l+2>>0]|0,o[s+3>>0]=o[l+3>>0]|0,s=s+4|0,l=l+4|0;for(;(s|0)<(d|0);)o[s>>0]=o[l>>0]|0,s=s+1|0,l=l+1|0;return m|0}function g7(s){s=s|0;var l=0;return l=o[N+(s&255)>>0]|0,(l|0)<8?l|0:(l=o[N+(s>>8&255)>>0]|0,(l|0)<8?l+8|0:(l=o[N+(s>>16&255)>>0]|0,(l|0)<8?l+16|0:(o[N+(s>>>24)>>0]|0)+24|0))}function d7(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0;var m=0,B=0,k=0,Q=0,M=0,O=0,G=0,se=0,je=0,Me=0;if(O=s,Q=l,M=Q,B=c,se=f,k=se,!M)return m=(d|0)!=0,k?m?(n[d>>2]=s|0,n[d+4>>2]=l&0,se=0,d=0,Pe=se,d|0):(se=0,d=0,Pe=se,d|0):(m&&(n[d>>2]=(O>>>0)%(B>>>0),n[d+4>>2]=0),se=0,d=(O>>>0)/(B>>>0)>>>0,Pe=se,d|0);m=(k|0)==0;do if(B){if(!m){if(m=(S(k|0)|0)-(S(M|0)|0)|0,m>>>0<=31){G=m+1|0,k=31-m|0,l=m-31>>31,B=G,s=O>>>(G>>>0)&l|M<<k,l=M>>>(G>>>0)&l,m=0,k=O<<k;break}return d?(n[d>>2]=s|0,n[d+4>>2]=Q|l&0,se=0,d=0,Pe=se,d|0):(se=0,d=0,Pe=se,d|0)}if(m=B-1|0,m&B|0){k=(S(B|0)|0)+33-(S(M|0)|0)|0,Me=64-k|0,G=32-k|0,Q=G>>31,je=k-32|0,l=je>>31,B=k,s=G-1>>31&M>>>(je>>>0)|(M<<G|O>>>(k>>>0))&l,l=l&M>>>(k>>>0),m=O<<Me&Q,k=(M<<Me|O>>>(je>>>0))&Q|O<<G&k-33>>31;break}return d|0&&(n[d>>2]=m&O,n[d+4>>2]=0),(B|0)==1?(je=Q|l&0,Me=s|0|0,Pe=je,Me|0):(Me=g7(B|0)|0,je=M>>>(Me>>>0)|0,Me=M<<32-Me|O>>>(Me>>>0)|0,Pe=je,Me|0)}else{if(m)return d|0&&(n[d>>2]=(M>>>0)%(B>>>0),n[d+4>>2]=0),je=0,Me=(M>>>0)/(B>>>0)>>>0,Pe=je,Me|0;if(!O)return d|0&&(n[d>>2]=0,n[d+4>>2]=(M>>>0)%(k>>>0)),je=0,Me=(M>>>0)/(k>>>0)>>>0,Pe=je,Me|0;if(m=k-1|0,!(m&k))return d|0&&(n[d>>2]=s|0,n[d+4>>2]=m&M|l&0),je=0,Me=M>>>((g7(k|0)|0)>>>0),Pe=je,Me|0;if(m=(S(k|0)|0)-(S(M|0)|0)|0,m>>>0<=30){l=m+1|0,k=31-m|0,B=l,s=M<<k|O>>>(l>>>0),l=M>>>(l>>>0),m=0,k=O<<k;break}return d?(n[d>>2]=s|0,n[d+4>>2]=Q|l&0,je=0,Me=0,Pe=je,Me|0):(je=0,Me=0,Pe=je,Me|0)}while(0);if(!B)M=k,Q=0,k=0;else{G=c|0|0,O=se|f&0,M=xR(G|0,O|0,-1,-1)|0,c=Pe,Q=k,k=0;do f=Q,Q=m>>>31|Q<<1,m=k|m<<1,f=s<<1|f>>>31|0,se=s>>>31|l<<1|0,dD(M|0,c|0,f|0,se|0)|0,Me=Pe,je=Me>>31|((Me|0)<0?-1:0)<<1,k=je&1,s=dD(f|0,se|0,je&G|0,(((Me|0)<0?-1:0)>>31|((Me|0)<0?-1:0)<<1)&O|0)|0,l=Pe,B=B-1|0;while((B|0)!=0);M=Q,Q=0}return B=0,d|0&&(n[d>>2]=s,n[d+4>>2]=l),je=(m|0)>>>31|(M|B)<<1|(B<<1|m>>>31)&0|Q,Me=(m<<1|0>>>31)&-2|k,Pe=je,Me|0}function kR(s,l,c,f){return s=s|0,l=l|0,c=c|0,f=f|0,d7(s,l,c,f,0)|0}function Fp(s){s=s|0;var l=0,c=0;return c=s+15&-16|0,l=n[I>>2]|0,s=l+c|0,(c|0)>0&(s|0)<(l|0)|(s|0)<0?(ie()|0,DA(12),-1):(n[I>>2]=s,(s|0)>(Z()|0)&&(X()|0)==0?(n[I>>2]=l,DA(12),-1):l|0)}function Mw(s,l,c){s=s|0,l=l|0,c=c|0;var f=0;if((l|0)<(s|0)&(s|0)<(l+c|0)){for(f=s,l=l+c|0,s=s+c|0;(c|0)>0;)s=s-1|0,l=l-1|0,c=c-1|0,o[s>>0]=o[l>>0]|0;s=f}else Dr(s,l,c)|0;return s|0}function QR(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0;var d=0,m=0;return m=C,C=C+16|0,d=m|0,d7(s,l,c,f,d)|0,C=m,Pe=n[d+4>>2]|0,n[d>>2]|0|0}function m7(s){return s=s|0,(s&255)<<24|(s>>8&255)<<16|(s>>16&255)<<8|s>>>24|0}function i3e(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,y7[s&1](l|0,c|0,f|0,d|0,m|0)}function s3e(s,l,c){s=s|0,l=l|0,c=y(c),E7[s&1](l|0,y(c))}function o3e(s,l,c){s=s|0,l=l|0,c=+c,C7[s&31](l|0,+c)}function a3e(s,l,c,f){return s=s|0,l=l|0,c=y(c),f=y(f),y(w7[s&0](l|0,y(c),y(f)))}function l3e(s,l){s=s|0,l=l|0,tf[s&127](l|0)}function c3e(s,l,c){s=s|0,l=l|0,c=c|0,rf[s&31](l|0,c|0)}function u3e(s,l){return s=s|0,l=l|0,Og[s&31](l|0)|0}function A3e(s,l,c,f,d){s=s|0,l=l|0,c=+c,f=+f,d=d|0,I7[s&1](l|0,+c,+f,d|0)}function f3e(s,l,c,f){s=s|0,l=l|0,c=+c,f=+f,W3e[s&1](l|0,+c,+f)}function p3e(s,l,c,f){return s=s|0,l=l|0,c=c|0,f=f|0,ED[s&7](l|0,c|0,f|0)|0}function h3e(s,l,c,f){return s=s|0,l=l|0,c=c|0,f=f|0,+K3e[s&1](l|0,c|0,f|0)}function g3e(s,l){return s=s|0,l=l|0,+B7[s&15](l|0)}function d3e(s,l,c){return s=s|0,l=l|0,c=+c,z3e[s&1](l|0,+c)|0}function m3e(s,l,c){return s=s|0,l=l|0,c=c|0,RR[s&15](l|0,c|0)|0}function y3e(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=+f,d=+d,m=m|0,V3e[s&1](l|0,c|0,+f,+d,m|0)}function E3e(s,l,c,f,d,m,B){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,B=B|0,J3e[s&1](l|0,c|0,f|0,d|0,m|0,B|0)}function C3e(s,l,c){return s=s|0,l=l|0,c=c|0,+v7[s&7](l|0,c|0)}function w3e(s){return s=s|0,CD[s&7]()|0}function I3e(s,l,c,f,d,m){return s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,D7[s&1](l|0,c|0,f|0,d|0,m|0)|0}function B3e(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=+d,X3e[s&1](l|0,c|0,f|0,+d)}function v3e(s,l,c,f,d,m,B){s=s|0,l=l|0,c=c|0,f=y(f),d=d|0,m=y(m),B=B|0,P7[s&1](l|0,c|0,y(f),d|0,y(m),B|0)}function D3e(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,Hw[s&15](l|0,c|0,f|0)}function P3e(s){s=s|0,S7[s&0]()}function S3e(s,l,c,f){s=s|0,l=l|0,c=c|0,f=+f,b7[s&15](l|0,c|0,+f)}function b3e(s,l,c){return s=s|0,l=+l,c=+c,Z3e[s&1](+l,+c)|0}function x3e(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,TR[s&15](l|0,c|0,f|0,d|0)}function k3e(s,l,c,f,d){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,F(0)}function Q3e(s,l){s=s|0,l=y(l),F(1)}function ma(s,l){s=s|0,l=+l,F(2)}function F3e(s,l,c){return s=s|0,l=y(l),c=y(c),F(3),Ze}function Er(s){s=s|0,F(4)}function Uw(s,l){s=s|0,l=l|0,F(5)}function Ja(s){return s=s|0,F(6),0}function R3e(s,l,c,f){s=s|0,l=+l,c=+c,f=f|0,F(7)}function T3e(s,l,c){s=s|0,l=+l,c=+c,F(8)}function L3e(s,l,c){return s=s|0,l=l|0,c=c|0,F(9),0}function N3e(s,l,c){return s=s|0,l=l|0,c=c|0,F(10),0}function Ng(s){return s=s|0,F(11),0}function O3e(s,l){return s=s|0,l=+l,F(12),0}function _w(s,l){return s=s|0,l=l|0,F(13),0}function M3e(s,l,c,f,d){s=s|0,l=l|0,c=+c,f=+f,d=d|0,F(14)}function U3e(s,l,c,f,d,m){s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,m=m|0,F(15)}function FR(s,l){return s=s|0,l=l|0,F(16),0}function _3e(){return F(17),0}function H3e(s,l,c,f,d){return s=s|0,l=l|0,c=c|0,f=f|0,d=d|0,F(18),0}function q3e(s,l,c,f){s=s|0,l=l|0,c=c|0,f=+f,F(19)}function G3e(s,l,c,f,d,m){s=s|0,l=l|0,c=y(c),f=f|0,d=y(d),m=m|0,F(20)}function yD(s,l,c){s=s|0,l=l|0,c=c|0,F(21)}function j3e(){F(22)}function Zm(s,l,c){s=s|0,l=l|0,c=+c,F(23)}function Y3e(s,l){return s=+s,l=+l,F(24),0}function $m(s,l,c,f){s=s|0,l=l|0,c=c|0,f=f|0,F(25)}var y7=[k3e,HNe],E7=[Q3e,fo],C7=[ma,xw,kw,EF,CF,Pl,Qw,wF,qm,xu,Rw,IF,$v,KA,eD,Gm,tD,rD,jm,ma,ma,ma,ma,ma,ma,ma,ma,ma,ma,ma,ma,ma],w7=[F3e],tf=[Er,Jm,wDe,IDe,BDe,Zbe,$be,exe,dLe,mLe,yLe,bNe,xNe,kNe,J4e,X4e,Z4e,hs,zv,Hm,WA,Fw,mve,yve,ADe,QDe,GDe,aPe,BPe,_Pe,nSe,ySe,RSe,VSe,Abe,Sbe,Gbe,mxe,Rxe,Vxe,Ake,Ske,Gke,lQe,BQe,OQe,$Qe,bc,kFe,WFe,ARe,xRe,jRe,ATe,wTe,vTe,HTe,jTe,aLe,CLe,BLe,_Le,iNe,i9,UOe,dMe,QMe,WMe,h4e,x4e,_4e,G4e,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er,Er],rf=[Uw,fF,pF,bw,bu,hF,gF,vp,dF,mF,yF,Zv,zA,ze,ft,Wt,vr,Sn,Fr,vF,ive,Sve,fQe,PQe,RRe,qOe,fNe,q5,Uw,Uw,Uw,Uw],Og=[Ja,SUe,AF,D,Ae,De,vt,wt,xt,_r,di,po,tve,rve,Eve,rFe,zRe,GLe,WOe,Ka,Ja,Ja,Ja,Ja,Ja,Ja,Ja,Ja,Ja,Ja,Ja,Ja],I7=[R3e,Cve],W3e=[T3e,uLe],ED=[L3e,r7,bUe,QUe,jPe,wxe,TFe,JMe],K3e=[N3e,gbe],B7=[Ng,Yo,rt,bn,wve,Ive,Bve,vve,Dve,Pve,Ng,Ng,Ng,Ng,Ng,Ng],z3e=[O3e,yTe],RR=[_w,ZUe,nve,gDe,APe,oSe,wSe,Kbe,Oxe,HQe,Wv,LMe,_w,_w,_w,_w],V3e=[M3e,KDe],J3e=[U3e,y4e],v7=[FR,ai,bve,xve,kve,Qbe,FR,FR],CD=[_3e,Qve,Pw,ga,bTe,zTe,SLe,K4e],D7=[H3e,Cw],X3e=[q3e,gke],P7=[G3e,sve],Hw=[yD,T,is,tn,ho,SPe,NSe,Qke,Kke,_m,uOe,CMe,R4e,yD,yD,yD],S7=[j3e],b7=[Zm,Vv,Jv,Xv,YA,nD,BF,P,$xe,JFe,hTe,Zm,Zm,Zm,Zm,Zm],Z3e=[Y3e,hLe],TR=[$m,$Se,uFe,gRe,nTe,TTe,eLe,TLe,cNe,ZOe,iUe,$m,$m,$m,$m,$m];return{_llvm_bswap_i32:m7,dynCall_idd:b3e,dynCall_i:w3e,_i64Subtract:dD,___udivdi3:kR,dynCall_vif:s3e,setThrew:gu,dynCall_viii:D3e,_bitshift64Lshr:mD,_bitshift64Shl:h7,dynCall_vi:l3e,dynCall_viiddi:y3e,dynCall_diii:h3e,dynCall_iii:m3e,_memset:Xm,_sbrk:Fp,_memcpy:Dr,__GLOBAL__sub_I_Yoga_cpp:Um,dynCall_vii:c3e,___uremdi3:QR,dynCall_vid:o3e,stackAlloc:lo,_nbind_init:gUe,getTempRet0:Ha,dynCall_di:g3e,dynCall_iid:d3e,setTempRet0:xA,_i64Add:xR,dynCall_fiff:a3e,dynCall_iiii:p3e,_emscripten_get_global_libc:PUe,dynCall_viid:S3e,dynCall_viiid:B3e,dynCall_viififi:v3e,dynCall_ii:u3e,__GLOBAL__sub_I_Binding_cc:QOe,dynCall_viiii:x3e,dynCall_iiiiii:I3e,stackSave:dc,dynCall_viiiii:i3e,__GLOBAL__sub_I_nbind_cc:Fve,dynCall_vidd:f3e,_free:hD,runPostSets:n3e,dynCall_viiiiii:E3e,establishStackSpace:qi,_memmove:Mw,stackRestore:hu,_malloc:pD,__GLOBAL__sub_I_common_cc:XLe,dynCall_viddi:A3e,dynCall_dii:C3e,dynCall_v:P3e}}(Module.asmGlobalArg,Module.asmLibraryArg,buffer),_llvm_bswap_i32=Module._llvm_bswap_i32=asm._llvm_bswap_i32,getTempRet0=Module.getTempRet0=asm.getTempRet0,___udivdi3=Module.___udivdi3=asm.___udivdi3,setThrew=Module.setThrew=asm.setThrew,_bitshift64Lshr=Module._bitshift64Lshr=asm._bitshift64Lshr,_bitshift64Shl=Module._bitshift64Shl=asm._bitshift64Shl,_memset=Module._memset=asm._memset,_sbrk=Module._sbrk=asm._sbrk,_memcpy=Module._memcpy=asm._memcpy,stackAlloc=Module.stackAlloc=asm.stackAlloc,___uremdi3=Module.___uremdi3=asm.___uremdi3,_nbind_init=Module._nbind_init=asm._nbind_init,_i64Subtract=Module._i64Subtract=asm._i64Subtract,setTempRet0=Module.setTempRet0=asm.setTempRet0,_i64Add=Module._i64Add=asm._i64Add,_emscripten_get_global_libc=Module._emscripten_get_global_libc=asm._emscripten_get_global_libc,__GLOBAL__sub_I_Yoga_cpp=Module.__GLOBAL__sub_I_Yoga_cpp=asm.__GLOBAL__sub_I_Yoga_cpp,__GLOBAL__sub_I_Binding_cc=Module.__GLOBAL__sub_I_Binding_cc=asm.__GLOBAL__sub_I_Binding_cc,stackSave=Module.stackSave=asm.stackSave,__GLOBAL__sub_I_nbind_cc=Module.__GLOBAL__sub_I_nbind_cc=asm.__GLOBAL__sub_I_nbind_cc,_free=Module._free=asm._free,runPostSets=Module.runPostSets=asm.runPostSets,establishStackSpace=Module.establishStackSpace=asm.establishStackSpace,_memmove=Module._memmove=asm._memmove,stackRestore=Module.stackRestore=asm.stackRestore,_malloc=Module._malloc=asm._malloc,__GLOBAL__sub_I_common_cc=Module.__GLOBAL__sub_I_common_cc=asm.__GLOBAL__sub_I_common_cc,dynCall_viiiii=Module.dynCall_viiiii=asm.dynCall_viiiii,dynCall_vif=Module.dynCall_vif=asm.dynCall_vif,dynCall_vid=Module.dynCall_vid=asm.dynCall_vid,dynCall_fiff=Module.dynCall_fiff=asm.dynCall_fiff,dynCall_vi=Module.dynCall_vi=asm.dynCall_vi,dynCall_vii=Module.dynCall_vii=asm.dynCall_vii,dynCall_ii=Module.dynCall_ii=asm.dynCall_ii,dynCall_viddi=Module.dynCall_viddi=asm.dynCall_viddi,dynCall_vidd=Module.dynCall_vidd=asm.dynCall_vidd,dynCall_iiii=Module.dynCall_iiii=asm.dynCall_iiii,dynCall_diii=Module.dynCall_diii=asm.dynCall_diii,dynCall_di=Module.dynCall_di=asm.dynCall_di,dynCall_iid=Module.dynCall_iid=asm.dynCall_iid,dynCall_iii=Module.dynCall_iii=asm.dynCall_iii,dynCall_viiddi=Module.dynCall_viiddi=asm.dynCall_viiddi,dynCall_viiiiii=Module.dynCall_viiiiii=asm.dynCall_viiiiii,dynCall_dii=Module.dynCall_dii=asm.dynCall_dii,dynCall_i=Module.dynCall_i=asm.dynCall_i,dynCall_iiiiii=Module.dynCall_iiiiii=asm.dynCall_iiiiii,dynCall_viiid=Module.dynCall_viiid=asm.dynCall_viiid,dynCall_viififi=Module.dynCall_viififi=asm.dynCall_viififi,dynCall_viii=Module.dynCall_viii=asm.dynCall_viii,dynCall_v=Module.dynCall_v=asm.dynCall_v,dynCall_viid=Module.dynCall_viid=asm.dynCall_viid,dynCall_idd=Module.dynCall_idd=asm.dynCall_idd,dynCall_viiii=Module.dynCall_viiii=asm.dynCall_viiii;Runtime.stackAlloc=Module.stackAlloc,Runtime.stackSave=Module.stackSave,Runtime.stackRestore=Module.stackRestore,Runtime.establishStackSpace=Module.establishStackSpace,Runtime.setTempRet0=Module.setTempRet0,Runtime.getTempRet0=Module.getTempRet0,Module.asm=asm;function ExitStatus(t){this.name=\"ExitStatus\",this.message=\"Program terminated with exit(\"+t+\")\",this.status=t}ExitStatus.prototype=new Error,ExitStatus.prototype.constructor=ExitStatus;var initialStackTop,preloadStartTime=null,calledMain=!1;dependenciesFulfilled=function t(){Module.calledRun||run(),Module.calledRun||(dependenciesFulfilled=t)},Module.callMain=Module.callMain=function t(e){e=e||[],ensureInitRuntime();var r=e.length+1;function o(){for(var p=0;p<4-1;p++)a.push(0)}var a=[allocate(intArrayFromString(Module.thisProgram),\"i8\",ALLOC_NORMAL)];o();for(var n=0;n<r-1;n=n+1)a.push(allocate(intArrayFromString(e[n]),\"i8\",ALLOC_NORMAL)),o();a.push(0),a=allocate(a,\"i32\",ALLOC_NORMAL);try{var u=Module._main(r,a,0);exit(u,!0)}catch(p){if(p instanceof ExitStatus)return;if(p==\"SimulateInfiniteLoop\"){Module.noExitRuntime=!0;return}else{var A=p;p&&typeof p==\"object\"&&p.stack&&(A=[p,p.stack]),Module.printErr(\"exception thrown: \"+A),Module.quit(1,p)}}finally{calledMain=!0}};function run(t){if(t=t||Module.arguments,preloadStartTime===null&&(preloadStartTime=Date.now()),runDependencies>0||(preRun(),runDependencies>0)||Module.calledRun)return;function e(){Module.calledRun||(Module.calledRun=!0,!ABORT&&(ensureInitRuntime(),preMain(),Module.onRuntimeInitialized&&Module.onRuntimeInitialized(),Module._main&&shouldRunNow&&Module.callMain(t),postRun()))}Module.setStatus?(Module.setStatus(\"Running...\"),setTimeout(function(){setTimeout(function(){Module.setStatus(\"\")},1),e()},1)):e()}Module.run=Module.run=run;function exit(t,e){e&&Module.noExitRuntime||(Module.noExitRuntime||(ABORT=!0,EXITSTATUS=t,STACKTOP=initialStackTop,exitRuntime(),Module.onExit&&Module.onExit(t)),ENVIRONMENT_IS_NODE&&process.exit(t),Module.quit(t,new ExitStatus(t)))}Module.exit=Module.exit=exit;var abortDecorators=[];function abort(t){Module.onAbort&&Module.onAbort(t),t!==void 0?(Module.print(t),Module.printErr(t),t=JSON.stringify(t)):t=\"\",ABORT=!0,EXITSTATUS=1;var e=`\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.`,r=\"abort(\"+t+\") at \"+stackTrace()+e;throw abortDecorators&&abortDecorators.forEach(function(o){r=o(r,t)}),r}if(Module.abort=Module.abort=abort,Module.preInit)for(typeof Module.preInit==\"function\"&&(Module.preInit=[Module.preInit]);Module.preInit.length>0;)Module.preInit.pop()();var shouldRunNow=!0;Module.noInitialRun&&(shouldRunNow=!1),run()})});var lm=_((IKt,NEe)=>{\"use strict\";var Yyt=TEe(),Wyt=LEe(),x6=!1,k6=null;Wyt({},function(t,e){if(!x6){if(x6=!0,t)throw t;k6=e}});if(!x6)throw new Error(\"Failed to load the yoga module - it needed to be loaded synchronously, but didn't\");NEe.exports=Yyt(k6.bind,k6.lib)});var F6=_((BKt,Q6)=>{\"use strict\";var OEe=t=>Number.isNaN(t)?!1:t>=4352&&(t<=4447||t===9001||t===9002||11904<=t&&t<=12871&&t!==12351||12880<=t&&t<=19903||19968<=t&&t<=42182||43360<=t&&t<=43388||44032<=t&&t<=55203||63744<=t&&t<=64255||65040<=t&&t<=65049||65072<=t&&t<=65131||65281<=t&&t<=65376||65504<=t&&t<=65510||110592<=t&&t<=110593||127488<=t&&t<=127569||131072<=t&&t<=262141);Q6.exports=OEe;Q6.exports.default=OEe});var UEe=_((vKt,MEe)=>{\"use strict\";MEe.exports=function(){return/\\uD83C\\uDFF4\\uDB40\\uDC67\\uDB40\\uDC62(?:\\uDB40\\uDC65\\uDB40\\uDC6E\\uDB40\\uDC67|\\uDB40\\uDC73\\uDB40\\uDC63\\uDB40\\uDC74|\\uDB40\\uDC77\\uDB40\\uDC6C\\uDB40\\uDC73)\\uDB40\\uDC7F|\\uD83D\\uDC68(?:\\uD83C\\uDFFC\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68\\uD83C\\uDFFB|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C\\uDFFF\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68(?:\\uD83C[\\uDFFB-\\uDFFE])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C\\uDFFE\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68(?:\\uD83C[\\uDFFB-\\uDFFD])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C\\uDFFD\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68(?:\\uD83C[\\uDFFB\\uDFFC])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\u200D(?:\\u2764\\uFE0F\\u200D(?:\\uD83D\\uDC8B\\u200D)?\\uD83D\\uDC68|(?:\\uD83D[\\uDC68\\uDC69])\\u200D(?:\\uD83D\\uDC66\\u200D\\uD83D\\uDC66|\\uD83D\\uDC67\\u200D(?:\\uD83D[\\uDC66\\uDC67]))|\\uD83D\\uDC66\\u200D\\uD83D\\uDC66|\\uD83D\\uDC67\\u200D(?:\\uD83D[\\uDC66\\uDC67])|(?:\\uD83D[\\uDC68\\uDC69])\\u200D(?:\\uD83D[\\uDC66\\uDC67])|[\\u2695\\u2696\\u2708]\\uFE0F|\\uD83D[\\uDC66\\uDC67]|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|(?:\\uD83C\\uDFFB\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFF\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFE\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFD\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFC\\u200D[\\u2695\\u2696\\u2708])\\uFE0F|\\uD83C\\uDFFB\\u200D(?:\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C[\\uDFFB-\\uDFFF])|(?:\\uD83E\\uDDD1\\uD83C\\uDFFB\\u200D\\uD83E\\uDD1D\\u200D\\uD83E\\uDDD1|\\uD83D\\uDC69\\uD83C\\uDFFC\\u200D\\uD83E\\uDD1D\\u200D\\uD83D\\uDC69)\\uD83C\\uDFFB|\\uD83E\\uDDD1(?:\\uD83C\\uDFFF\\u200D\\uD83E\\uDD1D\\u200D\\uD83E\\uDDD1(?:\\uD83C[\\uDFFB-\\uDFFF])|\\u200D\\uD83E\\uDD1D\\u200D\\uD83E\\uDDD1)|(?:\\uD83E\\uDDD1\\uD83C\\uDFFE\\u200D\\uD83E\\uDD1D\\u200D\\uD83E\\uDDD1|\\uD83D\\uDC69\\uD83C\\uDFFF\\u200D\\uD83E\\uDD1D\\u200D(?:\\uD83D[\\uDC68\\uDC69]))(?:\\uD83C[\\uDFFB-\\uDFFE])|(?:\\uD83E\\uDDD1\\uD83C\\uDFFC\\u200D\\uD83E\\uDD1D\\u200D\\uD83E\\uDDD1|\\uD83D\\uDC69\\uD83C\\uDFFD\\u200D\\uD83E\\uDD1D\\u200D\\uD83D\\uDC69)(?:\\uD83C[\\uDFFB\\uDFFC])|\\uD83D\\uDC69(?:\\uD83C\\uDFFE\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68(?:\\uD83C[\\uDFFB-\\uDFFD\\uDFFF])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C\\uDFFC\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68(?:\\uD83C[\\uDFFB\\uDFFD-\\uDFFF])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C\\uDFFB\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68(?:\\uD83C[\\uDFFC-\\uDFFF])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C\\uDFFD\\u200D(?:\\uD83E\\uDD1D\\u200D\\uD83D\\uDC68(?:\\uD83C[\\uDFFB\\uDFFC\\uDFFE\\uDFFF])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\u200D(?:\\u2764\\uFE0F\\u200D(?:\\uD83D\\uDC8B\\u200D(?:\\uD83D[\\uDC68\\uDC69])|\\uD83D[\\uDC68\\uDC69])|\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD])|\\uD83C\\uDFFF\\u200D(?:\\uD83C[\\uDF3E\\uDF73\\uDF93\\uDFA4\\uDFA8\\uDFEB\\uDFED]|\\uD83D[\\uDCBB\\uDCBC\\uDD27\\uDD2C\\uDE80\\uDE92]|\\uD83E[\\uDDAF-\\uDDB3\\uDDBC\\uDDBD]))|\\uD83D\\uDC69\\u200D\\uD83D\\uDC69\\u200D(?:\\uD83D\\uDC66\\u200D\\uD83D\\uDC66|\\uD83D\\uDC67\\u200D(?:\\uD83D[\\uDC66\\uDC67]))|(?:\\uD83E\\uDDD1\\uD83C\\uDFFD\\u200D\\uD83E\\uDD1D\\u200D\\uD83E\\uDDD1|\\uD83D\\uDC69\\uD83C\\uDFFE\\u200D\\uD83E\\uDD1D\\u200D\\uD83D\\uDC69)(?:\\uD83C[\\uDFFB-\\uDFFD])|\\uD83D\\uDC69\\u200D\\uD83D\\uDC66\\u200D\\uD83D\\uDC66|\\uD83D\\uDC69\\u200D\\uD83D\\uDC69\\u200D(?:\\uD83D[\\uDC66\\uDC67])|(?:\\uD83D\\uDC41\\uFE0F\\u200D\\uD83D\\uDDE8|\\uD83D\\uDC69(?:\\uD83C\\uDFFF\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFE\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFC\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFB\\u200D[\\u2695\\u2696\\u2708]|\\uD83C\\uDFFD\\u200D[\\u2695\\u2696\\u2708]|\\u200D[\\u2695\\u2696\\u2708])|(?:(?:\\u26F9|\\uD83C[\\uDFCB\\uDFCC]|\\uD83D\\uDD75)\\uFE0F|\\uD83D\\uDC6F|\\uD83E[\\uDD3C\\uDDDE\\uDDDF])\\u200D[\\u2640\\u2642]|(?:\\u26F9|\\uD83C[\\uDFCB\\uDFCC]|\\uD83D\\uDD75)(?:\\uD83C[\\uDFFB-\\uDFFF])\\u200D[\\u2640\\u2642]|(?:\\uD83C[\\uDFC3\\uDFC4\\uDFCA]|\\uD83D[\\uDC6E\\uDC71\\uDC73\\uDC77\\uDC81\\uDC82\\uDC86\\uDC87\\uDE45-\\uDE47\\uDE4B\\uDE4D\\uDE4E\\uDEA3\\uDEB4-\\uDEB6]|\\uD83E[\\uDD26\\uDD37-\\uDD39\\uDD3D\\uDD3E\\uDDB8\\uDDB9\\uDDCD-\\uDDCF\\uDDD6-\\uDDDD])(?:(?:\\uD83C[\\uDFFB-\\uDFFF])\\u200D[\\u2640\\u2642]|\\u200D[\\u2640\\u2642])|\\uD83C\\uDFF4\\u200D\\u2620)\\uFE0F|\\uD83D\\uDC69\\u200D\\uD83D\\uDC67\\u200D(?:\\uD83D[\\uDC66\\uDC67])|\\uD83C\\uDFF3\\uFE0F\\u200D\\uD83C\\uDF08|\\uD83D\\uDC15\\u200D\\uD83E\\uDDBA|\\uD83D\\uDC69\\u200D\\uD83D\\uDC66|\\uD83D\\uDC69\\u200D\\uD83D\\uDC67|\\uD83C\\uDDFD\\uD83C\\uDDF0|\\uD83C\\uDDF4\\uD83C\\uDDF2|\\uD83C\\uDDF6\\uD83C\\uDDE6|[#\\*0-9]\\uFE0F\\u20E3|\\uD83C\\uDDE7(?:\\uD83C[\\uDDE6\\uDDE7\\uDDE9-\\uDDEF\\uDDF1-\\uDDF4\\uDDF6-\\uDDF9\\uDDFB\\uDDFC\\uDDFE\\uDDFF])|\\uD83C\\uDDF9(?:\\uD83C[\\uDDE6\\uDDE8\\uDDE9\\uDDEB-\\uDDED\\uDDEF-\\uDDF4\\uDDF7\\uDDF9\\uDDFB\\uDDFC\\uDDFF])|\\uD83C\\uDDEA(?:\\uD83C[\\uDDE6\\uDDE8\\uDDEA\\uDDEC\\uDDED\\uDDF7-\\uDDFA])|\\uD83E\\uDDD1(?:\\uD83C[\\uDFFB-\\uDFFF])|\\uD83C\\uDDF7(?:\\uD83C[\\uDDEA\\uDDF4\\uDDF8\\uDDFA\\uDDFC])|\\uD83D\\uDC69(?:\\uD83C[\\uDFFB-\\uDFFF])|\\uD83C\\uDDF2(?:\\uD83C[\\uDDE6\\uDDE8-\\uDDED\\uDDF0-\\uDDFF])|\\uD83C\\uDDE6(?:\\uD83C[\\uDDE8-\\uDDEC\\uDDEE\\uDDF1\\uDDF2\\uDDF4\\uDDF6-\\uDDFA\\uDDFC\\uDDFD\\uDDFF])|\\uD83C\\uDDF0(?:\\uD83C[\\uDDEA\\uDDEC-\\uDDEE\\uDDF2\\uDDF3\\uDDF5\\uDDF7\\uDDFC\\uDDFE\\uDDFF])|\\uD83C\\uDDED(?:\\uD83C[\\uDDF0\\uDDF2\\uDDF3\\uDDF7\\uDDF9\\uDDFA])|\\uD83C\\uDDE9(?:\\uD83C[\\uDDEA\\uDDEC\\uDDEF\\uDDF0\\uDDF2\\uDDF4\\uDDFF])|\\uD83C\\uDDFE(?:\\uD83C[\\uDDEA\\uDDF9])|\\uD83C\\uDDEC(?:\\uD83C[\\uDDE6\\uDDE7\\uDDE9-\\uDDEE\\uDDF1-\\uDDF3\\uDDF5-\\uDDFA\\uDDFC\\uDDFE])|\\uD83C\\uDDF8(?:\\uD83C[\\uDDE6-\\uDDEA\\uDDEC-\\uDDF4\\uDDF7-\\uDDF9\\uDDFB\\uDDFD-\\uDDFF])|\\uD83C\\uDDEB(?:\\uD83C[\\uDDEE-\\uDDF0\\uDDF2\\uDDF4\\uDDF7])|\\uD83C\\uDDF5(?:\\uD83C[\\uDDE6\\uDDEA-\\uDDED\\uDDF0-\\uDDF3\\uDDF7-\\uDDF9\\uDDFC\\uDDFE])|\\uD83C\\uDDFB(?:\\uD83C[\\uDDE6\\uDDE8\\uDDEA\\uDDEC\\uDDEE\\uDDF3\\uDDFA])|\\uD83C\\uDDF3(?:\\uD83C[\\uDDE6\\uDDE8\\uDDEA-\\uDDEC\\uDDEE\\uDDF1\\uDDF4\\uDDF5\\uDDF7\\uDDFA\\uDDFF])|\\uD83C\\uDDE8(?:\\uD83C[\\uDDE6\\uDDE8\\uDDE9\\uDDEB-\\uDDEE\\uDDF0-\\uDDF5\\uDDF7\\uDDFA-\\uDDFF])|\\uD83C\\uDDF1(?:\\uD83C[\\uDDE6-\\uDDE8\\uDDEE\\uDDF0\\uDDF7-\\uDDFB\\uDDFE])|\\uD83C\\uDDFF(?:\\uD83C[\\uDDE6\\uDDF2\\uDDFC])|\\uD83C\\uDDFC(?:\\uD83C[\\uDDEB\\uDDF8])|\\uD83C\\uDDFA(?:\\uD83C[\\uDDE6\\uDDEC\\uDDF2\\uDDF3\\uDDF8\\uDDFE\\uDDFF])|\\uD83C\\uDDEE(?:\\uD83C[\\uDDE8-\\uDDEA\\uDDF1-\\uDDF4\\uDDF6-\\uDDF9])|\\uD83C\\uDDEF(?:\\uD83C[\\uDDEA\\uDDF2\\uDDF4\\uDDF5])|(?:\\uD83C[\\uDFC3\\uDFC4\\uDFCA]|\\uD83D[\\uDC6E\\uDC71\\uDC73\\uDC77\\uDC81\\uDC82\\uDC86\\uDC87\\uDE45-\\uDE47\\uDE4B\\uDE4D\\uDE4E\\uDEA3\\uDEB4-\\uDEB6]|\\uD83E[\\uDD26\\uDD37-\\uDD39\\uDD3D\\uDD3E\\uDDB8\\uDDB9\\uDDCD-\\uDDCF\\uDDD6-\\uDDDD])(?:\\uD83C[\\uDFFB-\\uDFFF])|(?:\\u26F9|\\uD83C[\\uDFCB\\uDFCC]|\\uD83D\\uDD75)(?:\\uD83C[\\uDFFB-\\uDFFF])|(?:[\\u261D\\u270A-\\u270D]|\\uD83C[\\uDF85\\uDFC2\\uDFC7]|\\uD83D[\\uDC42\\uDC43\\uDC46-\\uDC50\\uDC66\\uDC67\\uDC6B-\\uDC6D\\uDC70\\uDC72\\uDC74-\\uDC76\\uDC78\\uDC7C\\uDC83\\uDC85\\uDCAA\\uDD74\\uDD7A\\uDD90\\uDD95\\uDD96\\uDE4C\\uDE4F\\uDEC0\\uDECC]|\\uD83E[\\uDD0F\\uDD18-\\uDD1C\\uDD1E\\uDD1F\\uDD30-\\uDD36\\uDDB5\\uDDB6\\uDDBB\\uDDD2-\\uDDD5])(?:\\uD83C[\\uDFFB-\\uDFFF])|(?:[\\u231A\\u231B\\u23E9-\\u23EC\\u23F0\\u23F3\\u25FD\\u25FE\\u2614\\u2615\\u2648-\\u2653\\u267F\\u2693\\u26A1\\u26AA\\u26AB\\u26BD\\u26BE\\u26C4\\u26C5\\u26CE\\u26D4\\u26EA\\u26F2\\u26F3\\u26F5\\u26FA\\u26FD\\u2705\\u270A\\u270B\\u2728\\u274C\\u274E\\u2753-\\u2755\\u2757\\u2795-\\u2797\\u27B0\\u27BF\\u2B1B\\u2B1C\\u2B50\\u2B55]|\\uD83C[\\uDC04\\uDCCF\\uDD8E\\uDD91-\\uDD9A\\uDDE6-\\uDDFF\\uDE01\\uDE1A\\uDE2F\\uDE32-\\uDE36\\uDE38-\\uDE3A\\uDE50\\uDE51\\uDF00-\\uDF20\\uDF2D-\\uDF35\\uDF37-\\uDF7C\\uDF7E-\\uDF93\\uDFA0-\\uDFCA\\uDFCF-\\uDFD3\\uDFE0-\\uDFF0\\uDFF4\\uDFF8-\\uDFFF]|\\uD83D[\\uDC00-\\uDC3E\\uDC40\\uDC42-\\uDCFC\\uDCFF-\\uDD3D\\uDD4B-\\uDD4E\\uDD50-\\uDD67\\uDD7A\\uDD95\\uDD96\\uDDA4\\uDDFB-\\uDE4F\\uDE80-\\uDEC5\\uDECC\\uDED0-\\uDED2\\uDED5\\uDEEB\\uDEEC\\uDEF4-\\uDEFA\\uDFE0-\\uDFEB]|\\uD83E[\\uDD0D-\\uDD3A\\uDD3C-\\uDD45\\uDD47-\\uDD71\\uDD73-\\uDD76\\uDD7A-\\uDDA2\\uDDA5-\\uDDAA\\uDDAE-\\uDDCA\\uDDCD-\\uDDFF\\uDE70-\\uDE73\\uDE78-\\uDE7A\\uDE80-\\uDE82\\uDE90-\\uDE95])|(?:[#\\*0-9\\xA9\\xAE\\u203C\\u2049\\u2122\\u2139\\u2194-\\u2199\\u21A9\\u21AA\\u231A\\u231B\\u2328\\u23CF\\u23E9-\\u23F3\\u23F8-\\u23FA\\u24C2\\u25AA\\u25AB\\u25B6\\u25C0\\u25FB-\\u25FE\\u2600-\\u2604\\u260E\\u2611\\u2614\\u2615\\u2618\\u261D\\u2620\\u2622\\u2623\\u2626\\u262A\\u262E\\u262F\\u2638-\\u263A\\u2640\\u2642\\u2648-\\u2653\\u265F\\u2660\\u2663\\u2665\\u2666\\u2668\\u267B\\u267E\\u267F\\u2692-\\u2697\\u2699\\u269B\\u269C\\u26A0\\u26A1\\u26AA\\u26AB\\u26B0\\u26B1\\u26BD\\u26BE\\u26C4\\u26C5\\u26C8\\u26CE\\u26CF\\u26D1\\u26D3\\u26D4\\u26E9\\u26EA\\u26F0-\\u26F5\\u26F7-\\u26FA\\u26FD\\u2702\\u2705\\u2708-\\u270D\\u270F\\u2712\\u2714\\u2716\\u271D\\u2721\\u2728\\u2733\\u2734\\u2744\\u2747\\u274C\\u274E\\u2753-\\u2755\\u2757\\u2763\\u2764\\u2795-\\u2797\\u27A1\\u27B0\\u27BF\\u2934\\u2935\\u2B05-\\u2B07\\u2B1B\\u2B1C\\u2B50\\u2B55\\u3030\\u303D\\u3297\\u3299]|\\uD83C[\\uDC04\\uDCCF\\uDD70\\uDD71\\uDD7E\\uDD7F\\uDD8E\\uDD91-\\uDD9A\\uDDE6-\\uDDFF\\uDE01\\uDE02\\uDE1A\\uDE2F\\uDE32-\\uDE3A\\uDE50\\uDE51\\uDF00-\\uDF21\\uDF24-\\uDF93\\uDF96\\uDF97\\uDF99-\\uDF9B\\uDF9E-\\uDFF0\\uDFF3-\\uDFF5\\uDFF7-\\uDFFF]|\\uD83D[\\uDC00-\\uDCFD\\uDCFF-\\uDD3D\\uDD49-\\uDD4E\\uDD50-\\uDD67\\uDD6F\\uDD70\\uDD73-\\uDD7A\\uDD87\\uDD8A-\\uDD8D\\uDD90\\uDD95\\uDD96\\uDDA4\\uDDA5\\uDDA8\\uDDB1\\uDDB2\\uDDBC\\uDDC2-\\uDDC4\\uDDD1-\\uDDD3\\uDDDC-\\uDDDE\\uDDE1\\uDDE3\\uDDE8\\uDDEF\\uDDF3\\uDDFA-\\uDE4F\\uDE80-\\uDEC5\\uDECB-\\uDED2\\uDED5\\uDEE0-\\uDEE5\\uDEE9\\uDEEB\\uDEEC\\uDEF0\\uDEF3-\\uDEFA\\uDFE0-\\uDFEB]|\\uD83E[\\uDD0D-\\uDD3A\\uDD3C-\\uDD45\\uDD47-\\uDD71\\uDD73-\\uDD76\\uDD7A-\\uDDA2\\uDDA5-\\uDDAA\\uDDAE-\\uDDCA\\uDDCD-\\uDDFF\\uDE70-\\uDE73\\uDE78-\\uDE7A\\uDE80-\\uDE82\\uDE90-\\uDE95])\\uFE0F|(?:[\\u261D\\u26F9\\u270A-\\u270D]|\\uD83C[\\uDF85\\uDFC2-\\uDFC4\\uDFC7\\uDFCA-\\uDFCC]|\\uD83D[\\uDC42\\uDC43\\uDC46-\\uDC50\\uDC66-\\uDC78\\uDC7C\\uDC81-\\uDC83\\uDC85-\\uDC87\\uDC8F\\uDC91\\uDCAA\\uDD74\\uDD75\\uDD7A\\uDD90\\uDD95\\uDD96\\uDE45-\\uDE47\\uDE4B-\\uDE4F\\uDEA3\\uDEB4-\\uDEB6\\uDEC0\\uDECC]|\\uD83E[\\uDD0F\\uDD18-\\uDD1F\\uDD26\\uDD30-\\uDD39\\uDD3C-\\uDD3E\\uDDB5\\uDDB6\\uDDB8\\uDDB9\\uDDBB\\uDDCD-\\uDDCF\\uDDD1-\\uDDDD])/g}});var Kk=_((DKt,R6)=>{\"use strict\";var Kyt=NP(),zyt=F6(),Vyt=UEe(),_Ee=t=>{if(typeof t!=\"string\"||t.length===0||(t=Kyt(t),t.length===0))return 0;t=t.replace(Vyt(),\"  \");let e=0;for(let r=0;r<t.length;r++){let o=t.codePointAt(r);o<=31||o>=127&&o<=159||o>=768&&o<=879||(o>65535&&r++,e+=zyt(o)?2:1)}return e};R6.exports=_Ee;R6.exports.default=_Ee});var L6=_((PKt,T6)=>{\"use strict\";var Jyt=Kk(),HEe=t=>{let e=0;for(let r of t.split(`\n`))e=Math.max(e,Jyt(r));return e};T6.exports=HEe;T6.exports.default=HEe});var qEe=_(cB=>{\"use strict\";var Xyt=cB&&cB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(cB,\"__esModule\",{value:!0});var Zyt=Xyt(L6()),N6={};cB.default=t=>{if(t.length===0)return{width:0,height:0};if(N6[t])return N6[t];let e=Zyt.default(t),r=t.split(`\n`).length;return N6[t]={width:e,height:r},{width:e,height:r}}});var GEe=_(uB=>{\"use strict\";var $yt=uB&&uB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(uB,\"__esModule\",{value:!0});var dn=$yt(lm()),eEt=(t,e)=>{\"position\"in e&&t.setPositionType(e.position===\"absolute\"?dn.default.POSITION_TYPE_ABSOLUTE:dn.default.POSITION_TYPE_RELATIVE)},tEt=(t,e)=>{\"marginLeft\"in e&&t.setMargin(dn.default.EDGE_START,e.marginLeft||0),\"marginRight\"in e&&t.setMargin(dn.default.EDGE_END,e.marginRight||0),\"marginTop\"in e&&t.setMargin(dn.default.EDGE_TOP,e.marginTop||0),\"marginBottom\"in e&&t.setMargin(dn.default.EDGE_BOTTOM,e.marginBottom||0)},rEt=(t,e)=>{\"paddingLeft\"in e&&t.setPadding(dn.default.EDGE_LEFT,e.paddingLeft||0),\"paddingRight\"in e&&t.setPadding(dn.default.EDGE_RIGHT,e.paddingRight||0),\"paddingTop\"in e&&t.setPadding(dn.default.EDGE_TOP,e.paddingTop||0),\"paddingBottom\"in e&&t.setPadding(dn.default.EDGE_BOTTOM,e.paddingBottom||0)},nEt=(t,e)=>{var r;\"flexGrow\"in e&&t.setFlexGrow((r=e.flexGrow)!==null&&r!==void 0?r:0),\"flexShrink\"in e&&t.setFlexShrink(typeof e.flexShrink==\"number\"?e.flexShrink:1),\"flexDirection\"in e&&(e.flexDirection===\"row\"&&t.setFlexDirection(dn.default.FLEX_DIRECTION_ROW),e.flexDirection===\"row-reverse\"&&t.setFlexDirection(dn.default.FLEX_DIRECTION_ROW_REVERSE),e.flexDirection===\"column\"&&t.setFlexDirection(dn.default.FLEX_DIRECTION_COLUMN),e.flexDirection===\"column-reverse\"&&t.setFlexDirection(dn.default.FLEX_DIRECTION_COLUMN_REVERSE)),\"flexBasis\"in e&&(typeof e.flexBasis==\"number\"?t.setFlexBasis(e.flexBasis):typeof e.flexBasis==\"string\"?t.setFlexBasisPercent(Number.parseInt(e.flexBasis,10)):t.setFlexBasis(NaN)),\"alignItems\"in e&&((e.alignItems===\"stretch\"||!e.alignItems)&&t.setAlignItems(dn.default.ALIGN_STRETCH),e.alignItems===\"flex-start\"&&t.setAlignItems(dn.default.ALIGN_FLEX_START),e.alignItems===\"center\"&&t.setAlignItems(dn.default.ALIGN_CENTER),e.alignItems===\"flex-end\"&&t.setAlignItems(dn.default.ALIGN_FLEX_END)),\"alignSelf\"in e&&((e.alignSelf===\"auto\"||!e.alignSelf)&&t.setAlignSelf(dn.default.ALIGN_AUTO),e.alignSelf===\"flex-start\"&&t.setAlignSelf(dn.default.ALIGN_FLEX_START),e.alignSelf===\"center\"&&t.setAlignSelf(dn.default.ALIGN_CENTER),e.alignSelf===\"flex-end\"&&t.setAlignSelf(dn.default.ALIGN_FLEX_END)),\"justifyContent\"in e&&((e.justifyContent===\"flex-start\"||!e.justifyContent)&&t.setJustifyContent(dn.default.JUSTIFY_FLEX_START),e.justifyContent===\"center\"&&t.setJustifyContent(dn.default.JUSTIFY_CENTER),e.justifyContent===\"flex-end\"&&t.setJustifyContent(dn.default.JUSTIFY_FLEX_END),e.justifyContent===\"space-between\"&&t.setJustifyContent(dn.default.JUSTIFY_SPACE_BETWEEN),e.justifyContent===\"space-around\"&&t.setJustifyContent(dn.default.JUSTIFY_SPACE_AROUND))},iEt=(t,e)=>{var r,o;\"width\"in e&&(typeof e.width==\"number\"?t.setWidth(e.width):typeof e.width==\"string\"?t.setWidthPercent(Number.parseInt(e.width,10)):t.setWidthAuto()),\"height\"in e&&(typeof e.height==\"number\"?t.setHeight(e.height):typeof e.height==\"string\"?t.setHeightPercent(Number.parseInt(e.height,10)):t.setHeightAuto()),\"minWidth\"in e&&(typeof e.minWidth==\"string\"?t.setMinWidthPercent(Number.parseInt(e.minWidth,10)):t.setMinWidth((r=e.minWidth)!==null&&r!==void 0?r:0)),\"minHeight\"in e&&(typeof e.minHeight==\"string\"?t.setMinHeightPercent(Number.parseInt(e.minHeight,10)):t.setMinHeight((o=e.minHeight)!==null&&o!==void 0?o:0))},sEt=(t,e)=>{\"display\"in e&&t.setDisplay(e.display===\"flex\"?dn.default.DISPLAY_FLEX:dn.default.DISPLAY_NONE)},oEt=(t,e)=>{if(\"borderStyle\"in e){let r=typeof e.borderStyle==\"string\"?1:0;t.setBorder(dn.default.EDGE_TOP,r),t.setBorder(dn.default.EDGE_BOTTOM,r),t.setBorder(dn.default.EDGE_LEFT,r),t.setBorder(dn.default.EDGE_RIGHT,r)}};uB.default=(t,e={})=>{eEt(t,e),tEt(t,e),rEt(t,e),nEt(t,e),iEt(t,e),sEt(t,e),oEt(t,e)}});var WEe=_((xKt,YEe)=>{\"use strict\";var AB=Kk(),aEt=NP(),lEt=DI(),M6=new Set([\"\\x1B\",\"\\x9B\"]),cEt=39,jEe=t=>`${M6.values().next().value}[${t}m`,uEt=t=>t.split(\" \").map(e=>AB(e)),O6=(t,e,r)=>{let o=[...e],a=!1,n=AB(aEt(t[t.length-1]));for(let[u,A]of o.entries()){let p=AB(A);if(n+p<=r?t[t.length-1]+=A:(t.push(A),n=0),M6.has(A))a=!0;else if(a&&A===\"m\"){a=!1;continue}a||(n+=p,n===r&&u<o.length-1&&(t.push(\"\"),n=0))}!n&&t[t.length-1].length>0&&t.length>1&&(t[t.length-2]+=t.pop())},AEt=t=>{let e=t.split(\" \"),r=e.length;for(;r>0&&!(AB(e[r-1])>0);)r--;return r===e.length?t:e.slice(0,r).join(\" \")+e.slice(r).join(\"\")},fEt=(t,e,r={})=>{if(r.trim!==!1&&t.trim()===\"\")return\"\";let o=\"\",a=\"\",n,u=uEt(t),A=[\"\"];for(let[p,h]of t.split(\" \").entries()){r.trim!==!1&&(A[A.length-1]=A[A.length-1].trimLeft());let E=AB(A[A.length-1]);if(p!==0&&(E>=e&&(r.wordWrap===!1||r.trim===!1)&&(A.push(\"\"),E=0),(E>0||r.trim===!1)&&(A[A.length-1]+=\" \",E++)),r.hard&&u[p]>e){let I=e-E,v=1+Math.floor((u[p]-I-1)/e);Math.floor((u[p]-1)/e)<v&&A.push(\"\"),O6(A,h,e);continue}if(E+u[p]>e&&E>0&&u[p]>0){if(r.wordWrap===!1&&E<e){O6(A,h,e);continue}A.push(\"\")}if(E+u[p]>e&&r.wordWrap===!1){O6(A,h,e);continue}A[A.length-1]+=h}r.trim!==!1&&(A=A.map(AEt)),o=A.join(`\n`);for(let[p,h]of[...o].entries()){if(a+=h,M6.has(h)){let I=parseFloat(/\\d[^m]*/.exec(o.slice(p,p+4)));n=I===cEt?null:I}let E=lEt.codes.get(Number(n));n&&E&&(o[p+1]===`\n`?a+=jEe(E):h===`\n`&&(a+=jEe(n)))}return a};YEe.exports=(t,e,r)=>String(t).normalize().replace(/\\r\\n/g,`\n`).split(`\n`).map(o=>fEt(o,e,r)).join(`\n`)});var VEe=_((kKt,zEe)=>{\"use strict\";var KEe=\"[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]\",pEt=t=>t&&t.exact?new RegExp(`^${KEe}$`):new RegExp(KEe,\"g\");zEe.exports=pEt});var U6=_((QKt,$Ee)=>{\"use strict\";var hEt=F6(),gEt=VEe(),JEe=DI(),ZEe=[\"\\x1B\",\"\\x9B\"],zk=t=>`${ZEe[0]}[${t}m`,XEe=(t,e,r)=>{let o=[];t=[...t];for(let a of t){let n=a;a.match(\";\")&&(a=a.split(\";\")[0][0]+\"0\");let u=JEe.codes.get(parseInt(a,10));if(u){let A=t.indexOf(u.toString());A>=0?t.splice(A,1):o.push(zk(e?u:n))}else if(e){o.push(zk(0));break}else o.push(zk(n))}if(e&&(o=o.filter((a,n)=>o.indexOf(a)===n),r!==void 0)){let a=zk(JEe.codes.get(parseInt(r,10)));o=o.reduce((n,u)=>u===a?[u,...n]:[...n,u],[])}return o.join(\"\")};$Ee.exports=(t,e,r)=>{let o=[...t.normalize()],a=[];r=typeof r==\"number\"?r:o.length;let n=!1,u,A=0,p=\"\";for(let[h,E]of o.entries()){let I=!1;if(ZEe.includes(E)){let v=/\\d[^m]*/.exec(t.slice(h,h+18));u=v&&v.length>0?v[0]:void 0,A<r&&(n=!0,u!==void 0&&a.push(u))}else n&&E===\"m\"&&(n=!1,I=!0);if(!n&&!I&&++A,!gEt({exact:!0}).test(E)&&hEt(E.codePointAt())&&++A,A>e&&A<=r)p+=E;else if(A===e&&!n&&u!==void 0)p=XEe(a);else if(A>=r){p+=XEe(a,!0,u);break}}return p}});var tCe=_((FKt,eCe)=>{\"use strict\";var C0=U6(),dEt=Kk();function Vk(t,e,r){if(t.charAt(e)===\" \")return e;for(let o=1;o<=3;o++)if(r){if(t.charAt(e+o)===\" \")return e+o}else if(t.charAt(e-o)===\" \")return e-o;return e}eCe.exports=(t,e,r)=>{r={position:\"end\",preferTruncationOnSpace:!1,...r};let{position:o,space:a,preferTruncationOnSpace:n}=r,u=\"\\u2026\",A=1;if(typeof t!=\"string\")throw new TypeError(`Expected \\`input\\` to be a string, got ${typeof t}`);if(typeof e!=\"number\")throw new TypeError(`Expected \\`columns\\` to be a number, got ${typeof e}`);if(e<1)return\"\";if(e===1)return u;let p=dEt(t);if(p<=e)return t;if(o===\"start\"){if(n){let h=Vk(t,p-e+1,!0);return u+C0(t,h,p).trim()}return a===!0&&(u+=\" \",A=2),u+C0(t,p-e+A,p)}if(o===\"middle\"){a===!0&&(u=\" \"+u+\" \",A=3);let h=Math.floor(e/2);if(n){let E=Vk(t,h),I=Vk(t,p-(e-h)+1,!0);return C0(t,0,E)+u+C0(t,I,p).trim()}return C0(t,0,h)+u+C0(t,p-(e-h)+A,p)}if(o===\"end\"){if(n){let h=Vk(t,e-1);return C0(t,0,h)+u}return a===!0&&(u=\" \"+u,A=2),C0(t,0,e-A)+u}throw new Error(`Expected \\`options.position\\` to be either \\`start\\`, \\`middle\\` or \\`end\\`, got ${o}`)}});var H6=_(fB=>{\"use strict\";var rCe=fB&&fB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(fB,\"__esModule\",{value:!0});var mEt=rCe(WEe()),yEt=rCe(tCe()),_6={};fB.default=(t,e,r)=>{let o=t+String(e)+String(r);if(_6[o])return _6[o];let a=t;if(r===\"wrap\"&&(a=mEt.default(t,e,{trim:!1,hard:!0})),r.startsWith(\"truncate\")){let n=\"end\";r===\"truncate-middle\"&&(n=\"middle\"),r===\"truncate-start\"&&(n=\"start\"),a=yEt.default(t,e,{position:n})}return _6[o]=a,a}});var G6=_(q6=>{\"use strict\";Object.defineProperty(q6,\"__esModule\",{value:!0});var nCe=t=>{let e=\"\";if(t.childNodes.length>0)for(let r of t.childNodes){let o=\"\";r.nodeName===\"#text\"?o=r.nodeValue:((r.nodeName===\"ink-text\"||r.nodeName===\"ink-virtual-text\")&&(o=nCe(r)),o.length>0&&typeof r.internal_transform==\"function\"&&(o=r.internal_transform(o))),e+=o}return e};q6.default=nCe});var j6=_(pi=>{\"use strict\";var pB=pi&&pi.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(pi,\"__esModule\",{value:!0});pi.setTextNodeValue=pi.createTextNode=pi.setStyle=pi.setAttribute=pi.removeChildNode=pi.insertBeforeNode=pi.appendChildNode=pi.createNode=pi.TEXT_NAME=void 0;var EEt=pB(lm()),iCe=pB(qEe()),CEt=pB(GEe()),wEt=pB(H6()),IEt=pB(G6());pi.TEXT_NAME=\"#text\";pi.createNode=t=>{var e;let r={nodeName:t,style:{},attributes:{},childNodes:[],parentNode:null,yogaNode:t===\"ink-virtual-text\"?void 0:EEt.default.Node.create()};return t===\"ink-text\"&&((e=r.yogaNode)===null||e===void 0||e.setMeasureFunc(BEt.bind(null,r))),r};pi.appendChildNode=(t,e)=>{var r;e.parentNode&&pi.removeChildNode(e.parentNode,e),e.parentNode=t,t.childNodes.push(e),e.yogaNode&&((r=t.yogaNode)===null||r===void 0||r.insertChild(e.yogaNode,t.yogaNode.getChildCount())),(t.nodeName===\"ink-text\"||t.nodeName===\"ink-virtual-text\")&&Jk(t)};pi.insertBeforeNode=(t,e,r)=>{var o,a;e.parentNode&&pi.removeChildNode(e.parentNode,e),e.parentNode=t;let n=t.childNodes.indexOf(r);if(n>=0){t.childNodes.splice(n,0,e),e.yogaNode&&((o=t.yogaNode)===null||o===void 0||o.insertChild(e.yogaNode,n));return}t.childNodes.push(e),e.yogaNode&&((a=t.yogaNode)===null||a===void 0||a.insertChild(e.yogaNode,t.yogaNode.getChildCount())),(t.nodeName===\"ink-text\"||t.nodeName===\"ink-virtual-text\")&&Jk(t)};pi.removeChildNode=(t,e)=>{var r,o;e.yogaNode&&((o=(r=e.parentNode)===null||r===void 0?void 0:r.yogaNode)===null||o===void 0||o.removeChild(e.yogaNode)),e.parentNode=null;let a=t.childNodes.indexOf(e);a>=0&&t.childNodes.splice(a,1),(t.nodeName===\"ink-text\"||t.nodeName===\"ink-virtual-text\")&&Jk(t)};pi.setAttribute=(t,e,r)=>{t.attributes[e]=r};pi.setStyle=(t,e)=>{t.style=e,t.yogaNode&&CEt.default(t.yogaNode,e)};pi.createTextNode=t=>{let e={nodeName:\"#text\",nodeValue:t,yogaNode:void 0,parentNode:null,style:{}};return pi.setTextNodeValue(e,t),e};var BEt=function(t,e){var r,o;let a=t.nodeName===\"#text\"?t.nodeValue:IEt.default(t),n=iCe.default(a);if(n.width<=e||n.width>=1&&e>0&&e<1)return n;let u=(o=(r=t.style)===null||r===void 0?void 0:r.textWrap)!==null&&o!==void 0?o:\"wrap\",A=wEt.default(a,e,u);return iCe.default(A)},sCe=t=>{var e;if(!(!t||!t.parentNode))return(e=t.yogaNode)!==null&&e!==void 0?e:sCe(t.parentNode)},Jk=t=>{let e=sCe(t);e?.markDirty()};pi.setTextNodeValue=(t,e)=>{typeof e!=\"string\"&&(e=String(e)),t.nodeValue=e,Jk(t)}});var uCe=_(hB=>{\"use strict\";var cCe=hB&&hB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(hB,\"__esModule\",{value:!0});var oCe=P6(),vEt=cCe(bEe()),aCe=cCe(lm()),Oo=j6(),lCe=t=>{t?.unsetMeasureFunc(),t?.freeRecursive()};hB.default=vEt.default({schedulePassiveEffects:oCe.unstable_scheduleCallback,cancelPassiveEffects:oCe.unstable_cancelCallback,now:Date.now,getRootHostContext:()=>({isInsideText:!1}),prepareForCommit:()=>{},resetAfterCommit:t=>{if(t.isStaticDirty){t.isStaticDirty=!1,typeof t.onImmediateRender==\"function\"&&t.onImmediateRender();return}typeof t.onRender==\"function\"&&t.onRender()},getChildHostContext:(t,e)=>{let r=t.isInsideText,o=e===\"ink-text\"||e===\"ink-virtual-text\";return r===o?t:{isInsideText:o}},shouldSetTextContent:()=>!1,createInstance:(t,e,r,o)=>{if(o.isInsideText&&t===\"ink-box\")throw new Error(\"<Box> can\\u2019t be nested inside <Text> component\");let a=t===\"ink-text\"&&o.isInsideText?\"ink-virtual-text\":t,n=Oo.createNode(a);for(let[u,A]of Object.entries(e))u!==\"children\"&&(u===\"style\"?Oo.setStyle(n,A):u===\"internal_transform\"?n.internal_transform=A:u===\"internal_static\"?n.internal_static=!0:Oo.setAttribute(n,u,A));return n},createTextInstance:(t,e,r)=>{if(!r.isInsideText)throw new Error(`Text string \"${t}\" must be rendered inside <Text> component`);return Oo.createTextNode(t)},resetTextContent:()=>{},hideTextInstance:t=>{Oo.setTextNodeValue(t,\"\")},unhideTextInstance:(t,e)=>{Oo.setTextNodeValue(t,e)},getPublicInstance:t=>t,hideInstance:t=>{var e;(e=t.yogaNode)===null||e===void 0||e.setDisplay(aCe.default.DISPLAY_NONE)},unhideInstance:t=>{var e;(e=t.yogaNode)===null||e===void 0||e.setDisplay(aCe.default.DISPLAY_FLEX)},appendInitialChild:Oo.appendChildNode,appendChild:Oo.appendChildNode,insertBefore:Oo.insertBeforeNode,finalizeInitialChildren:(t,e,r,o)=>(t.internal_static&&(o.isStaticDirty=!0,o.staticNode=t),!1),supportsMutation:!0,appendChildToContainer:Oo.appendChildNode,insertInContainerBefore:Oo.insertBeforeNode,removeChildFromContainer:(t,e)=>{Oo.removeChildNode(t,e),lCe(e.yogaNode)},prepareUpdate:(t,e,r,o,a)=>{t.internal_static&&(a.isStaticDirty=!0);let n={},u=Object.keys(o);for(let A of u)if(o[A]!==r[A]){if(A===\"style\"&&typeof o.style==\"object\"&&typeof r.style==\"object\"){let h=o.style,E=r.style,I=Object.keys(h);for(let v of I){if(v===\"borderStyle\"||v===\"borderColor\"){if(typeof n.style!=\"object\"){let x={};n.style=x}n.style.borderStyle=h.borderStyle,n.style.borderColor=h.borderColor}if(h[v]!==E[v]){if(typeof n.style!=\"object\"){let x={};n.style=x}n.style[v]=h[v]}}continue}n[A]=o[A]}return n},commitUpdate:(t,e)=>{for(let[r,o]of Object.entries(e))r!==\"children\"&&(r===\"style\"?Oo.setStyle(t,o):r===\"internal_transform\"?t.internal_transform=o:r===\"internal_static\"?t.internal_static=!0:Oo.setAttribute(t,r,o))},commitTextUpdate:(t,e,r)=>{Oo.setTextNodeValue(t,r)},removeChild:(t,e)=>{Oo.removeChildNode(t,e),lCe(e.yogaNode)}})});var fCe=_((OKt,ACe)=>{\"use strict\";ACe.exports=(t,e=1,r)=>{if(r={indent:\" \",includeEmptyLines:!1,...r},typeof t!=\"string\")throw new TypeError(`Expected \\`input\\` to be a \\`string\\`, got \\`${typeof t}\\``);if(typeof e!=\"number\")throw new TypeError(`Expected \\`count\\` to be a \\`number\\`, got \\`${typeof e}\\``);if(typeof r.indent!=\"string\")throw new TypeError(`Expected \\`options.indent\\` to be a \\`string\\`, got \\`${typeof r.indent}\\``);if(e===0)return t;let o=r.includeEmptyLines?/^/gm:/^(?!\\s*$)/gm;return t.replace(o,r.indent.repeat(e))}});var pCe=_(gB=>{\"use strict\";var DEt=gB&&gB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(gB,\"__esModule\",{value:!0});var Xk=DEt(lm());gB.default=t=>t.getComputedWidth()-t.getComputedPadding(Xk.default.EDGE_LEFT)-t.getComputedPadding(Xk.default.EDGE_RIGHT)-t.getComputedBorder(Xk.default.EDGE_LEFT)-t.getComputedBorder(Xk.default.EDGE_RIGHT)});var hCe=_((UKt,PEt)=>{PEt.exports={single:{topLeft:\"\\u250C\",topRight:\"\\u2510\",bottomRight:\"\\u2518\",bottomLeft:\"\\u2514\",vertical:\"\\u2502\",horizontal:\"\\u2500\"},double:{topLeft:\"\\u2554\",topRight:\"\\u2557\",bottomRight:\"\\u255D\",bottomLeft:\"\\u255A\",vertical:\"\\u2551\",horizontal:\"\\u2550\"},round:{topLeft:\"\\u256D\",topRight:\"\\u256E\",bottomRight:\"\\u256F\",bottomLeft:\"\\u2570\",vertical:\"\\u2502\",horizontal:\"\\u2500\"},bold:{topLeft:\"\\u250F\",topRight:\"\\u2513\",bottomRight:\"\\u251B\",bottomLeft:\"\\u2517\",vertical:\"\\u2503\",horizontal:\"\\u2501\"},singleDouble:{topLeft:\"\\u2553\",topRight:\"\\u2556\",bottomRight:\"\\u255C\",bottomLeft:\"\\u2559\",vertical:\"\\u2551\",horizontal:\"\\u2500\"},doubleSingle:{topLeft:\"\\u2552\",topRight:\"\\u2555\",bottomRight:\"\\u255B\",bottomLeft:\"\\u2558\",vertical:\"\\u2502\",horizontal:\"\\u2550\"},classic:{topLeft:\"+\",topRight:\"+\",bottomRight:\"+\",bottomLeft:\"+\",vertical:\"|\",horizontal:\"-\"}}});var dCe=_((_Kt,Y6)=>{\"use strict\";var gCe=hCe();Y6.exports=gCe;Y6.exports.default=gCe});var yCe=_((HKt,mCe)=>{\"use strict\";var SEt=(t,e,r)=>{let o=t.indexOf(e);if(o===-1)return t;let a=e.length,n=0,u=\"\";do u+=t.substr(n,o-n)+e+r,n=o+a,o=t.indexOf(e,n);while(o!==-1);return u+=t.substr(n),u},bEt=(t,e,r,o)=>{let a=0,n=\"\";do{let u=t[o-1]===\"\\r\";n+=t.substr(a,(u?o-1:o)-a)+e+(u?`\\r\n`:`\n`)+r,a=o+1,o=t.indexOf(`\n`,a)}while(o!==-1);return n+=t.substr(a),n};mCe.exports={stringReplaceAll:SEt,stringEncaseCRLFWithFirstIndex:bEt}});var BCe=_((qKt,ICe)=>{\"use strict\";var xEt=/(?:\\\\(u(?:[a-f\\d]{4}|\\{[a-f\\d]{1,6}\\})|x[a-f\\d]{2}|.))|(?:\\{(~)?(\\w+(?:\\([^)]*\\))?(?:\\.\\w+(?:\\([^)]*\\))?)*)(?:[ \\t]|(?=\\r?\\n)))|(\\})|((?:.|[\\r\\n\\f])+?)/gi,ECe=/(?:^|\\.)(\\w+)(?:\\(([^)]*)\\))?/g,kEt=/^(['\"])((?:\\\\.|(?!\\1)[^\\\\])*)\\1$/,QEt=/\\\\(u(?:[a-f\\d]{4}|{[a-f\\d]{1,6}})|x[a-f\\d]{2}|.)|([^\\\\])/gi,FEt=new Map([[\"n\",`\n`],[\"r\",\"\\r\"],[\"t\",\"\t\"],[\"b\",\"\\b\"],[\"f\",\"\\f\"],[\"v\",\"\\v\"],[\"0\",\"\\0\"],[\"\\\\\",\"\\\\\"],[\"e\",\"\\x1B\"],[\"a\",\"\\x07\"]]);function wCe(t){let e=t[0]===\"u\",r=t[1]===\"{\";return e&&!r&&t.length===5||t[0]===\"x\"&&t.length===3?String.fromCharCode(parseInt(t.slice(1),16)):e&&r?String.fromCodePoint(parseInt(t.slice(2,-1),16)):FEt.get(t)||t}function REt(t,e){let r=[],o=e.trim().split(/\\s*,\\s*/g),a;for(let n of o){let u=Number(n);if(!Number.isNaN(u))r.push(u);else if(a=n.match(kEt))r.push(a[2].replace(QEt,(A,p,h)=>p?wCe(p):h));else throw new Error(`Invalid Chalk template style argument: ${n} (in style '${t}')`)}return r}function TEt(t){ECe.lastIndex=0;let e=[],r;for(;(r=ECe.exec(t))!==null;){let o=r[1];if(r[2]){let a=REt(o,r[2]);e.push([o].concat(a))}else e.push([o])}return e}function CCe(t,e){let r={};for(let a of e)for(let n of a.styles)r[n[0]]=a.inverse?null:n.slice(1);let o=t;for(let[a,n]of Object.entries(r))if(!!Array.isArray(n)){if(!(a in o))throw new Error(`Unknown Chalk style: ${a}`);o=n.length>0?o[a](...n):o[a]}return o}ICe.exports=(t,e)=>{let r=[],o=[],a=[];if(e.replace(xEt,(n,u,A,p,h,E)=>{if(u)a.push(wCe(u));else if(p){let I=a.join(\"\");a=[],o.push(r.length===0?I:CCe(t,r)(I)),r.push({inverse:A,styles:TEt(p)})}else if(h){if(r.length===0)throw new Error(\"Found extraneous } in Chalk template literal\");o.push(CCe(t,r)(a.join(\"\"))),a=[],r.pop()}else a.push(E)}),o.push(a.join(\"\")),r.length>0){let n=`Chalk template literal is missing ${r.length} closing bracket${r.length===1?\"\":\"s\"} (\\`}\\`)`;throw new Error(n)}return o.join(\"\")}});var rQ=_((GKt,xCe)=>{\"use strict\";var dB=DI(),{stdout:K6,stderr:z6}=dL(),{stringReplaceAll:LEt,stringEncaseCRLFWithFirstIndex:NEt}=yCe(),{isArray:Zk}=Array,DCe=[\"ansi\",\"ansi\",\"ansi256\",\"ansi16m\"],HC=Object.create(null),OEt=(t,e={})=>{if(e.level&&!(Number.isInteger(e.level)&&e.level>=0&&e.level<=3))throw new Error(\"The `level` option should be an integer from 0 to 3\");let r=K6?K6.level:0;t.level=e.level===void 0?r:e.level},V6=class{constructor(e){return PCe(e)}},PCe=t=>{let e={};return OEt(e,t),e.template=(...r)=>bCe(e.template,...r),Object.setPrototypeOf(e,$k.prototype),Object.setPrototypeOf(e.template,e),e.template.constructor=()=>{throw new Error(\"`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.\")},e.template.Instance=V6,e.template};function $k(t){return PCe(t)}for(let[t,e]of Object.entries(dB))HC[t]={get(){let r=eQ(this,J6(e.open,e.close,this._styler),this._isEmpty);return Object.defineProperty(this,t,{value:r}),r}};HC.visible={get(){let t=eQ(this,this._styler,!0);return Object.defineProperty(this,\"visible\",{value:t}),t}};var SCe=[\"rgb\",\"hex\",\"keyword\",\"hsl\",\"hsv\",\"hwb\",\"ansi\",\"ansi256\"];for(let t of SCe)HC[t]={get(){let{level:e}=this;return function(...r){let o=J6(dB.color[DCe[e]][t](...r),dB.color.close,this._styler);return eQ(this,o,this._isEmpty)}}};for(let t of SCe){let e=\"bg\"+t[0].toUpperCase()+t.slice(1);HC[e]={get(){let{level:r}=this;return function(...o){let a=J6(dB.bgColor[DCe[r]][t](...o),dB.bgColor.close,this._styler);return eQ(this,a,this._isEmpty)}}}}var MEt=Object.defineProperties(()=>{},{...HC,level:{enumerable:!0,get(){return this._generator.level},set(t){this._generator.level=t}}}),J6=(t,e,r)=>{let o,a;return r===void 0?(o=t,a=e):(o=r.openAll+t,a=e+r.closeAll),{open:t,close:e,openAll:o,closeAll:a,parent:r}},eQ=(t,e,r)=>{let o=(...a)=>Zk(a[0])&&Zk(a[0].raw)?vCe(o,bCe(o,...a)):vCe(o,a.length===1?\"\"+a[0]:a.join(\" \"));return Object.setPrototypeOf(o,MEt),o._generator=t,o._styler=e,o._isEmpty=r,o},vCe=(t,e)=>{if(t.level<=0||!e)return t._isEmpty?\"\":e;let r=t._styler;if(r===void 0)return e;let{openAll:o,closeAll:a}=r;if(e.indexOf(\"\\x1B\")!==-1)for(;r!==void 0;)e=LEt(e,r.close,r.open),r=r.parent;let n=e.indexOf(`\n`);return n!==-1&&(e=NEt(e,a,o,n)),o+e+a},W6,bCe=(t,...e)=>{let[r]=e;if(!Zk(r)||!Zk(r.raw))return e.join(\" \");let o=e.slice(1),a=[r.raw[0]];for(let n=1;n<r.length;n++)a.push(String(o[n-1]).replace(/[{}\\\\]/g,\"\\\\$&\"),String(r.raw[n]));return W6===void 0&&(W6=BCe()),W6(t,a.join(\"\"))};Object.defineProperties($k.prototype,HC);var tQ=$k();tQ.supportsColor=K6;tQ.stderr=$k({level:z6?z6.level:0});tQ.stderr.supportsColor=z6;xCe.exports=tQ});var X6=_(yB=>{\"use strict\";var UEt=yB&&yB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(yB,\"__esModule\",{value:!0});var mB=UEt(rQ()),_Et=/^(rgb|hsl|hsv|hwb)\\(\\s?(\\d+),\\s?(\\d+),\\s?(\\d+)\\s?\\)$/,HEt=/^(ansi|ansi256)\\(\\s?(\\d+)\\s?\\)$/,nQ=(t,e)=>e===\"foreground\"?t:\"bg\"+t[0].toUpperCase()+t.slice(1);yB.default=(t,e,r)=>{if(!e)return t;if(e in mB.default){let a=nQ(e,r);return mB.default[a](t)}if(e.startsWith(\"#\")){let a=nQ(\"hex\",r);return mB.default[a](e)(t)}if(e.startsWith(\"ansi\")){let a=HEt.exec(e);if(!a)return t;let n=nQ(a[1],r),u=Number(a[2]);return mB.default[n](u)(t)}if(e.startsWith(\"rgb\")||e.startsWith(\"hsl\")||e.startsWith(\"hsv\")||e.startsWith(\"hwb\")){let a=_Et.exec(e);if(!a)return t;let n=nQ(a[1],r),u=Number(a[2]),A=Number(a[3]),p=Number(a[4]);return mB.default[n](u,A,p)(t)}return t}});var QCe=_(EB=>{\"use strict\";var kCe=EB&&EB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(EB,\"__esModule\",{value:!0});var qEt=kCe(dCe()),Z6=kCe(X6());EB.default=(t,e,r,o)=>{if(typeof r.style.borderStyle==\"string\"){let a=r.yogaNode.getComputedWidth(),n=r.yogaNode.getComputedHeight(),u=r.style.borderColor,A=qEt.default[r.style.borderStyle],p=Z6.default(A.topLeft+A.horizontal.repeat(a-2)+A.topRight,u,\"foreground\"),h=(Z6.default(A.vertical,u,\"foreground\")+`\n`).repeat(n-2),E=Z6.default(A.bottomLeft+A.horizontal.repeat(a-2)+A.bottomRight,u,\"foreground\");o.write(t,e,p,{transformers:[]}),o.write(t,e+1,h,{transformers:[]}),o.write(t+a-1,e+1,h,{transformers:[]}),o.write(t,e+n-1,E,{transformers:[]})}}});var RCe=_(CB=>{\"use strict\";var cm=CB&&CB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(CB,\"__esModule\",{value:!0});var GEt=cm(lm()),jEt=cm(L6()),YEt=cm(fCe()),WEt=cm(H6()),KEt=cm(pCe()),zEt=cm(G6()),VEt=cm(QCe()),JEt=(t,e)=>{var r;let o=(r=t.childNodes[0])===null||r===void 0?void 0:r.yogaNode;if(o){let a=o.getComputedLeft(),n=o.getComputedTop();e=`\n`.repeat(n)+YEt.default(e,a)}return e},FCe=(t,e,r)=>{var o;let{offsetX:a=0,offsetY:n=0,transformers:u=[],skipStaticElements:A}=r;if(A&&t.internal_static)return;let{yogaNode:p}=t;if(p){if(p.getDisplay()===GEt.default.DISPLAY_NONE)return;let h=a+p.getComputedLeft(),E=n+p.getComputedTop(),I=u;if(typeof t.internal_transform==\"function\"&&(I=[t.internal_transform,...u]),t.nodeName===\"ink-text\"){let v=zEt.default(t);if(v.length>0){let x=jEt.default(v),C=KEt.default(p);if(x>C){let R=(o=t.style.textWrap)!==null&&o!==void 0?o:\"wrap\";v=WEt.default(v,C,R)}v=JEt(t,v),e.write(h,E,v,{transformers:I})}return}if(t.nodeName===\"ink-box\"&&VEt.default(h,E,t,e),t.nodeName===\"ink-root\"||t.nodeName===\"ink-box\")for(let v of t.childNodes)FCe(v,e,{offsetX:h,offsetY:E,transformers:I,skipStaticElements:A})}};CB.default=FCe});var LCe=_((KKt,TCe)=>{\"use strict\";TCe.exports=t=>{t=Object.assign({onlyFirst:!1},t);let e=[\"[\\\\u001B\\\\u009B][[\\\\]()#;?]*(?:(?:(?:[a-zA-Z\\\\d]*(?:;[-a-zA-Z\\\\d\\\\/#&.:=?%@~_]*)*)?\\\\u0007)\",\"(?:(?:\\\\d{1,4}(?:;\\\\d{0,4})*)?[\\\\dA-PR-TZcf-ntqry=><~]))\"].join(\"|\");return new RegExp(e,t.onlyFirst?void 0:\"g\")}});var OCe=_((zKt,$6)=>{\"use strict\";var XEt=LCe(),NCe=t=>typeof t==\"string\"?t.replace(XEt(),\"\"):t;$6.exports=NCe;$6.exports.default=NCe});var _Ce=_((VKt,UCe)=>{\"use strict\";var MCe=\"[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]\";UCe.exports=t=>t&&t.exact?new RegExp(`^${MCe}$`):new RegExp(MCe,\"g\")});var qCe=_((JKt,eq)=>{\"use strict\";var ZEt=OCe(),$Et=_Ce(),HCe=t=>ZEt(t).replace($Et(),\" \").length;eq.exports=HCe;eq.exports.default=HCe});var YCe=_(wB=>{\"use strict\";var jCe=wB&&wB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(wB,\"__esModule\",{value:!0});var GCe=jCe(U6()),eCt=jCe(qCe()),tq=class{constructor(e){this.writes=[];let{width:r,height:o}=e;this.width=r,this.height=o}write(e,r,o,a){let{transformers:n}=a;!o||this.writes.push({x:e,y:r,text:o,transformers:n})}get(){let e=[];for(let o=0;o<this.height;o++)e.push(\" \".repeat(this.width));for(let o of this.writes){let{x:a,y:n,text:u,transformers:A}=o,p=u.split(`\n`),h=0;for(let E of p){let I=e[n+h];if(!I)continue;let v=eCt.default(E);for(let x of A)E=x(E);e[n+h]=GCe.default(I,0,a)+E+GCe.default(I,a+v),h++}}return{output:e.map(o=>o.trimRight()).join(`\n`),height:e.length}}};wB.default=tq});var zCe=_(IB=>{\"use strict\";var rq=IB&&IB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(IB,\"__esModule\",{value:!0});var tCt=rq(lm()),WCe=rq(RCe()),KCe=rq(YCe());IB.default=(t,e)=>{var r;if(t.yogaNode.setWidth(e),t.yogaNode){t.yogaNode.calculateLayout(void 0,void 0,tCt.default.DIRECTION_LTR);let o=new KCe.default({width:t.yogaNode.getComputedWidth(),height:t.yogaNode.getComputedHeight()});WCe.default(t,o,{skipStaticElements:!0});let a;!((r=t.staticNode)===null||r===void 0)&&r.yogaNode&&(a=new KCe.default({width:t.staticNode.yogaNode.getComputedWidth(),height:t.staticNode.yogaNode.getComputedHeight()}),WCe.default(t.staticNode,a,{skipStaticElements:!1}));let{output:n,height:u}=o.get();return{output:n,outputHeight:u,staticOutput:a?`${a.get().output}\n`:\"\"}}return{output:\"\",outputHeight:0,staticOutput:\"\"}}});var ZCe=_(($Kt,XCe)=>{\"use strict\";var VCe=ve(\"stream\"),JCe=[\"assert\",\"count\",\"countReset\",\"debug\",\"dir\",\"dirxml\",\"error\",\"group\",\"groupCollapsed\",\"groupEnd\",\"info\",\"log\",\"table\",\"time\",\"timeEnd\",\"timeLog\",\"trace\",\"warn\"],nq={},rCt=t=>{let e=new VCe.PassThrough,r=new VCe.PassThrough;e.write=a=>t(\"stdout\",a),r.write=a=>t(\"stderr\",a);let o=new console.Console(e,r);for(let a of JCe)nq[a]=console[a],console[a]=o[a];return()=>{for(let a of JCe)console[a]=nq[a];nq={}}};XCe.exports=rCt});var sq=_(iq=>{\"use strict\";Object.defineProperty(iq,\"__esModule\",{value:!0});iq.default=new WeakMap});var aq=_(oq=>{\"use strict\";Object.defineProperty(oq,\"__esModule\",{value:!0});var nCt=on(),$Ce=nCt.createContext({exit:()=>{}});$Ce.displayName=\"InternalAppContext\";oq.default=$Ce});var cq=_(lq=>{\"use strict\";Object.defineProperty(lq,\"__esModule\",{value:!0});var iCt=on(),ewe=iCt.createContext({stdin:void 0,setRawMode:()=>{},isRawModeSupported:!1,internal_exitOnCtrlC:!0});ewe.displayName=\"InternalStdinContext\";lq.default=ewe});var Aq=_(uq=>{\"use strict\";Object.defineProperty(uq,\"__esModule\",{value:!0});var sCt=on(),twe=sCt.createContext({stdout:void 0,write:()=>{}});twe.displayName=\"InternalStdoutContext\";uq.default=twe});var pq=_(fq=>{\"use strict\";Object.defineProperty(fq,\"__esModule\",{value:!0});var oCt=on(),rwe=oCt.createContext({stderr:void 0,write:()=>{}});rwe.displayName=\"InternalStderrContext\";fq.default=rwe});var iQ=_(hq=>{\"use strict\";Object.defineProperty(hq,\"__esModule\",{value:!0});var aCt=on(),nwe=aCt.createContext({activeId:void 0,add:()=>{},remove:()=>{},activate:()=>{},deactivate:()=>{},enableFocus:()=>{},disableFocus:()=>{},focusNext:()=>{},focusPrevious:()=>{}});nwe.displayName=\"InternalFocusContext\";hq.default=nwe});var swe=_((ozt,iwe)=>{\"use strict\";var lCt=/[|\\\\{}()[\\]^$+*?.-]/g;iwe.exports=t=>{if(typeof t!=\"string\")throw new TypeError(\"Expected a string\");return t.replace(lCt,\"\\\\$&\")}});var cwe=_((azt,lwe)=>{\"use strict\";var cCt=swe(),uCt=typeof process==\"object\"&&process&&typeof process.cwd==\"function\"?process.cwd():\".\",awe=[].concat(ve(\"module\").builtinModules,\"bootstrap_node\",\"node\").map(t=>new RegExp(`(?:\\\\((?:node:)?${t}(?:\\\\.js)?:\\\\d+:\\\\d+\\\\)$|^\\\\s*at (?:node:)?${t}(?:\\\\.js)?:\\\\d+:\\\\d+$)`));awe.push(/\\((?:node:)?internal\\/[^:]+:\\d+:\\d+\\)$/,/\\s*at (?:node:)?internal\\/[^:]+:\\d+:\\d+$/,/\\/\\.node-spawn-wrap-\\w+-\\w+\\/node:\\d+:\\d+\\)?$/);var BB=class{constructor(e){e={ignoredPackages:[],...e},\"internals\"in e||(e.internals=BB.nodeInternals()),\"cwd\"in e||(e.cwd=uCt),this._cwd=e.cwd.replace(/\\\\/g,\"/\"),this._internals=[].concat(e.internals,ACt(e.ignoredPackages)),this._wrapCallSite=e.wrapCallSite||!1}static nodeInternals(){return[...awe]}clean(e,r=0){r=\" \".repeat(r),Array.isArray(e)||(e=e.split(`\n`)),!/^\\s*at /.test(e[0])&&/^\\s*at /.test(e[1])&&(e=e.slice(1));let o=!1,a=null,n=[];return e.forEach(u=>{if(u=u.replace(/\\\\/g,\"/\"),this._internals.some(p=>p.test(u)))return;let A=/^\\s*at /.test(u);o?u=u.trimEnd().replace(/^(\\s+)at /,\"$1\"):(u=u.trim(),A&&(u=u.slice(3))),u=u.replace(`${this._cwd}/`,\"\"),u&&(A?(a&&(n.push(a),a=null),n.push(u)):(o=!0,a=u))}),n.map(u=>`${r}${u}\n`).join(\"\")}captureString(e,r=this.captureString){typeof e==\"function\"&&(r=e,e=1/0);let{stackTraceLimit:o}=Error;e&&(Error.stackTraceLimit=e);let a={};Error.captureStackTrace(a,r);let{stack:n}=a;return Error.stackTraceLimit=o,this.clean(n)}capture(e,r=this.capture){typeof e==\"function\"&&(r=e,e=1/0);let{prepareStackTrace:o,stackTraceLimit:a}=Error;Error.prepareStackTrace=(A,p)=>this._wrapCallSite?p.map(this._wrapCallSite):p,e&&(Error.stackTraceLimit=e);let n={};Error.captureStackTrace(n,r);let{stack:u}=n;return Object.assign(Error,{prepareStackTrace:o,stackTraceLimit:a}),u}at(e=this.at){let[r]=this.capture(1,e);if(!r)return{};let o={line:r.getLineNumber(),column:r.getColumnNumber()};owe(o,r.getFileName(),this._cwd),r.isConstructor()&&(o.constructor=!0),r.isEval()&&(o.evalOrigin=r.getEvalOrigin()),r.isNative()&&(o.native=!0);let a;try{a=r.getTypeName()}catch{}a&&a!==\"Object\"&&a!==\"[object Object]\"&&(o.type=a);let n=r.getFunctionName();n&&(o.function=n);let u=r.getMethodName();return u&&n!==u&&(o.method=u),o}parseLine(e){let r=e&&e.match(fCt);if(!r)return null;let o=r[1]===\"new\",a=r[2],n=r[3],u=r[4],A=Number(r[5]),p=Number(r[6]),h=r[7],E=r[8],I=r[9],v=r[10]===\"native\",x=r[11]===\")\",C,R={};if(E&&(R.line=Number(E)),I&&(R.column=Number(I)),x&&h){let N=0;for(let U=h.length-1;U>0;U--)if(h.charAt(U)===\")\")N++;else if(h.charAt(U)===\"(\"&&h.charAt(U-1)===\" \"&&(N--,N===-1&&h.charAt(U-1)===\" \")){let V=h.slice(0,U-1);h=h.slice(U+1),a+=` (${V}`;break}}if(a){let N=a.match(pCt);N&&(a=N[1],C=N[2])}return owe(R,h,this._cwd),o&&(R.constructor=!0),n&&(R.evalOrigin=n,R.evalLine=A,R.evalColumn=p,R.evalFile=u&&u.replace(/\\\\/g,\"/\")),v&&(R.native=!0),a&&(R.function=a),C&&a!==C&&(R.method=C),R}};function owe(t,e,r){e&&(e=e.replace(/\\\\/g,\"/\"),e.startsWith(`${r}/`)&&(e=e.slice(r.length+1)),t.file=e)}function ACt(t){if(t.length===0)return[];let e=t.map(r=>cCt(r));return new RegExp(`[/\\\\\\\\]node_modules[/\\\\\\\\](?:${e.join(\"|\")})[/\\\\\\\\][^:]+:\\\\d+:\\\\d+`)}var fCt=new RegExp(\"^(?:\\\\s*at )?(?:(new) )?(?:(.*?) \\\\()?(?:eval at ([^ ]+) \\\\((.+?):(\\\\d+):(\\\\d+)\\\\), )?(?:(.+?):(\\\\d+):(\\\\d+)|(native))(\\\\)?)$\"),pCt=/^(.*?) \\[as (.*?)\\]$/;lwe.exports=BB});var Awe=_((lzt,uwe)=>{\"use strict\";uwe.exports=(t,e)=>t.replace(/^\\t+/gm,r=>\" \".repeat(r.length*(e||2)))});var pwe=_((czt,fwe)=>{\"use strict\";var hCt=Awe(),gCt=(t,e)=>{let r=[],o=t-e,a=t+e;for(let n=o;n<=a;n++)r.push(n);return r};fwe.exports=(t,e,r)=>{if(typeof t!=\"string\")throw new TypeError(\"Source code is missing.\");if(!e||e<1)throw new TypeError(\"Line number must start from `1`.\");if(t=hCt(t).split(/\\r?\\n/),!(e>t.length))return r={around:3,...r},gCt(e,r.around).filter(o=>t[o-1]!==void 0).map(o=>({line:o,value:t[o-1]}))}});var sQ=_(nu=>{\"use strict\";var dCt=nu&&nu.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),mCt=nu&&nu.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,\"default\",{enumerable:!0,value:e})}:function(t,e){t.default=e}),yCt=nu&&nu.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!==\"default\"&&Object.hasOwnProperty.call(t,r)&&dCt(e,t,r);return mCt(e,t),e},ECt=nu&&nu.__rest||function(t,e){var r={};for(var o in t)Object.prototype.hasOwnProperty.call(t,o)&&e.indexOf(o)<0&&(r[o]=t[o]);if(t!=null&&typeof Object.getOwnPropertySymbols==\"function\")for(var a=0,o=Object.getOwnPropertySymbols(t);a<o.length;a++)e.indexOf(o[a])<0&&Object.prototype.propertyIsEnumerable.call(t,o[a])&&(r[o[a]]=t[o[a]]);return r};Object.defineProperty(nu,\"__esModule\",{value:!0});var hwe=yCt(on()),gq=hwe.forwardRef((t,e)=>{var{children:r}=t,o=ECt(t,[\"children\"]);let a=Object.assign(Object.assign({},o),{marginLeft:o.marginLeft||o.marginX||o.margin||0,marginRight:o.marginRight||o.marginX||o.margin||0,marginTop:o.marginTop||o.marginY||o.margin||0,marginBottom:o.marginBottom||o.marginY||o.margin||0,paddingLeft:o.paddingLeft||o.paddingX||o.padding||0,paddingRight:o.paddingRight||o.paddingX||o.padding||0,paddingTop:o.paddingTop||o.paddingY||o.padding||0,paddingBottom:o.paddingBottom||o.paddingY||o.padding||0});return hwe.default.createElement(\"ink-box\",{ref:e,style:a},r)});gq.displayName=\"Box\";gq.defaultProps={flexDirection:\"row\",flexGrow:0,flexShrink:1};nu.default=gq});var yq=_(vB=>{\"use strict\";var dq=vB&&vB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(vB,\"__esModule\",{value:!0});var CCt=dq(on()),qC=dq(rQ()),gwe=dq(X6()),mq=({color:t,backgroundColor:e,dimColor:r,bold:o,italic:a,underline:n,strikethrough:u,inverse:A,wrap:p,children:h})=>{if(h==null)return null;let E=I=>(r&&(I=qC.default.dim(I)),t&&(I=gwe.default(I,t,\"foreground\")),e&&(I=gwe.default(I,e,\"background\")),o&&(I=qC.default.bold(I)),a&&(I=qC.default.italic(I)),n&&(I=qC.default.underline(I)),u&&(I=qC.default.strikethrough(I)),A&&(I=qC.default.inverse(I)),I);return CCt.default.createElement(\"ink-text\",{style:{flexGrow:0,flexShrink:1,flexDirection:\"row\",textWrap:p},internal_transform:E},h)};mq.displayName=\"Text\";mq.defaultProps={dimColor:!1,bold:!1,italic:!1,underline:!1,strikethrough:!1,wrap:\"wrap\"};vB.default=mq});var Ewe=_(iu=>{\"use strict\";var wCt=iu&&iu.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),ICt=iu&&iu.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,\"default\",{enumerable:!0,value:e})}:function(t,e){t.default=e}),BCt=iu&&iu.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!==\"default\"&&Object.hasOwnProperty.call(t,r)&&wCt(e,t,r);return ICt(e,t),e},DB=iu&&iu.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(iu,\"__esModule\",{value:!0});var dwe=BCt(ve(\"fs\")),fs=DB(on()),mwe=DB(cwe()),vCt=DB(pwe()),Zf=DB(sQ()),gA=DB(yq()),ywe=new mwe.default({cwd:process.cwd(),internals:mwe.default.nodeInternals()}),DCt=({error:t})=>{let e=t.stack?t.stack.split(`\n`).slice(1):void 0,r=e?ywe.parseLine(e[0]):void 0,o,a=0;if(r?.file&&r?.line&&dwe.existsSync(r.file)){let n=dwe.readFileSync(r.file,\"utf8\");if(o=vCt.default(n,r.line),o)for(let{line:u}of o)a=Math.max(a,String(u).length)}return fs.default.createElement(Zf.default,{flexDirection:\"column\",padding:1},fs.default.createElement(Zf.default,null,fs.default.createElement(gA.default,{backgroundColor:\"red\",color:\"white\"},\" \",\"ERROR\",\" \"),fs.default.createElement(gA.default,null,\" \",t.message)),r&&fs.default.createElement(Zf.default,{marginTop:1},fs.default.createElement(gA.default,{dimColor:!0},r.file,\":\",r.line,\":\",r.column)),r&&o&&fs.default.createElement(Zf.default,{marginTop:1,flexDirection:\"column\"},o.map(({line:n,value:u})=>fs.default.createElement(Zf.default,{key:n},fs.default.createElement(Zf.default,{width:a+1},fs.default.createElement(gA.default,{dimColor:n!==r.line,backgroundColor:n===r.line?\"red\":void 0,color:n===r.line?\"white\":void 0},String(n).padStart(a,\" \"),\":\")),fs.default.createElement(gA.default,{key:n,backgroundColor:n===r.line?\"red\":void 0,color:n===r.line?\"white\":void 0},\" \"+u)))),t.stack&&fs.default.createElement(Zf.default,{marginTop:1,flexDirection:\"column\"},t.stack.split(`\n`).slice(1).map(n=>{let u=ywe.parseLine(n);return u?fs.default.createElement(Zf.default,{key:n},fs.default.createElement(gA.default,{dimColor:!0},\"- \"),fs.default.createElement(gA.default,{dimColor:!0,bold:!0},u.function),fs.default.createElement(gA.default,{dimColor:!0,color:\"gray\"},\" \",\"(\",u.file,\":\",u.line,\":\",u.column,\")\")):fs.default.createElement(Zf.default,{key:n},fs.default.createElement(gA.default,{dimColor:!0},\"- \"),fs.default.createElement(gA.default,{dimColor:!0,bold:!0},n))})))};iu.default=DCt});var wwe=_(su=>{\"use strict\";var PCt=su&&su.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),SCt=su&&su.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,\"default\",{enumerable:!0,value:e})}:function(t,e){t.default=e}),bCt=su&&su.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!==\"default\"&&Object.hasOwnProperty.call(t,r)&&PCt(e,t,r);return SCt(e,t),e},Am=su&&su.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(su,\"__esModule\",{value:!0});var um=bCt(on()),Cwe=Am(g6()),xCt=Am(aq()),kCt=Am(cq()),QCt=Am(Aq()),FCt=Am(pq()),RCt=Am(iQ()),TCt=Am(Ewe()),LCt=\"\t\",NCt=\"\\x1B[Z\",OCt=\"\\x1B\",oQ=class extends um.PureComponent{constructor(){super(...arguments),this.state={isFocusEnabled:!0,activeFocusId:void 0,focusables:[],error:void 0},this.rawModeEnabledCount=0,this.handleSetRawMode=e=>{let{stdin:r}=this.props;if(!this.isRawModeSupported())throw r===process.stdin?new Error(`Raw mode is not supported on the current process.stdin, which Ink uses as input stream by default.\nRead about how to prevent this error on https://github.com/vadimdemedes/ink/#israwmodesupported`):new Error(`Raw mode is not supported on the stdin provided to Ink.\nRead about how to prevent this error on https://github.com/vadimdemedes/ink/#israwmodesupported`);if(r.setEncoding(\"utf8\"),e){this.rawModeEnabledCount===0&&(r.addListener(\"data\",this.handleInput),r.resume(),r.setRawMode(!0)),this.rawModeEnabledCount++;return}--this.rawModeEnabledCount===0&&(r.setRawMode(!1),r.removeListener(\"data\",this.handleInput),r.pause())},this.handleInput=e=>{e===\"\u0003\"&&this.props.exitOnCtrlC&&this.handleExit(),e===OCt&&this.state.activeFocusId&&this.setState({activeFocusId:void 0}),this.state.isFocusEnabled&&this.state.focusables.length>0&&(e===LCt&&this.focusNext(),e===NCt&&this.focusPrevious())},this.handleExit=e=>{this.isRawModeSupported()&&this.handleSetRawMode(!1),this.props.onExit(e)},this.enableFocus=()=>{this.setState({isFocusEnabled:!0})},this.disableFocus=()=>{this.setState({isFocusEnabled:!1})},this.focusNext=()=>{this.setState(e=>{let r=e.focusables[0].id;return{activeFocusId:this.findNextFocusable(e)||r}})},this.focusPrevious=()=>{this.setState(e=>{let r=e.focusables[e.focusables.length-1].id;return{activeFocusId:this.findPreviousFocusable(e)||r}})},this.addFocusable=(e,{autoFocus:r})=>{this.setState(o=>{let a=o.activeFocusId;return!a&&r&&(a=e),{activeFocusId:a,focusables:[...o.focusables,{id:e,isActive:!0}]}})},this.removeFocusable=e=>{this.setState(r=>({activeFocusId:r.activeFocusId===e?void 0:r.activeFocusId,focusables:r.focusables.filter(o=>o.id!==e)}))},this.activateFocusable=e=>{this.setState(r=>({focusables:r.focusables.map(o=>o.id!==e?o:{id:e,isActive:!0})}))},this.deactivateFocusable=e=>{this.setState(r=>({activeFocusId:r.activeFocusId===e?void 0:r.activeFocusId,focusables:r.focusables.map(o=>o.id!==e?o:{id:e,isActive:!1})}))},this.findNextFocusable=e=>{let r=e.focusables.findIndex(o=>o.id===e.activeFocusId);for(let o=r+1;o<e.focusables.length;o++)if(e.focusables[o].isActive)return e.focusables[o].id},this.findPreviousFocusable=e=>{let r=e.focusables.findIndex(o=>o.id===e.activeFocusId);for(let o=r-1;o>=0;o--)if(e.focusables[o].isActive)return e.focusables[o].id}}static getDerivedStateFromError(e){return{error:e}}isRawModeSupported(){return this.props.stdin.isTTY}render(){return um.default.createElement(xCt.default.Provider,{value:{exit:this.handleExit}},um.default.createElement(kCt.default.Provider,{value:{stdin:this.props.stdin,setRawMode:this.handleSetRawMode,isRawModeSupported:this.isRawModeSupported(),internal_exitOnCtrlC:this.props.exitOnCtrlC}},um.default.createElement(QCt.default.Provider,{value:{stdout:this.props.stdout,write:this.props.writeToStdout}},um.default.createElement(FCt.default.Provider,{value:{stderr:this.props.stderr,write:this.props.writeToStderr}},um.default.createElement(RCt.default.Provider,{value:{activeId:this.state.activeFocusId,add:this.addFocusable,remove:this.removeFocusable,activate:this.activateFocusable,deactivate:this.deactivateFocusable,enableFocus:this.enableFocus,disableFocus:this.disableFocus,focusNext:this.focusNext,focusPrevious:this.focusPrevious}},this.state.error?um.default.createElement(TCt.default,{error:this.state.error}):this.props.children)))))}componentDidMount(){Cwe.default.hide(this.props.stdout)}componentWillUnmount(){Cwe.default.show(this.props.stdout),this.isRawModeSupported()&&this.handleSetRawMode(!1)}componentDidCatch(e){this.handleExit(e)}};su.default=oQ;oQ.displayName=\"InternalApp\"});var vwe=_(ou=>{\"use strict\";var MCt=ou&&ou.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),UCt=ou&&ou.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,\"default\",{enumerable:!0,value:e})}:function(t,e){t.default=e}),_Ct=ou&&ou.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!==\"default\"&&Object.hasOwnProperty.call(t,r)&&MCt(e,t,r);return UCt(e,t),e},au=ou&&ou.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(ou,\"__esModule\",{value:!0});var HCt=au(on()),Iwe=lM(),qCt=au(cEe()),GCt=au(u6()),jCt=au(gEe()),YCt=au(mEe()),Eq=au(uCe()),WCt=au(zCe()),KCt=au(h6()),zCt=au(ZCe()),VCt=_Ct(j6()),JCt=au(sq()),XCt=au(wwe()),GC=process.env.CI===\"false\"?!1:jCt.default,Bwe=()=>{},Cq=class{constructor(e){this.resolveExitPromise=()=>{},this.rejectExitPromise=()=>{},this.unsubscribeExit=()=>{},this.onRender=()=>{if(this.isUnmounted)return;let{output:r,outputHeight:o,staticOutput:a}=WCt.default(this.rootNode,this.options.stdout.columns||80),n=a&&a!==`\n`;if(this.options.debug){n&&(this.fullStaticOutput+=a),this.options.stdout.write(this.fullStaticOutput+r);return}if(GC){n&&this.options.stdout.write(a),this.lastOutput=r;return}if(n&&(this.fullStaticOutput+=a),o>=this.options.stdout.rows){this.options.stdout.write(GCt.default.clearTerminal+this.fullStaticOutput+r),this.lastOutput=r;return}n&&(this.log.clear(),this.options.stdout.write(a),this.log(r)),!n&&r!==this.lastOutput&&this.throttledLog(r),this.lastOutput=r},YCt.default(this),this.options=e,this.rootNode=VCt.createNode(\"ink-root\"),this.rootNode.onRender=e.debug?this.onRender:Iwe(this.onRender,32,{leading:!0,trailing:!0}),this.rootNode.onImmediateRender=this.onRender,this.log=qCt.default.create(e.stdout),this.throttledLog=e.debug?this.log:Iwe(this.log,void 0,{leading:!0,trailing:!0}),this.isUnmounted=!1,this.lastOutput=\"\",this.fullStaticOutput=\"\",this.container=Eq.default.createContainer(this.rootNode,!1,!1),this.unsubscribeExit=KCt.default(this.unmount,{alwaysLast:!1}),e.patchConsole&&this.patchConsole(),GC||(e.stdout.on(\"resize\",this.onRender),this.unsubscribeResize=()=>{e.stdout.off(\"resize\",this.onRender)})}render(e){let r=HCt.default.createElement(XCt.default,{stdin:this.options.stdin,stdout:this.options.stdout,stderr:this.options.stderr,writeToStdout:this.writeToStdout,writeToStderr:this.writeToStderr,exitOnCtrlC:this.options.exitOnCtrlC,onExit:this.unmount},e);Eq.default.updateContainer(r,this.container,null,Bwe)}writeToStdout(e){if(!this.isUnmounted){if(this.options.debug){this.options.stdout.write(e+this.fullStaticOutput+this.lastOutput);return}if(GC){this.options.stdout.write(e);return}this.log.clear(),this.options.stdout.write(e),this.log(this.lastOutput)}}writeToStderr(e){if(!this.isUnmounted){if(this.options.debug){this.options.stderr.write(e),this.options.stdout.write(this.fullStaticOutput+this.lastOutput);return}if(GC){this.options.stderr.write(e);return}this.log.clear(),this.options.stderr.write(e),this.log(this.lastOutput)}}unmount(e){this.isUnmounted||(this.onRender(),this.unsubscribeExit(),typeof this.restoreConsole==\"function\"&&this.restoreConsole(),typeof this.unsubscribeResize==\"function\"&&this.unsubscribeResize(),GC?this.options.stdout.write(this.lastOutput+`\n`):this.options.debug||this.log.done(),this.isUnmounted=!0,Eq.default.updateContainer(null,this.container,null,Bwe),JCt.default.delete(this.options.stdout),e instanceof Error?this.rejectExitPromise(e):this.resolveExitPromise())}waitUntilExit(){return this.exitPromise||(this.exitPromise=new Promise((e,r)=>{this.resolveExitPromise=e,this.rejectExitPromise=r})),this.exitPromise}clear(){!GC&&!this.options.debug&&this.log.clear()}patchConsole(){this.options.debug||(this.restoreConsole=zCt.default((e,r)=>{e===\"stdout\"&&this.writeToStdout(r),e===\"stderr\"&&(r.startsWith(\"The above error occurred\")||this.writeToStderr(r))}))}};ou.default=Cq});var Pwe=_(PB=>{\"use strict\";var Dwe=PB&&PB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(PB,\"__esModule\",{value:!0});var ZCt=Dwe(vwe()),aQ=Dwe(sq()),$Ct=ve(\"stream\"),ewt=(t,e)=>{let r=Object.assign({stdout:process.stdout,stdin:process.stdin,stderr:process.stderr,debug:!1,exitOnCtrlC:!0,patchConsole:!0},twt(e)),o=rwt(r.stdout,()=>new ZCt.default(r));return o.render(t),{rerender:o.render,unmount:()=>o.unmount(),waitUntilExit:o.waitUntilExit,cleanup:()=>aQ.default.delete(r.stdout),clear:o.clear}};PB.default=ewt;var twt=(t={})=>t instanceof $Ct.Stream?{stdout:t,stdin:process.stdin}:t,rwt=(t,e)=>{let r;return aQ.default.has(t)?r=aQ.default.get(t):(r=e(),aQ.default.set(t,r)),r}});var bwe=_($f=>{\"use strict\";var nwt=$f&&$f.__createBinding||(Object.create?function(t,e,r,o){o===void 0&&(o=r),Object.defineProperty(t,o,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,o){o===void 0&&(o=r),t[o]=e[r]}),iwt=$f&&$f.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,\"default\",{enumerable:!0,value:e})}:function(t,e){t.default=e}),swt=$f&&$f.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(t!=null)for(var r in t)r!==\"default\"&&Object.hasOwnProperty.call(t,r)&&nwt(e,t,r);return iwt(e,t),e};Object.defineProperty($f,\"__esModule\",{value:!0});var SB=swt(on()),Swe=t=>{let{items:e,children:r,style:o}=t,[a,n]=SB.useState(0),u=SB.useMemo(()=>e.slice(a),[e,a]);SB.useLayoutEffect(()=>{n(e.length)},[e.length]);let A=u.map((h,E)=>r(h,a+E)),p=SB.useMemo(()=>Object.assign({position:\"absolute\",flexDirection:\"column\"},o),[o]);return SB.default.createElement(\"ink-box\",{internal_static:!0,style:p},A)};Swe.displayName=\"Static\";$f.default=Swe});var kwe=_(bB=>{\"use strict\";var owt=bB&&bB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(bB,\"__esModule\",{value:!0});var awt=owt(on()),xwe=({children:t,transform:e})=>t==null?null:awt.default.createElement(\"ink-text\",{style:{flexGrow:0,flexShrink:1,flexDirection:\"row\"},internal_transform:e},t);xwe.displayName=\"Transform\";bB.default=xwe});var Fwe=_(xB=>{\"use strict\";var lwt=xB&&xB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(xB,\"__esModule\",{value:!0});var cwt=lwt(on()),Qwe=({count:t=1})=>cwt.default.createElement(\"ink-text\",null,`\n`.repeat(t));Qwe.displayName=\"Newline\";xB.default=Qwe});var Lwe=_(kB=>{\"use strict\";var Rwe=kB&&kB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(kB,\"__esModule\",{value:!0});var uwt=Rwe(on()),Awt=Rwe(sQ()),Twe=()=>uwt.default.createElement(Awt.default,{flexGrow:1});Twe.displayName=\"Spacer\";kB.default=Twe});var lQ=_(QB=>{\"use strict\";var fwt=QB&&QB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(QB,\"__esModule\",{value:!0});var pwt=on(),hwt=fwt(cq()),gwt=()=>pwt.useContext(hwt.default);QB.default=gwt});var Owe=_(FB=>{\"use strict\";var dwt=FB&&FB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(FB,\"__esModule\",{value:!0});var Nwe=on(),mwt=dwt(lQ()),ywt=(t,e={})=>{let{stdin:r,setRawMode:o,internal_exitOnCtrlC:a}=mwt.default();Nwe.useEffect(()=>{if(e.isActive!==!1)return o(!0),()=>{o(!1)}},[e.isActive,o]),Nwe.useEffect(()=>{if(e.isActive===!1)return;let n=u=>{let A=String(u),p={upArrow:A===\"\\x1B[A\",downArrow:A===\"\\x1B[B\",leftArrow:A===\"\\x1B[D\",rightArrow:A===\"\\x1B[C\",pageDown:A===\"\\x1B[6~\",pageUp:A===\"\\x1B[5~\",return:A===\"\\r\",escape:A===\"\\x1B\",ctrl:!1,shift:!1,tab:A===\"\t\"||A===\"\\x1B[Z\",backspace:A===\"\\b\",delete:A===\"\\x7F\"||A===\"\\x1B[3~\",meta:!1};A<=\"\u001a\"&&!p.return&&(A=String.fromCharCode(A.charCodeAt(0)+\"a\".charCodeAt(0)-1),p.ctrl=!0),A.startsWith(\"\\x1B\")&&(A=A.slice(1),p.meta=!0);let h=A>=\"A\"&&A<=\"Z\",E=A>=\"\\u0410\"&&A<=\"\\u042F\";A.length===1&&(h||E)&&(p.shift=!0),p.tab&&A===\"[Z\"&&(p.shift=!0),(p.tab||p.backspace||p.delete)&&(A=\"\"),(!(A===\"c\"&&p.ctrl)||!a)&&t(A,p)};return r?.on(\"data\",n),()=>{r?.off(\"data\",n)}},[e.isActive,r,a,t])};FB.default=ywt});var Mwe=_(RB=>{\"use strict\";var Ewt=RB&&RB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(RB,\"__esModule\",{value:!0});var Cwt=on(),wwt=Ewt(aq()),Iwt=()=>Cwt.useContext(wwt.default);RB.default=Iwt});var Uwe=_(TB=>{\"use strict\";var Bwt=TB&&TB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(TB,\"__esModule\",{value:!0});var vwt=on(),Dwt=Bwt(Aq()),Pwt=()=>vwt.useContext(Dwt.default);TB.default=Pwt});var _we=_(LB=>{\"use strict\";var Swt=LB&&LB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(LB,\"__esModule\",{value:!0});var bwt=on(),xwt=Swt(pq()),kwt=()=>bwt.useContext(xwt.default);LB.default=kwt});var qwe=_(OB=>{\"use strict\";var Hwe=OB&&OB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(OB,\"__esModule\",{value:!0});var NB=on(),Qwt=Hwe(iQ()),Fwt=Hwe(lQ()),Rwt=({isActive:t=!0,autoFocus:e=!1}={})=>{let{isRawModeSupported:r,setRawMode:o}=Fwt.default(),{activeId:a,add:n,remove:u,activate:A,deactivate:p}=NB.useContext(Qwt.default),h=NB.useMemo(()=>Math.random().toString().slice(2,7),[]);return NB.useEffect(()=>(n(h,{autoFocus:e}),()=>{u(h)}),[h,e]),NB.useEffect(()=>{t?A(h):p(h)},[t,h]),NB.useEffect(()=>{if(!(!r||!t))return o(!0),()=>{o(!1)}},[t]),{isFocused:Boolean(h)&&a===h}};OB.default=Rwt});var Gwe=_(MB=>{\"use strict\";var Twt=MB&&MB.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(MB,\"__esModule\",{value:!0});var Lwt=on(),Nwt=Twt(iQ()),Owt=()=>{let t=Lwt.useContext(Nwt.default);return{enableFocus:t.enableFocus,disableFocus:t.disableFocus,focusNext:t.focusNext,focusPrevious:t.focusPrevious}};MB.default=Owt});var jwe=_(wq=>{\"use strict\";Object.defineProperty(wq,\"__esModule\",{value:!0});wq.default=t=>{var e,r,o,a;return{width:(r=(e=t.yogaNode)===null||e===void 0?void 0:e.getComputedWidth())!==null&&r!==void 0?r:0,height:(a=(o=t.yogaNode)===null||o===void 0?void 0:o.getComputedHeight())!==null&&a!==void 0?a:0}}});var sc=_(ro=>{\"use strict\";Object.defineProperty(ro,\"__esModule\",{value:!0});var Mwt=Pwe();Object.defineProperty(ro,\"render\",{enumerable:!0,get:function(){return Mwt.default}});var Uwt=sQ();Object.defineProperty(ro,\"Box\",{enumerable:!0,get:function(){return Uwt.default}});var _wt=yq();Object.defineProperty(ro,\"Text\",{enumerable:!0,get:function(){return _wt.default}});var Hwt=bwe();Object.defineProperty(ro,\"Static\",{enumerable:!0,get:function(){return Hwt.default}});var qwt=kwe();Object.defineProperty(ro,\"Transform\",{enumerable:!0,get:function(){return qwt.default}});var Gwt=Fwe();Object.defineProperty(ro,\"Newline\",{enumerable:!0,get:function(){return Gwt.default}});var jwt=Lwe();Object.defineProperty(ro,\"Spacer\",{enumerable:!0,get:function(){return jwt.default}});var Ywt=Owe();Object.defineProperty(ro,\"useInput\",{enumerable:!0,get:function(){return Ywt.default}});var Wwt=Mwe();Object.defineProperty(ro,\"useApp\",{enumerable:!0,get:function(){return Wwt.default}});var Kwt=lQ();Object.defineProperty(ro,\"useStdin\",{enumerable:!0,get:function(){return Kwt.default}});var zwt=Uwe();Object.defineProperty(ro,\"useStdout\",{enumerable:!0,get:function(){return zwt.default}});var Vwt=_we();Object.defineProperty(ro,\"useStderr\",{enumerable:!0,get:function(){return Vwt.default}});var Jwt=qwe();Object.defineProperty(ro,\"useFocus\",{enumerable:!0,get:function(){return Jwt.default}});var Xwt=Gwe();Object.defineProperty(ro,\"useFocusManager\",{enumerable:!0,get:function(){return Xwt.default}});var Zwt=jwe();Object.defineProperty(ro,\"measureElement\",{enumerable:!0,get:function(){return Zwt.default}})});var Bq={};zt(Bq,{Gem:()=>Iq});var Ywe,fm,Iq,cQ=Et(()=>{Ywe=$e(sc()),fm=$e(on()),Iq=(0,fm.memo)(({active:t})=>{let e=(0,fm.useMemo)(()=>t?\"\\u25C9\":\"\\u25EF\",[t]),r=(0,fm.useMemo)(()=>t?\"green\":\"yellow\",[t]);return fm.default.createElement(Ywe.Text,{color:r},e)})});var Kwe={};zt(Kwe,{useKeypress:()=>pm});function pm({active:t},e,r){let{stdin:o}=(0,Wwe.useStdin)(),a=(0,uQ.useCallback)((n,u)=>e(n,u),r);(0,uQ.useEffect)(()=>{if(!(!t||!o))return o.on(\"keypress\",a),()=>{o.off(\"keypress\",a)}},[t,a,o])}var Wwe,uQ,UB=Et(()=>{Wwe=$e(sc()),uQ=$e(on())});var Vwe={};zt(Vwe,{FocusRequest:()=>zwe,useFocusRequest:()=>vq});var zwe,vq,Dq=Et(()=>{UB();zwe=(r=>(r.BEFORE=\"before\",r.AFTER=\"after\",r))(zwe||{}),vq=function({active:t},e,r){pm({active:t},(o,a)=>{a.name===\"tab\"&&(a.shift?e(\"before\"):e(\"after\"))},r)}});var Jwe={};zt(Jwe,{useListInput:()=>_B});var _B,AQ=Et(()=>{UB();_B=function(t,e,{active:r,minus:o,plus:a,set:n,loop:u=!0}){pm({active:r},(A,p)=>{let h=e.indexOf(t);switch(p.name){case o:{let E=h-1;if(u){n(e[(e.length+E)%e.length]);return}if(E<0)return;n(e[E])}break;case a:{let E=h+1;if(u){n(e[E%e.length]);return}if(E>=e.length)return;n(e[E])}break}},[e,t,a,n,u])}});var fQ={};zt(fQ,{ScrollableItems:()=>$wt});var w0,Na,$wt,pQ=Et(()=>{w0=$e(sc()),Na=$e(on());Dq();AQ();$wt=({active:t=!0,children:e=[],radius:r=10,size:o=1,loop:a=!0,onFocusRequest:n,willReachEnd:u})=>{let A=N=>{if(N.key===null)throw new Error(\"Expected all children to have a key\");return N.key},p=Na.default.Children.map(e,N=>A(N)),h=p[0],[E,I]=(0,Na.useState)(h),v=p.indexOf(E);(0,Na.useEffect)(()=>{p.includes(E)||I(h)},[e]),(0,Na.useEffect)(()=>{u&&v>=p.length-2&&u()},[v]),vq({active:t&&!!n},N=>{n?.(N)},[n]),_B(E,p,{active:t,minus:\"up\",plus:\"down\",set:I,loop:a});let x=v-r,C=v+r;C>p.length&&(x-=C-p.length,C=p.length),x<0&&(C+=-x,x=0),C>=p.length&&(C=p.length-1);let R=[];for(let N=x;N<=C;++N){let U=p[N],V=t&&U===E;R.push(Na.default.createElement(w0.Box,{key:U,height:o},Na.default.createElement(w0.Box,{marginLeft:1,marginRight:1},Na.default.createElement(w0.Text,null,V?Na.default.createElement(w0.Text,{color:\"cyan\",bold:!0},\">\"):\" \")),Na.default.createElement(w0.Box,null,Na.default.cloneElement(e[N],{active:V}))))}return Na.default.createElement(w0.Box,{flexDirection:\"column\",width:\"100%\"},R)}});var Xwe,ep,Zwe,Pq,$we,Sq=Et(()=>{Xwe=$e(sc()),ep=$e(on()),Zwe=ve(\"readline\"),Pq=ep.default.createContext(null),$we=({children:t})=>{let{stdin:e,setRawMode:r}=(0,Xwe.useStdin)();(0,ep.useEffect)(()=>{r&&r(!0),e&&(0,Zwe.emitKeypressEvents)(e)},[e,r]);let[o,a]=(0,ep.useState)(new Map),n=(0,ep.useMemo)(()=>({getAll:()=>o,get:u=>o.get(u),set:(u,A)=>a(new Map([...o,[u,A]]))}),[o,a]);return ep.default.createElement(Pq.Provider,{value:n,children:t})}});var bq={};zt(bq,{useMinistore:()=>eIt});function eIt(t,e){let r=(0,hQ.useContext)(Pq);if(r===null)throw new Error(\"Expected this hook to run with a ministore context attached\");if(typeof t>\"u\")return r.getAll();let o=(0,hQ.useCallback)(n=>{r.set(t,n)},[t,r.set]),a=r.get(t);return typeof a>\"u\"&&(a=e),[a,o]}var hQ,xq=Et(()=>{hQ=$e(on());Sq()});var dQ={};zt(dQ,{renderForm:()=>tIt});async function tIt(t,e,{stdin:r,stdout:o,stderr:a}){let n,u=p=>{let{exit:h}=(0,gQ.useApp)();pm({active:!0},(E,I)=>{I.name===\"return\"&&(n=p,h())},[h,p])},{waitUntilExit:A}=(0,gQ.render)(kq.default.createElement($we,null,kq.default.createElement(t,{...e,useSubmit:u})),{stdin:r,stdout:o,stderr:a});return await A(),n}var gQ,kq,mQ=Et(()=>{gQ=$e(sc()),kq=$e(on());Sq();UB()});var nIe=_(HB=>{\"use strict\";Object.defineProperty(HB,\"__esModule\",{value:!0});HB.UncontrolledTextInput=void 0;var tIe=on(),Qq=on(),eIe=sc(),hm=rQ(),rIe=({value:t,placeholder:e=\"\",focus:r=!0,mask:o,highlightPastedText:a=!1,showCursor:n=!0,onChange:u,onSubmit:A})=>{let[{cursorOffset:p,cursorWidth:h},E]=Qq.useState({cursorOffset:(t||\"\").length,cursorWidth:0});Qq.useEffect(()=>{E(R=>{if(!r||!n)return R;let N=t||\"\";return R.cursorOffset>N.length-1?{cursorOffset:N.length,cursorWidth:0}:R})},[t,r,n]);let I=a?h:0,v=o?o.repeat(t.length):t,x=v,C=e?hm.grey(e):void 0;if(n&&r){C=e.length>0?hm.inverse(e[0])+hm.grey(e.slice(1)):hm.inverse(\" \"),x=v.length>0?\"\":hm.inverse(\" \");let R=0;for(let N of v)R>=p-I&&R<=p?x+=hm.inverse(N):x+=N,R++;v.length>0&&p===v.length&&(x+=hm.inverse(\" \"))}return eIe.useInput((R,N)=>{if(N.upArrow||N.downArrow||N.ctrl&&R===\"c\"||N.tab||N.shift&&N.tab)return;if(N.return){A&&A(t);return}let U=p,V=t,te=0;N.leftArrow?n&&U--:N.rightArrow?n&&U++:N.backspace||N.delete?p>0&&(V=t.slice(0,p-1)+t.slice(p,t.length),U--):(V=t.slice(0,p)+R+t.slice(p,t.length),U+=R.length,R.length>1&&(te=R.length)),p<0&&(U=0),p>t.length&&(U=t.length),E({cursorOffset:U,cursorWidth:te}),V!==t&&u(V)},{isActive:r}),tIe.createElement(eIe.Text,null,e?v.length>0?x:C:x)};HB.default=rIe;HB.UncontrolledTextInput=t=>{let[e,r]=Qq.useState(\"\");return tIe.createElement(rIe,Object.assign({},t,{value:e,onChange:r}))}});var oIe={};zt(oIe,{Pad:()=>Fq});var iIe,sIe,Fq,Rq=Et(()=>{iIe=$e(sc()),sIe=$e(on()),Fq=({length:t,active:e})=>{if(t===0)return null;let r=t>1?` ${\"-\".repeat(t-1)}`:\" \";return sIe.default.createElement(iIe.Text,{dimColor:!e},r)}});var aIe={};zt(aIe,{ItemOptions:()=>rIt});var GB,B0,rIt,lIe=Et(()=>{GB=$e(sc()),B0=$e(on());AQ();cQ();Rq();rIt=function({active:t,skewer:e,options:r,value:o,onChange:a,sizes:n=[]}){let u=r.filter(({label:p})=>!!p).map(({value:p})=>p),A=r.findIndex(p=>p.value===o&&p.label!=\"\");return _B(o,u,{active:t,minus:\"left\",plus:\"right\",set:a}),B0.default.createElement(B0.default.Fragment,null,r.map(({label:p},h)=>{let E=h===A,I=n[h]-1||0,v=p.replace(/[\\u001b\\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,\"\"),x=Math.max(0,I-v.length-2);return p?B0.default.createElement(GB.Box,{key:p,width:I,marginLeft:1},B0.default.createElement(GB.Text,{wrap:\"truncate\"},B0.default.createElement(Iq,{active:E}),\" \",p),e?B0.default.createElement(Fq,{active:t,length:x}):null):B0.default.createElement(GB.Box,{key:`spacer-${h}`,width:I,marginLeft:1})}))}});var vIe=_((XVt,BIe)=>{var qq;BIe.exports=()=>(typeof qq>\"u\"&&(qq=ve(\"zlib\").brotliDecompressSync(Buffer.from(\"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\",\"base64\")).toString()),qq)});var YIe=_((IJt,jIe)=>{var Xq=Symbol(\"arg flag\"),Oa=class extends Error{constructor(e,r){super(e),this.name=\"ArgError\",this.code=r,Object.setPrototypeOf(this,Oa.prototype)}};function sv(t,{argv:e=process.argv.slice(2),permissive:r=!1,stopAtPositional:o=!1}={}){if(!t)throw new Oa(\"argument specification object is required\",\"ARG_CONFIG_NO_SPEC\");let a={_:[]},n={},u={};for(let A of Object.keys(t)){if(!A)throw new Oa(\"argument key cannot be an empty string\",\"ARG_CONFIG_EMPTY_KEY\");if(A[0]!==\"-\")throw new Oa(`argument key must start with '-' but found: '${A}'`,\"ARG_CONFIG_NONOPT_KEY\");if(A.length===1)throw new Oa(`argument key must have a name; singular '-' keys are not allowed: ${A}`,\"ARG_CONFIG_NONAME_KEY\");if(typeof t[A]==\"string\"){n[A]=t[A];continue}let p=t[A],h=!1;if(Array.isArray(p)&&p.length===1&&typeof p[0]==\"function\"){let[E]=p;p=(I,v,x=[])=>(x.push(E(I,v,x[x.length-1])),x),h=E===Boolean||E[Xq]===!0}else if(typeof p==\"function\")h=p===Boolean||p[Xq]===!0;else throw new Oa(`type missing or not a function or valid array type: ${A}`,\"ARG_CONFIG_VAD_TYPE\");if(A[1]!==\"-\"&&A.length>2)throw new Oa(`short argument keys (with a single hyphen) must have only one character: ${A}`,\"ARG_CONFIG_SHORTOPT_TOOLONG\");u[A]=[p,h]}for(let A=0,p=e.length;A<p;A++){let h=e[A];if(o&&a._.length>0){a._=a._.concat(e.slice(A));break}if(h===\"--\"){a._=a._.concat(e.slice(A+1));break}if(h.length>1&&h[0]===\"-\"){let E=h[1]===\"-\"||h.length===2?[h]:h.slice(1).split(\"\").map(I=>`-${I}`);for(let I=0;I<E.length;I++){let v=E[I],[x,C]=v[1]===\"-\"?v.split(/=(.*)/,2):[v,void 0],R=x;for(;R in n;)R=n[R];if(!(R in u))if(r){a._.push(v);continue}else throw new Oa(`unknown or unexpected option: ${x}`,\"ARG_UNKNOWN_OPTION\");let[N,U]=u[R];if(!U&&I+1<E.length)throw new Oa(`option requires argument (but was followed by another short argument): ${x}`,\"ARG_MISSING_REQUIRED_SHORTARG\");if(U)a[R]=N(!0,R,a[R]);else if(C===void 0){if(e.length<A+2||e[A+1].length>1&&e[A+1][0]===\"-\"&&!(e[A+1].match(/^-?\\d*(\\.(?=\\d))?\\d*$/)&&(N===Number||typeof BigInt<\"u\"&&N===BigInt))){let V=x===R?\"\":` (alias for ${R})`;throw new Oa(`option requires argument: ${x}${V}`,\"ARG_MISSING_REQUIRED_LONGARG\")}a[R]=N(e[A+1],R,a[R]),++A}else a[R]=N(C,R,a[R])}}else a._.push(h)}return a}sv.flag=t=>(t[Xq]=!0,t);sv.COUNT=sv.flag((t,e,r)=>(r||0)+1);sv.ArgError=Oa;jIe.exports=sv});var $Ie=_((ZJt,ZIe)=>{var tG;ZIe.exports=()=>(typeof tG>\"u\"&&(tG=ve(\"zlib\").brotliDecompressSync(Buffer.from(\"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\",\"base64\")).toString()),tG)});var i1e=_((aG,lG)=>{(function(t){aG&&typeof aG==\"object\"&&typeof lG<\"u\"?lG.exports=t():typeof define==\"function\"&&define.amd?define([],t):typeof window<\"u\"?window.isWindows=t():typeof global<\"u\"?global.isWindows=t():typeof self<\"u\"?self.isWindows=t():this.isWindows=t()})(function(){\"use strict\";return function(){return process&&(process.platform===\"win32\"||/^(msys|cygwin)$/.test(process.env.OSTYPE))}})});var l1e=_((JXt,a1e)=>{\"use strict\";cG.ifExists=$It;var YC=ve(\"util\"),oc=ve(\"path\"),s1e=i1e(),JIt=/^#!\\s*(?:\\/usr\\/bin\\/env)?\\s*([^ \\t]+)(.*)$/,XIt={createPwshFile:!0,createCmdFile:s1e(),fs:ve(\"fs\")},ZIt=new Map([[\".js\",\"node\"],[\".cjs\",\"node\"],[\".mjs\",\"node\"],[\".cmd\",\"cmd\"],[\".bat\",\"cmd\"],[\".ps1\",\"pwsh\"],[\".sh\",\"sh\"]]);function o1e(t){let e={...XIt,...t},r=e.fs;return e.fs_={chmod:r.chmod?YC.promisify(r.chmod):async()=>{},mkdir:YC.promisify(r.mkdir),readFile:YC.promisify(r.readFile),stat:YC.promisify(r.stat),unlink:YC.promisify(r.unlink),writeFile:YC.promisify(r.writeFile)},e}async function cG(t,e,r){let o=o1e(r);await o.fs_.stat(t),await t1t(t,e,o)}function $It(t,e,r){return cG(t,e,r).catch(()=>{})}function e1t(t,e){return e.fs_.unlink(t).catch(()=>{})}async function t1t(t,e,r){let o=await o1t(t,r);return await r1t(e,r),n1t(t,e,o,r)}function r1t(t,e){return e.fs_.mkdir(oc.dirname(t),{recursive:!0})}function n1t(t,e,r,o){let a=o1e(o),n=[{generator:c1t,extension:\"\"}];return a.createCmdFile&&n.push({generator:l1t,extension:\".cmd\"}),a.createPwshFile&&n.push({generator:u1t,extension:\".ps1\"}),Promise.all(n.map(u=>a1t(t,e+u.extension,r,u.generator,a)))}function i1t(t,e){return e1t(t,e)}function s1t(t,e){return A1t(t,e)}async function o1t(t,e){let a=(await e.fs_.readFile(t,\"utf8\")).trim().split(/\\r*\\n/)[0].match(JIt);if(!a){let n=oc.extname(t).toLowerCase();return{program:ZIt.get(n)||null,additionalArgs:\"\"}}return{program:a[1],additionalArgs:a[2]}}async function a1t(t,e,r,o,a){let n=a.preserveSymlinks?\"--preserve-symlinks\":\"\",u=[r.additionalArgs,n].filter(A=>A).join(\" \");return a=Object.assign({},a,{prog:r.program,args:u}),await i1t(e,a),await a.fs_.writeFile(e,o(t,e,a),\"utf8\"),s1t(e,a)}function l1t(t,e,r){let a=oc.relative(oc.dirname(e),t).split(\"/\").join(\"\\\\\"),n=oc.isAbsolute(a)?`\"${a}\"`:`\"%~dp0\\\\${a}\"`,u,A=r.prog,p=r.args||\"\",h=uG(r.nodePath).win32;A?(u=`\"%~dp0\\\\${A}.exe\"`,a=n):(A=n,p=\"\",a=\"\");let E=r.progArgs?`${r.progArgs.join(\" \")} `:\"\",I=h?`@SET NODE_PATH=${h}\\r\n`:\"\";return u?I+=`@IF EXIST ${u} (\\r\n  ${u} ${p} ${a} ${E}%*\\r\n) ELSE (\\r\n  @SETLOCAL\\r\n  @SET PATHEXT=%PATHEXT:;.JS;=;%\\r\n  ${A} ${p} ${a} ${E}%*\\r\n)\\r\n`:I+=`@${A} ${p} ${a} ${E}%*\\r\n`,I}function c1t(t,e,r){let o=oc.relative(oc.dirname(e),t),a=r.prog&&r.prog.split(\"\\\\\").join(\"/\"),n;o=o.split(\"\\\\\").join(\"/\");let u=oc.isAbsolute(o)?`\"${o}\"`:`\"$basedir/${o}\"`,A=r.args||\"\",p=uG(r.nodePath).posix;a?(n=`\"$basedir/${r.prog}\"`,o=u):(a=u,A=\"\",o=\"\");let h=r.progArgs?`${r.progArgs.join(\" \")} `:\"\",E=`#!/bin/sh\nbasedir=$(dirname \"$(echo \"$0\" | sed -e 's,\\\\\\\\,/,g')\")\n\ncase \\`uname\\` in\n    *CYGWIN*) basedir=\\`cygpath -w \"$basedir\"\\`;;\nesac\n\n`,I=r.nodePath?`export NODE_PATH=\"${p}\"\n`:\"\";return n?E+=`${I}if [ -x ${n} ]; then\n  exec ${n} ${A} ${o} ${h}\"$@\"\nelse\n  exec ${a} ${A} ${o} ${h}\"$@\"\nfi\n`:E+=`${I}${a} ${A} ${o} ${h}\"$@\"\nexit $?\n`,E}function u1t(t,e,r){let o=oc.relative(oc.dirname(e),t),a=r.prog&&r.prog.split(\"\\\\\").join(\"/\"),n=a&&`\"${a}$exe\"`,u;o=o.split(\"\\\\\").join(\"/\");let A=oc.isAbsolute(o)?`\"${o}\"`:`\"$basedir/${o}\"`,p=r.args||\"\",h=uG(r.nodePath),E=h.win32,I=h.posix;n?(u=`\"$basedir/${r.prog}$exe\"`,o=A):(n=A,p=\"\",o=\"\");let v=r.progArgs?`${r.progArgs.join(\" \")} `:\"\",x=`#!/usr/bin/env pwsh\n$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent\n\n$exe=\"\"\n${r.nodePath?`$env_node_path=$env:NODE_PATH\n$env:NODE_PATH=\"${E}\"\n`:\"\"}if ($PSVersionTable.PSVersion -lt \"6.0\" -or $IsWindows) {\n  # Fix case when both the Windows and Linux builds of Node\n  # are installed in the same directory\n  $exe=\".exe\"\n}`;return r.nodePath&&(x+=` else {\n  $env:NODE_PATH=\"${I}\"\n}`),u?x+=`\n$ret=0\nif (Test-Path ${u}) {\n  # Support pipeline input\n  if ($MyInvocation.ExpectingInput) {\n    $input | & ${u} ${p} ${o} ${v}$args\n  } else {\n    & ${u} ${p} ${o} ${v}$args\n  }\n  $ret=$LASTEXITCODE\n} else {\n  # Support pipeline input\n  if ($MyInvocation.ExpectingInput) {\n    $input | & ${n} ${p} ${o} ${v}$args\n  } else {\n    & ${n} ${p} ${o} ${v}$args\n  }\n  $ret=$LASTEXITCODE\n}\n${r.nodePath?`$env:NODE_PATH=$env_node_path\n`:\"\"}exit $ret\n`:x+=`\n# Support pipeline input\nif ($MyInvocation.ExpectingInput) {\n  $input | & ${n} ${p} ${o} ${v}$args\n} else {\n  & ${n} ${p} ${o} ${v}$args\n}\n${r.nodePath?`$env:NODE_PATH=$env_node_path\n`:\"\"}exit $LASTEXITCODE\n`,x}function A1t(t,e){return e.fs_.chmod(t,493)}function uG(t){if(!t)return{win32:\"\",posix:\"\"};let e=typeof t==\"string\"?t.split(oc.delimiter):Array.from(t),r={};for(let o=0;o<e.length;o++){let a=e[o].split(\"/\").join(\"\\\\\"),n=s1e()?e[o].split(\"\\\\\").join(\"/\").replace(/^([^:\\\\/]*):/,(u,A)=>`/mnt/${A.toLowerCase()}`):e[o];r.win32=r.win32?`${r.win32};${a}`:a,r.posix=r.posix?`${r.posix}:${n}`:n,r[o]={win32:a,posix:n}}return r}a1e.exports=cG});var vG=_((m$t,x1e)=>{x1e.exports=ve(\"stream\")});var R1e=_((y$t,F1e)=>{\"use strict\";function k1e(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(t);e&&(o=o.filter(function(a){return Object.getOwnPropertyDescriptor(t,a).enumerable})),r.push.apply(r,o)}return r}function M1t(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?k1e(Object(r),!0).forEach(function(o){U1t(t,o,r[o])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):k1e(Object(r)).forEach(function(o){Object.defineProperty(t,o,Object.getOwnPropertyDescriptor(r,o))})}return t}function U1t(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function _1t(t,e){if(!(t instanceof e))throw new TypeError(\"Cannot call a class as a function\")}function Q1e(t,e){for(var r=0;r<e.length;r++){var o=e[r];o.enumerable=o.enumerable||!1,o.configurable=!0,\"value\"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}function H1t(t,e,r){return e&&Q1e(t.prototype,e),r&&Q1e(t,r),t}var q1t=ve(\"buffer\"),xQ=q1t.Buffer,G1t=ve(\"util\"),DG=G1t.inspect,j1t=DG&&DG.custom||\"inspect\";function Y1t(t,e,r){xQ.prototype.copy.call(t,e,r)}F1e.exports=function(){function t(){_1t(this,t),this.head=null,this.tail=null,this.length=0}return H1t(t,[{key:\"push\",value:function(r){var o={data:r,next:null};this.length>0?this.tail.next=o:this.head=o,this.tail=o,++this.length}},{key:\"unshift\",value:function(r){var o={data:r,next:this.head};this.length===0&&(this.tail=o),this.head=o,++this.length}},{key:\"shift\",value:function(){if(this.length!==0){var r=this.head.data;return this.length===1?this.head=this.tail=null:this.head=this.head.next,--this.length,r}}},{key:\"clear\",value:function(){this.head=this.tail=null,this.length=0}},{key:\"join\",value:function(r){if(this.length===0)return\"\";for(var o=this.head,a=\"\"+o.data;o=o.next;)a+=r+o.data;return a}},{key:\"concat\",value:function(r){if(this.length===0)return xQ.alloc(0);for(var o=xQ.allocUnsafe(r>>>0),a=this.head,n=0;a;)Y1t(a.data,o,n),n+=a.data.length,a=a.next;return o}},{key:\"consume\",value:function(r,o){var a;return r<this.head.data.length?(a=this.head.data.slice(0,r),this.head.data=this.head.data.slice(r)):r===this.head.data.length?a=this.shift():a=o?this._getString(r):this._getBuffer(r),a}},{key:\"first\",value:function(){return this.head.data}},{key:\"_getString\",value:function(r){var o=this.head,a=1,n=o.data;for(r-=n.length;o=o.next;){var u=o.data,A=r>u.length?u.length:r;if(A===u.length?n+=u:n+=u.slice(0,r),r-=A,r===0){A===u.length?(++a,o.next?this.head=o.next:this.head=this.tail=null):(this.head=o,o.data=u.slice(A));break}++a}return this.length-=a,n}},{key:\"_getBuffer\",value:function(r){var o=xQ.allocUnsafe(r),a=this.head,n=1;for(a.data.copy(o),r-=a.data.length;a=a.next;){var u=a.data,A=r>u.length?u.length:r;if(u.copy(o,o.length-r,0,A),r-=A,r===0){A===u.length?(++n,a.next?this.head=a.next:this.head=this.tail=null):(this.head=a,a.data=u.slice(A));break}++n}return this.length-=n,o}},{key:j1t,value:function(r,o){return DG(this,M1t({},o,{depth:0,customInspect:!1}))}}]),t}()});var SG=_((E$t,L1e)=>{\"use strict\";function W1t(t,e){var r=this,o=this._readableState&&this._readableState.destroyed,a=this._writableState&&this._writableState.destroyed;return o||a?(e?e(t):t&&(this._writableState?this._writableState.errorEmitted||(this._writableState.errorEmitted=!0,process.nextTick(PG,this,t)):process.nextTick(PG,this,t)),this):(this._readableState&&(this._readableState.destroyed=!0),this._writableState&&(this._writableState.destroyed=!0),this._destroy(t||null,function(n){!e&&n?r._writableState?r._writableState.errorEmitted?process.nextTick(kQ,r):(r._writableState.errorEmitted=!0,process.nextTick(T1e,r,n)):process.nextTick(T1e,r,n):e?(process.nextTick(kQ,r),e(n)):process.nextTick(kQ,r)}),this)}function T1e(t,e){PG(t,e),kQ(t)}function kQ(t){t._writableState&&!t._writableState.emitClose||t._readableState&&!t._readableState.emitClose||t.emit(\"close\")}function K1t(){this._readableState&&(this._readableState.destroyed=!1,this._readableState.reading=!1,this._readableState.ended=!1,this._readableState.endEmitted=!1),this._writableState&&(this._writableState.destroyed=!1,this._writableState.ended=!1,this._writableState.ending=!1,this._writableState.finalCalled=!1,this._writableState.prefinished=!1,this._writableState.finished=!1,this._writableState.errorEmitted=!1)}function PG(t,e){t.emit(\"error\",e)}function z1t(t,e){var r=t._readableState,o=t._writableState;r&&r.autoDestroy||o&&o.autoDestroy?t.destroy(e):t.emit(\"error\",e)}L1e.exports={destroy:W1t,undestroy:K1t,errorOrDestroy:z1t}});var F0=_((C$t,M1e)=>{\"use strict\";var O1e={};function lc(t,e,r){r||(r=Error);function o(n,u,A){return typeof e==\"string\"?e:e(n,u,A)}class a extends r{constructor(u,A,p){super(o(u,A,p))}}a.prototype.name=r.name,a.prototype.code=t,O1e[t]=a}function N1e(t,e){if(Array.isArray(t)){let r=t.length;return t=t.map(o=>String(o)),r>2?`one of ${e} ${t.slice(0,r-1).join(\", \")}, or `+t[r-1]:r===2?`one of ${e} ${t[0]} or ${t[1]}`:`of ${e} ${t[0]}`}else return`of ${e} ${String(t)}`}function V1t(t,e,r){return t.substr(!r||r<0?0:+r,e.length)===e}function J1t(t,e,r){return(r===void 0||r>t.length)&&(r=t.length),t.substring(r-e.length,r)===e}function X1t(t,e,r){return typeof r!=\"number\"&&(r=0),r+e.length>t.length?!1:t.indexOf(e,r)!==-1}lc(\"ERR_INVALID_OPT_VALUE\",function(t,e){return'The value \"'+e+'\" is invalid for option \"'+t+'\"'},TypeError);lc(\"ERR_INVALID_ARG_TYPE\",function(t,e,r){let o;typeof e==\"string\"&&V1t(e,\"not \")?(o=\"must not be\",e=e.replace(/^not /,\"\")):o=\"must be\";let a;if(J1t(t,\" argument\"))a=`The ${t} ${o} ${N1e(e,\"type\")}`;else{let n=X1t(t,\".\")?\"property\":\"argument\";a=`The \"${t}\" ${n} ${o} ${N1e(e,\"type\")}`}return a+=`. Received type ${typeof r}`,a},TypeError);lc(\"ERR_STREAM_PUSH_AFTER_EOF\",\"stream.push() after EOF\");lc(\"ERR_METHOD_NOT_IMPLEMENTED\",function(t){return\"The \"+t+\" method is not implemented\"});lc(\"ERR_STREAM_PREMATURE_CLOSE\",\"Premature close\");lc(\"ERR_STREAM_DESTROYED\",function(t){return\"Cannot call \"+t+\" after a stream was destroyed\"});lc(\"ERR_MULTIPLE_CALLBACK\",\"Callback called multiple times\");lc(\"ERR_STREAM_CANNOT_PIPE\",\"Cannot pipe, not readable\");lc(\"ERR_STREAM_WRITE_AFTER_END\",\"write after end\");lc(\"ERR_STREAM_NULL_VALUES\",\"May not write null values to stream\",TypeError);lc(\"ERR_UNKNOWN_ENCODING\",function(t){return\"Unknown encoding: \"+t},TypeError);lc(\"ERR_STREAM_UNSHIFT_AFTER_END_EVENT\",\"stream.unshift() after end event\");M1e.exports.codes=O1e});var bG=_((w$t,U1e)=>{\"use strict\";var Z1t=F0().codes.ERR_INVALID_OPT_VALUE;function $1t(t,e,r){return t.highWaterMark!=null?t.highWaterMark:e?t[r]:null}function e2t(t,e,r,o){var a=$1t(e,o,r);if(a!=null){if(!(isFinite(a)&&Math.floor(a)===a)||a<0){var n=o?r:\"highWaterMark\";throw new Z1t(n,a)}return Math.floor(a)}return t.objectMode?16:16*1024}U1e.exports={getHighWaterMark:e2t}});var _1e=_((I$t,xG)=>{typeof Object.create==\"function\"?xG.exports=function(e,r){r&&(e.super_=r,e.prototype=Object.create(r.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}))}:xG.exports=function(e,r){if(r){e.super_=r;var o=function(){};o.prototype=r.prototype,e.prototype=new o,e.prototype.constructor=e}}});var R0=_((B$t,QG)=>{try{if(kG=ve(\"util\"),typeof kG.inherits!=\"function\")throw\"\";QG.exports=kG.inherits}catch{QG.exports=_1e()}var kG});var q1e=_((v$t,H1e)=>{H1e.exports=ve(\"util\").deprecate});var TG=_((D$t,z1e)=>{\"use strict\";z1e.exports=Ri;function j1e(t){var e=this;this.next=null,this.entry=null,this.finish=function(){S2t(e,t)}}var JC;Ri.WritableState=mv;var t2t={deprecate:q1e()},Y1e=vG(),FQ=ve(\"buffer\").Buffer,r2t=global.Uint8Array||function(){};function n2t(t){return FQ.from(t)}function i2t(t){return FQ.isBuffer(t)||t instanceof r2t}var RG=SG(),s2t=bG(),o2t=s2t.getHighWaterMark,T0=F0().codes,a2t=T0.ERR_INVALID_ARG_TYPE,l2t=T0.ERR_METHOD_NOT_IMPLEMENTED,c2t=T0.ERR_MULTIPLE_CALLBACK,u2t=T0.ERR_STREAM_CANNOT_PIPE,A2t=T0.ERR_STREAM_DESTROYED,f2t=T0.ERR_STREAM_NULL_VALUES,p2t=T0.ERR_STREAM_WRITE_AFTER_END,h2t=T0.ERR_UNKNOWN_ENCODING,XC=RG.errorOrDestroy;R0()(Ri,Y1e);function g2t(){}function mv(t,e,r){JC=JC||Cm(),t=t||{},typeof r!=\"boolean\"&&(r=e instanceof JC),this.objectMode=!!t.objectMode,r&&(this.objectMode=this.objectMode||!!t.writableObjectMode),this.highWaterMark=o2t(this,t,\"writableHighWaterMark\",r),this.finalCalled=!1,this.needDrain=!1,this.ending=!1,this.ended=!1,this.finished=!1,this.destroyed=!1;var o=t.decodeStrings===!1;this.decodeStrings=!o,this.defaultEncoding=t.defaultEncoding||\"utf8\",this.length=0,this.writing=!1,this.corked=0,this.sync=!0,this.bufferProcessing=!1,this.onwrite=function(a){I2t(e,a)},this.writecb=null,this.writelen=0,this.bufferedRequest=null,this.lastBufferedRequest=null,this.pendingcb=0,this.prefinished=!1,this.errorEmitted=!1,this.emitClose=t.emitClose!==!1,this.autoDestroy=!!t.autoDestroy,this.bufferedRequestCount=0,this.corkedRequestsFree=new j1e(this)}mv.prototype.getBuffer=function(){for(var e=this.bufferedRequest,r=[];e;)r.push(e),e=e.next;return r};(function(){try{Object.defineProperty(mv.prototype,\"buffer\",{get:t2t.deprecate(function(){return this.getBuffer()},\"_writableState.buffer is deprecated. Use _writableState.getBuffer instead.\",\"DEP0003\")})}catch{}})();var QQ;typeof Symbol==\"function\"&&Symbol.hasInstance&&typeof Function.prototype[Symbol.hasInstance]==\"function\"?(QQ=Function.prototype[Symbol.hasInstance],Object.defineProperty(Ri,Symbol.hasInstance,{value:function(e){return QQ.call(this,e)?!0:this!==Ri?!1:e&&e._writableState instanceof mv}})):QQ=function(e){return e instanceof this};function Ri(t){JC=JC||Cm();var e=this instanceof JC;if(!e&&!QQ.call(Ri,this))return new Ri(t);this._writableState=new mv(t,this,e),this.writable=!0,t&&(typeof t.write==\"function\"&&(this._write=t.write),typeof t.writev==\"function\"&&(this._writev=t.writev),typeof t.destroy==\"function\"&&(this._destroy=t.destroy),typeof t.final==\"function\"&&(this._final=t.final)),Y1e.call(this)}Ri.prototype.pipe=function(){XC(this,new u2t)};function d2t(t,e){var r=new p2t;XC(t,r),process.nextTick(e,r)}function m2t(t,e,r,o){var a;return r===null?a=new f2t:typeof r!=\"string\"&&!e.objectMode&&(a=new a2t(\"chunk\",[\"string\",\"Buffer\"],r)),a?(XC(t,a),process.nextTick(o,a),!1):!0}Ri.prototype.write=function(t,e,r){var o=this._writableState,a=!1,n=!o.objectMode&&i2t(t);return n&&!FQ.isBuffer(t)&&(t=n2t(t)),typeof e==\"function\"&&(r=e,e=null),n?e=\"buffer\":e||(e=o.defaultEncoding),typeof r!=\"function\"&&(r=g2t),o.ending?d2t(this,r):(n||m2t(this,o,t,r))&&(o.pendingcb++,a=E2t(this,o,n,t,e,r)),a};Ri.prototype.cork=function(){this._writableState.corked++};Ri.prototype.uncork=function(){var t=this._writableState;t.corked&&(t.corked--,!t.writing&&!t.corked&&!t.bufferProcessing&&t.bufferedRequest&&W1e(this,t))};Ri.prototype.setDefaultEncoding=function(e){if(typeof e==\"string\"&&(e=e.toLowerCase()),!([\"hex\",\"utf8\",\"utf-8\",\"ascii\",\"binary\",\"base64\",\"ucs2\",\"ucs-2\",\"utf16le\",\"utf-16le\",\"raw\"].indexOf((e+\"\").toLowerCase())>-1))throw new h2t(e);return this._writableState.defaultEncoding=e,this};Object.defineProperty(Ri.prototype,\"writableBuffer\",{enumerable:!1,get:function(){return this._writableState&&this._writableState.getBuffer()}});function y2t(t,e,r){return!t.objectMode&&t.decodeStrings!==!1&&typeof e==\"string\"&&(e=FQ.from(e,r)),e}Object.defineProperty(Ri.prototype,\"writableHighWaterMark\",{enumerable:!1,get:function(){return this._writableState.highWaterMark}});function E2t(t,e,r,o,a,n){if(!r){var u=y2t(e,o,a);o!==u&&(r=!0,a=\"buffer\",o=u)}var A=e.objectMode?1:o.length;e.length+=A;var p=e.length<e.highWaterMark;if(p||(e.needDrain=!0),e.writing||e.corked){var h=e.lastBufferedRequest;e.lastBufferedRequest={chunk:o,encoding:a,isBuf:r,callback:n,next:null},h?h.next=e.lastBufferedRequest:e.bufferedRequest=e.lastBufferedRequest,e.bufferedRequestCount+=1}else FG(t,e,!1,A,o,a,n);return p}function FG(t,e,r,o,a,n,u){e.writelen=o,e.writecb=u,e.writing=!0,e.sync=!0,e.destroyed?e.onwrite(new A2t(\"write\")):r?t._writev(a,e.onwrite):t._write(a,n,e.onwrite),e.sync=!1}function C2t(t,e,r,o,a){--e.pendingcb,r?(process.nextTick(a,o),process.nextTick(dv,t,e),t._writableState.errorEmitted=!0,XC(t,o)):(a(o),t._writableState.errorEmitted=!0,XC(t,o),dv(t,e))}function w2t(t){t.writing=!1,t.writecb=null,t.length-=t.writelen,t.writelen=0}function I2t(t,e){var r=t._writableState,o=r.sync,a=r.writecb;if(typeof a!=\"function\")throw new c2t;if(w2t(r),e)C2t(t,r,o,e,a);else{var n=K1e(r)||t.destroyed;!n&&!r.corked&&!r.bufferProcessing&&r.bufferedRequest&&W1e(t,r),o?process.nextTick(G1e,t,r,n,a):G1e(t,r,n,a)}}function G1e(t,e,r,o){r||B2t(t,e),e.pendingcb--,o(),dv(t,e)}function B2t(t,e){e.length===0&&e.needDrain&&(e.needDrain=!1,t.emit(\"drain\"))}function W1e(t,e){e.bufferProcessing=!0;var r=e.bufferedRequest;if(t._writev&&r&&r.next){var o=e.bufferedRequestCount,a=new Array(o),n=e.corkedRequestsFree;n.entry=r;for(var u=0,A=!0;r;)a[u]=r,r.isBuf||(A=!1),r=r.next,u+=1;a.allBuffers=A,FG(t,e,!0,e.length,a,\"\",n.finish),e.pendingcb++,e.lastBufferedRequest=null,n.next?(e.corkedRequestsFree=n.next,n.next=null):e.corkedRequestsFree=new j1e(e),e.bufferedRequestCount=0}else{for(;r;){var p=r.chunk,h=r.encoding,E=r.callback,I=e.objectMode?1:p.length;if(FG(t,e,!1,I,p,h,E),r=r.next,e.bufferedRequestCount--,e.writing)break}r===null&&(e.lastBufferedRequest=null)}e.bufferedRequest=r,e.bufferProcessing=!1}Ri.prototype._write=function(t,e,r){r(new l2t(\"_write()\"))};Ri.prototype._writev=null;Ri.prototype.end=function(t,e,r){var o=this._writableState;return typeof t==\"function\"?(r=t,t=null,e=null):typeof e==\"function\"&&(r=e,e=null),t!=null&&this.write(t,e),o.corked&&(o.corked=1,this.uncork()),o.ending||P2t(this,o,r),this};Object.defineProperty(Ri.prototype,\"writableLength\",{enumerable:!1,get:function(){return this._writableState.length}});function K1e(t){return t.ending&&t.length===0&&t.bufferedRequest===null&&!t.finished&&!t.writing}function v2t(t,e){t._final(function(r){e.pendingcb--,r&&XC(t,r),e.prefinished=!0,t.emit(\"prefinish\"),dv(t,e)})}function D2t(t,e){!e.prefinished&&!e.finalCalled&&(typeof t._final==\"function\"&&!e.destroyed?(e.pendingcb++,e.finalCalled=!0,process.nextTick(v2t,t,e)):(e.prefinished=!0,t.emit(\"prefinish\")))}function dv(t,e){var r=K1e(e);if(r&&(D2t(t,e),e.pendingcb===0&&(e.finished=!0,t.emit(\"finish\"),e.autoDestroy))){var o=t._readableState;(!o||o.autoDestroy&&o.endEmitted)&&t.destroy()}return r}function P2t(t,e,r){e.ending=!0,dv(t,e),r&&(e.finished?process.nextTick(r):t.once(\"finish\",r)),e.ended=!0,t.writable=!1}function S2t(t,e,r){var o=t.entry;for(t.entry=null;o;){var a=o.callback;e.pendingcb--,a(r),o=o.next}e.corkedRequestsFree.next=t}Object.defineProperty(Ri.prototype,\"destroyed\",{enumerable:!1,get:function(){return this._writableState===void 0?!1:this._writableState.destroyed},set:function(e){!this._writableState||(this._writableState.destroyed=e)}});Ri.prototype.destroy=RG.destroy;Ri.prototype._undestroy=RG.undestroy;Ri.prototype._destroy=function(t,e){e(t)}});var Cm=_((P$t,J1e)=>{\"use strict\";var b2t=Object.keys||function(t){var e=[];for(var r in t)e.push(r);return e};J1e.exports=EA;var V1e=OG(),NG=TG();R0()(EA,V1e);for(LG=b2t(NG.prototype),RQ=0;RQ<LG.length;RQ++)TQ=LG[RQ],EA.prototype[TQ]||(EA.prototype[TQ]=NG.prototype[TQ]);var LG,TQ,RQ;function EA(t){if(!(this instanceof EA))return new EA(t);V1e.call(this,t),NG.call(this,t),this.allowHalfOpen=!0,t&&(t.readable===!1&&(this.readable=!1),t.writable===!1&&(this.writable=!1),t.allowHalfOpen===!1&&(this.allowHalfOpen=!1,this.once(\"end\",x2t)))}Object.defineProperty(EA.prototype,\"writableHighWaterMark\",{enumerable:!1,get:function(){return this._writableState.highWaterMark}});Object.defineProperty(EA.prototype,\"writableBuffer\",{enumerable:!1,get:function(){return this._writableState&&this._writableState.getBuffer()}});Object.defineProperty(EA.prototype,\"writableLength\",{enumerable:!1,get:function(){return this._writableState.length}});function x2t(){this._writableState.ended||process.nextTick(k2t,this)}function k2t(t){t.end()}Object.defineProperty(EA.prototype,\"destroyed\",{enumerable:!1,get:function(){return this._readableState===void 0||this._writableState===void 0?!1:this._readableState.destroyed&&this._writableState.destroyed},set:function(e){this._readableState===void 0||this._writableState===void 0||(this._readableState.destroyed=e,this._writableState.destroyed=e)}})});var $1e=_((MG,Z1e)=>{var LQ=ve(\"buffer\"),sp=LQ.Buffer;function X1e(t,e){for(var r in t)e[r]=t[r]}sp.from&&sp.alloc&&sp.allocUnsafe&&sp.allocUnsafeSlow?Z1e.exports=LQ:(X1e(LQ,MG),MG.Buffer=ZC);function ZC(t,e,r){return sp(t,e,r)}X1e(sp,ZC);ZC.from=function(t,e,r){if(typeof t==\"number\")throw new TypeError(\"Argument must not be a number\");return sp(t,e,r)};ZC.alloc=function(t,e,r){if(typeof t!=\"number\")throw new TypeError(\"Argument must be a number\");var o=sp(t);return e!==void 0?typeof r==\"string\"?o.fill(e,r):o.fill(e):o.fill(0),o};ZC.allocUnsafe=function(t){if(typeof t!=\"number\")throw new TypeError(\"Argument must be a number\");return sp(t)};ZC.allocUnsafeSlow=function(t){if(typeof t!=\"number\")throw new TypeError(\"Argument must be a number\");return LQ.SlowBuffer(t)}});var HG=_(t2e=>{\"use strict\";var _G=$1e().Buffer,e2e=_G.isEncoding||function(t){switch(t=\"\"+t,t&&t.toLowerCase()){case\"hex\":case\"utf8\":case\"utf-8\":case\"ascii\":case\"binary\":case\"base64\":case\"ucs2\":case\"ucs-2\":case\"utf16le\":case\"utf-16le\":case\"raw\":return!0;default:return!1}};function Q2t(t){if(!t)return\"utf8\";for(var e;;)switch(t){case\"utf8\":case\"utf-8\":return\"utf8\";case\"ucs2\":case\"ucs-2\":case\"utf16le\":case\"utf-16le\":return\"utf16le\";case\"latin1\":case\"binary\":return\"latin1\";case\"base64\":case\"ascii\":case\"hex\":return t;default:if(e)return;t=(\"\"+t).toLowerCase(),e=!0}}function F2t(t){var e=Q2t(t);if(typeof e!=\"string\"&&(_G.isEncoding===e2e||!e2e(t)))throw new Error(\"Unknown encoding: \"+t);return e||t}t2e.StringDecoder=yv;function yv(t){this.encoding=F2t(t);var e;switch(this.encoding){case\"utf16le\":this.text=M2t,this.end=U2t,e=4;break;case\"utf8\":this.fillLast=L2t,e=4;break;case\"base64\":this.text=_2t,this.end=H2t,e=3;break;default:this.write=q2t,this.end=G2t;return}this.lastNeed=0,this.lastTotal=0,this.lastChar=_G.allocUnsafe(e)}yv.prototype.write=function(t){if(t.length===0)return\"\";var e,r;if(this.lastNeed){if(e=this.fillLast(t),e===void 0)return\"\";r=this.lastNeed,this.lastNeed=0}else r=0;return r<t.length?e?e+this.text(t,r):this.text(t,r):e||\"\"};yv.prototype.end=O2t;yv.prototype.text=N2t;yv.prototype.fillLast=function(t){if(this.lastNeed<=t.length)return t.copy(this.lastChar,this.lastTotal-this.lastNeed,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal);t.copy(this.lastChar,this.lastTotal-this.lastNeed,0,t.length),this.lastNeed-=t.length};function UG(t){return t<=127?0:t>>5===6?2:t>>4===14?3:t>>3===30?4:t>>6===2?-1:-2}function R2t(t,e,r){var o=e.length-1;if(o<r)return 0;var a=UG(e[o]);return a>=0?(a>0&&(t.lastNeed=a-1),a):--o<r||a===-2?0:(a=UG(e[o]),a>=0?(a>0&&(t.lastNeed=a-2),a):--o<r||a===-2?0:(a=UG(e[o]),a>=0?(a>0&&(a===2?a=0:t.lastNeed=a-3),a):0))}function T2t(t,e,r){if((e[0]&192)!==128)return t.lastNeed=0,\"\\uFFFD\";if(t.lastNeed>1&&e.length>1){if((e[1]&192)!==128)return t.lastNeed=1,\"\\uFFFD\";if(t.lastNeed>2&&e.length>2&&(e[2]&192)!==128)return t.lastNeed=2,\"\\uFFFD\"}}function L2t(t){var e=this.lastTotal-this.lastNeed,r=T2t(this,t,e);if(r!==void 0)return r;if(this.lastNeed<=t.length)return t.copy(this.lastChar,e,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal);t.copy(this.lastChar,e,0,t.length),this.lastNeed-=t.length}function N2t(t,e){var r=R2t(this,t,e);if(!this.lastNeed)return t.toString(\"utf8\",e);this.lastTotal=r;var o=t.length-(r-this.lastNeed);return t.copy(this.lastChar,0,o),t.toString(\"utf8\",e,o)}function O2t(t){var e=t&&t.length?this.write(t):\"\";return this.lastNeed?e+\"\\uFFFD\":e}function M2t(t,e){if((t.length-e)%2===0){var r=t.toString(\"utf16le\",e);if(r){var o=r.charCodeAt(r.length-1);if(o>=55296&&o<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=t[t.length-2],this.lastChar[1]=t[t.length-1],r.slice(0,-1)}return r}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=t[t.length-1],t.toString(\"utf16le\",e,t.length-1)}function U2t(t){var e=t&&t.length?this.write(t):\"\";if(this.lastNeed){var r=this.lastTotal-this.lastNeed;return e+this.lastChar.toString(\"utf16le\",0,r)}return e}function _2t(t,e){var r=(t.length-e)%3;return r===0?t.toString(\"base64\",e):(this.lastNeed=3-r,this.lastTotal=3,r===1?this.lastChar[0]=t[t.length-1]:(this.lastChar[0]=t[t.length-2],this.lastChar[1]=t[t.length-1]),t.toString(\"base64\",e,t.length-r))}function H2t(t){var e=t&&t.length?this.write(t):\"\";return this.lastNeed?e+this.lastChar.toString(\"base64\",0,3-this.lastNeed):e}function q2t(t){return t.toString(this.encoding)}function G2t(t){return t&&t.length?this.write(t):\"\"}});var NQ=_((b$t,i2e)=>{\"use strict\";var r2e=F0().codes.ERR_STREAM_PREMATURE_CLOSE;function j2t(t){var e=!1;return function(){if(!e){e=!0;for(var r=arguments.length,o=new Array(r),a=0;a<r;a++)o[a]=arguments[a];t.apply(this,o)}}}function Y2t(){}function W2t(t){return t.setHeader&&typeof t.abort==\"function\"}function n2e(t,e,r){if(typeof e==\"function\")return n2e(t,null,e);e||(e={}),r=j2t(r||Y2t);var o=e.readable||e.readable!==!1&&t.readable,a=e.writable||e.writable!==!1&&t.writable,n=function(){t.writable||A()},u=t._writableState&&t._writableState.finished,A=function(){a=!1,u=!0,o||r.call(t)},p=t._readableState&&t._readableState.endEmitted,h=function(){o=!1,p=!0,a||r.call(t)},E=function(C){r.call(t,C)},I=function(){var C;if(o&&!p)return(!t._readableState||!t._readableState.ended)&&(C=new r2e),r.call(t,C);if(a&&!u)return(!t._writableState||!t._writableState.ended)&&(C=new r2e),r.call(t,C)},v=function(){t.req.on(\"finish\",A)};return W2t(t)?(t.on(\"complete\",A),t.on(\"abort\",I),t.req?v():t.on(\"request\",v)):a&&!t._writableState&&(t.on(\"end\",n),t.on(\"close\",n)),t.on(\"end\",h),t.on(\"finish\",A),e.error!==!1&&t.on(\"error\",E),t.on(\"close\",I),function(){t.removeListener(\"complete\",A),t.removeListener(\"abort\",I),t.removeListener(\"request\",v),t.req&&t.req.removeListener(\"finish\",A),t.removeListener(\"end\",n),t.removeListener(\"close\",n),t.removeListener(\"finish\",A),t.removeListener(\"end\",h),t.removeListener(\"error\",E),t.removeListener(\"close\",I)}}i2e.exports=n2e});var o2e=_((x$t,s2e)=>{\"use strict\";var OQ;function L0(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var K2t=NQ(),N0=Symbol(\"lastResolve\"),wm=Symbol(\"lastReject\"),Ev=Symbol(\"error\"),MQ=Symbol(\"ended\"),Im=Symbol(\"lastPromise\"),qG=Symbol(\"handlePromise\"),Bm=Symbol(\"stream\");function O0(t,e){return{value:t,done:e}}function z2t(t){var e=t[N0];if(e!==null){var r=t[Bm].read();r!==null&&(t[Im]=null,t[N0]=null,t[wm]=null,e(O0(r,!1)))}}function V2t(t){process.nextTick(z2t,t)}function J2t(t,e){return function(r,o){t.then(function(){if(e[MQ]){r(O0(void 0,!0));return}e[qG](r,o)},o)}}var X2t=Object.getPrototypeOf(function(){}),Z2t=Object.setPrototypeOf((OQ={get stream(){return this[Bm]},next:function(){var e=this,r=this[Ev];if(r!==null)return Promise.reject(r);if(this[MQ])return Promise.resolve(O0(void 0,!0));if(this[Bm].destroyed)return new Promise(function(u,A){process.nextTick(function(){e[Ev]?A(e[Ev]):u(O0(void 0,!0))})});var o=this[Im],a;if(o)a=new Promise(J2t(o,this));else{var n=this[Bm].read();if(n!==null)return Promise.resolve(O0(n,!1));a=new Promise(this[qG])}return this[Im]=a,a}},L0(OQ,Symbol.asyncIterator,function(){return this}),L0(OQ,\"return\",function(){var e=this;return new Promise(function(r,o){e[Bm].destroy(null,function(a){if(a){o(a);return}r(O0(void 0,!0))})})}),OQ),X2t),$2t=function(e){var r,o=Object.create(Z2t,(r={},L0(r,Bm,{value:e,writable:!0}),L0(r,N0,{value:null,writable:!0}),L0(r,wm,{value:null,writable:!0}),L0(r,Ev,{value:null,writable:!0}),L0(r,MQ,{value:e._readableState.endEmitted,writable:!0}),L0(r,qG,{value:function(n,u){var A=o[Bm].read();A?(o[Im]=null,o[N0]=null,o[wm]=null,n(O0(A,!1))):(o[N0]=n,o[wm]=u)},writable:!0}),r));return o[Im]=null,K2t(e,function(a){if(a&&a.code!==\"ERR_STREAM_PREMATURE_CLOSE\"){var n=o[wm];n!==null&&(o[Im]=null,o[N0]=null,o[wm]=null,n(a)),o[Ev]=a;return}var u=o[N0];u!==null&&(o[Im]=null,o[N0]=null,o[wm]=null,u(O0(void 0,!0))),o[MQ]=!0}),e.on(\"readable\",V2t.bind(null,o)),o};s2e.exports=$2t});var u2e=_((k$t,c2e)=>{\"use strict\";function a2e(t,e,r,o,a,n,u){try{var A=t[n](u),p=A.value}catch(h){r(h);return}A.done?e(p):Promise.resolve(p).then(o,a)}function eBt(t){return function(){var e=this,r=arguments;return new Promise(function(o,a){var n=t.apply(e,r);function u(p){a2e(n,o,a,u,A,\"next\",p)}function A(p){a2e(n,o,a,u,A,\"throw\",p)}u(void 0)})}}function l2e(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(t);e&&(o=o.filter(function(a){return Object.getOwnPropertyDescriptor(t,a).enumerable})),r.push.apply(r,o)}return r}function tBt(t){for(var e=1;e<arguments.length;e++){var r=arguments[e]!=null?arguments[e]:{};e%2?l2e(Object(r),!0).forEach(function(o){rBt(t,o,r[o])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):l2e(Object(r)).forEach(function(o){Object.defineProperty(t,o,Object.getOwnPropertyDescriptor(r,o))})}return t}function rBt(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}var nBt=F0().codes.ERR_INVALID_ARG_TYPE;function iBt(t,e,r){var o;if(e&&typeof e.next==\"function\")o=e;else if(e&&e[Symbol.asyncIterator])o=e[Symbol.asyncIterator]();else if(e&&e[Symbol.iterator])o=e[Symbol.iterator]();else throw new nBt(\"iterable\",[\"Iterable\"],e);var a=new t(tBt({objectMode:!0},r)),n=!1;a._read=function(){n||(n=!0,u())};function u(){return A.apply(this,arguments)}function A(){return A=eBt(function*(){try{var p=yield o.next(),h=p.value,E=p.done;E?a.push(null):a.push(yield h)?u():n=!1}catch(I){a.destroy(I)}}),A.apply(this,arguments)}return a}c2e.exports=iBt});var OG=_((F$t,C2e)=>{\"use strict\";C2e.exports=mn;var $C;mn.ReadableState=h2e;var Q$t=ve(\"events\").EventEmitter,p2e=function(e,r){return e.listeners(r).length},wv=vG(),UQ=ve(\"buffer\").Buffer,sBt=global.Uint8Array||function(){};function oBt(t){return UQ.from(t)}function aBt(t){return UQ.isBuffer(t)||t instanceof sBt}var GG=ve(\"util\"),en;GG&&GG.debuglog?en=GG.debuglog(\"stream\"):en=function(){};var lBt=R1e(),JG=SG(),cBt=bG(),uBt=cBt.getHighWaterMark,_Q=F0().codes,ABt=_Q.ERR_INVALID_ARG_TYPE,fBt=_Q.ERR_STREAM_PUSH_AFTER_EOF,pBt=_Q.ERR_METHOD_NOT_IMPLEMENTED,hBt=_Q.ERR_STREAM_UNSHIFT_AFTER_END_EVENT,ew,jG,YG;R0()(mn,wv);var Cv=JG.errorOrDestroy,WG=[\"error\",\"close\",\"destroy\",\"pause\",\"resume\"];function gBt(t,e,r){if(typeof t.prependListener==\"function\")return t.prependListener(e,r);!t._events||!t._events[e]?t.on(e,r):Array.isArray(t._events[e])?t._events[e].unshift(r):t._events[e]=[r,t._events[e]]}function h2e(t,e,r){$C=$C||Cm(),t=t||{},typeof r!=\"boolean\"&&(r=e instanceof $C),this.objectMode=!!t.objectMode,r&&(this.objectMode=this.objectMode||!!t.readableObjectMode),this.highWaterMark=uBt(this,t,\"readableHighWaterMark\",r),this.buffer=new lBt,this.length=0,this.pipes=null,this.pipesCount=0,this.flowing=null,this.ended=!1,this.endEmitted=!1,this.reading=!1,this.sync=!0,this.needReadable=!1,this.emittedReadable=!1,this.readableListening=!1,this.resumeScheduled=!1,this.paused=!0,this.emitClose=t.emitClose!==!1,this.autoDestroy=!!t.autoDestroy,this.destroyed=!1,this.defaultEncoding=t.defaultEncoding||\"utf8\",this.awaitDrain=0,this.readingMore=!1,this.decoder=null,this.encoding=null,t.encoding&&(ew||(ew=HG().StringDecoder),this.decoder=new ew(t.encoding),this.encoding=t.encoding)}function mn(t){if($C=$C||Cm(),!(this instanceof mn))return new mn(t);var e=this instanceof $C;this._readableState=new h2e(t,this,e),this.readable=!0,t&&(typeof t.read==\"function\"&&(this._read=t.read),typeof t.destroy==\"function\"&&(this._destroy=t.destroy)),wv.call(this)}Object.defineProperty(mn.prototype,\"destroyed\",{enumerable:!1,get:function(){return this._readableState===void 0?!1:this._readableState.destroyed},set:function(e){!this._readableState||(this._readableState.destroyed=e)}});mn.prototype.destroy=JG.destroy;mn.prototype._undestroy=JG.undestroy;mn.prototype._destroy=function(t,e){e(t)};mn.prototype.push=function(t,e){var r=this._readableState,o;return r.objectMode?o=!0:typeof t==\"string\"&&(e=e||r.defaultEncoding,e!==r.encoding&&(t=UQ.from(t,e),e=\"\"),o=!0),g2e(this,t,e,!1,o)};mn.prototype.unshift=function(t){return g2e(this,t,null,!0,!1)};function g2e(t,e,r,o,a){en(\"readableAddChunk\",e);var n=t._readableState;if(e===null)n.reading=!1,yBt(t,n);else{var u;if(a||(u=dBt(n,e)),u)Cv(t,u);else if(n.objectMode||e&&e.length>0)if(typeof e!=\"string\"&&!n.objectMode&&Object.getPrototypeOf(e)!==UQ.prototype&&(e=oBt(e)),o)n.endEmitted?Cv(t,new hBt):KG(t,n,e,!0);else if(n.ended)Cv(t,new fBt);else{if(n.destroyed)return!1;n.reading=!1,n.decoder&&!r?(e=n.decoder.write(e),n.objectMode||e.length!==0?KG(t,n,e,!1):VG(t,n)):KG(t,n,e,!1)}else o||(n.reading=!1,VG(t,n))}return!n.ended&&(n.length<n.highWaterMark||n.length===0)}function KG(t,e,r,o){e.flowing&&e.length===0&&!e.sync?(e.awaitDrain=0,t.emit(\"data\",r)):(e.length+=e.objectMode?1:r.length,o?e.buffer.unshift(r):e.buffer.push(r),e.needReadable&&HQ(t)),VG(t,e)}function dBt(t,e){var r;return!aBt(e)&&typeof e!=\"string\"&&e!==void 0&&!t.objectMode&&(r=new ABt(\"chunk\",[\"string\",\"Buffer\",\"Uint8Array\"],e)),r}mn.prototype.isPaused=function(){return this._readableState.flowing===!1};mn.prototype.setEncoding=function(t){ew||(ew=HG().StringDecoder);var e=new ew(t);this._readableState.decoder=e,this._readableState.encoding=this._readableState.decoder.encoding;for(var r=this._readableState.buffer.head,o=\"\";r!==null;)o+=e.write(r.data),r=r.next;return this._readableState.buffer.clear(),o!==\"\"&&this._readableState.buffer.push(o),this._readableState.length=o.length,this};var A2e=1073741824;function mBt(t){return t>=A2e?t=A2e:(t--,t|=t>>>1,t|=t>>>2,t|=t>>>4,t|=t>>>8,t|=t>>>16,t++),t}function f2e(t,e){return t<=0||e.length===0&&e.ended?0:e.objectMode?1:t!==t?e.flowing&&e.length?e.buffer.head.data.length:e.length:(t>e.highWaterMark&&(e.highWaterMark=mBt(t)),t<=e.length?t:e.ended?e.length:(e.needReadable=!0,0))}mn.prototype.read=function(t){en(\"read\",t),t=parseInt(t,10);var e=this._readableState,r=t;if(t!==0&&(e.emittedReadable=!1),t===0&&e.needReadable&&((e.highWaterMark!==0?e.length>=e.highWaterMark:e.length>0)||e.ended))return en(\"read: emitReadable\",e.length,e.ended),e.length===0&&e.ended?zG(this):HQ(this),null;if(t=f2e(t,e),t===0&&e.ended)return e.length===0&&zG(this),null;var o=e.needReadable;en(\"need readable\",o),(e.length===0||e.length-t<e.highWaterMark)&&(o=!0,en(\"length less than watermark\",o)),e.ended||e.reading?(o=!1,en(\"reading or ended\",o)):o&&(en(\"do read\"),e.reading=!0,e.sync=!0,e.length===0&&(e.needReadable=!0),this._read(e.highWaterMark),e.sync=!1,e.reading||(t=f2e(r,e)));var a;return t>0?a=y2e(t,e):a=null,a===null?(e.needReadable=e.length<=e.highWaterMark,t=0):(e.length-=t,e.awaitDrain=0),e.length===0&&(e.ended||(e.needReadable=!0),r!==t&&e.ended&&zG(this)),a!==null&&this.emit(\"data\",a),a};function yBt(t,e){if(en(\"onEofChunk\"),!e.ended){if(e.decoder){var r=e.decoder.end();r&&r.length&&(e.buffer.push(r),e.length+=e.objectMode?1:r.length)}e.ended=!0,e.sync?HQ(t):(e.needReadable=!1,e.emittedReadable||(e.emittedReadable=!0,d2e(t)))}}function HQ(t){var e=t._readableState;en(\"emitReadable\",e.needReadable,e.emittedReadable),e.needReadable=!1,e.emittedReadable||(en(\"emitReadable\",e.flowing),e.emittedReadable=!0,process.nextTick(d2e,t))}function d2e(t){var e=t._readableState;en(\"emitReadable_\",e.destroyed,e.length,e.ended),!e.destroyed&&(e.length||e.ended)&&(t.emit(\"readable\"),e.emittedReadable=!1),e.needReadable=!e.flowing&&!e.ended&&e.length<=e.highWaterMark,XG(t)}function VG(t,e){e.readingMore||(e.readingMore=!0,process.nextTick(EBt,t,e))}function EBt(t,e){for(;!e.reading&&!e.ended&&(e.length<e.highWaterMark||e.flowing&&e.length===0);){var r=e.length;if(en(\"maybeReadMore read 0\"),t.read(0),r===e.length)break}e.readingMore=!1}mn.prototype._read=function(t){Cv(this,new pBt(\"_read()\"))};mn.prototype.pipe=function(t,e){var r=this,o=this._readableState;switch(o.pipesCount){case 0:o.pipes=t;break;case 1:o.pipes=[o.pipes,t];break;default:o.pipes.push(t);break}o.pipesCount+=1,en(\"pipe count=%d opts=%j\",o.pipesCount,e);var a=(!e||e.end!==!1)&&t!==process.stdout&&t!==process.stderr,n=a?A:R;o.endEmitted?process.nextTick(n):r.once(\"end\",n),t.on(\"unpipe\",u);function u(N,U){en(\"onunpipe\"),N===r&&U&&U.hasUnpiped===!1&&(U.hasUnpiped=!0,E())}function A(){en(\"onend\"),t.end()}var p=CBt(r);t.on(\"drain\",p);var h=!1;function E(){en(\"cleanup\"),t.removeListener(\"close\",x),t.removeListener(\"finish\",C),t.removeListener(\"drain\",p),t.removeListener(\"error\",v),t.removeListener(\"unpipe\",u),r.removeListener(\"end\",A),r.removeListener(\"end\",R),r.removeListener(\"data\",I),h=!0,o.awaitDrain&&(!t._writableState||t._writableState.needDrain)&&p()}r.on(\"data\",I);function I(N){en(\"ondata\");var U=t.write(N);en(\"dest.write\",U),U===!1&&((o.pipesCount===1&&o.pipes===t||o.pipesCount>1&&E2e(o.pipes,t)!==-1)&&!h&&(en(\"false write response, pause\",o.awaitDrain),o.awaitDrain++),r.pause())}function v(N){en(\"onerror\",N),R(),t.removeListener(\"error\",v),p2e(t,\"error\")===0&&Cv(t,N)}gBt(t,\"error\",v);function x(){t.removeListener(\"finish\",C),R()}t.once(\"close\",x);function C(){en(\"onfinish\"),t.removeListener(\"close\",x),R()}t.once(\"finish\",C);function R(){en(\"unpipe\"),r.unpipe(t)}return t.emit(\"pipe\",r),o.flowing||(en(\"pipe resume\"),r.resume()),t};function CBt(t){return function(){var r=t._readableState;en(\"pipeOnDrain\",r.awaitDrain),r.awaitDrain&&r.awaitDrain--,r.awaitDrain===0&&p2e(t,\"data\")&&(r.flowing=!0,XG(t))}}mn.prototype.unpipe=function(t){var e=this._readableState,r={hasUnpiped:!1};if(e.pipesCount===0)return this;if(e.pipesCount===1)return t&&t!==e.pipes?this:(t||(t=e.pipes),e.pipes=null,e.pipesCount=0,e.flowing=!1,t&&t.emit(\"unpipe\",this,r),this);if(!t){var o=e.pipes,a=e.pipesCount;e.pipes=null,e.pipesCount=0,e.flowing=!1;for(var n=0;n<a;n++)o[n].emit(\"unpipe\",this,{hasUnpiped:!1});return this}var u=E2e(e.pipes,t);return u===-1?this:(e.pipes.splice(u,1),e.pipesCount-=1,e.pipesCount===1&&(e.pipes=e.pipes[0]),t.emit(\"unpipe\",this,r),this)};mn.prototype.on=function(t,e){var r=wv.prototype.on.call(this,t,e),o=this._readableState;return t===\"data\"?(o.readableListening=this.listenerCount(\"readable\")>0,o.flowing!==!1&&this.resume()):t===\"readable\"&&!o.endEmitted&&!o.readableListening&&(o.readableListening=o.needReadable=!0,o.flowing=!1,o.emittedReadable=!1,en(\"on readable\",o.length,o.reading),o.length?HQ(this):o.reading||process.nextTick(wBt,this)),r};mn.prototype.addListener=mn.prototype.on;mn.prototype.removeListener=function(t,e){var r=wv.prototype.removeListener.call(this,t,e);return t===\"readable\"&&process.nextTick(m2e,this),r};mn.prototype.removeAllListeners=function(t){var e=wv.prototype.removeAllListeners.apply(this,arguments);return(t===\"readable\"||t===void 0)&&process.nextTick(m2e,this),e};function m2e(t){var e=t._readableState;e.readableListening=t.listenerCount(\"readable\")>0,e.resumeScheduled&&!e.paused?e.flowing=!0:t.listenerCount(\"data\")>0&&t.resume()}function wBt(t){en(\"readable nexttick read 0\"),t.read(0)}mn.prototype.resume=function(){var t=this._readableState;return t.flowing||(en(\"resume\"),t.flowing=!t.readableListening,IBt(this,t)),t.paused=!1,this};function IBt(t,e){e.resumeScheduled||(e.resumeScheduled=!0,process.nextTick(BBt,t,e))}function BBt(t,e){en(\"resume\",e.reading),e.reading||t.read(0),e.resumeScheduled=!1,t.emit(\"resume\"),XG(t),e.flowing&&!e.reading&&t.read(0)}mn.prototype.pause=function(){return en(\"call pause flowing=%j\",this._readableState.flowing),this._readableState.flowing!==!1&&(en(\"pause\"),this._readableState.flowing=!1,this.emit(\"pause\")),this._readableState.paused=!0,this};function XG(t){var e=t._readableState;for(en(\"flow\",e.flowing);e.flowing&&t.read()!==null;);}mn.prototype.wrap=function(t){var e=this,r=this._readableState,o=!1;t.on(\"end\",function(){if(en(\"wrapped end\"),r.decoder&&!r.ended){var u=r.decoder.end();u&&u.length&&e.push(u)}e.push(null)}),t.on(\"data\",function(u){if(en(\"wrapped data\"),r.decoder&&(u=r.decoder.write(u)),!(r.objectMode&&u==null)&&!(!r.objectMode&&(!u||!u.length))){var A=e.push(u);A||(o=!0,t.pause())}});for(var a in t)this[a]===void 0&&typeof t[a]==\"function\"&&(this[a]=function(A){return function(){return t[A].apply(t,arguments)}}(a));for(var n=0;n<WG.length;n++)t.on(WG[n],this.emit.bind(this,WG[n]));return this._read=function(u){en(\"wrapped _read\",u),o&&(o=!1,t.resume())},this};typeof Symbol==\"function\"&&(mn.prototype[Symbol.asyncIterator]=function(){return jG===void 0&&(jG=o2e()),jG(this)});Object.defineProperty(mn.prototype,\"readableHighWaterMark\",{enumerable:!1,get:function(){return this._readableState.highWaterMark}});Object.defineProperty(mn.prototype,\"readableBuffer\",{enumerable:!1,get:function(){return this._readableState&&this._readableState.buffer}});Object.defineProperty(mn.prototype,\"readableFlowing\",{enumerable:!1,get:function(){return this._readableState.flowing},set:function(e){this._readableState&&(this._readableState.flowing=e)}});mn._fromList=y2e;Object.defineProperty(mn.prototype,\"readableLength\",{enumerable:!1,get:function(){return this._readableState.length}});function y2e(t,e){if(e.length===0)return null;var r;return e.objectMode?r=e.buffer.shift():!t||t>=e.length?(e.decoder?r=e.buffer.join(\"\"):e.buffer.length===1?r=e.buffer.first():r=e.buffer.concat(e.length),e.buffer.clear()):r=e.buffer.consume(t,e.decoder),r}function zG(t){var e=t._readableState;en(\"endReadable\",e.endEmitted),e.endEmitted||(e.ended=!0,process.nextTick(vBt,e,t))}function vBt(t,e){if(en(\"endReadableNT\",t.endEmitted,t.length),!t.endEmitted&&t.length===0&&(t.endEmitted=!0,e.readable=!1,e.emit(\"end\"),t.autoDestroy)){var r=e._writableState;(!r||r.autoDestroy&&r.finished)&&e.destroy()}}typeof Symbol==\"function\"&&(mn.from=function(t,e){return YG===void 0&&(YG=u2e()),YG(mn,t,e)});function E2e(t,e){for(var r=0,o=t.length;r<o;r++)if(t[r]===e)return r;return-1}});var ZG=_((R$t,I2e)=>{\"use strict\";I2e.exports=op;var qQ=F0().codes,DBt=qQ.ERR_METHOD_NOT_IMPLEMENTED,PBt=qQ.ERR_MULTIPLE_CALLBACK,SBt=qQ.ERR_TRANSFORM_ALREADY_TRANSFORMING,bBt=qQ.ERR_TRANSFORM_WITH_LENGTH_0,GQ=Cm();R0()(op,GQ);function xBt(t,e){var r=this._transformState;r.transforming=!1;var o=r.writecb;if(o===null)return this.emit(\"error\",new PBt);r.writechunk=null,r.writecb=null,e!=null&&this.push(e),o(t);var a=this._readableState;a.reading=!1,(a.needReadable||a.length<a.highWaterMark)&&this._read(a.highWaterMark)}function op(t){if(!(this instanceof op))return new op(t);GQ.call(this,t),this._transformState={afterTransform:xBt.bind(this),needTransform:!1,transforming:!1,writecb:null,writechunk:null,writeencoding:null},this._readableState.needReadable=!0,this._readableState.sync=!1,t&&(typeof t.transform==\"function\"&&(this._transform=t.transform),typeof t.flush==\"function\"&&(this._flush=t.flush)),this.on(\"prefinish\",kBt)}function kBt(){var t=this;typeof this._flush==\"function\"&&!this._readableState.destroyed?this._flush(function(e,r){w2e(t,e,r)}):w2e(this,null,null)}op.prototype.push=function(t,e){return this._transformState.needTransform=!1,GQ.prototype.push.call(this,t,e)};op.prototype._transform=function(t,e,r){r(new DBt(\"_transform()\"))};op.prototype._write=function(t,e,r){var o=this._transformState;if(o.writecb=r,o.writechunk=t,o.writeencoding=e,!o.transforming){var a=this._readableState;(o.needTransform||a.needReadable||a.length<a.highWaterMark)&&this._read(a.highWaterMark)}};op.prototype._read=function(t){var e=this._transformState;e.writechunk!==null&&!e.transforming?(e.transforming=!0,this._transform(e.writechunk,e.writeencoding,e.afterTransform)):e.needTransform=!0};op.prototype._destroy=function(t,e){GQ.prototype._destroy.call(this,t,function(r){e(r)})};function w2e(t,e,r){if(e)return t.emit(\"error\",e);if(r!=null&&t.push(r),t._writableState.length)throw new bBt;if(t._transformState.transforming)throw new SBt;return t.push(null)}});var D2e=_((T$t,v2e)=>{\"use strict\";v2e.exports=Iv;var B2e=ZG();R0()(Iv,B2e);function Iv(t){if(!(this instanceof Iv))return new Iv(t);B2e.call(this,t)}Iv.prototype._transform=function(t,e,r){r(null,t)}});var k2e=_((L$t,x2e)=>{\"use strict\";var $G;function QBt(t){var e=!1;return function(){e||(e=!0,t.apply(void 0,arguments))}}var b2e=F0().codes,FBt=b2e.ERR_MISSING_ARGS,RBt=b2e.ERR_STREAM_DESTROYED;function P2e(t){if(t)throw t}function TBt(t){return t.setHeader&&typeof t.abort==\"function\"}function LBt(t,e,r,o){o=QBt(o);var a=!1;t.on(\"close\",function(){a=!0}),$G===void 0&&($G=NQ()),$G(t,{readable:e,writable:r},function(u){if(u)return o(u);a=!0,o()});var n=!1;return function(u){if(!a&&!n){if(n=!0,TBt(t))return t.abort();if(typeof t.destroy==\"function\")return t.destroy();o(u||new RBt(\"pipe\"))}}}function S2e(t){t()}function NBt(t,e){return t.pipe(e)}function OBt(t){return!t.length||typeof t[t.length-1]!=\"function\"?P2e:t.pop()}function MBt(){for(var t=arguments.length,e=new Array(t),r=0;r<t;r++)e[r]=arguments[r];var o=OBt(e);if(Array.isArray(e[0])&&(e=e[0]),e.length<2)throw new FBt(\"streams\");var a,n=e.map(function(u,A){var p=A<e.length-1,h=A>0;return LBt(u,p,h,function(E){a||(a=E),E&&n.forEach(S2e),!p&&(n.forEach(S2e),o(a))})});return e.reduce(NBt)}x2e.exports=MBt});var tw=_((cc,vv)=>{var Bv=ve(\"stream\");process.env.READABLE_STREAM===\"disable\"&&Bv?(vv.exports=Bv.Readable,Object.assign(vv.exports,Bv),vv.exports.Stream=Bv):(cc=vv.exports=OG(),cc.Stream=Bv||cc,cc.Readable=cc,cc.Writable=TG(),cc.Duplex=Cm(),cc.Transform=ZG(),cc.PassThrough=D2e(),cc.finished=NQ(),cc.pipeline=k2e())});var R2e=_((N$t,F2e)=>{\"use strict\";var{Buffer:cu}=ve(\"buffer\"),Q2e=Symbol.for(\"BufferList\");function ni(t){if(!(this instanceof ni))return new ni(t);ni._init.call(this,t)}ni._init=function(e){Object.defineProperty(this,Q2e,{value:!0}),this._bufs=[],this.length=0,e&&this.append(e)};ni.prototype._new=function(e){return new ni(e)};ni.prototype._offset=function(e){if(e===0)return[0,0];let r=0;for(let o=0;o<this._bufs.length;o++){let a=r+this._bufs[o].length;if(e<a||o===this._bufs.length-1)return[o,e-r];r=a}};ni.prototype._reverseOffset=function(t){let e=t[0],r=t[1];for(let o=0;o<e;o++)r+=this._bufs[o].length;return r};ni.prototype.get=function(e){if(e>this.length||e<0)return;let r=this._offset(e);return this._bufs[r[0]][r[1]]};ni.prototype.slice=function(e,r){return typeof e==\"number\"&&e<0&&(e+=this.length),typeof r==\"number\"&&r<0&&(r+=this.length),this.copy(null,0,e,r)};ni.prototype.copy=function(e,r,o,a){if((typeof o!=\"number\"||o<0)&&(o=0),(typeof a!=\"number\"||a>this.length)&&(a=this.length),o>=this.length||a<=0)return e||cu.alloc(0);let n=!!e,u=this._offset(o),A=a-o,p=A,h=n&&r||0,E=u[1];if(o===0&&a===this.length){if(!n)return this._bufs.length===1?this._bufs[0]:cu.concat(this._bufs,this.length);for(let I=0;I<this._bufs.length;I++)this._bufs[I].copy(e,h),h+=this._bufs[I].length;return e}if(p<=this._bufs[u[0]].length-E)return n?this._bufs[u[0]].copy(e,r,E,E+p):this._bufs[u[0]].slice(E,E+p);n||(e=cu.allocUnsafe(A));for(let I=u[0];I<this._bufs.length;I++){let v=this._bufs[I].length-E;if(p>v)this._bufs[I].copy(e,h,E),h+=v;else{this._bufs[I].copy(e,h,E,E+p),h+=v;break}p-=v,E&&(E=0)}return e.length>h?e.slice(0,h):e};ni.prototype.shallowSlice=function(e,r){if(e=e||0,r=typeof r!=\"number\"?this.length:r,e<0&&(e+=this.length),r<0&&(r+=this.length),e===r)return this._new();let o=this._offset(e),a=this._offset(r),n=this._bufs.slice(o[0],a[0]+1);return a[1]===0?n.pop():n[n.length-1]=n[n.length-1].slice(0,a[1]),o[1]!==0&&(n[0]=n[0].slice(o[1])),this._new(n)};ni.prototype.toString=function(e,r,o){return this.slice(r,o).toString(e)};ni.prototype.consume=function(e){if(e=Math.trunc(e),Number.isNaN(e)||e<=0)return this;for(;this._bufs.length;)if(e>=this._bufs[0].length)e-=this._bufs[0].length,this.length-=this._bufs[0].length,this._bufs.shift();else{this._bufs[0]=this._bufs[0].slice(e),this.length-=e;break}return this};ni.prototype.duplicate=function(){let e=this._new();for(let r=0;r<this._bufs.length;r++)e.append(this._bufs[r]);return e};ni.prototype.append=function(e){if(e==null)return this;if(e.buffer)this._appendBuffer(cu.from(e.buffer,e.byteOffset,e.byteLength));else if(Array.isArray(e))for(let r=0;r<e.length;r++)this.append(e[r]);else if(this._isBufferList(e))for(let r=0;r<e._bufs.length;r++)this.append(e._bufs[r]);else typeof e==\"number\"&&(e=e.toString()),this._appendBuffer(cu.from(e));return this};ni.prototype._appendBuffer=function(e){this._bufs.push(e),this.length+=e.length};ni.prototype.indexOf=function(t,e,r){if(r===void 0&&typeof e==\"string\"&&(r=e,e=void 0),typeof t==\"function\"||Array.isArray(t))throw new TypeError('The \"value\" argument must be one of type string, Buffer, BufferList, or Uint8Array.');if(typeof t==\"number\"?t=cu.from([t]):typeof t==\"string\"?t=cu.from(t,r):this._isBufferList(t)?t=t.slice():Array.isArray(t.buffer)?t=cu.from(t.buffer,t.byteOffset,t.byteLength):cu.isBuffer(t)||(t=cu.from(t)),e=Number(e||0),isNaN(e)&&(e=0),e<0&&(e=this.length+e),e<0&&(e=0),t.length===0)return e>this.length?this.length:e;let o=this._offset(e),a=o[0],n=o[1];for(;a<this._bufs.length;a++){let u=this._bufs[a];for(;n<u.length;)if(u.length-n>=t.length){let p=u.indexOf(t,n);if(p!==-1)return this._reverseOffset([a,p]);n=u.length-t.length+1}else{let p=this._reverseOffset([a,n]);if(this._match(p,t))return p;n++}n=0}return-1};ni.prototype._match=function(t,e){if(this.length-t<e.length)return!1;for(let r=0;r<e.length;r++)if(this.get(t+r)!==e[r])return!1;return!0};(function(){let t={readDoubleBE:8,readDoubleLE:8,readFloatBE:4,readFloatLE:4,readInt32BE:4,readInt32LE:4,readUInt32BE:4,readUInt32LE:4,readInt16BE:2,readInt16LE:2,readUInt16BE:2,readUInt16LE:2,readInt8:1,readUInt8:1,readIntBE:null,readIntLE:null,readUIntBE:null,readUIntLE:null};for(let e in t)(function(r){t[r]===null?ni.prototype[r]=function(o,a){return this.slice(o,o+a)[r](0,a)}:ni.prototype[r]=function(o=0){return this.slice(o,o+t[r])[r](0)}})(e)})();ni.prototype._isBufferList=function(e){return e instanceof ni||ni.isBufferList(e)};ni.isBufferList=function(e){return e!=null&&e[Q2e]};F2e.exports=ni});var T2e=_((O$t,jQ)=>{\"use strict\";var ej=tw().Duplex,UBt=R0(),Dv=R2e();function Uo(t){if(!(this instanceof Uo))return new Uo(t);if(typeof t==\"function\"){this._callback=t;let e=function(o){this._callback&&(this._callback(o),this._callback=null)}.bind(this);this.on(\"pipe\",function(o){o.on(\"error\",e)}),this.on(\"unpipe\",function(o){o.removeListener(\"error\",e)}),t=null}Dv._init.call(this,t),ej.call(this)}UBt(Uo,ej);Object.assign(Uo.prototype,Dv.prototype);Uo.prototype._new=function(e){return new Uo(e)};Uo.prototype._write=function(e,r,o){this._appendBuffer(e),typeof o==\"function\"&&o()};Uo.prototype._read=function(e){if(!this.length)return this.push(null);e=Math.min(e,this.length),this.push(this.slice(0,e)),this.consume(e)};Uo.prototype.end=function(e){ej.prototype.end.call(this,e),this._callback&&(this._callback(null,this.slice()),this._callback=null)};Uo.prototype._destroy=function(e,r){this._bufs.length=0,this.length=0,r(e)};Uo.prototype._isBufferList=function(e){return e instanceof Uo||e instanceof Dv||Uo.isBufferList(e)};Uo.isBufferList=Dv.isBufferList;jQ.exports=Uo;jQ.exports.BufferListStream=Uo;jQ.exports.BufferList=Dv});var nj=_(nw=>{var _Bt=Buffer.alloc,HBt=\"0000000000000000000\",qBt=\"7777777777777777777\",L2e=\"0\".charCodeAt(0),N2e=Buffer.from(\"ustar\\0\",\"binary\"),GBt=Buffer.from(\"00\",\"binary\"),jBt=Buffer.from(\"ustar \",\"binary\"),YBt=Buffer.from(\" \\0\",\"binary\"),WBt=parseInt(\"7777\",8),Pv=257,rj=263,KBt=function(t,e,r){return typeof t!=\"number\"?r:(t=~~t,t>=e?e:t>=0||(t+=e,t>=0)?t:0)},zBt=function(t){switch(t){case 0:return\"file\";case 1:return\"link\";case 2:return\"symlink\";case 3:return\"character-device\";case 4:return\"block-device\";case 5:return\"directory\";case 6:return\"fifo\";case 7:return\"contiguous-file\";case 72:return\"pax-header\";case 55:return\"pax-global-header\";case 27:return\"gnu-long-link-path\";case 28:case 30:return\"gnu-long-path\"}return null},VBt=function(t){switch(t){case\"file\":return 0;case\"link\":return 1;case\"symlink\":return 2;case\"character-device\":return 3;case\"block-device\":return 4;case\"directory\":return 5;case\"fifo\":return 6;case\"contiguous-file\":return 7;case\"pax-header\":return 72}return 0},O2e=function(t,e,r,o){for(;r<o;r++)if(t[r]===e)return r;return o},M2e=function(t){for(var e=256,r=0;r<148;r++)e+=t[r];for(var o=156;o<512;o++)e+=t[o];return e},M0=function(t,e){return t=t.toString(8),t.length>e?qBt.slice(0,e)+\" \":HBt.slice(0,e-t.length)+t+\" \"};function JBt(t){var e;if(t[0]===128)e=!0;else if(t[0]===255)e=!1;else return null;for(var r=[],o=t.length-1;o>0;o--){var a=t[o];e?r.push(a):r.push(255-a)}var n=0,u=r.length;for(o=0;o<u;o++)n+=r[o]*Math.pow(256,o);return e?n:-1*n}var U0=function(t,e,r){if(t=t.slice(e,e+r),e=0,t[e]&128)return JBt(t);for(;e<t.length&&t[e]===32;)e++;for(var o=KBt(O2e(t,32,e,t.length),t.length,t.length);e<o&&t[e]===0;)e++;return o===e?0:parseInt(t.slice(e,o).toString(),8)},rw=function(t,e,r,o){return t.slice(e,O2e(t,0,e,e+r)).toString(o)},tj=function(t){var e=Buffer.byteLength(t),r=Math.floor(Math.log(e)/Math.log(10))+1;return e+r>=Math.pow(10,r)&&r++,e+r+t};nw.decodeLongPath=function(t,e){return rw(t,0,t.length,e)};nw.encodePax=function(t){var e=\"\";t.name&&(e+=tj(\" path=\"+t.name+`\n`)),t.linkname&&(e+=tj(\" linkpath=\"+t.linkname+`\n`));var r=t.pax;if(r)for(var o in r)e+=tj(\" \"+o+\"=\"+r[o]+`\n`);return Buffer.from(e)};nw.decodePax=function(t){for(var e={};t.length;){for(var r=0;r<t.length&&t[r]!==32;)r++;var o=parseInt(t.slice(0,r).toString(),10);if(!o)return e;var a=t.slice(r+1,o-1).toString(),n=a.indexOf(\"=\");if(n===-1)return e;e[a.slice(0,n)]=a.slice(n+1),t=t.slice(o)}return e};nw.encode=function(t){var e=_Bt(512),r=t.name,o=\"\";if(t.typeflag===5&&r[r.length-1]!==\"/\"&&(r+=\"/\"),Buffer.byteLength(r)!==r.length)return null;for(;Buffer.byteLength(r)>100;){var a=r.indexOf(\"/\");if(a===-1)return null;o+=o?\"/\"+r.slice(0,a):r.slice(0,a),r=r.slice(a+1)}return Buffer.byteLength(r)>100||Buffer.byteLength(o)>155||t.linkname&&Buffer.byteLength(t.linkname)>100?null:(e.write(r),e.write(M0(t.mode&WBt,6),100),e.write(M0(t.uid,6),108),e.write(M0(t.gid,6),116),e.write(M0(t.size,11),124),e.write(M0(t.mtime.getTime()/1e3|0,11),136),e[156]=L2e+VBt(t.type),t.linkname&&e.write(t.linkname,157),N2e.copy(e,Pv),GBt.copy(e,rj),t.uname&&e.write(t.uname,265),t.gname&&e.write(t.gname,297),e.write(M0(t.devmajor||0,6),329),e.write(M0(t.devminor||0,6),337),o&&e.write(o,345),e.write(M0(M2e(e),6),148),e)};nw.decode=function(t,e,r){var o=t[156]===0?0:t[156]-L2e,a=rw(t,0,100,e),n=U0(t,100,8),u=U0(t,108,8),A=U0(t,116,8),p=U0(t,124,12),h=U0(t,136,12),E=zBt(o),I=t[157]===0?null:rw(t,157,100,e),v=rw(t,265,32),x=rw(t,297,32),C=U0(t,329,8),R=U0(t,337,8),N=M2e(t);if(N===8*32)return null;if(N!==U0(t,148,8))throw new Error(\"Invalid tar header. Maybe the tar is corrupted or it needs to be gunzipped?\");if(N2e.compare(t,Pv,Pv+6)===0)t[345]&&(a=rw(t,345,155,e)+\"/\"+a);else if(!(jBt.compare(t,Pv,Pv+6)===0&&YBt.compare(t,rj,rj+2)===0)){if(!r)throw new Error(\"Invalid tar header: unknown format.\")}return o===0&&a&&a[a.length-1]===\"/\"&&(o=5),{name:a,mode:n,uid:u,gid:A,size:p,mtime:new Date(1e3*h),type:E,linkname:I,uname:v,gname:x,devmajor:C,devminor:R}}});var Y2e=_((U$t,j2e)=>{var _2e=ve(\"util\"),XBt=T2e(),Sv=nj(),H2e=tw().Writable,q2e=tw().PassThrough,G2e=function(){},U2e=function(t){return t&=511,t&&512-t},ZBt=function(t,e){var r=new YQ(t,e);return r.end(),r},$Bt=function(t,e){return e.path&&(t.name=e.path),e.linkpath&&(t.linkname=e.linkpath),e.size&&(t.size=parseInt(e.size,10)),t.pax=e,t},YQ=function(t,e){this._parent=t,this.offset=e,q2e.call(this,{autoDestroy:!1})};_2e.inherits(YQ,q2e);YQ.prototype.destroy=function(t){this._parent.destroy(t)};var ap=function(t){if(!(this instanceof ap))return new ap(t);H2e.call(this,t),t=t||{},this._offset=0,this._buffer=XBt(),this._missing=0,this._partial=!1,this._onparse=G2e,this._header=null,this._stream=null,this._overflow=null,this._cb=null,this._locked=!1,this._destroyed=!1,this._pax=null,this._paxGlobal=null,this._gnuLongPath=null,this._gnuLongLinkPath=null;var e=this,r=e._buffer,o=function(){e._continue()},a=function(v){if(e._locked=!1,v)return e.destroy(v);e._stream||o()},n=function(){e._stream=null;var v=U2e(e._header.size);v?e._parse(v,u):e._parse(512,I),e._locked||o()},u=function(){e._buffer.consume(U2e(e._header.size)),e._parse(512,I),o()},A=function(){var v=e._header.size;e._paxGlobal=Sv.decodePax(r.slice(0,v)),r.consume(v),n()},p=function(){var v=e._header.size;e._pax=Sv.decodePax(r.slice(0,v)),e._paxGlobal&&(e._pax=Object.assign({},e._paxGlobal,e._pax)),r.consume(v),n()},h=function(){var v=e._header.size;this._gnuLongPath=Sv.decodeLongPath(r.slice(0,v),t.filenameEncoding),r.consume(v),n()},E=function(){var v=e._header.size;this._gnuLongLinkPath=Sv.decodeLongPath(r.slice(0,v),t.filenameEncoding),r.consume(v),n()},I=function(){var v=e._offset,x;try{x=e._header=Sv.decode(r.slice(0,512),t.filenameEncoding,t.allowUnknownFormat)}catch(C){e.emit(\"error\",C)}if(r.consume(512),!x){e._parse(512,I),o();return}if(x.type===\"gnu-long-path\"){e._parse(x.size,h),o();return}if(x.type===\"gnu-long-link-path\"){e._parse(x.size,E),o();return}if(x.type===\"pax-global-header\"){e._parse(x.size,A),o();return}if(x.type===\"pax-header\"){e._parse(x.size,p),o();return}if(e._gnuLongPath&&(x.name=e._gnuLongPath,e._gnuLongPath=null),e._gnuLongLinkPath&&(x.linkname=e._gnuLongLinkPath,e._gnuLongLinkPath=null),e._pax&&(e._header=x=$Bt(x,e._pax),e._pax=null),e._locked=!0,!x.size||x.type===\"directory\"){e._parse(512,I),e.emit(\"entry\",x,ZBt(e,v),a);return}e._stream=new YQ(e,v),e.emit(\"entry\",x,e._stream,a),e._parse(x.size,n),o()};this._onheader=I,this._parse(512,I)};_2e.inherits(ap,H2e);ap.prototype.destroy=function(t){this._destroyed||(this._destroyed=!0,t&&this.emit(\"error\",t),this.emit(\"close\"),this._stream&&this._stream.emit(\"close\"))};ap.prototype._parse=function(t,e){this._destroyed||(this._offset+=t,this._missing=t,e===this._onheader&&(this._partial=!1),this._onparse=e)};ap.prototype._continue=function(){if(!this._destroyed){var t=this._cb;this._cb=G2e,this._overflow?this._write(this._overflow,void 0,t):t()}};ap.prototype._write=function(t,e,r){if(!this._destroyed){var o=this._stream,a=this._buffer,n=this._missing;if(t.length&&(this._partial=!0),t.length<n)return this._missing-=t.length,this._overflow=null,o?o.write(t,r):(a.append(t),r());this._cb=r,this._missing=0;var u=null;t.length>n&&(u=t.slice(n),t=t.slice(0,n)),o?o.end(t):a.append(t),this._overflow=u,this._onparse()}};ap.prototype._final=function(t){if(this._partial)return this.destroy(new Error(\"Unexpected end of data\"));t()};j2e.exports=ap});var K2e=_((_$t,W2e)=>{W2e.exports=ve(\"fs\").constants||ve(\"constants\")});var Z2e=_((H$t,X2e)=>{var iw=K2e(),z2e=NM(),KQ=R0(),evt=Buffer.alloc,V2e=tw().Readable,sw=tw().Writable,tvt=ve(\"string_decoder\").StringDecoder,WQ=nj(),rvt=parseInt(\"755\",8),nvt=parseInt(\"644\",8),J2e=evt(1024),sj=function(){},ij=function(t,e){e&=511,e&&t.push(J2e.slice(0,512-e))};function ivt(t){switch(t&iw.S_IFMT){case iw.S_IFBLK:return\"block-device\";case iw.S_IFCHR:return\"character-device\";case iw.S_IFDIR:return\"directory\";case iw.S_IFIFO:return\"fifo\";case iw.S_IFLNK:return\"symlink\"}return\"file\"}var zQ=function(t){sw.call(this),this.written=0,this._to=t,this._destroyed=!1};KQ(zQ,sw);zQ.prototype._write=function(t,e,r){if(this.written+=t.length,this._to.push(t))return r();this._to._drain=r};zQ.prototype.destroy=function(){this._destroyed||(this._destroyed=!0,this.emit(\"close\"))};var VQ=function(){sw.call(this),this.linkname=\"\",this._decoder=new tvt(\"utf-8\"),this._destroyed=!1};KQ(VQ,sw);VQ.prototype._write=function(t,e,r){this.linkname+=this._decoder.write(t),r()};VQ.prototype.destroy=function(){this._destroyed||(this._destroyed=!0,this.emit(\"close\"))};var bv=function(){sw.call(this),this._destroyed=!1};KQ(bv,sw);bv.prototype._write=function(t,e,r){r(new Error(\"No body allowed for this entry\"))};bv.prototype.destroy=function(){this._destroyed||(this._destroyed=!0,this.emit(\"close\"))};var CA=function(t){if(!(this instanceof CA))return new CA(t);V2e.call(this,t),this._drain=sj,this._finalized=!1,this._finalizing=!1,this._destroyed=!1,this._stream=null};KQ(CA,V2e);CA.prototype.entry=function(t,e,r){if(this._stream)throw new Error(\"already piping an entry\");if(!(this._finalized||this._destroyed)){typeof e==\"function\"&&(r=e,e=null),r||(r=sj);var o=this;if((!t.size||t.type===\"symlink\")&&(t.size=0),t.type||(t.type=ivt(t.mode)),t.mode||(t.mode=t.type===\"directory\"?rvt:nvt),t.uid||(t.uid=0),t.gid||(t.gid=0),t.mtime||(t.mtime=new Date),typeof e==\"string\"&&(e=Buffer.from(e)),Buffer.isBuffer(e)){t.size=e.length,this._encode(t);var a=this.push(e);return ij(o,t.size),a?process.nextTick(r):this._drain=r,new bv}if(t.type===\"symlink\"&&!t.linkname){var n=new VQ;return z2e(n,function(A){if(A)return o.destroy(),r(A);t.linkname=n.linkname,o._encode(t),r()}),n}if(this._encode(t),t.type!==\"file\"&&t.type!==\"contiguous-file\")return process.nextTick(r),new bv;var u=new zQ(this);return this._stream=u,z2e(u,function(A){if(o._stream=null,A)return o.destroy(),r(A);if(u.written!==t.size)return o.destroy(),r(new Error(\"size mismatch\"));ij(o,t.size),o._finalizing&&o.finalize(),r()}),u}};CA.prototype.finalize=function(){if(this._stream){this._finalizing=!0;return}this._finalized||(this._finalized=!0,this.push(J2e),this.push(null))};CA.prototype.destroy=function(t){this._destroyed||(this._destroyed=!0,t&&this.emit(\"error\",t),this.emit(\"close\"),this._stream&&this._stream.destroy&&this._stream.destroy())};CA.prototype._encode=function(t){if(!t.pax){var e=WQ.encode(t);if(e){this.push(e);return}}this._encodePax(t)};CA.prototype._encodePax=function(t){var e=WQ.encodePax({name:t.name,linkname:t.linkname,pax:t.pax}),r={name:\"PaxHeader\",mode:t.mode,uid:t.uid,gid:t.gid,size:e.length,mtime:t.mtime,type:\"pax-header\",linkname:t.linkname&&\"PaxHeader\",uname:t.uname,gname:t.gname,devmajor:t.devmajor,devminor:t.devminor};this.push(WQ.encode(r)),this.push(e),ij(this,e.length),r.size=t.size,r.type=t.type,this.push(WQ.encode(r))};CA.prototype._read=function(t){var e=this._drain;this._drain=sj,e()};X2e.exports=CA});var $2e=_(oj=>{oj.extract=Y2e();oj.pack=Z2e()});var ABe=_((aer,uBe)=>{\"use strict\";var vm=class{constructor(e,r,o){this.__specs=e||{},Object.keys(this.__specs).forEach(a=>{if(typeof this.__specs[a]==\"string\"){let n=this.__specs[a],u=this.__specs[n];if(u){let A=u.aliases||[];A.push(a,n),u.aliases=[...new Set(A)],this.__specs[a]=u}else throw new Error(`Alias refers to invalid key: ${n} -> ${a}`)}}),this.__opts=r||{},this.__providers=lBe(o.filter(a=>a!=null&&typeof a==\"object\")),this.__isFiggyPudding=!0}get(e){return fj(this,e,!0)}get[Symbol.toStringTag](){return\"FiggyPudding\"}forEach(e,r=this){for(let[o,a]of this.entries())e.call(r,a,o,this)}toJSON(){let e={};return this.forEach((r,o)=>{e[o]=r}),e}*entries(e){for(let o of Object.keys(this.__specs))yield[o,this.get(o)];let r=e||this.__opts.other;if(r){let o=new Set;for(let a of this.__providers){let n=a.entries?a.entries(r):Evt(a);for(let[u,A]of n)r(u)&&!o.has(u)&&(o.add(u),yield[u,A])}}}*[Symbol.iterator](){for(let[e,r]of this.entries())yield[e,r]}*keys(){for(let[e]of this.entries())yield e}*values(){for(let[,e]of this.entries())yield e}concat(...e){return new Proxy(new vm(this.__specs,this.__opts,lBe(this.__providers).concat(e)),cBe)}};try{let t=ve(\"util\");vm.prototype[t.inspect.custom]=function(e,r){return this[Symbol.toStringTag]+\" \"+t.inspect(this.toJSON(),r)}}catch{}function mvt(t){throw Object.assign(new Error(`invalid config key requested: ${t}`),{code:\"EBADKEY\"})}function fj(t,e,r){let o=t.__specs[e];if(r&&!o&&(!t.__opts.other||!t.__opts.other(e)))mvt(e);else{o||(o={});let a;for(let n of t.__providers){if(a=aBe(e,n),a===void 0&&o.aliases&&o.aliases.length){for(let u of o.aliases)if(u!==e&&(a=aBe(u,n),a!==void 0))break}if(a!==void 0)break}return a===void 0&&o.default!==void 0?typeof o.default==\"function\"?o.default(t):o.default:a}}function aBe(t,e){let r;return e.__isFiggyPudding?r=fj(e,t,!1):typeof e.get==\"function\"?r=e.get(t):r=e[t],r}var cBe={has(t,e){return e in t.__specs&&fj(t,e,!1)!==void 0},ownKeys(t){return Object.keys(t.__specs)},get(t,e){return typeof e==\"symbol\"||e.slice(0,2)===\"__\"||e in vm.prototype?t[e]:t.get(e)},set(t,e,r){if(typeof e==\"symbol\"||e.slice(0,2)===\"__\")return t[e]=r,!0;throw new Error(\"figgyPudding options cannot be modified. Use .concat() instead.\")},deleteProperty(){throw new Error(\"figgyPudding options cannot be deleted. Use .concat() and shadow them instead.\")}};uBe.exports=yvt;function yvt(t,e){function r(...o){return new Proxy(new vm(t,e,o),cBe)}return r}function lBe(t){let e=[];return t.forEach(r=>e.unshift(r)),e}function Evt(t){return Object.keys(t).map(e=>[e,t[e]])}});var hBe=_((ler,BA)=>{\"use strict\";var kv=ve(\"crypto\"),Cvt=ABe(),wvt=ve(\"stream\").Transform,fBe=[\"sha256\",\"sha384\",\"sha512\"],Ivt=/^[a-z0-9+/]+(?:=?=?)$/i,Bvt=/^([^-]+)-([^?]+)([?\\S*]*)$/,vvt=/^([^-]+)-([A-Za-z0-9+/=]{44,88})(\\?[\\x21-\\x7E]*)*$/,Dvt=/^[\\x21-\\x7E]+$/,ia=Cvt({algorithms:{default:[\"sha512\"]},error:{default:!1},integrity:{},options:{default:[]},pickAlgorithm:{default:()=>Rvt},Promise:{default:()=>Promise},sep:{default:\" \"},single:{default:!1},size:{},strict:{default:!1}}),H0=class{get isHash(){return!0}constructor(e,r){r=ia(r);let o=!!r.strict;this.source=e.trim();let a=this.source.match(o?vvt:Bvt);if(!a||o&&!fBe.some(u=>u===a[1]))return;this.algorithm=a[1],this.digest=a[2];let n=a[3];this.options=n?n.slice(1).split(\"?\"):[]}hexDigest(){return this.digest&&Buffer.from(this.digest,\"base64\").toString(\"hex\")}toJSON(){return this.toString()}toString(e){if(e=ia(e),e.strict&&!(fBe.some(o=>o===this.algorithm)&&this.digest.match(Ivt)&&(this.options||[]).every(o=>o.match(Dvt))))return\"\";let r=this.options&&this.options.length?`?${this.options.join(\"?\")}`:\"\";return`${this.algorithm}-${this.digest}${r}`}},Dm=class{get isIntegrity(){return!0}toJSON(){return this.toString()}toString(e){e=ia(e);let r=e.sep||\" \";return e.strict&&(r=r.replace(/\\S+/g,\" \")),Object.keys(this).map(o=>this[o].map(a=>H0.prototype.toString.call(a,e)).filter(a=>a.length).join(r)).filter(o=>o.length).join(r)}concat(e,r){r=ia(r);let o=typeof e==\"string\"?e:xv(e,r);return IA(`${this.toString(r)} ${o}`,r)}hexDigest(){return IA(this,{single:!0}).hexDigest()}match(e,r){r=ia(r);let o=IA(e,r),a=o.pickAlgorithm(r);return this[a]&&o[a]&&this[a].find(n=>o[a].find(u=>n.digest===u.digest))||!1}pickAlgorithm(e){e=ia(e);let r=e.pickAlgorithm,o=Object.keys(this);if(!o.length)throw new Error(`No algorithms available for ${JSON.stringify(this.toString())}`);return o.reduce((a,n)=>r(a,n)||a)}};BA.exports.parse=IA;function IA(t,e){if(e=ia(e),typeof t==\"string\")return pj(t,e);if(t.algorithm&&t.digest){let r=new Dm;return r[t.algorithm]=[t],pj(xv(r,e),e)}else return pj(xv(t,e),e)}function pj(t,e){return e.single?new H0(t,e):t.trim().split(/\\s+/).reduce((r,o)=>{let a=new H0(o,e);if(a.algorithm&&a.digest){let n=a.algorithm;r[n]||(r[n]=[]),r[n].push(a)}return r},new Dm)}BA.exports.stringify=xv;function xv(t,e){return e=ia(e),t.algorithm&&t.digest?H0.prototype.toString.call(t,e):typeof t==\"string\"?xv(IA(t,e),e):Dm.prototype.toString.call(t,e)}BA.exports.fromHex=Pvt;function Pvt(t,e,r){r=ia(r);let o=r.options&&r.options.length?`?${r.options.join(\"?\")}`:\"\";return IA(`${e}-${Buffer.from(t,\"hex\").toString(\"base64\")}${o}`,r)}BA.exports.fromData=Svt;function Svt(t,e){e=ia(e);let r=e.algorithms,o=e.options&&e.options.length?`?${e.options.join(\"?\")}`:\"\";return r.reduce((a,n)=>{let u=kv.createHash(n).update(t).digest(\"base64\"),A=new H0(`${n}-${u}${o}`,e);if(A.algorithm&&A.digest){let p=A.algorithm;a[p]||(a[p]=[]),a[p].push(A)}return a},new Dm)}BA.exports.fromStream=bvt;function bvt(t,e){e=ia(e);let r=e.Promise||Promise,o=hj(e);return new r((a,n)=>{t.pipe(o),t.on(\"error\",n),o.on(\"error\",n);let u;o.on(\"integrity\",A=>{u=A}),o.on(\"end\",()=>a(u)),o.on(\"data\",()=>{})})}BA.exports.checkData=xvt;function xvt(t,e,r){if(r=ia(r),e=IA(e,r),!Object.keys(e).length){if(r.error)throw Object.assign(new Error(\"No valid integrity hashes to check against\"),{code:\"EINTEGRITY\"});return!1}let o=e.pickAlgorithm(r),a=kv.createHash(o).update(t).digest(\"base64\"),n=IA({algorithm:o,digest:a}),u=n.match(e,r);if(u||!r.error)return u;if(typeof r.size==\"number\"&&t.length!==r.size){let A=new Error(`data size mismatch when checking ${e}.\n  Wanted: ${r.size}\n  Found: ${t.length}`);throw A.code=\"EBADSIZE\",A.found=t.length,A.expected=r.size,A.sri=e,A}else{let A=new Error(`Integrity checksum failed when using ${o}: Wanted ${e}, but got ${n}. (${t.length} bytes)`);throw A.code=\"EINTEGRITY\",A.found=n,A.expected=e,A.algorithm=o,A.sri=e,A}}BA.exports.checkStream=kvt;function kvt(t,e,r){r=ia(r);let o=r.Promise||Promise,a=hj(r.concat({integrity:e}));return new o((n,u)=>{t.pipe(a),t.on(\"error\",u),a.on(\"error\",u);let A;a.on(\"verified\",p=>{A=p}),a.on(\"end\",()=>n(A)),a.on(\"data\",()=>{})})}BA.exports.integrityStream=hj;function hj(t){t=ia(t);let e=t.integrity&&IA(t.integrity,t),r=e&&Object.keys(e).length,o=r&&e.pickAlgorithm(t),a=r&&e[o],n=Array.from(new Set(t.algorithms.concat(o?[o]:[]))),u=n.map(kv.createHash),A=0,p=new wvt({transform(h,E,I){A+=h.length,u.forEach(v=>v.update(h,E)),I(null,h,E)}}).on(\"end\",()=>{let h=t.options&&t.options.length?`?${t.options.join(\"?\")}`:\"\",E=IA(u.map((v,x)=>`${n[x]}-${v.digest(\"base64\")}${h}`).join(\" \"),t),I=r&&E.match(e,t);if(typeof t.size==\"number\"&&A!==t.size){let v=new Error(`stream size mismatch when checking ${e}.\n  Wanted: ${t.size}\n  Found: ${A}`);v.code=\"EBADSIZE\",v.found=A,v.expected=t.size,v.sri=e,p.emit(\"error\",v)}else if(t.integrity&&!I){let v=new Error(`${e} integrity checksum failed when using ${o}: wanted ${a} but got ${E}. (${A} bytes)`);v.code=\"EINTEGRITY\",v.found=E,v.expected=a,v.algorithm=o,v.sri=e,p.emit(\"error\",v)}else p.emit(\"size\",A),p.emit(\"integrity\",E),I&&p.emit(\"verified\",I)});return p}BA.exports.create=Qvt;function Qvt(t){t=ia(t);let e=t.algorithms,r=t.options.length?`?${t.options.join(\"?\")}`:\"\",o=e.map(kv.createHash);return{update:function(a,n){return o.forEach(u=>u.update(a,n)),this},digest:function(a){return e.reduce((u,A)=>{let p=o.shift().digest(\"base64\"),h=new H0(`${A}-${p}${r}`,t);if(h.algorithm&&h.digest){let E=h.algorithm;u[E]||(u[E]=[]),u[E].push(h)}return u},new Dm)}}}var Fvt=new Set(kv.getHashes()),pBe=[\"md5\",\"whirlpool\",\"sha1\",\"sha224\",\"sha256\",\"sha384\",\"sha512\",\"sha3\",\"sha3-256\",\"sha3-384\",\"sha3-512\",\"sha3_256\",\"sha3_384\",\"sha3_512\"].filter(t=>Fvt.has(t));function Rvt(t,e){return pBe.indexOf(t.toLowerCase())>=pBe.indexOf(e.toLowerCase())?t:e}});var GBe=_((Air,qBe)=>{var RDt=cN();function TDt(t){return RDt(t)?void 0:t}qBe.exports=TDt});var YBe=_((fir,jBe)=>{var LDt=Hb(),NDt=x8(),ODt=R8(),MDt=jd(),UDt=md(),_Dt=GBe(),HDt=v_(),qDt=b8(),GDt=1,jDt=2,YDt=4,WDt=HDt(function(t,e){var r={};if(t==null)return r;var o=!1;e=LDt(e,function(n){return n=MDt(n,t),o||(o=n.length>1),n}),UDt(t,qDt(t),r),o&&(r=NDt(r,GDt|jDt|YDt,_Dt));for(var a=e.length;a--;)ODt(r,e[a]);return r});jBe.exports=WDt});Pt();Ye();Pt();var JBe=ve(\"child_process\"),XBe=$e(rd());qt();var AC=new Map([]);var a2={};zt(a2,{BaseCommand:()=>ut,WorkspaceRequiredError:()=>nr,getCli:()=>ehe,getDynamicLibs:()=>$pe,getPluginConfiguration:()=>pC,openWorkspace:()=>fC,pluginCommands:()=>AC,runExit:()=>nk});qt();var ut=class extends nt{constructor(){super(...arguments);this.cwd=ge.String(\"--cwd\",{hidden:!0})}validateAndExecute(){if(typeof this.cwd<\"u\")throw new it(\"The --cwd option is ambiguous when used anywhere else than the very first parameter provided in the command line, before even the command path\");return super.validateAndExecute()}};Ye();Pt();qt();var nr=class extends it{constructor(e,r){let o=z.relative(e,r),a=z.join(e,Ot.fileName);super(`This command can only be run from within a workspace of your project (${o} isn't a workspace of ${a}).`)}};Ye();Pt();iA();Nl();k1();qt();var TAt=$e(Jn());$a();var $pe=()=>new Map([[\"@yarnpkg/cli\",a2],[\"@yarnpkg/core\",o2],[\"@yarnpkg/fslib\",zw],[\"@yarnpkg/libzip\",x1],[\"@yarnpkg/parsers\",rI],[\"@yarnpkg/shell\",T1],[\"clipanion\",hI],[\"semver\",TAt],[\"typanion\",zo]]);Ye();async function fC(t,e){let{project:r,workspace:o}=await St.find(t,e);if(!o)throw new nr(r.cwd,e);return o}Ye();Pt();iA();Nl();k1();qt();var tPt=$e(Jn());$a();var $8={};zt($8,{AddCommand:()=>Qh,BinCommand:()=>Fh,CacheCleanCommand:()=>Rh,ClipanionCommand:()=>zd,ConfigCommand:()=>Oh,ConfigGetCommand:()=>Th,ConfigSetCommand:()=>Lh,ConfigUnsetCommand:()=>Nh,DedupeCommand:()=>Mh,EntryCommand:()=>mC,ExecCommand:()=>Uh,ExplainCommand:()=>qh,ExplainPeerRequirementsCommand:()=>_h,HelpCommand:()=>Vd,InfoCommand:()=>Gh,LinkCommand:()=>Yh,NodeCommand:()=>Wh,PluginCheckCommand:()=>Kh,PluginImportCommand:()=>Jh,PluginImportSourcesCommand:()=>Xh,PluginListCommand:()=>zh,PluginRemoveCommand:()=>Zh,PluginRuntimeCommand:()=>$h,RebuildCommand:()=>e0,RemoveCommand:()=>t0,RunCommand:()=>r0,RunIndexCommand:()=>Zd,SetResolutionCommand:()=>n0,SetVersionCommand:()=>Hh,SetVersionSourcesCommand:()=>Vh,UnlinkCommand:()=>i0,UpCommand:()=>Vf,VersionCommand:()=>Jd,WhyCommand:()=>s0,WorkspaceCommand:()=>l0,WorkspacesListCommand:()=>a0,YarnCommand:()=>jh,dedupeUtils:()=>pk,default:()=>Sgt,suggestUtils:()=>Xc});var Qde=$e(rd());Ye();Ye();Ye();qt();var H0e=$e(f2());$a();var Xc={};zt(Xc,{Modifier:()=>B8,Strategy:()=>uk,Target:()=>p2,WorkspaceModifier:()=>N0e,applyModifier:()=>ept,extractDescriptorFromPath:()=>v8,extractRangeModifier:()=>O0e,fetchDescriptorFrom:()=>D8,findProjectDescriptors:()=>_0e,getModifier:()=>h2,getSuggestedDescriptors:()=>g2,makeWorkspaceDescriptor:()=>U0e,toWorkspaceModifier:()=>M0e});Ye();Ye();Pt();var I8=$e(Jn()),Zft=\"workspace:\",p2=(o=>(o.REGULAR=\"dependencies\",o.DEVELOPMENT=\"devDependencies\",o.PEER=\"peerDependencies\",o))(p2||{}),B8=(o=>(o.CARET=\"^\",o.TILDE=\"~\",o.EXACT=\"\",o))(B8||{}),N0e=(o=>(o.CARET=\"^\",o.TILDE=\"~\",o.EXACT=\"*\",o))(N0e||{}),uk=(n=>(n.KEEP=\"keep\",n.REUSE=\"reuse\",n.PROJECT=\"project\",n.LATEST=\"latest\",n.CACHE=\"cache\",n))(uk||{});function h2(t,e){return t.exact?\"\":t.caret?\"^\":t.tilde?\"~\":e.configuration.get(\"defaultSemverRangePrefix\")}var $ft=/^([\\^~]?)[0-9]+(?:\\.[0-9]+){0,2}(?:-\\S+)?$/;function O0e(t,{project:e}){let r=t.match($ft);return r?r[1]:e.configuration.get(\"defaultSemverRangePrefix\")}function ept(t,e){let{protocol:r,source:o,params:a,selector:n}=W.parseRange(t.range);return I8.default.valid(n)&&(n=`${e}${t.range}`),W.makeDescriptor(t,W.makeRange({protocol:r,source:o,params:a,selector:n}))}function M0e(t){switch(t){case\"^\":return\"^\";case\"~\":return\"~\";case\"\":return\"*\";default:throw new Error(`Assertion failed: Unknown modifier: \"${t}\"`)}}function U0e(t,e){return W.makeDescriptor(t.anchoredDescriptor,`${Zft}${M0e(e)}`)}async function _0e(t,{project:e,target:r}){let o=new Map,a=n=>{let u=o.get(n.descriptorHash);return u||o.set(n.descriptorHash,u={descriptor:n,locators:[]}),u};for(let n of e.workspaces)if(r===\"peerDependencies\"){let u=n.manifest.peerDependencies.get(t.identHash);u!==void 0&&a(u).locators.push(n.anchoredLocator)}else{let u=n.manifest.dependencies.get(t.identHash),A=n.manifest.devDependencies.get(t.identHash);r===\"devDependencies\"?A!==void 0?a(A).locators.push(n.anchoredLocator):u!==void 0&&a(u).locators.push(n.anchoredLocator):u!==void 0?a(u).locators.push(n.anchoredLocator):A!==void 0&&a(A).locators.push(n.anchoredLocator)}return o}async function v8(t,{cwd:e,workspace:r}){return await tpt(async o=>{z.isAbsolute(t)||(t=z.relative(r.cwd,z.resolve(e,t)),t.match(/^\\.{0,2}\\//)||(t=`./${t}`));let{project:a}=r,n=await D8(W.makeIdent(null,\"archive\"),t,{project:r.project,cache:o,workspace:r});if(!n)throw new Error(\"Assertion failed: The descriptor should have been found\");let u=new Qi,A=a.configuration.makeResolver(),p=a.configuration.makeFetcher(),h={checksums:a.storedChecksums,project:a,cache:o,fetcher:p,report:u,resolver:A},E=A.bindDescriptor(n,r.anchoredLocator,h),I=W.convertDescriptorToLocator(E),v=await p.fetch(I,h),x=await Ot.find(v.prefixPath,{baseFs:v.packageFs});if(!x.name)throw new Error(\"Target path doesn't have a name\");return W.makeDescriptor(x.name,t)})}async function g2(t,{project:e,workspace:r,cache:o,target:a,fixed:n,modifier:u,strategies:A,maxResults:p=1/0}){if(!(p>=0))throw new Error(`Invalid maxResults (${p})`);let[h,E]=t.range!==\"unknown\"?n||kr.validRange(t.range)||!t.range.match(/^[a-z0-9._-]+$/i)?[t.range,\"latest\"]:[\"unknown\",t.range]:[\"unknown\",\"latest\"];if(h!==\"unknown\")return{suggestions:[{descriptor:t,name:`Use ${W.prettyDescriptor(e.configuration,t)}`,reason:\"(unambiguous explicit request)\"}],rejections:[]};let I=typeof r<\"u\"&&r!==null&&r.manifest[a].get(t.identHash)||null,v=[],x=[],C=async R=>{try{await R()}catch(N){x.push(N)}};for(let R of A){if(v.length>=p)break;switch(R){case\"keep\":await C(async()=>{I&&v.push({descriptor:I,name:`Keep ${W.prettyDescriptor(e.configuration,I)}`,reason:\"(no changes)\"})});break;case\"reuse\":await C(async()=>{for(let{descriptor:N,locators:U}of(await _0e(t,{project:e,target:a})).values()){if(U.length===1&&U[0].locatorHash===r.anchoredLocator.locatorHash&&A.includes(\"keep\"))continue;let V=`(originally used by ${W.prettyLocator(e.configuration,U[0])}`;V+=U.length>1?` and ${U.length-1} other${U.length>2?\"s\":\"\"})`:\")\",v.push({descriptor:N,name:`Reuse ${W.prettyDescriptor(e.configuration,N)}`,reason:V})}});break;case\"cache\":await C(async()=>{for(let N of e.storedDescriptors.values())N.identHash===t.identHash&&v.push({descriptor:N,name:`Reuse ${W.prettyDescriptor(e.configuration,N)}`,reason:\"(already used somewhere in the lockfile)\"})});break;case\"project\":await C(async()=>{if(r.manifest.name!==null&&t.identHash===r.manifest.name.identHash)return;let N=e.tryWorkspaceByIdent(t);if(N===null)return;let U=U0e(N,u);v.push({descriptor:U,name:`Attach ${W.prettyDescriptor(e.configuration,U)}`,reason:`(local workspace at ${de.pretty(e.configuration,N.relativeCwd,de.Type.PATH)})`})});break;case\"latest\":{let N=e.configuration.get(\"enableNetwork\"),U=e.configuration.get(\"enableOfflineMode\");await C(async()=>{if(a===\"peerDependencies\")v.push({descriptor:W.makeDescriptor(t,\"*\"),name:\"Use *\",reason:\"(catch-all peer dependency pattern)\"});else if(!N&&!U)v.push({descriptor:null,name:\"Resolve from latest\",reason:de.pretty(e.configuration,\"(unavailable because enableNetwork is toggled off)\",\"grey\")});else{let V=await D8(t,E,{project:e,cache:o,workspace:r,modifier:u});V&&v.push({descriptor:V,name:`Use ${W.prettyDescriptor(e.configuration,V)}`,reason:`(resolved from ${U?\"the cache\":\"latest\"})`})}})}break}}return{suggestions:v.slice(0,p),rejections:x.slice(0,p)}}async function D8(t,e,{project:r,cache:o,workspace:a,preserveModifier:n=!0,modifier:u}){let A=r.configuration.normalizeDependency(W.makeDescriptor(t,e)),p=new Qi,h=r.configuration.makeFetcher(),E=r.configuration.makeResolver(),I={project:r,fetcher:h,cache:o,checksums:r.storedChecksums,report:p,cacheOptions:{skipIntegrityCheck:!0}},v={...I,resolver:E,fetchOptions:I},x=E.bindDescriptor(A,a.anchoredLocator,v),C=await E.getCandidates(x,{},v);if(C.length===0)return null;let R=C[0],{protocol:N,source:U,params:V,selector:te}=W.parseRange(W.convertToManifestRange(R.reference));if(N===r.configuration.get(\"defaultProtocol\")&&(N=null),I8.default.valid(te)){let ae=te;if(typeof u<\"u\")te=u+te;else if(n!==!1){let me=typeof n==\"string\"?n:A.range;te=O0e(me,{project:r})+te}let fe=W.makeDescriptor(R,W.makeRange({protocol:N,source:U,params:V,selector:te}));(await E.getCandidates(r.configuration.normalizeDependency(fe),{},v)).length!==1&&(te=ae)}return W.makeDescriptor(R,W.makeRange({protocol:N,source:U,params:V,selector:te}))}async function tpt(t){return await oe.mktempPromise(async e=>{let r=Ke.create(e);return r.useWithSource(e,{enableMirror:!1,compressionLevel:0},e,{overwrite:!0}),await t(new Nr(e,{configuration:r,check:!1,immutable:!1}))})}var Qh=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.fixed=ge.Boolean(\"-F,--fixed\",!1,{description:\"Store dependency tags as-is instead of resolving them\"});this.exact=ge.Boolean(\"-E,--exact\",!1,{description:\"Don't use any semver modifier on the resolved range\"});this.tilde=ge.Boolean(\"-T,--tilde\",!1,{description:\"Use the `~` semver modifier on the resolved range\"});this.caret=ge.Boolean(\"-C,--caret\",!1,{description:\"Use the `^` semver modifier on the resolved range\"});this.dev=ge.Boolean(\"-D,--dev\",!1,{description:\"Add a package as a dev dependency\"});this.peer=ge.Boolean(\"-P,--peer\",!1,{description:\"Add a package as a peer dependency\"});this.optional=ge.Boolean(\"-O,--optional\",!1,{description:\"Add / upgrade a package to an optional regular / peer dependency\"});this.preferDev=ge.Boolean(\"--prefer-dev\",!1,{description:\"Add / upgrade a package to a dev dependency\"});this.interactive=ge.Boolean(\"-i,--interactive\",{description:\"Reuse the specified package from other workspaces in the project\"});this.cached=ge.Boolean(\"--cached\",!1,{description:\"Reuse the highest version already used somewhere within the project\"});this.mode=ge.String(\"--mode\",{description:\"Change what artifacts installs generate\",validator:Ks(hl)});this.silent=ge.Boolean(\"--silent\",{hidden:!0});this.packages=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Nr.find(r);if(!a)throw new nr(o.cwd,this.context.cwd);await o.restoreInstallState({restoreResolutions:!1});let u=this.fixed,A=this.interactive??r.get(\"preferInteractive\"),p=A||r.get(\"preferReuse\"),h=h2(this,o),E=[p?\"reuse\":void 0,\"project\",this.cached?\"cache\":void 0,\"latest\"].filter(U=>typeof U<\"u\"),I=A?1/0:1,v=await Promise.all(this.packages.map(async U=>{let V=U.match(/^\\.{0,2}\\//)?await v8(U,{cwd:this.context.cwd,workspace:a}):W.tryParseDescriptor(U),te=U.match(/^(https?:|git@github)/);if(te)throw new it(`It seems you are trying to add a package using a ${de.pretty(r,`${te[0]}...`,de.Type.RANGE)} url; we now require package names to be explicitly specified.\nTry running the command again with the package name prefixed: ${de.pretty(r,\"yarn add\",de.Type.CODE)} ${de.pretty(r,W.makeDescriptor(W.makeIdent(null,\"my-package\"),`${te[0]}...`),de.Type.DESCRIPTOR)}`);if(!V)throw new it(`The ${de.pretty(r,U,de.Type.CODE)} string didn't match the required format (package-name@range). Did you perhaps forget to explicitly reference the package name?`);let ae=rpt(a,V,{dev:this.dev,peer:this.peer,preferDev:this.preferDev,optional:this.optional});return await Promise.all(ae.map(async ue=>{let me=await g2(V,{project:o,workspace:a,cache:n,fixed:u,target:ue,modifier:h,strategies:E,maxResults:I});return{request:V,suggestedDescriptors:me,target:ue}}))})).then(U=>U.flat()),x=await fA.start({configuration:r,stdout:this.context.stdout,suggestInstall:!1},async U=>{for(let{request:V,suggestedDescriptors:{suggestions:te,rejections:ae}}of v)if(te.filter(ue=>ue.descriptor!==null).length===0){let[ue]=ae;if(typeof ue>\"u\")throw new Error(\"Assertion failed: Expected an error to have been set\");o.configuration.get(\"enableNetwork\")?U.reportError(27,`${W.prettyDescriptor(r,V)} can't be resolved to a satisfying range`):U.reportError(27,`${W.prettyDescriptor(r,V)} can't be resolved to a satisfying range (note: network resolution has been disabled)`),U.reportSeparator(),U.reportExceptionOnce(ue)}});if(x.hasErrors())return x.exitCode();let C=!1,R=[],N=[];for(let{suggestedDescriptors:{suggestions:U},target:V}of v){let te,ae=U.filter(he=>he.descriptor!==null),fe=ae[0].descriptor,ue=ae.every(he=>W.areDescriptorsEqual(he.descriptor,fe));ae.length===1||ue?te=fe:(C=!0,{answer:te}=await(0,H0e.prompt)({type:\"select\",name:\"answer\",message:\"Which range do you want to use?\",choices:U.map(({descriptor:he,name:Be,reason:we})=>he?{name:Be,hint:we,descriptor:he}:{name:Be,hint:we,disabled:!0}),onCancel:()=>process.exit(130),result(he){return this.find(he,\"descriptor\")},stdin:this.context.stdin,stdout:this.context.stdout}));let me=a.manifest[V].get(te.identHash);(typeof me>\"u\"||me.descriptorHash!==te.descriptorHash)&&(a.manifest[V].set(te.identHash,te),this.optional&&(V===\"dependencies\"?a.manifest.ensureDependencyMeta({...te,range:\"unknown\"}).optional=!0:V===\"peerDependencies\"&&(a.manifest.ensurePeerDependencyMeta({...te,range:\"unknown\"}).optional=!0)),typeof me>\"u\"?R.push([a,V,te,E]):N.push([a,V,me,te]))}return await r.triggerMultipleHooks(U=>U.afterWorkspaceDependencyAddition,R),await r.triggerMultipleHooks(U=>U.afterWorkspaceDependencyReplacement,N),C&&this.context.stdout.write(`\n`),await o.installWithNewReport({json:this.json,stdout:this.context.stdout,quiet:this.context.quiet},{cache:n,mode:this.mode})}};Qh.paths=[[\"add\"]],Qh.usage=nt.Usage({description:\"add dependencies to the project\",details:\"\\n      This command adds a package to the package.json for the nearest workspace.\\n\\n      - If it didn't exist before, the package will by default be added to the regular `dependencies` field, but this behavior can be overriden thanks to the `-D,--dev` flag (which will cause the dependency to be added to the `devDependencies` field instead) and the `-P,--peer` flag (which will do the same but for `peerDependencies`).\\n\\n      - If the package was already listed in your dependencies, it will by default be upgraded whether it's part of your `dependencies` or `devDependencies` (it won't ever update `peerDependencies`, though).\\n\\n      - If set, the `--prefer-dev` flag will operate as a more flexible `-D,--dev` in that it will add the package to your `devDependencies` if it isn't already listed in either `dependencies` or `devDependencies`, but it will also happily upgrade your `dependencies` if that's what you already use (whereas `-D,--dev` would throw an exception).\\n\\n      - If set, the `-O,--optional` flag will add the package to the `optionalDependencies` field and, in combination with the `-P,--peer` flag, it will add the package as an optional peer dependency. If the package was already listed in your `dependencies`, it will be upgraded to `optionalDependencies`. If the package was already listed in your `peerDependencies`, in combination with the `-P,--peer` flag, it will be upgraded to an optional peer dependency: `\\\"peerDependenciesMeta\\\": { \\\"<package>\\\": { \\\"optional\\\": true } }`\\n\\n      - If the added package doesn't specify a range at all its `latest` tag will be resolved and the returned version will be used to generate a new semver range (using the `^` modifier by default unless otherwise configured via the `defaultSemverRangePrefix` configuration, or the `~` modifier if `-T,--tilde` is specified, or no modifier at all if `-E,--exact` is specified). Two exceptions to this rule: the first one is that if the package is a workspace then its local version will be used, and the second one is that if you use `-P,--peer` the default range will be `*` and won't be resolved at all.\\n\\n      - If the added package specifies a range (such as `^1.0.0`, `latest`, or `rc`), Yarn will add this range as-is in the resulting package.json entry (in particular, tags such as `rc` will be encoded as-is rather than being converted into a semver range).\\n\\n      If the `--cached` option is used, Yarn will preferably reuse the highest version already used somewhere within the project, even if through a transitive dependency.\\n\\n      If the `-i,--interactive` option is used (or if the `preferInteractive` settings is toggled on) the command will first try to check whether other workspaces in the project use the specified package and, if so, will offer to reuse them.\\n\\n      If the `--mode=<mode>` option is set, Yarn will change which artifacts are generated. The modes currently supported are:\\n\\n      - `skip-build` will not run the build scripts at all. Note that this is different from setting `enableScripts` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.\\n\\n      - `update-lockfile` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.\\n\\n      For a compilation of all the supported protocols, please consult the dedicated page from our website: https://yarnpkg.com/protocols.\\n    \",examples:[[\"Add a regular package to the current workspace\",\"$0 add lodash\"],[\"Add a specific version for a package to the current workspace\",\"$0 add lodash@1.2.3\"],[\"Add a package from a GitHub repository (the master branch) to the current workspace using a URL\",\"$0 add lodash@https://github.com/lodash/lodash\"],[\"Add a package from a GitHub repository (the master branch) to the current workspace using the GitHub protocol\",\"$0 add lodash@github:lodash/lodash\"],[\"Add a package from a GitHub repository (the master branch) to the current workspace using the GitHub protocol (shorthand)\",\"$0 add lodash@lodash/lodash\"],[\"Add a package from a specific branch of a GitHub repository to the current workspace using the GitHub protocol (shorthand)\",\"$0 add lodash-es@lodash/lodash#es\"]]});function rpt(t,e,{dev:r,peer:o,preferDev:a,optional:n}){let u=t.manifest[\"dependencies\"].has(e.identHash),A=t.manifest[\"devDependencies\"].has(e.identHash),p=t.manifest[\"peerDependencies\"].has(e.identHash);if((r||o)&&u)throw new it(`Package \"${W.prettyIdent(t.project.configuration,e)}\" is already listed as a regular dependency - remove the -D,-P flags or remove it from your dependencies first`);if(!r&&!o&&p)throw new it(`Package \"${W.prettyIdent(t.project.configuration,e)}\" is already listed as a peer dependency - use either of -D or -P, or remove it from your peer dependencies first`);if(n&&A)throw new it(`Package \"${W.prettyIdent(t.project.configuration,e)}\" is already listed as a dev dependency - remove the -O flag or remove it from your dev dependencies first`);if(n&&!o&&p)throw new it(`Package \"${W.prettyIdent(t.project.configuration,e)}\" is already listed as a peer dependency - remove the -O flag or add the -P flag or remove it from your peer dependencies first`);if((r||a)&&n)throw new it(`Package \"${W.prettyIdent(t.project.configuration,e)}\" cannot simultaneously be a dev dependency and an optional dependency`);let h=[];return o&&h.push(\"peerDependencies\"),(r||a)&&h.push(\"devDependencies\"),n&&h.push(\"dependencies\"),h.length>0?h:A?[\"devDependencies\"]:p?[\"peerDependencies\"]:[\"dependencies\"]}Ye();Ye();qt();var Fh=class extends ut{constructor(){super(...arguments);this.verbose=ge.Boolean(\"-v,--verbose\",!1,{description:\"Print both the binary name and the locator of the package that provides the binary\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.name=ge.String({required:!1})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,locator:a}=await St.find(r,this.context.cwd);if(await o.restoreInstallState(),this.name){let A=(await un.getPackageAccessibleBinaries(a,{project:o})).get(this.name);if(!A)throw new it(`Couldn't find a binary named \"${this.name}\" for package \"${W.prettyLocator(r,a)}\"`);let[,p]=A;return this.context.stdout.write(`${p}\n`),0}return(await Lt.start({configuration:r,json:this.json,stdout:this.context.stdout},async u=>{let A=await un.getPackageAccessibleBinaries(a,{project:o}),h=Array.from(A.keys()).reduce((E,I)=>Math.max(E,I.length),0);for(let[E,[I,v]]of A)u.reportJson({name:E,source:W.stringifyIdent(I),path:v});if(this.verbose)for(let[E,[I]]of A)u.reportInfo(null,`${E.padEnd(h,\" \")}   ${W.prettyLocator(r,I)}`);else for(let E of A.keys())u.reportInfo(null,E)})).exitCode()}};Fh.paths=[[\"bin\"]],Fh.usage=nt.Usage({description:\"get the path to a binary script\",details:`\n      When used without arguments, this command will print the list of all the binaries available in the current workspace. Adding the \\`-v,--verbose\\` flag will cause the output to contain both the binary name and the locator of the package that provides the binary.\n\n      When an argument is specified, this command will just print the path to the binary on the standard output and exit. Note that the reported path may be stored within a zip archive.\n    `,examples:[[\"List all the available binaries\",\"$0 bin\"],[\"Print the path to a specific binary\",\"$0 bin eslint\"]]});Ye();Pt();qt();var Rh=class extends ut{constructor(){super(...arguments);this.mirror=ge.Boolean(\"--mirror\",!1,{description:\"Remove the global cache files instead of the local cache files\"});this.all=ge.Boolean(\"--all\",!1,{description:\"Remove both the global cache files and the local cache files of the current project\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),o=await Nr.find(r);return(await Lt.start({configuration:r,stdout:this.context.stdout},async()=>{let n=(this.all||this.mirror)&&o.mirrorCwd!==null,u=!this.mirror;n&&(await oe.removePromise(o.mirrorCwd),await r.triggerHook(A=>A.cleanGlobalArtifacts,r)),u&&await oe.removePromise(o.cwd)})).exitCode()}};Rh.paths=[[\"cache\",\"clean\"],[\"cache\",\"clear\"]],Rh.usage=nt.Usage({description:\"remove the shared cache files\",details:`\n      This command will remove all the files from the cache.\n    `,examples:[[\"Remove all the local archives\",\"$0 cache clean\"],[\"Remove all the archives stored in the ~/.yarn directory\",\"$0 cache clean --mirror\"]]});Ye();qt();var G0e=$e(d2()),P8=ve(\"util\"),Th=class extends ut{constructor(){super(...arguments);this.why=ge.Boolean(\"--why\",!1,{description:\"Print the explanation for why a setting has its value\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.unsafe=ge.Boolean(\"--no-redacted\",!1,{description:\"Don't redact secrets (such as tokens) from the output\"});this.name=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),o=this.name.replace(/[.[].*$/,\"\"),a=this.name.replace(/^[^.[]*/,\"\");if(typeof r.settings.get(o)>\"u\")throw new it(`Couldn't find a configuration settings named \"${o}\"`);let u=r.getSpecial(o,{hideSecrets:!this.unsafe,getNativePaths:!0}),A=_e.convertMapsToIndexableObjects(u),p=a?(0,G0e.default)(A,a):A,h=await Lt.start({configuration:r,includeFooter:!1,json:this.json,stdout:this.context.stdout},async E=>{E.reportJson(p)});if(!this.json){if(typeof p==\"string\")return this.context.stdout.write(`${p}\n`),h.exitCode();P8.inspect.styles.name=\"cyan\",this.context.stdout.write(`${(0,P8.inspect)(p,{depth:1/0,colors:r.get(\"enableColors\"),compact:!1})}\n`)}return h.exitCode()}};Th.paths=[[\"config\",\"get\"]],Th.usage=nt.Usage({description:\"read a configuration settings\",details:`\n      This command will print a configuration setting.\n\n      Secrets (such as tokens) will be redacted from the output by default. If this behavior isn't desired, set the \\`--no-redacted\\` to get the untransformed value.\n    `,examples:[[\"Print a simple configuration setting\",\"yarn config get yarnPath\"],[\"Print a complex configuration setting\",\"yarn config get packageExtensions\"],[\"Print a nested field from the configuration\",`yarn config get 'npmScopes[\"my-company\"].npmRegistryServer'`],[\"Print a token from the configuration\",\"yarn config get npmAuthToken --no-redacted\"],[\"Print a configuration setting as JSON\",\"yarn config get packageExtensions --json\"]]});Ye();qt();var Rge=$e(k8()),Tge=$e(d2()),Lge=$e(Q8()),F8=ve(\"util\"),Lh=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean(\"--json\",!1,{description:\"Set complex configuration settings to JSON values\"});this.home=ge.Boolean(\"-H,--home\",!1,{description:\"Update the home configuration instead of the project configuration\"});this.name=ge.String();this.value=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),o=()=>{if(!r.projectCwd)throw new it(\"This command must be run from within a project folder\");return r.projectCwd},a=this.name.replace(/[.[].*$/,\"\"),n=this.name.replace(/^[^.[]*\\.?/,\"\");if(typeof r.settings.get(a)>\"u\")throw new it(`Couldn't find a configuration settings named \"${a}\"`);if(a===\"enableStrictSettings\")throw new it(\"This setting only affects the file it's in, and thus cannot be set from the CLI\");let A=this.json?JSON.parse(this.value):this.value;await(this.home?C=>Ke.updateHomeConfiguration(C):C=>Ke.updateConfiguration(o(),C))(C=>{if(n){let R=(0,Rge.default)(C);return(0,Lge.default)(R,this.name,A),R}else return{...C,[a]:A}});let E=(await Ke.find(this.context.cwd,this.context.plugins)).getSpecial(a,{hideSecrets:!0,getNativePaths:!0}),I=_e.convertMapsToIndexableObjects(E),v=n?(0,Tge.default)(I,n):I;return(await Lt.start({configuration:r,includeFooter:!1,stdout:this.context.stdout},async C=>{F8.inspect.styles.name=\"cyan\",C.reportInfo(0,`Successfully set ${this.name} to ${(0,F8.inspect)(v,{depth:1/0,colors:r.get(\"enableColors\"),compact:!1})}`)})).exitCode()}};Lh.paths=[[\"config\",\"set\"]],Lh.usage=nt.Usage({description:\"change a configuration settings\",details:`\n      This command will set a configuration setting.\n\n      When used without the \\`--json\\` flag, it can only set a simple configuration setting (a string, a number, or a boolean).\n\n      When used with the \\`--json\\` flag, it can set both simple and complex configuration settings, including Arrays and Objects.\n    `,examples:[[\"Set a simple configuration setting (a string, a number, or a boolean)\",\"yarn config set initScope myScope\"],[\"Set a simple configuration setting (a string, a number, or a boolean) using the `--json` flag\",'yarn config set initScope --json \\\\\"myScope\\\\\"'],[\"Set a complex configuration setting (an Array) using the `--json` flag\",`yarn config set unsafeHttpWhitelist --json '[\"*.example.com\", \"example.com\"]'`],[\"Set a complex configuration setting (an Object) using the `--json` flag\",`yarn config set packageExtensions --json '{ \"@babel/parser@*\": { \"dependencies\": { \"@babel/types\": \"*\" } } }'`],[\"Set a nested configuration setting\",'yarn config set npmScopes.company.npmRegistryServer \"https://npm.example.com\"'],[\"Set a nested configuration setting using indexed access for non-simple keys\",`yarn config set 'npmRegistries[\"//npm.example.com\"].npmAuthToken' \"ffffffff-ffff-ffff-ffff-ffffffffffff\"`]]});Ye();qt();var Wge=$e(k8()),Kge=$e(Uge()),zge=$e(T8()),Nh=class extends ut{constructor(){super(...arguments);this.home=ge.Boolean(\"-H,--home\",!1,{description:\"Update the home configuration instead of the project configuration\"});this.name=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),o=()=>{if(!r.projectCwd)throw new it(\"This command must be run from within a project folder\");return r.projectCwd},a=this.name.replace(/[.[].*$/,\"\"),n=this.name.replace(/^[^.[]*\\.?/,\"\");if(typeof r.settings.get(a)>\"u\")throw new it(`Couldn't find a configuration settings named \"${a}\"`);let A=this.home?h=>Ke.updateHomeConfiguration(h):h=>Ke.updateConfiguration(o(),h);return(await Lt.start({configuration:r,includeFooter:!1,stdout:this.context.stdout},async h=>{let E=!1;await A(I=>{if(!(0,Kge.default)(I,this.name))return h.reportWarning(0,`Configuration doesn't contain setting ${this.name}; there is nothing to unset`),E=!0,I;let v=n?(0,Wge.default)(I):{...I};return(0,zge.default)(v,this.name),v}),E||h.reportInfo(0,`Successfully unset ${this.name}`)})).exitCode()}};Nh.paths=[[\"config\",\"unset\"]],Nh.usage=nt.Usage({description:\"unset a configuration setting\",details:`\n      This command will unset a configuration setting.\n    `,examples:[[\"Unset a simple configuration setting\",\"yarn config unset initScope\"],[\"Unset a complex configuration setting\",\"yarn config unset packageExtensions\"],[\"Unset a nested configuration setting\",\"yarn config unset npmScopes.company.npmRegistryServer\"]]});Ye();Pt();qt();var fk=ve(\"util\"),Oh=class extends ut{constructor(){super(...arguments);this.noDefaults=ge.Boolean(\"--no-defaults\",!1,{description:\"Omit the default values from the display\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.verbose=ge.Boolean(\"-v,--verbose\",{hidden:!0});this.why=ge.Boolean(\"--why\",{hidden:!0});this.names=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins,{strict:!1}),o=await NE({configuration:r,stdout:this.context.stdout,forceError:this.json},[{option:this.verbose,message:\"The --verbose option is deprecated, the settings' descriptions are now always displayed\"},{option:this.why,message:\"The --why option is deprecated, the settings' sources are now always displayed\"}]);if(o!==null)return o;let a=this.names.length>0?[...new Set(this.names)].sort():[...r.settings.keys()].sort(),n,u=await Lt.start({configuration:r,json:this.json,stdout:this.context.stdout,includeFooter:!1},async A=>{if(r.invalid.size>0&&!this.json){for(let[p,h]of r.invalid)A.reportError(34,`Invalid configuration key \"${p}\" in ${h}`);A.reportSeparator()}if(this.json)for(let p of a){let h=r.settings.get(p);typeof h>\"u\"&&A.reportError(34,`No configuration key named \"${p}\"`);let E=r.getSpecial(p,{hideSecrets:!0,getNativePaths:!0}),I=r.sources.get(p)??\"<default>\",v=I&&I[0]!==\"<\"?le.fromPortablePath(I):I;A.reportJson({key:p,effective:E,source:v,...h})}else{let p={breakLength:1/0,colors:r.get(\"enableColors\"),maxArrayLength:2},h={},E={children:h};for(let I of a){if(this.noDefaults&&!r.sources.has(I))continue;let v=r.settings.get(I),x=r.sources.get(I)??\"<default>\",C=r.getSpecial(I,{hideSecrets:!0,getNativePaths:!0}),R={Description:{label:\"Description\",value:de.tuple(de.Type.MARKDOWN,{text:v.description,format:this.cli.format(),paragraphs:!1})},Source:{label:\"Source\",value:de.tuple(x[0]===\"<\"?de.Type.CODE:de.Type.PATH,x)}};h[I]={value:de.tuple(de.Type.CODE,I),children:R};let N=(U,V)=>{for(let[te,ae]of V)if(ae instanceof Map){let fe={};U[te]={children:fe},N(fe,ae)}else U[te]={label:te,value:de.tuple(de.Type.NO_HINT,(0,fk.inspect)(ae,p))}};C instanceof Map?N(R,C):R.Value={label:\"Value\",value:de.tuple(de.Type.NO_HINT,(0,fk.inspect)(C,p))}}a.length!==1&&(n=void 0),$s.emitTree(E,{configuration:r,json:this.json,stdout:this.context.stdout,separators:2})}});if(!this.json&&typeof n<\"u\"){let A=a[0],p=(0,fk.inspect)(r.getSpecial(A,{hideSecrets:!0,getNativePaths:!0}),{colors:r.get(\"enableColors\")});this.context.stdout.write(`\n`),this.context.stdout.write(`${p}\n`)}return u.exitCode()}};Oh.paths=[[\"config\"]],Oh.usage=nt.Usage({description:\"display the current configuration\",details:`\n      This command prints the current active configuration settings.\n    `,examples:[[\"Print the active configuration settings\",\"$0 config\"]]});Ye();qt();$a();var pk={};zt(pk,{Strategy:()=>m2,acceptedStrategies:()=>M0t,dedupe:()=>L8});Ye();Ye();var Vge=$e(Zo()),m2=(e=>(e.HIGHEST=\"highest\",e))(m2||{}),M0t=new Set(Object.values(m2)),U0t={highest:async(t,e,{resolver:r,fetcher:o,resolveOptions:a,fetchOptions:n})=>{let u=new Map;for(let[p,h]of t.storedResolutions){let E=t.storedDescriptors.get(p);if(typeof E>\"u\")throw new Error(`Assertion failed: The descriptor (${p}) should have been registered`);_e.getSetWithDefault(u,E.identHash).add(h)}let A=new Map(_e.mapAndFilter(t.storedDescriptors.values(),p=>W.isVirtualDescriptor(p)?_e.mapAndFilter.skip:[p.descriptorHash,_e.makeDeferred()]));for(let p of t.storedDescriptors.values()){let h=A.get(p.descriptorHash);if(typeof h>\"u\")throw new Error(`Assertion failed: The descriptor (${p.descriptorHash}) should have been registered`);let E=t.storedResolutions.get(p.descriptorHash);if(typeof E>\"u\")throw new Error(`Assertion failed: The resolution (${p.descriptorHash}) should have been registered`);let I=t.originalPackages.get(E);if(typeof I>\"u\")throw new Error(`Assertion failed: The package (${E}) should have been registered`);Promise.resolve().then(async()=>{let v=r.getResolutionDependencies(p,a),x=Object.fromEntries(await _e.allSettledSafe(Object.entries(v).map(async([te,ae])=>{let fe=A.get(ae.descriptorHash);if(typeof fe>\"u\")throw new Error(`Assertion failed: The descriptor (${ae.descriptorHash}) should have been registered`);let ue=await fe.promise;if(!ue)throw new Error(\"Assertion failed: Expected the dependency to have been through the dedupe process itself\");return[te,ue.updatedPackage]})));if(e.length&&!Vge.default.isMatch(W.stringifyIdent(p),e)||!r.shouldPersistResolution(I,a))return I;let C=u.get(p.identHash);if(typeof C>\"u\")throw new Error(`Assertion failed: The resolutions (${p.identHash}) should have been registered`);if(C.size===1)return I;let R=[...C].map(te=>{let ae=t.originalPackages.get(te);if(typeof ae>\"u\")throw new Error(`Assertion failed: The package (${te}) should have been registered`);return ae}),N=await r.getSatisfying(p,x,R,a),U=N.locators?.[0];if(typeof U>\"u\"||!N.sorted)return I;let V=t.originalPackages.get(U.locatorHash);if(typeof V>\"u\")throw new Error(`Assertion failed: The package (${U.locatorHash}) should have been registered`);return V}).then(async v=>{let x=await t.preparePackage(v,{resolver:r,resolveOptions:a});h.resolve({descriptor:p,currentPackage:I,updatedPackage:v,resolvedPackage:x})}).catch(v=>{h.reject(v)})}return[...A.values()].map(p=>p.promise)}};async function L8(t,{strategy:e,patterns:r,cache:o,report:a}){let{configuration:n}=t,u=new Qi,A=n.makeResolver(),p=n.makeFetcher(),h={cache:o,checksums:t.storedChecksums,fetcher:p,project:t,report:u,cacheOptions:{skipIntegrityCheck:!0}},E={project:t,resolver:A,report:u,fetchOptions:h};return await a.startTimerPromise(\"Deduplication step\",async()=>{let I=U0t[e],v=await I(t,r,{resolver:A,resolveOptions:E,fetcher:p,fetchOptions:h}),x=Xs.progressViaCounter(v.length);await a.reportProgress(x);let C=0;await Promise.all(v.map(U=>U.then(V=>{if(V===null||V.currentPackage.locatorHash===V.updatedPackage.locatorHash)return;C++;let{descriptor:te,currentPackage:ae,updatedPackage:fe}=V;a.reportInfo(0,`${W.prettyDescriptor(n,te)} can be deduped from ${W.prettyLocator(n,ae)} to ${W.prettyLocator(n,fe)}`),a.reportJson({descriptor:W.stringifyDescriptor(te),currentResolution:W.stringifyLocator(ae),updatedResolution:W.stringifyLocator(fe)}),t.storedResolutions.set(te.descriptorHash,fe.locatorHash)}).finally(()=>x.tick())));let R;switch(C){case 0:R=\"No packages\";break;case 1:R=\"One package\";break;default:R=`${C} packages`}let N=de.pretty(n,e,de.Type.CODE);return a.reportInfo(0,`${R} can be deduped using the ${N} strategy`),C})}var Mh=class extends ut{constructor(){super(...arguments);this.strategy=ge.String(\"-s,--strategy\",\"highest\",{description:\"The strategy to use when deduping dependencies\",validator:Ks(m2)});this.check=ge.Boolean(\"-c,--check\",!1,{description:\"Exit with exit code 1 when duplicates are found, without persisting the dependency tree\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.mode=ge.String(\"--mode\",{description:\"Change what artifacts installs generate\",validator:Ks(hl)});this.patterns=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd),a=await Nr.find(r);await o.restoreInstallState({restoreResolutions:!1});let n=0,u=await Lt.start({configuration:r,includeFooter:!1,stdout:this.context.stdout,json:this.json},async A=>{n=await L8(o,{strategy:this.strategy,patterns:this.patterns,cache:a,report:A})});return u.hasErrors()?u.exitCode():this.check?n?1:0:await o.installWithNewReport({json:this.json,stdout:this.context.stdout},{cache:a,mode:this.mode})}};Mh.paths=[[\"dedupe\"]],Mh.usage=nt.Usage({description:\"deduplicate dependencies with overlapping ranges\",details:\"\\n      Duplicates are defined as descriptors with overlapping ranges being resolved and locked to different locators. They are a natural consequence of Yarn's deterministic installs, but they can sometimes pile up and unnecessarily increase the size of your project.\\n\\n      This command dedupes dependencies in the current project using different strategies (only one is implemented at the moment):\\n\\n      - `highest`: Reuses (where possible) the locators with the highest versions. This means that dependencies can only be upgraded, never downgraded. It's also guaranteed that it never takes more than a single pass to dedupe the entire dependency tree.\\n\\n      **Note:** Even though it never produces a wrong dependency tree, this command should be used with caution, as it modifies the dependency tree, which can sometimes cause problems when packages don't strictly follow semver recommendations. Because of this, it is recommended to also review the changes manually.\\n\\n      If set, the `-c,--check` flag will only report the found duplicates, without persisting the modified dependency tree. If changes are found, the command will exit with a non-zero exit code, making it suitable for CI purposes.\\n\\n      If the `--mode=<mode>` option is set, Yarn will change which artifacts are generated. The modes currently supported are:\\n\\n      - `skip-build` will not run the build scripts at all. Note that this is different from setting `enableScripts` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.\\n\\n      - `update-lockfile` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.\\n\\n      This command accepts glob patterns as arguments (if valid Idents and supported by [micromatch](https://github.com/micromatch/micromatch)). Make sure to escape the patterns, to prevent your own shell from trying to expand them.\\n\\n      ### In-depth explanation:\\n\\n      Yarn doesn't deduplicate dependencies by default, otherwise installs wouldn't be deterministic and the lockfile would be useless. What it actually does is that it tries to not duplicate dependencies in the first place.\\n\\n      **Example:** If `foo@^2.3.4` (a dependency of a dependency) has already been resolved to `foo@2.3.4`, running `yarn add foo@*`will cause Yarn to reuse `foo@2.3.4`, even if the latest `foo` is actually `foo@2.10.14`, thus preventing unnecessary duplication.\\n\\n      Duplication happens when Yarn can't unlock dependencies that have already been locked inside the lockfile.\\n\\n      **Example:** If `foo@^2.3.4` (a dependency of a dependency) has already been resolved to `foo@2.3.4`, running `yarn add foo@2.10.14` will cause Yarn to install `foo@2.10.14` because the existing resolution doesn't satisfy the range `2.10.14`. This behavior can lead to (sometimes) unwanted duplication, since now the lockfile contains 2 separate resolutions for the 2 `foo` descriptors, even though they have overlapping ranges, which means that the lockfile can be simplified so that both descriptors resolve to `foo@2.10.14`.\\n    \",examples:[[\"Dedupe all packages\",\"$0 dedupe\"],[\"Dedupe all packages using a specific strategy\",\"$0 dedupe --strategy highest\"],[\"Dedupe a specific package\",\"$0 dedupe lodash\"],[\"Dedupe all packages with the `@babel/*` scope\",\"$0 dedupe '@babel/*'\"],[\"Check for duplicates (can be used as a CI step)\",\"$0 dedupe --check\"]]});Ye();qt();var zd=class extends ut{async execute(){let{plugins:e}=await Ke.find(this.context.cwd,this.context.plugins),r=[];for(let u of e){let{commands:A}=u[1];if(A){let h=as.from(A).definitions();r.push([u[0],h])}}let o=this.cli.definitions(),a=(u,A)=>u.split(\" \").slice(1).join()===A.split(\" \").slice(1).join(),n=Jge()[\"@yarnpkg/builder\"].bundles.standard;for(let u of r){let A=u[1];for(let p of A)o.find(h=>a(h.path,p.path)).plugin={name:u[0],isDefault:n.includes(u[0])}}this.context.stdout.write(`${JSON.stringify(o,null,2)}\n`)}};zd.paths=[[\"--clipanion=definitions\"]];var Vd=class extends ut{async execute(){this.context.stdout.write(this.cli.usage(null))}};Vd.paths=[[\"help\"],[\"--help\"],[\"-h\"]];Ye();Pt();qt();var mC=class extends ut{constructor(){super(...arguments);this.leadingArgument=ge.String();this.args=ge.Proxy()}async execute(){if(this.leadingArgument.match(/[\\\\/]/)&&!W.tryParseIdent(this.leadingArgument)){let r=z.resolve(this.context.cwd,le.toPortablePath(this.leadingArgument));return await this.cli.run(this.args,{cwd:r})}else return await this.cli.run([\"run\",this.leadingArgument,...this.args])}};Ye();var Jd=class extends ut{async execute(){this.context.stdout.write(`${rn||\"<unknown>\"}\n`)}};Jd.paths=[[\"-v\"],[\"--version\"]];Ye();Ye();qt();var Uh=class extends ut{constructor(){super(...arguments);this.commandName=ge.String();this.args=ge.Proxy()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,locator:a}=await St.find(r,this.context.cwd);return await o.restoreInstallState(),await un.executePackageShellcode(a,this.commandName,this.args,{cwd:this.context.cwd,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr,project:o})}};Uh.paths=[[\"exec\"]],Uh.usage=nt.Usage({description:\"execute a shell script\",details:`\n      This command simply executes a shell script within the context of the root directory of the active workspace using the portable shell.\n\n      It also makes sure to call it in a way that's compatible with the current project (for example, on PnP projects the environment will be setup in such a way that PnP will be correctly injected into the environment).\n    `,examples:[[\"Execute a single shell command\",\"$0 exec echo Hello World\"],[\"Execute a shell script\",'$0 exec \"tsc & babel src --out-dir lib\"']]});Ye();qt();$a();var _h=class extends ut{constructor(){super(...arguments);this.hash=ge.String({validator:oP(Cy(),[oI(/^p[0-9a-f]{5}$/)])})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd);return await o.restoreInstallState({restoreResolutions:!1}),await o.applyLightResolution(),await H0t(this.hash,o,{stdout:this.context.stdout})}};_h.paths=[[\"explain\",\"peer-requirements\"]],_h.usage=nt.Usage({description:\"explain a set of peer requirements\",details:`\n      A set of peer requirements represents all peer requirements that a dependent must satisfy when providing a given peer request to a requester and its descendants.\n\n      When the hash argument is specified, this command prints a detailed explanation of all requirements of the set corresponding to the hash and whether they're satisfied or not.\n\n      When used without arguments, this command lists all sets of peer requirements and the corresponding hash that can be used to get detailed information about a given set.\n\n      **Note:** A hash is a six-letter p-prefixed code that can be obtained from peer dependency warnings or from the list of all peer requirements (\\`yarn explain peer-requirements\\`).\n    `,examples:[[\"Explain the corresponding set of peer requirements for a hash\",\"$0 explain peer-requirements p1a4ed\"],[\"List all sets of peer requirements\",\"$0 explain peer-requirements\"]]});async function H0t(t,e,r){let o=e.peerWarnings.find(n=>n.hash===t);if(typeof o>\"u\")throw new Error(`No peerDependency requirements found for hash: \"${t}\"`);return(await Lt.start({configuration:e.configuration,stdout:r.stdout,includeFooter:!1,includePrefix:!1},async n=>{let u=de.mark(e.configuration);switch(o.type){case 2:{n.reportInfo(0,`We have a problem with ${de.pretty(e.configuration,o.requested,de.Type.IDENT)}, which is provided with version ${W.prettyReference(e.configuration,o.version)}.`),n.reportInfo(0,\"It is needed by the following direct dependencies of workspaces in your project:\"),n.reportSeparator();for(let h of o.requesters.values()){let E=e.storedPackages.get(h.locatorHash);if(!E)throw new Error(\"Assertion failed: Expected the package to be registered\");let I=E?.peerDependencies.get(o.requested.identHash);if(!I)throw new Error(\"Assertion failed: Expected the package to list the peer dependency\");let v=kr.satisfiesWithPrereleases(o.version,I.range)?u.Check:u.Cross;n.reportInfo(null,`  ${v} ${W.prettyLocator(e.configuration,h)} (via ${W.prettyRange(e.configuration,I.range)})`)}let A=[...o.links.values()].filter(h=>!o.requesters.has(h.locatorHash));if(A.length>0){n.reportSeparator(),n.reportInfo(0,`However, those packages themselves have more dependencies listing ${W.prettyIdent(e.configuration,o.requested)} as peer dependency:`),n.reportSeparator();for(let h of A){let E=e.storedPackages.get(h.locatorHash);if(!E)throw new Error(\"Assertion failed: Expected the package to be registered\");let I=E?.peerDependencies.get(o.requested.identHash);if(!I)throw new Error(\"Assertion failed: Expected the package to list the peer dependency\");let v=kr.satisfiesWithPrereleases(o.version,I.range)?u.Check:u.Cross;n.reportInfo(null,`  ${v} ${W.prettyLocator(e.configuration,h)} (via ${W.prettyRange(e.configuration,I.range)})`)}}let p=Array.from(o.links.values(),h=>{let E=e.storedPackages.get(h.locatorHash);if(typeof E>\"u\")throw new Error(\"Assertion failed: Expected the package to be registered\");let I=E.peerDependencies.get(o.requested.identHash);if(typeof I>\"u\")throw new Error(\"Assertion failed: Expected the ident to be registered\");return I.range});if(p.length>1){let h=kr.simplifyRanges(p);n.reportSeparator(),h===null?(n.reportInfo(0,\"Unfortunately, put together, we found no single range that can satisfy all those peer requirements.\"),n.reportInfo(0,`Your best option may be to try to upgrade some dependencies with ${de.pretty(e.configuration,\"yarn up\",de.Type.CODE)}, or silence the warning via ${de.pretty(e.configuration,\"logFilters\",de.Type.CODE)}.`)):n.reportInfo(0,`Put together, the final range we computed is ${de.pretty(e.configuration,h,de.Type.RANGE)}`)}}break;default:n.reportInfo(0,`The ${de.pretty(e.configuration,\"yarn explain peer-requirements\",de.Type.CODE)} command doesn't support this warning type yet.`);break}})).exitCode()}Ye();qt();$a();Ye();Ye();Pt();qt();var Xge=$e(Jn()),Hh=class extends ut{constructor(){super(...arguments);this.useYarnPath=ge.Boolean(\"--yarn-path\",{description:\"Set the yarnPath setting even if the version can be accessed by Corepack\"});this.onlyIfNeeded=ge.Boolean(\"--only-if-needed\",!1,{description:\"Only lock the Yarn version if it isn't already locked\"});this.version=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins);if(this.onlyIfNeeded&&r.get(\"yarnPath\")){let A=r.sources.get(\"yarnPath\");if(!A)throw new Error(\"Assertion failed: Expected 'yarnPath' to have a source\");let p=r.projectCwd??r.startingCwd;if(z.contains(p,A))return 0}let o=()=>{if(typeof rn>\"u\")throw new it(\"The --install flag can only be used without explicit version specifier from the Yarn CLI\");return`file://${process.argv[1]}`},a,n=(A,p)=>({version:p,url:A.replace(/\\{\\}/g,p)});if(this.version===\"self\")a={url:o(),version:rn??\"self\"};else if(this.version===\"latest\"||this.version===\"berry\"||this.version===\"stable\")a=n(\"https://repo.yarnpkg.com/{}/packages/yarnpkg-cli/bin/yarn.js\",await y2(r,\"stable\"));else if(this.version===\"canary\")a=n(\"https://repo.yarnpkg.com/{}/packages/yarnpkg-cli/bin/yarn.js\",await y2(r,\"canary\"));else if(this.version===\"classic\")a={url:\"https://classic.yarnpkg.com/latest.js\",version:\"classic\"};else if(this.version.match(/^https?:/))a={url:this.version,version:\"remote\"};else if(this.version.match(/^\\.{0,2}[\\\\/]/)||le.isAbsolute(this.version))a={url:`file://${z.resolve(le.toPortablePath(this.version))}`,version:\"file\"};else if(kr.satisfiesWithPrereleases(this.version,\">=2.0.0\"))a=n(\"https://repo.yarnpkg.com/{}/packages/yarnpkg-cli/bin/yarn.js\",this.version);else if(kr.satisfiesWithPrereleases(this.version,\"^0.x || ^1.x\"))a=n(\"https://github.com/yarnpkg/yarn/releases/download/v{}/yarn-{}.js\",this.version);else if(kr.validRange(this.version))a=n(\"https://repo.yarnpkg.com/{}/packages/yarnpkg-cli/bin/yarn.js\",await q0t(r,this.version));else throw new it(`Invalid version descriptor \"${this.version}\"`);return(await Lt.start({configuration:r,stdout:this.context.stdout,includeLogs:!this.context.quiet},async A=>{let p=async()=>{let h=\"file://\";return a.url.startsWith(h)?(A.reportInfo(0,`Retrieving ${de.pretty(r,a.url,de.Type.PATH)}`),await oe.readFilePromise(a.url.slice(h.length))):(A.reportInfo(0,`Downloading ${de.pretty(r,a.url,de.Type.URL)}`),await nn.get(a.url,{configuration:r}))};await N8(r,a.version,p,{report:A,useYarnPath:this.useYarnPath})})).exitCode()}};Hh.paths=[[\"set\",\"version\"]],Hh.usage=nt.Usage({description:\"lock the Yarn version used by the project\",details:\"\\n      This command will set a specific release of Yarn to be used by Corepack: https://nodejs.org/api/corepack.html.\\n\\n      By default it only will set the `packageManager` field at the root of your project, but if the referenced release cannot be represented this way, if you already have `yarnPath` configured, or if you set the `--yarn-path` command line flag, then the release will also be downloaded from the Yarn GitHub repository, stored inside your project, and referenced via the `yarnPath` settings from your project `.yarnrc.yml` file.\\n\\n      A very good use case for this command is to enforce the version of Yarn used by any single member of your team inside the same project - by doing this you ensure that you have control over Yarn upgrades and downgrades (including on your deployment servers), and get rid of most of the headaches related to someone using a slightly different version and getting different behavior.\\n\\n      The version specifier can be:\\n\\n      - a tag:\\n        - `latest` / `berry` / `stable` -> the most recent stable berry (`>=2.0.0`) release\\n        - `canary` -> the most recent canary (release candidate) berry (`>=2.0.0`) release\\n        - `classic` -> the most recent classic (`^0.x || ^1.x`) release\\n\\n      - a semver range (e.g. `2.x`) -> the most recent version satisfying the range (limited to berry releases)\\n\\n      - a semver version (e.g. `2.4.1`, `1.22.1`)\\n\\n      - a local file referenced through either a relative or absolute path\\n\\n      - `self` -> the version used to invoke the command\\n    \",examples:[[\"Download the latest release from the Yarn repository\",\"$0 set version latest\"],[\"Download the latest canary release from the Yarn repository\",\"$0 set version canary\"],[\"Download the latest classic release from the Yarn repository\",\"$0 set version classic\"],[\"Download the most recent Yarn 3 build\",\"$0 set version 3.x\"],[\"Download a specific Yarn 2 build\",\"$0 set version 2.0.0-rc.30\"],[\"Switch back to a specific Yarn 1 release\",\"$0 set version 1.22.1\"],[\"Use a release from the local filesystem\",\"$0 set version ./yarn.cjs\"],[\"Use a release from a URL\",\"$0 set version https://repo.yarnpkg.com/3.1.0/packages/yarnpkg-cli/bin/yarn.js\"],[\"Download the version used to invoke the command\",\"$0 set version self\"]]});async function q0t(t,e){let o=(await nn.get(\"https://repo.yarnpkg.com/tags\",{configuration:t,jsonResponse:!0})).tags.filter(a=>kr.satisfiesWithPrereleases(a,e));if(o.length===0)throw new it(`No matching release found for range ${de.pretty(t,e,de.Type.RANGE)}.`);return o[0]}async function y2(t,e){let r=await nn.get(\"https://repo.yarnpkg.com/tags\",{configuration:t,jsonResponse:!0});if(!r.latest[e])throw new it(`Tag ${de.pretty(t,e,de.Type.RANGE)} not found`);return r.latest[e]}async function N8(t,e,r,{report:o,useYarnPath:a}){let n,u=async()=>(typeof n>\"u\"&&(n=await r()),n);if(e===null){let te=await u();await oe.mktempPromise(async ae=>{let fe=z.join(ae,\"yarn.cjs\");await oe.writeFilePromise(fe,te);let{stdout:ue}=await Ur.execvp(process.execPath,[le.fromPortablePath(fe),\"--version\"],{cwd:ae,env:{...t.env,YARN_IGNORE_PATH:\"1\"}});if(e=ue.trim(),!Xge.default.valid(e))throw new Error(`Invalid semver version. ${de.pretty(t,\"yarn --version\",de.Type.CODE)} returned:\n${e}`)})}let A=t.projectCwd??t.startingCwd,p=z.resolve(A,\".yarn/releases\"),h=z.resolve(p,`yarn-${e}.cjs`),E=z.relative(t.startingCwd,h),I=_e.isTaggedYarnVersion(e),v=t.get(\"yarnPath\"),x=!I,C=x||!!v||!!a;if(a===!1){if(x)throw new Jt(0,\"You explicitly opted out of yarnPath usage in your command line, but the version you specified cannot be represented by Corepack\");C=!1}else!C&&!process.env.COREPACK_ROOT&&(o.reportWarning(0,`You don't seem to have ${de.applyHyperlink(t,\"Corepack\",\"https://nodejs.org/api/corepack.html\")} enabled; we'll have to rely on ${de.applyHyperlink(t,\"yarnPath\",\"https://yarnpkg.com/configuration/yarnrc#yarnPath\")} instead`),C=!0);if(C){let te=await u();o.reportInfo(0,`Saving the new release in ${de.pretty(t,E,\"magenta\")}`),await oe.removePromise(z.dirname(h)),await oe.mkdirPromise(z.dirname(h),{recursive:!0}),await oe.writeFilePromise(h,te,{mode:493}),await Ke.updateConfiguration(A,{yarnPath:z.relative(A,h)})}else await oe.removePromise(z.dirname(h)),await Ke.updateConfiguration(A,{yarnPath:Ke.deleteProperty});let R=await Ot.tryFind(A)||new Ot;R.packageManager=`yarn@${I?e:await y2(t,\"stable\")}`;let N={};R.exportTo(N);let U=z.join(A,Ot.fileName),V=`${JSON.stringify(N,null,R.indent)}\n`;return await oe.changeFilePromise(U,V,{automaticNewlines:!0}),{bundleVersion:e}}function Zge(t){return wr[AP(t)]}var G0t=/## (?<code>YN[0-9]{4}) - `(?<name>[A-Z_]+)`\\n\\n(?<details>(?:.(?!##))+)/gs;async function j0t(t){let r=`https://repo.yarnpkg.com/${_e.isTaggedYarnVersion(rn)?rn:await y2(t,\"canary\")}/packages/gatsby/content/advanced/error-codes.md`,o=await nn.get(r,{configuration:t});return new Map(Array.from(o.toString().matchAll(G0t),({groups:a})=>{if(!a)throw new Error(\"Assertion failed: Expected the match to have been successful\");let n=Zge(a.code);if(a.name!==n)throw new Error(`Assertion failed: Invalid error code data: Expected \"${a.name}\" to be named \"${n}\"`);return[a.code,a.details]}))}var qh=class extends ut{constructor(){super(...arguments);this.code=ge.String({required:!1,validator:aI(Cy(),[oI(/^YN[0-9]{4}$/)])});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins);if(typeof this.code<\"u\"){let o=Zge(this.code),a=de.pretty(r,o,de.Type.CODE),n=this.cli.format().header(`${this.code} - ${a}`),A=(await j0t(r)).get(this.code),p=typeof A<\"u\"?de.jsonOrPretty(this.json,r,de.tuple(de.Type.MARKDOWN,{text:A,format:this.cli.format(),paragraphs:!0})):`This error code does not have a description.\n\nYou can help us by editing this page on GitHub \\u{1F642}:\n${de.jsonOrPretty(this.json,r,de.tuple(de.Type.URL,\"https://github.com/yarnpkg/berry/blob/master/packages/gatsby/content/advanced/error-codes.md\"))}\n`;this.json?this.context.stdout.write(`${JSON.stringify({code:this.code,name:o,details:p})}\n`):this.context.stdout.write(`${n}\n\n${p}\n`)}else{let o={children:_e.mapAndFilter(Object.entries(wr),([a,n])=>Number.isNaN(Number(a))?_e.mapAndFilter.skip:{label:Ku(Number(a)),value:de.tuple(de.Type.CODE,n)})};$s.emitTree(o,{configuration:r,stdout:this.context.stdout,json:this.json})}}};qh.paths=[[\"explain\"]],qh.usage=nt.Usage({description:\"explain an error code\",details:`\n      When the code argument is specified, this command prints its name and its details.\n\n      When used without arguments, this command lists all error codes and their names.\n    `,examples:[[\"Explain an error code\",\"$0 explain YN0006\"],[\"List all error codes\",\"$0 explain\"]]});Ye();Pt();qt();var $ge=$e(Zo()),Gh=class extends ut{constructor(){super(...arguments);this.all=ge.Boolean(\"-A,--all\",!1,{description:\"Print versions of a package from the whole project\"});this.recursive=ge.Boolean(\"-R,--recursive\",!1,{description:\"Print information for all packages, including transitive dependencies\"});this.extra=ge.Array(\"-X,--extra\",[],{description:\"An array of requests of extra data provided by plugins\"});this.cache=ge.Boolean(\"--cache\",!1,{description:\"Print information about the cache entry of a package (path, size, checksum)\"});this.dependents=ge.Boolean(\"--dependents\",!1,{description:\"Print all dependents for each matching package\"});this.manifest=ge.Boolean(\"--manifest\",!1,{description:\"Print data obtained by looking at the package archive (license, homepage, ...)\"});this.nameOnly=ge.Boolean(\"--name-only\",!1,{description:\"Only print the name for the matching packages\"});this.virtuals=ge.Boolean(\"--virtuals\",!1,{description:\"Print each instance of the virtual packages\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.patterns=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Nr.find(r);if(!a&&!this.all)throw new nr(o.cwd,this.context.cwd);await o.restoreInstallState();let u=new Set(this.extra);this.cache&&u.add(\"cache\"),this.dependents&&u.add(\"dependents\"),this.manifest&&u.add(\"manifest\");let A=(ae,{recursive:fe})=>{let ue=ae.anchoredLocator.locatorHash,me=new Map,he=[ue];for(;he.length>0;){let Be=he.shift();if(me.has(Be))continue;let we=o.storedPackages.get(Be);if(typeof we>\"u\")throw new Error(\"Assertion failed: Expected the package to be registered\");if(me.set(Be,we),W.isVirtualLocator(we)&&he.push(W.devirtualizeLocator(we).locatorHash),!(!fe&&Be!==ue))for(let g of we.dependencies.values()){let Ee=o.storedResolutions.get(g.descriptorHash);if(typeof Ee>\"u\")throw new Error(\"Assertion failed: Expected the resolution to be registered\");he.push(Ee)}}return me.values()},p=({recursive:ae})=>{let fe=new Map;for(let ue of o.workspaces)for(let me of A(ue,{recursive:ae}))fe.set(me.locatorHash,me);return fe.values()},h=({all:ae,recursive:fe})=>ae&&fe?o.storedPackages.values():ae?p({recursive:fe}):A(a,{recursive:fe}),E=({all:ae,recursive:fe})=>{let ue=h({all:ae,recursive:fe}),me=this.patterns.map(we=>{let g=W.parseLocator(we),Ee=$ge.default.makeRe(W.stringifyIdent(g)),Pe=W.isVirtualLocator(g),ce=Pe?W.devirtualizeLocator(g):g;return ne=>{let ee=W.stringifyIdent(ne);if(!Ee.test(ee))return!1;if(g.reference===\"unknown\")return!0;let Ie=W.isVirtualLocator(ne),Fe=Ie?W.devirtualizeLocator(ne):ne;return!(Pe&&Ie&&g.reference!==ne.reference||ce.reference!==Fe.reference)}}),he=_e.sortMap([...ue],we=>W.stringifyLocator(we));return{selection:he.filter(we=>me.length===0||me.some(g=>g(we))),sortedLookup:he}},{selection:I,sortedLookup:v}=E({all:this.all,recursive:this.recursive});if(I.length===0)throw new it(\"No package matched your request\");let x=new Map;if(this.dependents)for(let ae of v)for(let fe of ae.dependencies.values()){let ue=o.storedResolutions.get(fe.descriptorHash);if(typeof ue>\"u\")throw new Error(\"Assertion failed: Expected the resolution to be registered\");_e.getArrayWithDefault(x,ue).push(ae)}let C=new Map;for(let ae of v){if(!W.isVirtualLocator(ae))continue;let fe=W.devirtualizeLocator(ae);_e.getArrayWithDefault(C,fe.locatorHash).push(ae)}let R={},N={children:R},U=r.makeFetcher(),V={project:o,fetcher:U,cache:n,checksums:o.storedChecksums,report:new Qi,cacheOptions:{skipIntegrityCheck:!0}},te=[async(ae,fe,ue)=>{if(!fe.has(\"manifest\"))return;let me=await U.fetch(ae,V),he;try{he=await Ot.find(me.prefixPath,{baseFs:me.packageFs})}finally{me.releaseFs?.()}ue(\"Manifest\",{License:de.tuple(de.Type.NO_HINT,he.license),Homepage:de.tuple(de.Type.URL,he.raw.homepage??null)})},async(ae,fe,ue)=>{if(!fe.has(\"cache\"))return;let me=o.storedChecksums.get(ae.locatorHash)??null,he=n.getLocatorPath(ae,me),Be;if(he!==null)try{Be=await oe.statPromise(he)}catch{}let we=typeof Be<\"u\"?[Be.size,de.Type.SIZE]:void 0;ue(\"Cache\",{Checksum:de.tuple(de.Type.NO_HINT,me),Path:de.tuple(de.Type.PATH,he),Size:we})}];for(let ae of I){let fe=W.isVirtualLocator(ae);if(!this.virtuals&&fe)continue;let ue={},me={value:[ae,de.Type.LOCATOR],children:ue};if(R[W.stringifyLocator(ae)]=me,this.nameOnly){delete me.children;continue}let he=C.get(ae.locatorHash);typeof he<\"u\"&&(ue.Instances={label:\"Instances\",value:de.tuple(de.Type.NUMBER,he.length)}),ue.Version={label:\"Version\",value:de.tuple(de.Type.NO_HINT,ae.version)};let Be=(g,Ee)=>{let Pe={};if(ue[g]=Pe,Array.isArray(Ee))Pe.children=Ee.map(ce=>({value:ce}));else{let ce={};Pe.children=ce;for(let[ne,ee]of Object.entries(Ee))typeof ee>\"u\"||(ce[ne]={label:ne,value:ee})}};if(!fe){for(let g of te)await g(ae,u,Be);await r.triggerHook(g=>g.fetchPackageInfo,ae,u,Be)}ae.bin.size>0&&!fe&&Be(\"Exported Binaries\",[...ae.bin.keys()].map(g=>de.tuple(de.Type.PATH,g)));let we=x.get(ae.locatorHash);typeof we<\"u\"&&we.length>0&&Be(\"Dependents\",we.map(g=>de.tuple(de.Type.LOCATOR,g))),ae.dependencies.size>0&&!fe&&Be(\"Dependencies\",[...ae.dependencies.values()].map(g=>{let Ee=o.storedResolutions.get(g.descriptorHash),Pe=typeof Ee<\"u\"?o.storedPackages.get(Ee)??null:null;return de.tuple(de.Type.RESOLUTION,{descriptor:g,locator:Pe})})),ae.peerDependencies.size>0&&fe&&Be(\"Peer dependencies\",[...ae.peerDependencies.values()].map(g=>{let Ee=ae.dependencies.get(g.identHash),Pe=typeof Ee<\"u\"?o.storedResolutions.get(Ee.descriptorHash)??null:null,ce=Pe!==null?o.storedPackages.get(Pe)??null:null;return de.tuple(de.Type.RESOLUTION,{descriptor:g,locator:ce})}))}$s.emitTree(N,{configuration:r,json:this.json,stdout:this.context.stdout,separators:this.nameOnly?0:2})}};Gh.paths=[[\"info\"]],Gh.usage=nt.Usage({description:\"see information related to packages\",details:\"\\n      This command prints various information related to the specified packages, accepting glob patterns.\\n\\n      By default, if the locator reference is missing, Yarn will default to print the information about all the matching direct dependencies of the package for the active workspace. To instead print all versions of the package that are direct dependencies of any of your workspaces, use the `-A,--all` flag. Adding the `-R,--recursive` flag will also report transitive dependencies.\\n\\n      Some fields will be hidden by default in order to keep the output readable, but can be selectively displayed by using additional options (`--dependents`, `--manifest`, `--virtuals`, ...) described in the option descriptions.\\n\\n      Note that this command will only print the information directly related to the selected packages - if you wish to know why the package is there in the first place, use `yarn why` which will do just that (it also provides a `-R,--recursive` flag that may be of some help).\\n    \",examples:[[\"Show information about Lodash\",\"$0 info lodash\"]]});Ye();Pt();Nl();var hk=$e(rd());qt();var O8=$e(Jn());$a();var Y0t=[{selector:t=>t===-1,name:\"nodeLinker\",value:\"node-modules\"},{selector:t=>t!==-1&&t<8,name:\"enableGlobalCache\",value:!1},{selector:t=>t!==-1&&t<8,name:\"compressionLevel\",value:\"mixed\"}],jh=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.immutable=ge.Boolean(\"--immutable\",{description:\"Abort with an error exit code if the lockfile was to be modified\"});this.immutableCache=ge.Boolean(\"--immutable-cache\",{description:\"Abort with an error exit code if the cache folder was to be modified\"});this.refreshLockfile=ge.Boolean(\"--refresh-lockfile\",{description:\"Refresh the package metadata stored in the lockfile\"});this.checkCache=ge.Boolean(\"--check-cache\",{description:\"Always refetch the packages and ensure that their checksums are consistent\"});this.checkResolutions=ge.Boolean(\"--check-resolutions\",{description:\"Validates that the package resolutions are coherent\"});this.inlineBuilds=ge.Boolean(\"--inline-builds\",{description:\"Verbosely print the output of the build steps of dependencies\"});this.mode=ge.String(\"--mode\",{description:\"Change what artifacts installs generate\",validator:Ks(hl)});this.cacheFolder=ge.String(\"--cache-folder\",{hidden:!0});this.frozenLockfile=ge.Boolean(\"--frozen-lockfile\",{hidden:!0});this.ignoreEngines=ge.Boolean(\"--ignore-engines\",{hidden:!0});this.nonInteractive=ge.Boolean(\"--non-interactive\",{hidden:!0});this.preferOffline=ge.Boolean(\"--prefer-offline\",{hidden:!0});this.production=ge.Boolean(\"--production\",{hidden:!0});this.registry=ge.String(\"--registry\",{hidden:!0});this.silent=ge.Boolean(\"--silent\",{hidden:!0});this.networkTimeout=ge.String(\"--network-timeout\",{hidden:!0})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins);typeof this.inlineBuilds<\"u\"&&r.useWithSource(\"<cli>\",{enableInlineBuilds:this.inlineBuilds},r.startingCwd,{overwrite:!0});let o=!!process.env.FUNCTION_TARGET||!!process.env.GOOGLE_RUNTIME,a=await NE({configuration:r,stdout:this.context.stdout},[{option:this.ignoreEngines,message:\"The --ignore-engines option is deprecated; engine checking isn't a core feature anymore\",error:!hk.default.VERCEL},{option:this.registry,message:\"The --registry option is deprecated; prefer setting npmRegistryServer in your .yarnrc.yml file\"},{option:this.preferOffline,message:\"The --prefer-offline flag is deprecated; use the --cached flag with 'yarn add' instead\",error:!hk.default.VERCEL},{option:this.production,message:\"The --production option is deprecated on 'install'; use 'yarn workspaces focus' instead\",error:!0},{option:this.nonInteractive,message:\"The --non-interactive option is deprecated\",error:!o},{option:this.frozenLockfile,message:\"The --frozen-lockfile option is deprecated; use --immutable and/or --immutable-cache instead\",callback:()=>this.immutable=this.frozenLockfile},{option:this.cacheFolder,message:\"The cache-folder option has been deprecated; use rc settings instead\",error:!hk.default.NETLIFY}]);if(a!==null)return a;let n=this.mode===\"update-lockfile\";if(n&&(this.immutable||this.immutableCache))throw new it(`${de.pretty(r,\"--immutable\",de.Type.CODE)} and ${de.pretty(r,\"--immutable-cache\",de.Type.CODE)} cannot be used with ${de.pretty(r,\"--mode=update-lockfile\",de.Type.CODE)}`);let u=(this.immutable??r.get(\"enableImmutableInstalls\"))&&!n,A=this.immutableCache&&!n;if(r.projectCwd!==null){let R=await Lt.start({configuration:r,json:this.json,stdout:this.context.stdout,includeFooter:!1},async N=>{let U=!1;await z0t(r,u)&&(N.reportInfo(48,\"Automatically removed core plugins that are now builtins \\u{1F44D}\"),U=!0),await K0t(r,u)&&(N.reportInfo(48,\"Automatically fixed merge conflicts \\u{1F44D}\"),U=!0),U&&N.reportSeparator()});if(R.hasErrors())return R.exitCode()}if(r.projectCwd!==null){let R=await Lt.start({configuration:r,json:this.json,stdout:this.context.stdout,includeFooter:!1},async N=>{if(Ke.telemetry?.isNew)Ke.telemetry.commitTips(),N.reportInfo(65,\"Yarn will periodically gather anonymous telemetry: https://yarnpkg.com/advanced/telemetry\"),N.reportInfo(65,`Run ${de.pretty(r,\"yarn config set --home enableTelemetry 0\",de.Type.CODE)} to disable`),N.reportSeparator();else if(Ke.telemetry?.shouldShowTips){let U=await nn.get(\"https://repo.yarnpkg.com/tags\",{configuration:r,jsonResponse:!0}).catch(()=>null);if(U!==null){let V=null;if(rn!==null){let ae=O8.default.prerelease(rn)?\"canary\":\"stable\",fe=U.latest[ae];O8.default.gt(fe,rn)&&(V=[ae,fe])}if(V)Ke.telemetry.commitTips(),N.reportInfo(88,`${de.applyStyle(r,`A new ${V[0]} version of Yarn is available:`,de.Style.BOLD)} ${W.prettyReference(r,V[1])}!`),N.reportInfo(88,`Upgrade now by running ${de.pretty(r,`yarn set version ${V[1]}`,de.Type.CODE)}`),N.reportSeparator();else{let te=Ke.telemetry.selectTip(U.tips);te&&(N.reportInfo(89,de.pretty(r,te.message,de.Type.MARKDOWN_INLINE)),te.url&&N.reportInfo(89,`Learn more at ${te.url}`),N.reportSeparator())}}}});if(R.hasErrors())return R.exitCode()}let{project:p,workspace:h}=await St.find(r,this.context.cwd),E=p.lockfileLastVersion;if(E!==null){let R=await Lt.start({configuration:r,json:this.json,stdout:this.context.stdout,includeFooter:!1},async N=>{let U={};for(let V of Y0t)V.selector(E)&&typeof r.sources.get(V.name)>\"u\"&&(r.use(\"<compat>\",{[V.name]:V.value},p.cwd,{overwrite:!0}),U[V.name]=V.value);Object.keys(U).length>0&&(await Ke.updateConfiguration(p.cwd,U),N.reportInfo(87,\"Migrated your project to the latest Yarn version \\u{1F680}\"),N.reportSeparator())});if(R.hasErrors())return R.exitCode()}let I=await Nr.find(r,{immutable:A,check:this.checkCache});if(!h)throw new nr(p.cwd,this.context.cwd);await p.restoreInstallState({restoreResolutions:!1});let v=r.get(\"enableHardenedMode\");v&&typeof r.sources.get(\"enableHardenedMode\")>\"u\"&&await Lt.start({configuration:r,json:this.json,stdout:this.context.stdout,includeFooter:!1},async R=>{R.reportWarning(0,\"Yarn detected that the current workflow is executed from a public pull request. For safety the hardened mode has been enabled.\"),R.reportWarning(0,`It will prevent malicious lockfile manipulations, in exchange for a slower install time. You can opt-out if necessary; check our ${de.applyHyperlink(r,\"documentation\",\"https://yarnpkg.com/features/security#hardened-mode\")} for more details.`),R.reportSeparator()}),(this.refreshLockfile??v)&&(p.lockfileNeedsRefresh=!0);let x=this.checkResolutions??v;return(await Lt.start({configuration:r,json:this.json,stdout:this.context.stdout,forceSectionAlignment:!0,includeLogs:!0,includeVersion:!0},async R=>{await p.install({cache:I,report:R,immutable:u,checkResolutions:x,mode:this.mode})})).exitCode()}};jh.paths=[[\"install\"],nt.Default],jh.usage=nt.Usage({description:\"install the project dependencies\",details:\"\\n      This command sets up your project if needed. The installation is split into four different steps that each have their own characteristics:\\n\\n      - **Resolution:** First the package manager will resolve your dependencies. The exact way a dependency version is privileged over another isn't standardized outside of the regular semver guarantees. If a package doesn't resolve to what you would expect, check that all dependencies are correctly declared (also check our website for more information: ).\\n\\n      - **Fetch:** Then we download all the dependencies if needed, and make sure that they're all stored within our cache (check the value of `cacheFolder` in `yarn config` to see where the cache files are stored).\\n\\n      - **Link:** Then we send the dependency tree information to internal plugins tasked with writing them on the disk in some form (for example by generating the `.pnp.cjs` file you might know).\\n\\n      - **Build:** Once the dependency tree has been written on the disk, the package manager will now be free to run the build scripts for all packages that might need it, in a topological order compatible with the way they depend on one another. See https://yarnpkg.com/advanced/lifecycle-scripts for detail.\\n\\n      Note that running this command is not part of the recommended workflow. Yarn supports zero-installs, which means that as long as you store your cache and your `.pnp.cjs` file inside your repository, everything will work without requiring any install right after cloning your repository or switching branches.\\n\\n      If the `--immutable` option is set (defaults to true on CI), Yarn will abort with an error exit code if the lockfile was to be modified (other paths can be added using the `immutablePatterns` configuration setting). For backward compatibility we offer an alias under the name of `--frozen-lockfile`, but it will be removed in a later release.\\n\\n      If the `--immutable-cache` option is set, Yarn will abort with an error exit code if the cache folder was to be modified (either because files would be added, or because they'd be removed).\\n\\n      If the `--refresh-lockfile` option is set, Yarn will keep the same resolution for the packages currently in the lockfile but will refresh their metadata. If used together with `--immutable`, it can validate that the lockfile information are consistent. This flag is enabled by default when Yarn detects it runs within a pull request context.\\n\\n      If the `--check-cache` option is set, Yarn will always refetch the packages and will ensure that their checksum matches what's 1/ described in the lockfile 2/ inside the existing cache files (if present). This is recommended as part of your CI workflow if you're both following the Zero-Installs model and accepting PRs from third-parties, as they'd otherwise have the ability to alter the checked-in packages before submitting them.\\n\\n      If the `--inline-builds` option is set, Yarn will verbosely print the output of the build steps of your dependencies (instead of writing them into individual files). This is likely useful mostly for debug purposes only when using Docker-like environments.\\n\\n      If the `--mode=<mode>` option is set, Yarn will change which artifacts are generated. The modes currently supported are:\\n\\n      - `skip-build` will not run the build scripts at all. Note that this is different from setting `enableScripts` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.\\n\\n      - `update-lockfile` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.\\n    \",examples:[[\"Install the project\",\"$0 install\"],[\"Validate a project when using Zero-Installs\",\"$0 install --immutable --immutable-cache\"],[\"Validate a project when using Zero-Installs (slightly safer if you accept external PRs)\",\"$0 install --immutable --immutable-cache --check-cache\"]]});var W0t=\"<<<<<<<\";async function K0t(t,e){if(!t.projectCwd)return!1;let r=z.join(t.projectCwd,dr.lockfile);if(!await oe.existsPromise(r)||!(await oe.readFilePromise(r,\"utf8\")).includes(W0t))return!1;if(e)throw new Jt(47,\"Cannot autofix a lockfile when running an immutable install\");let a=await Ur.execvp(\"git\",[\"rev-parse\",\"MERGE_HEAD\",\"HEAD\"],{cwd:t.projectCwd});if(a.code!==0&&(a=await Ur.execvp(\"git\",[\"rev-parse\",\"REBASE_HEAD\",\"HEAD\"],{cwd:t.projectCwd})),a.code!==0&&(a=await Ur.execvp(\"git\",[\"rev-parse\",\"CHERRY_PICK_HEAD\",\"HEAD\"],{cwd:t.projectCwd})),a.code!==0)throw new Jt(83,\"Git returned an error when trying to find the commits pertaining to the conflict\");let n=await Promise.all(a.stdout.trim().split(/\\n/).map(async A=>{let p=await Ur.execvp(\"git\",[\"show\",`${A}:./${dr.lockfile}`],{cwd:t.projectCwd});if(p.code!==0)throw new Jt(83,`Git returned an error when trying to access the lockfile content in ${A}`);try{return Ki(p.stdout)}catch{throw new Jt(46,\"A variant of the conflicting lockfile failed to parse\")}}));n=n.filter(A=>!!A.__metadata);for(let A of n){if(A.__metadata.version<7)for(let p of Object.keys(A)){if(p===\"__metadata\")continue;let h=W.parseDescriptor(p,!0),E=t.normalizeDependency(h),I=W.stringifyDescriptor(E);I!==p&&(A[I]=A[p],delete A[p])}for(let p of Object.keys(A)){if(p===\"__metadata\")continue;let h=A[p].checksum;typeof h==\"string\"&&h.includes(\"/\")||(A[p].checksum=`${A.__metadata.cacheKey}/${h}`)}}let u=Object.assign({},...n);u.__metadata.version=`${Math.min(...n.map(A=>parseInt(A.__metadata.version??0)))}`,u.__metadata.cacheKey=\"merged\";for(let[A,p]of Object.entries(u))typeof p==\"string\"&&delete u[A];return await oe.changeFilePromise(r,Ba(u),{automaticNewlines:!0}),!0}async function z0t(t,e){if(!t.projectCwd)return!1;let r=[],o=z.join(t.projectCwd,\".yarn/plugins/@yarnpkg\");return await Ke.updateConfiguration(t.projectCwd,{plugins:n=>{if(!Array.isArray(n))return n;let u=n.filter(A=>{if(!A.path)return!0;let p=z.resolve(t.projectCwd,A.path),h=v1.has(A.spec)&&z.contains(o,p);return h&&r.push(p),!h});return u.length===0?Ke.deleteProperty:u.length===n.length?n:u}},{immutable:e})?(await Promise.all(r.map(async n=>{await oe.removePromise(n)})),!0):!1}Ye();Pt();qt();var Yh=class extends ut{constructor(){super(...arguments);this.all=ge.Boolean(\"-A,--all\",!1,{description:\"Link all workspaces belonging to the target projects to the current one\"});this.private=ge.Boolean(\"-p,--private\",!1,{description:\"Also link private workspaces belonging to the target projects to the current one\"});this.relative=ge.Boolean(\"-r,--relative\",!1,{description:\"Link workspaces using relative paths instead of absolute paths\"});this.destinations=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Nr.find(r);if(!a)throw new nr(o.cwd,this.context.cwd);await o.restoreInstallState({restoreResolutions:!1});let u=o.topLevelWorkspace,A=[];for(let p of this.destinations){let h=z.resolve(this.context.cwd,le.toPortablePath(p)),E=await Ke.find(h,this.context.plugins,{useRc:!1,strict:!1}),{project:I,workspace:v}=await St.find(E,h);if(o.cwd===I.cwd)throw new it(`Invalid destination '${p}'; Can't link the project to itself`);if(!v)throw new nr(I.cwd,h);if(this.all){let x=!1;for(let C of I.workspaces)C.manifest.name&&(!C.manifest.private||this.private)&&(A.push(C),x=!0);if(!x)throw new it(`No workspace found to be linked in the target project: ${p}`)}else{if(!v.manifest.name)throw new it(`The target workspace at '${p}' doesn't have a name and thus cannot be linked`);if(v.manifest.private&&!this.private)throw new it(`The target workspace at '${p}' is marked private - use the --private flag to link it anyway`);A.push(v)}}for(let p of A){let h=W.stringifyIdent(p.anchoredLocator),E=this.relative?z.relative(o.cwd,p.cwd):p.cwd;u.manifest.resolutions.push({pattern:{descriptor:{fullName:h}},reference:`portal:${E}`})}return await o.installWithNewReport({stdout:this.context.stdout},{cache:n})}};Yh.paths=[[\"link\"]],Yh.usage=nt.Usage({description:\"connect the local project to another one\",details:\"\\n      This command will set a new `resolutions` field in the project-level manifest and point it to the workspace at the specified location (even if part of another project).\\n    \",examples:[[\"Register one or more remote workspaces for use in the current project\",\"$0 link ~/ts-loader ~/jest\"],[\"Register all workspaces from a remote project for use in the current project\",\"$0 link ~/jest --all\"]]});qt();var Wh=class extends ut{constructor(){super(...arguments);this.args=ge.Proxy()}async execute(){return this.cli.run([\"exec\",\"node\",...this.args])}};Wh.paths=[[\"node\"]],Wh.usage=nt.Usage({description:\"run node with the hook already setup\",details:`\n      This command simply runs Node. It also makes sure to call it in a way that's compatible with the current project (for example, on PnP projects the environment will be setup in such a way that PnP will be correctly injected into the environment).\n\n      The Node process will use the exact same version of Node as the one used to run Yarn itself, which might be a good way to ensure that your commands always use a consistent Node version.\n    `,examples:[[\"Run a Node script\",\"$0 node ./my-script.js\"]]});Ye();qt();var Kh=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),o=await Ke.findRcFiles(this.context.cwd);return(await Lt.start({configuration:r,json:this.json,stdout:this.context.stdout},async n=>{for(let u of o)if(!!u.data?.plugins)for(let A of u.data.plugins){if(!A.checksum||!A.spec.match(/^https?:/))continue;let p=await nn.get(A.spec,{configuration:r}),h=wn.makeHash(p);if(A.checksum===h)continue;let E=de.pretty(r,A.path,de.Type.PATH),I=de.pretty(r,A.spec,de.Type.URL),v=`${E} is different from the file provided by ${I}`;n.reportJson({...A,newChecksum:h}),n.reportError(0,v)}})).exitCode()}};Kh.paths=[[\"plugin\",\"check\"]],Kh.usage=nt.Usage({category:\"Plugin-related commands\",description:\"find all third-party plugins that differ from their own spec\",details:`\n      Check only the plugins from https.\n\n      If this command detects any plugin differences in the CI environment, it will throw an error.\n    `,examples:[[\"find all third-party plugins that differ from their own spec\",\"$0 plugin check\"]]});Ye();Ye();Pt();qt();var ide=ve(\"os\");Ye();Pt();qt();var ede=ve(\"os\");Ye();Nl();qt();var V0t=\"https://raw.githubusercontent.com/yarnpkg/berry/master/plugins.yml\";async function Xd(t,e){let r=await nn.get(V0t,{configuration:t}),o=Ki(r.toString());return Object.fromEntries(Object.entries(o).filter(([a,n])=>!e||kr.satisfiesWithPrereleases(e,n.range??\"<4.0.0-rc.1\")))}var zh=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins);return(await Lt.start({configuration:r,json:this.json,stdout:this.context.stdout},async a=>{let n=await Xd(r,rn);for(let[u,{experimental:A,...p}]of Object.entries(n)){let h=u;A&&(h+=\" [experimental]\"),a.reportJson({name:u,experimental:A,...p}),a.reportInfo(null,h)}})).exitCode()}};zh.paths=[[\"plugin\",\"list\"]],zh.usage=nt.Usage({category:\"Plugin-related commands\",description:\"list the available official plugins\",details:\"\\n      This command prints the plugins available directly from the Yarn repository. Only those plugins can be referenced by name in `yarn plugin import`.\\n    \",examples:[[\"List the official plugins\",\"$0 plugin list\"]]});var J0t=/^[0-9]+$/,X0t=process.platform===\"win32\";function tde(t){return J0t.test(t)?`pull/${t}/head`:t}var Z0t=({repository:t,branch:e},r)=>[[\"git\",\"init\",le.fromPortablePath(r)],[\"git\",\"remote\",\"add\",\"origin\",t],[\"git\",\"fetch\",\"origin\",\"--depth=1\",tde(e)],[\"git\",\"reset\",\"--hard\",\"FETCH_HEAD\"]],$0t=({branch:t})=>[[\"git\",\"fetch\",\"origin\",\"--depth=1\",tde(t),\"--force\"],[\"git\",\"reset\",\"--hard\",\"FETCH_HEAD\"],[\"git\",\"clean\",\"-dfx\",\"-e\",\"packages/yarnpkg-cli/bundles\"]],egt=({plugins:t,noMinify:e},r,o)=>[[\"yarn\",\"build:cli\",...new Array().concat(...t.map(a=>[\"--plugin\",z.resolve(o,a)])),...e?[\"--no-minify\"]:[],\"|\"],[X0t?\"move\":\"mv\",\"packages/yarnpkg-cli/bundles/yarn.js\",le.fromPortablePath(r),\"|\"]],Vh=class extends ut{constructor(){super(...arguments);this.installPath=ge.String(\"--path\",{description:\"The path where the repository should be cloned to\"});this.repository=ge.String(\"--repository\",\"https://github.com/yarnpkg/berry.git\",{description:\"The repository that should be cloned\"});this.branch=ge.String(\"--branch\",\"master\",{description:\"The branch of the repository that should be cloned\"});this.plugins=ge.Array(\"--plugin\",[],{description:\"An array of additional plugins that should be included in the bundle\"});this.dryRun=ge.Boolean(\"-n,--dry-run\",!1,{description:\"If set, the bundle will be built but not added to the project\"});this.noMinify=ge.Boolean(\"--no-minify\",!1,{description:\"Build a bundle for development (debugging) - non-minified and non-mangled\"});this.force=ge.Boolean(\"-f,--force\",!1,{description:\"Always clone the repository instead of trying to fetch the latest commits\"});this.skipPlugins=ge.Boolean(\"--skip-plugins\",!1,{description:\"Skip updating the contrib plugins\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd),a=typeof this.installPath<\"u\"?z.resolve(this.context.cwd,le.toPortablePath(this.installPath)):z.resolve(le.toPortablePath((0,ede.tmpdir)()),\"yarnpkg-sources\",wn.makeHash(this.repository).slice(0,6));return(await Lt.start({configuration:r,stdout:this.context.stdout},async u=>{await M8(this,{configuration:r,report:u,target:a}),u.reportSeparator(),u.reportInfo(0,\"Building a fresh bundle\"),u.reportSeparator();let A=await Ur.execvp(\"git\",[\"rev-parse\",\"--short\",\"HEAD\"],{cwd:a,strict:!0}),p=z.join(a,`packages/yarnpkg-cli/bundles/yarn-${A.stdout.trim()}.js`);oe.existsSync(p)||(await E2(egt(this,p,a),{configuration:r,context:this.context,target:a}),u.reportSeparator());let h=await oe.readFilePromise(p);if(!this.dryRun){let{bundleVersion:E}=await N8(r,null,async()=>h,{report:u});this.skipPlugins||await tgt(this,E,{project:o,report:u,target:a})}})).exitCode()}};Vh.paths=[[\"set\",\"version\",\"from\",\"sources\"]],Vh.usage=nt.Usage({description:\"build Yarn from master\",details:`\n      This command will clone the Yarn repository into a temporary folder, then build it. The resulting bundle will then be copied into the local project.\n\n      By default, it also updates all contrib plugins to the same commit the bundle is built from. This behavior can be disabled by using the \\`--skip-plugins\\` flag.\n    `,examples:[[\"Build Yarn from master\",\"$0 set version from sources\"]]});async function E2(t,{configuration:e,context:r,target:o}){for(let[a,...n]of t){let u=n[n.length-1]===\"|\";if(u&&n.pop(),u)await Ur.pipevp(a,n,{cwd:o,stdin:r.stdin,stdout:r.stdout,stderr:r.stderr,strict:!0});else{r.stdout.write(`${de.pretty(e,`  $ ${[a,...n].join(\" \")}`,\"grey\")}\n`);try{await Ur.execvp(a,n,{cwd:o,strict:!0})}catch(A){throw r.stdout.write(A.stdout||A.stack),A}}}}async function M8(t,{configuration:e,report:r,target:o}){let a=!1;if(!t.force&&oe.existsSync(z.join(o,\".git\"))){r.reportInfo(0,\"Fetching the latest commits\"),r.reportSeparator();try{await E2($0t(t),{configuration:e,context:t.context,target:o}),a=!0}catch{r.reportSeparator(),r.reportWarning(0,\"Repository update failed; we'll try to regenerate it\")}}a||(r.reportInfo(0,\"Cloning the remote repository\"),r.reportSeparator(),await oe.removePromise(o),await oe.mkdirPromise(o,{recursive:!0}),await E2(Z0t(t,o),{configuration:e,context:t.context,target:o}))}async function tgt(t,e,{project:r,report:o,target:a}){let n=await Xd(r.configuration,e),u=new Set(Object.keys(n));for(let A of r.configuration.plugins.keys())!u.has(A)||await U8(A,t,{project:r,report:o,target:a})}Ye();Ye();Pt();qt();var rde=$e(Jn()),nde=ve(\"vm\");var Jh=class extends ut{constructor(){super(...arguments);this.name=ge.String();this.checksum=ge.Boolean(\"--checksum\",!0,{description:\"Whether to care if this plugin is modified\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins);return(await Lt.start({configuration:r,stdout:this.context.stdout},async a=>{let{project:n}=await St.find(r,this.context.cwd),u,A;if(this.name.match(/^\\.{0,2}[\\\\/]/)||le.isAbsolute(this.name)){let p=z.resolve(this.context.cwd,le.toPortablePath(this.name));a.reportInfo(0,`Reading ${de.pretty(r,p,de.Type.PATH)}`),u=z.relative(n.cwd,p),A=await oe.readFilePromise(p)}else{let p;if(this.name.match(/^https?:/)){try{new URL(this.name)}catch{throw new Jt(52,`Plugin specifier \"${this.name}\" is neither a plugin name nor a valid url`)}u=this.name,p=this.name}else{let h=W.parseLocator(this.name.replace(/^((@yarnpkg\\/)?plugin-)?/,\"@yarnpkg/plugin-\"));if(h.reference!==\"unknown\"&&!rde.default.valid(h.reference))throw new Jt(0,\"Official plugins only accept strict version references. Use an explicit URL if you wish to download them from another location.\");let E=W.stringifyIdent(h),I=await Xd(r,rn);if(!Object.hasOwn(I,E)){let v=`Couldn't find a plugin named ${W.prettyIdent(r,h)} on the remote registry.\n`;throw r.plugins.has(E)?v+=`A plugin named ${W.prettyIdent(r,h)} is already installed; possibly attempting to import a built-in plugin.`:v+=`Note that only the plugins referenced on our website (${de.pretty(r,\"https://github.com/yarnpkg/berry/blob/master/plugins.yml\",de.Type.URL)}) can be referenced by their name; any other plugin will have to be referenced through its public url (for example ${de.pretty(r,\"https://github.com/yarnpkg/berry/raw/master/packages/plugin-typescript/bin/%40yarnpkg/plugin-typescript.js\",de.Type.URL)}).`,new Jt(51,v)}u=E,p=I[E].url,h.reference!==\"unknown\"?p=p.replace(/\\/master\\//,`/${E}/${h.reference}/`):rn!==null&&(p=p.replace(/\\/master\\//,`/@yarnpkg/cli/${rn}/`))}a.reportInfo(0,`Downloading ${de.pretty(r,p,\"green\")}`),A=await nn.get(p,{configuration:r})}await _8(u,A,{checksum:this.checksum,project:n,report:a})})).exitCode()}};Jh.paths=[[\"plugin\",\"import\"]],Jh.usage=nt.Usage({category:\"Plugin-related commands\",description:\"download a plugin\",details:`\n      This command downloads the specified plugin from its remote location and updates the configuration to reference it in further CLI invocations.\n\n      Three types of plugin references are accepted:\n\n      - If the plugin is stored within the Yarn repository, it can be referenced by name.\n      - Third-party plugins can be referenced directly through their public urls.\n      - Local plugins can be referenced by their path on the disk.\n\n      If the \\`--no-checksum\\` option is set, Yarn will no longer care if the plugin is modified.\n\n      Plugins cannot be downloaded from the npm registry, and aren't allowed to have dependencies (they need to be bundled into a single file, possibly thanks to the \\`@yarnpkg/builder\\` package).\n    `,examples:[['Download and activate the \"@yarnpkg/plugin-exec\" plugin',\"$0 plugin import @yarnpkg/plugin-exec\"],['Download and activate the \"@yarnpkg/plugin-exec\" plugin (shorthand)',\"$0 plugin import exec\"],[\"Download and activate a community plugin\",\"$0 plugin import https://example.org/path/to/plugin.js\"],[\"Activate a local plugin\",\"$0 plugin import ./path/to/plugin.js\"]]});async function _8(t,e,{checksum:r=!0,project:o,report:a}){let{configuration:n}=o,u={},A={exports:u};(0,nde.runInNewContext)(e.toString(),{module:A,exports:u});let h=`.yarn/plugins/${A.exports.name}.cjs`,E=z.resolve(o.cwd,h);a.reportInfo(0,`Saving the new plugin in ${de.pretty(n,h,\"magenta\")}`),await oe.mkdirPromise(z.dirname(E),{recursive:!0}),await oe.writeFilePromise(E,e);let I={path:h,spec:t};r&&(I.checksum=wn.makeHash(e)),await Ke.addPlugin(o.cwd,[I])}var rgt=({pluginName:t,noMinify:e},r)=>[[\"yarn\",`build:${t}`,...e?[\"--no-minify\"]:[],\"|\"]],Xh=class extends ut{constructor(){super(...arguments);this.installPath=ge.String(\"--path\",{description:\"The path where the repository should be cloned to\"});this.repository=ge.String(\"--repository\",\"https://github.com/yarnpkg/berry.git\",{description:\"The repository that should be cloned\"});this.branch=ge.String(\"--branch\",\"master\",{description:\"The branch of the repository that should be cloned\"});this.noMinify=ge.Boolean(\"--no-minify\",!1,{description:\"Build a plugin for development (debugging) - non-minified and non-mangled\"});this.force=ge.Boolean(\"-f,--force\",!1,{description:\"Always clone the repository instead of trying to fetch the latest commits\"});this.name=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),o=typeof this.installPath<\"u\"?z.resolve(this.context.cwd,le.toPortablePath(this.installPath)):z.resolve(le.toPortablePath((0,ide.tmpdir)()),\"yarnpkg-sources\",wn.makeHash(this.repository).slice(0,6));return(await Lt.start({configuration:r,stdout:this.context.stdout},async n=>{let{project:u}=await St.find(r,this.context.cwd),A=W.parseIdent(this.name.replace(/^((@yarnpkg\\/)?plugin-)?/,\"@yarnpkg/plugin-\")),p=W.stringifyIdent(A),h=await Xd(r,rn);if(!Object.hasOwn(h,p))throw new Jt(51,`Couldn't find a plugin named \"${p}\" on the remote registry. Note that only the plugins referenced on our website (https://github.com/yarnpkg/berry/blob/master/plugins.yml) can be built and imported from sources.`);let E=p;await M8(this,{configuration:r,report:n,target:o}),await U8(E,this,{project:u,report:n,target:o})})).exitCode()}};Xh.paths=[[\"plugin\",\"import\",\"from\",\"sources\"]],Xh.usage=nt.Usage({category:\"Plugin-related commands\",description:\"build a plugin from sources\",details:`\n      This command clones the Yarn repository into a temporary folder, builds the specified contrib plugin and updates the configuration to reference it in further CLI invocations.\n\n      The plugins can be referenced by their short name if sourced from the official Yarn repository.\n    `,examples:[['Build and activate the \"@yarnpkg/plugin-exec\" plugin',\"$0 plugin import from sources @yarnpkg/plugin-exec\"],['Build and activate the \"@yarnpkg/plugin-exec\" plugin (shorthand)',\"$0 plugin import from sources exec\"]]});async function U8(t,{context:e,noMinify:r},{project:o,report:a,target:n}){let u=t.replace(/@yarnpkg\\//,\"\"),{configuration:A}=o;a.reportSeparator(),a.reportInfo(0,`Building a fresh ${u}`),a.reportSeparator(),await E2(rgt({pluginName:u,noMinify:r},n),{configuration:A,context:e,target:n}),a.reportSeparator();let p=z.resolve(n,`packages/${u}/bundles/${t}.js`),h=await oe.readFilePromise(p);await _8(t,h,{project:o,report:a})}Ye();Pt();qt();var Zh=class extends ut{constructor(){super(...arguments);this.name=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd);return(await Lt.start({configuration:r,stdout:this.context.stdout},async n=>{let u=this.name,A=W.parseIdent(u);if(!r.plugins.has(u))throw new it(`${W.prettyIdent(r,A)} isn't referenced by the current configuration`);let p=`.yarn/plugins/${u}.cjs`,h=z.resolve(o.cwd,p);oe.existsSync(h)&&(n.reportInfo(0,`Removing ${de.pretty(r,p,de.Type.PATH)}...`),await oe.removePromise(h)),n.reportInfo(0,\"Updating the configuration...\"),await Ke.updateConfiguration(o.cwd,{plugins:E=>{if(!Array.isArray(E))return E;let I=E.filter(v=>v.path!==p);return I.length===0?Ke.deleteProperty:I.length===E.length?E:I}})})).exitCode()}};Zh.paths=[[\"plugin\",\"remove\"]],Zh.usage=nt.Usage({category:\"Plugin-related commands\",description:\"remove a plugin\",details:`\n      This command deletes the specified plugin from the .yarn/plugins folder and removes it from the configuration.\n\n      **Note:** The plugins have to be referenced by their name property, which can be obtained using the \\`yarn plugin runtime\\` command. Shorthands are not allowed.\n   `,examples:[[\"Remove a plugin imported from the Yarn repository\",\"$0 plugin remove @yarnpkg/plugin-typescript\"],[\"Remove a plugin imported from a local file\",\"$0 plugin remove my-local-plugin\"]]});Ye();qt();var $h=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins);return(await Lt.start({configuration:r,json:this.json,stdout:this.context.stdout},async a=>{for(let n of r.plugins.keys()){let u=this.context.plugins.plugins.has(n),A=n;u&&(A+=\" [builtin]\"),a.reportJson({name:n,builtin:u}),a.reportInfo(null,`${A}`)}})).exitCode()}};$h.paths=[[\"plugin\",\"runtime\"]],$h.usage=nt.Usage({category:\"Plugin-related commands\",description:\"list the active plugins\",details:`\n      This command prints the currently active plugins. Will be displayed both builtin plugins and external plugins.\n    `,examples:[[\"List the currently active plugins\",\"$0 plugin runtime\"]]});Ye();Ye();qt();var e0=class extends ut{constructor(){super(...arguments);this.idents=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Nr.find(r);if(!a)throw new nr(o.cwd,this.context.cwd);let u=new Set;for(let A of this.idents)u.add(W.parseIdent(A).identHash);if(await o.restoreInstallState({restoreResolutions:!1}),await o.resolveEverything({cache:n,report:new Qi}),u.size>0)for(let A of o.storedPackages.values())u.has(A.identHash)&&(o.storedBuildState.delete(A.locatorHash),o.skippedBuilds.delete(A.locatorHash));else o.storedBuildState.clear(),o.skippedBuilds.clear();return await o.installWithNewReport({stdout:this.context.stdout,quiet:this.context.quiet},{cache:n})}};e0.paths=[[\"rebuild\"]],e0.usage=nt.Usage({description:\"rebuild the project's native packages\",details:`\n      This command will automatically cause Yarn to forget about previous compilations of the given packages and to run them again.\n\n      Note that while Yarn forgets the compilation, the previous artifacts aren't erased from the filesystem and may affect the next builds (in good or bad). To avoid this, you may remove the .yarn/unplugged folder, or any other relevant location where packages might have been stored (Yarn may offer a way to do that automatically in the future).\n\n      By default all packages will be rebuilt, but you can filter the list by specifying the names of the packages you want to clear from memory.\n    `,examples:[[\"Rebuild all packages\",\"$0 rebuild\"],[\"Rebuild fsevents only\",\"$0 rebuild fsevents\"]]});Ye();Ye();Ye();qt();var H8=$e(Zo());$a();var t0=class extends ut{constructor(){super(...arguments);this.all=ge.Boolean(\"-A,--all\",!1,{description:\"Apply the operation to all workspaces from the current project\"});this.mode=ge.String(\"--mode\",{description:\"Change what artifacts installs generate\",validator:Ks(hl)});this.patterns=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Nr.find(r);if(!a)throw new nr(o.cwd,this.context.cwd);await o.restoreInstallState({restoreResolutions:!1});let u=this.all?o.workspaces:[a],A=[\"dependencies\",\"devDependencies\",\"peerDependencies\"],p=[],h=!1,E=[];for(let C of this.patterns){let R=!1,N=W.parseIdent(C);for(let U of u){let V=[...U.manifest.peerDependenciesMeta.keys()];for(let te of(0,H8.default)(V,C))U.manifest.peerDependenciesMeta.delete(te),h=!0,R=!0;for(let te of A){let ae=U.manifest.getForScope(te),fe=[...ae.values()].map(ue=>W.stringifyIdent(ue));for(let ue of(0,H8.default)(fe,W.stringifyIdent(N))){let{identHash:me}=W.parseIdent(ue),he=ae.get(me);if(typeof he>\"u\")throw new Error(\"Assertion failed: Expected the descriptor to be registered\");U.manifest[te].delete(me),E.push([U,te,he]),h=!0,R=!0}}}R||p.push(C)}let I=p.length>1?\"Patterns\":\"Pattern\",v=p.length>1?\"don't\":\"doesn't\",x=this.all?\"any\":\"this\";if(p.length>0)throw new it(`${I} ${de.prettyList(r,p,de.Type.CODE)} ${v} match any packages referenced by ${x} workspace`);return h?(await r.triggerMultipleHooks(C=>C.afterWorkspaceDependencyRemoval,E),await o.installWithNewReport({stdout:this.context.stdout},{cache:n,mode:this.mode})):0}};t0.paths=[[\"remove\"]],t0.usage=nt.Usage({description:\"remove dependencies from the project\",details:`\n      This command will remove the packages matching the specified patterns from the current workspace.\n\n      If the \\`--mode=<mode>\\` option is set, Yarn will change which artifacts are generated. The modes currently supported are:\n\n      - \\`skip-build\\` will not run the build scripts at all. Note that this is different from setting \\`enableScripts\\` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.\n\n      - \\`update-lockfile\\` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.\n\n      This command accepts glob patterns as arguments (if valid Idents and supported by [micromatch](https://github.com/micromatch/micromatch)). Make sure to escape the patterns, to prevent your own shell from trying to expand them.\n    `,examples:[[\"Remove a dependency from the current project\",\"$0 remove lodash\"],[\"Remove a dependency from all workspaces at once\",\"$0 remove lodash --all\"],[\"Remove all dependencies starting with `eslint-`\",\"$0 remove 'eslint-*'\"],[\"Remove all dependencies with the `@babel` scope\",\"$0 remove '@babel/*'\"],[\"Remove all dependencies matching `react-dom` or `react-helmet`\",\"$0 remove 'react-{dom,helmet}'\"]]});Ye();Ye();qt();var sde=ve(\"util\"),Zd=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new nr(o.cwd,this.context.cwd);return(await Lt.start({configuration:r,stdout:this.context.stdout,json:this.json},async u=>{let A=a.manifest.scripts,p=_e.sortMap(A.keys(),I=>I),h={breakLength:1/0,colors:r.get(\"enableColors\"),maxArrayLength:2},E=p.reduce((I,v)=>Math.max(I,v.length),0);for(let[I,v]of A.entries())u.reportInfo(null,`${I.padEnd(E,\" \")}   ${(0,sde.inspect)(v,h)}`),u.reportJson({name:I,script:v})})).exitCode()}};Zd.paths=[[\"run\"]];Ye();Ye();qt();var r0=class extends ut{constructor(){super(...arguments);this.inspect=ge.String(\"--inspect\",!1,{tolerateBoolean:!0,description:\"Forwarded to the underlying Node process when executing a binary\"});this.inspectBrk=ge.String(\"--inspect-brk\",!1,{tolerateBoolean:!0,description:\"Forwarded to the underlying Node process when executing a binary\"});this.topLevel=ge.Boolean(\"-T,--top-level\",!1,{description:\"Check the root workspace for scripts and/or binaries instead of the current one\"});this.binariesOnly=ge.Boolean(\"-B,--binaries-only\",!1,{description:\"Ignore any user defined scripts and only check for binaries\"});this.require=ge.String(\"--require\",{description:\"Forwarded to the underlying Node process when executing a binary\"});this.silent=ge.Boolean(\"--silent\",{hidden:!0});this.scriptName=ge.String();this.args=ge.Proxy()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a,locator:n}=await St.find(r,this.context.cwd);await o.restoreInstallState();let u=this.topLevel?o.topLevelWorkspace.anchoredLocator:n;if(!this.binariesOnly&&await un.hasPackageScript(u,this.scriptName,{project:o}))return await un.executePackageScript(u,this.scriptName,this.args,{project:o,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr});let A=await un.getPackageAccessibleBinaries(u,{project:o});if(A.get(this.scriptName)){let h=[];return this.inspect&&(typeof this.inspect==\"string\"?h.push(`--inspect=${this.inspect}`):h.push(\"--inspect\")),this.inspectBrk&&(typeof this.inspectBrk==\"string\"?h.push(`--inspect-brk=${this.inspectBrk}`):h.push(\"--inspect-brk\")),this.require&&h.push(`--require=${this.require}`),await un.executePackageAccessibleBinary(u,this.scriptName,this.args,{cwd:this.context.cwd,project:o,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr,nodeArgs:h,packageAccessibleBinaries:A})}if(!this.topLevel&&!this.binariesOnly&&a&&this.scriptName.includes(\":\")){let E=(await Promise.all(o.workspaces.map(async I=>I.manifest.scripts.has(this.scriptName)?I:null))).filter(I=>I!==null);if(E.length===1)return await un.executeWorkspaceScript(E[0],this.scriptName,this.args,{stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr})}if(this.topLevel)throw this.scriptName===\"node-gyp\"?new it(`Couldn't find a script name \"${this.scriptName}\" in the top-level (used by ${W.prettyLocator(r,n)}). This typically happens because some package depends on \"node-gyp\" to build itself, but didn't list it in their dependencies. To fix that, please run \"yarn add node-gyp\" into your top-level workspace. You also can open an issue on the repository of the specified package to suggest them to use an optional peer dependency.`):new it(`Couldn't find a script name \"${this.scriptName}\" in the top-level (used by ${W.prettyLocator(r,n)}).`);{if(this.scriptName===\"global\")throw new it(\"The 'yarn global' commands have been removed in 2.x - consider using 'yarn dlx' or a third-party plugin instead\");let h=[this.scriptName].concat(this.args);for(let[E,I]of AC)for(let v of I)if(h.length>=v.length&&JSON.stringify(h.slice(0,v.length))===JSON.stringify(v))throw new it(`Couldn't find a script named \"${this.scriptName}\", but a matching command can be found in the ${E} plugin. You can install it with \"yarn plugin import ${E}\".`);throw new it(`Couldn't find a script named \"${this.scriptName}\".`)}}};r0.paths=[[\"run\"]],r0.usage=nt.Usage({description:\"run a script defined in the package.json\",details:`\n      This command will run a tool. The exact tool that will be executed will depend on the current state of your workspace:\n\n      - If the \\`scripts\\` field from your local package.json contains a matching script name, its definition will get executed.\n\n      - Otherwise, if one of the local workspace's dependencies exposes a binary with a matching name, this binary will get executed.\n\n      - Otherwise, if the specified name contains a colon character and if one of the workspaces in the project contains exactly one script with a matching name, then this script will get executed.\n\n      Whatever happens, the cwd of the spawned process will be the workspace that declares the script (which makes it possible to call commands cross-workspaces using the third syntax).\n    `,examples:[[\"Run the tests from the local workspace\",\"$0 run test\"],['Same thing, but without the \"run\" keyword',\"$0 test\"],[\"Inspect Webpack while running\",\"$0 run --inspect-brk webpack\"]]});Ye();Ye();qt();var n0=class extends ut{constructor(){super(...arguments);this.descriptor=ge.String();this.resolution=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Nr.find(r);if(await o.restoreInstallState({restoreResolutions:!1}),!a)throw new nr(o.cwd,this.context.cwd);let u=W.parseDescriptor(this.descriptor,!0),A=W.makeDescriptor(u,this.resolution);return o.storedDescriptors.set(u.descriptorHash,u),o.storedDescriptors.set(A.descriptorHash,A),o.resolutionAliases.set(u.descriptorHash,A.descriptorHash),await o.installWithNewReport({stdout:this.context.stdout},{cache:n})}};n0.paths=[[\"set\",\"resolution\"]],n0.usage=nt.Usage({description:\"enforce a package resolution\",details:'\\n      This command updates the resolution table so that `descriptor` is resolved by `resolution`.\\n\\n      Note that by default this command only affect the current resolution table - meaning that this \"manual override\" will disappear if you remove the lockfile, or if the package disappear from the table. If you wish to make the enforced resolution persist whatever happens, edit the `resolutions` field in your top-level manifest.\\n\\n      Note that no attempt is made at validating that `resolution` is a valid resolution entry for `descriptor`.\\n    ',examples:[[\"Force all instances of lodash@npm:^1.2.3 to resolve to 1.5.0\",\"$0 set resolution lodash@npm:^1.2.3 1.5.0\"]]});Ye();Pt();qt();var ode=$e(Zo()),i0=class extends ut{constructor(){super(...arguments);this.all=ge.Boolean(\"-A,--all\",!1,{description:\"Unlink all workspaces belonging to the target project from the current one\"});this.leadingArguments=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Nr.find(r);if(!a)throw new nr(o.cwd,this.context.cwd);let u=o.topLevelWorkspace,A=new Set;if(this.leadingArguments.length===0&&this.all)for(let{pattern:p,reference:h}of u.manifest.resolutions)h.startsWith(\"portal:\")&&A.add(p.descriptor.fullName);if(this.leadingArguments.length>0)for(let p of this.leadingArguments){let h=z.resolve(this.context.cwd,le.toPortablePath(p));if(_e.isPathLike(p)){let E=await Ke.find(h,this.context.plugins,{useRc:!1,strict:!1}),{project:I,workspace:v}=await St.find(E,h);if(!v)throw new nr(I.cwd,h);if(this.all){for(let x of I.workspaces)x.manifest.name&&A.add(W.stringifyIdent(x.anchoredLocator));if(A.size===0)throw new it(\"No workspace found to be unlinked in the target project\")}else{if(!v.manifest.name)throw new it(\"The target workspace doesn't have a name and thus cannot be unlinked\");A.add(W.stringifyIdent(v.anchoredLocator))}}else{let E=[...u.manifest.resolutions.map(({pattern:I})=>I.descriptor.fullName)];for(let I of(0,ode.default)(E,p))A.add(I)}}return u.manifest.resolutions=u.manifest.resolutions.filter(({pattern:p})=>!A.has(p.descriptor.fullName)),await o.installWithNewReport({stdout:this.context.stdout,quiet:this.context.quiet},{cache:n})}};i0.paths=[[\"unlink\"]],i0.usage=nt.Usage({description:\"disconnect the local project from another one\",details:`\n      This command will remove any resolutions in the project-level manifest that would have been added via a yarn link with similar arguments.\n    `,examples:[[\"Unregister a remote workspace in the current project\",\"$0 unlink ~/ts-loader\"],[\"Unregister all workspaces from a remote project in the current project\",\"$0 unlink ~/jest --all\"],[\"Unregister all previously linked workspaces\",\"$0 unlink --all\"],[\"Unregister all workspaces matching a glob\",\"$0 unlink '@babel/*' 'pkg-{a,b}'\"]]});Ye();Ye();Ye();qt();var ade=$e(f2()),q8=$e(Zo());$a();var Vf=class extends ut{constructor(){super(...arguments);this.interactive=ge.Boolean(\"-i,--interactive\",{description:\"Offer various choices, depending on the detected upgrade paths\"});this.fixed=ge.Boolean(\"-F,--fixed\",!1,{description:\"Store dependency tags as-is instead of resolving them\"});this.exact=ge.Boolean(\"-E,--exact\",!1,{description:\"Don't use any semver modifier on the resolved range\"});this.tilde=ge.Boolean(\"-T,--tilde\",!1,{description:\"Use the `~` semver modifier on the resolved range\"});this.caret=ge.Boolean(\"-C,--caret\",!1,{description:\"Use the `^` semver modifier on the resolved range\"});this.recursive=ge.Boolean(\"-R,--recursive\",!1,{description:\"Resolve again ALL resolutions for those packages\"});this.mode=ge.String(\"--mode\",{description:\"Change what artifacts installs generate\",validator:Ks(hl)});this.patterns=ge.Rest()}async execute(){return this.recursive?await this.executeUpRecursive():await this.executeUpClassic()}async executeUpRecursive(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Nr.find(r);if(!a)throw new nr(o.cwd,this.context.cwd);await o.restoreInstallState({restoreResolutions:!1});let u=[...o.storedDescriptors.values()],A=u.map(E=>W.stringifyIdent(E)),p=new Set;for(let E of this.patterns){if(W.parseDescriptor(E).range!==\"unknown\")throw new it(\"Ranges aren't allowed when using --recursive\");for(let I of(0,q8.default)(A,E)){let v=W.parseIdent(I);p.add(v.identHash)}}let h=u.filter(E=>p.has(E.identHash));for(let E of h)o.storedDescriptors.delete(E.descriptorHash),o.storedResolutions.delete(E.descriptorHash);return await o.installWithNewReport({stdout:this.context.stdout},{cache:n,mode:this.mode})}async executeUpClassic(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Nr.find(r);if(!a)throw new nr(o.cwd,this.context.cwd);await o.restoreInstallState({restoreResolutions:!1});let u=this.fixed,A=this.interactive??r.get(\"preferInteractive\"),p=h2(this,o),h=A?[\"keep\",\"reuse\",\"project\",\"latest\"]:[\"project\",\"latest\"],E=[],I=[];for(let N of this.patterns){let U=!1,V=W.parseDescriptor(N),te=W.stringifyIdent(V);for(let ae of o.workspaces)for(let fe of[\"dependencies\",\"devDependencies\"]){let me=[...ae.manifest.getForScope(fe).values()].map(Be=>W.stringifyIdent(Be)),he=te===\"*\"?me:(0,q8.default)(me,te);for(let Be of he){let we=W.parseIdent(Be),g=ae.manifest[fe].get(we.identHash);if(typeof g>\"u\")throw new Error(\"Assertion failed: Expected the descriptor to be registered\");let Ee=W.makeDescriptor(we,V.range);E.push(Promise.resolve().then(async()=>[ae,fe,g,await g2(Ee,{project:o,workspace:ae,cache:n,target:fe,fixed:u,modifier:p,strategies:h})])),U=!0}}U||I.push(N)}if(I.length>1)throw new it(`Patterns ${de.prettyList(r,I,de.Type.CODE)} don't match any packages referenced by any workspace`);if(I.length>0)throw new it(`Pattern ${de.prettyList(r,I,de.Type.CODE)} doesn't match any packages referenced by any workspace`);let v=await Promise.all(E),x=await fA.start({configuration:r,stdout:this.context.stdout,suggestInstall:!1},async N=>{for(let[,,U,{suggestions:V,rejections:te}]of v){let ae=V.filter(fe=>fe.descriptor!==null);if(ae.length===0){let[fe]=te;if(typeof fe>\"u\")throw new Error(\"Assertion failed: Expected an error to have been set\");let ue=this.cli.error(fe);o.configuration.get(\"enableNetwork\")?N.reportError(27,`${W.prettyDescriptor(r,U)} can't be resolved to a satisfying range\n\n${ue}`):N.reportError(27,`${W.prettyDescriptor(r,U)} can't be resolved to a satisfying range (note: network resolution has been disabled)\n\n${ue}`)}else ae.length>1&&!A&&N.reportError(27,`${W.prettyDescriptor(r,U)} has multiple possible upgrade strategies; use -i to disambiguate manually`)}});if(x.hasErrors())return x.exitCode();let C=!1,R=[];for(let[N,U,,{suggestions:V}]of v){let te,ae=V.filter(he=>he.descriptor!==null),fe=ae[0].descriptor,ue=ae.every(he=>W.areDescriptorsEqual(he.descriptor,fe));ae.length===1||ue?te=fe:(C=!0,{answer:te}=await(0,ade.prompt)({type:\"select\",name:\"answer\",message:`Which range do you want to use in ${W.prettyWorkspace(r,N)} \\u276F ${U}?`,choices:V.map(({descriptor:he,name:Be,reason:we})=>he?{name:Be,hint:we,descriptor:he}:{name:Be,hint:we,disabled:!0}),onCancel:()=>process.exit(130),result(he){return this.find(he,\"descriptor\")},stdin:this.context.stdin,stdout:this.context.stdout}));let me=N.manifest[U].get(te.identHash);if(typeof me>\"u\")throw new Error(\"Assertion failed: This descriptor should have a matching entry\");if(me.descriptorHash!==te.descriptorHash)N.manifest[U].set(te.identHash,te),R.push([N,U,me,te]);else{let he=r.makeResolver(),Be={project:o,resolver:he},we=r.normalizeDependency(me),g=he.bindDescriptor(we,N.anchoredLocator,Be);o.forgetResolution(g)}}return await r.triggerMultipleHooks(N=>N.afterWorkspaceDependencyReplacement,R),C&&this.context.stdout.write(`\n`),await o.installWithNewReport({stdout:this.context.stdout},{cache:n,mode:this.mode})}};Vf.paths=[[\"up\"]],Vf.usage=nt.Usage({description:\"upgrade dependencies across the project\",details:\"\\n      This command upgrades the packages matching the list of specified patterns to their latest available version across the whole project (regardless of whether they're part of `dependencies` or `devDependencies` - `peerDependencies` won't be affected). This is a project-wide command: all workspaces will be upgraded in the process.\\n\\n      If `-R,--recursive` is set the command will change behavior and no other switch will be allowed. When operating under this mode `yarn up` will force all ranges matching the selected packages to be resolved again (often to the highest available versions) before being stored in the lockfile. It however won't touch your manifests anymore, so depending on your needs you might want to run both `yarn up` and `yarn up -R` to cover all bases.\\n\\n      If `-i,--interactive` is set (or if the `preferInteractive` settings is toggled on) the command will offer various choices, depending on the detected upgrade paths. Some upgrades require this flag in order to resolve ambiguities.\\n\\n      The, `-C,--caret`, `-E,--exact` and  `-T,--tilde` options have the same meaning as in the `add` command (they change the modifier used when the range is missing or a tag, and are ignored when the range is explicitly set).\\n\\n      If the `--mode=<mode>` option is set, Yarn will change which artifacts are generated. The modes currently supported are:\\n\\n      - `skip-build` will not run the build scripts at all. Note that this is different from setting `enableScripts` to false because the latter will disable build scripts, and thus affect the content of the artifacts generated on disk, whereas the former will just disable the build step - but not the scripts themselves, which just won't run.\\n\\n      - `update-lockfile` will skip the link step altogether, and only fetch packages that are missing from the lockfile (or that have no associated checksums). This mode is typically used by tools like Renovate or Dependabot to keep a lockfile up-to-date without incurring the full install cost.\\n\\n      Generally you can see `yarn up` as a counterpart to what was `yarn upgrade --latest` in Yarn 1 (ie it ignores the ranges previously listed in your manifests), but unlike `yarn upgrade` which only upgraded dependencies in the current workspace, `yarn up` will upgrade all workspaces at the same time.\\n\\n      This command accepts glob patterns as arguments (if valid Descriptors and supported by [micromatch](https://github.com/micromatch/micromatch)). Make sure to escape the patterns, to prevent your own shell from trying to expand them.\\n\\n      **Note:** The ranges have to be static, only the package scopes and names can contain glob patterns.\\n    \",examples:[[\"Upgrade all instances of lodash to the latest release\",\"$0 up lodash\"],[\"Upgrade all instances of lodash to the latest release, but ask confirmation for each\",\"$0 up lodash -i\"],[\"Upgrade all instances of lodash to 1.2.3\",\"$0 up lodash@1.2.3\"],[\"Upgrade all instances of packages with the `@babel` scope to the latest release\",\"$0 up '@babel/*'\"],[\"Upgrade all instances of packages containing the word `jest` to the latest release\",\"$0 up '*jest*'\"],[\"Upgrade all instances of packages with the `@babel` scope to 7.0.0\",\"$0 up '@babel/*@7.0.0'\"]]}),Vf.schema=[cI(\"recursive\",Yu.Forbids,[\"interactive\",\"exact\",\"tilde\",\"caret\"],{ignore:[void 0,!1]})];Ye();Ye();Ye();qt();var s0=class extends ut{constructor(){super(...arguments);this.recursive=ge.Boolean(\"-R,--recursive\",!1,{description:\"List, for each workspace, what are all the paths that lead to the dependency\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.peers=ge.Boolean(\"--peers\",!1,{description:\"Also print the peer dependencies that match the specified name\"});this.package=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new nr(o.cwd,this.context.cwd);await o.restoreInstallState();let n=W.parseIdent(this.package).identHash,u=this.recursive?igt(o,n,{configuration:r,peers:this.peers}):ngt(o,n,{configuration:r,peers:this.peers});$s.emitTree(u,{configuration:r,stdout:this.context.stdout,json:this.json,separators:1})}};s0.paths=[[\"why\"]],s0.usage=nt.Usage({description:\"display the reason why a package is needed\",details:`\n      This command prints the exact reasons why a package appears in the dependency tree.\n\n      If \\`-R,--recursive\\` is set, the listing will go in depth and will list, for each workspaces, what are all the paths that lead to the dependency. Note that the display is somewhat optimized in that it will not print the package listing twice for a single package, so if you see a leaf named \"Foo\" when looking for \"Bar\", it means that \"Foo\" already got printed higher in the tree.\n    `,examples:[[\"Explain why lodash is used in your project\",\"$0 why lodash\"]]});function ngt(t,e,{configuration:r,peers:o}){let a=_e.sortMap(t.storedPackages.values(),A=>W.stringifyLocator(A)),n={},u={children:n};for(let A of a){let p={};for(let E of A.dependencies.values()){if(!o&&A.peerDependencies.has(E.identHash))continue;let I=t.storedResolutions.get(E.descriptorHash);if(!I)throw new Error(\"Assertion failed: The resolution should have been registered\");let v=t.storedPackages.get(I);if(!v)throw new Error(\"Assertion failed: The package should have been registered\");if(v.identHash!==e)continue;{let C=W.stringifyLocator(A);n[C]={value:[A,de.Type.LOCATOR],children:p}}let x=W.stringifyLocator(v);p[x]={value:[{descriptor:E,locator:v},de.Type.DEPENDENT]}}}return u}function igt(t,e,{configuration:r,peers:o}){let a=_e.sortMap(t.workspaces,v=>W.stringifyLocator(v.anchoredLocator)),n=new Set,u=new Set,A=v=>{if(n.has(v.locatorHash))return u.has(v.locatorHash);if(n.add(v.locatorHash),v.identHash===e)return u.add(v.locatorHash),!0;let x=!1;v.identHash===e&&(x=!0);for(let C of v.dependencies.values()){if(!o&&v.peerDependencies.has(C.identHash))continue;let R=t.storedResolutions.get(C.descriptorHash);if(!R)throw new Error(\"Assertion failed: The resolution should have been registered\");let N=t.storedPackages.get(R);if(!N)throw new Error(\"Assertion failed: The package should have been registered\");A(N)&&(x=!0)}return x&&u.add(v.locatorHash),x};for(let v of a)A(v.anchoredPackage);let p=new Set,h={},E={children:h},I=(v,x,C)=>{if(!u.has(v.locatorHash))return;let R=C!==null?de.tuple(de.Type.DEPENDENT,{locator:v,descriptor:C}):de.tuple(de.Type.LOCATOR,v),N={},U={value:R,children:N},V=W.stringifyLocator(v);if(x[V]=U,!(C!==null&&t.tryWorkspaceByLocator(v))&&!p.has(v.locatorHash)){p.add(v.locatorHash);for(let te of v.dependencies.values()){if(!o&&v.peerDependencies.has(te.identHash))continue;let ae=t.storedResolutions.get(te.descriptorHash);if(!ae)throw new Error(\"Assertion failed: The resolution should have been registered\");let fe=t.storedPackages.get(ae);if(!fe)throw new Error(\"Assertion failed: The package should have been registered\");I(fe,N,te)}}};for(let v of a)I(v.anchoredPackage,h,null);return E}Ye();var Z8={};zt(Z8,{GitFetcher:()=>w2,GitResolver:()=>I2,default:()=>Dgt,gitUtils:()=>ra});Ye();Pt();var ra={};zt(ra,{TreeishProtocols:()=>C2,clone:()=>X8,fetchBase:()=>xde,fetchChangedFiles:()=>kde,fetchChangedWorkspaces:()=>Bgt,fetchRoot:()=>bde,isGitUrl:()=>CC,lsRemote:()=>Sde,normalizeLocator:()=>Igt,normalizeRepoUrl:()=>yC,resolveUrl:()=>J8,splitRepoUrl:()=>o0,validateRepoUrl:()=>V8});Ye();Pt();qt();var vde=$e(wde()),Dde=$e(mU()),EC=$e(ve(\"querystring\")),K8=$e(Jn());function W8(t,e,r){let o=t.indexOf(r);return t.lastIndexOf(e,o>-1?o:1/0)}function Ide(t){try{return new URL(t)}catch{return}}function Cgt(t){let e=W8(t,\"@\",\"#\"),r=W8(t,\":\",\"#\");return r>e&&(t=`${t.slice(0,r)}/${t.slice(r+1)}`),W8(t,\":\",\"#\")===-1&&t.indexOf(\"//\")===-1&&(t=`ssh://${t}`),t}function Bde(t){return Ide(t)||Ide(Cgt(t))}function yC(t,{git:e=!1}={}){if(t=t.replace(/^git\\+https:/,\"https:\"),t=t.replace(/^(?:github:|https:\\/\\/github\\.com\\/|git:\\/\\/github\\.com\\/)?(?!\\.{1,2}\\/)([a-zA-Z0-9._-]+)\\/(?!\\.{1,2}(?:#|$))([a-zA-Z0-9._-]+?)(?:\\.git)?(#.*)?$/,\"https://github.com/$1/$2.git$3\"),t=t.replace(/^https:\\/\\/github\\.com\\/(?!\\.{1,2}\\/)([a-zA-Z0-9._-]+)\\/(?!\\.{1,2}(?:#|$))([a-zA-Z0-9._-]+?)\\/tarball\\/(.+)?$/,\"https://github.com/$1/$2.git#$3\"),e){let r=Bde(t);r&&(t=r.href),t=t.replace(/^git\\+([^:]+):/,\"$1:\")}return t}function Pde(){return{...process.env,GIT_SSH_COMMAND:process.env.GIT_SSH_COMMAND||`${process.env.GIT_SSH||\"ssh\"} -o BatchMode=yes`}}var wgt=[/^ssh:/,/^git(?:\\+[^:]+)?:/,/^(?:git\\+)?https?:[^#]+\\/[^#]+(?:\\.git)(?:#.*)?$/,/^git@[^#]+\\/[^#]+\\.git(?:#.*)?$/,/^(?:github:|https:\\/\\/github\\.com\\/)?(?!\\.{1,2}\\/)([a-zA-Z._0-9-]+)\\/(?!\\.{1,2}(?:#|$))([a-zA-Z._0-9-]+?)(?:\\.git)?(?:#.*)?$/,/^https:\\/\\/github\\.com\\/(?!\\.{1,2}\\/)([a-zA-Z0-9._-]+)\\/(?!\\.{1,2}(?:#|$))([a-zA-Z0-9._-]+?)\\/tarball\\/(.+)?$/],C2=(a=>(a.Commit=\"commit\",a.Head=\"head\",a.Tag=\"tag\",a.Semver=\"semver\",a))(C2||{});function CC(t){return t?wgt.some(e=>!!t.match(e)):!1}function o0(t){t=yC(t);let e=t.indexOf(\"#\");if(e===-1)return{repo:t,treeish:{protocol:\"head\",request:\"HEAD\"},extra:{}};let r=t.slice(0,e),o=t.slice(e+1);if(o.match(/^[a-z]+=/)){let a=EC.default.parse(o);for(let[p,h]of Object.entries(a))if(typeof h!=\"string\")throw new Error(`Assertion failed: The ${p} parameter must be a literal string`);let n=Object.values(C2).find(p=>Object.hasOwn(a,p)),[u,A]=typeof n<\"u\"?[n,a[n]]:[\"head\",\"HEAD\"];for(let p of Object.values(C2))delete a[p];return{repo:r,treeish:{protocol:u,request:A},extra:a}}else{let a=o.indexOf(\":\"),[n,u]=a===-1?[null,o]:[o.slice(0,a),o.slice(a+1)];return{repo:r,treeish:{protocol:n,request:u},extra:{}}}}function Igt(t){return W.makeLocator(t,yC(t.reference))}function V8(t,{configuration:e}){let r=yC(t,{git:!0});if(!nn.getNetworkSettings(`https://${(0,vde.default)(r).resource}`,{configuration:e}).enableNetwork)throw new Jt(80,`Request to '${r}' has been blocked because of your configuration settings`);return r}async function Sde(t,e){let r=V8(t,{configuration:e}),o=await z8(\"listing refs\",[\"ls-remote\",r],{cwd:e.startingCwd,env:Pde()},{configuration:e,normalizedRepoUrl:r}),a=new Map,n=/^([a-f0-9]{40})\\t([^\\n]+)/gm,u;for(;(u=n.exec(o.stdout))!==null;)a.set(u[2],u[1]);return a}async function J8(t,e){let{repo:r,treeish:{protocol:o,request:a},extra:n}=o0(t),u=await Sde(r,e),A=(h,E)=>{switch(h){case\"commit\":{if(!E.match(/^[a-f0-9]{40}$/))throw new Error(\"Invalid commit hash\");return EC.default.stringify({...n,commit:E})}case\"head\":{let I=u.get(E===\"HEAD\"?E:`refs/heads/${E}`);if(typeof I>\"u\")throw new Error(`Unknown head (\"${E}\")`);return EC.default.stringify({...n,commit:I})}case\"tag\":{let I=u.get(`refs/tags/${E}`);if(typeof I>\"u\")throw new Error(`Unknown tag (\"${E}\")`);return EC.default.stringify({...n,commit:I})}case\"semver\":{let I=kr.validRange(E);if(!I)throw new Error(`Invalid range (\"${E}\")`);let v=new Map([...u.entries()].filter(([C])=>C.startsWith(\"refs/tags/\")).map(([C,R])=>[K8.default.parse(C.slice(10)),R]).filter(C=>C[0]!==null)),x=K8.default.maxSatisfying([...v.keys()],I);if(x===null)throw new Error(`No matching range (\"${E}\")`);return EC.default.stringify({...n,commit:v.get(x)})}case null:{let I;if((I=p(\"commit\",E))!==null||(I=p(\"tag\",E))!==null||(I=p(\"head\",E))!==null)return I;throw E.match(/^[a-f0-9]+$/)?new Error(`Couldn't resolve \"${E}\" as either a commit, a tag, or a head - if a commit, use the 40-characters commit hash`):new Error(`Couldn't resolve \"${E}\" as either a commit, a tag, or a head`)}default:throw new Error(`Invalid Git resolution protocol (\"${h}\")`)}},p=(h,E)=>{try{return A(h,E)}catch{return null}};return yC(`${r}#${A(o,a)}`)}async function X8(t,e){return await e.getLimit(\"cloneConcurrency\")(async()=>{let{repo:r,treeish:{protocol:o,request:a}}=o0(t);if(o!==\"commit\")throw new Error(\"Invalid treeish protocol when cloning\");let n=V8(r,{configuration:e}),u=await oe.mktempPromise(),A={cwd:u,env:Pde()};return await z8(\"cloning the repository\",[\"clone\",\"-c core.autocrlf=false\",n,le.fromPortablePath(u)],A,{configuration:e,normalizedRepoUrl:n}),await z8(\"switching branch\",[\"checkout\",`${a}`],A,{configuration:e,normalizedRepoUrl:n}),u})}async function bde(t){let e,r=t;do{if(e=r,await oe.existsPromise(z.join(e,\".git\")))return e;r=z.dirname(e)}while(r!==e);return null}async function xde(t,{baseRefs:e}){if(e.length===0)throw new it(\"Can't run this command with zero base refs specified.\");let r=[];for(let A of e){let{code:p}=await Ur.execvp(\"git\",[\"merge-base\",A,\"HEAD\"],{cwd:t});p===0&&r.push(A)}if(r.length===0)throw new it(`No ancestor could be found between any of HEAD and ${e.join(\", \")}`);let{stdout:o}=await Ur.execvp(\"git\",[\"merge-base\",\"HEAD\",...r],{cwd:t,strict:!0}),a=o.trim(),{stdout:n}=await Ur.execvp(\"git\",[\"show\",\"--quiet\",\"--pretty=format:%s\",a],{cwd:t,strict:!0}),u=n.trim();return{hash:a,title:u}}async function kde(t,{base:e,project:r}){let o=_e.buildIgnorePattern(r.configuration.get(\"changesetIgnorePatterns\")),{stdout:a}=await Ur.execvp(\"git\",[\"diff\",\"--name-only\",`${e}`],{cwd:t,strict:!0}),n=a.split(/\\r\\n|\\r|\\n/).filter(h=>h.length>0).map(h=>z.resolve(t,le.toPortablePath(h))),{stdout:u}=await Ur.execvp(\"git\",[\"ls-files\",\"--others\",\"--exclude-standard\"],{cwd:t,strict:!0}),A=u.split(/\\r\\n|\\r|\\n/).filter(h=>h.length>0).map(h=>z.resolve(t,le.toPortablePath(h))),p=[...new Set([...n,...A].sort())];return o?p.filter(h=>!z.relative(r.cwd,h).match(o)):p}async function Bgt({ref:t,project:e}){if(e.configuration.projectCwd===null)throw new it(\"This command can only be run from within a Yarn project\");let r=[z.resolve(e.cwd,dr.lockfile),z.resolve(e.cwd,e.configuration.get(\"cacheFolder\")),z.resolve(e.cwd,e.configuration.get(\"installStatePath\")),z.resolve(e.cwd,e.configuration.get(\"virtualFolder\"))];await e.configuration.triggerHook(u=>u.populateYarnPaths,e,u=>{u!=null&&r.push(u)});let o=await bde(e.configuration.projectCwd);if(o==null)throw new it(\"This command can only be run on Git repositories\");let a=await xde(o,{baseRefs:typeof t==\"string\"?[t]:e.configuration.get(\"changesetBaseRefs\")}),n=await kde(o,{base:a.hash,project:e});return new Set(_e.mapAndFilter(n,u=>{let A=e.tryWorkspaceByFilePath(u);return A===null?_e.mapAndFilter.skip:r.some(p=>u.startsWith(p))?_e.mapAndFilter.skip:A}))}async function z8(t,e,r,{configuration:o,normalizedRepoUrl:a}){try{return await Ur.execvp(\"git\",e,{...r,strict:!0})}catch(n){if(!(n instanceof Ur.ExecError))throw n;let u=n.reportExtra,A=n.stderr.toString();throw new Jt(1,`Failed ${t}`,p=>{p.reportError(1,`  ${de.prettyField(o,{label:\"Repository URL\",value:de.tuple(de.Type.URL,a)})}`);for(let h of A.matchAll(/^(.+?): (.*)$/gm)){let[,E,I]=h;E=E.toLowerCase();let v=E===\"error\"?\"Error\":`${(0,Dde.default)(E)} Error`;p.reportError(1,`  ${de.prettyField(o,{label:v,value:de.tuple(de.Type.NO_HINT,I)})}`)}u?.(p)})}}var w2=class{supports(e,r){return CC(e.reference)}getLocalPath(e,r){return null}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,a=new Map(r.checksums);a.set(e.locatorHash,o);let n={...r,checksums:a},u=await this.downloadHosted(e,n);if(u!==null)return u;let[A,p,h]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the remote repository`),loader:()=>this.cloneFromRemote(e,n),...r.cacheOptions});return{packageFs:A,releaseFs:p,prefixPath:W.getIdentVendorPath(e),checksum:h}}async downloadHosted(e,r){return r.project.configuration.reduceHook(o=>o.fetchHostedRepository,null,e,r)}async cloneFromRemote(e,r){let o=await X8(e.reference,r.project.configuration),a=o0(e.reference),n=z.join(o,\"package.tgz\");await un.prepareExternalProject(o,n,{configuration:r.project.configuration,report:r.report,workspace:a.extra.workspace,locator:e});let u=await oe.readFilePromise(n);return await _e.releaseAfterUseAsync(async()=>await Xi.convertToZip(u,{configuration:r.project.configuration,prefixPath:W.getIdentVendorPath(e),stripComponents:1}))}};Ye();Ye();var I2=class{supportsDescriptor(e,r){return CC(e.range)}supportsLocator(e,r){return CC(e.reference)}shouldPersistResolution(e,r){return!0}bindDescriptor(e,r,o){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){let a=await J8(e.range,o.project.configuration);return[W.makeLocator(e,a)]}async getSatisfying(e,r,o,a){let n=o0(e.range);return{locators:o.filter(A=>{if(A.identHash!==e.identHash)return!1;let p=o0(A.reference);return!(n.repo!==p.repo||n.treeish.protocol===\"commit\"&&n.treeish.request!==p.treeish.request)}),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error(\"Assertion failed: This resolver cannot be used unless a fetcher is configured\");let o=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await _e.releaseAfterUseAsync(async()=>await Ot.find(o.prefixPath,{baseFs:o.packageFs}),o.releaseFs);return{...e,version:a.version||\"0.0.0\",languageName:a.languageName||r.project.configuration.get(\"defaultLanguageName\"),linkType:\"HARD\",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var vgt={configuration:{changesetBaseRefs:{description:\"The base git refs that the current HEAD is compared against when detecting changes. Supports git branches, tags, and commits.\",type:\"STRING\",isArray:!0,isNullable:!1,default:[\"master\",\"origin/master\",\"upstream/master\",\"main\",\"origin/main\",\"upstream/main\"]},changesetIgnorePatterns:{description:\"Array of glob patterns; files matching them will be ignored when fetching the changed files\",type:\"STRING\",default:[],isArray:!0},cloneConcurrency:{description:\"Maximal number of concurrent clones\",type:\"NUMBER\",default:2}},fetchers:[w2],resolvers:[I2]};var Dgt=vgt;qt();var a0=class extends ut{constructor(){super(...arguments);this.since=ge.String(\"--since\",{description:\"Only include workspaces that have been changed since the specified ref.\",tolerateBoolean:!0});this.recursive=ge.Boolean(\"-R,--recursive\",!1,{description:\"Find packages via dependencies/devDependencies instead of using the workspaces field\"});this.noPrivate=ge.Boolean(\"--no-private\",{description:\"Exclude workspaces that have the private field set to true\"});this.verbose=ge.Boolean(\"-v,--verbose\",!1,{description:\"Also return the cross-dependencies between workspaces\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd);return(await Lt.start({configuration:r,json:this.json,stdout:this.context.stdout},async n=>{let u=this.since?await ra.fetchChangedWorkspaces({ref:this.since,project:o}):o.workspaces,A=new Set(u);if(this.recursive)for(let p of[...u].map(h=>h.getRecursiveWorkspaceDependents()))for(let h of p)A.add(h);for(let p of A){let{manifest:h}=p;if(h.private&&this.noPrivate)continue;let E;if(this.verbose){let I=new Set,v=new Set;for(let x of Ot.hardDependencies)for(let[C,R]of h.getForScope(x)){let N=o.tryWorkspaceByDescriptor(R);N===null?o.workspacesByIdent.has(C)&&v.add(R):I.add(N)}E={workspaceDependencies:Array.from(I).map(x=>x.relativeCwd),mismatchedWorkspaceDependencies:Array.from(v).map(x=>W.stringifyDescriptor(x))}}n.reportInfo(null,`${p.relativeCwd}`),n.reportJson({location:p.relativeCwd,name:h.name?W.stringifyIdent(h.name):null,...E})}})).exitCode()}};a0.paths=[[\"workspaces\",\"list\"]],a0.usage=nt.Usage({category:\"Workspace-related commands\",description:\"list all available workspaces\",details:\"\\n      This command will print the list of all workspaces in the project.\\n\\n      - If `--since` is set, Yarn will only list workspaces that have been modified since the specified ref. By default Yarn will use the refs specified by the `changesetBaseRefs` configuration option.\\n\\n      - If `-R,--recursive` is set, Yarn will find workspaces to run the command on by recursively evaluating `dependencies` and `devDependencies` fields, instead of looking at the `workspaces` fields.\\n\\n      - If `--no-private` is set, Yarn will not list any workspaces that have the `private` field set to `true`.\\n\\n      - If both the `-v,--verbose` and `--json` options are set, Yarn will also return the cross-dependencies between each workspaces (useful when you wish to automatically generate Buck / Bazel rules).\\n    \"});Ye();Ye();qt();var l0=class extends ut{constructor(){super(...arguments);this.workspaceName=ge.String();this.commandName=ge.String();this.args=ge.Proxy()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new nr(o.cwd,this.context.cwd);let n=o.workspaces,u=new Map(n.map(p=>[W.stringifyIdent(p.anchoredLocator),p])),A=u.get(this.workspaceName);if(A===void 0){let p=Array.from(u.keys()).sort();throw new it(`Workspace '${this.workspaceName}' not found. Did you mean any of the following:\n  - ${p.join(`\n  - `)}?`)}return this.cli.run([this.commandName,...this.args],{cwd:A.cwd})}};l0.paths=[[\"workspace\"]],l0.usage=nt.Usage({category:\"Workspace-related commands\",description:\"run a command within the specified workspace\",details:`\n      This command will run a given sub-command on a single workspace.\n    `,examples:[[\"Add a package to a single workspace\",\"yarn workspace components add -D react\"],[\"Run build script on a single workspace\",\"yarn workspace components run build\"]]});var Pgt={configuration:{enableImmutableInstalls:{description:\"If true (the default on CI), prevents the install command from modifying the lockfile\",type:\"BOOLEAN\",default:Qde.isCI},defaultSemverRangePrefix:{description:\"The default save prefix: '^', '~' or ''\",type:\"STRING\",values:[\"^\",\"~\",\"\"],default:\"^\"},preferReuse:{description:\"If true, `yarn add` will attempt to reuse the most common dependency range in other workspaces.\",type:\"BOOLEAN\",default:!1}},commands:[Rh,Th,Lh,Nh,n0,Vh,Hh,a0,zd,Vd,mC,Jd,Qh,Fh,Oh,Mh,Uh,_h,qh,Gh,jh,Yh,i0,Wh,Kh,Xh,Jh,Zh,zh,$h,e0,t0,Zd,r0,Vf,s0,l0]},Sgt=Pgt;var iH={};zt(iH,{default:()=>xgt});Ye();var kt={optional:!0},eH=[[\"@tailwindcss/aspect-ratio@<0.2.1\",{peerDependencies:{tailwindcss:\"^2.0.2\"}}],[\"@tailwindcss/line-clamp@<0.2.1\",{peerDependencies:{tailwindcss:\"^2.0.2\"}}],[\"@fullhuman/postcss-purgecss@3.1.3 || 3.1.3-alpha.0\",{peerDependencies:{postcss:\"^8.0.0\"}}],[\"@samverschueren/stream-to-observable@<0.3.1\",{peerDependenciesMeta:{rxjs:kt,zenObservable:kt}}],[\"any-observable@<0.5.1\",{peerDependenciesMeta:{rxjs:kt,zenObservable:kt}}],[\"@pm2/agent@<1.0.4\",{dependencies:{debug:\"*\"}}],[\"debug@<4.2.0\",{peerDependenciesMeta:{[\"supports-color\"]:kt}}],[\"got@<11\",{dependencies:{[\"@types/responselike\"]:\"^1.0.0\",[\"@types/keyv\"]:\"^3.1.1\"}}],[\"cacheable-lookup@<4.1.2\",{dependencies:{[\"@types/keyv\"]:\"^3.1.1\"}}],[\"http-link-dataloader@*\",{peerDependencies:{graphql:\"^0.13.1 || ^14.0.0\"}}],[\"typescript-language-server@*\",{dependencies:{[\"vscode-jsonrpc\"]:\"^5.0.1\",[\"vscode-languageserver-protocol\"]:\"^3.15.0\"}}],[\"postcss-syntax@*\",{peerDependenciesMeta:{[\"postcss-html\"]:kt,[\"postcss-jsx\"]:kt,[\"postcss-less\"]:kt,[\"postcss-markdown\"]:kt,[\"postcss-scss\"]:kt}}],[\"jss-plugin-rule-value-function@<=10.1.1\",{dependencies:{[\"tiny-warning\"]:\"^1.0.2\"}}],[\"ink-select-input@<4.1.0\",{peerDependencies:{react:\"^16.8.2\"}}],[\"license-webpack-plugin@<2.3.18\",{peerDependenciesMeta:{webpack:kt}}],[\"snowpack@>=3.3.0\",{dependencies:{[\"node-gyp\"]:\"^7.1.0\"}}],[\"promise-inflight@*\",{peerDependenciesMeta:{bluebird:kt}}],[\"reactcss@*\",{peerDependencies:{react:\"*\"}}],[\"react-color@<=2.19.0\",{peerDependencies:{react:\"*\"}}],[\"gatsby-plugin-i18n@*\",{dependencies:{ramda:\"^0.24.1\"}}],[\"useragent@^2.0.0\",{dependencies:{request:\"^2.88.0\",yamlparser:\"0.0.x\",semver:\"5.5.x\"}}],[\"@apollographql/apollo-tools@<=0.5.2\",{peerDependencies:{graphql:\"^14.2.1 || ^15.0.0\"}}],[\"material-table@^2.0.0\",{dependencies:{\"@babel/runtime\":\"^7.11.2\"}}],[\"@babel/parser@*\",{dependencies:{\"@babel/types\":\"^7.8.3\"}}],[\"fork-ts-checker-webpack-plugin@<=6.3.4\",{peerDependencies:{eslint:\">= 6\",typescript:\">= 2.7\",webpack:\">= 4\",\"vue-template-compiler\":\"*\"},peerDependenciesMeta:{eslint:kt,\"vue-template-compiler\":kt}}],[\"rc-animate@<=3.1.1\",{peerDependencies:{react:\">=16.9.0\",\"react-dom\":\">=16.9.0\"}}],[\"react-bootstrap-table2-paginator@*\",{dependencies:{classnames:\"^2.2.6\"}}],[\"react-draggable@<=4.4.3\",{peerDependencies:{react:\">= 16.3.0\",\"react-dom\":\">= 16.3.0\"}}],[\"apollo-upload-client@<14\",{peerDependencies:{graphql:\"14 - 15\"}}],[\"react-instantsearch-core@<=6.7.0\",{peerDependencies:{algoliasearch:\">= 3.1 < 5\"}}],[\"react-instantsearch-dom@<=6.7.0\",{dependencies:{\"react-fast-compare\":\"^3.0.0\"}}],[\"ws@<7.2.1\",{peerDependencies:{bufferutil:\"^4.0.1\",\"utf-8-validate\":\"^5.0.2\"},peerDependenciesMeta:{bufferutil:kt,\"utf-8-validate\":kt}}],[\"react-portal@<4.2.2\",{peerDependencies:{\"react-dom\":\"^15.0.0-0 || ^16.0.0-0 || ^17.0.0-0\"}}],[\"react-scripts@<=4.0.1\",{peerDependencies:{react:\"*\"}}],[\"testcafe@<=1.10.1\",{dependencies:{\"@babel/plugin-transform-for-of\":\"^7.12.1\",\"@babel/runtime\":\"^7.12.5\"}}],[\"testcafe-legacy-api@<=4.2.0\",{dependencies:{\"testcafe-hammerhead\":\"^17.0.1\",\"read-file-relative\":\"^1.2.0\"}}],[\"@google-cloud/firestore@<=4.9.3\",{dependencies:{protobufjs:\"^6.8.6\"}}],[\"gatsby-source-apiserver@*\",{dependencies:{[\"babel-polyfill\"]:\"^6.26.0\"}}],[\"@webpack-cli/package-utils@<=1.0.1-alpha.4\",{dependencies:{[\"cross-spawn\"]:\"^7.0.3\"}}],[\"gatsby-remark-prismjs@<3.3.28\",{dependencies:{lodash:\"^4\"}}],[\"gatsby-plugin-favicon@*\",{peerDependencies:{webpack:\"*\"}}],[\"gatsby-plugin-sharp@<=4.6.0-next.3\",{dependencies:{debug:\"^4.3.1\"}}],[\"gatsby-react-router-scroll@<=5.6.0-next.0\",{dependencies:{[\"prop-types\"]:\"^15.7.2\"}}],[\"@rebass/forms@*\",{dependencies:{[\"@styled-system/should-forward-prop\"]:\"^5.0.0\"},peerDependencies:{react:\"^16.8.6\"}}],[\"rebass@*\",{peerDependencies:{react:\"^16.8.6\"}}],[\"@ant-design/react-slick@<=0.28.3\",{peerDependencies:{react:\">=16.0.0\"}}],[\"mqtt@<4.2.7\",{dependencies:{duplexify:\"^4.1.1\"}}],[\"vue-cli-plugin-vuetify@<=2.0.3\",{dependencies:{semver:\"^6.3.0\"},peerDependenciesMeta:{\"sass-loader\":kt,\"vuetify-loader\":kt}}],[\"vue-cli-plugin-vuetify@<=2.0.4\",{dependencies:{\"null-loader\":\"^3.0.0\"}}],[\"vue-cli-plugin-vuetify@>=2.4.3\",{peerDependencies:{vue:\"*\"}}],[\"@vuetify/cli-plugin-utils@<=0.0.4\",{dependencies:{semver:\"^6.3.0\"},peerDependenciesMeta:{\"sass-loader\":kt}}],[\"@vue/cli-plugin-typescript@<=5.0.0-alpha.0\",{dependencies:{\"babel-loader\":\"^8.1.0\"}}],[\"@vue/cli-plugin-typescript@<=5.0.0-beta.0\",{dependencies:{\"@babel/core\":\"^7.12.16\"},peerDependencies:{\"vue-template-compiler\":\"^2.0.0\"},peerDependenciesMeta:{\"vue-template-compiler\":kt}}],[\"cordova-ios@<=6.3.0\",{dependencies:{underscore:\"^1.9.2\"}}],[\"cordova-lib@<=10.0.1\",{dependencies:{underscore:\"^1.9.2\"}}],[\"git-node-fs@*\",{peerDependencies:{\"js-git\":\"^0.7.8\"},peerDependenciesMeta:{\"js-git\":kt}}],[\"consolidate@<0.16.0\",{peerDependencies:{mustache:\"^3.0.0\"},peerDependenciesMeta:{mustache:kt}}],[\"consolidate@<=0.16.0\",{peerDependencies:{velocityjs:\"^2.0.1\",tinyliquid:\"^0.2.34\",\"liquid-node\":\"^3.0.1\",jade:\"^1.11.0\",\"then-jade\":\"*\",dust:\"^0.3.0\",\"dustjs-helpers\":\"^1.7.4\",\"dustjs-linkedin\":\"^2.7.5\",swig:\"^1.4.2\",\"swig-templates\":\"^2.0.3\",\"razor-tmpl\":\"^1.3.1\",atpl:\">=0.7.6\",liquor:\"^0.0.5\",twig:\"^1.15.2\",ejs:\"^3.1.5\",eco:\"^1.1.0-rc-3\",jazz:\"^0.0.18\",jqtpl:\"~1.1.0\",hamljs:\"^0.6.2\",hamlet:\"^0.3.3\",whiskers:\"^0.4.0\",\"haml-coffee\":\"^1.14.1\",\"hogan.js\":\"^3.0.2\",templayed:\">=0.2.3\",handlebars:\"^4.7.6\",underscore:\"^1.11.0\",lodash:\"^4.17.20\",pug:\"^3.0.0\",\"then-pug\":\"*\",qejs:\"^3.0.5\",walrus:\"^0.10.1\",mustache:\"^4.0.1\",just:\"^0.1.8\",ect:\"^0.5.9\",mote:\"^0.2.0\",toffee:\"^0.3.6\",dot:\"^1.1.3\",\"bracket-template\":\"^1.1.5\",ractive:\"^1.3.12\",nunjucks:\"^3.2.2\",htmling:\"^0.0.8\",\"babel-core\":\"^6.26.3\",plates:\"~0.4.11\",\"react-dom\":\"^16.13.1\",react:\"^16.13.1\",\"arc-templates\":\"^0.5.3\",vash:\"^0.13.0\",slm:\"^2.0.0\",marko:\"^3.14.4\",teacup:\"^2.0.0\",\"coffee-script\":\"^1.12.7\",squirrelly:\"^5.1.0\",twing:\"^5.0.2\"},peerDependenciesMeta:{velocityjs:kt,tinyliquid:kt,\"liquid-node\":kt,jade:kt,\"then-jade\":kt,dust:kt,\"dustjs-helpers\":kt,\"dustjs-linkedin\":kt,swig:kt,\"swig-templates\":kt,\"razor-tmpl\":kt,atpl:kt,liquor:kt,twig:kt,ejs:kt,eco:kt,jazz:kt,jqtpl:kt,hamljs:kt,hamlet:kt,whiskers:kt,\"haml-coffee\":kt,\"hogan.js\":kt,templayed:kt,handlebars:kt,underscore:kt,lodash:kt,pug:kt,\"then-pug\":kt,qejs:kt,walrus:kt,mustache:kt,just:kt,ect:kt,mote:kt,toffee:kt,dot:kt,\"bracket-template\":kt,ractive:kt,nunjucks:kt,htmling:kt,\"babel-core\":kt,plates:kt,\"react-dom\":kt,react:kt,\"arc-templates\":kt,vash:kt,slm:kt,marko:kt,teacup:kt,\"coffee-script\":kt,squirrelly:kt,twing:kt}}],[\"vue-loader@<=16.3.3\",{peerDependencies:{\"@vue/compiler-sfc\":\"^3.0.8\",webpack:\"^4.1.0 || ^5.0.0-0\"},peerDependenciesMeta:{\"@vue/compiler-sfc\":kt}}],[\"vue-loader@^16.7.0\",{peerDependencies:{\"@vue/compiler-sfc\":\"^3.0.8\",vue:\"^3.2.13\"},peerDependenciesMeta:{\"@vue/compiler-sfc\":kt,vue:kt}}],[\"scss-parser@<=1.0.5\",{dependencies:{lodash:\"^4.17.21\"}}],[\"query-ast@<1.0.5\",{dependencies:{lodash:\"^4.17.21\"}}],[\"redux-thunk@<=2.3.0\",{peerDependencies:{redux:\"^4.0.0\"}}],[\"skypack@<=0.3.2\",{dependencies:{tar:\"^6.1.0\"}}],[\"@npmcli/metavuln-calculator@<2.0.0\",{dependencies:{\"json-parse-even-better-errors\":\"^2.3.1\"}}],[\"bin-links@<2.3.0\",{dependencies:{\"mkdirp-infer-owner\":\"^1.0.2\"}}],[\"rollup-plugin-polyfill-node@<=0.8.0\",{peerDependencies:{rollup:\"^1.20.0 || ^2.0.0\"}}],[\"snowpack@<3.8.6\",{dependencies:{\"magic-string\":\"^0.25.7\"}}],[\"elm-webpack-loader@*\",{dependencies:{temp:\"^0.9.4\"}}],[\"winston-transport@<=4.4.0\",{dependencies:{logform:\"^2.2.0\"}}],[\"jest-vue-preprocessor@*\",{dependencies:{\"@babel/core\":\"7.8.7\",\"@babel/template\":\"7.8.6\"},peerDependencies:{pug:\"^2.0.4\"},peerDependenciesMeta:{pug:kt}}],[\"redux-persist@*\",{peerDependencies:{react:\">=16\"},peerDependenciesMeta:{react:kt}}],[\"sodium@>=3\",{dependencies:{\"node-gyp\":\"^3.8.0\"}}],[\"babel-plugin-graphql-tag@<=3.1.0\",{peerDependencies:{graphql:\"^14.0.0 || ^15.0.0\"}}],[\"@playwright/test@<=1.14.1\",{dependencies:{\"jest-matcher-utils\":\"^26.4.2\"}}],...[\"babel-plugin-remove-graphql-queries@<3.14.0-next.1\",\"babel-preset-gatsby-package@<1.14.0-next.1\",\"create-gatsby@<1.14.0-next.1\",\"gatsby-admin@<0.24.0-next.1\",\"gatsby-cli@<3.14.0-next.1\",\"gatsby-core-utils@<2.14.0-next.1\",\"gatsby-design-tokens@<3.14.0-next.1\",\"gatsby-legacy-polyfills@<1.14.0-next.1\",\"gatsby-plugin-benchmark-reporting@<1.14.0-next.1\",\"gatsby-plugin-graphql-config@<0.23.0-next.1\",\"gatsby-plugin-image@<1.14.0-next.1\",\"gatsby-plugin-mdx@<2.14.0-next.1\",\"gatsby-plugin-netlify-cms@<5.14.0-next.1\",\"gatsby-plugin-no-sourcemaps@<3.14.0-next.1\",\"gatsby-plugin-page-creator@<3.14.0-next.1\",\"gatsby-plugin-preact@<5.14.0-next.1\",\"gatsby-plugin-preload-fonts@<2.14.0-next.1\",\"gatsby-plugin-schema-snapshot@<2.14.0-next.1\",\"gatsby-plugin-styletron@<6.14.0-next.1\",\"gatsby-plugin-subfont@<3.14.0-next.1\",\"gatsby-plugin-utils@<1.14.0-next.1\",\"gatsby-recipes@<0.25.0-next.1\",\"gatsby-source-shopify@<5.6.0-next.1\",\"gatsby-source-wikipedia@<3.14.0-next.1\",\"gatsby-transformer-screenshot@<3.14.0-next.1\",\"gatsby-worker@<0.5.0-next.1\"].map(t=>[t,{dependencies:{\"@babel/runtime\":\"^7.14.8\"}}]),[\"gatsby-core-utils@<2.14.0-next.1\",{dependencies:{got:\"8.3.2\"}}],[\"gatsby-plugin-gatsby-cloud@<=3.1.0-next.0\",{dependencies:{\"gatsby-core-utils\":\"^2.13.0-next.0\"}}],[\"gatsby-plugin-gatsby-cloud@<=3.2.0-next.1\",{peerDependencies:{webpack:\"*\"}}],[\"babel-plugin-remove-graphql-queries@<=3.14.0-next.1\",{dependencies:{\"gatsby-core-utils\":\"^2.8.0-next.1\"}}],[\"gatsby-plugin-netlify@3.13.0-next.1\",{dependencies:{\"gatsby-core-utils\":\"^2.13.0-next.0\"}}],[\"clipanion-v3-codemod@<=0.2.0\",{peerDependencies:{jscodeshift:\"^0.11.0\"}}],[\"react-live@*\",{peerDependencies:{\"react-dom\":\"*\",react:\"*\"}}],[\"webpack@<4.44.1\",{peerDependenciesMeta:{\"webpack-cli\":kt,\"webpack-command\":kt}}],[\"webpack@<5.0.0-beta.23\",{peerDependenciesMeta:{\"webpack-cli\":kt}}],[\"webpack-dev-server@<3.10.2\",{peerDependenciesMeta:{\"webpack-cli\":kt}}],[\"@docusaurus/responsive-loader@<1.5.0\",{peerDependenciesMeta:{sharp:kt,jimp:kt}}],[\"eslint-module-utils@*\",{peerDependenciesMeta:{\"eslint-import-resolver-node\":kt,\"eslint-import-resolver-typescript\":kt,\"eslint-import-resolver-webpack\":kt,\"@typescript-eslint/parser\":kt}}],[\"eslint-plugin-import@*\",{peerDependenciesMeta:{\"@typescript-eslint/parser\":kt}}],[\"critters-webpack-plugin@<3.0.2\",{peerDependenciesMeta:{\"html-webpack-plugin\":kt}}],[\"terser@<=5.10.0\",{dependencies:{acorn:\"^8.5.0\"}}],[\"babel-preset-react-app@10.0.x <10.0.2\",{dependencies:{\"@babel/plugin-proposal-private-property-in-object\":\"^7.16.7\"}}],[\"eslint-config-react-app@*\",{peerDependenciesMeta:{typescript:kt}}],[\"@vue/eslint-config-typescript@<11.0.0\",{peerDependenciesMeta:{typescript:kt}}],[\"unplugin-vue2-script-setup@<0.9.1\",{peerDependencies:{\"@vue/composition-api\":\"^1.4.3\",\"@vue/runtime-dom\":\"^3.2.26\"}}],[\"@cypress/snapshot@*\",{dependencies:{debug:\"^3.2.7\"}}],[\"auto-relay@<=0.14.0\",{peerDependencies:{\"reflect-metadata\":\"^0.1.13\"}}],[\"vue-template-babel-compiler@<1.2.0\",{peerDependencies:{[\"vue-template-compiler\"]:\"^2.6.0\"}}],[\"@parcel/transformer-image@<2.5.0\",{peerDependencies:{[\"@parcel/core\"]:\"*\"}}],[\"@parcel/transformer-js@<2.5.0\",{peerDependencies:{[\"@parcel/core\"]:\"*\"}}],[\"parcel@*\",{peerDependenciesMeta:{[\"@parcel/core\"]:kt}}],[\"react-scripts@*\",{peerDependencies:{eslint:\"*\"}}],[\"focus-trap-react@^8.0.0\",{dependencies:{tabbable:\"^5.3.2\"}}],[\"react-rnd@<10.3.7\",{peerDependencies:{react:\">=16.3.0\",\"react-dom\":\">=16.3.0\"}}],[\"connect-mongo@<5.0.0\",{peerDependencies:{\"express-session\":\"^1.17.1\"}}],[\"vue-i18n@<9\",{peerDependencies:{vue:\"^2\"}}],[\"vue-router@<4\",{peerDependencies:{vue:\"^2\"}}],[\"unified@<10\",{dependencies:{\"@types/unist\":\"^2.0.0\"}}],[\"react-github-btn@<=1.3.0\",{peerDependencies:{react:\">=16.3.0\"}}],[\"react-dev-utils@*\",{peerDependencies:{typescript:\">=2.7\",webpack:\">=4\"},peerDependenciesMeta:{typescript:kt}}],[\"@asyncapi/react-component@<=1.0.0-next.39\",{peerDependencies:{react:\">=16.8.0\",\"react-dom\":\">=16.8.0\"}}],[\"xo@*\",{peerDependencies:{webpack:\">=1.11.0\"},peerDependenciesMeta:{webpack:kt}}],[\"babel-plugin-remove-graphql-queries@<=4.20.0-next.0\",{dependencies:{\"@babel/types\":\"^7.15.4\"}}],[\"gatsby-plugin-page-creator@<=4.20.0-next.1\",{dependencies:{\"fs-extra\":\"^10.1.0\"}}],[\"gatsby-plugin-utils@<=3.14.0-next.1\",{dependencies:{fastq:\"^1.13.0\"},peerDependencies:{graphql:\"^15.0.0\"}}],[\"gatsby-plugin-mdx@<3.1.0-next.1\",{dependencies:{mkdirp:\"^1.0.4\"}}],[\"gatsby-plugin-mdx@^2\",{peerDependencies:{gatsby:\"^3.0.0-next\"}}],[\"fdir@<=5.2.0\",{peerDependencies:{picomatch:\"2.x\"},peerDependenciesMeta:{picomatch:kt}}],[\"babel-plugin-transform-typescript-metadata@<=0.3.2\",{peerDependencies:{\"@babel/core\":\"^7\",\"@babel/traverse\":\"^7\"},peerDependenciesMeta:{\"@babel/traverse\":kt}}],[\"graphql-compose@>=9.0.10\",{peerDependencies:{graphql:\"^14.2.0 || ^15.0.0 || ^16.0.0\"}}],[\"vite-plugin-vuetify@<=1.0.2\",{peerDependencies:{vue:\"^3.0.0\"}}],[\"webpack-plugin-vuetify@<=2.0.1\",{peerDependencies:{vue:\"^3.2.6\"}}],[\"eslint-import-resolver-vite@<2.0.1\",{dependencies:{debug:\"^4.3.4\",resolve:\"^1.22.8\"}}]];var tH;function Fde(){return typeof tH>\"u\"&&(tH=ve(\"zlib\").brotliDecompressSync(Buffer.from(\"G7weAByFTVk3Vs7UfHhq4yykgEM7pbW7TI43SG2S5tvGrwHBAzdz+s/npQ6tgEvobvxisrPIadkXeUAJotBn5bDZ5kAhcRqsIHe3F75Walet5hNalwgFDtxb0BiDUjiUQkjG0yW2hto9HPgiCkm316d6bC0kST72YN7D7rfkhCE9x4J0XwB0yavalxpUu2t9xszHrmtwalOxT7VslsxWcB1qpqZwERUra4psWhTV8BgwWeizurec82Caf1ABL11YMfbf8FJ9JBceZOkgmvrQPbC9DUldX/yMbmX06UQluCEjSwUoyO+EZPIjofr+/oAZUck2enraRD+oWLlnlYnj8xB+gwSo9lmmks4fXv574qSqcWA6z21uYkzMu3EWj+K23RxeQlLqiE35/rC8GcS4CGkKHKKq+zAIQwD9iRDNfiAqueLLpicFFrNsAI4zeTD/eO9MHcnRa5m8UT+M2+V+AkFST4BlKneiAQRSdST8KEAIyFlULt6wa9EBd0Ds28VmpaxquJdVt+nwdEs5xUskI13OVtFyY0UrQIRAlCuvvWivvlSKQfTO+2Q8OyUR1W5RvetaPz4jD27hdtwHFFA1Ptx6Ee/t2cY2rg2G46M1pNDRf2pWhvpy8pqMnuI3++4OF3+7OFIWXGjh+o7Nr2jNvbiYcQdQS1h903/jVFgOpA0yJ78z+x759bFA0rq+6aY5qPB4FzS3oYoLupDUhD9nDz6F6H7hpnlMf18KNKDu4IKjTWwrAnY6MFQw1W6ymOALHlFyCZmQhldg1MQHaMVVQTVgDC60TfaBqG++Y8PEoFhN/PBTZT175KNP/BlHDYGOOBmnBdzqJKplZ/ljiVG0ZBzfqeBRrrUkn6rA54462SgiliKoYVnbeptMdXNfAuaupIEi0bApF10TlgHfmEJAPUVidRVFyDupSem5po5vErPqWKhKbUIp0LozpYsIKK57dM/HKr+nguF+7924IIWMICkQ8JUigs9D+W+c4LnNoRtPPKNRUiCYmP+Jfo2lfKCKw8qpraEeWU3uiNRO6zcyKQoXPR5htmzzLznke7b4YbXW3I1lIRzmgG02Udb58U+7TpwyN7XymCgH+wuPDthZVQvRZuEP+SnLtMicz9m5zASWOBiAcLmkuFlTKuHspSIhCBD0yUPKcxu81A+4YD78rA2vtwsUEday9WNyrShyrl60rWmA+SmbYZkQOwFJWArxRYYc5jGhA5ikxYw1rx3ei4NmeX/lKiwpZ9Ln1tV2Ae7sArvxuVLbJjqJRjW1vFXAyHpvLG+8MJ6T2Ubx5M2KDa2SN6vuIGxJ9WQM9Mk3Q7aCNiZONXllhqq24DmoLbQfW2rYWsOgHWjtOmIQMyMKdiHZDjoyIq5+U700nZ6odJAoYXPQBvFNiQ78d5jaXliBqLTJEqUCwi+LiH2mx92EmNKDsJL74Z613+3lf20pxkV1+erOrjj8pW00vsPaahKUM+05ssd5uwM7K482KWEf3TCwlg/o3e5ngto7qSMz7YteIgCsF1UOcsLk7F7MxWbvrPMY473ew0G+noVL8EPbkmEMftMSeL6HFub/zy+2JQ==\",\"base64\")).toString()),tH}var rH;function Rde(){return typeof rH>\"u\"&&(rH=ve(\"zlib\").brotliDecompressSync(Buffer.from(\"G8MSIIzURnVBnObTcvb3XE6v2S9Qgc2K801Oa5otNKEtK8BINZNcaQHy+9/vf/WXBimwutXC33P2DPc64pps5rz7NGGWaOKNSPL4Y2KRE8twut2lFOIN+OXPtRmPMRhMTILib2bEQx43az2I5d3YS8Roa5UZpF/ujHb3Djd3GDvYUfvFYSUQ39vb2cmifp/rgB4J/65JK3wRBTvMBoNBmn3mbXC63/gbBkW/2IRPri0O8bcsRBsmarF328pAln04nyJFkwUAvNu934supAqLtyerZZpJ8I8suJHhf/ocMV+scKwa8NOiDKIPXw6Ex/EEZD6TEGaW8N5zvNHYF10l6Lfooj7D5W2k3dgvQSbp2Wv8TGOayS978gxlOLVjTGXs66ozewbrjwElLtyrYNnWTfzzdEutgROUFPVMhnMoy8EjJLLlWwIEoySxliim9kYW30JUHiPVyjt0iAw/ZpPmCbUCltYPnq6ZNblIKhTNhqS/oqC9iya5sGKZTOVsTEg34n92uZTf2iPpcZih8rPW8CzA+adIGmyCPcKdLMsBLShd+zuEbTrqpwuh+DLmracZcjPC5Sdf5odDAhKpFuOsQS67RT+1VgWWygSv3YwxDnylc04/PYuaMeIzhBkLrvs7e/OUzRTF56MmfY6rI63QtEjEQzq637zQqJ39nNhu3NmoRRhW/086bHGBUtx0PE0j3aEGvkdh9WJC8y8j8mqqke9/dQ5la+Q3ba4RlhvTbnfQhPDDab3tUifkjKuOsp13mXEmO00Mu88F/M67R7LXfoFDFLNtgCSWjWX+3Jn1371pJTK9xPBiMJafvDjtFyAzu8rxeQ0TKMQXNPs5xxiBOd+BRJP8KP88XPtJIbZKh/cdW8KvBUkpqKpGoiIaA32c3/JnQr4efXt85mXvidOvn/eU3Pase1typLYBalJ14mCso9h79nuMOuCa/kZAOkJHmTjP5RM2WNoPasZUAnT1TAE/NH25hUxcQv6hQWR/m1PKk4ooXMcM4SR1iYU3fUohvqk4RY2hbmTVVIXv6TvqO+0doOjgeVFAcom+RlwJQmOVH7pr1Q9LoJT6n1DeQEB+NHygsATbIwTcOKZlJsY8G4+suX1uQLjUWwLjjs0mvSvZcLTpIGAekeR7GCgl8eo3ndAqEe2XCav4huliHjdbIPBsGJuPX7lrO9HX1UbXRH5opOe1x6JsOSgHZR+EaxuXVhpLLxm6jk1LJtZfHSc6BKPun3CpYYVMJGwEUyk8MTGG0XL5MfEwaXpnc9TKnBmlGn6nHiGREc3ysn47XIBDzA+YvFdjZzVIEDcKGpS6PbUJehFRjEne8D0lVU1XuRtlgszq6pTNlQ/3MzNOEgCWPyTct22V2mEi2krizn5VDo9B19/X2DB3hCGRMM7ONbtnAcIx/OWB1u5uPbW1gsH8irXxT/IzG0PoXWYjhbMsH3KTuoOl5o17PulcgvsfTSnKFM354GWI8luqZnrswWjiXy3G+Vbyo1KMopFmmvBwNELgaS8z8dNZchx/Cl/xjddxhMcyqtzFyONb2Zdu90NkI8pAeufe7YlXrp53v8Dj/l8vWeVspRKBGXScBBPI/HinSTGmLDOGGOCIyH0JFdOZx0gWsacNlQLJMIrBhqRxXxHF/5pseWwejlAAvZ3klZSDSYY8mkToaWejXhgNomeGtx1DTLEUFMRkgF5yFB22WYdJnaWN14r1YJj81hGi45+jrADS5nYRhCiSlCJJ1nL8pYX+HDSMhdTEWyRcgHVp/IsUIZYMfT+YYncUQPgcxNGCHfZ88vDdrcUuaGIl6zhAsiaq7R5dfqrqXH/JcBhfjT8D0azayIyEz75Nxp6YkcyDxlJq3EXnJUpqDohJJOysL1t1uNiHESlvsxPb5cpbW0+ICZqJmUZus1BMW0F5IVBODLIo2zHHjA0=\",\"base64\")).toString()),rH}var nH;function Tde(){return typeof nH>\"u\"&&(nH=ve(\"zlib\").brotliDecompressSync(Buffer.from(\"m409OwVy8xl9Wz0aWLh5C+Rku0TnEAOUUhQ/9+e/2xNhHl63hoddw+s91FRj6zag6vW4MQY+qFXdgWBlxR3KtnlgCulKXrSTz7DFgsKPlnjjvrPfnVFSm37PhHADc/LAJ3x7Bi78Y7UW3fQUbD8b50X9jaQ80AMJo2VFl85CtqGmExRKMEx10T7JmdsVtqcUvAbQY3MJqoxwFiK2e+IU6pjhoLkU+Wj7zdVlQvLAI14qgoc8xZsrIC254zYHUS6Vi6BN130uOk/gy3YQKR2VDrN/Nu29+3IS2iaK/ZDwNvLlklqd6nXEE5IdxqYMkkMmLJep2t+f144+WjhLKC5NukZ3udKtBSoAKSQUxNld2cfMhNA8j9CDl9Or+OaiAS5VQ3H+ARxHMmU3N7OG/yU/gn4dchhvSR2kVhnRuOEtYV6Si6ravaugcJJ5SJ0ywQkPQ/9rocqeC4VyqlBdoU9GvQsD+ZDuwH5WbLasANlkldI0DcwHOLn3gUynsmgMYa0YTj3B2P3/elN7txBGBDjnfOl/29IkgA6Ek8Yb/sWOCpRTTOhbdetyGt2AhgCIMwBBTohKDppxiHVTVaO7AQ0gUiFZVnIKebPyZhvyznm3fq8BzqfSxJ+CQ4qLxcZ+77IS351V/1KrnXocex0y6wVs4QJkxOY9qS8kfkb7Fp6ZAc1aZmgGZwGmqaR2qJLIqBvNOv+fqVapHrUg571FF3VCFUar+r0GrTkXNV9+Xo88G62LXBIs7nU3AUjrjeacqDOizrmIIonqsTrn0stcuBcJDJJosxxAdwNaTTcxu6zqfifWb+wTu4Az2plz4Wl5enhALQ4kE+kjRcq+VK3A/NJ7kOH8vuW3F5KU6g6pGrLxWNlvDys0Qj0UayRgrF5m55FS1aypW014PeT/bc0dBkRqmiL8sPQY+/q22+83A0RUMnLKYx496A+XK3RIM4zhDf1Th6mJG8t5bbvdTgSYpKcWbhcoZs1E88MdIqTJmmm5L1bewYtYLt1s5BCLsbTk2tyf/iogn0BgXaHgmAxd6s/VspNCKKOK/pUoqrkYFPaK2mI9m3sCz+cnf2eYr4mFLRsiUsl79HaOsZ9fW6X79j6JiICIJAeH2EJvy7jved/vnZJUWph0KwyE7NO+qjwbkjeHr+M0bgRC/UCgthk1wOqjYvpV/tZPlSXM56dSwN6lJj3fU/uzQb8vrWD98wLmd3bkfm/zt4/yJ757/VhP4FUj/THzz8Cw68HfxqgtrHbzDV8fsm++dRjDs8wKlj/JR30FvPPQX/Fv71C+QpAe9/sepC/7bD/+TH9tK9QKCvgOZl7PJSDNA2DTJ3ZCQMy89NBHjtLup5Bev1zDOLM82MrFLpZ2LTAoIiC/3WAOHfxC7DeKh1yHZtLtve8RQwBTMBXRQEPPUh6jx4q54V3/3yJfM66MNu99IO1hJG5vlrJx2WaepqX5CuN/G8ajiK3G3yTKd8tm/7UVFm2KMCOih/Q/Lki345v40l3GZfVuHXEZIGDm9GWgs+BZ3t8JY8haRJmRoBD3somexND8brTJTEUPSzhanMKy1COI8VNmjc7KLg255ur7ezqEbjooxDhxGX+SxWhkm3IFSfXbKwHR4OL1w1BydEG4Zgz4q4glxmBbtgybg0HAJDH++brRjJsIMhLPmjcRg4V9pDpvp8UF4GgpsLu43sV8GdWvN8SEAkUYF/wLOqQJyYc0jUEgAxHxJT9NVCTgocxY3p4jKUAYIWwI1VWRfWD6fikEeeH1MAIkGnx0TZDNMOayb/tgpJA8u6q+xUkWkEzpjr37TVUfu5t2jt6hnyln+12uyWzGICeTJAOWiwPzAGPXFyQOWRN74AvqEwO4GchaIhBRImHLJmr9NsU43/HvATunlCWglpCpmnclokgBJSdBcRYPsfIiAQvCLQFaNhPPLfSrsWi43gyF6x3CrH9Dj1arFqkM6v8XPCXrRy0XEzBXQTRk3iEZSW3dXJGW5hEon2Uqn9aU0v1CfloWmCsEZoQpvrAUJi5igQUftLYQX3/F8TOgnwW9XmQqLpxQMqpykVMgzknHJiBUj1KCg6qJNqK/tFTJ/R/7CJRYz3OrAQUqaHfP1svdr3huX+/0Oo6oixugurI1b0S6cKxI7vdto1ipRyECBiWLfSsP9XqdSIg68/ItIaB0RwxgMg/7G+wLIreZhpONPOTmoZfTZzYnJOryKStfOpbt8cHm/8Kyob1yMxv9cI7OpAbkv5LMOaMlVsH0JH/ZvCKeoMSFsO9CB58R1Y6IWwl92VzTSb0jqeeJBRUe+1s4Lht/VoLWaMyV3xBLfO04v/KLN3iF3MVKB8gtt1sI2MMi50/l2x5W4yotRONUbN+zqD5uuvS/ysYOp1GuuuNKcs+tc77DHSsVUmLdcZZiCmQpNvB2sX6jgw8jF34sZZ8+73hunrVEk1T05pVT6DcnrPkbil9YoVRLsYxCkHB7FPw5159rS0fQgu4lu3L1jHDhta9JjSBQdzjcgyZDSNlTJywfY471wMca3W8aXbbu9ry5BjI7hw9/3Bncp8NPAh2QoqerqZ2kQF8MPwRBQYikKPCs3p/lxUll3/4wu+/JpL882ntXPr0Oc+KI12EmKOu0xezCmowv/X6QrzWRo1VWrnKKWQDw3RY8duV0MSLbzWiSWIRIq30qMPTX7R79vJyO+YA80GmoNuf5DLV0m5wzxJBpdT2TU7o8FMZtH9Ll2j6FGDwuWh+9SEYj7rB/4HZMsrX0oadYzQ7bcB/LFJI7vrwAZbYWPyjyVuaunWizGCj+Y0hGm3tLEjautJTWduIqd2hEZ1QTQHjJoxDWondapkGpGmfBb4aGhYzsTq8klwYEsI8oRyIjFsR36aqFKePt+v7WygN2xle51UmGHlmwZlJeqXKAxmupXuJlyEglt7QOqMdQXN8jABR1aSFD/um9mEDkEf6lQbYUUBDkuAUBVj1NYUlR1VtdRvos90iCzJHjT2SyROiEMDB+yVBirUgIfZSVErukkFgQErNo6OJhW9jfNgPoE0BDg4Nc49IiejvDRaO3Ta829PYFjURZVS6kEt9BkUvQ+J1IEmUkD40lpufU5We8bZ+p3/1JOfV+xt/tvlPORPfwKbFi8vPuXj3oKx7aZ6QaDM90FyqKBu5hIT9jLwFO9AMtz1Zeer0NYisQizDQ9X2kPLIZHs+uXALdBOGaZ5TrxRTsyXlFBvRTvF7eA2SbLqL1SjXqg8PT/waNd1nNLF11rsCX9/ndZTYI9r5JtQgecsA2+CyC2zzd+l6t9LzXH6aAWKlj0swRYzfTzuhmelibjRm31e/1X61FmLF62tJGGbY3qmkPvFephv1hxTZhTiItw3dw3kCql8tmc/9BxK1qXkXLc435rVfyH9KVThWpw6VGVBbFNcBszwopnhMqnlxb3PNvjeEhCOwBcB+734K5O5p/QZwnpMK5dOEkUr15q9icqLh/KrEHYBVyM/VHRfAHE7SN1p9PFQFZV+yabDOdNxdu/ln2qIK5ZOdzcvUp7gVU546R0f29ddlgc/ORP47i8MLrUTSIVahkaveoqoSN55RffAWb0Lhi1UMwfJD5Zr+SCcsOtrPCvOxzlX5ExXvKMtfxZ3n8fkmjAqYW2rRvVWtmVAOjXQOuyG8M5He/MXX1pOXGkrCO/9NN42IpEGTjpim/CJoBCvFi0nu0EsDLis7tz8eqEga6HLZ/ruKfTj78BSsDyhDKZLN1vpelcDDxTKVsmLHg8saQIY3dK+BpP7KAbHxnUSUdtdC3eD2g78l/k/CCkdwdrJtp5x/0aI7xPQfR43RsnBzbR3+srALNBzMmtQa82YDz689/XgWCuNqN6rDJJ8sPtlS5tNHJaH9IrLI8kcjlU9cZ5DcPUfCTQw8viAgqgDhmfQaims+zpyVcAOCE17bkQwuPNEbVbuO1K3ilRgDAwoVNWkEzkFhmNp4I5lPl7Xs7tv6kG3hj+FGkvIlblqcRrVyb4ApxAQAcLFIVTsPqUds1sNpFjwCAFjCK0Eyjl2k60cynBihvvYCffOAHU9vfRWVY6Gaa5/MEKwBo5/c9eHrv153RozaY1alEOZ9qlocWMn5S7Qlcfzq5BOr0OahzLJkpwgUAZkBnFwvPNSxGaeehsRs/ZjUCACeHC+HYfZ+HZDdqj/9O1uEb5+zf3ZNNvG1uD01lAACkFwTy/85Nnz3N+O1a6Ma8ozE/OyNwVMdkR8ngUGpxPXSA2yO5+0oOtjP0vcAZnv4Tj8vbQ9O3AADZjyiLJ0I25kmdnki45zTJCuFTeyb7dB/4eGdZJgAwQcHNC8F5uAbhifxpvyOVQ0wBxUxKhbYAQAmrmxkOVjfRHqqxr5ZZlwBAi6skR+KegSD2fKrTD20IiUfH7aEptgAAncx8owrDsGYy7dWIqccaz2oEAErCCNHYDfgDGv9oEMy8C5v0cnhpmlcBQDeLDc34HP8KWzNtLf806M9sesuGlPbSzGuaZgsAOMcmvswwsDrJ9kNl5Vmd6Y0AgBwqJGM3HR2z+PlAd8DI2KW3n1tv35RwFG97aCoDACCR9IAa0ybxZ6dwA67IjNV2E9Y5x/4W7m16mOolgzuzl2Q/QPT03/Gp6e2h6VsAgMQsx9OY9hgHo4gbEwdorLRn0di2HzMzAYAT95JwAT73274ywc3jlsM9nMakpggXAKgBnR4kPCg0Jva3TPtKY9u+GZcAwMpGtOfVu6b7/OJC/2Hzy2H8kXIRLgBQRmM6/pYRPmlM5Mu0jzS25ZuxCQCMuC1h0xW/+16pNaHd/Gl4f1PBCgDWWaxsUHklNN2vzzXCPu++v8I+lsaNSgVD03EBAI/ZtSjDfVhVxn2wqlmNAMCgbw1yhYr2HGpdJbeSTSly9ea4JOBnUyMYT9L38dXwBR5NvRUYnb4p+e+Fw/ckmLEdHCRpdA0McCUduiI88YZdlmDqYKGpC/BEfGpzGU6FjrAkx9WAI7/+6elQaYP+TFR53lPalj/tesHeR2+60JzP4p9TcM99g8hQ9622vTpFX4Ba5q3iJm8BMWeSxgE409lKKfbQv+Lzaa83WyTbNxHvnZ6CU5m5MRUtEqiRviWj7ajkFtYS9Fu5+4xlFgTp+xhvznABysNNL50X9NI3g5zTu3KSMNpfeCtP3vWqfv5C0eP6H/v0hc8eXU9zJKcAGWGAd9f6Kn7CZjfCwYFChJTmWn/fGP6OMEQ1ktcZjzpB/e5kI5c9MdMxmQPpsfA+r1BXo+aYvBROGfs22z6h/nuzOq4BUtWgzu2R94qRphCDSzMi07QNXUslo9eiiEz8O9iLAYpMOo5fvy7fY5cXmBEZ0b87ccXHZZDxfhxYE2Y9BnJNpBvXnPDvq4NISJHDIwz66Lpjvfs9joM/YuW7KUHs4G3Mk4BXen9/PxKxg15+z733Nj6Ele+c+9Agk3QYcir3bprV9F1JokYoxJDLIDsPP0E7nfVRKonAmERl16T9+CfGCOD1OBmBjG3wS45lYdpgBYRM7Fj6etMybonUtiFSvLFwMMqT8JQP92iY3gkx4VddR+j43Vjf0832G2Ln4Z+2HmvPJyH8/Gln2uTj11lAdu9wPnm9ymniYAev85kDIgEQLWjbZk4CRAT7kaV/WYu8/ws57JRGlJNZyUtCrFE0H/iYKtLnZox8w3PmNwmDA4H/llN9yARPxyvamCr5npubvSoyNxekFVlicjxLSEF5PTln5f+IzI36dZm1yXrRod3iDSRnLnj77Hvvppzt97L/BQrYigo+rn6QHG5MyC9j4gK0fHUcTd0Pd0AAQIZ9QFVOS8er1kW/asbFv6613Hnde0uo1Ism4/y7hTT6x1ju+7hfblGptV+7p4B8Va7sbVcCTkiYpyd6v+XdA936kwXAo8lyT1VOblKH3uwIYIa32HJn8nwgwkBkT3Pm1nSC86ZhDsosWQ6xBniUsPFKYroCvg4az2wZnQ0ZXSkMCEklYNiiG0qXfyDj4K3e9FfMoVo+xFWoRltN0EU9fjuXk8EkaxdJdbGP8znNfa6Lf5zP/nuHaW0lNOelBzpC/NXZhuLHaWxiyaWdRPz0up+mN/qhHDlr/WMQivK2P3JoSVgsOZhYcHE9cAT9PhZQWDnvtPhWtlU6BpFr9sx5pzd1vAfvRUCUYLf30hAkvIU2WYhAVC3XvD/rChDSGwpBCEqct2OAAqkWFrVI3Kq0q47IPD+n1x3k5ZzVgB/ccA22TUtc71MOXtIuPabpKPu9NvX2IwlJ8cv2celjuIuGUfii3eil/YgCm4eElVvBsOwirEkQfumG0FzmoTj6NeEQOQfrPblbGL3240vDak+qTN6TeXv3OV24wwPVsLOiJTF5SJMxGW1APx4LAqkpVKvTkka8fM3IK+6PX4zmjjKKZBF3B3MKCvC4D32NznujIrwqnCv2PiC9jTHuypEzmy277bVq1CRzBfq6yj4Mdlg59wyMIS9xW5GA1Z6yAEcWHfDnc1MzdQ4XYp0tuMzzhDqt+WUzJYlYS5vf/LJtTTDa4G/HUr+isFOjtyzEwjV6f+zqvV7leM/Qh6R7sOzAEH3y3zbLCaOKe78oAC2NL6GMusCxcbVZjjYK2XJg54VQkxw9pqvaM3fwDt6ndFayZQ12pakDkhVoAHfl+MxUZgDAvUlDkxVe95hpj3udoQkARCsny+ewhnkCC94s7ZT0eYMt3ZU0pY3gRDZqD3XeJnznSja7wd5m6nWStQ6CK2YGACj2JEVS5vjItDuYfHst0AQAnLO1I8u3sNC5Ar2sT3L7xpDdvKcS4STqVnsmqpjfdCvZuk7FVAC+W01oiQjXnryFv7XTlWxNr313mnpZspYhM4XMAMAsdyW1XFLYayrtKvdYoAkAXGmZsjzE8uQDJIiKLctG1v6+Nz9vC9gHL5Dn+q7w/11GhcCPQ+S8Ob8KzQCAhVw11BPqanfm+FyrZEltl+BKZmG+DsI5W6OS/fRY/m/g+I6iR73XHhgTMKyQ99wM3ezATGXUWG4Ls/ekEHlcAg7oNtPd5Q/vjkpVFfWFdns5P0h7XIhihGY+TEZCjeeC6+4RK4a2jLOXmZYpKaDKiCq8+kWCYItWfo2dogfHeHQaEElWwIOXs480LESyaI2jaURf8rpjlwmE3HDZP/E4QQs6LpnzSxweCxyGCStIyNw5FYKE5v/uuYC03IEc7QCljJTp5VxZoQTB+ug4Na3j5rcwwCkx9+b60gzp0ah59eCbvbxkArHMCgypOUMt8mij7C9TB5GiqMHOLLO/h6Yz+2AnEUEizTqW3cVjRSMWFY5+6YDo8A/sEV41a9eH8s9DuMfcce8nqDw60uQ2SGhnHp3W6nw663BgYVqjAbeVQ62jl9aliwATiSIOfrbDv7yjedTLDYaXzittzO2asgvCqwG7NgGWzhRhTnQHZePXwDoh9kG+qEML7x8fB0Z1jrxU3BDxFThDILgSIuwaR9AgT+VjcDwcy21Sj2ReU+BIrqi78XJFqQ7skIGcOMlWfBLubUL/2rXgXbYUEEoMgtw7TKUH7HcPMvUvcgTx7YH7txHDv49V5adCwGYxAwAjP1eQ8FlBL758t2OyU4WyNluUVq+XCQBQhtnp0mZW8Qed/xd3l/YO39PrBCsasV7Qx+rzPs0nEOakHsObmPHcIkNnHX78Oq3APT0gGCyjCh4A7E/k1DMnO5HfE8SMHovb9xVueHFbDIf6pUlbhKP4Y2gTqvzHWkH93GC/f+W0HqnrVcZBaRK7FxaavUlcndmNLWBd73vnj2djr3t9DY4poQIBhf/vzn2Tr5iXznm4ewOJQ780vhzlFLOJjPD3hwFCAbitlDcx3PTWT3b72aOpEjuTtrakJmSRoyZ6u9Pa4fUenZWeasDRShwSSmS1o6yTbBTbn8v9rTPr4MKsZq7IhQfGt7WCBrEurgIbN3yWyVfO7Ois/FeI+byZhb6uf6KxqHuIXltLy5Y6gZ9xfr4hlYVEh1V3PlzMgHu1XMACLliKysua1a3w9ad58P7zY9UTACVFhGpjC5J1q9wIYhczAwA2VpwRTkMp7VBN1fYerLBIEwDIQM5l9y5BbuejBADuojmqkskdwMYoabpqRESXzx2AwhtbBg+2X1bSXVpE/06tcgDKiBAYSk33xH+1d+L+I6Sbz3iZEeE5fcoBKENCbNxw3aHzZMne/Y/32w4ilx8RshejDvx4NZ4RjNdzmQEAXmA6Z4SZKooea6K2t7CGBZoAQIun55x3v8s6UmwSAGgQFc1q9y7d69jygZeODz+fi/6/TZmLUQd+DKJDOQoms8wAgLFFxeuvmCLJuGPzU4surD8U9tAWrWlPab7r/DJRjf7iDy98Gctc+Ivry0fJaKi4gQipFbG1L9RgG9/dbwq6FLa77/5ASn+JkxpgOoICYHh5HcepTfgCOO2G07SASfD5jVvGyUtiyXTG5qAvgKjm11isa1aFDGH/yLiFSW4RMuQQlP2CblggAwDZIxBJDtRKcAde9JhyBs04V/5HOxpSmw5Mi59Q4Uq0u4+y7smX4OpNL+F8s+GJ1DxDaPaAYFynCr+hosMARd8tOYG6umhwrv8JBOaENxu49yVsDND1XdH15ftvcjSnHmcoj47Hi/rVnA/2Ey7suRmidKhmuR/Eboy8taFtqEj9o+cxso7i0YWks3NP6sIrQBRSvYjSYUnokwUyVEL50C0GiZNtMBmBTUswZpmAwY1niUPvL28q2rpernZTAICv1cFMHIv7oDRYB3FUnr+WLzwsz67ljpRqtdTKD6LhVt9j/jD1B56VjmBA8FivGV+n4Z9pWPMRDyzBkLjKYPBgHsT+SBuYhH7hsC2Gkbw4SvrPGJhyQwuEhHRgEqMPtNC8Fz1BYWIMPs/lgmt1iNNijwke3SpWp6GOKR51xZcp+0F6cJ+trEhc/zVO+e5eWXbWDgCOjo5xLQbWzIksVgqMpEuOqEx0jksx//TluAKHLW6AEHbvn47ZJ4qXEUMuDDho6vN8+TKNdmDV6ObcbQ95XQal0SDBL0jQueHL2Y3R98qq3SG6kCF3j4MbzAgQAbceWCnIHsJUYC78c+Oad1wAPP7RrtXLbbcTWlPu+x1csWuKA+yQreb1RvXul1yGCTbJRvrtQlm1gOiEWPAFC7JZMbZPkDglADHcz3RhhfTOrdB1NkIjrEjZwCOZ4fl61rXrEpASY6UtAm87w82hEgkyKGm5c58yoBU5Y2a/+9ELpzy5KrTPj0wN76VXBOz7J+HIyu9EqzDmHedU0314lcCQoJjPwkW+PfbCWmwrD2rDEhrQBAxJ8+6HRhd7yABtGewmMsglsWC4nMWXDRKNI353ZoMdOh75PsxFnE8k8MODVJIPVNF5IRQ3y/DGTLt5t6G/MlPztfnnwqvJI0wrmirOiFHKmkSJFBJSnUT8k6eAkjGgQnJGNsRAus9w6Xira93bJ42pGm179lPK0bVlM4IhooAX936enot2bZOIMK7UI6KlA9xHzvgdbzXw7sX8QeLzPDJDszwBIItlaokP6oOW0yGtjHixKCdXgCFzF/he8/HVKHVETPsLpmbsMgzPOx54dtWVjP4eZ9CKyssORvOWHXZX/trnIem4dih/lvHXDaMrSgtXKD78bA1cXlhVtmor27inlrDYL1IiBj9PYRT6ZUQbBxUH5J+TjnCEjS4Uo/t0v7zPWOLJaD7uLRPjN1U8eF5+LoMW9PBthjshmjQXGr4/AodvRqEM0rz7afDZZnLuv37VTQrb+m7NXAUfG8eSqsdbtxmwg+CvacwAwJGzC3/FFP+vcYmKU4ug7I9MuxpV82zBU5QJAIh3vrWfrqu36gH+Gna1U5vf+B4F1gjAtRm0Fm/3do5efQk3FCMS9wGiDgPiOYbqSXk9T/B1o9v4c09koLrcdY441HQFwFYdx/o3yw5TmrEJPxINd94JiPqACBesXHHAMERQkii6CAFKEll4fn3zn4s714/dzF+S0xvaA4Ddsqs2N5e4UYUPuoS7xtLzFqkEZ6AhigxDwtgfkKw4wLbnWqV2HnL7W4BEYx29icY37apfA+bDpB6YeC7tNKtDjKvmRjP+FcGHI4yeOK76GcH5eysw1kP9l69w73X3T8Llr6O8bku2q0AfdtbnSuL7mwl/eZ68PZQASedVbz9feOcDeONG98HJR8nMxWO3b4+LxzKY5A49Y0ASCf16rJPugSk++u/A5AGw/Cxa36OKOGjPKOjjrKZ2bfLervihU1+BYDJvwGE3jL7ce2s/Au/cRwocT8Z/viS9dZin6H8uEn13CPHvgk6nF6SbXQ3I10BTnI9nWhBY9zGiX7koQxqH6tqNSZ+PWxVqAO7GlYN1WxdWO6+Cs5cKrBuRsjaohnqm+ln+WH3H+j9U4BanBkN7RVHXbvBGs454J4kwGk44mxuvHpCPBvkw8lj0J5f1om7S0SOHib1c4azFlNOblHAuuPvqV+zmmnjor72YD5uCrhHjyLDJvfn8kCu5Eja7ytUY0DJFUNlovKzR0fCQwWQ26PWN8QtYJebwgAM+cCxfYatgCGLsRfMAdV5uGVJfdxKcwDUY2F8XtS/fokeZAXt136Vg5BpSiBaF8jhecxrx43v3pmKqHHQZVEyPkIqBMhFSGA6dEZuZdZ5AFHpSsh4813SlRkGC5kacHjdYXEbLOsnv5NfzJ/SNjVBwGkw0K0P2MvrymtOHa0cfzkib7r2eAzuWFf4rr+AfT3U0tT++SUxlcg8yYZmQCZdl2umMQkFtiyxygbP3baOzZOIyoKpx3z5lc1JPhGvQXe/CuMKaYoI58u33rb539oU0r5YBb0UpzMyAN0QDy8GnOZpd5aIniPljur4O7R1iU/YmJfHueCRWxHmhsWzRtV2zzU4EfeWuRq7ciH/50B4I9/S0hr6m8djvcRdP0xcHXvCb0KoNVNE2Jc5/rf94W/7Quo0SPNmEg/LNBFIiPY92PyWQOVuUEvAywHtS8Y2K1qZhE0RfAs99yBN2XOHlTNQLj2PGXgcPnhYjcnUlrAtq27yR+ZrEJcqjwBkngMEZl+8gu3ZFYQdHONJZckKaDKBejHNsRhiHoQF1C/LPFQteegi7WJW63tzF1JOcIJaIj4pbVensEJJgRehgh1HCTmLdWsC0625ew/SytV2WUZ7CcF8blprwU9eLpRFGWgYgxI7gxotmbx7LGJoKnhwtLhptHb0nd9F+pcRlt6aFMcMddCeViyJyDAEELCH2314Yx2+wxOGCfe+WyzSvYzEFiK2YU77zwVPFMNBt5En5U59gNn6c+iLhxx5/Nn9PeQr0Y7pG6MOfW7E48EFXEj62Xu18d/gd3hHnRCHPHgZvDHwdTdgPYxFCAPHSISK6IDCGpiuSC+FXOWHB8W9LuYWjbIExEDs6QcfmItUvizOJXMMHanPQKA1InIlY3nv23/O2YSodVKR7Ai/TzQXjjhVA4ktNdpFyy2t9MshZEzBPcyhIbLDcAO/UR0GSU9NP6bd68gNlw++ZucnfOQv4xP+6tQMegd+PUi/K0gKzLfhY8T3MAMCZ5C3melfrzYTHTaGJxV4fhHeeXexje5Xs5dBMAOCYz8gr2BPZ3A6Yq0Rv1wzbbvUDAEcDKQzlIXBf8MUNTEVxpoBl+ssCjOgJdquzuYLx2vfVdVfc1bKkmoOqCktK6gRkN8x2ALgKC+eAqjnbO0CY+E4TUM6KTNIGEQ3f5j7Nq4NpA1hnsIdgPw/9O9VAAii5fzi6x8QfCtPv7cFLZrPt0ivdfxOeUxckgCISxTZbqhut393FPQAtZWI7osch22ifVG13dRhgUn7NYgYAWs5M+ysbLFu8PnlUdnB65LjDy3WEjws0AQCCZvZUmwVknae3xXpXYT8AwIKolagspCX7FAhOGscQlfo3A+EqBmMsU3vngqhWOXanuSYfxPZcIP9gx1dmM3BZWvj3cUj/cgIO5F8zzQAAyzmUv7KfY4szHZ/C7rZFtM+Xm39j8AvKNHPwP+Oi0bbK8Vwn+kerKwJhQ+KHj7Y4hpW7CqJrPBUsNw52c4K1BdG917lud+PvbndP2CdU/5t0ePAToBNcCEVJKiim//Vj6rfScQhitZd1mLv7mHq21wv0pKBtjlt9wvgm80i5bPVJ8GhhG97qk28Zylhoqy9YLxDB8LzTF/H2pSakdNtZZwbzW2Hf6ff4/Z1d+/dyni9lTSeFdXhqBGwaMwCQqJac5/ZXRtjyVpUny85uu9hideuZnwkAmHf+HBncX7OGcu+9Hw4zcByM1nf2j4777A8qS7Ks+3UNYzscR9dSF3513rE67calE+br1depxQBAWx2PeBklO/Pu9svqTfxU8T78nanq9qbUa5VTEtRSQP6SDucaaINwFL/RPvydKdDeRAQcGCiMuKT30e3bzh3aSHsNLJZ0hoDNzUnyDMdN2zrudZ6UGaUCaE9VwREAemRkc1IAU1V5czaADCwq0nQhvoWO3eqd+fJZe5IXpKc/K7PluLiewI+tdFt4f0o7R5M9XqFzO+nfy4EZtGNV4VLxriJmAKBbftOlJ25UHb5khbx9yrj3Xhue63mc6xRNACAni0YqbXQ2jLzvB2g6lXPC4Op2QQAQNHenmnBQcGYWVUDZ9kgrAGXEtBXA9n6MFYRzBY4VJFm51yF1yWQgkK5EKQh7RrkMM1Bg3GFxDJgsZ58F5hTftwWmkxVdCToR7XTsrplG2fm16YX45MTKbB6mIEgA5fcPR2sduzXDm1/J9ui+XV58ujJbhykNEkBBiYKndQhXPCJPHx7g08pgmhghiH9yM08b+WPJqoVUz2IGAKqb4fqscjZY3uHdnpl25Ge5x9op0gQAsBCNaqOCJLlyaZ7GpdAgAOhAMEqUBamSfQSkLY3dEET9CyGQYpCG8KT3AlEtd7zRTvSde7wtReuYnRVsCusLObKAzfHCXDKzIE+yzDUSrnbx7VEIbMG0RHI0GEfFI575S+Jx/trmDC9Cq2PEV/wDxqKG4Fcu7m9yPT+zM9n4xzcl+/kTB5oX1a48OOBTxhEEtYuJAMsvTmbAVIe8andjJn7mqrUyvFcdnBU3T2aw68eawbk30gI8EuNXCe2WlLup+Y6UKVniTbQjSvCHYG7HwVJSiZjPR5WCKS3SsmPWptj6/kM1nDf1OvdpJT3BBTCmO8rIAhhmdMrVBSXdcx3/xsMgfIP0WdeXeB4bUXURFKGst0kf22/8dsVHM9K7OlTyHKhYFm5essPqhwmDKM/uAmWJEYhcBnScCqPKsQE0uX7GCVzPiioF/a63jF6vbLoptEERaHz4RK+ATU0uK7CalIoKTIbEdBhCcvmXWPUFIJDusC+CZFqC42E6nTuUgWGMgtw39Nofe3T5pTz5CuHk/AFn7Me1hCYGPElR97goH8knhZ/XUldd0giuiOuCDUrpJGrKZ+me7m0IVxheudyK2EaNgDeNUMzpOf0CUeKCXgJfY789NzVnZRB8pw2pUCTnwhb//au95hMAmdBJKIFzlL3mUCRZbn6haLsXDYxZJHfDljWMgZWeIK6e7IgiJxXzprJvP1knTcSJcmKuyFDUx//D4A1uIfHwcLZHKRaM54Kxf0dsp31Ps9Hrf0FwlzU4LLd99tzI+qfLY/kSYdFMwlYqQw8OmAorGCQWI4sRmmf3xC4C1dmR+im0RUA2NgsPKRaHTVs6R39W+9TnVJfsk7/ZsysGrg3UkcRwcZG/vDNw4Zf1rRgIrqopa1911gudHd/V8Yl1AICpOfjyxRTTjKPFeEiJV/vI4To1VglWew6J/kkTs2I4P+UadmjLu+qDDq2+GD6EFqW2PEeW1TC2xrPIfWWoY73FsTmTAHfCsSszgdXmDhxIS7T2pMtzC/JZwSazDslVCLTYl1rMcQgrTF8nLZcR4r4kHiYKE9edCWtiMWoyUZwvE9qmrGsDho14h5LNQxKGK0Le9Mm7BkxsJCxo3fCeYAj3VhfcKp4CNOEDoAbpt4XQIBo85H3cIOjTiB8b/G+rd3TR0+He3J+qowUhHfSt3uR9/bfpy6pa6jbYgIFdOuU9HagETUR1B/wdtGXKx7UxQB6gvt1hiiYOZ/LgAgJFIi93Q8tA4c0QnVxdEGxRxYZRfF+jAg7SAVzng8Dw7KeAWxOv0LX5XMsBJCXBEsm93+sBkw/RIECH+TQnlmgPeE8Ulypvda8MhugtNphidRJLiQRoUpJIpMrUD/9KYNVgArtbrf231diRtgS7N72iad0SGAcd6eNz8efBi3zU1flHAJFr7hLrs22JpQu7O/JkPft/EXszj0XIaUiGk8Qk/NFCXuneurd2R5Wl1mVyeJ/UHvW2br/ScJXZguESi+uTpSWA19UatocuXGCIcHorhXn3YBv1ubLdUP3cTCwBUsQEOH1n7gQ2jHTSk73/OWGpwbpHcgQMqQ8dqwUH68Kpvbs1JLCy3IHIQcJCQ+9RNqxrAFpZDN318CJE2R6Ke708Ihku7AFBckifIMq/E77IMzxnqLgIEb1T6GrM/XSSd0tpLSsIIJHWSI1KxZi8vMWESFLcVWAApTyXGbiW/39lkCidqAB5Wn65D1yDlKVvp8a03FEyU5i2m8FRsVzO/jAXaSMKiUTYpCnDUOLcSszPvPtFDr7RjyOpLhkCpf5E5Q09nkSmlbjN9dXvPwj1rnw+iRZNPLMWudkriuBmbWl3U/tRwvRQYrDVrIcWOxV+TZWX2y7vDNOlnTxBZDYJKCFt5cnvgyIX5hKhDcIQ3XhAY1CQVXG4rbSed0EESVyyqJxGAtyc9kl39pDdFB81i3xDKo6buXxFY2W30ycNyF3H+4I3t18l3uPc/NoZ9a3Bf706q+8F32iXT9d9i4WuPlrDw1EIY5/W7s3/HM0lNwawu7elx9IOTj+5h+VW+Dq9S+o+Zr5x2Wlzmr3e3Imm7HXGvOBvg7uLi8aJcgLWl721X0ovBZvpmJHEoPVeMo1Rg0z19WYVWn/kTEt5T8INo/Ohkrp50BoB6fF0tuX7oskymQ15H/weT64daUtGvjeXR/ViomLAFYegFPtP/o/VbnPyiFtM6Y9G4s492U3qkM93SHc1iA3cp9ARmJUEmh6vVjeh7+LeyCF6gABdFwVwvRApKwG4CILJGapmOt9yditYx9jp+fPFQCwIaOoDia6RWZSI7o7+XCX4m10F+4fs/7/sr8P6rt/g8P82t3jzx1yMm4f/96v8w/ttGJ39AW5/C4fzNwivPjkb+h2M2Ijew2PQR/vRkIHzDwhlaEVuuxCx/mRqtBoPNyZNaDKzwkp7SJBqffcb/3eW8AVrY5nraRL/nvIOXNkYyA7jTWdyQJCOWV8/YwNuTcwVpGhedT8Er8OJaxQufdM8FXMuXn02zyx3ZKeep6KK1x2tyrFO5jUn18CN27RmbuBOV38jN22Sbuj8pk22qnLwaHf2+GqMDZznJZt8256zifJo9B7fJQHmTXq/oBcsNAb0eHhvo0CMdZ1jQDOSoN0LOWuUlYggPahtxKhsugjY2bi8MKZ08FQNy5mhLKADLTzg0xWAI1EptpfWzJAC8WyOkJpEg8z0w1R407df+c2buyVRgaBFB0RN9jIdj03bzCZnQLiLgnrRVQ896La4QOiQBBcZmCM9IugVhZBiiDMvP2DkNie0HMOe9sIgMJmT1xgUvzK6d4gnTeNp+nqc3pP/BiJIU/o6tC0CawsZ8jRP1fr9Iggy7DCebcobhhGKKuaWVGQiRdeG0Dk5SqNxHiuvNyItdiGuO12eZk4rXW7iPmWeqgzj1XQOln2om5/1UEBjXZBL64/ZvTq6oml72nGnNQG/S5o6LluDaI9rOqa+i6q/4Y4TtA2mW1l83xJxm/F1meH9P1mYgA87VPhqVIGq8odRnvkiB91VZn+9jBgxk3Pn6iqHGXcFwMRDQWdv2UTDaR7hAFsXu716fPCK36PhkivusNf77NdIdSAV9szBqxNBx8ll9wStrW5IfeoeHB9vHO6YsTh65J6WFv95yFXCkWzPOaaIhinmmqIytfBWrs+rs+W9DcFLcr+dRXDAFQ8Auiz97hkkXghHQT3+NDTdIk5Rep+EXvDxcK30NB7cqT/Opj1zry5JCneHsh4Wx3+dibh3CP/9aXP8n9FjehJTlqmNvOZ1xed2g+PskqVZmMQ80q6uTi+3glX+GvPtZsLxbo/+5p5SGn02gwMxAclVASaJPJceIA2QHm/sx7yPgP+QfvGOwNNtwt6HHIDiuSPYheBjOn1guiuRhgvEcRGV5eMCYxlhs+92mwxBwIXHviOUNArAlgnuxIkxIEwmm7jnvcD7jaBQk2kpoz6CvAM47jUOAVy8hdBbiWaIeURBR01icp0G7D2lCHSursE+0k6tsTZxk4bn2rk0xCHDg+6A4Zly6JyEFv4sPDMadsQiZ5BrYaPobfTSCOSfQQrJ2u5SbJTyrgu+h3hcBUIvcKuAaZmFjWV1JxRLgrUNhM9FxPIUiXHDj9yWYq5VJNFtExiYNVjPutsAYMSrx7RL/up5vSFSEuDtI7CwJrHZ6OiIST9bQ1oZexItREzQBLtkYysQFT8eiQ5EyWkUbmMYeKo3J0wOG6g4kD4gzDvKVyPquy0bMITYPtrxDpE/7GD3pTvwZkyYAXG8d/0ew5BRNXq/cX+Q5Nbh8SOuZp5Y4xQnBpu8FNn8YnsOA/6O5blSfIcAr8uJWY7UZPUkPEVJ+pS6kHKrw7yc3dJhqIaYbxyBfQWxB+sJJeA665lmUMWDZF+T9pbMemEnMq27vKzNBgEoKwWIuCaM3xZLZBf/am9U8MIxsV510K3CKzKOi0F4YxXkh/yxuvhF/Q6Tf2k7T4OhljxQPAbrAvr39F9pXIGdfcd74S98OtneFED2n1bpLIEyXJkxBssQHEUbUSxsJKqWAo8Y+4k28WiZTavY3dVp7KPpsAVwYTArebSMcbmaD50rZcyOaQCBSZDdh7IMa+xnS9d/PXBfHpwvqdsXGLb+tY4jkCNkJ2ZkAxDT7//vXjRKjIcAV6H7z+g1kldYHN+jteubGAvGIAgQPpnPflvZbjhZ7jQkhc4EvjuXFGQ/Cg84pKgdggDf3kMRidUuWbQa4yrA1aSDKUDwnReGVfWcQyxtQZ/3ryfwnVGwgV98K/W1cq9Spjgla4l6Hz//yRqztz+7880W5SnmVZdYIDw1x+vVriF0s7pMUMXw18BD1j/IL8ZbcaNK2oUBoK1ZJMkixTZTEgbo36/8ZCHBhPbSlYemEhUaCDiRcUDmxn6R2hoT5kA/uv3ZUHYKXQFxzfckDT4s6C1+jnb6ZuK+k0wX0VUpXh76mmAVG20FwQD+oc25+rR+qFN6yBKxmPyShM1TCEnXf6VL+Rf6BlqN7PQ7Y9YBpG2mlVvpfwbhSLdq7rOLhBQPz7GMBqfV0YuOWMMRUQVwv04yHatHJhFJziU6qiB9QOZUi48AsNsBOqJqxDfPyKnP9dmg+bmZP3H4b78R63icxjduvmU5GvjYeAW/5PJsk3kmY71SudPh9Dxh3yeEdp6w74slQw/kSOPIwL63A0snRdkJSiLlQr4inyykVD8dPp8iuAvn+zS/p77eZ8Twtvb+PpkLJOs5KdmqhBbwj7oBgIJVeTEhzuiYdCI5OFe2aXbrzmEwrfCWXjOrmK2Y9Y5eu00ddbf8Jg0Ku10EM0TIbXQXqfIEU2nXsr/FDtO/2wJX/OE/AICiQE70s2wwuXC7LjC7Nnwcsbd2tHH6zv3JJ7mbroAtoqxGJ8COwILBe3NgaR67A7Lu/20HAFBVy4UL//ahmsuFm96pqfN2GsuhdvnyeEAPqIWmEwo5pVeZTiium2YeAMAeMEjE3RZQFDPTB7Tg7OEA13LDhEA7CdRIAM35RvUEU/F39MIqyfQPtNJxPab+/1joDsB+wV92Q2INXFVQNaYSKXV1qgvv5/Gb3/1zZSpivZu43c9TbQOoBpM7ufmepL+jF7YX5lM5BZ+sWD85Keo4tV/+qthTnO/qhL0yF8zvv2bcWuCva+L2SPV9H/G1gq3j1LcNYK/NgidzF9clROgdZHiH/ZrvdlcrPtNK6zekQbkKwluogM3qBgDcvga0obSul3ya8bk0teldloOayQpb7LH9yK0Y2mJP8eVJXBwkXXER7RExYaO74NkTuJLadX+LZNO/GYPc/vAfAOjFAe3RTxDgKNymDLyM4sECn+hvVMgcVIwCHBfA1lT9OB+iEt/V7fzTN96nTcVZe0tXuDmqXSpycHgTsFldAMDZySL20ch/V4qpdx9G6tfPOr0af9aFsxU8z96W9WyR8vmRFT6jzZlTQ8OZRsGZxpICAIAJ4C2ywm9DdL/ibTifcBlatKJ0ANm9XAcAUEK4sYVczCu9JBS56T5DWtPElz7YNhXWRZgra+hh9CYOLbTFwVjVyci8uF3Y0e628ivXCgKBnJtLWWznyatlSm2b7S9e3Pn/tWuVQx28bN+OVJMD0E7t+UhTJcj11vrd2pvbl/yefio+e17d6oU98dOeaa1i/dIKN1kNctNVVpTJ0atiwGZzAwAr12v6kTJMKTcxfCAnhrKknJZe1pWd3mAuxUtW2NIU4cfxFZM4r1xT8h0ncdJBeWYhAgARlrWYYNVTMNFIC8p50Z+2gK2Bl/0DAFoHsCH04yT/LMApVJcesVC5oIYD9Ze0eJLslTnS9J6jjzLnIl4tm8Ar4wLf9R0h8Kb0SaqJLBlssYNu5h2nypvQ2JG40jgcVw66H6hmDn01GkaDkRECvhZvfs3Nq8kSl81d1Rokg2shGMyh4TUWcdXGIhXcGoSCJx8ywa17egU13y19d5qdpi35/NYhEAzGQjXEgd1IA1dHGLgqssBF59VzIwnsQBAYpLf60sxv2JLML4wQMPRPg81UNxLAdRAA1n1COHiub6ZbYYGR/bY/5Ob7aT31VO8rJOSOoQTYdqXLqrFp1oW0gMUEklDFUD4DrGhAsBhmTQEA5ApwdrXHTngGuHChHXvML7jkvQn4hVUyTp0KuLaX5QEAxzH8JqjgtqpzvtXZ9uZJzPaq+dXtlN4lVGyfre2wgiaByrDWWaRmEdRikzoVHWHoMXwmFDDpMatmb3EvPH+W3tMe+IozXDUr3HI10hX4odmJu9Qopn5r5zUQ02WAq2vN370d7Rm/3GNPK9xSNUxIVXMZPOHo9c3rdQMAeihUwGsNQiw3M0Z27s3drauApxYKkMQCWQTqOQlc8rfKqFqIAMDI6LrABJuaDb/29wm7N/t312uNBl03/wEAl1FPb/fjtcVcQvM4YLFviG9al13B8oz+NlFcR62a4lFBeodb771JWdoJyhHjMNX53HrANLOHXVPIVex6QiEvNOY9rlGNVjsAkDKFhoJvaK7RRG43EtoFdSsNCVDXzAMAnAPnGBw6b1krma2QQbHDFVUyt5SNspUsRA2osZKtXoBiefnEurxl5eP6cFKcJi04n6IFR+pgqN6RI4tZeaGfIfuxBr8yRdIvcJwKjA2gKkd5cm/1SSPvs6AfyU9Lz+IHjNQJsWdh5yhbSfGzAXypxj5rofQLME5Fxwaw52HzKH1K3rWp19ZsZlLJExirHmJ+VWLovcNkR7yvGwCY6PxLg9zcKSQjs5tejZdMLZRCz1dUUke1kmLmJGqV6WshAgADoYsbJljV3OW5v0/IKv2bazCtH/4DAFoZuEk/cQFfh+YQIKAVT9JMFQ6D3rOMWtVL+QLfovdhb7w636CU3Rs9FLi2Q3cJ+RksvU8P6Q/Ze9xTXNG9sJcVb+DHIDokr4LJbBsAgMmn2hm3Ta+loGrvP26/lqJZIqpyulsz0GopzMSA9Cw8f1dwIbMoQ6zAhW3DWcTCJbQXxQQAwLStThV8KfOtBJXGx4lvsqUrOxmAWdnm5uwAALsFj1hIKZY0Lp2ZABpTEyeGxqJJIgLBFhydEgfe9Ovb5Rwwp0CN/GsplqmU+qikryrPYDBB1hNM4O1mBPV3dp6K17327TK8rD2W68HLeUWb7LosWWXYZYoMAYCbIEgcplCbeKHOTnzqVjNMs5ycJIl8YuL5ySV8/G2hqlxcgRLgqPYCCVQMRc8cRAAAAM6U+7yJiAIJU3v5f9PZNLE+XfwPAAyAOUj92UplVbIlN7chW9J4G7L1DbpNsqTUujFQ0ydYGLhgeV3Mhy2i/VdN9z7IO9n9y/uv9JekVbpBAHP53wuu8UcSVfZGndTMYtQk6ShdE0xwDOFgRHIt23u7DoJiaf/3rOfjUVcJxWNlOoZ5PlfeDoVjdaf19g3iZrd74L6AfoVdFjG6lgXVdqWmTsDZQWJmIWYhwzvva0k+gDLPVdJt/CAIA481NFemoQsF0yh26V1nrR4myxzYvcYYPMUzsCkM4WmmTwEASZsKjqL5vPIZOFa5ndfsmuvWTFEFBLfeynVjWh4AMEivOktkvdJwbp7BjapkzARwc41scwW4I6PB6gLS3kVRUQUnXTiP4oM7QxrrwVVO61bvj8HLsD3BF7q/4Cvacl+MLxgnM5I21a0X2EVRbQqY73Wzoi11fR2zrnWdHU2nAzbNEAAYa/DjkWpnTS84cDNxyGr8/O7UulFJn7wwePfuRoeCukwCPoRTLkKYc4U3uotpMtH2Aixn/3iDYMkw7OY/ADASut3rfxYJnHp62zaXnF6Y8ZLTi6PLSekJUjyB705UrkBpO0lfx4sqTHVdEoIKs4uBEoWmdre7wTSarurGghUl3flROwAQVqEBdssXsSgBs2wX8SgS+dZKUhW1klVaeQAAy8OragUFETc1gK2YcQqQ4GzPAnq5ISVAYw4qNS7c//y6E0sUPiLPaE4R31hvaKQPhkoNOVIVleUpuOFPM537NHGhcS6rNYAKDOVJ0FNOWVklvTX4M4LfkYEifULsT9coEzx6qfTV6MLuNwcU51JbA9jfrjctTTlgDWce1DSfWHsDBfuSPlWJW++cI1Z1GDgAkI4/vtQONzeERDC77Fq/bGKhzu0lFsVGqpRJlIV07CLQM/7/Rnfh2reKMnJ76dRs+je9IxvqMF3NfwBgQHSu6X+2UtT09JxtbnN6y4y3Ob11dHtSegbUXMAdACf6VUvoUolt+o00PqF+4tC8RfGF3vQHenfOftbk80UmHB8fHwO7jleBia6xH+/JtZBvHr7/i8eFCx97FXv8q0h7AOZE8ngxMkPWZgErZJpxBIjAwiHmBbCQvDGtmA6LAalv7LBfnJv89/XnlBgvkC0WR19DUkKpOHzS4uk67RwIj2toH2GamxqxzE1RmcDD6hZ9qPKUZoMLrlFZ79eUwlQGdkik1dN3S7AV/v4gTRf8nlQke+qhbYZJsMoGumGujD3Nb5Eb1UHqQ7sxrDktiY7UrkD2cYq26hYu5s2XSq69oSOd2nUYWrcBv360cr0H3H1qYq8TgVv3JylyM7+RmnT0dNoPyF80Macezt2H7mVGOHGtbFLOfkhuhgfFGbiRc7q3uzkSZfPiCQOvA93bQi3h38PdWgiA8iI7JyJP/diySOLEvp3MqMUIFEEmh2ypF2i6qAEk83VTTf0AdeWlKv65I0V6Pp1zX/4pgKGtssB8sE0xAH/S48KiTlMliV3a9P0rgM8/oLSy+teODNBfWbX6yDdbnPmMyOGYblDnsPSX5yPYZwNodD0X3/7TzExSxUcA8fPLM5e8CQQYn/nSozjJh361DW2hzmcIihKwrAq41KuUXR62TKz52K8xiAXe+TGLlM61awfAT47GPG+haHN7Tqc7TXzTFT+XkOINqAuV31xjgkuXhza357am1icXfkSo+oLcXXjfZ9Dp0zz19WCi6f/zotvB37Fq/dnWJowz+O9csr1717XaH4azHvxzhrsn4PX58gWSuUnyD+y8RLVxEOlrUdf9YwIa43HKiptRCk3CoGwJarXq4ZQJqgKjaxUuiqQoHCutrwDtUBh/gIlEqSWyqBzFdaW+BomnRHTjZUQ40NThF83SR0G66aLOquh/3M3F/ruYffjG1jTpo6gFykc25wugAgI3PcsBr4ndDhPR9gBjJ2OJNQhBgGeTfWDahCR9jQwdjwiILV+W4Z3c/Ln47edTcpFCbVfxgEYHaAMwshpVEhcTA3hvGTCj3nkwxjRB5qF4K1pJDqMfzj8sGXLz/gLbbaPrmlmpTZgR1u2r1I0WKrFBiKqUZZON3V3FRrjJ4gZKoZisgc6snxiAMRiYCMNthi0cCX19Ugb1GX3sacnfvQOTK33cep09AKDPxViCjQb6ylgMxeKtRjU2wTGxT5E5SuGgsKoyUWocFLs0MUq5mh9og6AV0rmTgzLbKEDNLsUCHJQ1ZgBqix1MjUbXoAObmmprgOHA7zwx2SJBVmGTrXZTC2BzZ4ylYuy99qV0ddbhyBotGfI0pBgbWa8aesarCs921ZHMdNX+ESmJ0Un2jp7wkImpNahHP60yuhCoAPJPFdJ1QUhs8BIESPVswF7Mz584Yn35TnmhpLLGuFdQ9q+GnmMVCZO8qYAUtuILKOwU/YlgTrYTtgVTZekAvsXCvemEQ3wDu2HJoIp+XpUolUsVn4FcOwoEx+77aotguQ2w5218z1jw1Xl7j+e9MuOkgpswsEh6JnMDsSpEDs7OFhBFp+Qs6X3iVvTqG+Ae5oNooTOnzVvnlp3GLKKroBBymlb0osba+R4s193nqLiPYBUP4Kzofutq4NSjka3wQbo741in6FSn8IfxPbazZE7O8WI1ffpOHDRWhyQPls3z9awUAvwbBJwbzdX0TXt1KLT+7Tvl+mpTbttHMYuPAGdap56KWu/V+31+t+5JDP6khl/lr18jda+u5jD2dNG2b+r7tR4STgFJX8MEAAiIDO09ZjpO0EGUojL/ScNVVrJ0xu7iKmuuL2Czucq67pHYMgKXi2Adbq49FwEAEAMw0eKAEbsOo/21McDBUQMgAMgN4BX9GAeUNcx0r4xcgUtvirPWX6rgNpUmBAO7gp3VS0CFUfmAPStE4K6tAnElhFtLWeViNxZltU1jyXBtddOACACyBKmzvu1x1L5sepK7XbCegWSVU1HSSZsQAOACmcU2booAoWxmd9xX1Y3B2XvFejMrQRwOZJCIHUwz4SSr6kYoxmHNayBD/bmzt4JG/V+noW4A1TIajkRX3XCqSL8lg0nfsJpzYt+84q/TWjeAffWKzRrXjZZwJfyLAT+nnX/H99Mr/tpwSaq6DgTF7mh4aN4AJMwbqFpzTAAA9ULNUj08Y7hqHCVFFf6DwA42ncoYj5g/K9OMagOEZlMlqWhk1VbTwm1a26YnLhq3wxyLlmsOohbpAK3vzwACAB2w6/oHwoZbzQor3AmxFrHsnu2qS71YlCrI6B7mNfTWP2uw45ySgaxPaed6kly/tTZ3+vU9vvS7z8GmpI5LR7CCBNjhlTIeFpNdDfTAEvJD4CqWZlAl4fwTDlLfqH9hwp55KM6lMyShrKACGlD26HLGUNlzPgAAl+DUlsFCT8Er9bdmTRBsGja540+oJnlg9UqWNZlktxKQw1PWTWdszoZCgFyKs9DIDCF1YQOtM5IyUx4znp1XzFXEr3SH2BaB9W4bmMjFBIYNstA53AIN0uu8RB99r0SPv/FlenfUKdz7oaXj4d9K11wm3Pd3e+n+oD3ctRuNtStPppPbPjplEOzGYHtp1skBOr2ohrJwF7F/Xt6r1at7NUCx7oy3RcLeQFOcYwIApAY6PTh9PFB1KYBy7bs4Oyg9I0rKHmRAAMpelEQIiyoSBQBUAIVBRDR1UFTehpIdL5YpNnnizysorpZqAwAod25hDGephQ4a1FPobAvpsxJd0GxUmS0baGo1ceuO3pV20fRpSLVrEF5yoYP2pHJFD1bcwAINREOu0xMto4GjSy/fhekL7hp6BGqFQUlzDcPkjRS8gCtE8x56YBCDKy4eOwD7ylr+EAAcVMJ1UvEdh9jXo08c52Q7YdenrFwtYwJ2d7Zp+d4WZlLbxLuwwlVvmzmcFLafxKRM4KRw5xXGtksnRdiDHjzRSbPPUyLmgZ0P5SF9MeGiqXR7hcgx+TI0G2YK4345+PQpjPP8qsMl/s/GK6Sr74d+FDxsxkh4tqBzM8cEANhq6HUr6ufedURTwn9R4KRTfkaVFqMaCFhcJUnEsopEAQAfwKAREQfjemtwHz6p1TRZYnSV4xo824gHAKYbCOtcnLvz+bjCldCMDlgw4uzy56SCTS81NW7kPwUxU+Z6He2tJytmbf7HAG7tiq3hrovBtjPCG4JwjHfRD41wEY/dkuGSBkQAcGtwM9F3tww3m9zdHXqaYpXLLotYdbcq4dvFek56+n5GQIPbGVvyK2hsMgMr6OiyR1ZwH0HMFHAzEZuEHy7KTVeyfcbgozsXnWSHc22G3v9Zy20AdRhK8uOOeaQfjM+62rk5+ktrsCNbfy631ncbwI5tzT/CSUj447b02El+Ui4Ceqe2axOftW1uKtCrmxssW3fGUyJhj6E+zDEBAHyBTgWnjwLlnfonDYCHN8W2pWfsg7KDDIiGsgclEcQii0QBAB5AdRARjdHb1UGRfq1ElKQo8zc5LNoDAFxLc8NYUgZQcWHGucW+06+CVMtNCcKRxissLW7TBRKnrj1UWgiWbKX+HP0sRKUI69cU9scU4flMvLWcs7/DdAf5Q/n2/qHRcW9TriHJ/xGHCJLOIJMMuDRZoCxtk9wg1UL34qWebu5ZnT/4ktIT1KiYiFo78jGYl4iDKtLLLsEdmpbIQFB+/oVvWwS8PnqUYAI5h51eEOJKOINkcXwfY/AIdzFZhnsao5nxC6k/TEbEVXVigiBnV4WvI7Akktd21ykKgM6aXzV6akViS7XVkuxW1rZppZW7XfjPvQm+/JoeusPSmeuG7goVHAt61Zr8dPAt3pIPAGBrF64Y5opG4FfnVXb+e5bTzPAZNCI/3fOln3NZAIDFfgntoqHU6QXaI53ZubIT03mdLl38eo5HHr/4Ovh7Q/mS3qC3lcJ2DdYrVOjFpSldVvVGJ90L3wcGjIP2vtZ745qPdCP42eiVVO21KEx2BQQiYSC5SkSB9SP6uae/Ej+RfPV1vWtepCbT05aIs2vMP7YOzj0vOuPx4LxaXcnLwEujZ6CwVShIC7lqB0WodWKxn4YAAAhaEBHpWFFGO+htvUYi+sAIvuxeY94eANC3FcRJHClgCtgHq7pCYBeYLXUmDu4C21ET47J30+wCixFL4UbxAkuSr+xNF1eowPKpAsQ+igubtdG1KwKb4+LBXfccsXBYJp/osqYXh2X5ST5r2HR2nJmut2WaMQeCXyncOWTXCuwLSRNN+B+CdTeWPYTX2kpdM88w/Ms/g+9PfBzlxNoYujQXcW/wIcsuQuSudKlTyax8gxhn6f2Hs5+zMoR1ERFfYPI+Y+RxpJteHyEP8ABnTtWzfEt0TRqvfZHkAQhxwjs39pdw6eWoADoPjadyyXdhj1+nNPrizJXvp0tAFBqXJxm56t8wFTEpKYMcFUzTxQvkSy2dyEFyEE0tXtwENv5zTBM/mEgLDDesPtxaVn8Tc/25eknSCj0BGCjQNF3fu66/0vk40lm498pD/I/pDX8u4cV5GuI6gLYwAGTl3MPcPa13xub/RAtqxNWb4caCTpeHSf1P9vyNLoAaBeRzWUW7+EyQzhNcPULir92AssrWvekdtVHwECgSNoxaQPN+NzAd7sCcv+uc8f+1Y5qcElcKOrppISR4T41uQIsSd4+edOQijahLWk4fUJISH3uiZiEv7xl1aGnuAGCLM44aNLENnT+siIqE+x8WQAjYERkzvrszeU+SKiLhIAE7tBlaFRHCkMpW2cCFtc7ZA9uLRmok1q8zcgfn7/qn8CAdsJTny6jk0XqpqYizOwA7gjuxSZw38esXO5O6iwyJaBJHnF7onF/bjGk/Sdu89jJKQm6nOWo84Lcpa2YC0+59I30XLseYOEyt+rN6r69BvnybAXSV6znAXEQdQOQaPsMftW2kX6e9ST3vb6sjEFrzYTo8fJHH4Dx44O2DpwZ5O10btRxZHbaJSnyT/se4RYLPlUahxYsdfnRJwOWATNAa97A4L9Zm8zkeLuns4Cry1ucQ/NStSo+/2aX55Mc9UHG5N7tUxgdeJrGWXCO3R1G0LLSd041uripHXRGWmDm4mjDFjFKwxYwWwxgzCg2Dan7fAQ6E7nXBjnLyiX5bcDtyKwwMDngYe+qQujpUM6M0dDOjkr98Rk1opy0K8kM/M5oEBX3yq+7c5sNFMxoDH82oAifNKOmMtBtumtF++GnGBIGjZlSDp2Y0DK4qNQRjAmrDWeUHCYVEth/uaqYNL7ih8RECu7nvUfcJBMetqEdqL9KZ1RuLrbUDRxlI4xprYR+HUzXBoCSgC/rcx7xI66YY9MQOd67URfDksvsHSTw4bscXo7Dh0xVc6A9Qm6lyWBHTAz1QaKYmBA5BAKR5cI2JVFVutAzUFk3XglXrj6zZO/ujrLgm7xTiS3227fvlCHe8tpXTu35PTONT/sk37fyLiDW4J3usM9IWHNZwgpqaa5fW2TrBWNnu2UaL+Z1qKSEAkOpZJt6clB1vl3ALnUDdT2SCzM5TYwbByEYuMMjmAwaAUbrO49ixFVZFE25zBDahybfnxZ2Lkg/1DBr/JNO7joYhHOqjMSu5Ops89QA5hjCUDkqYanY+CgCgBTQlyRC9T+OJICmr1T8qw0yD01hZu/jRRPkbVxdMArVFoLBVqEgTKbaVCLJTdDcNAQAQXD0qkTuP6h2gal8jEegebZQybw8AQM+eMRVLSvei/rB2dQOCk5tsCEsasyEsZYpNCDJw01d2UHvEymCmKGqK9kQX4XBRvE7Z3EWOeYQndtktqXebqCpcdtntqPWbMsoI3QODp+kFuldLTwKA5hR2o7DUbgBoQUBTpfnaSZw7h01tUFOPtxudbZvepqrM6qSa8swnBACYQMeVynWh8O1hKcuZnTdAQJyNPQDRIQhcA4xYJsZrQmre5LgS4436ma9G+y/xDF+uIXEzBHwadAgQO+qQNBiFXf4Fvyds0N+8yumUAILEz8z8adUhQEBBYvNhYsOmvDpHjg71Q0+v08EEiX82OidVO8dj+9sC3AYsIbwYUVJg/JiNAgDM1aykvFM9xHJdL46S1gX/NZcd7mp67eWeYWF7oxrosHqySLMuUXqsySxRAIB6SCND1JsdqI8UcxMbrKtn7QEAU3ntxZI2c531YQ3D4SO5NLP1kXJM3DcZCkA6alsEIVPXPT8uCZZoU/86Ei4Jq32LXRWJB/ptD3/75t6G591Yh9s5QCYkQyYadmkRu2CXxWQ3Db2d+SUAwF3B3Q3Z4E5QsYSDdBrq32iEvNtce5SP69QRS/TJ11lduem5kTFqBvqyVrKckI626AMAmKubOPg2YrIsOgJoL6qBFGzweikLAAAXAKKEXMjet4fDEYiJziRvyb7ljyyPJqbYtre49cj+ewN9SXgAXaO7GY6B86uPBv6mSU9sdHrbyFk2219xBD7XnDbWcDfiqhKOxmjT1ekbfuwKy9UQxoqxfNFNzUcBADaidqo6C2ugAE6gypSeaRqqLDLQEKoplKQJdE/Ztqtq1ydpC6EHE0WZlWJAK7mJzPoCbtPr5fAAAKcXJgX9KAXIotZUdoNeAXmsizV4Y/KiNg0BzY121an8ghEqaBv6RJeaCiayzEoxhzW4b+di7Q4t1nD8KlHas3dP62bhyzeEkPExOzNF4+/zvfSv6WAWJHLtPwuAwJIX23J+cIhw9D6xRJlJJAaIaWJgeTwABJB46UkAgHVjI8uldgMArgxgEc3HUp9h4g6xlOV2LLu75K4IhcHuPdcRYGYuIQCASZEjshu2pYajcNiNcuLq1jQxslqCuBRtA+JSIUwgfbVoLPLhHI75NrgjEG4d+/7BwXy61q0V+D67+6hVob0dHg0dWHxqSzQoyFXq0HF3k0WIhFnMtWHKsh/TUQAAOftophMk9FAK4GWTwuHa7KIzXQOu3TYLdCRcV42RdF6L2blrV41w9/0/pyEAALLYmCgxhJObyMXmzM3VBgB4vUMQDqlMMfrRHKDhVJnaLUCT08W63uUHmWaxlA6IF3TX8tXdWWETKrgqEsXdLmGLLDpsCriL7Y3ul7FZqsQ24yiQYCC41S4FAoTLYKMYgEgMHsoAiNmlJwEAFWETl6V2AwDdi03xZF+SGsNNSiV3zACqamNFIGXDKiYEAC7ukFp1XFowlFMaZaIEMRRtC2KoEDY74coyuJi62bc/AwPfTfoCKdGRn4pPR4kGSalKthdNbosFGrCEcBkrR1nyYyYKAHBvlL3KB1ErYcZRWtdZwKto5W5obf7ZFdaOanDA2lORTnDXHGpz84AiOklbiAVMlOjij9/isOM9zU9UsVbTtQGAolZuaCW6jMsuC199S7Bx5hl2e9vViomfAch0pq3TmNezvohdT0hCQrV1N/Kk3eVHjTJaJPLSNZa6DE53EFy62+Ubk4+oU30YbSQepUeE5ApQAgCb9Z2iuwGgjtVK+5w9Ep517jF38RbvYAYFy6DNcDzc4ZKPe7+ODv9TeMWsC/pHfApJTAkOAYIAEpvxEe704qX4yVH0mXx81gsASHzlR9MYrFwd1J8OgO1Fw1hMF73HkkopAICg0eqNqRhwYgt7xjNoOSjaoLHZKKkUdXBo4rYDVVlaW1AXCSCfSJDFeAAgB6kC8gIIZ4DluECUW4ORb9DOib8IlfYRw1jMIDXWV5NrRV9+44IDOex8dU/0WW3TkQVcNwaZuwru7vgxwwQAOCnUaQPKS9SEg3R5CHDH0MyVzkwPNFeycrix5oygdCq6fCzoTv0P7/r+/BD8PxITPUBXbD5WWOdnmpSWVxLUEGpJD+yqSmvuBDtmOQsAwHLBZqC47OVWVkiy1cjMy25X76E7p4lVVQaCwOPuv6mn6hgjNpDVx+laH+k81bhyfUKd9qIEGoiGXKUnWHzUx/Ir4Sw+QyTchE9nSWjQ8FvwveXhkXFE9z/h6u5U1T1r/B3h5lq/IWHcQHHnx7QUAMAaFfUe2PoygLX7eXnqpfyzVcRf1rZqsMFaqkh7UBcuuEZ52CEhM17YpLv6GBwyZ5Uo10/vcqCee41ECNdxhdlC75x4AEB0KqmCG0E/Rq4oHDNKa5reY73AUGli85oQ4Dsw/ND0VjlOhz10YPkqbzh9beBsa6QKhDBV4y4HMNVd8NQriSXe+L8wT0L2tg8ixmwTI+xTlesIvjcfPoy8yRDV68o9i0/vNDPuGChynUxN95yoX6Vvxb+dOxTD463mw2nRXuMFrHepMMpP3dPm2PsHIFXvKU38fAFhqXqdiWvGp8TaewMfZDr1FvrrsLY64SG5GvrdExrYFixP0Op8z4Ym20IGFNpkRcgx+jgC2qnCy0RSetK3bPM/4XlIqMhAjWFTD8kU3bVP/s2ygWSKY5Bmsm7znpd/C6U8YHMzIaIsuUpgAzRBBY1XNIMABQhThQWX7dzR3Xnsya012YcewrZuLAYPL3ppk9X76A/yJjDuO/m7V01P/OC9lyMgjFm/ZruC3G4e2RooNsV4M+bISbCzn/ZIHiWeWJBFxz3ecAUxGYfAhQd1hd35+ZASJZAMNkkjUx/4db6daT9Sg0NqFAxmBFFRQuhxR/QbT4i3JtcPfBMdnOF48XIVTxqkR9zMmyFNVNEhaKML8Unh+PMj6fjzQzr+HK89pH4+ko4/W+pnEBN2Hc5vGUdIAVAQzoNeMjzT5+5YbkBnKHMu/mJYEwoUcpSqc5J4EGY+JHkUHgHHnyeWEauR9j4lIZ6jno2RQ6n4tAlzg3zMh9vwSxzIHLI+RV1o+6eorKOAjZuDqLVHS5+rvk9tkgLQgKBLPK14nU0VOW9M08AnOWer5yCoKxxtFGZvhxL2FJ1rmpE2HqYXdf7WWJUFYgJyJkgHUaGOD5bCR2IaFU1Obq0VDn7hE7PtTZQEllVICADkFjcTragG/qbhKAs+XCUTFAGfxsgO0IBvaD4EGmC6FvGm4eqVetndc+zqTAj5KsC27IQoWQOZWqqo0quu97XJF46r+dqnVl4poqrvmrvUKzruZY/jH1F1TdmTJo+9+bC6s03+/lOXzblZjYle1zfo5Q14ypMJzTXcr6aYgtv7cs4kVDjV2aq1Pr+7eZTvo4eiE63c7pQ75jUerB6rFZSdIWH21Iuiwt4fowAA7GOsokIspTPLVZXJf6p7B4yrC3ebnrmUfwriajJwBXGRklzLKXR7FwDAULk9Jpq6mQ+2FofOJWpf/8CHUsND4gEASzVR/sfaC2bXVuERmtYCUW+MrVryaXvyJGKa91ZB7bV2svqAhY+Iakld6Kkbch4RBbiYiF4ix+4I1AByog2rC5OcMeqD8z8ujlFWLre0rU6D2/0xmQCgPqNqensqxhS1SATinLr3J+DKld2K+/BEWSHa+b1dp+8CicWZ1cnYOg0aMryhpNWUrTYlnSEIqQELVZccT7aG1Ij7dekkxDYHr47wvYYmxETxiS7QEKNXxcDa60kIX+5iyl5/TUcBAGRkq+k0XCV5EoA7HLc3GreXf+baq78sl2rgwnIpSS64UbeMFwAwosAS1ypJtEXhekiUmzhhvTh1DwA4QWbFk5LuzI8vqjEzz5Nm8sLe+AicEo8+wqhSO1iS9J67PMYe4kv9256knOnKgQ3XR5r5iSMIoBI0IVQqjLRtjaQSSWlkWK3cbYP1uaIyAWADQWSqwzqVIcgBMiIBbnMvWSbuwgbuHj/sYzToum+jlSekEPFOz/4AQgwRO1Pnv7d7f07ooGlz0xiFFxJ6dxLvlUxz67TdgtWwoSmlAAADtVY3hjXgLnY2fbYvCzQaJzbQoY6SdKhKvACAoamLdoGzicOhvsk9AKBTlsqTovSPaHuFkwBcfN9wxSNKPb1gJW7BfcDi34Sa1PN3g69p9t6ebOT/h2XyU/0CH1L//1X1Y37r/i2eT3d1pkxYqEITAACklpRhaxSapIOWpAJuYa1TR7wIwEk/a0lpVQrG9yrnueGc3/NWQ5KmuPZ31l/tZ0/0+VoKcgAAGEuXbCmtjAAHL65h9bmeLmgBAMZYN4rLdSlgEJZkkGbe6Dqe5pVSYuppXkslUtPsqtQbBWX8LXXbjIJ0Mz9wFLUfzK9/xj0Ev9FyYvWpPr86GeGdQku+rgUpAEAVtFVpQw9DlAx6kDgBeGi981iNY89cX8Z7LDhjMHqInO05DjUYVS+AMIso3gUAdmCLU4qOc2mJoHMTCdbhongAgAvpZF14bpDtVwLJTS4EI40FCFaVEiE6+R1BXIpAArR6UFd7zoCdu2zBLkxsb6CkDAIahlIx2Ggun6f/cVEYtVIOFm3TEYzXy8kEAPoWoLnVKSeLTSuIgDNtLJMEuJS1WEVWYyrawzRVSAgATFX59R5WuxqOaWyfnM6gGeR7J77QbDa8E9+e1yEBIWuonExV9Ob8PAkVuQACKnlYNpwlxIdiIOm9lmIcqGh8/1yfTghvP6MecpyOAgDosaiEenZyWioVUM2Oq+KxZ6786321yxiMvtopTcewRSmQubsAALaBKRATTbMMtNyRasxLdC9w/7ckxYJ4AMArmJbqYnXyMPt9MDFS07vbjYKV1cRON5OXvME0h6TCgmUnfd2uQqhY2RTS/20UhHYEFEvxQi9fqoDiPoWemCg9zXWdGYKVnk8Lq11zwkVRg9sk/OolGKW3XrCtnsFWlZaTCQBCN6B2V6fiNrbat2hQvIIeGq24s0VOARPNKQQAeJWmnAQr42yaacoZNc201WyRZnpVCBnCzinzEc70n3cn3DpOsUFsaKk8taNNjNufJEgKVw6ZvpqmpAAAeupw8qON/BhLabmygLejQd24G1NHlTerCXOtrrQy1zNlNLVYatMqxkSrp4AXABhgtZJFdUEbE88IL5W4qO47LacQDwCMjpXVz26gUI7FiOYUKpmO9UlxHWQ9PKpaCo2dFVecoeDD+kaOccCxCN6zaN21y+CH0+LSiTZHRxNAh4qHS4i2y6lUmtFvzY2T3Y72zimUCQClYwVBHT1UdnBtrh2FYs/I3djhgfgLEO8mFkjwovToQrh/LtBPan0A0YYEXrrnB5ak/qzexJQLqFCONIT1pwU9jRrOFN96aZxSCgCwGsQfjfdAltKoBtzFzmXQCJU6MATlNFCXeAGAQBUXVYY+x+ozn1gcYDEeAAikCggLIJwBluMCUVMNhr/PnYjH1sr/BqvxfAbqL3JE66kyeEPxvdGP+bL6gVd3Ofoc4rt2dV1mTxF6ctEEADAUdRuaRQ244Fneyx7v9JfSwA+/XXqbOUax7K010t00lE2S8sxa9rnwFcEy0Vp+63bta7qoPxmz+zK0p85aNnWvYmt7/uFBOTa2sOGdJxoTWvj60w9PSnCEEJB9g9uoqP4g8uLu9vl9BkxdYfvYnUOfpNS/Qe1V5Kt9ey0Ebb5+uwDOi1P71/NjdVW7uqu9NA1j1wCIxUknjO7prUVBDgCwDIKvC4hlfU3GFo/NBLk1twWzj83rzGcBAFQEtC7VRVntl8MRFERn6rx99DulTJ2rlDhAKXuuvhncmuLeuvGd1xwjwgSxsQGnw8YKwYq00sB6ZzcHUIOGXFlOvOoCWsCx1Hc9w+b0c39bj+zO72/BSiMMdCBfyWd9sb2f95nD4jxqYpOMbZaGcPglN8u+yFFCbYkYiG1GGC3EhF5UBtkx0PuLKD1BjVqF3JG8B59DsxQM+XLHenLGHGIsbdSJkwRkE25mJIezGsjuTsXQ0Trl2vVKnqCNTgNGvfuxcFRMDG5O8TnnZbVkJdHpZF+7dPUAqu86j2ywBEo9HwUAkAx1IBkGP4xrkwSSi7UqoHjEPfA9DPOlSjVuC8ZKOkW7CCYgb3xFvQvaag0JTORra5KvaQigr/NV9NEmg8VAtL8gZK4n+jDb+4jshARJQ0sWQ0u2NR5fjpBOl/9INu2wgDVWLVZwMa0NEw1dCcURTrfPIuMJl8y4lQ581vKGkjVavgsAyEYuP7LZU4q2lt96MBZlieYdb1RsEz0nHgCwfLJ8hQBWf8IDdCKE3dcj1uwwt0AoXo+4+IBEAKF5PbLtGn3TQZzR38icIRQhXigCGRzCKsOLmJoUUMTKTZzClnx4IC5saVoKJyX7TwTVlrbxYobY0k3ZdvZoujOnTAAYEJZQo+6RZqYVgqsNzTD5re1olZXdeYwP2uZ8QgDA5XI3Aiy2jvMUMNjVM+MAwwrOHi8wJBDEpIBVZpHZjigYZSPOLgGW28jzOLgBWvxa7tHqUHkLJ0Gyiv+GB1cpKw6oLkD1qsLUlmppUQUpAAAF0NtqenBWkvusqAoocsswQmZ92dxcQGUGAbHECwAsUEx0AT09dCrxPPHioSb3AIAmfTtTCkU/U0HfQ7HmDnjpGbDxGdF9BKDfCcLdSU8/As0nDhwxynn7LnYfcsliIhuD7AwRuDKH9qFdYnMt0B4xug7oOt12F6ePjTIBwC3g2kA1m8G12aAJNJUQSlgrnanJjx5AqRAAaFAcd37J9TAs00MrGkFW2eMIdPzgCCRPBk7o5ir84I1wD8dmF8QvPOYV6WT4+1l9d7eldV8OUJQaboilFACA0HBDRxcsCtLiVCAh5eYWTGYQUEq8AEBjdrdo7sDkE5cDXYwHAARaARmUcApQjhdS/a4DFvACowXA66fb7WJ3GXv2Ls7j5nxib3yTNqsIPKvqPCrFNnpUinF1msrcdp1OCxfKBADq2IGglh4qN9g6jadCwZ3NxM/I2cZ3Xy1Xf8hPEdj36YctspXgU7h/Sg8EiHQlbO4ADMn1gOZFp9Py21AfeVGuhP/GjLDO67jS8tRwQSilAACAotULWhUIiLm5AckMNuQSLwBQYKKipVnfQfKJA2oxHgAQQekf0eJYs6HR6wFcrAfq94Ukr2nrPwcW4f9O/XOwft7NgFob+MfrYX8MsNmuH/jZej/4xjSLfGCigYtv2U7KCihlPqxxgQkAMAud6rRhmsbZCQcpCxlAHtglPKzdOT97WKNSH6CgNN6uquPxYfjDh3X7igMNHPT7NXtA4m8qvh+qK+az/o938+yyK3szkyGphjttU6wxXREmqhXhOjzTRC3ZKuz+QV1cVKO+wVbz5lkAAIJ74o1DKuimsZJrAZdOarpLX8rd59pWFhvCc923tz+jd4gl5xlL7f2sKt/EecatRnkWY3mOD4jPVQH3pHhPP3oEZhs/Zh5NSdCtKZx6MWWtAiaVaYSENQfVZT4KAOAqaDhqeqabfsPFWAWUVjz+myYqrrlyOUYwaksFVQW1i6Y8KoOdTe0EAAKag20uJlqoqKAGW12a6HjCXa17i+IBgGmINvlz32fJQzxycxqSSo3nhGHybNIq7xPIQn7fQFaqwB3WNvLCDdaiPBG3WENMoAPWCLPphDXGjDpjzZRu68L6XEGZAFBFUyeJ2sPTOuUO9tLsngyKL0pZR9sszycEACxBD9Zw6WtYQXrorPTMlk8owzBbwNlbA8xiEcR2AXvhYrIDz+5M+6dTMeNS5fwUoGcYeYEHd7dSf6PzyJRI44sVGKv4es6/VjFrM00HqKEqTNX+ZRZVlAIAUNAwanqm66nAxQgBSrU/id8y+8JkfdncHDFztSDvsLqiLgAgMBHRDamdEahU4iEcyjk0NxEPAJxv3z0wctlH9n6ybY4zTxo/I6jZuGkI6aH1O4DZ9X4KVmhRfHKTBGvQeFEJhrvIO7+sKCEtJVJl1W33A6aCujMhbPrG0c7odCe4HBm/mFPdx4Vtc801o9EmEwDURzF9ceo9zN0zMxWB7wSTEoHbmVYrc4hvHwFNEwIAa7q/BzFc0wx9BMgz5RyPh46z9TARhB6QmnOfcr3csqdB8VCtC4huMpiv4bhtxb3sn4gaDmaXUgAAHQStHoyrQB7UuTlDnBnkYbSoCwD4AHQRAfOJAlOKBwCm2/bhYBRQg/Bmp6DuOD7lWKD0u0ELeACVwPIugdntIndbLe0IXplIHu+6lf8TmJyYJlsvC9+FFruU2mY1Y2FXs9sTDhWLZQJAgZLUovUqgm3T88fgWkShJMdOz8ptup/Pfw3zWJ2G3fkqCiyaldApKDCJBwJEtxI29wSGPVtfCq7TlEG005XIVsKnncDdpbTu67UCq2FDU0oBABbqSL3ZSeiQYsAdK8Chys0JIDO4EIu6AMCCjop673EOkE8kyGI8AJADUUAFecuZAyvGpPXpd4EScAOI/xAq3wT2OTwXHbo+eniVbNtjCbIj/XiFwIcpIwFgjRM48mBiJYqRs2GnxLQOITCYOBvftYFEeb2fSxv6hUybON11vO/iaJKImwBHfs7u4Gu5QZhqzHITMFVsPuJOzsKPj8Hqw66TpmF5iSO0jIiEuBJegfnFN/vHj1y0K1uUOjEYK+sJX/qw54T+KDBLImhbsdY0+/DPRWBf5ukSc3tYo7p051tjXMSWdHAt1tSLylseHkT2LuPQGE/p3gdRVTdGBCMTu9iFocr1UoNLxIDjx/e3vTIIVcwEsVm8AQAaGAlz/7Iii4tFo9ka1Ary54VaZZkFAIiekS7pw3bWBy/8RPungTUkc9MBYQRJiOGTh6R9qOD8LTDFXxE4asCEPbIWGzU34yAoJdk0tLLLeIoFNprAAQGxQ9fdepsmuKt1uBZv7bltTseKoMjLk8OgSH3j1ibqcfYp3MHdJmwFgAQ4uMVc25ucHxybbyeE5c+nP+IDp3Yx0aB938mmBf3XaWX1HWfrxswUdrOkCwB0sGpFlLtjVyNIucR0nVs8sLQHAPCmPBFTSqdKtCtThc2jBWPevAl2NcIMGzuCZtZhbmTg8SqYo5Hu8yNkjf9OMAUuL3MQrMfitFdtIQdHyzGjWHajVQVHNynVdnQzpRqPbjb57aPb8mKZAODi6AxFte0uNTto0KWxqxJOTzneD9uZKAQAevYsTsOIHI5cwY49i8zetKPxbFNln57l1RAQdjRPluZhmi7YnkoOgw2rvDmGWILvzZpN3KydiJ0AfidzBYDnTeZhOL/aP5CiwFde9XmfqTm/0pgY9LnOSV0AQKtSRPlAEwNjC0wllozXHjC5BwDcRhVmSmnjko52Vlgh1mwQynsID99afbgnEvssQAfMJ4XBlw8Wh5r/vW9PaJSXtreEnrDziaJ3J5qA9O5ZzUZ6965mJL1Rym6LPQMslgkAouOUqIYVZ/ODwVoaZZaA20cPOL132002hpcscX0yBPBIIjO3NupHAFG2TwIbQVS0bR6YKPOEysOhL5Lufoq+Bp24/4LOUZhO3AoACQVxi7m2u/7MvYyyZBVYUOfmApgZLEhFXQCgAHWRAfOJ5sAU4wEAgFE9BJFN0Prk2KCyDwFg7/2v24MYxcuLPcFVXtp6F3pCySeK3u3RBKR35zQb6d1zmpH07nN2m+wZrWKZACA6pkU1rJjLDwZrapTZhWfPhsPttfkYPZuopmve3lH3TOwKAIlPMU3OAUThE/geIdTgpfbi1iaC+y2jRxH4TOgKAAmacZN58Pr3aP/FqArkQZWbM4SZQR6Gi7oAgA9AFwkgnygOpBgPADSI6gEwbzb5hhysGIvWl30waH695eoTWJD/76L6hEojj330hnN4/Av+CY8+3U0xGzc4jCFcrI069BaPNnw/+TebNNwWkBgL5DLO/Kjv5sTP7jplgPD++/vbwswRz/gq6e7aNb8f1qxktD53AHp4rPXzcVtZWMPugAdmi5VR2yoqniSQinhzmtY3jxW3tI5en+PJ6zUqZLaw1yBr/diIMKADYehQEGjn+QUbAOLmtGeN+J3d60ZjtVesn6c17qJiCD6hsw9AY3mmwkjmMho5VdCW5AGB8yt4Itgsbkfxvv9PFWHnRk59hSFeYJ8lr7rd9XP+9EjocdcvUiLWg8AkeNgRB+J6gQgxCpKKRYjhprzIphg/0ppaD+LtaEkEH1Ea42wrTuQetfz7wmFlouKo8D99u8OiUDjqowHl7eegWCJvqHAO9Bo1QaNu0tFp7E3VnZGzHlKyDEcM7iWyGL5fq+1fpA/aEohn7CkLsMx+kd0zdlmskvcoYlN+3LgzclEm6S5CpyzKXYerDv2yTN1XffV1YaMTO3CW+ZV5jUCC59kuG2ezZWB10CAMYJ9jk9g7kdp2Q/LiR2StsCtmbX+4ofZkt18K7E0M3yBCIM1cDpjmyjTAH5SzT0m1lX/EC8CchtAqT7EAcUQ3N3X9Q5+m3jitfv4BoLOwDvqTgElPTyYcU1G2mrJzJgk0xzcWKGf1UKNEfgqjRZkjRKmOYQWIrfLY4Ozig6zeTvwkAhxJZCgtYEMTX4lJZnWYOD8kIA6Va2sH6rviPxcg5vZYz7YXGDROaFvqni00xT8gMxkxq3ys4EoGl+FPScY7TcNQGxnnK+uxKUA+bSEtCIAKOa7jo3KVu8DpuA1ERqNN9cmCxBuOroUoZsWW6ZM4zfQzSGlyIA3BtB6c/GMPcZzPA1ji6qvB5BUT5wjFaRiMCE+sfFJPE4Y6SacwZVN4U4yerAR9Q0QIsmr1mGIUqstfqO/Q22iwDgYCAdmIXoYRPhGzQ7n1CnbMpi3YBG219S+jybpBFo5HY0zlq9CU+ND4TcsPPQU/lU/JvSD5HscUvxQCZtddWgHyAtVHiNvPA+qkqg4aZtDnrVqYsAiG4goKgOREtZGNXG9QJncY55bVWXUGEOFEZlDx63HGksYcWnyFDiFnqSLv1AjSugbWNiisApJM5i8XQG6o4YUzEaewRP/GD3VPNJZkV/L1oa4300Ttw3076tKH1Xv5ITvcxIMRic5PEHZsZx0oLTYc/rCEtHhR4JB8Il+EE7CLKasQMy60GLqUftZ6VBtEZbNR6ENnuRahdOhVfS84yWryHIf3/AVdL+1QIQO74Bp+PUEf4/+xt8NR7XdiiX1NrNdF/yv2qeJqOrl0EyquOqj/ut5Q6F24rFGzZuFM6M6fw/qPSojui6mO8MPCSCEQ2+Kdj9CBD1M0OrbXL7Kfmga+zub8bn7ahLSImw3eq/SRFxkyAtG9b5/SCehumLD3fU7A7p5uQehNJJfE88Ny0hJ1SIZlW3CEYHQgHuj2qDxEn/M2NEtTZRBHCNxIs33XB2sEbvjUNrv6gRnhtThE/WXB2aOpye/maSHknorj1xkNA8uDcq3w3gJEty6Ri7EI3Ot4mwGFMiy61rNrFFqivJeNOWwFjIg+0ZvOZjuUYE+u9XKL2A9bgkYQbW0Eyljuh7Y7aV/FD+PertAc5KHUkwQgDH1S6hK7rHofzjdaEP1nCOjATLHebUi8EUMZHAOeyhbeb9zwEpBb0fHIv+NSgu5UjC2I76XADGgKSO4/XGx1VpIGJ6wAETqADxoAinb6ubz+c+aN9udf1V9/CX/87y+gCE9DnMzd0XBgH0LRROm13LcrCurN9vU1Ox8+z/v+z5bkBwTsattQyUFv7I2sm1srilhpPpp2qfuUVlZTJnY1Ta0eDxyKm/ssNY9bLpHnuvROZdhnZTLBQJdPQ2IZVKBDBa8ogdorfVXy5lwZn5jaW6R4sW8snpcr1g8+FdNEV1jlBE+49bzecgeVwCPJYy1ftgsdw5+rM8rrJrFi2vkFP2444y6bpcjk99bl53ZPxHlTNCsOPDfLe1wS1Zvx2HcCQfNcyycIci1Ht0llSsnYp1kraNiZvdcOihf1ke27Xh9OyxzMBaRVitRxLmbJK40DP5WiGXIARVl2JVxAjXlDZntbR/exBO4quh5lFk6oxrZqj7uQUlF1iTZa1HFAUac7nUil6JxRZ4vvaMe6eTq/Wtb1Vh2ceKXUXxfH0VbhXf/GHcycT0zySNiE4cPoglodYabg8yxJQ5rOjmWRV/hMinAj61vZoATqJhQUw8ojlLat3uLU8TZ4ES1dozBJemXPnEJD7nczKWhaxP8nOjf+Dw0NjK4YdQBQ3TAXpAO/CzTOihWWa7yIbNh12Aiins6YuoLg7zAc2RVFRkP3CsfMwvL+31AVb3Qfz+0th8lqnuHMHuAET2/k1U2T+KlVEVB9P2yq8YoMQuV4ZaxB3rPbsDOsP23Jt1olvVab9/SF6BT+UOT21+95u5OfFlM+1vzHt9zJwL+PePyunbS4DR///BU977FcYV51RzZ/ge8bmZYvadhg+8VKGTZL2dmDzwcfKUh6v0qpWxW5qIy5RzGcPdrt8/Ck5fG/hbCm73DScvTvI7CGOdxr7Y1B8+sZ30NPC2WUksbExyUrtTfQT35b4tBgX9ZNGBo8Vcz9UiigUquXlBaxZj5XrF7FVpo9/6s+n3/5oDzNEUrBD2XuenizrKICxCYIm7Wja4X0jkJS5s7NRCnYkWcrloAzDr+K1S940dcOqfL1SWHdv3MuBuvPeEE4+g+fAQBitg4nRax/V1Lc3AF8Dmj+i1eJjOvAue+OIPL39c49EYyx7QoXpzQc32KEffvP9o8t38fzo/E/X32mcZifos7Ona/zjubYtuhTLtaWnvws+LwC8bEwFMila/LsiOZNTf5Nca+p91omQjVoXpm/flOJvz8y+rk7zj7S9pUnazDb6Bh1s66/AsiovcsvgDb+LQy4tYcF0NG/ZQFXPNwP+kYRPh/PPi6AKRwHX23rwwKY3uPgq6U44NNA/htuz6OfmMDrPgFBb1GJAjc4hYPVWypV4AoLYXvL2x6M8S5me1nwHy7bAwDDHmZnF4L5pRDLH55BdRKXBoqnHsxmEg/31lXadXqPAGkzS2mRhziqCnWuiHq3CEQuTBHWLBjoAjd6caWofp0Rp/4sBHoLObL+9exmLZ4NFsKy8gPOIkOy2oQOOaoa+t/MfVEgwHvrYkxIU1N8I6tn0RKOLQt8i/iV0lna/fhLj227saA2YjxdCbdp5MWFKNGyLyTohMasUmP/8SpLg3t2WX3dnhJDeX22U2te9xYG0GL/B1RfeQNR5QUWik7hHwqGhPwYNINwc5BY6fi2LkHDNaoMYLuoUtcUTGHZBZVW1yzaRUcPepheqfStHZ91B/cgWv/iNSDBGNO43rDl4tOCtDMfj2GXeMUXjoGz/lxmxEe8ySp98hrmsSO4oIqYPHPOyW2o+EIzIOUt96BpUN6gnrmMYb2rN7xF1DW0Z1eRQOACrvqYoVS1VnD0LX7ZM/lskd/gx6E3uzDTzBCAgA7PQ3hUirfmylPkp8kJoo8dqpP8+X5Ea6lTB+2TN8K3dIwDhrVZtzDApDz963lz9PZrx3f2Gt0edI+x/OrAINZpqvofwwVQpryPQkhFEX+tbyrPou4XReC10sWHoqtjUTm4bbOzt9lknb1NVuvZy1mvZ5es2LP7rdk4uBXEfrYgjrOKzkJthw69Dlv/bDab/2zc9j87nwKYvfFTAbO7pwQIDIEEPP/8V1s6BUCYOlSCdCVMcdUWWZA3qmYSJRYHE82ucBspZkLp4+2cV8N9tKuo8CCVxIRajSfsdw7BwZda+7c07/zufgstIAhNQssWjnnsLIDqLhfhr+H0WlHUYlHaiG9u7YdOOB/jjMiyHfhgOIHyukY9fWHEW7mrLYmbvnTpFKNyoLRaVIppdmmu1ytL+ZRmVlOKV3zoURAorYYyKW7Z1ZypfcOstSCXcQi7QjK2L+got3ax4XI2kLhy6Af2iJjhPhgdg0mleNWg0tFOu0Z31lbG9lCT4tcQ5r6qTw3ok2MqOFZ3nlngmf3Y4+5ZaKfGkk0wdaBe8s5r/OZ5UMNX22suQaJYpVGyYmeTdmAsseZoF+DuiuFcOt8pBz+GScORROtTbi7FpguNznn2zsCTnpUzesyt7xwbvXYe/JLoZkvYhUyUMg/qlM7cl8H9o6CpctPthE3pDTM7RJUMXclEIXdKCvrlMnO0ryUqsWyJXsfTL3nJEcCWFCR6LTnYRhZMJgbxyZhUzBwZ89rlvAtAOvpc6AIQDOdmW5uUIyVfMpLVJyNZ3i6NKC6SlpkwLWEgsCbrDEvTTFJUGtgSonstmZrFpUgPqkknWS0hM6gYmWqJkz61RM8BGT3NkhGk+x/KmZeDK9dUFMwlFXsmzno42aZcUSHngoozKB7u25eTiffIC5rEjmxLjCdPzqZQhm8tzBdm9s17cdu+2KYaqEEGNWggBvAiIgpc4DQWKhtkV6yGBmcdNl+J4uJr4gL5ZePvod3apZYUX9O86SJ7bv0HeiVdU5HwFXuladlfgsbmziwuUS5TS+zwvWDJ63VFSf4jX2p9QfJt+yeJqol3ICT2amBqsTmFPKBpypmELCBBUejKDfGqOx6UFI8tIfpnKX9JZHbx1DFIeYwoGDLnF1Kt++WlBM4LntH758IcLJE8oZo+yWBgUw63FWUaYV5fukQ94ne+FB+o8Q89LD7PTv4kfNf0vKd88Bq8U2Ch4LUzlSsfgVAZ4PXA25cTggeny2KGpazveoD352WV9WZOf7uGF2dfAhVFgsZvcjaKAtyXIMs0jjsQHwIxty72ihakDnabmQml1culVpTzfh1HFMetkhC6djpxrLk23f4CmjU5LcXTIo8T9C4lqBAlsh+wxIlCK1OC4zxnLgJeZfW4Qd9Si9Ox2qVb11Ofcb8TKfV7mn6Av5PehEdUnuau7KurHf7dvfef4fYhviWF+37uem+E1L3lketLGrEWQt+VnIZ8M5dh1Sg6mko9OCMeGb+59FXHmeL4VMvwGYYEELwp8n1XQMg7RSUcshmHMPELcI6zJD9BUygUSL5zVLREv7JUClRDkziIUNNYNU599TVQRQjpcPXyoUhlVFSLhw7V1RQlvZ0Q4do7NLSW3I3SR1LKyhwP+6jD274dnfsLdx9eJUAD4dJUO+eouI1wrhNuT+BjalYkmmlM1HJSWxGGC0Si5b5ArdIPoy5q9WO/4rOzCMT6yE1RnYimDUfuhKv4sIG6eISCaIA6KijDTcd/l9ukyWQ6dKrlJJnmApnAdm0T5jQ/hGmiKE7DtViD+On8ODei0yDUMNU10VzReAElzt2NQnlLyK+5SnNqP7dS0ASEGqG+icRvvpg9UdrzXBMcHiKVoi4+3QRRlkObOXggVM4ExZtjkzBwSddAdTXKRPT2ID61gmiManR+HCdwUDAq/StyEzCaSWfUUIdgP32N53XdGfyRsLsPLJXBFHXxyREEM2nUpAnCnJb32LZmMlNTTQx4VGY/rRhsnKIXY82lAi/jJNvnMt58WiBRgqN2mkeaIz5YPhoxqYwfzMdT3k6KGBpteWadS93DYBd/m16EfhpA0P9C8lg0S8cQb2icL9pqTnCfEGOL81dUSD6VDpVVkoHOr2HKa5ZCHFB1fppyymm4+kojBKl0ZF7InZBE/dqkVG82/R+tCqhqq4lOV0ULtdfEpyOo+ZpoMjg0aLKJpCJdfXcr2VEtjqvxukNIrW6MMoTduYTfo37Ce8/AXy/Fbqb5lNzVSWczvVodGkv9Z/F8t/Hmm7Y6FCIelLFuYX+zbCgTeq01v1Wqo6b/fwdmctyzq97qFqZjtR2yKc2ixVC7FFfRfI/vRAcwnT395aT6IQcXL9QUfgXhiTF//fYKnFsdf0mp9SV+DVCKnxOeCG/Y4rfElr+kVELaagLirFwW0Fe3ANSO6RT1lpTqg0opw6UQF1SUX3l4at4Ird+ODeO6paX6cV4N41GSjui42hzwzHACaD8NPDcww32++C9IwY62Zb7mqs1KR0tT+ZNt1mVPfgOEI9iri2sUPuWhyaEdDhfuQ8oZWkM/DRAGzjjPDdzjF0A+aYMnQkvb74B5zQH09GXUsuCMp0/SZ0zwG9vl1T7x/b9LJXDAOObgbStIqAFOJG9fOB8b7osCg4XLk2zWNI1TTXm66txQSW1UE+fi56fjWsWPuHA6rvmc6vOr60S59kRtj+MquWnBZs1TXn3l6RpG135NpdOhmjhUmq756vOrz41rGy/kUl1xfs3WfPWgOtqvterT+ZFi6tP5+en8ms+vIp0f50e8CFcT4RT1oaoQKma+xvf8K8kvL/HnpJWG6muu8pwqKQ+J6mu48hBSVbbgWulXg+v2sn3j7NhlZF5udDTSlu9Sv7E2v3hQPUN+i+5rVnDf7NKaIYLiO1+Y3cLXnz0Gu22NIys63z3dkwuBzknhWukFjHp6TXEY6Ctizu5gfZsopzM2p8fb6DG7fud3wa+bDhvb903r6eLde5Qk2sDtNGdXZP+PEN0w/Tm57P0Fr1vMp5RRPZI+oB41hH2RUuj1sOUVfogDh85PqaRojNqvoYI/pKkgdhAFxAoiQDCI+iA6/oyGVmrlaaNFgfQaio5Ky1JYHdghZ75KfFGLxdKKWjpsxnb7Hf/rvgTGZAmOn3Oiu5NYhHf18wv4ioIDdJLdFW4Hu85+nOUCA6rnOn55lPmqceh9g08PyhVjdrc7T4XhzbC+c7hdzMmIFCPQJIBCKBm5ydgYaBrzKPc/rGBz8mBhb9QCy21yBEQAjYCRZhoeEZ151PkfWtA7KWN7bL/zEZlYIBVBHOg+f6WUNs+q/YeW2PZC4nPrBTjdFIlT1RdZXzKnuyN5EdXR5YLbJhnRiIgg5UBqgTQEPdz83smi9knVQVneRMl9lBEDkWJEzAAEDz0995jNY64MtIfdYLGsVcfiwKRS1941+D2PDp+N8mjndv07/c0B2KVd86rVngCyOKl6aLqQ85RlHV3gEQCwsJaI7woQ54RzJPxGOXQ/ceuDc14Gl/HT92TYxaiH++dlRw78mCd2aa2TPQajv2VeG1zv0n98509wpgQRg9N69WE3k0H2dkT9L/Zn8tq7YKY9NMX2XLGNdNieeUEyzgtOJJYcCnuvfwYAUKymRSnnBZa0SqHRHhbWOALuV/oxWc9rtE9/zevz99TBRrfB+KP9BbpiznVT9pjwIb14achALWsJJ1CPsMfUAoK5KmJnGB3f7W11X+6Aiaoo/kffc6XIdOSwvu18R5iinSPuaAnD1dmtBTQJDyJyWSEQT3L3JHzw1lRLBoCJ0CMfmhEL0QAA3YFuDW7d84GjyL8TzYRH8elntyVDF6zv5u2nvBKUuQ3Fm0XXIugUejiNCTSFJJjHMNY7remG9pTBRzBcQ8bM9YCvgh4HbaaN0DRZUwGpMahqtG/F51fDSmxY0B04Smj9WtEtv13UZJy6a8K9/PZREnOscoGAgIkzuCE1TziV0QddYyVLri2tkgi4zmIl6HNhrb0L4qOfdHJ6FPxjLzBNMjTpeh4tMK4pwdLJBWlnceD7zzfWfQebmwBfx8/k1AvTgMaydPUiBidBe7EOGGeyzTB2ITpll9J4yZPwtGFDQOXdl2z5uzB4ES/1cZiPXdPwjAeBl8Vmng3bkuIukxfCJ86aAje2e7m79mIWmhr7zhhLo7XoohNM3BmIeEuJycV9+m/Fy0UOipExu02edSA72eSEZMK4FKHsCaZE/6WLjmdfrpndGiXTaocojO+iDDUb2btqqRc5Dwz/+WBQzQHsBuYrMDoSvj5QIHxnDfiHEnl3IptjnNoFjkHbAqFx8mpfvXft5KQ2JYXEK9rQ+Vikbeb4etmhCA+2eLLQq2NYOitElNPyKCnqqA4+iALHwWVxroXzomQAyCbCZedEYI1kvyURtEnNDeDDQcoUlyhUQzgalxXz8LUeHfi8dRJD1KmisnIPr5crfp1ikb/n3mVaLfLip6G5tplxQYGYsG583YQVy0sSc+gDdheJlEfOU2/xDWw2d343D9HOtdw8W24kzPo5dXxgKX77sSSufX21FJeJPjAyt5sligJMQCkg9EMMnaW+XkrST+aZ6KtamZB+B5o2nI4Zbc43wxwrJsicfEUtnTlmqpg5N2eOd1XLnM2ZU3eVN+dw5tJTuc3NcOZCVKZzc8SHT+EmeB/F+fngbkeKfuStCCC66tXSpxod3RfG+MWY+CgdFae7NIZDOuJCdzXY0JujL52ka61vdErvWy1pGBWSDv9ySh5w6752vY46NpSLxvkqiSlQ42aNwylhxYvgd6oUNSjO40QqGmca6Cw1ertL0AAA1gonfGiS3NQbh6doVAhuZla94bvEwry9GbA7tYA9pcN3rxbtpKZBcme6ZLdCTwGhgkHEzQfVgZCpYiCZA+GuaoF0HIjdVR7k4kDuqdygKQ5kojKFBlRDvTXuFn/5Dave/I3iYWVxhFvYn+uzxRHT4Bi0nLDkUyjgLQO4n7OSLXGDJWDG5FtXDtxLdNDNHD77HwkgS3E/YTP5s8yf7AEPeLCnoa3MjeW7dFhbJK2LcfGl2MUiSpIWY9BAhZaudQx2p5I025OH8LSWf1VnMLuG/5oSdes/fwMAtumm/jVyvC+yUBoaUpUVAMHFTTCHDQrLEwIAeAtAJ/MQYwACNP6pHcA5VR2qbbZ9rS92ju3QGvlAEGsM3SwHdEXVX3MGNCZVffvIHRpff/na4A7G8EXx3vE15KohrQMrfio+hjT4hgeDaEtDjeDXXDpCEHdoK9sUMmK6Pm1wOOjOoI/TEHK9z8O/DNPls+0WxzGv21vtAEOXi7OPgO5wWRsA8G7MjWl9YvBnByOZeWGJHAh8+S4wT6ITZNN8uSz6/p/emhWpfTAWrPzlyq6+dM0gOmhYZFdVZX6lNEdd9RVCSOM1FJnTcOe1V4eEAW6jpQr7aRqnkiKMiF99zVSSrr4KGs3OKSoTRGxKIK5PVkERjVdZDYTUH+46N8/kK9W6YFQkhPhIeejrnJzLX38Ab/XXplXRX0F7NFmbNdFENonZHbLUty3dFq6lxFNxM5pLb9xE9U/4U/U7hOC6q/SNXQCezBF4BSC7qkFcANqpWpANgO6qPOSWjSlruyuxMShdezBgNeW/gwn4Me3Bek3EW2Ix+MvvAqzWf6Mn9bdb4erNz0iuqjRdg9RXjB2pzypqmgWsqV8N2LHGkj45SADU/QICiUE2EyaH2DYlQXJ+5t/XOKXAiwCsd3fbAMphdEc9+W00SLIhCIhfRrtGzxWSQG70ds+oh8YBWr3lTh0t7yXW4vKOAMCdPbD24r1eH1hnTkd9OsD6BP1evjtFEoKLmsUmDRCuQWRWs9ePrSJLmkndeuT9haaQS2DppmPmG0wNgz7SD2WnFQfSbN4LrJtl7JMZX2txLkUZora7dbpKrm3OV4meUiERWvSuqnzigF5hUYVQ4ZZSfqPkO7iij7zHZ+0uLq6mEkQAe4qTjSJ0h2hPLlmkT+VRefNV4cSKIMTxTg7czEPcxR0BwFSxTuG93uEhu6+IU26A51p5PgMcebjirLR2Qq6Gd3SPd/BcXwWXA7RQLs1zlHfbYzuoepegAQCopIUGZwSj2XIDgru3aA/rq8Mw/dzJTLI2AuriswJfXO3X/XW/He3aUkkF0X4tppPSbbm+AY7EdYaPpsLY0cACOjHDloe9+VZW5AP0h4diNUzTkXtzEH8o9kwxRXI2w1cpouaU0kDQxsZlFyb8Dk/oGM5U9CHLKTFwR2AJ5rmcCSw6jOSMN7/u8L+w7qP/ouu/SZvVLW21otj2l8TdlM2sOSVuizWdn7elybpjwnx/8MeZNUTNiMvdGWGTRiFXwRbQMjfQWOuJC6pqPbvJJ0HioeoPoGrwN5y+FQUkLSuyuMA/33RUm00yKT5WUra3TafOhPAEDA07a+pkpBczH7yWlymBV5bDJqcRowQQctekWGr1oFfLrEmmfCkZ+RUzBCXp5uO71+NbqTYK8Uz1S/tzHfgB0Z5p+bL+tYL8XJv3c+xJ6sKZmmvm/7r5I6s/ARkvKqaDnj0/AWWpPfRi5O5M7Zl853d52dcVQNn4iTqf7BFg9c8HA/PDIZxydmPldCtpcGscyvyG1WtZCI6KrWGN7LGWH/bQrdYKW5J8XdkiYfhmT3XLnPF6LS1NQVWFpnbCg2LU2tEgMc0hJKpDZIuC4wzEWWjznF0HWM5SMACAbazMREVWV6JmYoHiwhqefNjokCrcznpNfA8uz0sN2AtL2NPC95alO+mA6R3jZZh9ZdONQvaIzUDLnA/bkna5M7qdKs9V41kXFhgzdYympotGrEHrRb8G57+oS3chx9HboKnum18ooi5xChYRFzEx0yatzi6U5TUPuSLQok1C11q0mlsoMA+PfWfOw4weMH143I+23F3jomHAPBbHkFA78jZsa5TdVbJxgIyrP9wuwO5U9USJGwaHLgsG120jd68NikOtBmVpRz3T7GqJXNf+LaYnT7d186rJCHOuo7rfXcL46/oPPIbsCP/gd3XVwN1c/nGhDoBUIOG47xrl1U2FCZx7qOiZd5x1yGjvzENZB/Q/BYElwscdKrBRnXSoSLmP884A+nlPE9GONC7ZMtJQkTLOOBoYj00O3Z7Sv8uhay+idqkNVTd2vCjGFQIX+EhCN+aB3p80utsGCWsaPaGyYXPQG1Uu7CF6myqPvfYs+zbYfhN5Hbc9yV5ePLofH5GPnZ2dR/O9gagXQDXP5c3qx0fjH7O9OhHUk/wB3Tt2U3v30Xx2MtIcjVFKVBBxTiP1sRt3zpDUGv+umjneGcYmQkE3A66Qs8pBYR9uMY/72KftU+qUAXSz0AkDsOHOAiVMbELwvIYBkjX2cByAMc9CLCwn1eF/gCnxMrz7Eezq7AcxoFMGMMQRbacnDGDpsYuV8ru7OttaBoznrMPyehjTA2TPWUXrc1CNrwal+rGrKwq1Y4FmdpdWeJsby6FeOODizBOshLKBfv81BTgC2DafzCpC14jqxJLSZEPtIZHzSbVP0905T4x1VkFHADCHLBQ+N5I54QjCj6nPve+wvrR1gAvlTe9VGUeFXHVF/ihoMTquePi5Yp6fUeCsXgoGAJzDy9naws1cdYVbJtEX69Xgdnyhrj3phM0iWOH1Vfmxv7yOL5kIvsenVX79gfedEV4RvS99DWY1CGppvlqnO411TheuS8cl3KUp651oYelVBdPU1+q52Va5nqZRxxmsE5Ok24tYrwbaEoaDDCVToicZa1TG7h7qp5Id83BQLHuFQOTSQTHr0TDu9RmUqjSLLZ5Bqfnudsa/F7IfH88UxwgXz+jiN+a/l2G3Fpj96M+qevkku/wPFSkH3fIl2Qul+k12fu0NAFf26LGqJjYHP6/TDArtzEgzDF6eC3e3W51Rg7sL5Xu5rbQR85VlFgMAAI56qHkaoz5Bgq3CiFKZj6xF9nw2D/Kw7ikGAwDQ5aFqx1nzoh1PV/2M4o5Q3ynNa4KdgsvXUQIpuXQHCKYQu0QChmGCWBQw2zrGrpts4QpMjW6x6QrMlLlgu5c/s+2MqePxsu2lEevZ0sku70JXzgctYSqlP7u9i6TmDlzjFjcdRfa1djlCAHDcgGOVeXj2sp0S6t8sSI8f+1FgrDW9uapikQFbYHW87EYvMXQPDqBrqz8uGnCaVb2KxU30fS9vtKOQjqrDZPfk8KqG2G708Ohw5uAAAKOqxikVTKvjjV6TsIXFUFCrtzXOZWhPSci60AwA2GEtfBN7qr5CZIv1xsnCPxcWu1YZelehR5XHNMDa/aY0QVeu9FMUm+rDI6nTpFbaZDTpli7TbBrzzg4S2hvkfff0jG9RxLD22ngINodCR0fSHBcKPhtQqR8zggkcCRx0Vjfggwt8ZrmVbeyNycPqHvIhHVZteXVKZUlYld6ywXmvj/75O84eer9v6CGoZJ2WSjqfXyx+Rb+7YCn/L8KRIdJegbAZiPyQe6LRABI5IbhBAmE9hl1J5Gd4EnRjTCRsUrBHh/h+bvzHarDbvIF0D2eZ7iz0FAxMoHvyRVuBZJ0pGRY2LZ52VmIcP2CmtJEjmHn63jkgpBZVJFzcbld5dOvoYPE6pvzVPKB/p55HAPUNIBpFKAVRnVhSNK+R6Gl7QR85R1QDkL58LIl1brFJALADuVIffZDxydBF+O1CuEHP4OfTRyA53tPQ+94L1VrHPcPMm88K5FzMKjPpZm1mhQEAB9nKxAZ3B/zStrU9+DM+2/Ppffnr9lVg7wOsj6XOGJpx3lLmbO1KngPWnip4gk5GPd/u5zYetoViMABgY/CIXbBaiUjDOFMhKpwx2tndRHrNzxsIiFOOjTmGSJpJ3s7i8S56ZzRBUADQp6piUFdA36BqQSNA39pcQPOw0UdTB9RgA3XmMpjDnahI+c1HgX9O1kK8S9oQaH0le1bwacWPmQAAwEnp6B2hoMwhQZHQNBFzNlDOIHTFMDXmhAEAroVOl7xajgu/cbQ8XTDgAh4QnMrzxIORKGF3N5RG2Y5J4MpluhzYQFaHQaY4sgHvItdQy0xd3whkOWmXaQI5j7kwrdWejtHO0N3C2Z7exrHDoSMgkbGEzQLsjSpF9txAZ7s0XiEDpO0NqW2HmXPRX1J9TR5NLGlXtit5bfptlpp+MJRPOSe05400Zxu9XuFDTYRJGvfPof8FwoIWfc+tAfH/HT5aexD7swr8qd8m/5lM9LM//GX4Sl1bwWTwFCQOKcaY9DmajhDnRzJnPlU6H01BXFsPOle19koXc6hzXVgP0mWvYE+qP+8e4Nmu6lO3bMiD9NKGo8DOdxbou0fk0Kw7ks6BtmoODgDQaljR8gULK6AU4rA0arUNDAA1m90ZA5sDF5oBADTEzu3J0risMeZucNOdsuyPDWz3bQk6V4DRWxqjCpSDR5FTwAjQ+5MWXBVE4r45zI25UtUYEcxdVYtZBbhb5oLZPNkmgI5s9HuBpkkcbAvm4BHjFTdZB40gdhNgo88qbBGbrUU9PQXrzCm193C2CHqFEKw1lH1oJrUm+bgrWxReTwAA2PJ1iAVD+VR5Qn9u1HG2dPIKOU4YRUFny3Oe0+Fa9lox0Oo7xfS5xQZBt42BDU/lcdFWMOMzpRMD9vYZ1rtgiCrD0H8jEHbfpW4Mt70GtdFkYSPq+xnCllNasRnc2rHOZ+URQs+dn4pYXv9OPY8A6gxAOJkg6yOsE4uLpguZHsg6y/oqgkq4uVEhxDPvIwBIhabr1MdZyOlkmCP8Vhd0t20e87cfBfvs6hiPPeiFaH2d+uzMrHcz4KjloIJOM4M+62MDDxvtsQbjxCQbt8GLLXbCsmHRHQAvnDRv34wEHbx6bd9aoyBrSXUCnZ6SpUHBDpPqTKzsPexUD+L60KbtI7TF7O0uyLYue56J6cpnSXkGV05Osi6/G0GJ6IhCjaEgjDXwhe5f78p4Y09wS+/N5TosvxI64xWIYTQPqGfPHnc8+O92/0qjYbYLj0tMjckOW0HNRmiNMnHTlQg/lzhBb4K8AkwlJxvLEEkGE3ce3wHKVglBdSVChm4tAwSGtnYBix10IGJghyanlB3DJriIGRbu5G2We1N78MdX1fquYYv4ho1/RvJmf1hXhQAAwBGmhtyZwAQrgnvF4fhXPYeYR4DKUM+tjFPxkZ3ZYADA6qvvIvhrFnw1NH2hkKeXGC7EeCAK4UyOniFR57H7sMTcnTRwcKkvp3YvtKdSSgiU8g8wDWqZYQPTtnYZCpjOYIahXeeoOw7rPKXWC90JXmLtGahqU4ppyIQtN4pAU5r5AQFA1rAU8eGmga0ds3/phiWtWU4LU0ZbjA1ztz6eO5gspDsSkGpWfyGCHfTqetO4rRXewqujGLkX+Gf1Lp3FW3NcNwCJelY1EwcAMPWshiGX+ta7k66HOG0ZA9qoIWSdItZRzd6BETvPDAAQCxbsOzE+gffnYtxfJqQ03KHtkrNjO4KK7hg8c/+uYZjJ11IW4CaxvNZNbswaKvcjKTxYevX+1sDQRCQqwjDRNpqGsVa7uAZGFGJwH01j0dFgaFrCwaODLv2YSWmwu1k4iCJMyKklCiy3mZ4b30UZexnREVQ2VWVRB9OcvnkfAcBloTtWHru7WSHbutPlNtghGU8xaWCbd6UomUBnebZMLaF3V02FVdAtV0bbNdDVVffbbugcSiuubvgYdSunv1IHB7dAdAWh+gPinH4hAVR6gMiKkBeiPrGkaU5T7aEglxMrCtLOjVKxThV+BABLyFXisa8X+sg4VtB9EPIZep+jWUrP1cbaBaB465vYZx2756FIazlE0OGo5+MmZ/KwGRSDAQBz3karKVpvxWFpOEV3tT69Z2Ob5JutXP1cNl/tGvu3rpU6WqxVzs4aRv/Wbxevyj/dbY8f//BrL4ZWeY1LSXlsp6sNFSU1PJhuLpzJ563qgzyV3G4bDABoyUqwlxdwFvHSxWWX1C4yozxvl2AbCfvZyhLpzs0AUxSSOeAbixk9rhDCXGbj8N5jAZEQA+awsQbaYRU2NotjWUC8bsBXhHHrO0aIzT6CSg0RbT1Kf9LtDimhMnhiGJKScVoaK5WOJk1LY58pqAm4qdmO/I3BPLtqTkUrpaLnIGFRGAAwpH4sXVAFinMmTsNKKUSb8rywYYZywqYW56LxudRS6c7AZ5JRX9YwC0rIQDYpLTNz7ExUapdlw2IghhVhmzJ2ttywnRi0W0NscurU4RH7vgS93yTGFuWXtDCHf/sd/QZUXD11Sg2r6nIjtGkWan5AAAAvrCcKorjQtIS5DSpcmKjlmreMwb2WoPfvB3Regs7/HWP995ApkBXjiZTQw1yRxnMG12XiGjK7gKhSQK/8LD1ElsQBIsJ46D6kKc1PBhxdH+glVbAXb42pHaG9mncCAPQOh9rPtPBLi1XZD/kybsJEqh5cqB1ocrh6tFApONsqmLbnmQEAXsJmu6TtGtBO4TGWoHSX/rkI414ZusdQ1ZXG+Abq8FE0bmArrfcXXjdlEscg8e7KJq1tzoHNRbvcGbq15kKqBjvVMY2CNnaKMIIDDizEIycmLJhH4ao4/C61Y4a1Zczh377HQgwP6YFnFbQIANWYB8KK6+8OwZWn1dTCkFMRdKM8WfLOJnYLBQAAcyAnm7zQ0xDXlIFs1vCKsrCJ9ilG19jGsRTFU9DxnkVSXuKl/5t+i2xZ/uH+Tbd+0YPNWwFArgoDDKyP4tmAMdyrD+lcKqSt2wZCXC2JL0A2OQxXCF45Dm4Ywbe+lw7sJL9TbjUNiBdHhTZKtJQhooU6JHebuYXbOvMct1iVPDi4lfyaDQYAxBZaay+wejP3M3VYAofqHqcXJPGrjf5f0uXrvehTr0mEdZ/c8WEd8pvOsO6TOwGsCVVwjN1CJ9GX2RakVRQGALS5WaYsL5AOmkiJm3S8DLp2jt5lHT5o7ZVjs8gQ2bgmZmD5caJnyT3oABcaIWDXei4OWEgVw54ArLR2IXpwOgLWEDEQmKudbGL7vUjRvWJhx6S913XEt/MSH9KP/fxrqg6/8naqN/iIBJrBJm6MWMpDCP0twyUbBSXQnhP/BmV+a9wi1cdpz3SGOQ9lTi5wVriEkzgdmnihstSmOlMgjocFnRVcffXBu+DkvV/cmphZnZ1HwuXMBU2QQZ/xPtTDcjMjDAAYb0tVLVpXY5dOQ9kDMyizKpyrXKybsc/8vCkhvilhzww3kx5zbeaEqgH40QUP8yxEnQOCMKJ0pTDNo8CvMRj53d6jt2Sx4U/XxVaMJwkGQ+J1mnMGxbtgSvRTNy/l6QJ8Kj9JYT0V/ucKz6xgnsqFPci2jG4h25hFE91Kb1sWBro17BcWEWWx3QGtBkWu3bNd7OrEbuxD7zdD1Q6IqApxPS0ijqWsAuY6jHGnyJgkxfB0sGe+f64DZEy3B/g2TNMj3nR2DLhM/ZNDr8ffb6cgXqdyO2HRmH6HgS4GcrORm2FdIIueC42TAMzOWNuGzETx1PINGxO9tDXt4ih594efUwj3hkCN/QR+ga1nhgn/HveOfKcex3svfv3a/IaHHf6apJ+hgEwTIgnw4r5O/DboyQo/wZcvI/ulwEHntwFLtodY0ioBm0WiONBj+83XFs+V33cDAeXFvG6fqP6FgM3Km+f0H07cUmuhBmhbzL3r+WMXwqJJ05ksioWJN1GXF0jo8itXMqwgsG4wLy9Ogx0Xf5uhb1TirSupnQZrNwrcnB0AAIT1jHwxF9AXtBqzsNZJh4Wrtw7LpWinIFahGQAQ0Vwpp20MA6mOzcAE5f5NYApK0aOlvtDnmSIpFPBVGuaRtBBM4TsVYzh2Ae+fw/3IP5n1H5V7uSqEblV7kp6jdQfxjQjTqv2Q7lNJwikAiqTlTQgEPdol6tWGIQtgMETYU1OcdypMb3/iY9jemyCWcP/72CLoMvwXOzLN4MQbsVU2yiPmvADKMXSAHDZonFo8gIWFetYN3eZZlcWBbo2Z0UWQ4BoD3tgiSxYAgK4xyf3x3o3ewnRsuIGuzFmyKQAc6wyjYgHe9iKU1AEIts5W8VYkVu247rS7XdhLtC4KiL2MtX0y2Mfucoy0+e6l9umqown3mD8ou7t/8dYH8mfAauKZnE0dHq3p7Plmu6KHXaUYDAA46GGtzaxf4NqGRbfkI7+Hpz3yeXxJvvhcRfZ6Tf1bD2VOCE97SpzSSd9UylW6o6nD2kN5gwalOlOc1XNqFDTyMLKKwQAAnh4aXo7BIH1TG5d677DSGuPpPBva5oNTt79vYB2iUcwptt8GxtdQN88J38I8MgsQN1UVpeJj+RHyvfp2sZ0YGw6FN2HcCBL3OZ3KyR6DgwpCUfEibONrRUVaqx6zJ9e3UPxLs4O52v43Z+tCv6qGQzV/np76xqg/T2hBiwljyzMhNXRBgIjSMtJAxKpFroOIiEHGFC5ty3MGkIYM04Mtn3GsxuutLPFRUXUbWS/MG5f/401oD6HgDnFr/uxapz2NN2jieQMAQLLQK0mdy0y446HXgwVvG47Omc+AQOMy+Fzl3SvtSlVwPhgAoDo9Fju7rkbuG0ppzjhuiTKqeO6Uo3c9FWOQK3l1YGKi/MpQGg6TM0YsLzT7zIF2VYRS4TCDQk7OGHs4qrTMGcBxrF3OAY47iOE82Oc7A+jmSvvSNmhvG4CbhYlMZh0qOJYh5Y0B9kmnULW4ZLtntL082l4SbQ8wbR+mLd4IU2r6RptNNLUR5RUj2z2l7Tm0if+QeNLS9cO0JVOClZqm0wZkzjhkMDhXmhj9V6PMQnWuW/Hq1CZSwG1rCyKzAgawoMqYbAC8nOEm+BBB45bq0xA/bjYc7+7gc2DHQzV53zdORzqs1iP1kUfgzb+H8SOLE3bchEU14ft0Q2FHqwGvMjfkwx6rcj5o8g61v1imbkCo2v6dozCLX0m8310Ri7fRlg5sC/fqWr2dzxFogsfY3Le1aOtTsm4K6uapwR0m+P/xfafj1i+Lhk6ICZekpVdtP9Tqk3TucPYeYUvNMQMAjgHQwoI2YAi1VqLkps+Mw9z1j4gV1NS9dwNkbEU2la4m9+9uXdPGvKtLtoZQdqgeN4Y4NZybQ+x8oCwkpAubxMkDZnbjyhp961Y6bX3GOvVF2DaO7+NHRLoc/hL+pXf5FW157RNaY2mu0ofLXgV7OxtiVBihEcmklwBtMFpVNZM5YNynXWb6yHkIxmxzYYZ1smdEg2lOwJ7xGcFzEbDlgkUwNmDkYB16ASY+q3DXAE9EPep06HZQq8+oYgxAKaSB7Ah2k9w62dDcvAUAAIPR6iaxLyA0esTVyHTDMDhV4g7wVJ1hfBNgZroUZUvTSQYsmLPVmjnBKj7j7iQ4V6x6QnSVAs4VxSf1V5FxrrHrFfr1wcPW3yIYiHkUDEbp0TAEINUV/aEMnaPA9btt8e2jP0zf4NgnO588NKCUCQ4eXIZF2paC3r6XrDtojwVhAEBbDxWgrGu6GuXQ+NYN4nn0kL3WBwu/QPB5GNBqY3bTphI7i6vgM6QZ0WEvuXVWqooF9ZrdCH0Y4vUsOBEGADiCkDFoGquasyGm88YcXo9arGhKUdOawaMQL8+7YjEKOfSG9JpkK+NOydROKkdcbCe1atDSOeqFAp9qoDlWUe8wbzUDmEd551nfa7+PX9jDkzH3aXZ5AACYxsyWZxqL0oOiGcTQOqb0uQ7RkL4R72zKwHSSTUmto233zqi0kVwZVZ6ZfJ704CS8HjlFoWNHFYFNR6IKcfdzfseeRWY9DTtRu1wAOwkxXIh9sTDQrbLR3hvrU9nY2JOsVaI92NSpUof0SAWy6hLdyhLR4KXxbfeFHLi2LB1TGZUaw4Yr9QL7zksX2ceEWu7+VPYBzyVYpR3bZGNqvB7kVKYZhDg0LHW4f4cwbJ/anMVmt7WFirBOaWNpsdVVqhvvgLlyHMt2R/+hCvsqp9+5wR3IPaRyFArW3fni7o5DsF5EiGAla+owTD5WIbW5V4p7yN2oGPdEKesAAAdJYgRFGwZabT0YRNorHeF2tmgGAByOpWfbEgxqtg3U6b+++9/sOFISU5J2eyfo25v/2V/i70DjXokpKevoc/H6F5Yrz1UOHJ723EZ+/32ZbvkXktPTPfZywibs/M/XcfZ/stX2fC9KZClLhXCVzCgkGZhV+mZoyFi+jCA7GYZdIEp51u9UplvYts3gLRSsK48a9sJEYJ3IsEGfXk6NdafyAAd0Ej7r5rQqNMyZC3PIFJHDV8agd0nSHPhJbFh480fNXQAAFtvb/0ck6KuHr+ZB75KAXoGLOouR8OOyxgQAwLLep+xy2GFg3Xva/6v1gsnwh4mVLnSWSVfBrpKL0rs+lILl9BlrMy1L4dR7RZgYWTQcCwA8TNvSfnZ2H/YwodXfQRaqRjvdNgx+A2BwYYJPeW4tB+JGVxHLrB1thkeLpaJLkLgoDADYwerOQQhwg/7sdHu35/2zJa/JPfUh7mAd9VNCvXLyINiCX4xLF/sBOnRNPH/w6FAHZolJyAP08WEJ5Cq/XUieuyxS5bdnZfCOlt6C5rneDo7eepeDAQB6B1qaziwu0MBwpf2+1fQe/MPkF9mmxM2C61rleS6szE5BZ2gr1zExUa4bgLtvRNn7LdOe/02/6O5No4oHfdZr32MM4ljugHwwlo/6KniqTBCvBvCEVYyvDXhu5YtvsXQK3i7E4Mssx2inAAMoPXuyU1wcG9TigVK8boV3LvW92xFfPclcT0ixXv0UKeryqyT4g083leqZ3vbKR60REtvzznubznoG9+H7mzuPAHQeIPilAtYg2dheQD4/TJ9Kl3dgklxDz60bQ4duadDf073dexFk+BzKii0vYFF8CzbgAMRQoC5q9fRa91fiWPefWbAXy7dP4eVfe1LeuXtbDwrWp1WXB9frc+PfwTZPm+6zEV/glYgpiTsf1OuH3HHvG34h3fmQXRWHc2R3ARqdMOUo/Sia6l9LH4bhvtnqy0s+6CUKlP2dw0RY0j3SGo8/tUPZ6/rsFzaakg3ydCB5XLhXKX1qmdtBeI/whzTEOyd5+VIb+NGxCLaW2KdgdG6Ok6nJxTGRgFOM3qELTunQIN1wTrXxzJnAbZyC7ix9l3ZlRxaEAQCOLXmHr7GgrSp5pTLy6rnyRXmHtzCvuwE6M4vge15452bhRm8LwKKNAVYpYr8Oa2kThF2dLrQOa2+rGHYtDutI+cJezzEB6/QUO7ngFXZ7DCA2zRV2D01aNgfYpg2ipRrYHA2pvQqQYV/KaR40kf3qzt0oL8ftcfy9lHGt+FLu+KCRWUwAQEfvswaJnBSmhVzjfTA97L4/SKQJ6oLaLw62BLunrfHM5roBMpyqYgoLZDbfglMziFzp4+8Bf7dJN7jtZb3KQecXHoef+217+3Gz7cH27s7s1aERt5SZ4dwMYxrfFrIyLQ==\",\"base64\")).toString()),nH}var Lde=new Map([[W.makeIdent(null,\"fsevents\").identHash,Fde],[W.makeIdent(null,\"resolve\").identHash,Rde],[W.makeIdent(null,\"typescript\").identHash,Tde]]),bgt={hooks:{registerPackageExtensions:async(t,e)=>{for(let[r,o]of eH)e(W.parseDescriptor(r,!0),o)},getBuiltinPatch:async(t,e)=>{let r=\"compat/\";if(!e.startsWith(r))return;let o=W.parseIdent(e.slice(r.length)),a=Lde.get(o.identHash)?.();return typeof a<\"u\"?a:null},reduceDependency:async(t,e,r,o)=>typeof Lde.get(t.identHash)>\"u\"?t:W.makeDescriptor(t,W.makeRange({protocol:\"patch:\",source:W.stringifyDescriptor(t),selector:`optional!builtin<compat/${W.stringifyIdent(t)}>`,params:null}))}},xgt=bgt;var wH={};zt(wH,{ConstraintsCheckCommand:()=>g0,ConstraintsQueryCommand:()=>p0,ConstraintsSourceCommand:()=>h0,default:()=>rdt});Ye();Ye();v2();var IC=class{constructor(e){this.project=e}createEnvironment(){let e=new wC([\"cwd\",\"ident\"]),r=new wC([\"workspace\",\"type\",\"ident\"]),o=new wC([\"ident\"]),a={manifestUpdates:new Map,reportedErrors:new Map},n=new Map,u=new Map;for(let A of this.project.storedPackages.values()){let p=Array.from(A.peerDependencies.values(),h=>[W.stringifyIdent(h),h.range]);n.set(A.locatorHash,{workspace:null,ident:W.stringifyIdent(A),version:A.version,dependencies:new Map,peerDependencies:new Map(p.filter(([h])=>A.peerDependenciesMeta.get(h)?.optional!==!0)),optionalPeerDependencies:new Map(p.filter(([h])=>A.peerDependenciesMeta.get(h)?.optional===!0))})}for(let A of this.project.storedPackages.values()){let p=n.get(A.locatorHash);p.dependencies=new Map(Array.from(A.dependencies.values(),h=>{let E=this.project.storedResolutions.get(h.descriptorHash);if(typeof E>\"u\")throw new Error(\"Assertion failed: The resolution should have been registered\");let I=n.get(E);if(typeof I>\"u\")throw new Error(\"Assertion failed: The package should have been registered\");return[W.stringifyIdent(h),I]})),p.dependencies.delete(p.ident)}for(let A of this.project.workspaces){let p=W.stringifyIdent(A.anchoredLocator),h=A.manifest.exportTo({}),E=n.get(A.anchoredLocator.locatorHash);if(typeof E>\"u\")throw new Error(\"Assertion failed: The package should have been registered\");let I=(R,N,{caller:U=Vi.getCaller()}={})=>{let V=B2(R),te=_e.getMapWithDefault(a.manifestUpdates,A.cwd),ae=_e.getMapWithDefault(te,V),fe=_e.getSetWithDefault(ae,N);U!==null&&fe.add(U)},v=R=>I(R,void 0,{caller:Vi.getCaller()}),x=R=>{_e.getArrayWithDefault(a.reportedErrors,A.cwd).push(R)},C=e.insert({cwd:A.relativeCwd,ident:p,manifest:h,pkg:E,set:I,unset:v,error:x});u.set(A,C);for(let R of Ot.allDependencies)for(let N of A.manifest[R].values()){let U=W.stringifyIdent(N),V=()=>{I([R,U],void 0,{caller:Vi.getCaller()})},te=fe=>{I([R,U],fe,{caller:Vi.getCaller()})},ae=null;if(R!==\"peerDependencies\"&&(R!==\"dependencies\"||!A.manifest.devDependencies.has(N.identHash))){let fe=A.anchoredPackage.dependencies.get(N.identHash);if(fe){if(typeof fe>\"u\")throw new Error(\"Assertion failed: The dependency should have been registered\");let ue=this.project.storedResolutions.get(fe.descriptorHash);if(typeof ue>\"u\")throw new Error(\"Assertion failed: The resolution should have been registered\");let me=n.get(ue);if(typeof me>\"u\")throw new Error(\"Assertion failed: The package should have been registered\");ae=me}}r.insert({workspace:C,ident:U,range:N.range,type:R,resolution:ae,update:te,delete:V,error:x})}}for(let A of this.project.storedPackages.values()){let p=this.project.tryWorkspaceByLocator(A);if(!p)continue;let h=u.get(p);if(typeof h>\"u\")throw new Error(\"Assertion failed: The workspace should have been registered\");let E=n.get(A.locatorHash);if(typeof E>\"u\")throw new Error(\"Assertion failed: The package should have been registered\");E.workspace=h}return{workspaces:e,dependencies:r,packages:o,result:a}}async process(){let e=this.createEnvironment(),r={Yarn:{workspace:a=>e.workspaces.find(a)[0]??null,workspaces:a=>e.workspaces.find(a),dependency:a=>e.dependencies.find(a)[0]??null,dependencies:a=>e.dependencies.find(a),package:a=>e.packages.find(a)[0]??null,packages:a=>e.packages.find(a)}},o=await this.project.loadUserConfig();return o?.constraints?(await o.constraints(r),e.result):null}};Ye();Ye();qt();var p0=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.query=ge.String()}async execute(){let{Constraints:r}=await Promise.resolve().then(()=>(x2(),b2)),o=await Ke.find(this.context.cwd,this.context.plugins),{project:a}=await St.find(o,this.context.cwd),n=await r.find(a),u=this.query;return u.endsWith(\".\")||(u=`${u}.`),(await Lt.start({configuration:o,json:this.json,stdout:this.context.stdout},async p=>{for await(let h of n.query(u)){let E=Array.from(Object.entries(h)),I=E.length,v=E.reduce((x,[C])=>Math.max(x,C.length),0);for(let x=0;x<I;x++){let[C,R]=E[x];p.reportInfo(null,`${edt(x,I)}${C.padEnd(v,\" \")} = ${$gt(R)}`)}p.reportJson(h)}})).exitCode()}};p0.paths=[[\"constraints\",\"query\"]],p0.usage=nt.Usage({category:\"Constraints-related commands\",description:\"query the constraints fact database\",details:`\n      This command will output all matches to the given prolog query.\n    `,examples:[[\"List all dependencies throughout the workspace\",\"yarn constraints query 'workspace_has_dependency(_, DependencyName, _, _).'\"]]});function $gt(t){return typeof t!=\"string\"?`${t}`:t.match(/^[a-zA-Z][a-zA-Z0-9_]+$/)?t:`'${t}'`}function edt(t,e){let r=t===0,o=t===e-1;return r&&o?\"\":r?\"\\u250C \":o?\"\\u2514 \":\"\\u2502 \"}Ye();qt();var h0=class extends ut{constructor(){super(...arguments);this.verbose=ge.Boolean(\"-v,--verbose\",!1,{description:\"Also print the fact database automatically compiled from the workspace manifests\"})}async execute(){let{Constraints:r}=await Promise.resolve().then(()=>(x2(),b2)),o=await Ke.find(this.context.cwd,this.context.plugins),{project:a}=await St.find(o,this.context.cwd),n=await r.find(a);this.context.stdout.write(this.verbose?n.fullSource:n.source)}};h0.paths=[[\"constraints\",\"source\"]],h0.usage=nt.Usage({category:\"Constraints-related commands\",description:\"print the source code for the constraints\",details:\"\\n      This command will print the Prolog source code used by the constraints engine. Adding the `-v,--verbose` flag will print the *full* source code, including the fact database automatically compiled from the workspace manifests.\\n    \",examples:[[\"Prints the source code\",\"yarn constraints source\"],[\"Print the source code and the fact database\",\"yarn constraints source -v\"]]});Ye();Ye();qt();v2();var g0=class extends ut{constructor(){super(...arguments);this.fix=ge.Boolean(\"--fix\",!1,{description:\"Attempt to automatically fix unambiguous issues, following a multi-pass process\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd);await o.restoreInstallState();let a=await o.loadUserConfig(),n;if(a?.constraints)n=new IC(o);else{let{Constraints:h}=await Promise.resolve().then(()=>(x2(),b2));n=await h.find(o)}let u,A=!1,p=!1;for(let h=this.fix?10:1;h>0;--h){let E=await n.process();if(!E)break;let{changedWorkspaces:I,remainingErrors:v}=gk(o,E,{fix:this.fix}),x=[];for(let[C,R]of I){let N=C.manifest.indent;C.manifest=new Ot,C.manifest.indent=N,C.manifest.load(R),x.push(C.persistManifest())}if(await Promise.all(x),!(I.size>0&&h>1)){u=qde(v,{configuration:r}),A=!1,p=!0;for(let[,C]of v)for(let R of C)R.fixable?A=!0:p=!1}}if(u.children.length===0)return 0;if(A){let h=p?`Those errors can all be fixed by running ${de.pretty(r,\"yarn constraints --fix\",de.Type.CODE)}`:`Errors prefixed by '\\u2699' can be fixed by running ${de.pretty(r,\"yarn constraints --fix\",de.Type.CODE)}`;await Lt.start({configuration:r,stdout:this.context.stdout,includeNames:!1,includeFooter:!1},async E=>{E.reportInfo(0,h),E.reportSeparator()})}return u.children=_e.sortMap(u.children,h=>h.value[1]),$s.emitTree(u,{configuration:r,stdout:this.context.stdout,json:this.json,separators:1}),1}};g0.paths=[[\"constraints\"]],g0.usage=nt.Usage({category:\"Constraints-related commands\",description:\"check that the project constraints are met\",details:`\n      This command will run constraints on your project and emit errors for each one that is found but isn't met. If any error is emitted the process will exit with a non-zero exit code.\n\n      If the \\`--fix\\` flag is used, Yarn will attempt to automatically fix the issues the best it can, following a multi-pass process (with a maximum of 10 iterations). Some ambiguous patterns cannot be autofixed, in which case you'll have to manually specify the right resolution.\n\n      For more information as to how to write constraints, please consult our dedicated page on our website: https://yarnpkg.com/features/constraints.\n    `,examples:[[\"Check that all constraints are satisfied\",\"yarn constraints\"],[\"Autofix all unmet constraints\",\"yarn constraints --fix\"]]});v2();var tdt={configuration:{enableConstraintsChecks:{description:\"If true, constraints will run during installs\",type:\"BOOLEAN\",default:!1},constraintsPath:{description:\"The path of the constraints file.\",type:\"ABSOLUTE_PATH\",default:\"./constraints.pro\"}},commands:[p0,h0,g0],hooks:{async validateProjectAfterInstall(t,{reportError:e}){if(!t.configuration.get(\"enableConstraintsChecks\"))return;let r=await t.loadUserConfig(),o;if(r?.constraints)o=new IC(t);else{let{Constraints:u}=await Promise.resolve().then(()=>(x2(),b2));o=await u.find(t)}let a=await o.process();if(!a)return;let{remainingErrors:n}=gk(t,a);if(n.size!==0)if(t.configuration.isCI)for(let[u,A]of n)for(let p of A)e(84,`${de.pretty(t.configuration,u.anchoredLocator,de.Type.IDENT)}: ${p.text}`);else e(84,`Constraint check failed; run ${de.pretty(t.configuration,\"yarn constraints\",de.Type.CODE)} for more details`)}}},rdt=tdt;var IH={};zt(IH,{CreateCommand:()=>rm,DlxCommand:()=>d0,default:()=>idt});Ye();qt();var rm=class extends ut{constructor(){super(...arguments);this.pkg=ge.String(\"-p,--package\",{description:\"The package to run the provided command from\"});this.quiet=ge.Boolean(\"-q,--quiet\",!1,{description:\"Only report critical errors instead of printing the full install logs\"});this.command=ge.String();this.args=ge.Proxy()}async execute(){let r=[];this.pkg&&r.push(\"--package\",this.pkg),this.quiet&&r.push(\"--quiet\");let o=this.command.replace(/^(@[^@/]+)(@|$)/,\"$1/create$2\"),a=W.parseDescriptor(o),n=a.name.match(/^create(-|$)/)?a:a.scope?W.makeIdent(a.scope,`create-${a.name}`):W.makeIdent(null,`create-${a.name}`),u=W.stringifyIdent(n);return a.range!==\"unknown\"&&(u+=`@${a.range}`),this.cli.run([\"dlx\",...r,u,...this.args])}};rm.paths=[[\"create\"]];Ye();Ye();Pt();qt();var d0=class extends ut{constructor(){super(...arguments);this.packages=ge.Array(\"-p,--package\",{description:\"The package(s) to install before running the command\"});this.quiet=ge.Boolean(\"-q,--quiet\",!1,{description:\"Only report critical errors instead of printing the full install logs\"});this.command=ge.String();this.args=ge.Proxy()}async execute(){return Ke.telemetry=null,await oe.mktempPromise(async r=>{let o=z.join(r,`dlx-${process.pid}`);await oe.mkdirPromise(o),await oe.writeFilePromise(z.join(o,\"package.json\"),`{}\n`),await oe.writeFilePromise(z.join(o,\"yarn.lock\"),\"\");let a=z.join(o,\".yarnrc.yml\"),n=await Ke.findProjectCwd(this.context.cwd),A={enableGlobalCache:!(await Ke.find(this.context.cwd,null,{strict:!1})).get(\"enableGlobalCache\"),enableTelemetry:!1,logFilters:[{code:Ku(68),level:de.LogLevel.Discard}]},p=n!==null?z.join(n,\".yarnrc.yml\"):null;p!==null&&oe.existsSync(p)?(await oe.copyFilePromise(p,a),await Ke.updateConfiguration(o,N=>{let U=_e.toMerged(N,A);return Array.isArray(N.plugins)&&(U.plugins=N.plugins.map(V=>{let te=typeof V==\"string\"?V:V.path,ae=le.isAbsolute(te)?te:le.resolve(le.fromPortablePath(n),te);return typeof V==\"string\"?ae:{path:ae,spec:V.spec}})),U})):await oe.writeJsonPromise(a,A);let h=this.packages??[this.command],E=W.parseDescriptor(this.command).name,I=await this.cli.run([\"add\",\"--fixed\",\"--\",...h],{cwd:o,quiet:this.quiet});if(I!==0)return I;this.quiet||this.context.stdout.write(`\n`);let v=await Ke.find(o,this.context.plugins),{project:x,workspace:C}=await St.find(v,o);if(C===null)throw new nr(x.cwd,o);await x.restoreInstallState();let R=await un.getWorkspaceAccessibleBinaries(C);return R.has(E)===!1&&R.size===1&&typeof this.packages>\"u\"&&(E=Array.from(R)[0][0]),await un.executeWorkspaceAccessibleBinary(C,E,this.args,{packageAccessibleBinaries:R,cwd:this.context.cwd,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr})})}};d0.paths=[[\"dlx\"]],d0.usage=nt.Usage({description:\"run a package in a temporary environment\",details:\"\\n      This command will install a package within a temporary environment, and run its binary script if it contains any. The binary will run within the current cwd.\\n\\n      By default Yarn will download the package named `command`, but this can be changed through the use of the `-p,--package` flag which will instruct Yarn to still run the same command but from a different package.\\n\\n      Using `yarn dlx` as a replacement of `yarn add` isn't recommended, as it makes your project non-deterministic (Yarn doesn't keep track of the packages installed through `dlx` - neither their name, nor their version).\\n    \",examples:[[\"Use create-react-app to create a new React app\",\"yarn dlx create-react-app ./my-app\"],[\"Install multiple packages for a single command\",`yarn dlx -p typescript -p ts-node ts-node --transpile-only -e \"console.log('hello!')\"`]]});var ndt={commands:[rm,d0]},idt=ndt;var DH={};zt(DH,{ExecFetcher:()=>Q2,ExecResolver:()=>F2,default:()=>adt,execUtils:()=>Ek});Ye();Ye();Pt();var pA=\"exec:\";var Ek={};zt(Ek,{loadGeneratorFile:()=>k2,makeLocator:()=>vH,makeSpec:()=>hme,parseSpec:()=>BH});Ye();Pt();function BH(t){let{params:e,selector:r}=W.parseRange(t),o=le.toPortablePath(r);return{parentLocator:e&&typeof e.locator==\"string\"?W.parseLocator(e.locator):null,path:o}}function hme({parentLocator:t,path:e,generatorHash:r,protocol:o}){let a=t!==null?{locator:W.stringifyLocator(t)}:{},n=typeof r<\"u\"?{hash:r}:{};return W.makeRange({protocol:o,source:e,selector:e,params:{...n,...a}})}function vH(t,{parentLocator:e,path:r,generatorHash:o,protocol:a}){return W.makeLocator(t,hme({parentLocator:e,path:r,generatorHash:o,protocol:a}))}async function k2(t,e,r){let{parentLocator:o,path:a}=W.parseFileStyleRange(t,{protocol:e}),n=z.isAbsolute(a)?{packageFs:new gn(Bt.root),prefixPath:Bt.dot,localPath:Bt.root}:await r.fetcher.fetch(o,r),u=n.localPath?{packageFs:new gn(Bt.root),prefixPath:z.relative(Bt.root,n.localPath)}:n;n!==u&&n.releaseFs&&n.releaseFs();let A=u.packageFs,p=z.join(u.prefixPath,a);return await A.readFilePromise(p,\"utf8\")}var Q2=class{supports(e,r){return!!e.reference.startsWith(pA)}getLocalPath(e,r){let{parentLocator:o,path:a}=W.parseFileStyleRange(e.reference,{protocol:pA});if(z.isAbsolute(a))return a;let n=r.fetcher.getLocalPath(o,r);return n===null?null:z.resolve(n,a)}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e),loader:()=>this.fetchFromDisk(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),localPath:this.getLocalPath(e,r),checksum:u}}async fetchFromDisk(e,r){let o=await k2(e.reference,pA,r);return oe.mktempPromise(async a=>{let n=z.join(a,\"generator.js\");return await oe.writeFilePromise(n,o),oe.mktempPromise(async u=>{if(await this.generatePackage(u,e,n,r),!oe.existsSync(z.join(u,\"build\")))throw new Error(\"The script should have generated a build directory\");return await Xi.makeArchiveFromDirectory(z.join(u,\"build\"),{prefixPath:W.getIdentVendorPath(e),compressionLevel:r.project.configuration.get(\"compressionLevel\")})})})}async generatePackage(e,r,o,a){return await oe.mktempPromise(async n=>{let u=await un.makeScriptEnv({project:a.project,binFolder:n}),A=z.join(e,\"runtime.js\");return await oe.mktempPromise(async p=>{let h=z.join(p,\"buildfile.log\"),E=z.join(e,\"generator\"),I=z.join(e,\"build\");await oe.mkdirPromise(E),await oe.mkdirPromise(I);let v={tempDir:le.fromPortablePath(E),buildDir:le.fromPortablePath(I),locator:W.stringifyLocator(r)};await oe.writeFilePromise(A,`\n          // Expose 'Module' as a global variable\n          Object.defineProperty(global, 'Module', {\n            get: () => require('module'),\n            configurable: true,\n            enumerable: false,\n          });\n\n          // Expose non-hidden built-in modules as global variables\n          for (const name of Module.builtinModules.filter((name) => name !== 'module' && !name.startsWith('_'))) {\n            Object.defineProperty(global, name, {\n              get: () => require(name),\n              configurable: true,\n              enumerable: false,\n            });\n          }\n\n          // Expose the 'execEnv' global variable\n          Object.defineProperty(global, 'execEnv', {\n            value: {\n              ...${JSON.stringify(v)},\n            },\n            enumerable: true,\n          });\n        `);let x=u.NODE_OPTIONS||\"\",C=/\\s*--require\\s+\\S*\\.pnp\\.c?js\\s*/g;x=x.replace(C,\" \").trim(),u.NODE_OPTIONS=x;let{stdout:R,stderr:N}=a.project.configuration.getSubprocessStreams(h,{header:`# This file contains the result of Yarn generating a package (${W.stringifyLocator(r)})\n`,prefix:W.prettyLocator(a.project.configuration,r),report:a.report}),{code:U}=await Ur.pipevp(process.execPath,[\"--require\",le.fromPortablePath(A),le.fromPortablePath(o),W.stringifyIdent(r)],{cwd:e,env:u,stdin:null,stdout:R,stderr:N});if(U!==0)throw oe.detachTemp(p),new Error(`Package generation failed (exit code ${U}, logs can be found here: ${de.pretty(a.project.configuration,h,de.Type.PATH)})`)})})}};Ye();Ye();var sdt=2,F2=class{supportsDescriptor(e,r){return!!e.range.startsWith(pA)}supportsLocator(e,r){return!!e.reference.startsWith(pA)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,o){return W.bindDescriptor(e,{locator:W.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){if(!o.fetchOptions)throw new Error(\"Assertion failed: This resolver cannot be used unless a fetcher is configured\");let{path:a,parentLocator:n}=BH(e.range);if(n===null)throw new Error(\"Assertion failed: The descriptor should have been bound\");let u=await k2(W.makeRange({protocol:pA,source:a,selector:a,params:{locator:W.stringifyLocator(n)}}),pA,o.fetchOptions),A=wn.makeHash(`${sdt}`,u).slice(0,6);return[vH(e,{parentLocator:n,path:a,generatorHash:A,protocol:pA})]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error(\"Assertion failed: This resolver cannot be used unless a fetcher is configured\");let o=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await _e.releaseAfterUseAsync(async()=>await Ot.find(o.prefixPath,{baseFs:o.packageFs}),o.releaseFs);return{...e,version:a.version||\"0.0.0\",languageName:a.languageName||r.project.configuration.get(\"defaultLanguageName\"),linkType:\"HARD\",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var odt={fetchers:[Q2],resolvers:[F2]},adt=odt;var SH={};zt(SH,{FileFetcher:()=>N2,FileResolver:()=>O2,TarballFileFetcher:()=>M2,TarballFileResolver:()=>U2,default:()=>udt,fileUtils:()=>nm});Ye();Pt();var PC=/^(?:[a-zA-Z]:[\\\\/]|\\.{0,2}\\/)/,R2=/^[^?]*\\.(?:tar\\.gz|tgz)(?:::.*)?$/,Ui=\"file:\";var nm={};zt(nm,{fetchArchiveFromLocator:()=>L2,makeArchiveFromLocator:()=>Ck,makeBufferFromLocator:()=>PH,makeLocator:()=>SC,makeSpec:()=>gme,parseSpec:()=>T2});Ye();Pt();function T2(t){let{params:e,selector:r}=W.parseRange(t),o=le.toPortablePath(r);return{parentLocator:e&&typeof e.locator==\"string\"?W.parseLocator(e.locator):null,path:o}}function gme({parentLocator:t,path:e,hash:r,protocol:o}){let a=t!==null?{locator:W.stringifyLocator(t)}:{},n=typeof r<\"u\"?{hash:r}:{};return W.makeRange({protocol:o,source:e,selector:e,params:{...n,...a}})}function SC(t,{parentLocator:e,path:r,hash:o,protocol:a}){return W.makeLocator(t,gme({parentLocator:e,path:r,hash:o,protocol:a}))}async function L2(t,e){let{parentLocator:r,path:o}=W.parseFileStyleRange(t.reference,{protocol:Ui}),a=z.isAbsolute(o)?{packageFs:new gn(Bt.root),prefixPath:Bt.dot,localPath:Bt.root}:await e.fetcher.fetch(r,e),n=a.localPath?{packageFs:new gn(Bt.root),prefixPath:z.relative(Bt.root,a.localPath)}:a;a!==n&&a.releaseFs&&a.releaseFs();let u=n.packageFs,A=z.join(n.prefixPath,o);return await _e.releaseAfterUseAsync(async()=>await u.readFilePromise(A),n.releaseFs)}async function Ck(t,{protocol:e,fetchOptions:r,inMemory:o=!1}){let{parentLocator:a,path:n}=W.parseFileStyleRange(t.reference,{protocol:e}),u=z.isAbsolute(n)?{packageFs:new gn(Bt.root),prefixPath:Bt.dot,localPath:Bt.root}:await r.fetcher.fetch(a,r),A=u.localPath?{packageFs:new gn(Bt.root),prefixPath:z.relative(Bt.root,u.localPath)}:u;u!==A&&u.releaseFs&&u.releaseFs();let p=A.packageFs,h=z.join(A.prefixPath,n);return await _e.releaseAfterUseAsync(async()=>await Xi.makeArchiveFromDirectory(h,{baseFs:p,prefixPath:W.getIdentVendorPath(t),compressionLevel:r.project.configuration.get(\"compressionLevel\"),inMemory:o}),A.releaseFs)}async function PH(t,{protocol:e,fetchOptions:r}){return(await Ck(t,{protocol:e,fetchOptions:r,inMemory:!0})).getBufferAndClose()}var N2=class{supports(e,r){return!!e.reference.startsWith(Ui)}getLocalPath(e,r){let{parentLocator:o,path:a}=W.parseFileStyleRange(e.reference,{protocol:Ui});if(z.isAbsolute(a))return a;let n=r.fetcher.getLocalPath(o,r);return n===null?null:z.resolve(n,a)}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the disk`),loader:()=>this.fetchFromDisk(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),localPath:this.getLocalPath(e,r),checksum:u}}async fetchFromDisk(e,r){return Ck(e,{protocol:Ui,fetchOptions:r})}};Ye();Ye();var ldt=2,O2=class{supportsDescriptor(e,r){return e.range.match(PC)?!0:!!e.range.startsWith(Ui)}supportsLocator(e,r){return!!e.reference.startsWith(Ui)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,o){return PC.test(e.range)&&(e=W.makeDescriptor(e,`${Ui}${e.range}`)),W.bindDescriptor(e,{locator:W.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){if(!o.fetchOptions)throw new Error(\"Assertion failed: This resolver cannot be used unless a fetcher is configured\");let{path:a,parentLocator:n}=T2(e.range);if(n===null)throw new Error(\"Assertion failed: The descriptor should have been bound\");let u=await PH(W.makeLocator(e,W.makeRange({protocol:Ui,source:a,selector:a,params:{locator:W.stringifyLocator(n)}})),{protocol:Ui,fetchOptions:o.fetchOptions}),A=wn.makeHash(`${ldt}`,u).slice(0,6);return[SC(e,{parentLocator:n,path:a,hash:A,protocol:Ui})]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error(\"Assertion failed: This resolver cannot be used unless a fetcher is configured\");let o=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await _e.releaseAfterUseAsync(async()=>await Ot.find(o.prefixPath,{baseFs:o.packageFs}),o.releaseFs);return{...e,version:a.version||\"0.0.0\",languageName:a.languageName||r.project.configuration.get(\"defaultLanguageName\"),linkType:\"HARD\",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};Ye();var M2=class{supports(e,r){return R2.test(e.reference)?!!e.reference.startsWith(Ui):!1}getLocalPath(e,r){return null}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the disk`),loader:()=>this.fetchFromDisk(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),checksum:u}}async fetchFromDisk(e,r){let o=await L2(e,r);return await Xi.convertToZip(o,{configuration:r.project.configuration,prefixPath:W.getIdentVendorPath(e),stripComponents:1})}};Ye();Ye();Ye();var U2=class{supportsDescriptor(e,r){return R2.test(e.range)?!!(e.range.startsWith(Ui)||PC.test(e.range)):!1}supportsLocator(e,r){return R2.test(e.reference)?!!e.reference.startsWith(Ui):!1}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,o){return PC.test(e.range)&&(e=W.makeDescriptor(e,`${Ui}${e.range}`)),W.bindDescriptor(e,{locator:W.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){if(!o.fetchOptions)throw new Error(\"Assertion failed: This resolver cannot be used unless a fetcher is configured\");let{path:a,parentLocator:n}=T2(e.range);if(n===null)throw new Error(\"Assertion failed: The descriptor should have been bound\");let u=SC(e,{parentLocator:n,path:a,hash:\"\",protocol:Ui}),A=await L2(u,o.fetchOptions),p=wn.makeHash(A).slice(0,6);return[SC(e,{parentLocator:n,path:a,hash:p,protocol:Ui})]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error(\"Assertion failed: This resolver cannot be used unless a fetcher is configured\");let o=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await _e.releaseAfterUseAsync(async()=>await Ot.find(o.prefixPath,{baseFs:o.packageFs}),o.releaseFs);return{...e,version:a.version||\"0.0.0\",languageName:a.languageName||r.project.configuration.get(\"defaultLanguageName\"),linkType:\"HARD\",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var cdt={fetchers:[M2,N2],resolvers:[U2,O2]},udt=cdt;var kH={};zt(kH,{GithubFetcher:()=>_2,default:()=>fdt,githubUtils:()=>wk});Ye();Pt();var wk={};zt(wk,{invalidGithubUrlMessage:()=>yme,isGithubUrl:()=>bH,parseGithubUrl:()=>xH});var dme=$e(ve(\"querystring\")),mme=[/^https?:\\/\\/(?:([^/]+?)@)?github.com\\/([^/#]+)\\/([^/#]+)\\/tarball\\/([^/#]+)(?:#(.*))?$/,/^https?:\\/\\/(?:([^/]+?)@)?github.com\\/([^/#]+)\\/([^/#]+?)(?:\\.git)?(?:#(.*))?$/];function bH(t){return t?mme.some(e=>!!t.match(e)):!1}function xH(t){let e;for(let A of mme)if(e=t.match(A),e)break;if(!e)throw new Error(yme(t));let[,r,o,a,n=\"master\"]=e,{commit:u}=dme.default.parse(n);return n=u||n.replace(/[^:]*:/,\"\"),{auth:r,username:o,reponame:a,treeish:n}}function yme(t){return`Input cannot be parsed as a valid GitHub URL ('${t}').`}var _2=class{supports(e,r){return!!bH(e.reference)}getLocalPath(e,r){return null}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from GitHub`),loader:()=>this.fetchFromNetwork(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),checksum:u}}async fetchFromNetwork(e,r){let o=await nn.get(this.getLocatorUrl(e,r),{configuration:r.project.configuration});return await oe.mktempPromise(async a=>{let n=new gn(a);await Xi.extractArchiveTo(o,n,{stripComponents:1});let u=ra.splitRepoUrl(e.reference),A=z.join(a,\"package.tgz\");await un.prepareExternalProject(a,A,{configuration:r.project.configuration,report:r.report,workspace:u.extra.workspace,locator:e});let p=await oe.readFilePromise(A);return await Xi.convertToZip(p,{configuration:r.project.configuration,prefixPath:W.getIdentVendorPath(e),stripComponents:1})})}getLocatorUrl(e,r){let{auth:o,username:a,reponame:n,treeish:u}=xH(e.reference);return`https://${o?`${o}@`:\"\"}github.com/${a}/${n}/archive/${u}.tar.gz`}};var Adt={hooks:{async fetchHostedRepository(t,e,r){if(t!==null)return t;let o=new _2;if(!o.supports(e,r))return null;try{return await o.fetch(e,r)}catch{return null}}}},fdt=Adt;var QH={};zt(QH,{TarballHttpFetcher:()=>q2,TarballHttpResolver:()=>G2,default:()=>hdt});Ye();function H2(t){let e;try{e=new URL(t)}catch{return!1}return!(e.protocol!==\"http:\"&&e.protocol!==\"https:\"||!e.pathname.match(/(\\.tar\\.gz|\\.tgz|\\/[^.]+)$/))}var q2=class{supports(e,r){return H2(e.reference)}getLocalPath(e,r){return null}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the remote server`),loader:()=>this.fetchFromNetwork(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),checksum:u}}async fetchFromNetwork(e,r){let o=await nn.get(e.reference,{configuration:r.project.configuration});return await Xi.convertToZip(o,{configuration:r.project.configuration,prefixPath:W.getIdentVendorPath(e),stripComponents:1})}};Ye();Ye();var G2=class{supportsDescriptor(e,r){return H2(e.range)}supportsLocator(e,r){return H2(e.reference)}shouldPersistResolution(e,r){return!0}bindDescriptor(e,r,o){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){return[W.convertDescriptorToLocator(e)]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error(\"Assertion failed: This resolver cannot be used unless a fetcher is configured\");let o=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await _e.releaseAfterUseAsync(async()=>await Ot.find(o.prefixPath,{baseFs:o.packageFs}),o.releaseFs);return{...e,version:a.version||\"0.0.0\",languageName:a.languageName||r.project.configuration.get(\"defaultLanguageName\"),linkType:\"HARD\",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var pdt={fetchers:[q2],resolvers:[G2]},hdt=pdt;var FH={};zt(FH,{InitCommand:()=>m0,default:()=>ddt});Ye();Ye();Pt();qt();var m0=class extends ut{constructor(){super(...arguments);this.private=ge.Boolean(\"-p,--private\",!1,{description:\"Initialize a private package\"});this.workspace=ge.Boolean(\"-w,--workspace\",!1,{description:\"Initialize a workspace root with a `packages/` directory\"});this.install=ge.String(\"-i,--install\",!1,{tolerateBoolean:!0,description:\"Initialize a package with a specific bundle that will be locked in the project\"});this.name=ge.String(\"-n,--name\",{description:\"Initialize a package with the given name\"});this.usev2=ge.Boolean(\"-2\",!1,{hidden:!0});this.yes=ge.Boolean(\"-y,--yes\",{hidden:!0})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),o=typeof this.install==\"string\"?this.install:this.usev2||this.install===!0?\"latest\":null;return o!==null?await this.executeProxy(r,o):await this.executeRegular(r)}async executeProxy(r,o){if(r.projectCwd!==null&&r.projectCwd!==this.context.cwd)throw new it(\"Cannot use the --install flag from within a project subdirectory\");oe.existsSync(this.context.cwd)||await oe.mkdirPromise(this.context.cwd,{recursive:!0});let a=z.join(this.context.cwd,dr.lockfile);oe.existsSync(a)||await oe.writeFilePromise(a,\"\");let n=await this.cli.run([\"set\",\"version\",o],{quiet:!0});if(n!==0)return n;let u=[];return this.private&&u.push(\"-p\"),this.workspace&&u.push(\"-w\"),this.name&&u.push(`-n=${this.name}`),this.yes&&u.push(\"-y\"),await oe.mktempPromise(async A=>{let{code:p}=await Ur.pipevp(\"yarn\",[\"init\",...u],{cwd:this.context.cwd,stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr,env:await un.makeScriptEnv({binFolder:A})});return p})}async executeRegular(r){let o=null;try{o=(await St.find(r,this.context.cwd)).project}catch{o=null}oe.existsSync(this.context.cwd)||await oe.mkdirPromise(this.context.cwd,{recursive:!0});let a=await Ot.tryFind(this.context.cwd),n=a??new Ot,u=Object.fromEntries(r.get(\"initFields\").entries());n.load(u),n.name=n.name??W.makeIdent(r.get(\"initScope\"),this.name??z.basename(this.context.cwd)),n.packageManager=rn&&_e.isTaggedYarnVersion(rn)?`yarn@${rn}`:null,(!a&&this.workspace||this.private)&&(n.private=!0),this.workspace&&n.workspaceDefinitions.length===0&&(await oe.mkdirPromise(z.join(this.context.cwd,\"packages\"),{recursive:!0}),n.workspaceDefinitions=[{pattern:\"packages/*\"}]);let A={};n.exportTo(A);let p=z.join(this.context.cwd,Ot.fileName);await oe.changeFilePromise(p,`${JSON.stringify(A,null,2)}\n`,{automaticNewlines:!0});let h=[p],E=z.join(this.context.cwd,\"README.md\");if(oe.existsSync(E)||(await oe.writeFilePromise(E,`# ${W.stringifyIdent(n.name)}\n`),h.push(E)),!o||o.cwd===this.context.cwd){let I=z.join(this.context.cwd,dr.lockfile);oe.existsSync(I)||(await oe.writeFilePromise(I,\"\"),h.push(I));let x=[\".yarn/*\",\"!.yarn/patches\",\"!.yarn/plugins\",\"!.yarn/releases\",\"!.yarn/sdks\",\"!.yarn/versions\",\"\",\"# Swap the comments on the following lines if you wish to use zero-installs\",\"# In that case, don't forget to run `yarn config set enableGlobalCache false`!\",\"# Documentation here: https://yarnpkg.com/features/caching#zero-installs\",\"\",\"#!.yarn/cache\",\".pnp.*\"].map(fe=>`${fe}\n`).join(\"\"),C=z.join(this.context.cwd,\".gitignore\");oe.existsSync(C)||(await oe.writeFilePromise(C,x),h.push(C));let N=[\"/.yarn/**            linguist-vendored\",\"/.yarn/releases/*    binary\",\"/.yarn/plugins/**/*  binary\",\"/.pnp.*              binary linguist-generated\"].map(fe=>`${fe}\n`).join(\"\"),U=z.join(this.context.cwd,\".gitattributes\");oe.existsSync(U)||(await oe.writeFilePromise(U,N),h.push(U));let V={[\"*\"]:{endOfLine:\"lf\",insertFinalNewline:!0},[\"*.{js,json,yml}\"]:{charset:\"utf-8\",indentStyle:\"space\",indentSize:2}};_e.mergeIntoTarget(V,r.get(\"initEditorConfig\"));let te=`root = true\n`;for(let[fe,ue]of Object.entries(V)){te+=`\n[${fe}]\n`;for(let[me,he]of Object.entries(ue)){let Be=me.replace(/[A-Z]/g,we=>`_${we.toLowerCase()}`);te+=`${Be} = ${he}\n`}}let ae=z.join(this.context.cwd,\".editorconfig\");oe.existsSync(ae)||(await oe.writeFilePromise(ae,te),h.push(ae)),await this.cli.run([\"install\"],{quiet:!0}),oe.existsSync(z.join(this.context.cwd,\".git\"))||(await Ur.execvp(\"git\",[\"init\"],{cwd:this.context.cwd}),await Ur.execvp(\"git\",[\"add\",\"--\",...h],{cwd:this.context.cwd}),await Ur.execvp(\"git\",[\"commit\",\"--allow-empty\",\"-m\",\"First commit\"],{cwd:this.context.cwd}))}}};m0.paths=[[\"init\"]],m0.usage=nt.Usage({description:\"create a new package\",details:\"\\n      This command will setup a new package in your local directory.\\n\\n      If the `-p,--private` or `-w,--workspace` options are set, the package will be private by default.\\n\\n      If the `-w,--workspace` option is set, the package will be configured to accept a set of workspaces in the `packages/` directory.\\n\\n      If the `-i,--install` option is given a value, Yarn will first download it using `yarn set version` and only then forward the init call to the newly downloaded bundle. Without arguments, the downloaded bundle will be `latest`.\\n\\n      The initial settings of the manifest can be changed by using the `initScope` and `initFields` configuration values. Additionally, Yarn will generate an EditorConfig file whose rules can be altered via `initEditorConfig`, and will initialize a Git repository in the current directory.\\n    \",examples:[[\"Create a new package in the local directory\",\"yarn init\"],[\"Create a new private package in the local directory\",\"yarn init -p\"],[\"Create a new package and store the Yarn release inside\",\"yarn init -i=latest\"],[\"Create a new private package and defines it as a workspace root\",\"yarn init -w\"]]});var gdt={configuration:{initScope:{description:\"Scope used when creating packages via the init command\",type:\"STRING\",default:null},initFields:{description:\"Additional fields to set when creating packages via the init command\",type:\"MAP\",valueDefinition:{description:\"\",type:\"ANY\"}},initEditorConfig:{description:\"Extra rules to define in the generator editorconfig\",type:\"MAP\",valueDefinition:{description:\"\",type:\"ANY\"}}},commands:[m0]},ddt=gdt;var Tq={};zt(Tq,{SearchCommand:()=>I0,UpgradeInteractiveCommand:()=>v0,default:()=>iIt});Ye();var Cme=$e(ve(\"os\"));function bC({stdout:t}){if(Cme.default.endianness()===\"BE\")throw new Error(\"Interactive commands cannot be used on big-endian systems because ink depends on yoga-layout-prebuilt which only supports little-endian architectures\");if(!t.isTTY)throw new Error(\"Interactive commands can only be used inside a TTY environment\")}qt();var Fye=$e(JH()),XH={appId:\"OFCNCOG2CU\",apiKey:\"6fe4476ee5a1832882e326b506d14126\",indexName:\"npm-search\"},pyt=(0,Fye.default)(XH.appId,XH.apiKey).initIndex(XH.indexName),ZH=async(t,e=0)=>await pyt.search(t,{analyticsTags:[\"yarn-plugin-interactive-tools\"],attributesToRetrieve:[\"name\",\"version\",\"owner\",\"repository\",\"humanDownloadsLast30Days\"],page:e,hitsPerPage:10});var qB=[\"regular\",\"dev\",\"peer\"],I0=class extends ut{async execute(){bC(this.context);let{Gem:e}=await Promise.resolve().then(()=>(cQ(),Bq)),{ScrollableItems:r}=await Promise.resolve().then(()=>(pQ(),fQ)),{useKeypress:o}=await Promise.resolve().then(()=>(UB(),Kwe)),{useMinistore:a}=await Promise.resolve().then(()=>(xq(),bq)),{renderForm:n}=await Promise.resolve().then(()=>(mQ(),dQ)),{default:u}=await Promise.resolve().then(()=>$e(nIe())),{Box:A,Text:p}=await Promise.resolve().then(()=>$e(sc())),{default:h,useEffect:E,useState:I}=await Promise.resolve().then(()=>$e(on())),v=await Ke.find(this.context.cwd,this.context.plugins),x=()=>h.createElement(A,{flexDirection:\"row\"},h.createElement(A,{flexDirection:\"column\",width:48},h.createElement(A,null,h.createElement(p,null,\"Press \",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<up>\"),\"/\",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<down>\"),\" to move between packages.\")),h.createElement(A,null,h.createElement(p,null,\"Press \",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<space>\"),\" to select a package.\")),h.createElement(A,null,h.createElement(p,null,\"Press \",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<space>\"),\" again to change the target.\"))),h.createElement(A,{flexDirection:\"column\"},h.createElement(A,{marginLeft:1},h.createElement(p,null,\"Press \",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<enter>\"),\" to install the selected packages.\")),h.createElement(A,{marginLeft:1},h.createElement(p,null,\"Press \",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<ctrl+c>\"),\" to abort.\")))),C=()=>h.createElement(h.Fragment,null,h.createElement(A,{width:15},h.createElement(p,{bold:!0,underline:!0,color:\"gray\"},\"Owner\")),h.createElement(A,{width:11},h.createElement(p,{bold:!0,underline:!0,color:\"gray\"},\"Version\")),h.createElement(A,{width:10},h.createElement(p,{bold:!0,underline:!0,color:\"gray\"},\"Downloads\"))),R=()=>h.createElement(A,{width:17},h.createElement(p,{bold:!0,underline:!0,color:\"gray\"},\"Target\")),N=({hit:he,active:Be})=>{let[we,g]=a(he.name,null);o({active:Be},(ce,ne)=>{if(ne.name!==\"space\")return;if(!we){g(qB[0]);return}let ee=qB.indexOf(we)+1;ee===qB.length?g(null):g(qB[ee])},[we,g]);let Ee=W.parseIdent(he.name),Pe=W.prettyIdent(v,Ee);return h.createElement(A,null,h.createElement(A,{width:45},h.createElement(p,{bold:!0,wrap:\"wrap\"},Pe)),h.createElement(A,{width:14,marginLeft:1},h.createElement(p,{bold:!0,wrap:\"truncate\"},he.owner.name)),h.createElement(A,{width:10,marginLeft:1},h.createElement(p,{italic:!0,wrap:\"truncate\"},he.version)),h.createElement(A,{width:16,marginLeft:1},h.createElement(p,null,he.humanDownloadsLast30Days)))},U=({name:he,active:Be})=>{let[we]=a(he,null),g=W.parseIdent(he);return h.createElement(A,null,h.createElement(A,{width:47},h.createElement(p,{bold:!0},\" - \",W.prettyIdent(v,g))),qB.map(Ee=>h.createElement(A,{key:Ee,width:14,marginLeft:1},h.createElement(p,null,\" \",h.createElement(e,{active:we===Ee}),\" \",h.createElement(p,{bold:!0},Ee)))))},V=()=>h.createElement(A,{marginTop:1},h.createElement(p,null,\"Powered by Algolia.\")),ae=await n(({useSubmit:he})=>{let Be=a();he(Be);let we=Array.from(Be.keys()).filter(H=>Be.get(H)!==null),[g,Ee]=I(\"\"),[Pe,ce]=I(0),[ne,ee]=I([]),Ie=H=>{H.match(/\\t| /)||Ee(H)},Fe=async()=>{ce(0);let H=await ZH(g);H.query===g&&ee(H.hits)},At=async()=>{let H=await ZH(g,Pe+1);H.query===g&&H.page-1===Pe&&(ce(H.page),ee([...ne,...H.hits]))};return E(()=>{g?Fe():ee([])},[g]),h.createElement(A,{flexDirection:\"column\"},h.createElement(x,null),h.createElement(A,{flexDirection:\"row\",marginTop:1},h.createElement(p,{bold:!0},\"Search: \"),h.createElement(A,{width:41},h.createElement(u,{value:g,onChange:Ie,placeholder:\"i.e. babel, webpack, react...\",showCursor:!1})),h.createElement(C,null)),ne.length?h.createElement(r,{radius:2,loop:!1,children:ne.map(H=>h.createElement(N,{key:H.name,hit:H,active:!1})),willReachEnd:At}):h.createElement(p,{color:\"gray\"},\"Start typing...\"),h.createElement(A,{flexDirection:\"row\",marginTop:1},h.createElement(A,{width:49},h.createElement(p,{bold:!0},\"Selected:\")),h.createElement(R,null)),we.length?we.map(H=>h.createElement(U,{key:H,name:H,active:!1})):h.createElement(p,{color:\"gray\"},\"No selected packages...\"),h.createElement(V,null))},{},{stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr});if(typeof ae>\"u\")return 1;let fe=Array.from(ae.keys()).filter(he=>ae.get(he)===\"regular\"),ue=Array.from(ae.keys()).filter(he=>ae.get(he)===\"dev\"),me=Array.from(ae.keys()).filter(he=>ae.get(he)===\"peer\");return fe.length&&await this.cli.run([\"add\",...fe]),ue.length&&await this.cli.run([\"add\",\"--dev\",...ue]),me&&await this.cli.run([\"add\",\"--peer\",...me]),0}};I0.paths=[[\"search\"]],I0.usage=nt.Usage({category:\"Interactive commands\",description:\"open the search interface\",details:`\n    This command opens a fullscreen terminal interface where you can search for and install packages from the npm registry.\n    `,examples:[[\"Open the search window\",\"yarn search\"]]});Ye();qt();E_();var uIe=$e(Jn()),cIe=/^((?:[\\^~]|>=?)?)([0-9]+)(\\.[0-9]+)(\\.[0-9]+)((?:-\\S+)?)$/,AIe=(t,e)=>t.length>0?[t.slice(0,e)].concat(AIe(t.slice(e),e)):[],v0=class extends ut{async execute(){bC(this.context);let{ItemOptions:e}=await Promise.resolve().then(()=>(lIe(),aIe)),{Pad:r}=await Promise.resolve().then(()=>(Rq(),oIe)),{ScrollableItems:o}=await Promise.resolve().then(()=>(pQ(),fQ)),{useMinistore:a}=await Promise.resolve().then(()=>(xq(),bq)),{renderForm:n}=await Promise.resolve().then(()=>(mQ(),dQ)),{Box:u,Text:A}=await Promise.resolve().then(()=>$e(sc())),{default:p,useEffect:h,useRef:E,useState:I}=await Promise.resolve().then(()=>$e(on())),v=await Ke.find(this.context.cwd,this.context.plugins),{project:x,workspace:C}=await St.find(v,this.context.cwd),R=await Nr.find(v);if(!C)throw new nr(x.cwd,this.context.cwd);await x.restoreInstallState({restoreResolutions:!1});let N=this.context.stdout.rows-7,U=(Ee,Pe)=>{let ce=Ape(Ee,Pe),ne=\"\";for(let ee of ce)ee.added?ne+=de.pretty(v,ee.value,\"green\"):ee.removed||(ne+=ee.value);return ne},V=(Ee,Pe)=>{if(Ee===Pe)return Pe;let ce=W.parseRange(Ee),ne=W.parseRange(Pe),ee=ce.selector.match(cIe),Ie=ne.selector.match(cIe);if(!ee||!Ie)return U(Ee,Pe);let Fe=[\"gray\",\"red\",\"yellow\",\"green\",\"magenta\"],At=null,H=\"\";for(let at=1;at<Fe.length;++at)At!==null||ee[at]!==Ie[at]?(At===null&&(At=Fe[at-1]),H+=de.pretty(v,Ie[at],At)):H+=Ie[at];return H},te=async(Ee,Pe,ce)=>{let ne=await Xc.fetchDescriptorFrom(Ee,ce,{project:x,cache:R,preserveModifier:Pe,workspace:C});return ne!==null?ne.range:Ee.range},ae=async Ee=>{let Pe=uIe.default.valid(Ee.range)?`^${Ee.range}`:Ee.range,[ce,ne]=await Promise.all([te(Ee,Ee.range,Pe).catch(()=>null),te(Ee,Ee.range,\"latest\").catch(()=>null)]),ee=[{value:null,label:Ee.range}];return ce&&ce!==Ee.range?ee.push({value:ce,label:V(Ee.range,ce)}):ee.push({value:null,label:\"\"}),ne&&ne!==ce&&ne!==Ee.range?ee.push({value:ne,label:V(Ee.range,ne)}):ee.push({value:null,label:\"\"}),ee},fe=()=>p.createElement(u,{flexDirection:\"row\"},p.createElement(u,{flexDirection:\"column\",width:49},p.createElement(u,{marginLeft:1},p.createElement(A,null,\"Press \",p.createElement(A,{bold:!0,color:\"cyanBright\"},\"<up>\"),\"/\",p.createElement(A,{bold:!0,color:\"cyanBright\"},\"<down>\"),\" to select packages.\")),p.createElement(u,{marginLeft:1},p.createElement(A,null,\"Press \",p.createElement(A,{bold:!0,color:\"cyanBright\"},\"<left>\"),\"/\",p.createElement(A,{bold:!0,color:\"cyanBright\"},\"<right>\"),\" to select versions.\"))),p.createElement(u,{flexDirection:\"column\"},p.createElement(u,{marginLeft:1},p.createElement(A,null,\"Press \",p.createElement(A,{bold:!0,color:\"cyanBright\"},\"<enter>\"),\" to install.\")),p.createElement(u,{marginLeft:1},p.createElement(A,null,\"Press \",p.createElement(A,{bold:!0,color:\"cyanBright\"},\"<ctrl+c>\"),\" to abort.\")))),ue=()=>p.createElement(u,{flexDirection:\"row\",paddingTop:1,paddingBottom:1},p.createElement(u,{width:50},p.createElement(A,{bold:!0},p.createElement(A,{color:\"greenBright\"},\"?\"),\" Pick the packages you want to upgrade.\")),p.createElement(u,{width:17},p.createElement(A,{bold:!0,underline:!0,color:\"gray\"},\"Current\")),p.createElement(u,{width:17},p.createElement(A,{bold:!0,underline:!0,color:\"gray\"},\"Range\")),p.createElement(u,{width:17},p.createElement(A,{bold:!0,underline:!0,color:\"gray\"},\"Latest\"))),me=({active:Ee,descriptor:Pe,suggestions:ce})=>{let[ne,ee]=a(Pe.descriptorHash,null),Ie=W.stringifyIdent(Pe),Fe=Math.max(0,45-Ie.length);return p.createElement(p.Fragment,null,p.createElement(u,null,p.createElement(u,{width:45},p.createElement(A,{bold:!0},W.prettyIdent(v,Pe)),p.createElement(r,{active:Ee,length:Fe})),p.createElement(e,{active:Ee,options:ce,value:ne,skewer:!0,onChange:ee,sizes:[17,17,17]})))},he=({dependencies:Ee})=>{let[Pe,ce]=I(Ee.map(()=>null)),ne=E(!0),ee=async Ie=>{let Fe=await ae(Ie);return Fe.filter(At=>At.label!==\"\").length<=1?null:{descriptor:Ie,suggestions:Fe}};return h(()=>()=>{ne.current=!1},[]),h(()=>{let Ie=Math.trunc(N*1.75),Fe=Ee.slice(0,Ie),At=Ee.slice(Ie),H=AIe(At,N),at=Fe.map(ee).reduce(async(Re,ke)=>{await Re;let xe=await ke;xe!==null&&(!ne.current||ce(He=>{let Te=He.findIndex(qe=>qe===null),Ve=[...He];return Ve[Te]=xe,Ve}))},Promise.resolve());H.reduce((Re,ke)=>Promise.all(ke.map(xe=>Promise.resolve().then(()=>ee(xe)))).then(async xe=>{xe=xe.filter(He=>He!==null),await Re,ne.current&&ce(He=>{let Te=He.findIndex(Ve=>Ve===null);return He.slice(0,Te).concat(xe).concat(He.slice(Te+xe.length))})}),at).then(()=>{ne.current&&ce(Re=>Re.filter(ke=>ke!==null))})},[]),Pe.length?p.createElement(o,{radius:N>>1,children:Pe.map((Ie,Fe)=>Ie!==null?p.createElement(me,{key:Fe,active:!1,descriptor:Ie.descriptor,suggestions:Ie.suggestions}):p.createElement(A,{key:Fe},\"Loading...\"))}):p.createElement(A,null,\"No upgrades found\")},we=await n(({useSubmit:Ee})=>{Ee(a());let Pe=new Map;for(let ne of x.workspaces)for(let ee of[\"dependencies\",\"devDependencies\"])for(let Ie of ne.manifest[ee].values())x.tryWorkspaceByDescriptor(Ie)===null&&(Ie.range.startsWith(\"link:\")||Pe.set(Ie.descriptorHash,Ie));let ce=_e.sortMap(Pe.values(),ne=>W.stringifyDescriptor(ne));return p.createElement(u,{flexDirection:\"column\"},p.createElement(fe,null),p.createElement(ue,null),p.createElement(he,{dependencies:ce}))},{},{stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr});if(typeof we>\"u\")return 1;let g=!1;for(let Ee of x.workspaces)for(let Pe of[\"dependencies\",\"devDependencies\"]){let ce=Ee.manifest[Pe];for(let ne of ce.values()){let ee=we.get(ne.descriptorHash);typeof ee<\"u\"&&ee!==null&&(ce.set(ne.identHash,W.makeDescriptor(ne,ee)),g=!0)}}return g?await x.installWithNewReport({quiet:this.context.quiet,stdout:this.context.stdout},{cache:R}):0}};v0.paths=[[\"upgrade-interactive\"]],v0.usage=nt.Usage({category:\"Interactive commands\",description:\"open the upgrade interface\",details:`\n      This command opens a fullscreen terminal interface where you can see any out of date packages used by your application, their status compared to the latest versions available on the remote registry, and select packages to upgrade.\n    `,examples:[[\"Open the upgrade window\",\"yarn upgrade-interactive\"]]});var nIt={commands:[I0,v0]},iIt=nIt;var Lq={};zt(Lq,{LinkFetcher:()=>jB,LinkResolver:()=>YB,PortalFetcher:()=>WB,PortalResolver:()=>KB,default:()=>oIt});Ye();Pt();var tp=\"portal:\",rp=\"link:\";var jB=class{supports(e,r){return!!e.reference.startsWith(rp)}getLocalPath(e,r){let{parentLocator:o,path:a}=W.parseFileStyleRange(e.reference,{protocol:rp});if(z.isAbsolute(a))return a;let n=r.fetcher.getLocalPath(o,r);return n===null?null:z.resolve(n,a)}async fetch(e,r){let{parentLocator:o,path:a}=W.parseFileStyleRange(e.reference,{protocol:rp}),n=z.isAbsolute(a)?{packageFs:new gn(Bt.root),prefixPath:Bt.dot,localPath:Bt.root}:await r.fetcher.fetch(o,r),u=n.localPath?{packageFs:new gn(Bt.root),prefixPath:z.relative(Bt.root,n.localPath),localPath:Bt.root}:n;n!==u&&n.releaseFs&&n.releaseFs();let A=u.packageFs,p=z.resolve(u.localPath??u.packageFs.getRealPath(),u.prefixPath,a);return n.localPath?{packageFs:new gn(p,{baseFs:A}),releaseFs:u.releaseFs,prefixPath:Bt.dot,discardFromLookup:!0,localPath:p}:{packageFs:new Hu(p,{baseFs:A}),releaseFs:u.releaseFs,prefixPath:Bt.dot,discardFromLookup:!0}}};Ye();Pt();var YB=class{supportsDescriptor(e,r){return!!e.range.startsWith(rp)}supportsLocator(e,r){return!!e.reference.startsWith(rp)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,o){return W.bindDescriptor(e,{locator:W.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){let a=e.range.slice(rp.length);return[W.makeLocator(e,`${rp}${le.toPortablePath(a)}`)]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){return{...e,version:\"0.0.0\",languageName:r.project.configuration.get(\"defaultLanguageName\"),linkType:\"SOFT\",conditions:null,dependencies:new Map,peerDependencies:new Map,dependenciesMeta:new Map,peerDependenciesMeta:new Map,bin:new Map}}};Ye();Pt();var WB=class{supports(e,r){return!!e.reference.startsWith(tp)}getLocalPath(e,r){let{parentLocator:o,path:a}=W.parseFileStyleRange(e.reference,{protocol:tp});if(z.isAbsolute(a))return a;let n=r.fetcher.getLocalPath(o,r);return n===null?null:z.resolve(n,a)}async fetch(e,r){let{parentLocator:o,path:a}=W.parseFileStyleRange(e.reference,{protocol:tp}),n=z.isAbsolute(a)?{packageFs:new gn(Bt.root),prefixPath:Bt.dot,localPath:Bt.root}:await r.fetcher.fetch(o,r),u=n.localPath?{packageFs:new gn(Bt.root),prefixPath:z.relative(Bt.root,n.localPath),localPath:Bt.root}:n;n!==u&&n.releaseFs&&n.releaseFs();let A=u.packageFs,p=z.resolve(u.localPath??u.packageFs.getRealPath(),u.prefixPath,a);return n.localPath?{packageFs:new gn(p,{baseFs:A}),releaseFs:u.releaseFs,prefixPath:Bt.dot,localPath:p}:{packageFs:new Hu(p,{baseFs:A}),releaseFs:u.releaseFs,prefixPath:Bt.dot}}};Ye();Ye();Pt();var KB=class{supportsDescriptor(e,r){return!!e.range.startsWith(tp)}supportsLocator(e,r){return!!e.reference.startsWith(tp)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,o){return W.bindDescriptor(e,{locator:W.stringifyLocator(r)})}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){let a=e.range.slice(tp.length);return[W.makeLocator(e,`${tp}${le.toPortablePath(a)}`)]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){if(!r.fetchOptions)throw new Error(\"Assertion failed: This resolver cannot be used unless a fetcher is configured\");let o=await r.fetchOptions.fetcher.fetch(e,r.fetchOptions),a=await _e.releaseAfterUseAsync(async()=>await Ot.find(o.prefixPath,{baseFs:o.packageFs}),o.releaseFs);return{...e,version:a.version||\"0.0.0\",languageName:a.languageName||r.project.configuration.get(\"defaultLanguageName\"),linkType:\"SOFT\",conditions:a.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(a.dependencies),peerDependencies:a.peerDependencies,dependenciesMeta:a.dependenciesMeta,peerDependenciesMeta:a.peerDependenciesMeta,bin:a.bin}}};var sIt={fetchers:[jB,WB],resolvers:[YB,KB]},oIt=sIt;var yG={};zt(yG,{NodeModulesLinker:()=>lv,NodeModulesMode:()=>hG,PnpLooseLinker:()=>cv,default:()=>I1t});Pt();Ye();Pt();Pt();var Oq=(t,e)=>`${t}@${e}`,fIe=(t,e)=>{let r=e.indexOf(\"#\"),o=r>=0?e.substring(r+1):e;return Oq(t,o)};var gIe=(t,e={})=>{let r=e.debugLevel||Number(process.env.NM_DEBUG_LEVEL||-1),o=e.check||r>=9,a=e.hoistingLimits||new Map,n={check:o,debugLevel:r,hoistingLimits:a,fastLookupPossible:!0},u;n.debugLevel>=0&&(u=Date.now());let A=pIt(t,n),p=!1,h=0;do p=Mq(A,[A],new Set([A.locator]),new Map,n).anotherRoundNeeded,n.fastLookupPossible=!1,h++;while(p);if(n.debugLevel>=0&&console.log(`hoist time: ${Date.now()-u}ms, rounds: ${h}`),n.debugLevel>=1){let E=zB(A);if(Mq(A,[A],new Set([A.locator]),new Map,n).isGraphChanged)throw new Error(`The hoisting result is not terminal, prev tree:\n${E}, next tree:\n${zB(A)}`);let v=dIe(A);if(v)throw new Error(`${v}, after hoisting finished:\n${zB(A)}`)}return n.debugLevel>=2&&console.log(zB(A)),hIt(A)},aIt=t=>{let e=t[t.length-1],r=new Map,o=new Set,a=n=>{if(!o.has(n)){o.add(n);for(let u of n.hoistedDependencies.values())r.set(u.name,u);for(let u of n.dependencies.values())n.peerNames.has(u.name)||a(u)}};return a(e),r},lIt=t=>{let e=t[t.length-1],r=new Map,o=new Set,a=new Set,n=(u,A)=>{if(o.has(u))return;o.add(u);for(let h of u.hoistedDependencies.values())if(!A.has(h.name)){let E;for(let I of t)E=I.dependencies.get(h.name),E&&r.set(E.name,E)}let p=new Set;for(let h of u.dependencies.values())p.add(h.name);for(let h of u.dependencies.values())u.peerNames.has(h.name)||n(h,p)};return n(e,a),r},pIe=(t,e)=>{if(e.decoupled)return e;let{name:r,references:o,ident:a,locator:n,dependencies:u,originalDependencies:A,hoistedDependencies:p,peerNames:h,reasons:E,isHoistBorder:I,hoistPriority:v,dependencyKind:x,hoistedFrom:C,hoistedTo:R}=e,N={name:r,references:new Set(o),ident:a,locator:n,dependencies:new Map(u),originalDependencies:new Map(A),hoistedDependencies:new Map(p),peerNames:new Set(h),reasons:new Map(E),decoupled:!0,isHoistBorder:I,hoistPriority:v,dependencyKind:x,hoistedFrom:new Map(C),hoistedTo:new Map(R)},U=N.dependencies.get(r);return U&&U.ident==N.ident&&N.dependencies.set(r,N),t.dependencies.set(N.name,N),N},cIt=(t,e)=>{let r=new Map([[t.name,[t.ident]]]);for(let a of t.dependencies.values())t.peerNames.has(a.name)||r.set(a.name,[a.ident]);let o=Array.from(e.keys());o.sort((a,n)=>{let u=e.get(a),A=e.get(n);return A.hoistPriority!==u.hoistPriority?A.hoistPriority-u.hoistPriority:A.peerDependents.size!==u.peerDependents.size?A.peerDependents.size-u.peerDependents.size:A.dependents.size-u.dependents.size});for(let a of o){let n=a.substring(0,a.indexOf(\"@\",1)),u=a.substring(n.length+1);if(!t.peerNames.has(n)){let A=r.get(n);A||(A=[],r.set(n,A)),A.indexOf(u)<0&&A.push(u)}}return r},Nq=t=>{let e=new Set,r=(o,a=new Set)=>{if(!a.has(o)){a.add(o);for(let n of o.peerNames)if(!t.peerNames.has(n)){let u=t.dependencies.get(n);u&&!e.has(u)&&r(u,a)}e.add(o)}};for(let o of t.dependencies.values())t.peerNames.has(o.name)||r(o);return e},Mq=(t,e,r,o,a,n=new Set)=>{let u=e[e.length-1];if(n.has(u))return{anotherRoundNeeded:!1,isGraphChanged:!1};n.add(u);let A=gIt(u),p=cIt(u,A),h=t==u?new Map:a.fastLookupPossible?aIt(e):lIt(e),E,I=!1,v=!1,x=new Map(Array.from(p.entries()).map(([R,N])=>[R,N[0]])),C=new Map;do{let R=fIt(t,e,r,h,x,p,o,C,a);R.isGraphChanged&&(v=!0),R.anotherRoundNeeded&&(I=!0),E=!1;for(let[N,U]of p)U.length>1&&!u.dependencies.has(N)&&(x.delete(N),U.shift(),x.set(N,U[0]),E=!0)}while(E);for(let R of u.dependencies.values())if(!u.peerNames.has(R.name)&&!r.has(R.locator)){r.add(R.locator);let N=Mq(t,[...e,R],r,C,a);N.isGraphChanged&&(v=!0),N.anotherRoundNeeded&&(I=!0),r.delete(R.locator)}return{anotherRoundNeeded:I,isGraphChanged:v}},uIt=t=>{for(let[e,r]of t.dependencies)if(!t.peerNames.has(e)&&r.ident!==t.ident)return!0;return!1},AIt=(t,e,r,o,a,n,u,A,{outputReason:p,fastLookupPossible:h})=>{let E,I=null,v=new Set;p&&(E=`${Array.from(e).map(N=>no(N)).join(\"\\u2192\")}`);let x=r[r.length-1],R=!(o.ident===x.ident);if(p&&!R&&(I=\"- self-reference\"),R&&(R=o.dependencyKind!==1,p&&!R&&(I=\"- workspace\")),R&&o.dependencyKind===2&&(R=!uIt(o),p&&!R&&(I=\"- external soft link with unhoisted dependencies\")),R&&(R=x.dependencyKind!==1||x.hoistedFrom.has(o.name)||e.size===1,p&&!R&&(I=x.reasons.get(o.name))),R&&(R=!t.peerNames.has(o.name),p&&!R&&(I=`- cannot shadow peer: ${no(t.originalDependencies.get(o.name).locator)} at ${E}`)),R){let N=!1,U=a.get(o.name);if(N=!U||U.ident===o.ident,p&&!N&&(I=`- filled by: ${no(U.locator)} at ${E}`),N)for(let V=r.length-1;V>=1;V--){let ae=r[V].dependencies.get(o.name);if(ae&&ae.ident!==o.ident){N=!1;let fe=A.get(x);fe||(fe=new Set,A.set(x,fe)),fe.add(o.name),p&&(I=`- filled by ${no(ae.locator)} at ${r.slice(0,V).map(ue=>no(ue.locator)).join(\"\\u2192\")}`);break}}R=N}if(R&&(R=n.get(o.name)===o.ident,p&&!R&&(I=`- filled by: ${no(u.get(o.name)[0])} at ${E}`)),R){let N=!0,U=new Set(o.peerNames);for(let V=r.length-1;V>=1;V--){let te=r[V];for(let ae of U){if(te.peerNames.has(ae)&&te.originalDependencies.has(ae))continue;let fe=te.dependencies.get(ae);fe&&t.dependencies.get(ae)!==fe&&(V===r.length-1?v.add(fe):(v=null,N=!1,p&&(I=`- peer dependency ${no(fe.locator)} from parent ${no(te.locator)} was not hoisted to ${E}`))),U.delete(ae)}if(!N)break}R=N}if(R&&!h)for(let N of o.hoistedDependencies.values()){let U=a.get(N.name)||t.dependencies.get(N.name);if(!U||N.ident!==U.ident){R=!1,p&&(I=`- previously hoisted dependency mismatch, needed: ${no(N.locator)}, available: ${no(U?.locator)}`);break}}return v!==null&&v.size>0?{isHoistable:2,dependsOn:v,reason:I}:{isHoistable:R?0:1,reason:I}},yQ=t=>`${t.name}@${t.locator}`,fIt=(t,e,r,o,a,n,u,A,p)=>{let h=e[e.length-1],E=new Set,I=!1,v=!1,x=(U,V,te,ae,fe)=>{if(E.has(ae))return;let ue=[...V,yQ(ae)],me=[...te,yQ(ae)],he=new Map,Be=new Map;for(let ce of Nq(ae)){let ne=AIt(h,r,[h,...U,ae],ce,o,a,n,A,{outputReason:p.debugLevel>=2,fastLookupPossible:p.fastLookupPossible});if(Be.set(ce,ne),ne.isHoistable===2)for(let ee of ne.dependsOn){let Ie=he.get(ee.name)||new Set;Ie.add(ce.name),he.set(ee.name,Ie)}}let we=new Set,g=(ce,ne,ee)=>{if(!we.has(ce)){we.add(ce),Be.set(ce,{isHoistable:1,reason:ee});for(let Ie of he.get(ce.name)||[])g(ae.dependencies.get(Ie),ne,p.debugLevel>=2?`- peer dependency ${no(ce.locator)} from parent ${no(ae.locator)} was not hoisted`:\"\")}};for(let[ce,ne]of Be)ne.isHoistable===1&&g(ce,ne,ne.reason);let Ee=!1;for(let ce of Be.keys())if(!we.has(ce)){v=!0;let ne=u.get(ae);ne&&ne.has(ce.name)&&(I=!0),Ee=!0,ae.dependencies.delete(ce.name),ae.hoistedDependencies.set(ce.name,ce),ae.reasons.delete(ce.name);let ee=h.dependencies.get(ce.name);if(p.debugLevel>=2){let Ie=Array.from(V).concat([ae.locator]).map(At=>no(At)).join(\"\\u2192\"),Fe=h.hoistedFrom.get(ce.name);Fe||(Fe=[],h.hoistedFrom.set(ce.name,Fe)),Fe.push(Ie),ae.hoistedTo.set(ce.name,Array.from(e).map(At=>no(At.locator)).join(\"\\u2192\"))}if(!ee)h.ident!==ce.ident&&(h.dependencies.set(ce.name,ce),fe.add(ce));else for(let Ie of ce.references)ee.references.add(Ie)}if(ae.dependencyKind===2&&Ee&&(I=!0),p.check){let ce=dIe(t);if(ce)throw new Error(`${ce}, after hoisting dependencies of ${[h,...U,ae].map(ne=>no(ne.locator)).join(\"\\u2192\")}:\n${zB(t)}`)}let Pe=Nq(ae);for(let ce of Pe)if(we.has(ce)){let ne=Be.get(ce);if((a.get(ce.name)===ce.ident||!ae.reasons.has(ce.name))&&ne.isHoistable!==0&&ae.reasons.set(ce.name,ne.reason),!ce.isHoistBorder&&me.indexOf(yQ(ce))<0){E.add(ae);let Ie=pIe(ae,ce);x([...U,ae],ue,me,Ie,R),E.delete(ae)}}},C,R=new Set(Nq(h)),N=Array.from(e).map(U=>yQ(U));do{C=R,R=new Set;for(let U of C){if(U.locator===h.locator||U.isHoistBorder)continue;let V=pIe(h,U);x([],Array.from(r),N,V,R)}}while(R.size>0);return{anotherRoundNeeded:I,isGraphChanged:v}},dIe=t=>{let e=[],r=new Set,o=new Set,a=(n,u,A)=>{if(r.has(n)||(r.add(n),o.has(n)))return;let p=new Map(u);for(let h of n.dependencies.values())n.peerNames.has(h.name)||p.set(h.name,h);for(let h of n.originalDependencies.values()){let E=p.get(h.name),I=()=>`${Array.from(o).concat([n]).map(v=>no(v.locator)).join(\"\\u2192\")}`;if(n.peerNames.has(h.name)){let v=u.get(h.name);(v!==E||!v||v.ident!==h.ident)&&e.push(`${I()} - broken peer promise: expected ${h.ident} but found ${v&&v.ident}`)}else{let v=A.hoistedFrom.get(n.name),x=n.hoistedTo.get(h.name),C=`${v?` hoisted from ${v.join(\", \")}`:\"\"}`,R=`${x?` hoisted to ${x}`:\"\"}`,N=`${I()}${C}`;E?E.ident!==h.ident&&e.push(`${N} - broken require promise for ${h.name}${R}: expected ${h.ident}, but found: ${E.ident}`):e.push(`${N} - broken require promise: no required dependency ${h.name}${R} found`)}}o.add(n);for(let h of n.dependencies.values())n.peerNames.has(h.name)||a(h,p,n);o.delete(n)};return a(t,t.dependencies,t),e.join(`\n`)},pIt=(t,e)=>{let{identName:r,name:o,reference:a,peerNames:n}=t,u={name:o,references:new Set([a]),locator:Oq(r,a),ident:fIe(r,a),dependencies:new Map,originalDependencies:new Map,hoistedDependencies:new Map,peerNames:new Set(n),reasons:new Map,decoupled:!0,isHoistBorder:!0,hoistPriority:0,dependencyKind:1,hoistedFrom:new Map,hoistedTo:new Map},A=new Map([[t,u]]),p=(h,E)=>{let I=A.get(h),v=!!I;if(!I){let{name:x,identName:C,reference:R,peerNames:N,hoistPriority:U,dependencyKind:V}=h,te=e.hoistingLimits.get(E.locator);I={name:x,references:new Set([R]),locator:Oq(C,R),ident:fIe(C,R),dependencies:new Map,originalDependencies:new Map,hoistedDependencies:new Map,peerNames:new Set(N),reasons:new Map,decoupled:!0,isHoistBorder:te?te.has(x):!1,hoistPriority:U||0,dependencyKind:V||0,hoistedFrom:new Map,hoistedTo:new Map},A.set(h,I)}if(E.dependencies.set(h.name,I),E.originalDependencies.set(h.name,I),v){let x=new Set,C=R=>{if(!x.has(R)){x.add(R),R.decoupled=!1;for(let N of R.dependencies.values())R.peerNames.has(N.name)||C(N)}};C(I)}else for(let x of h.dependencies)p(x,I)};for(let h of t.dependencies)p(h,u);return u},Uq=t=>t.substring(0,t.indexOf(\"@\",1)),hIt=t=>{let e={name:t.name,identName:Uq(t.locator),references:new Set(t.references),dependencies:new Set},r=new Set([t]),o=(a,n,u)=>{let A=r.has(a),p;if(n===a)p=u;else{let{name:h,references:E,locator:I}=a;p={name:h,identName:Uq(I),references:E,dependencies:new Set}}if(u.dependencies.add(p),!A){r.add(a);for(let h of a.dependencies.values())a.peerNames.has(h.name)||o(h,a,p);r.delete(a)}};for(let a of t.dependencies.values())o(a,t,e);return e},gIt=t=>{let e=new Map,r=new Set([t]),o=u=>`${u.name}@${u.ident}`,a=u=>{let A=o(u),p=e.get(A);return p||(p={dependents:new Set,peerDependents:new Set,hoistPriority:0},e.set(A,p)),p},n=(u,A)=>{let p=!!r.has(A);if(a(A).dependents.add(u.ident),!p){r.add(A);for(let E of A.dependencies.values()){let I=a(E);I.hoistPriority=Math.max(I.hoistPriority,E.hoistPriority),A.peerNames.has(E.name)?I.peerDependents.add(A.ident):n(A,E)}}};for(let u of t.dependencies.values())t.peerNames.has(u.name)||n(t,u);return e},no=t=>{if(!t)return\"none\";let e=t.indexOf(\"@\",1),r=t.substring(0,e);r.endsWith(\"$wsroot$\")&&(r=`wh:${r.replace(\"$wsroot$\",\"\")}`);let o=t.substring(e+1);if(o===\"workspace:.\")return\".\";if(o){let a=(o.indexOf(\"#\")>0?o.split(\"#\")[1]:o).replace(\"npm:\",\"\");return o.startsWith(\"virtual\")&&(r=`v:${r}`),a.startsWith(\"workspace\")&&(r=`w:${r}`,a=\"\"),`${r}${a?`@${a}`:\"\"}`}else return`${r}`},hIe=5e4,zB=t=>{let e=0,r=(a,n,u=\"\")=>{if(e>hIe||n.has(a))return\"\";e++;let A=Array.from(a.dependencies.values()).sort((h,E)=>h.name===E.name?0:h.name>E.name?1:-1),p=\"\";n.add(a);for(let h=0;h<A.length;h++){let E=A[h];if(!a.peerNames.has(E.name)&&E!==a){let I=a.reasons.get(E.name),v=Uq(E.locator);p+=`${u}${h<A.length-1?\"\\u251C\\u2500\":\"\\u2514\\u2500\"}${(n.has(E)?\">\":\"\")+(v!==E.name?`a:${E.name}:`:\"\")+no(E.locator)+(I?` ${I}`:\"\")}\n`,p+=r(E,n,`${u}${h<A.length-1?\"\\u2502 \":\"  \"}`)}}return n.delete(a),p};return r(t,new Set)+(e>hIe?`\nTree is too large, part of the tree has been dunped\n`:\"\")};var VB=(o=>(o.WORKSPACES=\"workspaces\",o.DEPENDENCIES=\"dependencies\",o.NONE=\"none\",o))(VB||{}),mIe=\"node_modules\",D0=\"$wsroot$\";var JB=(t,e)=>{let{packageTree:r,hoistingLimits:o,errors:a,preserveSymlinksRequired:n}=mIt(t,e),u=null;if(a.length===0){let A=gIe(r,{hoistingLimits:o});u=EIt(t,A,e)}return{tree:u,errors:a,preserveSymlinksRequired:n}},dA=t=>`${t.name}@${t.reference}`,Hq=t=>{let e=new Map;for(let[r,o]of t.entries())if(!o.dirList){let a=e.get(o.locator);a||(a={target:o.target,linkType:o.linkType,locations:[],aliases:o.aliases},e.set(o.locator,a)),a.locations.push(r)}for(let r of e.values())r.locations=r.locations.sort((o,a)=>{let n=o.split(z.delimiter).length,u=a.split(z.delimiter).length;return a===o?0:n!==u?u-n:a>o?1:-1});return e},yIe=(t,e)=>{let r=W.isVirtualLocator(t)?W.devirtualizeLocator(t):t,o=W.isVirtualLocator(e)?W.devirtualizeLocator(e):e;return W.areLocatorsEqual(r,o)},_q=(t,e,r,o)=>{if(t.linkType!==\"SOFT\")return!1;let a=le.toPortablePath(r.resolveVirtual&&e.reference&&e.reference.startsWith(\"virtual:\")?r.resolveVirtual(t.packageLocation):t.packageLocation);return z.contains(o,a)===null},dIt=t=>{let e=t.getPackageInformation(t.topLevel);if(e===null)throw new Error(\"Assertion failed: Expected the top-level package to have been registered\");if(t.findPackageLocator(e.packageLocation)===null)throw new Error(\"Assertion failed: Expected the top-level package to have a physical locator\");let o=le.toPortablePath(e.packageLocation.slice(0,-1)),a=new Map,n={children:new Map},u=t.getDependencyTreeRoots(),A=new Map,p=new Set,h=(v,x)=>{let C=dA(v);if(p.has(C))return;p.add(C);let R=t.getPackageInformation(v);if(R){let N=x?dA(x):\"\";if(dA(v)!==N&&R.linkType===\"SOFT\"&&!v.reference.startsWith(\"link:\")&&!_q(R,v,t,o)){let U=EIe(R,v,t);(!A.get(U)||v.reference.startsWith(\"workspace:\"))&&A.set(U,v)}for(let[U,V]of R.packageDependencies)V!==null&&(R.packagePeers.has(U)||h(t.getLocator(U,V),v))}};for(let v of u)h(v,null);let E=o.split(z.sep);for(let v of A.values()){let x=t.getPackageInformation(v),R=le.toPortablePath(x.packageLocation.slice(0,-1)).split(z.sep).slice(E.length),N=n;for(let U of R){let V=N.children.get(U);V||(V={children:new Map},N.children.set(U,V)),N=V}N.workspaceLocator=v}let I=(v,x)=>{if(v.workspaceLocator){let C=dA(x),R=a.get(C);R||(R=new Set,a.set(C,R)),R.add(v.workspaceLocator)}for(let C of v.children.values())I(C,v.workspaceLocator||x)};for(let v of n.children.values())I(v,n.workspaceLocator);return a},mIt=(t,e)=>{let r=[],o=!1,a=new Map,n=dIt(t),u=t.getPackageInformation(t.topLevel);if(u===null)throw new Error(\"Assertion failed: Expected the top-level package to have been registered\");let A=t.findPackageLocator(u.packageLocation);if(A===null)throw new Error(\"Assertion failed: Expected the top-level package to have a physical locator\");let p=le.toPortablePath(u.packageLocation.slice(0,-1)),h={name:A.name,identName:A.name,reference:A.reference,peerNames:u.packagePeers,dependencies:new Set,dependencyKind:1},E=new Map,I=(x,C)=>`${dA(C)}:${x}`,v=(x,C,R,N,U,V,te,ae)=>{let fe=I(x,R),ue=E.get(fe),me=!!ue;!me&&R.name===A.name&&R.reference===A.reference&&(ue=h,E.set(fe,h));let he=_q(C,R,t,p);if(!ue){let ce=0;he?ce=2:C.linkType===\"SOFT\"&&R.name.endsWith(D0)&&(ce=1),ue={name:x,identName:R.name,reference:R.reference,dependencies:new Set,peerNames:ce===1?new Set:C.packagePeers,dependencyKind:ce},E.set(fe,ue)}let Be;if(he?Be=2:U.linkType===\"SOFT\"?Be=1:Be=0,ue.hoistPriority=Math.max(ue.hoistPriority||0,Be),ae&&!he){let ce=dA({name:N.identName,reference:N.reference}),ne=a.get(ce)||new Set;a.set(ce,ne),ne.add(ue.name)}let we=new Map(C.packageDependencies);if(e.project){let ce=e.project.workspacesByCwd.get(le.toPortablePath(C.packageLocation.slice(0,-1)));if(ce){let ne=new Set([...Array.from(ce.manifest.peerDependencies.values(),ee=>W.stringifyIdent(ee)),...Array.from(ce.manifest.peerDependenciesMeta.keys())]);for(let ee of ne)we.has(ee)||(we.set(ee,V.get(ee)||null),ue.peerNames.add(ee))}}let g=dA({name:R.name.replace(D0,\"\"),reference:R.reference}),Ee=n.get(g);if(Ee)for(let ce of Ee)we.set(`${ce.name}${D0}`,ce.reference);(C!==U||C.linkType!==\"SOFT\"||!he&&(!e.selfReferencesByCwd||e.selfReferencesByCwd.get(te)))&&N.dependencies.add(ue);let Pe=R!==A&&C.linkType===\"SOFT\"&&!R.name.endsWith(D0)&&!he;if(!me&&!Pe){let ce=new Map;for(let[ne,ee]of we)if(ee!==null){let Ie=t.getLocator(ne,ee),Fe=t.getLocator(ne.replace(D0,\"\"),ee),At=t.getPackageInformation(Fe);if(At===null)throw new Error(\"Assertion failed: Expected the package to have been registered\");let H=_q(At,Ie,t,p);if(e.validateExternalSoftLinks&&e.project&&H){At.packageDependencies.size>0&&(o=!0);for(let[He,Te]of At.packageDependencies)if(Te!==null){let Ve=W.parseLocator(Array.isArray(Te)?`${Te[0]}@${Te[1]}`:`${He}@${Te}`);if(dA(Ve)!==dA(Ie)){let qe=we.get(He);if(qe){let b=W.parseLocator(Array.isArray(qe)?`${qe[0]}@${qe[1]}`:`${He}@${qe}`);yIe(b,Ve)||r.push({messageName:71,text:`Cannot link ${W.prettyIdent(e.project.configuration,W.parseIdent(Ie.name))} into ${W.prettyLocator(e.project.configuration,W.parseLocator(`${R.name}@${R.reference}`))} dependency ${W.prettyLocator(e.project.configuration,Ve)} conflicts with parent dependency ${W.prettyLocator(e.project.configuration,b)}`})}else{let b=ce.get(He);if(b){let w=b.target,S=W.parseLocator(Array.isArray(w)?`${w[0]}@${w[1]}`:`${He}@${w}`);yIe(S,Ve)||r.push({messageName:71,text:`Cannot link ${W.prettyIdent(e.project.configuration,W.parseIdent(Ie.name))} into ${W.prettyLocator(e.project.configuration,W.parseLocator(`${R.name}@${R.reference}`))} dependency ${W.prettyLocator(e.project.configuration,Ve)} conflicts with dependency ${W.prettyLocator(e.project.configuration,S)} from sibling portal ${W.prettyIdent(e.project.configuration,W.parseIdent(b.portal.name))}`})}else ce.set(He,{target:Ve.reference,portal:Ie})}}}}let at=e.hoistingLimitsByCwd?.get(te),Re=H?te:z.relative(p,le.toPortablePath(At.packageLocation))||Bt.dot,ke=e.hoistingLimitsByCwd?.get(Re);v(ne,At,Ie,ue,C,we,Re,at===\"dependencies\"||ke===\"dependencies\"||ke===\"workspaces\")}}};return v(A.name,u,A,h,u,u.packageDependencies,Bt.dot,!1),{packageTree:h,hoistingLimits:a,errors:r,preserveSymlinksRequired:o}};function EIe(t,e,r){let o=r.resolveVirtual&&e.reference&&e.reference.startsWith(\"virtual:\")?r.resolveVirtual(t.packageLocation):t.packageLocation;return le.toPortablePath(o||t.packageLocation)}function yIt(t,e,r){let o=e.getLocator(t.name.replace(D0,\"\"),t.reference),a=e.getPackageInformation(o);if(a===null)throw new Error(\"Assertion failed: Expected the package to be registered\");return r.pnpifyFs?{linkType:\"SOFT\",target:le.toPortablePath(a.packageLocation)}:{linkType:a.linkType,target:EIe(a,t,e)}}var EIt=(t,e,r)=>{let o=new Map,a=(E,I,v)=>{let{linkType:x,target:C}=yIt(E,t,r);return{locator:dA(E),nodePath:I,target:C,linkType:x,aliases:v}},n=E=>{let[I,v]=E.split(\"/\");return v?{scope:I,name:v}:{scope:null,name:I}},u=new Set,A=(E,I,v)=>{if(u.has(E))return;u.add(E);let x=Array.from(E.references).sort().join(\"#\");for(let C of E.dependencies){let R=Array.from(C.references).sort().join(\"#\");if(C.identName===E.identName.replace(D0,\"\")&&R===x)continue;let N=Array.from(C.references).sort(),U={name:C.identName,reference:N[0]},{name:V,scope:te}=n(C.name),ae=te?[te,V]:[V],fe=z.join(I,mIe),ue=z.join(fe,...ae),me=`${v}/${U.name}`,he=a(U,v,N.slice(1)),Be=!1;if(he.linkType===\"SOFT\"&&r.project){let we=r.project.workspacesByCwd.get(he.target.slice(0,-1));Be=!!(we&&!we.manifest.name)}if(!C.name.endsWith(D0)&&!Be){let we=o.get(ue);if(we){if(we.dirList)throw new Error(`Assertion failed: ${ue} cannot merge dir node with leaf node`);{let Pe=W.parseLocator(we.locator),ce=W.parseLocator(he.locator);if(we.linkType!==he.linkType)throw new Error(`Assertion failed: ${ue} cannot merge nodes with different link types ${we.nodePath}/${W.stringifyLocator(Pe)} and ${v}/${W.stringifyLocator(ce)}`);if(Pe.identHash!==ce.identHash)throw new Error(`Assertion failed: ${ue} cannot merge nodes with different idents ${we.nodePath}/${W.stringifyLocator(Pe)} and ${v}/s${W.stringifyLocator(ce)}`);he.aliases=[...he.aliases,...we.aliases,W.parseLocator(we.locator).reference]}}o.set(ue,he);let g=ue.split(\"/\"),Ee=g.indexOf(mIe);for(let Pe=g.length-1;Ee>=0&&Pe>Ee;Pe--){let ce=le.toPortablePath(g.slice(0,Pe).join(z.sep)),ne=g[Pe],ee=o.get(ce);if(!ee)o.set(ce,{dirList:new Set([ne])});else if(ee.dirList){if(ee.dirList.has(ne))break;ee.dirList.add(ne)}}}A(C,he.linkType===\"SOFT\"?he.target:ue,me)}},p=a({name:e.name,reference:Array.from(e.references)[0]},\"\",[]),h=p.target;return o.set(h,p),A(e,h,\"\"),o};Ye();Ye();Pt();Pt();iA();Nl();var oG={};zt(oG,{PnpInstaller:()=>mm,PnpLinker:()=>b0,UnplugCommand:()=>k0,default:()=>VIt,getPnpPath:()=>x0,jsInstallUtils:()=>yA,pnpUtils:()=>av,quotePathIfNeeded:()=>n1e});Pt();var r1e=ve(\"url\");Ye();Ye();Pt();Pt();var CIe={[\"DEFAULT\"]:{collapsed:!1,next:{[\"*\"]:\"DEFAULT\"}},[\"TOP_LEVEL\"]:{collapsed:!1,next:{fallbackExclusionList:\"FALLBACK_EXCLUSION_LIST\",packageRegistryData:\"PACKAGE_REGISTRY_DATA\",[\"*\"]:\"DEFAULT\"}},[\"FALLBACK_EXCLUSION_LIST\"]:{collapsed:!1,next:{[\"*\"]:\"FALLBACK_EXCLUSION_ENTRIES\"}},[\"FALLBACK_EXCLUSION_ENTRIES\"]:{collapsed:!0,next:{[\"*\"]:\"FALLBACK_EXCLUSION_DATA\"}},[\"FALLBACK_EXCLUSION_DATA\"]:{collapsed:!0,next:{[\"*\"]:\"DEFAULT\"}},[\"PACKAGE_REGISTRY_DATA\"]:{collapsed:!1,next:{[\"*\"]:\"PACKAGE_REGISTRY_ENTRIES\"}},[\"PACKAGE_REGISTRY_ENTRIES\"]:{collapsed:!0,next:{[\"*\"]:\"PACKAGE_STORE_DATA\"}},[\"PACKAGE_STORE_DATA\"]:{collapsed:!1,next:{[\"*\"]:\"PACKAGE_STORE_ENTRIES\"}},[\"PACKAGE_STORE_ENTRIES\"]:{collapsed:!0,next:{[\"*\"]:\"PACKAGE_INFORMATION_DATA\"}},[\"PACKAGE_INFORMATION_DATA\"]:{collapsed:!1,next:{packageDependencies:\"PACKAGE_DEPENDENCIES\",[\"*\"]:\"DEFAULT\"}},[\"PACKAGE_DEPENDENCIES\"]:{collapsed:!1,next:{[\"*\"]:\"PACKAGE_DEPENDENCY\"}},[\"PACKAGE_DEPENDENCY\"]:{collapsed:!0,next:{[\"*\"]:\"DEFAULT\"}}};function CIt(t,e,r){let o=\"\";o+=\"[\";for(let a=0,n=t.length;a<n;++a)o+=EQ(String(a),t[a],e,r).replace(/^ +/g,\"\"),a+1<n&&(o+=\", \");return o+=\"]\",o}function wIt(t,e,r){let o=`${r}  `,a=\"\";a+=r,a+=`[\n`;for(let n=0,u=t.length;n<u;++n)a+=o+EQ(String(n),t[n],e,o).replace(/^ +/,\"\"),n+1<u&&(a+=\",\"),a+=`\n`;return a+=r,a+=\"]\",a}function IIt(t,e,r){let o=Object.keys(t),a=\"\";a+=\"{\";for(let n=0,u=o.length,A=0;n<u;++n){let p=o[n],h=t[p];typeof h>\"u\"||(A!==0&&(a+=\", \"),a+=JSON.stringify(p),a+=\": \",a+=EQ(p,h,e,r).replace(/^ +/g,\"\"),A+=1)}return a+=\"}\",a}function BIt(t,e,r){let o=Object.keys(t),a=`${r}  `,n=\"\";n+=r,n+=`{\n`;let u=0;for(let A=0,p=o.length;A<p;++A){let h=o[A],E=t[h];typeof E>\"u\"||(u!==0&&(n+=\",\",n+=`\n`),n+=a,n+=JSON.stringify(h),n+=\": \",n+=EQ(h,E,e,a).replace(/^ +/g,\"\"),u+=1)}return u!==0&&(n+=`\n`),n+=r,n+=\"}\",n}function EQ(t,e,r,o){let{next:a}=CIe[r],n=a[t]||a[\"*\"];return wIe(e,n,o)}function wIe(t,e,r){let{collapsed:o}=CIe[e];return Array.isArray(t)?o?CIt(t,e,r):wIt(t,e,r):typeof t==\"object\"&&t!==null?o?IIt(t,e,r):BIt(t,e,r):JSON.stringify(t)}function IIe(t){return wIe(t,\"TOP_LEVEL\",\"\")}function XB(t,e){let r=Array.from(t);Array.isArray(e)||(e=[e]);let o=[];for(let n of e)o.push(r.map(u=>n(u)));let a=r.map((n,u)=>u);return a.sort((n,u)=>{for(let A of o){let p=A[n]<A[u]?-1:A[n]>A[u]?1:0;if(p!==0)return p}return 0}),a.map(n=>r[n])}function vIt(t){let e=new Map,r=XB(t.fallbackExclusionList||[],[({name:o,reference:a})=>o,({name:o,reference:a})=>a]);for(let{name:o,reference:a}of r){let n=e.get(o);typeof n>\"u\"&&e.set(o,n=new Set),n.add(a)}return Array.from(e).map(([o,a])=>[o,Array.from(a)])}function DIt(t){return XB(t.fallbackPool||[],([e])=>e)}function PIt(t){let e=[];for(let[r,o]of XB(t.packageRegistry,([a])=>a===null?\"0\":`1${a}`)){let a=[];e.push([r,a]);for(let[n,{packageLocation:u,packageDependencies:A,packagePeers:p,linkType:h,discardFromLookup:E}]of XB(o,([I])=>I===null?\"0\":`1${I}`)){let I=[];r!==null&&n!==null&&!A.has(r)&&I.push([r,n]);for(let[C,R]of XB(A.entries(),([N])=>N))I.push([C,R]);let v=p&&p.size>0?Array.from(p):void 0,x=E||void 0;a.push([n,{packageLocation:u,packageDependencies:I,packagePeers:v,linkType:h,discardFromLookup:x}])}}return e}function ZB(t){return{__info:[\"This file is automatically generated. Do not touch it, or risk\",\"your modifications being lost.\"],dependencyTreeRoots:t.dependencyTreeRoots,enableTopLevelFallback:t.enableTopLevelFallback||!1,ignorePatternData:t.ignorePattern||null,fallbackExclusionList:vIt(t),fallbackPool:DIt(t),packageRegistryData:PIt(t)}}var DIe=$e(vIe());function PIe(t,e){return[t?`${t}\n`:\"\",`/* eslint-disable */\n`,`// @ts-nocheck\n`,`\"use strict\";\n`,`\n`,e,`\n`,(0,DIe.default)()].join(\"\")}function SIt(t){return JSON.stringify(t,null,2)}function bIt(t){return`'${t.replace(/\\\\/g,\"\\\\\\\\\").replace(/'/g,\"\\\\'\").replace(/\\n/g,`\\\\\n`)}'`}function xIt(t){return[`const RAW_RUNTIME_STATE =\n`,`${bIt(IIe(t))};\n\n`,`function $$SETUP_STATE(hydrateRuntimeState, basePath) {\n`,`  return hydrateRuntimeState(JSON.parse(RAW_RUNTIME_STATE), {basePath: basePath || __dirname});\n`,`}\n`].join(\"\")}function kIt(){return[`function $$SETUP_STATE(hydrateRuntimeState, basePath) {\n`,`  const fs = require('fs');\n`,`  const path = require('path');\n`,`  const pnpDataFilepath = path.resolve(__dirname, ${JSON.stringify(dr.pnpData)});\n`,`  return hydrateRuntimeState(JSON.parse(fs.readFileSync(pnpDataFilepath, 'utf8')), {basePath: basePath || __dirname});\n`,`}\n`].join(\"\")}function SIe(t){let e=ZB(t),r=xIt(e);return PIe(t.shebang,r)}function bIe(t){let e=ZB(t),r=kIt(),o=PIe(t.shebang,r);return{dataFile:SIt(e),loaderFile:o}}Pt();function Gq(t,{basePath:e}){let r=le.toPortablePath(e),o=z.resolve(r),a=t.ignorePatternData!==null?new RegExp(t.ignorePatternData):null,n=new Map,u=new Map(t.packageRegistryData.map(([I,v])=>[I,new Map(v.map(([x,C])=>{if(I===null!=(x===null))throw new Error(\"Assertion failed: The name and reference should be null, or neither should\");let R=C.discardFromLookup??!1,N={name:I,reference:x},U=n.get(C.packageLocation);U?(U.discardFromLookup=U.discardFromLookup&&R,R||(U.locator=N)):n.set(C.packageLocation,{locator:N,discardFromLookup:R});let V=null;return[x,{packageDependencies:new Map(C.packageDependencies),packagePeers:new Set(C.packagePeers),linkType:C.linkType,discardFromLookup:R,get packageLocation(){return V||(V=z.join(o,C.packageLocation))}}]}))])),A=new Map(t.fallbackExclusionList.map(([I,v])=>[I,new Set(v)])),p=new Map(t.fallbackPool),h=t.dependencyTreeRoots,E=t.enableTopLevelFallback;return{basePath:r,dependencyTreeRoots:h,enableTopLevelFallback:E,fallbackExclusionList:A,fallbackPool:p,ignorePattern:a,packageLocatorsByLocations:n,packageRegistry:u}}Pt();Pt();var ip=ve(\"module\"),dm=ve(\"url\"),$q=ve(\"util\");var Mo=ve(\"url\");var FIe=$e(ve(\"assert\"));var jq=Array.isArray,$B=JSON.stringify,ev=Object.getOwnPropertyNames,gm=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),Yq=(t,e)=>RegExp.prototype.exec.call(t,e),Wq=(t,...e)=>RegExp.prototype[Symbol.replace].apply(t,e),P0=(t,...e)=>String.prototype.endsWith.apply(t,e),Kq=(t,...e)=>String.prototype.includes.apply(t,e),zq=(t,...e)=>String.prototype.lastIndexOf.apply(t,e),tv=(t,...e)=>String.prototype.indexOf.apply(t,e),xIe=(t,...e)=>String.prototype.replace.apply(t,e),S0=(t,...e)=>String.prototype.slice.apply(t,e),mA=(t,...e)=>String.prototype.startsWith.apply(t,e),kIe=Map,QIe=JSON.parse;function rv(t,e,r){return class extends r{constructor(...o){super(e(...o)),this.code=t,this.name=`${r.name} [${t}]`}}}var RIe=rv(\"ERR_PACKAGE_IMPORT_NOT_DEFINED\",(t,e,r)=>`Package import specifier \"${t}\" is not defined${e?` in package ${e}package.json`:\"\"} imported from ${r}`,TypeError),Vq=rv(\"ERR_INVALID_MODULE_SPECIFIER\",(t,e,r=void 0)=>`Invalid module \"${t}\" ${e}${r?` imported from ${r}`:\"\"}`,TypeError),TIe=rv(\"ERR_INVALID_PACKAGE_TARGET\",(t,e,r,o=!1,a=void 0)=>{let n=typeof r==\"string\"&&!o&&r.length&&!mA(r,\"./\");return e===\".\"?((0,FIe.default)(o===!1),`Invalid \"exports\" main target ${$B(r)} defined in the package config ${t}package.json${a?` imported from ${a}`:\"\"}${n?'; targets must start with \"./\"':\"\"}`):`Invalid \"${o?\"imports\":\"exports\"}\" target ${$B(r)} defined for '${e}' in the package config ${t}package.json${a?` imported from ${a}`:\"\"}${n?'; targets must start with \"./\"':\"\"}`},Error),nv=rv(\"ERR_INVALID_PACKAGE_CONFIG\",(t,e,r)=>`Invalid package config ${t}${e?` while importing ${e}`:\"\"}${r?`. ${r}`:\"\"}`,Error),LIe=rv(\"ERR_PACKAGE_PATH_NOT_EXPORTED\",(t,e,r=void 0)=>e===\".\"?`No \"exports\" main defined in ${t}package.json${r?` imported from ${r}`:\"\"}`:`Package subpath '${e}' is not defined by \"exports\" in ${t}package.json${r?` imported from ${r}`:\"\"}`,Error);var wQ=ve(\"url\");function NIe(t,e){let r=Object.create(null);for(let o=0;o<e.length;o++){let a=e[o];gm(t,a)&&(r[a]=t[a])}return r}var CQ=new kIe;function QIt(t,e,r,o){let a=CQ.get(t);if(a!==void 0)return a;let n=o(t);if(n===void 0){let x={pjsonPath:t,exists:!1,main:void 0,name:void 0,type:\"none\",exports:void 0,imports:void 0};return CQ.set(t,x),x}let u;try{u=QIe(n)}catch(x){throw new nv(t,(r?`\"${e}\" from `:\"\")+(0,wQ.fileURLToPath)(r||e),x.message)}let{imports:A,main:p,name:h,type:E}=NIe(u,[\"imports\",\"main\",\"name\",\"type\"]),I=gm(u,\"exports\")?u.exports:void 0;(typeof A!=\"object\"||A===null)&&(A=void 0),typeof p!=\"string\"&&(p=void 0),typeof h!=\"string\"&&(h=void 0),E!==\"module\"&&E!==\"commonjs\"&&(E=\"none\");let v={pjsonPath:t,exists:!0,main:p,name:h,type:E,exports:I,imports:A};return CQ.set(t,v),v}function OIe(t,e){let r=new URL(\"./package.json\",t);for(;;){let n=r.pathname;if(P0(n,\"node_modules/package.json\"))break;let u=QIt((0,wQ.fileURLToPath)(r),t,void 0,e);if(u.exists)return u;let A=r;if(r=new URL(\"../package.json\",r),r.pathname===A.pathname)break}let o=(0,wQ.fileURLToPath)(r),a={pjsonPath:o,exists:!1,main:void 0,name:void 0,type:\"none\",exports:void 0,imports:void 0};return CQ.set(o,a),a}function FIt(t,e,r){throw new RIe(t,e&&(0,Mo.fileURLToPath)(new URL(\".\",e)),(0,Mo.fileURLToPath)(r))}function RIt(t,e,r,o){let a=`request is not a valid subpath for the \"${r?\"imports\":\"exports\"}\" resolution of ${(0,Mo.fileURLToPath)(e)}`;throw new Vq(t,a,o&&(0,Mo.fileURLToPath)(o))}function iv(t,e,r,o,a){throw typeof e==\"object\"&&e!==null?e=$B(e,null,\"\"):e=`${e}`,new TIe((0,Mo.fileURLToPath)(new URL(\".\",r)),t,e,o,a&&(0,Mo.fileURLToPath)(a))}var MIe=/(^|\\\\|\\/)((\\.|%2e)(\\.|%2e)?|(n|%6e|%4e)(o|%6f|%4f)(d|%64|%44)(e|%65|%45)(_|%5f)(m|%6d|%4d)(o|%6f|%4f)(d|%64|%44)(u|%75|%55)(l|%6c|%4c)(e|%65|%45)(s|%73|%53))(\\\\|\\/|$)/i,UIe=/\\*/g;function TIt(t,e,r,o,a,n,u,A){if(e!==\"\"&&!n&&t[t.length-1]!==\"/\"&&iv(r,t,o,u,a),!mA(t,\"./\")){if(u&&!mA(t,\"../\")&&!mA(t,\"/\")){let I=!1;try{new URL(t),I=!0}catch{}if(!I)return n?Wq(UIe,t,()=>e):t+e}iv(r,t,o,u,a)}Yq(MIe,S0(t,2))!==null&&iv(r,t,o,u,a);let p=new URL(t,o),h=p.pathname,E=new URL(\".\",o).pathname;if(mA(h,E)||iv(r,t,o,u,a),e===\"\")return p;if(Yq(MIe,e)!==null){let I=n?xIe(r,\"*\",()=>e):r+e;RIt(I,o,u,a)}return n?new URL(Wq(UIe,p.href,()=>e)):new URL(e,p)}function LIt(t){let e=+t;return`${e}`!==t?!1:e>=0&&e<4294967295}function jC(t,e,r,o,a,n,u,A){if(typeof e==\"string\")return TIt(e,r,o,t,a,n,u,A);if(jq(e)){if(e.length===0)return null;let p;for(let h=0;h<e.length;h++){let E=e[h],I;try{I=jC(t,E,r,o,a,n,u,A)}catch(v){if(p=v,v.code===\"ERR_INVALID_PACKAGE_TARGET\")continue;throw v}if(I!==void 0){if(I===null){p=null;continue}return I}}if(p==null)return p;throw p}else if(typeof e==\"object\"&&e!==null){let p=ev(e);for(let h=0;h<p.length;h++){let E=p[h];if(LIt(E))throw new nv((0,Mo.fileURLToPath)(t),a,'\"exports\" cannot contain numeric property keys.')}for(let h=0;h<p.length;h++){let E=p[h];if(E===\"default\"||A.has(E)){let I=e[E],v=jC(t,I,r,o,a,n,u,A);if(v===void 0)continue;return v}}return}else if(e===null)return null;iv(o,e,t,u,a)}function HIe(t,e){let r=tv(t,\"*\"),o=tv(e,\"*\"),a=r===-1?t.length:r+1,n=o===-1?e.length:o+1;return a>n?-1:n>a||r===-1?1:o===-1||t.length>e.length?-1:e.length>t.length?1:0}function NIt(t,e,r){if(typeof t==\"string\"||jq(t))return!0;if(typeof t!=\"object\"||t===null)return!1;let o=ev(t),a=!1,n=0;for(let u=0;u<o.length;u++){let A=o[u],p=A===\"\"||A[0]!==\".\";if(n++===0)a=p;else if(a!==p)throw new nv((0,Mo.fileURLToPath)(e),r,`\"exports\" cannot contain some keys starting with '.' and some not. The exports object must either be an object of package subpath keys or an object of main entry condition name keys only.`)}return a}function Jq(t,e,r){throw new LIe((0,Mo.fileURLToPath)(new URL(\".\",e)),t,r&&(0,Mo.fileURLToPath)(r))}var _Ie=new Set;function OIt(t,e,r){let o=(0,Mo.fileURLToPath)(e);_Ie.has(o+\"|\"+t)||(_Ie.add(o+\"|\"+t),process.emitWarning(`Use of deprecated trailing slash pattern mapping \"${t}\" in the \"exports\" field module resolution of the package at ${o}${r?` imported from ${(0,Mo.fileURLToPath)(r)}`:\"\"}. Mapping specifiers ending in \"/\" is no longer supported.`,\"DeprecationWarning\",\"DEP0155\"))}function qIe({packageJSONUrl:t,packageSubpath:e,exports:r,base:o,conditions:a}){if(NIt(r,t,o)&&(r={\".\":r}),gm(r,e)&&!Kq(e,\"*\")&&!P0(e,\"/\")){let p=r[e],h=jC(t,p,\"\",e,o,!1,!1,a);return h==null&&Jq(e,t,o),h}let n=\"\",u,A=ev(r);for(let p=0;p<A.length;p++){let h=A[p],E=tv(h,\"*\");if(E!==-1&&mA(e,S0(h,0,E))){P0(e,\"/\")&&OIt(e,t,o);let I=S0(h,E+1);e.length>=h.length&&P0(e,I)&&HIe(n,h)===1&&zq(h,\"*\")===E&&(n=h,u=S0(e,E,e.length-I.length))}}if(n){let p=r[n],h=jC(t,p,u,n,o,!0,!1,a);return h==null&&Jq(e,t,o),h}Jq(e,t,o)}function GIe({name:t,base:e,conditions:r,readFileSyncFn:o}){if(t===\"#\"||mA(t,\"#/\")||P0(t,\"/\")){let u=\"is not a valid internal imports specifier name\";throw new Vq(t,u,(0,Mo.fileURLToPath)(e))}let a,n=OIe(e,o);if(n.exists){a=(0,Mo.pathToFileURL)(n.pjsonPath);let u=n.imports;if(u)if(gm(u,t)&&!Kq(t,\"*\")){let A=jC(a,u[t],\"\",t,e,!1,!0,r);if(A!=null)return A}else{let A=\"\",p,h=ev(u);for(let E=0;E<h.length;E++){let I=h[E],v=tv(I,\"*\");if(v!==-1&&mA(t,S0(I,0,v))){let x=S0(I,v+1);t.length>=I.length&&P0(t,x)&&HIe(A,I)===1&&zq(I,\"*\")===v&&(A=I,p=S0(t,v,t.length-x.length))}}if(A){let E=u[A],I=jC(a,E,p,A,e,!0,!0,r);if(I!=null)return I}}}FIt(t,a,e)}Pt();var MIt=new Set([\"BUILTIN_NODE_RESOLUTION_FAILED\",\"MISSING_DEPENDENCY\",\"MISSING_PEER_DEPENDENCY\",\"QUALIFIED_PATH_RESOLUTION_FAILED\",\"UNDECLARED_DEPENDENCY\"]);function $i(t,e,r={},o){o??=MIt.has(t)?\"MODULE_NOT_FOUND\":t;let a={configurable:!0,writable:!0,enumerable:!1};return Object.defineProperties(new Error(e),{code:{...a,value:o},pnpCode:{...a,value:t},data:{...a,value:r}})}function lu(t){return le.normalize(le.fromPortablePath(t))}var KIe=$e(YIe());function zIe(t){return UIt(),Zq[t]}var Zq;function UIt(){Zq||(Zq={\"--conditions\":[],...WIe(_It()),...WIe(process.execArgv)})}function WIe(t){return(0,KIe.default)({\"--conditions\":[String],\"-C\":\"--conditions\"},{argv:t,permissive:!0})}function _It(){let t=[],e=HIt(process.env.NODE_OPTIONS||\"\",t);return t.length,e}function HIt(t,e){let r=[],o=!1,a=!0;for(let n=0;n<t.length;++n){let u=t[n];if(u===\"\\\\\"&&o){if(n+1===t.length)return e.push(`invalid value for NODE_OPTIONS (invalid escape)\n`),r;u=t[++n]}else if(u===\" \"&&!o){a=!0;continue}else if(u==='\"'){o=!o;continue}a?(r.push(u),a=!1):r[r.length-1]+=u}return o&&e.push(`invalid value for NODE_OPTIONS (unterminated string)\n`),r}Pt();var[Ma,np]=process.versions.node.split(\".\").map(t=>parseInt(t,10)),VIe=Ma>19||Ma===19&&np>=2||Ma===18&&np>=13,vJt=Ma===20&&np<6||Ma===19&&np>=3,DJt=Ma>19||Ma===19&&np>=6,PJt=Ma>=21||Ma===20&&np>=10||Ma===18&&np>=19,SJt=Ma>=21||Ma===20&&np>=10||Ma===18&&np>=20,bJt=Ma>=22;function JIe(t){if(process.env.WATCH_REPORT_DEPENDENCIES&&process.send)if(t=t.map(e=>le.fromPortablePath(mi.resolveVirtual(le.toPortablePath(e)))),VIe)process.send({\"watch:require\":t});else for(let e of t)process.send({\"watch:require\":e})}function eG(t,e){let r=Number(process.env.PNP_ALWAYS_WARN_ON_FALLBACK)>0,o=Number(process.env.PNP_DEBUG_LEVEL),a=/^(?![a-zA-Z]:[\\\\/]|\\\\\\\\|\\.{0,2}(?:\\/|$))((?:node:)?(?:@[^/]+\\/)?[^/]+)\\/*(.*|)$/,n=/^(\\/|\\.{1,2}(\\/|$))/,u=/\\/$/,A=/^\\.{0,2}\\//,p={name:null,reference:null},h=[],E=new Set;if(t.enableTopLevelFallback===!0&&h.push(p),e.compatibilityMode!==!1)for(let Re of[\"react-scripts\",\"gatsby\"]){let ke=t.packageRegistry.get(Re);if(ke)for(let xe of ke.keys()){if(xe===null)throw new Error(\"Assertion failed: This reference shouldn't be null\");h.push({name:Re,reference:xe})}}let{ignorePattern:I,packageRegistry:v,packageLocatorsByLocations:x}=t;function C(Re,ke){return{fn:Re,args:ke,error:null,result:null}}function R(Re){let ke=process.stderr?.hasColors?.()??process.stdout.isTTY,xe=(Ve,qe)=>`\\x1B[${Ve}m${qe}\\x1B[0m`,He=Re.error;console.error(He?xe(\"31;1\",`\\u2716 ${Re.error?.message.replace(/\\n.*/s,\"\")}`):xe(\"33;1\",\"\\u203C Resolution\")),Re.args.length>0&&console.error();for(let Ve of Re.args)console.error(`  ${xe(\"37;1\",\"In \\u2190\")} ${(0,$q.inspect)(Ve,{colors:ke,compact:!0})}`);Re.result&&(console.error(),console.error(`  ${xe(\"37;1\",\"Out \\u2192\")} ${(0,$q.inspect)(Re.result,{colors:ke,compact:!0})}`));let Te=new Error().stack.match(/(?<=^ +)at.*/gm)?.slice(2)??[];if(Te.length>0){console.error();for(let Ve of Te)console.error(`  ${xe(\"38;5;244\",Ve)}`)}console.error()}function N(Re,ke){if(e.allowDebug===!1)return ke;if(Number.isFinite(o)){if(o>=2)return(...xe)=>{let He=C(Re,xe);try{return He.result=ke(...xe)}catch(Te){throw He.error=Te}finally{R(He)}};if(o>=1)return(...xe)=>{try{return ke(...xe)}catch(He){let Te=C(Re,xe);throw Te.error=He,R(Te),He}}}return ke}function U(Re){let ke=g(Re);if(!ke)throw $i(\"INTERNAL\",\"Couldn't find a matching entry in the dependency tree for the specified parent (this is probably an internal error)\");return ke}function V(Re){if(Re.name===null)return!0;for(let ke of t.dependencyTreeRoots)if(ke.name===Re.name&&ke.reference===Re.reference)return!0;return!1}let te=new Set([\"node\",\"require\",...zIe(\"--conditions\")]);function ae(Re,ke=te,xe){let He=ce(z.join(Re,\"internal.js\"),{resolveIgnored:!0,includeDiscardFromLookup:!0});if(He===null)throw $i(\"INTERNAL\",`The locator that owns the \"${Re}\" path can't be found inside the dependency tree (this is probably an internal error)`);let{packageLocation:Te}=U(He),Ve=z.join(Te,dr.manifest);if(!e.fakeFs.existsSync(Ve))return null;let qe=JSON.parse(e.fakeFs.readFileSync(Ve,\"utf8\"));if(qe.exports==null)return null;let b=z.contains(Te,Re);if(b===null)throw $i(\"INTERNAL\",\"unqualifiedPath doesn't contain the packageLocation (this is probably an internal error)\");b!==\".\"&&!A.test(b)&&(b=`./${b}`);try{let w=qIe({packageJSONUrl:(0,dm.pathToFileURL)(le.fromPortablePath(Ve)),packageSubpath:b,exports:qe.exports,base:xe?(0,dm.pathToFileURL)(le.fromPortablePath(xe)):null,conditions:ke});return le.toPortablePath((0,dm.fileURLToPath)(w))}catch(w){throw $i(\"EXPORTS_RESOLUTION_FAILED\",w.message,{unqualifiedPath:lu(Re),locator:He,pkgJson:qe,subpath:lu(b),conditions:ke},w.code)}}function fe(Re,ke,{extensions:xe}){let He;try{ke.push(Re),He=e.fakeFs.statSync(Re)}catch{}if(He&&!He.isDirectory())return e.fakeFs.realpathSync(Re);if(He&&He.isDirectory()){let Te;try{Te=JSON.parse(e.fakeFs.readFileSync(z.join(Re,dr.manifest),\"utf8\"))}catch{}let Ve;if(Te&&Te.main&&(Ve=z.resolve(Re,Te.main)),Ve&&Ve!==Re){let qe=fe(Ve,ke,{extensions:xe});if(qe!==null)return qe}}for(let Te=0,Ve=xe.length;Te<Ve;Te++){let qe=`${Re}${xe[Te]}`;if(ke.push(qe),e.fakeFs.existsSync(qe))return qe}if(He&&He.isDirectory())for(let Te=0,Ve=xe.length;Te<Ve;Te++){let qe=z.format({dir:Re,name:\"index\",ext:xe[Te]});if(ke.push(qe),e.fakeFs.existsSync(qe))return qe}return null}function ue(Re){let ke=new ip.Module(Re,null);return ke.filename=Re,ke.paths=ip.Module._nodeModulePaths(Re),ke}function me(Re,ke){return ke.endsWith(\"/\")&&(ke=z.join(ke,\"internal.js\")),ip.Module._resolveFilename(le.fromPortablePath(Re),ue(le.fromPortablePath(ke)),!1,{plugnplay:!1})}function he(Re){if(I===null)return!1;let ke=z.contains(t.basePath,Re);return ke===null?!1:!!I.test(ke.replace(/\\/$/,\"\"))}let Be={std:3,resolveVirtual:1,getAllLocators:1},we=p;function g({name:Re,reference:ke}){let xe=v.get(Re);if(!xe)return null;let He=xe.get(ke);return He||null}function Ee({name:Re,reference:ke}){let xe=[];for(let[He,Te]of v)if(He!==null)for(let[Ve,qe]of Te)Ve===null||qe.packageDependencies.get(Re)!==ke||He===Re&&Ve===ke||xe.push({name:He,reference:Ve});return xe}function Pe(Re,ke){let xe=new Map,He=new Set,Te=qe=>{let b=JSON.stringify(qe.name);if(He.has(b))return;He.add(b);let w=Ee(qe);for(let S of w)if(U(S).packagePeers.has(Re))Te(S);else{let F=xe.get(S.name);typeof F>\"u\"&&xe.set(S.name,F=new Set),F.add(S.reference)}};Te(ke);let Ve=[];for(let qe of[...xe.keys()].sort())for(let b of[...xe.get(qe)].sort())Ve.push({name:qe,reference:b});return Ve}function ce(Re,{resolveIgnored:ke=!1,includeDiscardFromLookup:xe=!1}={}){if(he(Re)&&!ke)return null;let He=z.relative(t.basePath,Re);He.match(n)||(He=`./${He}`),He.endsWith(\"/\")||(He=`${He}/`);do{let Te=x.get(He);if(typeof Te>\"u\"||Te.discardFromLookup&&!xe){He=He.substring(0,He.lastIndexOf(\"/\",He.length-2)+1);continue}return Te.locator}while(He!==\"\");return null}function ne(Re){try{return e.fakeFs.readFileSync(le.toPortablePath(Re),\"utf8\")}catch(ke){if(ke.code===\"ENOENT\")return;throw ke}}function ee(Re,ke,{considerBuiltins:xe=!0}={}){if(Re.startsWith(\"#\"))throw new Error(\"resolveToUnqualified can not handle private import mappings\");if(Re===\"pnpapi\")return le.toPortablePath(e.pnpapiResolution);if(xe&&(0,ip.isBuiltin)(Re))return null;let He=lu(Re),Te=ke&&lu(ke);if(ke&&he(ke)&&(!z.isAbsolute(Re)||ce(Re)===null)){let b=me(Re,ke);if(b===!1)throw $i(\"BUILTIN_NODE_RESOLUTION_FAILED\",`The builtin node resolution algorithm was unable to resolve the requested module (it didn't go through the pnp resolver because the issuer was explicitely ignored by the regexp)\n\nRequire request: \"${He}\"\nRequired by: ${Te}\n`,{request:He,issuer:Te});return le.toPortablePath(b)}let Ve,qe=Re.match(a);if(qe){if(!ke)throw $i(\"API_ERROR\",\"The resolveToUnqualified function must be called with a valid issuer when the path isn't a builtin nor absolute\",{request:He,issuer:Te});let[,b,w]=qe,S=ce(ke);if(!S){let Le=me(Re,ke);if(Le===!1)throw $i(\"BUILTIN_NODE_RESOLUTION_FAILED\",`The builtin node resolution algorithm was unable to resolve the requested module (it didn't go through the pnp resolver because the issuer doesn't seem to be part of the Yarn-managed dependency tree).\n\nRequire path: \"${He}\"\nRequired by: ${Te}\n`,{request:He,issuer:Te});return le.toPortablePath(Le)}let F=U(S).packageDependencies.get(b),J=null;if(F==null&&S.name!==null){let Le=t.fallbackExclusionList.get(S.name);if(!Le||!Le.has(S.reference)){for(let dt=0,Gt=h.length;dt<Gt;++dt){let bt=U(h[dt]).packageDependencies.get(b);if(bt!=null){r?J=bt:F=bt;break}}if(t.enableTopLevelFallback&&F==null&&J===null){let dt=t.fallbackPool.get(b);dt!=null&&(J=dt)}}}let X=null;if(F===null)if(V(S))X=$i(\"MISSING_PEER_DEPENDENCY\",`Your application tried to access ${b} (a peer dependency); this isn't allowed as there is no ancestor to satisfy the requirement. Use a devDependency if needed.\n\nRequired package: ${b}${b!==He?` (via \"${He}\")`:\"\"}\nRequired by: ${Te}\n`,{request:He,issuer:Te,dependencyName:b});else{let Le=Pe(b,S);Le.every(ot=>V(ot))?X=$i(\"MISSING_PEER_DEPENDENCY\",`${S.name} tried to access ${b} (a peer dependency) but it isn't provided by your application; this makes the require call ambiguous and unsound.\n\nRequired package: ${b}${b!==He?` (via \"${He}\")`:\"\"}\nRequired by: ${S.name}@${S.reference} (via ${Te})\n${Le.map(ot=>`Ancestor breaking the chain: ${ot.name}@${ot.reference}\n`).join(\"\")}\n`,{request:He,issuer:Te,issuerLocator:Object.assign({},S),dependencyName:b,brokenAncestors:Le}):X=$i(\"MISSING_PEER_DEPENDENCY\",`${S.name} tried to access ${b} (a peer dependency) but it isn't provided by its ancestors; this makes the require call ambiguous and unsound.\n\nRequired package: ${b}${b!==He?` (via \"${He}\")`:\"\"}\nRequired by: ${S.name}@${S.reference} (via ${Te})\n\n${Le.map(ot=>`Ancestor breaking the chain: ${ot.name}@${ot.reference}\n`).join(\"\")}\n`,{request:He,issuer:Te,issuerLocator:Object.assign({},S),dependencyName:b,brokenAncestors:Le})}else F===void 0&&(!xe&&(0,ip.isBuiltin)(Re)?V(S)?X=$i(\"UNDECLARED_DEPENDENCY\",`Your application tried to access ${b}. While this module is usually interpreted as a Node builtin, your resolver is running inside a non-Node resolution context where such builtins are ignored. Since ${b} isn't otherwise declared in your dependencies, this makes the require call ambiguous and unsound.\n\nRequired package: ${b}${b!==He?` (via \"${He}\")`:\"\"}\nRequired by: ${Te}\n`,{request:He,issuer:Te,dependencyName:b}):X=$i(\"UNDECLARED_DEPENDENCY\",`${S.name} tried to access ${b}. While this module is usually interpreted as a Node builtin, your resolver is running inside a non-Node resolution context where such builtins are ignored. Since ${b} isn't otherwise declared in ${S.name}'s dependencies, this makes the require call ambiguous and unsound.\n\nRequired package: ${b}${b!==He?` (via \"${He}\")`:\"\"}\nRequired by: ${Te}\n`,{request:He,issuer:Te,issuerLocator:Object.assign({},S),dependencyName:b}):V(S)?X=$i(\"UNDECLARED_DEPENDENCY\",`Your application tried to access ${b}, but it isn't declared in your dependencies; this makes the require call ambiguous and unsound.\n\nRequired package: ${b}${b!==He?` (via \"${He}\")`:\"\"}\nRequired by: ${Te}\n`,{request:He,issuer:Te,dependencyName:b}):X=$i(\"UNDECLARED_DEPENDENCY\",`${S.name} tried to access ${b}, but it isn't declared in its dependencies; this makes the require call ambiguous and unsound.\n\nRequired package: ${b}${b!==He?` (via \"${He}\")`:\"\"}\nRequired by: ${S.name}@${S.reference} (via ${Te})\n`,{request:He,issuer:Te,issuerLocator:Object.assign({},S),dependencyName:b}));if(F==null){if(J===null||X===null)throw X||new Error(\"Assertion failed: Expected an error to have been set\");F=J;let Le=X.message.replace(/\\n.*/g,\"\");X.message=Le,!E.has(Le)&&o!==0&&(E.add(Le),process.emitWarning(X))}let Z=Array.isArray(F)?{name:F[0],reference:F[1]}:{name:b,reference:F},ie=U(Z);if(!ie.packageLocation)throw $i(\"MISSING_DEPENDENCY\",`A dependency seems valid but didn't get installed for some reason. This might be caused by a partial install, such as dev vs prod.\n\nRequired package: ${Z.name}@${Z.reference}${Z.name!==He?` (via \"${He}\")`:\"\"}\nRequired by: ${S.name}@${S.reference} (via ${Te})\n`,{request:He,issuer:Te,dependencyLocator:Object.assign({},Z)});let be=ie.packageLocation;w?Ve=z.join(be,w):Ve=be}else if(z.isAbsolute(Re))Ve=z.normalize(Re);else{if(!ke)throw $i(\"API_ERROR\",\"The resolveToUnqualified function must be called with a valid issuer when the path isn't a builtin nor absolute\",{request:He,issuer:Te});let b=z.resolve(ke);ke.match(u)?Ve=z.normalize(z.join(b,Re)):Ve=z.normalize(z.join(z.dirname(b),Re))}return z.normalize(Ve)}function Ie(Re,ke,xe=te,He){if(n.test(Re))return ke;let Te=ae(ke,xe,He);return Te?z.normalize(Te):ke}function Fe(Re,{extensions:ke=Object.keys(ip.Module._extensions)}={}){let xe=[],He=fe(Re,xe,{extensions:ke});if(He)return z.normalize(He);{JIe(xe.map(qe=>le.fromPortablePath(qe)));let Te=lu(Re),Ve=ce(Re);if(Ve){let{packageLocation:qe}=U(Ve),b=!0;try{e.fakeFs.accessSync(qe)}catch(w){if(w?.code===\"ENOENT\")b=!1;else{let S=(w?.message??w??\"empty exception thrown\").replace(/^[A-Z]/,y=>y.toLowerCase());throw $i(\"QUALIFIED_PATH_RESOLUTION_FAILED\",`Required package exists but could not be accessed (${S}).\n\nMissing package: ${Ve.name}@${Ve.reference}\nExpected package location: ${lu(qe)}\n`,{unqualifiedPath:Te,extensions:ke})}}if(!b){let w=qe.includes(\"/unplugged/\")?\"Required unplugged package missing from disk. This may happen when switching branches without running installs (unplugged packages must be fully materialized on disk to work).\":\"Required package missing from disk. If you keep your packages inside your repository then restarting the Node process may be enough. Otherwise, try to run an install first.\";throw $i(\"QUALIFIED_PATH_RESOLUTION_FAILED\",`${w}\n\nMissing package: ${Ve.name}@${Ve.reference}\nExpected package location: ${lu(qe)}\n`,{unqualifiedPath:Te,extensions:ke})}}throw $i(\"QUALIFIED_PATH_RESOLUTION_FAILED\",`Qualified path resolution failed: we looked for the following paths, but none could be accessed.\n\nSource path: ${Te}\n${xe.map(qe=>`Not found: ${lu(qe)}\n`).join(\"\")}`,{unqualifiedPath:Te,extensions:ke})}}function At(Re,ke,xe){if(!ke)throw new Error(\"Assertion failed: An issuer is required to resolve private import mappings\");let He=GIe({name:Re,base:(0,dm.pathToFileURL)(le.fromPortablePath(ke)),conditions:xe.conditions??te,readFileSyncFn:ne});if(He instanceof URL)return Fe(le.toPortablePath((0,dm.fileURLToPath)(He)),{extensions:xe.extensions});if(He.startsWith(\"#\"))throw new Error(\"Mapping from one private import to another isn't allowed\");return H(He,ke,xe)}function H(Re,ke,xe={}){try{if(Re.startsWith(\"#\"))return At(Re,ke,xe);let{considerBuiltins:He,extensions:Te,conditions:Ve}=xe,qe=ee(Re,ke,{considerBuiltins:He});if(Re===\"pnpapi\")return qe;if(qe===null)return null;let b=()=>ke!==null?he(ke):!1,w=(!He||!(0,ip.isBuiltin)(Re))&&!b()?Ie(Re,qe,Ve,ke):qe;return Fe(w,{extensions:Te})}catch(He){throw Object.hasOwn(He,\"pnpCode\")&&Object.assign(He.data,{request:lu(Re),issuer:ke&&lu(ke)}),He}}function at(Re){let ke=z.normalize(Re),xe=mi.resolveVirtual(ke);return xe!==ke?xe:null}return{VERSIONS:Be,topLevel:we,getLocator:(Re,ke)=>Array.isArray(ke)?{name:ke[0],reference:ke[1]}:{name:Re,reference:ke},getDependencyTreeRoots:()=>[...t.dependencyTreeRoots],getAllLocators(){let Re=[];for(let[ke,xe]of v)for(let He of xe.keys())ke!==null&&He!==null&&Re.push({name:ke,reference:He});return Re},getPackageInformation:Re=>{let ke=g(Re);if(ke===null)return null;let xe=le.fromPortablePath(ke.packageLocation);return{...ke,packageLocation:xe}},findPackageLocator:Re=>ce(le.toPortablePath(Re)),resolveToUnqualified:N(\"resolveToUnqualified\",(Re,ke,xe)=>{let He=ke!==null?le.toPortablePath(ke):null,Te=ee(le.toPortablePath(Re),He,xe);return Te===null?null:le.fromPortablePath(Te)}),resolveUnqualified:N(\"resolveUnqualified\",(Re,ke)=>le.fromPortablePath(Fe(le.toPortablePath(Re),ke))),resolveRequest:N(\"resolveRequest\",(Re,ke,xe)=>{let He=ke!==null?le.toPortablePath(ke):null,Te=H(le.toPortablePath(Re),He,xe);return Te===null?null:le.fromPortablePath(Te)}),resolveVirtual:N(\"resolveVirtual\",Re=>{let ke=at(le.toPortablePath(Re));return ke!==null?le.fromPortablePath(ke):null})}}Pt();var XIe=(t,e,r)=>{let o=ZB(t),a=Gq(o,{basePath:e}),n=le.join(e,dr.pnpCjs);return eG(a,{fakeFs:r,pnpapiResolution:n})};var rG=$e($Ie());qt();var yA={};zt(yA,{checkManifestCompatibility:()=>e1e,extractBuildRequest:()=>IQ,getExtractHint:()=>nG,hasBindingGyp:()=>iG});Ye();Pt();function e1e(t){return W.isPackageCompatible(t,Vi.getArchitectureSet())}function IQ(t,e,r,{configuration:o}){let a=[];for(let n of[\"preinstall\",\"install\",\"postinstall\"])e.manifest.scripts.has(n)&&a.push({type:0,script:n});return!e.manifest.scripts.has(\"install\")&&e.misc.hasBindingGyp&&a.push({type:1,script:\"node-gyp rebuild\"}),a.length===0?null:t.linkType!==\"HARD\"?{skipped:!0,explain:n=>n.reportWarningOnce(6,`${W.prettyLocator(o,t)} lists build scripts, but is referenced through a soft link. Soft links don't support build scripts, so they'll be ignored.`)}:r&&r.built===!1?{skipped:!0,explain:n=>n.reportInfoOnce(5,`${W.prettyLocator(o,t)} lists build scripts, but its build has been explicitly disabled through configuration.`)}:!o.get(\"enableScripts\")&&!r.built?{skipped:!0,explain:n=>n.reportWarningOnce(4,`${W.prettyLocator(o,t)} lists build scripts, but all build scripts have been disabled.`)}:e1e(t)?{skipped:!1,directives:a}:{skipped:!0,explain:n=>n.reportWarningOnce(76,`${W.prettyLocator(o,t)} The ${Vi.getArchitectureName()} architecture is incompatible with this package, build skipped.`)}}var GIt=new Set([\".exe\",\".bin\",\".h\",\".hh\",\".hpp\",\".c\",\".cc\",\".cpp\",\".java\",\".jar\",\".node\"]);function nG(t){return t.packageFs.getExtractHint({relevantExtensions:GIt})}function iG(t){let e=z.join(t.prefixPath,\"binding.gyp\");return t.packageFs.existsSync(e)}var av={};zt(av,{getUnpluggedPath:()=>ov});Ye();Pt();function ov(t,{configuration:e}){return z.resolve(e.get(\"pnpUnpluggedFolder\"),W.slugifyLocator(t))}var jIt=new Set([W.makeIdent(null,\"open\").identHash,W.makeIdent(null,\"opn\").identHash]),b0=class{constructor(){this.mode=\"strict\";this.pnpCache=new Map}getCustomDataKey(){return JSON.stringify({name:\"PnpLinker\",version:2})}supportsPackage(e,r){return this.isEnabled(r)}async findPackageLocation(e,r){if(!this.isEnabled(r))throw new Error(\"Assertion failed: Expected the PnP linker to be enabled\");let o=x0(r.project).cjs;if(!oe.existsSync(o))throw new it(`The project in ${de.pretty(r.project.configuration,`${r.project.cwd}/package.json`,de.Type.PATH)} doesn't seem to have been installed - running an install there might help`);let a=_e.getFactoryWithDefault(this.pnpCache,o,()=>_e.dynamicRequire(o,{cachingStrategy:_e.CachingStrategy.FsTime})),n={name:W.stringifyIdent(e),reference:e.reference},u=a.getPackageInformation(n);if(!u)throw new it(`Couldn't find ${W.prettyLocator(r.project.configuration,e)} in the currently installed PnP map - running an install might help`);return le.toPortablePath(u.packageLocation)}async findPackageLocator(e,r){if(!this.isEnabled(r))return null;let o=x0(r.project).cjs;if(!oe.existsSync(o))return null;let n=_e.getFactoryWithDefault(this.pnpCache,o,()=>_e.dynamicRequire(o,{cachingStrategy:_e.CachingStrategy.FsTime})).findPackageLocator(le.fromPortablePath(e));return n?W.makeLocator(W.parseIdent(n.name),n.reference):null}makeInstaller(e){return new mm(e)}isEnabled(e){return!(e.project.configuration.get(\"nodeLinker\")!==\"pnp\"||e.project.configuration.get(\"pnpMode\")!==this.mode)}},mm=class{constructor(e){this.opts=e;this.mode=\"strict\";this.asyncActions=new _e.AsyncActions(10);this.packageRegistry=new Map;this.virtualTemplates=new Map;this.isESMLoaderRequired=!1;this.customData={store:new Map};this.unpluggedPaths=new Set;this.opts=e}attachCustomData(e){this.customData=e}async installPackage(e,r,o){let a=W.stringifyIdent(e),n=e.reference,u=!!this.opts.project.tryWorkspaceByLocator(e),A=W.isVirtualLocator(e),p=e.peerDependencies.size>0&&!A,h=!p&&!u,E=!p&&e.linkType!==\"SOFT\",I,v;if(h||E){let te=A?W.devirtualizeLocator(e):e;I=this.customData.store.get(te.locatorHash),typeof I>\"u\"&&(I=await YIt(r),e.linkType===\"HARD\"&&this.customData.store.set(te.locatorHash,I)),I.manifest.type===\"module\"&&(this.isESMLoaderRequired=!0),v=this.opts.project.getDependencyMeta(te,e.version)}let x=h?IQ(e,I,v,{configuration:this.opts.project.configuration}):null,C=E?await this.unplugPackageIfNeeded(e,I,r,v,o):r.packageFs;if(z.isAbsolute(r.prefixPath))throw new Error(`Assertion failed: Expected the prefix path (${r.prefixPath}) to be relative to the parent`);let R=z.resolve(C.getRealPath(),r.prefixPath),N=sG(this.opts.project.cwd,R),U=new Map,V=new Set;if(A){for(let te of e.peerDependencies.values())U.set(W.stringifyIdent(te),null),V.add(W.stringifyIdent(te));if(!u){let te=W.devirtualizeLocator(e);this.virtualTemplates.set(te.locatorHash,{location:sG(this.opts.project.cwd,mi.resolveVirtual(R)),locator:te})}}return _e.getMapWithDefault(this.packageRegistry,a).set(n,{packageLocation:N,packageDependencies:U,packagePeers:V,linkType:e.linkType,discardFromLookup:r.discardFromLookup||!1}),{packageLocation:R,buildRequest:x}}async attachInternalDependencies(e,r){let o=this.getPackageInformation(e);for(let[a,n]of r){let u=W.areIdentsEqual(a,n)?n.reference:[W.stringifyIdent(n),n.reference];o.packageDependencies.set(W.stringifyIdent(a),u)}}async attachExternalDependents(e,r){for(let o of r)this.getDiskInformation(o).packageDependencies.set(W.stringifyIdent(e),e.reference)}async finalizeInstall(){if(this.opts.project.configuration.get(\"pnpMode\")!==this.mode)return;let e=x0(this.opts.project);if(this.isEsmEnabled()||await oe.removePromise(e.esmLoader),this.opts.project.configuration.get(\"nodeLinker\")!==\"pnp\"){await oe.removePromise(e.cjs),await oe.removePromise(e.data),await oe.removePromise(e.esmLoader),await oe.removePromise(this.opts.project.configuration.get(\"pnpUnpluggedFolder\"));return}for(let{locator:E,location:I}of this.virtualTemplates.values())_e.getMapWithDefault(this.packageRegistry,W.stringifyIdent(E)).set(E.reference,{packageLocation:I,packageDependencies:new Map,packagePeers:new Set,linkType:\"SOFT\",discardFromLookup:!1});this.packageRegistry.set(null,new Map([[null,this.getPackageInformation(this.opts.project.topLevelWorkspace.anchoredLocator)]]));let r=this.opts.project.configuration.get(\"pnpFallbackMode\"),o=this.opts.project.workspaces.map(({anchoredLocator:E})=>({name:W.stringifyIdent(E),reference:E.reference})),a=r!==\"none\",n=[],u=new Map,A=_e.buildIgnorePattern([\".yarn/sdks/**\",...this.opts.project.configuration.get(\"pnpIgnorePatterns\")]),p=this.packageRegistry,h=this.opts.project.configuration.get(\"pnpShebang\");if(r===\"dependencies-only\")for(let E of this.opts.project.storedPackages.values())this.opts.project.tryWorkspaceByLocator(E)&&n.push({name:W.stringifyIdent(E),reference:E.reference});return await this.asyncActions.wait(),await this.finalizeInstallWithPnp({dependencyTreeRoots:o,enableTopLevelFallback:a,fallbackExclusionList:n,fallbackPool:u,ignorePattern:A,packageRegistry:p,shebang:h}),{customData:this.customData}}async transformPnpSettings(e){}isEsmEnabled(){if(this.opts.project.configuration.sources.has(\"pnpEnableEsmLoader\"))return this.opts.project.configuration.get(\"pnpEnableEsmLoader\");if(this.isESMLoaderRequired)return!0;for(let e of this.opts.project.workspaces)if(e.manifest.type===\"module\")return!0;return!1}async finalizeInstallWithPnp(e){let r=x0(this.opts.project),o=await this.locateNodeModules(e.ignorePattern);if(o.length>0){this.opts.report.reportWarning(31,\"One or more node_modules have been detected and will be removed. This operation may take some time.\");for(let n of o)await oe.removePromise(n)}if(await this.transformPnpSettings(e),this.opts.project.configuration.get(\"pnpEnableInlining\")){let n=SIe(e);await oe.changeFilePromise(r.cjs,n,{automaticNewlines:!0,mode:493}),await oe.removePromise(r.data)}else{let{dataFile:n,loaderFile:u}=bIe(e);await oe.changeFilePromise(r.cjs,u,{automaticNewlines:!0,mode:493}),await oe.changeFilePromise(r.data,n,{automaticNewlines:!0,mode:420})}this.isEsmEnabled()&&(this.opts.report.reportWarning(0,\"ESM support for PnP uses the experimental loader API and is therefore experimental\"),await oe.changeFilePromise(r.esmLoader,(0,rG.default)(),{automaticNewlines:!0,mode:420}));let a=this.opts.project.configuration.get(\"pnpUnpluggedFolder\");if(this.unpluggedPaths.size===0)await oe.removePromise(a);else for(let n of await oe.readdirPromise(a)){let u=z.resolve(a,n);this.unpluggedPaths.has(u)||await oe.removePromise(u)}}async locateNodeModules(e){let r=[],o=e?new RegExp(e):null;for(let a of this.opts.project.workspaces){let n=z.join(a.cwd,\"node_modules\");if(o&&o.test(z.relative(this.opts.project.cwd,a.cwd))||!oe.existsSync(n))continue;let u=await oe.readdirPromise(n,{withFileTypes:!0}),A=u.filter(p=>!p.isDirectory()||p.name===\".bin\"||!p.name.startsWith(\".\"));if(A.length===u.length)r.push(n);else for(let p of A)r.push(z.join(n,p.name))}return r}async unplugPackageIfNeeded(e,r,o,a,n){return this.shouldBeUnplugged(e,r,a)?this.unplugPackage(e,o,n):o.packageFs}shouldBeUnplugged(e,r,o){return typeof o.unplugged<\"u\"?o.unplugged:jIt.has(e.identHash)||e.conditions!=null?!0:r.manifest.preferUnplugged!==null?r.manifest.preferUnplugged:!!(IQ(e,r,o,{configuration:this.opts.project.configuration})?.skipped===!1||r.misc.extractHint)}async unplugPackage(e,r,o){let a=ov(e,{configuration:this.opts.project.configuration});return this.opts.project.disabledLocators.has(e.locatorHash)?new _u(a,{baseFs:r.packageFs,pathUtils:z}):(this.unpluggedPaths.add(a),o.holdFetchResult(this.asyncActions.set(e.locatorHash,async()=>{let n=z.join(a,r.prefixPath,\".ready\");await oe.existsPromise(n)||(this.opts.project.storedBuildState.delete(e.locatorHash),await oe.mkdirPromise(a,{recursive:!0}),await oe.copyPromise(a,Bt.dot,{baseFs:r.packageFs,overwrite:!1}),await oe.writeFilePromise(n,\"\"))})),new gn(a))}getPackageInformation(e){let r=W.stringifyIdent(e),o=e.reference,a=this.packageRegistry.get(r);if(!a)throw new Error(`Assertion failed: The package information store should have been available (for ${W.prettyIdent(this.opts.project.configuration,e)})`);let n=a.get(o);if(!n)throw new Error(`Assertion failed: The package information should have been available (for ${W.prettyLocator(this.opts.project.configuration,e)})`);return n}getDiskInformation(e){let r=_e.getMapWithDefault(this.packageRegistry,\"@@disk\"),o=sG(this.opts.project.cwd,e);return _e.getFactoryWithDefault(r,o,()=>({packageLocation:o,packageDependencies:new Map,packagePeers:new Set,linkType:\"SOFT\",discardFromLookup:!1}))}};function sG(t,e){let r=z.relative(t,e);return r.match(/^\\.{0,2}\\//)||(r=`./${r}`),r.replace(/\\/?$/,\"/\")}async function YIt(t){let e=await Ot.tryFind(t.prefixPath,{baseFs:t.packageFs})??new Ot,r=new Set([\"preinstall\",\"install\",\"postinstall\"]);for(let o of e.scripts.keys())r.has(o)||e.scripts.delete(o);return{manifest:{scripts:e.scripts,preferUnplugged:e.preferUnplugged,type:e.type},misc:{extractHint:nG(t),hasBindingGyp:iG(t)}}}Ye();Ye();qt();var t1e=$e(Zo());var k0=class extends ut{constructor(){super(...arguments);this.all=ge.Boolean(\"-A,--all\",!1,{description:\"Unplug direct dependencies from the entire project\"});this.recursive=ge.Boolean(\"-R,--recursive\",!1,{description:\"Unplug both direct and transitive dependencies\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.patterns=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Nr.find(r);if(!a)throw new nr(o.cwd,this.context.cwd);if(r.get(\"nodeLinker\")!==\"pnp\")throw new it(\"This command can only be used if the `nodeLinker` option is set to `pnp`\");await o.restoreInstallState();let u=new Set(this.patterns),A=this.patterns.map(x=>{let C=W.parseDescriptor(x),R=C.range!==\"unknown\"?C:W.makeDescriptor(C,\"*\");if(!kr.validRange(R.range))throw new it(`The range of the descriptor patterns must be a valid semver range (${W.prettyDescriptor(r,R)})`);return N=>{let U=W.stringifyIdent(N);return!t1e.default.isMatch(U,W.stringifyIdent(R))||N.version&&!kr.satisfiesWithPrereleases(N.version,R.range)?!1:(u.delete(x),!0)}}),p=()=>{let x=[];for(let C of o.storedPackages.values())!o.tryWorkspaceByLocator(C)&&!W.isVirtualLocator(C)&&A.some(R=>R(C))&&x.push(C);return x},h=x=>{let C=new Set,R=[],N=(U,V)=>{if(C.has(U.locatorHash))return;let te=!!o.tryWorkspaceByLocator(U);if(!(V>0&&!this.recursive&&te)&&(C.add(U.locatorHash),!o.tryWorkspaceByLocator(U)&&A.some(ae=>ae(U))&&R.push(U),!(V>0&&!this.recursive)))for(let ae of U.dependencies.values()){let fe=o.storedResolutions.get(ae.descriptorHash);if(!fe)throw new Error(\"Assertion failed: The resolution should have been registered\");let ue=o.storedPackages.get(fe);if(!ue)throw new Error(\"Assertion failed: The package should have been registered\");N(ue,V+1)}};for(let U of x)N(U.anchoredPackage,0);return R},E,I;if(this.all&&this.recursive?(E=p(),I=\"the project\"):this.all?(E=h(o.workspaces),I=\"any workspace\"):(E=h([a]),I=\"this workspace\"),u.size>1)throw new it(`Patterns ${de.prettyList(r,u,de.Type.CODE)} don't match any packages referenced by ${I}`);if(u.size>0)throw new it(`Pattern ${de.prettyList(r,u,de.Type.CODE)} doesn't match any packages referenced by ${I}`);E=_e.sortMap(E,x=>W.stringifyLocator(x));let v=await Lt.start({configuration:r,stdout:this.context.stdout,json:this.json},async x=>{for(let C of E){let R=C.version??\"unknown\",N=o.topLevelWorkspace.manifest.ensureDependencyMeta(W.makeDescriptor(C,R));N.unplugged=!0,x.reportInfo(0,`Will unpack ${W.prettyLocator(r,C)} to ${de.pretty(r,ov(C,{configuration:r}),de.Type.PATH)}`),x.reportJson({locator:W.stringifyLocator(C),version:R})}await o.topLevelWorkspace.persistManifest(),this.json||x.reportSeparator()});return v.hasErrors()?v.exitCode():await o.installWithNewReport({json:this.json,stdout:this.context.stdout},{cache:n})}};k0.paths=[[\"unplug\"]],k0.usage=nt.Usage({description:\"force the unpacking of a list of packages\",details:\"\\n      This command will add the selectors matching the specified patterns to the list of packages that must be unplugged when installed.\\n\\n      A package being unplugged means that instead of being referenced directly through its archive, it will be unpacked at install time in the directory configured via `pnpUnpluggedFolder`. Note that unpacking packages this way is generally not recommended because it'll make it harder to store your packages within the repository. However, it's a good approach to quickly and safely debug some packages, and can even sometimes be required depending on the context (for example when the package contains shellscripts).\\n\\n      Running the command will set a persistent flag inside your top-level `package.json`, in the `dependenciesMeta` field. As such, to undo its effects, you'll need to revert the changes made to the manifest and run `yarn install` to apply the modification.\\n\\n      By default, only direct dependencies from the current workspace are affected. If `-A,--all` is set, direct dependencies from the entire project are affected. Using the `-R,--recursive` flag will affect transitive dependencies as well as direct ones.\\n\\n      This command accepts glob patterns inside the scope and name components (not the range). Make sure to escape the patterns to prevent your own shell from trying to expand them.\\n    \",examples:[[\"Unplug the lodash dependency from the active workspace\",\"yarn unplug lodash\"],[\"Unplug all instances of lodash referenced by any workspace\",\"yarn unplug lodash -A\"],[\"Unplug all instances of lodash referenced by the active workspace and its dependencies\",\"yarn unplug lodash -R\"],[\"Unplug all instances of lodash, anywhere\",\"yarn unplug lodash -AR\"],[\"Unplug one specific version of lodash\",\"yarn unplug lodash@1.2.3\"],[\"Unplug all packages with the `@babel` scope\",\"yarn unplug '@babel/*'\"],[\"Unplug all packages (only for testing, not recommended)\",\"yarn unplug -R '*'\"]]});var x0=t=>({cjs:z.join(t.cwd,dr.pnpCjs),data:z.join(t.cwd,dr.pnpData),esmLoader:z.join(t.cwd,dr.pnpEsmLoader)}),n1e=t=>/\\s/.test(t)?JSON.stringify(t):t;async function WIt(t,e,r){let o=/\\s*--require\\s+\\S*\\.pnp\\.c?js\\s*/g,a=/\\s*--experimental-loader\\s+\\S*\\.pnp\\.loader\\.mjs\\s*/,n=(e.NODE_OPTIONS??\"\").replace(o,\" \").replace(a,\" \").trim();if(t.configuration.get(\"nodeLinker\")!==\"pnp\"){e.NODE_OPTIONS=n||void 0;return}let u=x0(t),A=`--require ${n1e(le.fromPortablePath(u.cjs))}`;oe.existsSync(u.esmLoader)&&(A=`${A} --experimental-loader ${(0,r1e.pathToFileURL)(le.fromPortablePath(u.esmLoader)).href}`),oe.existsSync(u.cjs)&&(e.NODE_OPTIONS=n?`${A} ${n}`:A)}async function KIt(t,e){let r=x0(t);e(r.cjs),e(r.data),e(r.esmLoader),e(t.configuration.get(\"pnpUnpluggedFolder\"))}var zIt={hooks:{populateYarnPaths:KIt,setupScriptEnvironment:WIt},configuration:{nodeLinker:{description:'The linker used for installing Node packages, one of: \"pnp\", \"pnpm\", or \"node-modules\"',type:\"STRING\",default:\"pnp\"},winLinkType:{description:\"Whether Yarn should use Windows Junctions or symlinks when creating links on Windows.\",type:\"STRING\",values:[\"junctions\",\"symlinks\"],default:\"junctions\"},pnpMode:{description:\"If 'strict', generates standard PnP maps. If 'loose', merges them with the n_m resolution.\",type:\"STRING\",default:\"strict\"},pnpShebang:{description:\"String to prepend to the generated PnP script\",type:\"STRING\",default:\"#!/usr/bin/env node\"},pnpIgnorePatterns:{description:\"Array of glob patterns; files matching them will use the classic resolution\",type:\"STRING\",default:[],isArray:!0},pnpEnableEsmLoader:{description:\"If true, Yarn will generate an ESM loader (`.pnp.loader.mjs`). If this is not explicitly set Yarn tries to automatically detect whether ESM support is required.\",type:\"BOOLEAN\",default:!1},pnpEnableInlining:{description:\"If true, the PnP data will be inlined along with the generated loader\",type:\"BOOLEAN\",default:!0},pnpFallbackMode:{description:\"If true, the generated PnP loader will follow the top-level fallback rule\",type:\"STRING\",default:\"dependencies-only\"},pnpUnpluggedFolder:{description:\"Folder where the unplugged packages must be stored\",type:\"ABSOLUTE_PATH\",default:\"./.yarn/unplugged\"}},linkers:[b0],commands:[k0]},VIt=zIt;var A1e=$e(l1e());qt();var pG=$e(ve(\"crypto\")),f1e=$e(ve(\"fs\")),p1e=1,Pi=\"node_modules\",BQ=\".bin\",h1e=\".yarn-state.yml\",f1t=1e3,hG=(o=>(o.CLASSIC=\"classic\",o.HARDLINKS_LOCAL=\"hardlinks-local\",o.HARDLINKS_GLOBAL=\"hardlinks-global\",o))(hG||{}),lv=class{constructor(){this.installStateCache=new Map}getCustomDataKey(){return JSON.stringify({name:\"NodeModulesLinker\",version:3})}supportsPackage(e,r){return this.isEnabled(r)}async findPackageLocation(e,r){if(!this.isEnabled(r))throw new Error(\"Assertion failed: Expected the node-modules linker to be enabled\");let o=r.project.tryWorkspaceByLocator(e);if(o)return o.cwd;let a=await _e.getFactoryWithDefault(this.installStateCache,r.project.cwd,async()=>await fG(r.project,{unrollAliases:!0}));if(a===null)throw new it(\"Couldn't find the node_modules state file - running an install might help (findPackageLocation)\");let n=a.locatorMap.get(W.stringifyLocator(e));if(!n){let p=new it(`Couldn't find ${W.prettyLocator(r.project.configuration,e)} in the currently installed node_modules map - running an install might help`);throw p.code=\"LOCATOR_NOT_INSTALLED\",p}let u=n.locations.sort((p,h)=>p.split(z.sep).length-h.split(z.sep).length),A=z.join(r.project.configuration.startingCwd,Pi);return u.find(p=>z.contains(A,p))||n.locations[0]}async findPackageLocator(e,r){if(!this.isEnabled(r))return null;let o=await _e.getFactoryWithDefault(this.installStateCache,r.project.cwd,async()=>await fG(r.project,{unrollAliases:!0}));if(o===null)return null;let{locationRoot:a,segments:n}=vQ(z.resolve(e),{skipPrefix:r.project.cwd}),u=o.locationTree.get(a);if(!u)return null;let A=u.locator;for(let p of n){if(u=u.children.get(p),!u)break;A=u.locator||A}return W.parseLocator(A)}makeInstaller(e){return new AG(e)}isEnabled(e){return e.project.configuration.get(\"nodeLinker\")===\"node-modules\"}},AG=class{constructor(e){this.opts=e;this.localStore=new Map;this.realLocatorChecksums=new Map;this.customData={store:new Map}}attachCustomData(e){this.customData=e}async installPackage(e,r){let o=z.resolve(r.packageFs.getRealPath(),r.prefixPath),a=this.customData.store.get(e.locatorHash);if(typeof a>\"u\"&&(a=await p1t(e,r),e.linkType===\"HARD\"&&this.customData.store.set(e.locatorHash,a)),!W.isPackageCompatible(e,this.opts.project.configuration.getSupportedArchitectures()))return{packageLocation:null,buildRequest:null};let n=new Map,u=new Set;n.has(W.stringifyIdent(e))||n.set(W.stringifyIdent(e),e.reference);let A=e;if(W.isVirtualLocator(e)){A=W.devirtualizeLocator(e);for(let E of e.peerDependencies.values())n.set(W.stringifyIdent(E),null),u.add(W.stringifyIdent(E))}let p={packageLocation:`${le.fromPortablePath(o)}/`,packageDependencies:n,packagePeers:u,linkType:e.linkType,discardFromLookup:r.discardFromLookup??!1};this.localStore.set(e.locatorHash,{pkg:e,customPackageData:a,dependencyMeta:this.opts.project.getDependencyMeta(e,e.version),pnpNode:p});let h=r.checksum?r.checksum.substring(r.checksum.indexOf(\"/\")+1):null;return this.realLocatorChecksums.set(A.locatorHash,h),{packageLocation:o,buildRequest:null}}async attachInternalDependencies(e,r){let o=this.localStore.get(e.locatorHash);if(typeof o>\"u\")throw new Error(\"Assertion failed: Expected information object to have been registered\");for(let[a,n]of r){let u=W.areIdentsEqual(a,n)?n.reference:[W.stringifyIdent(n),n.reference];o.pnpNode.packageDependencies.set(W.stringifyIdent(a),u)}}async attachExternalDependents(e,r){throw new Error(\"External dependencies haven't been implemented for the node-modules linker\")}async finalizeInstall(){if(this.opts.project.configuration.get(\"nodeLinker\")!==\"node-modules\")return;let e=new mi({baseFs:new Jl({maxOpenFiles:80,readOnlyArchives:!0})}),r=await fG(this.opts.project),o=this.opts.project.configuration.get(\"nmMode\");(r===null||o!==r.nmMode)&&(this.opts.project.storedBuildState.clear(),r={locatorMap:new Map,binSymlinks:new Map,locationTree:new Map,nmMode:o,mtimeMs:0});let a=new Map(this.opts.project.workspaces.map(v=>{let x=this.opts.project.configuration.get(\"nmHoistingLimits\");try{x=_e.validateEnum(VB,v.manifest.installConfig?.hoistingLimits??x)}catch{let R=W.prettyWorkspace(this.opts.project.configuration,v);this.opts.report.reportWarning(57,`${R}: Invalid 'installConfig.hoistingLimits' value. Expected one of ${Object.values(VB).join(\", \")}, using default: \"${x}\"`)}return[v.relativeCwd,x]})),n=new Map(this.opts.project.workspaces.map(v=>{let x=this.opts.project.configuration.get(\"nmSelfReferences\");return x=v.manifest.installConfig?.selfReferences??x,[v.relativeCwd,x]})),u={VERSIONS:{std:1},topLevel:{name:null,reference:null},getLocator:(v,x)=>Array.isArray(x)?{name:x[0],reference:x[1]}:{name:v,reference:x},getDependencyTreeRoots:()=>this.opts.project.workspaces.map(v=>{let x=v.anchoredLocator;return{name:W.stringifyIdent(x),reference:x.reference}}),getPackageInformation:v=>{let x=v.reference===null?this.opts.project.topLevelWorkspace.anchoredLocator:W.makeLocator(W.parseIdent(v.name),v.reference),C=this.localStore.get(x.locatorHash);if(typeof C>\"u\")throw new Error(\"Assertion failed: Expected the package reference to have been registered\");return C.pnpNode},findPackageLocator:v=>{let x=this.opts.project.tryWorkspaceByCwd(le.toPortablePath(v));if(x!==null){let C=x.anchoredLocator;return{name:W.stringifyIdent(C),reference:C.reference}}throw new Error(\"Assertion failed: Unimplemented\")},resolveToUnqualified:()=>{throw new Error(\"Assertion failed: Unimplemented\")},resolveUnqualified:()=>{throw new Error(\"Assertion failed: Unimplemented\")},resolveRequest:()=>{throw new Error(\"Assertion failed: Unimplemented\")},resolveVirtual:v=>le.fromPortablePath(mi.resolveVirtual(le.toPortablePath(v)))},{tree:A,errors:p,preserveSymlinksRequired:h}=JB(u,{pnpifyFs:!1,validateExternalSoftLinks:!0,hoistingLimitsByCwd:a,project:this.opts.project,selfReferencesByCwd:n});if(!A){for(let{messageName:v,text:x}of p)this.opts.report.reportError(v,x);return}let E=Hq(A);await E1t(r,E,{baseFs:e,project:this.opts.project,report:this.opts.report,realLocatorChecksums:this.realLocatorChecksums,loadManifest:async v=>{let x=W.parseLocator(v),C=this.localStore.get(x.locatorHash);if(typeof C>\"u\")throw new Error(\"Assertion failed: Expected the slot to exist\");return C.customPackageData.manifest}});let I=[];for(let[v,x]of E.entries()){if(y1e(v))continue;let C=W.parseLocator(v),R=this.localStore.get(C.locatorHash);if(typeof R>\"u\")throw new Error(\"Assertion failed: Expected the slot to exist\");if(this.opts.project.tryWorkspaceByLocator(R.pkg))continue;let N=yA.extractBuildRequest(R.pkg,R.customPackageData,R.dependencyMeta,{configuration:this.opts.project.configuration});!N||I.push({buildLocations:x.locations,locator:C,buildRequest:N})}return h&&this.opts.report.reportWarning(72,`The application uses portals and that's why ${de.pretty(this.opts.project.configuration,\"--preserve-symlinks\",de.Type.CODE)} Node option is required for launching it`),{customData:this.customData,records:I}}};async function p1t(t,e){let r=await Ot.tryFind(e.prefixPath,{baseFs:e.packageFs})??new Ot,o=new Set([\"preinstall\",\"install\",\"postinstall\"]);for(let a of r.scripts.keys())o.has(a)||r.scripts.delete(a);return{manifest:{bin:r.bin,scripts:r.scripts},misc:{hasBindingGyp:yA.hasBindingGyp(e)}}}async function h1t(t,e,r,o,{installChangedByUser:a}){let n=\"\";n+=`# Warning: This file is automatically generated. Removing it is fine, but will\n`,n+=`# cause your node_modules installation to become invalidated.\n`,n+=`\n`,n+=`__metadata:\n`,n+=`  version: ${p1e}\n`,n+=`  nmMode: ${o.value}\n`;let u=Array.from(e.keys()).sort(),A=W.stringifyLocator(t.topLevelWorkspace.anchoredLocator);for(let E of u){let I=e.get(E);n+=`\n`,n+=`${JSON.stringify(E)}:\n`,n+=`  locations:\n`;for(let v of I.locations){let x=z.contains(t.cwd,v);if(x===null)throw new Error(`Assertion failed: Expected the path to be within the project (${v})`);n+=`    - ${JSON.stringify(x)}\n`}if(I.aliases.length>0){n+=`  aliases:\n`;for(let v of I.aliases)n+=`    - ${JSON.stringify(v)}\n`}if(E===A&&r.size>0){n+=`  bin:\n`;for(let[v,x]of r){let C=z.contains(t.cwd,v);if(C===null)throw new Error(`Assertion failed: Expected the path to be within the project (${v})`);n+=`    ${JSON.stringify(C)}:\n`;for(let[R,N]of x){let U=z.relative(z.join(v,Pi),N);n+=`      ${JSON.stringify(R)}: ${JSON.stringify(U)}\n`}}}}let p=t.cwd,h=z.join(p,Pi,h1e);a&&await oe.removePromise(h),await oe.changeFilePromise(h,n,{automaticNewlines:!0})}async function fG(t,{unrollAliases:e=!1}={}){let r=t.cwd,o=z.join(r,Pi,h1e),a;try{a=await oe.statPromise(o)}catch{}if(!a)return null;let n=Ki(await oe.readFilePromise(o,\"utf8\"));if(n.__metadata.version>p1e)return null;let u=n.__metadata.nmMode||\"classic\",A=new Map,p=new Map;delete n.__metadata;for(let[h,E]of Object.entries(n)){let I=E.locations.map(x=>z.join(r,x)),v=E.bin;if(v)for(let[x,C]of Object.entries(v)){let R=z.join(r,le.toPortablePath(x)),N=_e.getMapWithDefault(p,R);for(let[U,V]of Object.entries(C))N.set(U,le.toPortablePath([R,Pi,V].join(z.sep)))}if(A.set(h,{target:Bt.dot,linkType:\"HARD\",locations:I,aliases:E.aliases||[]}),e&&E.aliases)for(let x of E.aliases){let{scope:C,name:R}=W.parseLocator(h),N=W.makeLocator(W.makeIdent(C,R),x),U=W.stringifyLocator(N);A.set(U,{target:Bt.dot,linkType:\"HARD\",locations:I,aliases:[]})}}return{locatorMap:A,binSymlinks:p,locationTree:g1e(A,{skipPrefix:t.cwd}),nmMode:u,mtimeMs:a.mtimeMs}}var WC=async(t,e)=>{if(t.split(z.sep).indexOf(Pi)<0)throw new Error(`Assertion failed: trying to remove dir that doesn't contain node_modules: ${t}`);try{if(!e.innerLoop){let o=e.allowSymlink?await oe.statPromise(t):await oe.lstatPromise(t);if(e.allowSymlink&&!o.isDirectory()||!e.allowSymlink&&o.isSymbolicLink()){await oe.unlinkPromise(t);return}}let r=await oe.readdirPromise(t,{withFileTypes:!0});for(let o of r){let a=z.join(t,o.name);o.isDirectory()?(o.name!==Pi||e&&e.innerLoop)&&await WC(a,{innerLoop:!0,contentsOnly:!1}):await oe.unlinkPromise(a)}e.contentsOnly||await oe.rmdirPromise(t)}catch(r){if(r.code!==\"ENOENT\"&&r.code!==\"ENOTEMPTY\")throw r}},c1e=4,vQ=(t,{skipPrefix:e})=>{let r=z.contains(e,t);if(r===null)throw new Error(`Assertion failed: Writing attempt prevented to ${t} which is outside project root: ${e}`);let o=r.split(z.sep).filter(p=>p!==\"\"),a=o.indexOf(Pi),n=o.slice(0,a).join(z.sep),u=z.join(e,n),A=o.slice(a);return{locationRoot:u,segments:A}},g1e=(t,{skipPrefix:e})=>{let r=new Map;if(t===null)return r;let o=()=>({children:new Map,linkType:\"HARD\"});for(let[a,n]of t.entries()){if(n.linkType===\"SOFT\"&&z.contains(e,n.target)!==null){let A=_e.getFactoryWithDefault(r,n.target,o);A.locator=a,A.linkType=n.linkType}for(let u of n.locations){let{locationRoot:A,segments:p}=vQ(u,{skipPrefix:e}),h=_e.getFactoryWithDefault(r,A,o);for(let E=0;E<p.length;++E){let I=p[E];if(I!==\".\"){let v=_e.getFactoryWithDefault(h.children,I,o);h.children.set(I,v),h=v}E===p.length-1&&(h.locator=a,h.linkType=n.linkType)}}}return r},gG=async(t,e,r)=>{if(process.platform===\"win32\"&&r===\"junctions\"){let o;try{o=await oe.lstatPromise(t)}catch{}if(!o||o.isDirectory()){await oe.symlinkPromise(t,e,\"junction\");return}}await oe.symlinkPromise(z.relative(z.dirname(e),t),e)};async function d1e(t,e,r){let o=z.join(t,`${pG.default.randomBytes(16).toString(\"hex\")}.tmp`);try{await oe.writeFilePromise(o,r);try{await oe.linkPromise(o,e)}catch{}}finally{await oe.unlinkPromise(o)}}async function g1t({srcPath:t,dstPath:e,entry:r,globalHardlinksStore:o,baseFs:a,nmMode:n}){if(r.kind===m1e.FILE){if(n.value===\"hardlinks-global\"&&o&&r.digest){let A=z.join(o,r.digest.substring(0,2),`${r.digest.substring(2)}.dat`),p;try{let h=await oe.statPromise(A);if(h&&(!r.mtimeMs||h.mtimeMs>r.mtimeMs||h.mtimeMs<r.mtimeMs-f1t))if(await wn.checksumFile(A,{baseFs:oe,algorithm:\"sha1\"})!==r.digest){let I=z.join(o,`${pG.default.randomBytes(16).toString(\"hex\")}.tmp`);await oe.renamePromise(A,I);let v=await a.readFilePromise(t);await oe.writeFilePromise(I,v);try{await oe.linkPromise(I,A),r.mtimeMs=new Date().getTime(),await oe.unlinkPromise(I)}catch{}}else r.mtimeMs||(r.mtimeMs=Math.ceil(h.mtimeMs));await oe.linkPromise(A,e),p=!0}catch{p=!1}if(!p){let h=await a.readFilePromise(t);await d1e(o,A,h),r.mtimeMs=new Date().getTime();try{await oe.linkPromise(A,e)}catch(E){E&&E.code&&E.code==\"EXDEV\"&&(n.value=\"hardlinks-local\",await a.copyFilePromise(t,e))}}}else await a.copyFilePromise(t,e);let u=r.mode&511;u!==420&&await oe.chmodPromise(e,u)}}var m1e=(o=>(o.FILE=\"file\",o.DIRECTORY=\"directory\",o.SYMLINK=\"symlink\",o))(m1e||{}),d1t=async(t,e,{baseFs:r,globalHardlinksStore:o,nmMode:a,windowsLinkType:n,packageChecksum:u})=>{await oe.mkdirPromise(t,{recursive:!0});let A=async(E=Bt.dot)=>{let I=z.join(e,E),v=await r.readdirPromise(I,{withFileTypes:!0}),x=new Map;for(let C of v){let R=z.join(E,C.name),N,U=z.join(I,C.name);if(C.isFile()){if(N={kind:\"file\",mode:(await r.lstatPromise(U)).mode},a.value===\"hardlinks-global\"){let V=await wn.checksumFile(U,{baseFs:r,algorithm:\"sha1\"});N.digest=V}}else if(C.isDirectory())N={kind:\"directory\"};else if(C.isSymbolicLink())N={kind:\"symlink\",symlinkTo:await r.readlinkPromise(U)};else throw new Error(`Unsupported file type (file: ${U}, mode: 0o${await r.statSync(U).mode.toString(8).padStart(6,\"0\")})`);if(x.set(R,N),C.isDirectory()&&R!==Pi){let V=await A(R);for(let[te,ae]of V)x.set(te,ae)}}return x},p;if(a.value===\"hardlinks-global\"&&o&&u){let E=z.join(o,u.substring(0,2),`${u.substring(2)}.json`);try{p=new Map(Object.entries(JSON.parse(await oe.readFilePromise(E,\"utf8\"))))}catch{p=await A()}}else p=await A();let h=!1;for(let[E,I]of p){let v=z.join(e,E),x=z.join(t,E);if(I.kind===\"directory\")await oe.mkdirPromise(x,{recursive:!0});else if(I.kind===\"file\"){let C=I.mtimeMs;await g1t({srcPath:v,dstPath:x,entry:I,nmMode:a,baseFs:r,globalHardlinksStore:o}),I.mtimeMs!==C&&(h=!0)}else I.kind===\"symlink\"&&await gG(z.resolve(z.dirname(x),I.symlinkTo),x,n)}if(a.value===\"hardlinks-global\"&&o&&h&&u){let E=z.join(o,u.substring(0,2),`${u.substring(2)}.json`);await oe.removePromise(E),await d1e(o,E,Buffer.from(JSON.stringify(Object.fromEntries(p))))}};function m1t(t,e,r,o){let a=new Map,n=new Map,u=new Map,A=!1,p=(h,E,I,v,x)=>{let C=!0,R=z.join(h,E),N=new Set;if(E===Pi||E.startsWith(\"@\")){let V;try{V=oe.statSync(R)}catch{}C=!!V,V?V.mtimeMs>r?(A=!0,N=new Set(oe.readdirSync(R))):N=new Set(I.children.get(E).children.keys()):A=!0;let te=e.get(h);if(te){let ae=z.join(h,Pi,BQ),fe;try{fe=oe.statSync(ae)}catch{}if(!fe)A=!0;else if(fe.mtimeMs>r){A=!0;let ue=new Set(oe.readdirSync(ae)),me=new Map;n.set(h,me);for(let[he,Be]of te)ue.has(he)&&me.set(he,Be)}else n.set(h,te)}}else C=x.has(E);let U=I.children.get(E);if(C){let{linkType:V,locator:te}=U,ae={children:new Map,linkType:V,locator:te};if(v.children.set(E,ae),te){let fe=_e.getSetWithDefault(u,te);fe.add(R),u.set(te,fe)}for(let fe of U.children.keys())p(R,fe,U,ae,N)}else U.locator&&o.storedBuildState.delete(W.parseLocator(U.locator).locatorHash)};for(let[h,E]of t){let{linkType:I,locator:v}=E,x={children:new Map,linkType:I,locator:v};if(a.set(h,x),v){let C=_e.getSetWithDefault(u,E.locator);C.add(h),u.set(E.locator,C)}E.children.has(Pi)&&p(h,Pi,E,x,new Set)}return{locationTree:a,binSymlinks:n,locatorLocations:u,installChangedByUser:A}}function y1e(t){let e=W.parseDescriptor(t);return W.isVirtualDescriptor(e)&&(e=W.devirtualizeDescriptor(e)),e.range.startsWith(\"link:\")}async function y1t(t,e,r,{loadManifest:o}){let a=new Map;for(let[A,{locations:p}]of t){let h=y1e(A)?null:await o(A,p[0]),E=new Map;if(h)for(let[I,v]of h.bin){let x=z.join(p[0],v);v!==\"\"&&oe.existsSync(x)&&E.set(I,v)}a.set(A,E)}let n=new Map,u=(A,p,h)=>{let E=new Map,I=z.contains(r,A);if(h.locator&&I!==null){let v=a.get(h.locator);for(let[x,C]of v){let R=z.join(A,le.toPortablePath(C));E.set(x,R)}for(let[x,C]of h.children){let R=z.join(A,x),N=u(R,R,C);N.size>0&&n.set(A,new Map([...n.get(A)||new Map,...N]))}}else for(let[v,x]of h.children){let C=u(z.join(A,v),p,x);for(let[R,N]of C)E.set(R,N)}return E};for(let[A,p]of e){let h=u(A,A,p);h.size>0&&n.set(A,new Map([...n.get(A)||new Map,...h]))}return n}var u1e=(t,e)=>{if(!t||!e)return t===e;let r=W.parseLocator(t);W.isVirtualLocator(r)&&(r=W.devirtualizeLocator(r));let o=W.parseLocator(e);return W.isVirtualLocator(o)&&(o=W.devirtualizeLocator(o)),W.areLocatorsEqual(r,o)};function dG(t){return z.join(t.get(\"globalFolder\"),\"store\")}async function E1t(t,e,{baseFs:r,project:o,report:a,loadManifest:n,realLocatorChecksums:u}){let A=z.join(o.cwd,Pi),{locationTree:p,binSymlinks:h,locatorLocations:E,installChangedByUser:I}=m1t(t.locationTree,t.binSymlinks,t.mtimeMs,o),v=g1e(e,{skipPrefix:o.cwd}),x=[],C=async({srcDir:Be,dstDir:we,linkType:g,globalHardlinksStore:Ee,nmMode:Pe,windowsLinkType:ce,packageChecksum:ne})=>{let ee=(async()=>{try{g===\"SOFT\"?(await oe.mkdirPromise(z.dirname(we),{recursive:!0}),await gG(z.resolve(Be),we,ce)):await d1t(we,Be,{baseFs:r,globalHardlinksStore:Ee,nmMode:Pe,windowsLinkType:ce,packageChecksum:ne})}catch(Ie){throw Ie.message=`While persisting ${Be} -> ${we} ${Ie.message}`,Ie}finally{ae.tick()}})().then(()=>x.splice(x.indexOf(ee),1));x.push(ee),x.length>c1e&&await Promise.race(x)},R=async(Be,we,g)=>{let Ee=(async()=>{let Pe=async(ce,ne,ee)=>{try{ee.innerLoop||await oe.mkdirPromise(ne,{recursive:!0});let Ie=await oe.readdirPromise(ce,{withFileTypes:!0});for(let Fe of Ie){if(!ee.innerLoop&&Fe.name===BQ)continue;let At=z.join(ce,Fe.name),H=z.join(ne,Fe.name);Fe.isDirectory()?(Fe.name!==Pi||ee&&ee.innerLoop)&&(await oe.mkdirPromise(H,{recursive:!0}),await Pe(At,H,{...ee,innerLoop:!0})):me.value===\"hardlinks-local\"||me.value===\"hardlinks-global\"?await oe.linkPromise(At,H):await oe.copyFilePromise(At,H,f1e.default.constants.COPYFILE_FICLONE)}}catch(Ie){throw ee.innerLoop||(Ie.message=`While cloning ${ce} -> ${ne} ${Ie.message}`),Ie}finally{ee.innerLoop||ae.tick()}};await Pe(Be,we,g)})().then(()=>x.splice(x.indexOf(Ee),1));x.push(Ee),x.length>c1e&&await Promise.race(x)},N=async(Be,we,g)=>{if(g)for(let[Ee,Pe]of we.children){let ce=g.children.get(Ee);await N(z.join(Be,Ee),Pe,ce)}else{we.children.has(Pi)&&await WC(z.join(Be,Pi),{contentsOnly:!1});let Ee=z.basename(Be)===Pi&&v.has(z.join(z.dirname(Be),z.sep));await WC(Be,{contentsOnly:Be===A,allowSymlink:Ee})}};for(let[Be,we]of p){let g=v.get(Be);for(let[Ee,Pe]of we.children){if(Ee===\".\")continue;let ce=g&&g.children.get(Ee),ne=z.join(Be,Ee);await N(ne,Pe,ce)}}let U=async(Be,we,g)=>{if(g){u1e(we.locator,g.locator)||await WC(Be,{contentsOnly:we.linkType===\"HARD\"});for(let[Ee,Pe]of we.children){let ce=g.children.get(Ee);await U(z.join(Be,Ee),Pe,ce)}}else{we.children.has(Pi)&&await WC(z.join(Be,Pi),{contentsOnly:!0});let Ee=z.basename(Be)===Pi&&v.has(z.join(z.dirname(Be),z.sep));await WC(Be,{contentsOnly:we.linkType===\"HARD\",allowSymlink:Ee})}};for(let[Be,we]of v){let g=p.get(Be);for(let[Ee,Pe]of we.children){if(Ee===\".\")continue;let ce=g&&g.children.get(Ee);await U(z.join(Be,Ee),Pe,ce)}}let V=new Map,te=[];for(let[Be,we]of E)for(let g of we){let{locationRoot:Ee,segments:Pe}=vQ(g,{skipPrefix:o.cwd}),ce=v.get(Ee),ne=Ee;if(ce){for(let ee of Pe)if(ne=z.join(ne,ee),ce=ce.children.get(ee),!ce)break;if(ce){let ee=u1e(ce.locator,Be),Ie=e.get(ce.locator),Fe=Ie.target,At=ne,H=Ie.linkType;if(ee)V.has(Fe)||V.set(Fe,At);else if(Fe!==At){let at=W.parseLocator(ce.locator);W.isVirtualLocator(at)&&(at=W.devirtualizeLocator(at)),te.push({srcDir:Fe,dstDir:At,linkType:H,realLocatorHash:at.locatorHash})}}}}for(let[Be,{locations:we}]of e.entries())for(let g of we){let{locationRoot:Ee,segments:Pe}=vQ(g,{skipPrefix:o.cwd}),ce=p.get(Ee),ne=v.get(Ee),ee=Ee,Ie=e.get(Be),Fe=W.parseLocator(Be);W.isVirtualLocator(Fe)&&(Fe=W.devirtualizeLocator(Fe));let At=Fe.locatorHash,H=Ie.target,at=g;if(H===at)continue;let Re=Ie.linkType;for(let ke of Pe)ne=ne.children.get(ke);if(!ce)te.push({srcDir:H,dstDir:at,linkType:Re,realLocatorHash:At});else for(let ke of Pe)if(ee=z.join(ee,ke),ce=ce.children.get(ke),!ce){te.push({srcDir:H,dstDir:at,linkType:Re,realLocatorHash:At});break}}let ae=Xs.progressViaCounter(te.length),fe=a.reportProgress(ae),ue=o.configuration.get(\"nmMode\"),me={value:ue},he=o.configuration.get(\"winLinkType\");try{let Be=me.value===\"hardlinks-global\"?`${dG(o.configuration)}/v1`:null;if(Be&&!await oe.existsPromise(Be)){await oe.mkdirpPromise(Be);for(let g=0;g<256;g++)await oe.mkdirPromise(z.join(Be,g.toString(16).padStart(2,\"0\")))}for(let g of te)(g.linkType===\"SOFT\"||!V.has(g.srcDir))&&(V.set(g.srcDir,g.dstDir),await C({...g,globalHardlinksStore:Be,nmMode:me,windowsLinkType:he,packageChecksum:u.get(g.realLocatorHash)||null}));await Promise.all(x),x.length=0;for(let g of te){let Ee=V.get(g.srcDir);g.linkType!==\"SOFT\"&&g.dstDir!==Ee&&await R(Ee,g.dstDir,{nmMode:me})}await Promise.all(x),await oe.mkdirPromise(A,{recursive:!0});let we=await y1t(e,v,o.cwd,{loadManifest:n});await C1t(h,we,o.cwd,he),await h1t(o,e,we,me,{installChangedByUser:I}),ue==\"hardlinks-global\"&&me.value==\"hardlinks-local\"&&a.reportWarningOnce(74,\"'nmMode' has been downgraded to 'hardlinks-local' due to global cache and install folder being on different devices\")}finally{fe.stop()}}async function C1t(t,e,r,o){for(let a of t.keys()){if(z.contains(r,a)===null)throw new Error(`Assertion failed. Excepted bin symlink location to be inside project dir, instead it was at ${a}`);if(!e.has(a)){let n=z.join(a,Pi,BQ);await oe.removePromise(n)}}for(let[a,n]of e){if(z.contains(r,a)===null)throw new Error(`Assertion failed. Excepted bin symlink location to be inside project dir, instead it was at ${a}`);let u=z.join(a,Pi,BQ),A=t.get(a)||new Map;await oe.mkdirPromise(u,{recursive:!0});for(let p of A.keys())n.has(p)||(await oe.removePromise(z.join(u,p)),process.platform===\"win32\"&&await oe.removePromise(z.join(u,`${p}.cmd`)));for(let[p,h]of n){let E=A.get(p),I=z.join(u,p);E!==h&&(process.platform===\"win32\"?await(0,A1e.default)(le.fromPortablePath(h),le.fromPortablePath(I),{createPwshFile:!1}):(await oe.removePromise(I),await gG(h,I,o),z.contains(r,await oe.realpathPromise(h))!==null&&await oe.chmodPromise(h,493)))}}}Ye();Pt();iA();var cv=class extends b0{constructor(){super(...arguments);this.mode=\"loose\"}makeInstaller(r){return new mG(r)}},mG=class extends mm{constructor(){super(...arguments);this.mode=\"loose\"}async transformPnpSettings(r){let o=new mi({baseFs:new Jl({maxOpenFiles:80,readOnlyArchives:!0})}),a=XIe(r,this.opts.project.cwd,o),{tree:n,errors:u}=JB(a,{pnpifyFs:!1,project:this.opts.project});if(!n){for(let{messageName:I,text:v}of u)this.opts.report.reportError(I,v);return}let A=new Map;r.fallbackPool=A;let p=(I,v)=>{let x=W.parseLocator(v.locator),C=W.stringifyIdent(x);C===I?A.set(I,x.reference):A.set(I,[C,x.reference])},h=z.join(this.opts.project.cwd,dr.nodeModules),E=n.get(h);if(!(typeof E>\"u\")){if(\"target\"in E)throw new Error(\"Assertion failed: Expected the root junction point to be a directory\");for(let I of E.dirList){let v=z.join(h,I),x=n.get(v);if(typeof x>\"u\")throw new Error(\"Assertion failed: Expected the child to have been registered\");if(\"target\"in x)p(I,x);else for(let C of x.dirList){let R=z.join(v,C),N=n.get(R);if(typeof N>\"u\")throw new Error(\"Assertion failed: Expected the subchild to have been registered\");if(\"target\"in N)p(`${I}/${C}`,N);else throw new Error(\"Assertion failed: Expected the leaf junction to be a package\")}}}}};var w1t={hooks:{cleanGlobalArtifacts:async t=>{let e=dG(t);await oe.removePromise(e)}},configuration:{nmHoistingLimits:{description:\"Prevents packages to be hoisted past specific levels\",type:\"STRING\",values:[\"workspaces\",\"dependencies\",\"none\"],default:\"none\"},nmMode:{description:\"Defines in which measure Yarn must use hardlinks and symlinks when generated `node_modules` directories.\",type:\"STRING\",values:[\"classic\",\"hardlinks-local\",\"hardlinks-global\"],default:\"classic\"},nmSelfReferences:{description:\"Defines whether the linker should generate self-referencing symlinks for workspaces.\",type:\"BOOLEAN\",default:!0}},linkers:[lv,cv]},I1t=w1t;var dj={};zt(dj,{NpmHttpFetcher:()=>fv,NpmRemapResolver:()=>pv,NpmSemverFetcher:()=>ml,NpmSemverResolver:()=>hv,NpmTagResolver:()=>gv,default:()=>Ovt,npmConfigUtils:()=>$n,npmHttpUtils:()=>Zr,npmPublishUtils:()=>ow});Ye();var P1e=$e(Jn());var Wn=\"npm:\";var Zr={};zt(Zr,{AuthType:()=>B1e,customPackageError:()=>ym,del:()=>T1t,get:()=>Em,getIdentUrl:()=>DQ,getPackageMetadata:()=>VC,handleInvalidAuthenticationError:()=>Q0,post:()=>F1t,put:()=>R1t});Ye();Ye();Pt();var wG=$e(f2()),w1e=$e(D_()),I1e=$e(Jn());var $n={};zt($n,{RegistryType:()=>E1e,getAuditRegistry:()=>B1t,getAuthConfiguration:()=>CG,getDefaultRegistry:()=>uv,getPublishRegistry:()=>v1t,getRegistryConfiguration:()=>C1e,getScopeConfiguration:()=>EG,getScopeRegistry:()=>KC,normalizeRegistry:()=>ac});var E1e=(o=>(o.AUDIT_REGISTRY=\"npmAuditRegistry\",o.FETCH_REGISTRY=\"npmRegistryServer\",o.PUBLISH_REGISTRY=\"npmPublishRegistry\",o))(E1e||{});function ac(t){return t.replace(/\\/$/,\"\")}function B1t({configuration:t}){return uv({configuration:t,type:\"npmAuditRegistry\"})}function v1t(t,{configuration:e}){return t.publishConfig?.registry?ac(t.publishConfig.registry):t.name?KC(t.name.scope,{configuration:e,type:\"npmPublishRegistry\"}):uv({configuration:e,type:\"npmPublishRegistry\"})}function KC(t,{configuration:e,type:r=\"npmRegistryServer\"}){let o=EG(t,{configuration:e});if(o===null)return uv({configuration:e,type:r});let a=o.get(r);return a===null?uv({configuration:e,type:r}):ac(a)}function uv({configuration:t,type:e=\"npmRegistryServer\"}){let r=t.get(e);return ac(r!==null?r:t.get(\"npmRegistryServer\"))}function C1e(t,{configuration:e}){let r=e.get(\"npmRegistries\"),o=ac(t),a=r.get(o);if(typeof a<\"u\")return a;let n=r.get(o.replace(/^[a-z]+:/,\"\"));return typeof n<\"u\"?n:null}function EG(t,{configuration:e}){if(t===null)return null;let o=e.get(\"npmScopes\").get(t);return o||null}function CG(t,{configuration:e,ident:r}){let o=r&&EG(r.scope,{configuration:e});return o?.get(\"npmAuthIdent\")||o?.get(\"npmAuthToken\")?o:C1e(t,{configuration:e})||e}var B1e=(a=>(a[a.NO_AUTH=0]=\"NO_AUTH\",a[a.BEST_EFFORT=1]=\"BEST_EFFORT\",a[a.CONFIGURATION=2]=\"CONFIGURATION\",a[a.ALWAYS_AUTH=3]=\"ALWAYS_AUTH\",a))(B1e||{});async function Q0(t,{attemptedAs:e,registry:r,headers:o,configuration:a}){if(SQ(t))throw new Jt(41,\"Invalid OTP token\");if(t.originalError?.name===\"HTTPError\"&&t.originalError?.response.statusCode===401)throw new Jt(41,`Invalid authentication (${typeof e!=\"string\"?`as ${await N1t(r,o,{configuration:a})}`:`attempted as ${e}`})`)}function ym(t,e){let r=t.response?.statusCode;return r?r===404?\"Package not found\":r>=500&&r<600?`The registry appears to be down (using a ${de.applyHyperlink(e,\"local cache\",\"https://yarnpkg.com/advanced/lexicon#local-cache\")} might have protected you against such outages)`:null:null}function DQ(t){return t.scope?`/@${t.scope}%2f${t.name}`:`/${t.name}`}var v1e=new Map,D1t=new Map;async function P1t(t){return await _e.getFactoryWithDefault(v1e,t,async()=>{let e=null;try{e=await oe.readJsonPromise(t)}catch{}return e})}async function S1t(t,e,{configuration:r,cached:o,registry:a,headers:n,version:u,...A}){return await _e.getFactoryWithDefault(D1t,t,async()=>await Em(DQ(e),{...A,customErrorMessage:ym,configuration:r,registry:a,ident:e,headers:{...n,[\"If-None-Match\"]:o?.etag,[\"If-Modified-Since\"]:o?.lastModified},wrapNetworkRequest:async p=>async()=>{let h=await p();if(h.statusCode===304){if(o===null)throw new Error(\"Assertion failed: cachedMetadata should not be null\");return{...h,body:o.metadata}}let E=b1t(JSON.parse(h.body.toString())),I={metadata:E,etag:h.headers.etag,lastModified:h.headers[\"last-modified\"]};return v1e.set(t,Promise.resolve(I)),Promise.resolve().then(async()=>{let v=`${t}-${process.pid}.tmp`;await oe.mkdirPromise(z.dirname(v),{recursive:!0}),await oe.writeJsonPromise(v,I,{compact:!0}),await oe.renamePromise(v,t)}).catch(()=>{}),{...h,body:E}}}))}async function VC(t,{cache:e,project:r,registry:o,headers:a,version:n,...u}){let{configuration:A}=r;o=Av(A,{ident:t,registry:o});let p=k1t(A,o),h=z.join(p,`${W.slugifyIdent(t)}.json`),E=null;if(!r.lockfileNeedsRefresh&&(E=await P1t(h),E)){if(typeof n<\"u\"&&typeof E.metadata.versions[n]<\"u\")return E.metadata;if(A.get(\"enableOfflineMode\")){let I=structuredClone(E.metadata),v=new Set;if(e){for(let C of Object.keys(I.versions)){let R=W.makeLocator(t,`npm:${C}`),N=e.getLocatorMirrorPath(R);(!N||!oe.existsSync(N))&&(delete I.versions[C],v.add(C))}let x=I[\"dist-tags\"].latest;if(v.has(x)){let C=Object.keys(E.metadata.versions).sort(I1e.default.compare),R=C.indexOf(x);for(;v.has(C[R])&&R>=0;)R-=1;R>=0?I[\"dist-tags\"].latest=C[R]:delete I[\"dist-tags\"].latest}}return I}}return await S1t(h,t,{...u,configuration:A,cached:E,registry:o,headers:a,version:n})}var D1e=[\"name\",\"dist.tarball\",\"bin\",\"scripts\",\"os\",\"cpu\",\"libc\",\"dependencies\",\"dependenciesMeta\",\"optionalDependencies\",\"peerDependencies\",\"peerDependenciesMeta\",\"deprecated\"];function b1t(t){return{\"dist-tags\":t[\"dist-tags\"],versions:Object.fromEntries(Object.entries(t.versions).map(([e,r])=>[e,(0,w1e.default)(r,D1e)]))}}var x1t=wn.makeHash(...D1e).slice(0,6);function k1t(t,e){let r=Q1t(t),o=new URL(e);return z.join(r,x1t,o.hostname)}function Q1t(t){return z.join(t.get(\"globalFolder\"),\"metadata/npm\")}async function Em(t,{configuration:e,headers:r,ident:o,authType:a,registry:n,...u}){n=Av(e,{ident:o,registry:n}),o&&o.scope&&typeof a>\"u\"&&(a=1);let A=await PQ(n,{authType:a,configuration:e,ident:o});A&&(r={...r,authorization:A});try{return await nn.get(t.charAt(0)===\"/\"?`${n}${t}`:t,{configuration:e,headers:r,...u})}catch(p){throw await Q0(p,{registry:n,configuration:e,headers:r}),p}}async function F1t(t,e,{attemptedAs:r,configuration:o,headers:a,ident:n,authType:u=3,registry:A,otp:p,...h}){A=Av(o,{ident:n,registry:A});let E=await PQ(A,{authType:u,configuration:o,ident:n});E&&(a={...a,authorization:E}),p&&(a={...a,...zC(p)});try{return await nn.post(A+t,e,{configuration:o,headers:a,...h})}catch(I){if(!SQ(I)||p)throw await Q0(I,{attemptedAs:r,registry:A,configuration:o,headers:a}),I;p=await IG(I,{configuration:o});let v={...a,...zC(p)};try{return await nn.post(`${A}${t}`,e,{configuration:o,headers:v,...h})}catch(x){throw await Q0(x,{attemptedAs:r,registry:A,configuration:o,headers:a}),x}}}async function R1t(t,e,{attemptedAs:r,configuration:o,headers:a,ident:n,authType:u=3,registry:A,otp:p,...h}){A=Av(o,{ident:n,registry:A});let E=await PQ(A,{authType:u,configuration:o,ident:n});E&&(a={...a,authorization:E}),p&&(a={...a,...zC(p)});try{return await nn.put(A+t,e,{configuration:o,headers:a,...h})}catch(I){if(!SQ(I))throw await Q0(I,{attemptedAs:r,registry:A,configuration:o,headers:a}),I;p=await IG(I,{configuration:o});let v={...a,...zC(p)};try{return await nn.put(`${A}${t}`,e,{configuration:o,headers:v,...h})}catch(x){throw await Q0(x,{attemptedAs:r,registry:A,configuration:o,headers:a}),x}}}async function T1t(t,{attemptedAs:e,configuration:r,headers:o,ident:a,authType:n=3,registry:u,otp:A,...p}){u=Av(r,{ident:a,registry:u});let h=await PQ(u,{authType:n,configuration:r,ident:a});h&&(o={...o,authorization:h}),A&&(o={...o,...zC(A)});try{return await nn.del(u+t,{configuration:r,headers:o,...p})}catch(E){if(!SQ(E)||A)throw await Q0(E,{attemptedAs:e,registry:u,configuration:r,headers:o}),E;A=await IG(E,{configuration:r});let I={...o,...zC(A)};try{return await nn.del(`${u}${t}`,{configuration:r,headers:I,...p})}catch(v){throw await Q0(v,{attemptedAs:e,registry:u,configuration:r,headers:o}),v}}}function Av(t,{ident:e,registry:r}){if(typeof r>\"u\"&&e)return KC(e.scope,{configuration:t});if(typeof r!=\"string\")throw new Error(\"Assertion failed: The registry should be a string\");return ac(r)}async function PQ(t,{authType:e=2,configuration:r,ident:o}){let a=CG(t,{configuration:r,ident:o}),n=L1t(a,e);if(!n)return null;let u=await r.reduceHook(A=>A.getNpmAuthenticationHeader,void 0,t,{configuration:r,ident:o});if(u)return u;if(a.get(\"npmAuthToken\"))return`Bearer ${a.get(\"npmAuthToken\")}`;if(a.get(\"npmAuthIdent\")){let A=a.get(\"npmAuthIdent\");return A.includes(\":\")?`Basic ${Buffer.from(A).toString(\"base64\")}`:`Basic ${A}`}if(n&&e!==1)throw new Jt(33,\"No authentication configured for request\");return null}function L1t(t,e){switch(e){case 2:return t.get(\"npmAlwaysAuth\");case 1:case 3:return!0;case 0:return!1;default:throw new Error(\"Unreachable\")}}async function N1t(t,e,{configuration:r}){if(typeof e>\"u\"||typeof e.authorization>\"u\")return\"an anonymous user\";try{return(await nn.get(new URL(`${t}/-/whoami`).href,{configuration:r,headers:e,jsonResponse:!0})).username??\"an unknown user\"}catch{return\"an unknown user\"}}async function IG(t,{configuration:e}){let r=t.originalError?.response.headers[\"npm-notice\"];if(r&&(await Lt.start({configuration:e,stdout:process.stdout,includeFooter:!1},async a=>{if(a.reportInfo(0,r.replace(/(https?:\\/\\/\\S+)/g,de.pretty(e,\"$1\",de.Type.URL))),!process.env.YARN_IS_TEST_ENV){let n=r.match(/open (https?:\\/\\/\\S+)/i);if(n&&Vi.openUrl){let{openNow:u}=await(0,wG.prompt)({type:\"confirm\",name:\"openNow\",message:\"Do you want to try to open this url now?\",required:!0,initial:!0,onCancel:()=>process.exit(130)});u&&(await Vi.openUrl(n[1])||(a.reportSeparator(),a.reportWarning(0,\"We failed to automatically open the url; you'll have to open it yourself in your browser of choice.\")))}}}),process.stdout.write(`\n`)),process.env.YARN_IS_TEST_ENV)return process.env.YARN_INJECT_NPM_2FA_TOKEN||\"\";let{otp:o}=await(0,wG.prompt)({type:\"password\",name:\"otp\",message:\"One-time password:\",required:!0,onCancel:()=>process.exit(130)});return process.stdout.write(`\n`),o}function SQ(t){if(t.originalError?.name!==\"HTTPError\")return!1;try{return(t.originalError?.response.headers[\"www-authenticate\"].split(/,\\s*/).map(r=>r.toLowerCase())).includes(\"otp\")}catch{return!1}}function zC(t){return{[\"npm-otp\"]:t}}var fv=class{supports(e,r){if(!e.reference.startsWith(Wn))return!1;let{selector:o,params:a}=W.parseRange(e.reference);return!(!P1e.default.valid(o)||a===null||typeof a.__archiveUrl!=\"string\")}getLocalPath(e,r){return null}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the remote server`),loader:()=>this.fetchFromNetwork(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),checksum:u}}async fetchFromNetwork(e,r){let{params:o}=W.parseRange(e.reference);if(o===null||typeof o.__archiveUrl!=\"string\")throw new Error(\"Assertion failed: The archiveUrl querystring parameter should have been available\");let a=await Em(o.__archiveUrl,{customErrorMessage:ym,configuration:r.project.configuration,ident:e});return await Xi.convertToZip(a,{configuration:r.project.configuration,prefixPath:W.getIdentVendorPath(e),stripComponents:1})}};Ye();var pv=class{supportsDescriptor(e,r){return!(!e.range.startsWith(Wn)||!W.tryParseDescriptor(e.range.slice(Wn.length),!0))}supportsLocator(e,r){return!1}shouldPersistResolution(e,r){throw new Error(\"Unreachable\")}bindDescriptor(e,r,o){return e}getResolutionDependencies(e,r){let o=r.project.configuration.normalizeDependency(W.parseDescriptor(e.range.slice(Wn.length),!0));return r.resolver.getResolutionDependencies(o,r)}async getCandidates(e,r,o){let a=o.project.configuration.normalizeDependency(W.parseDescriptor(e.range.slice(Wn.length),!0));return await o.resolver.getCandidates(a,r,o)}async getSatisfying(e,r,o,a){let n=a.project.configuration.normalizeDependency(W.parseDescriptor(e.range.slice(Wn.length),!0));return a.resolver.getSatisfying(n,r,o,a)}resolve(e,r){throw new Error(\"Unreachable\")}};Ye();Ye();var S1e=$e(Jn());var ml=class{supports(e,r){if(!e.reference.startsWith(Wn))return!1;let o=new URL(e.reference);return!(!S1e.default.valid(o.pathname)||o.searchParams.has(\"__archiveUrl\"))}getLocalPath(e,r){return null}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the remote registry`),loader:()=>this.fetchFromNetwork(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),checksum:u}}async fetchFromNetwork(e,r){let o;try{o=await Em(ml.getLocatorUrl(e),{customErrorMessage:ym,configuration:r.project.configuration,ident:e})}catch{o=await Em(ml.getLocatorUrl(e).replace(/%2f/g,\"/\"),{customErrorMessage:ym,configuration:r.project.configuration,ident:e})}return await Xi.convertToZip(o,{configuration:r.project.configuration,prefixPath:W.getIdentVendorPath(e),stripComponents:1})}static isConventionalTarballUrl(e,r,{configuration:o}){let a=KC(e.scope,{configuration:o}),n=ml.getLocatorUrl(e);return r=r.replace(/^https?:(\\/\\/(?:[^/]+\\.)?npmjs.org(?:$|\\/))/,\"https:$1\"),a=a.replace(/^https:\\/\\/registry\\.npmjs\\.org($|\\/)/,\"https://registry.yarnpkg.com$1\"),r=r.replace(/^https:\\/\\/registry\\.npmjs\\.org($|\\/)/,\"https://registry.yarnpkg.com$1\"),r===a+n||r===a+n.replace(/%2f/g,\"/\")}static getLocatorUrl(e){let r=kr.clean(e.reference.slice(Wn.length));if(r===null)throw new Jt(10,\"The npm semver resolver got selected, but the version isn't semver\");return`${DQ(e)}/-/${e.name}-${r}.tgz`}};Ye();Ye();Ye();var BG=$e(Jn());var bQ=W.makeIdent(null,\"node-gyp\"),O1t=/\\b(node-gyp|prebuild-install)\\b/,hv=class{supportsDescriptor(e,r){return e.range.startsWith(Wn)?!!kr.validRange(e.range.slice(Wn.length)):!1}supportsLocator(e,r){if(!e.reference.startsWith(Wn))return!1;let{selector:o}=W.parseRange(e.reference);return!!BG.default.valid(o)}shouldPersistResolution(e,r){return!0}bindDescriptor(e,r,o){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){let a=kr.validRange(e.range.slice(Wn.length));if(a===null)throw new Error(`Expected a valid range, got ${e.range.slice(Wn.length)}`);let n=await VC(e,{cache:o.fetchOptions?.cache,project:o.project,version:BG.default.valid(a.raw)?a.raw:void 0}),u=_e.mapAndFilter(Object.keys(n.versions),h=>{try{let E=new kr.SemVer(h);if(a.test(E))return E}catch{}return _e.mapAndFilter.skip}),A=u.filter(h=>!n.versions[h.raw].deprecated),p=A.length>0?A:u;return p.sort((h,E)=>-h.compare(E)),p.map(h=>{let E=W.makeLocator(e,`${Wn}${h.raw}`),I=n.versions[h.raw].dist.tarball;return ml.isConventionalTarballUrl(E,I,{configuration:o.project.configuration})?E:W.bindLocator(E,{__archiveUrl:I})})}async getSatisfying(e,r,o,a){let n=kr.validRange(e.range.slice(Wn.length));if(n===null)throw new Error(`Expected a valid range, got ${e.range.slice(Wn.length)}`);return{locators:_e.mapAndFilter(o,p=>{if(p.identHash!==e.identHash)return _e.mapAndFilter.skip;let h=W.tryParseRange(p.reference,{requireProtocol:Wn});if(!h)return _e.mapAndFilter.skip;let E=new kr.SemVer(h.selector);return n.test(E)?{locator:p,version:E}:_e.mapAndFilter.skip}).sort((p,h)=>-p.version.compare(h.version)).map(({locator:p})=>p),sorted:!0}}async resolve(e,r){let{selector:o}=W.parseRange(e.reference),a=kr.clean(o);if(a===null)throw new Jt(10,\"The npm semver resolver got selected, but the version isn't semver\");let n=await VC(e,{cache:r.fetchOptions?.cache,project:r.project,version:a});if(!Object.hasOwn(n,\"versions\"))throw new Jt(15,'Registry returned invalid data for - missing \"versions\" field');if(!Object.hasOwn(n.versions,a))throw new Jt(16,`Registry failed to return reference \"${a}\"`);let u=new Ot;if(u.load(n.versions[a]),!u.dependencies.has(bQ.identHash)&&!u.peerDependencies.has(bQ.identHash)){for(let A of u.scripts.values())if(A.match(O1t)){u.dependencies.set(bQ.identHash,W.makeDescriptor(bQ,\"latest\"));break}}return{...e,version:a,languageName:\"node\",linkType:\"HARD\",conditions:u.getConditions(),dependencies:r.project.configuration.normalizeDependencyMap(u.dependencies),peerDependencies:u.peerDependencies,dependenciesMeta:u.dependenciesMeta,peerDependenciesMeta:u.peerDependenciesMeta,bin:u.bin}}};Ye();Ye();var b1e=$e(Jn());var gv=class{supportsDescriptor(e,r){return!(!e.range.startsWith(Wn)||!FE.test(e.range.slice(Wn.length)))}supportsLocator(e,r){return!1}shouldPersistResolution(e,r){throw new Error(\"Unreachable\")}bindDescriptor(e,r,o){return e}getResolutionDependencies(e,r){return{}}async getCandidates(e,r,o){let a=e.range.slice(Wn.length),n=await VC(e,{cache:o.fetchOptions?.cache,project:o.project});if(!Object.hasOwn(n,\"dist-tags\"))throw new Jt(15,'Registry returned invalid data - missing \"dist-tags\" field');let u=n[\"dist-tags\"];if(!Object.hasOwn(u,a))throw new Jt(16,`Registry failed to return tag \"${a}\"`);let A=u[a],p=W.makeLocator(e,`${Wn}${A}`),h=n.versions[A].dist.tarball;return ml.isConventionalTarballUrl(p,h,{configuration:o.project.configuration})?[p]:[W.bindLocator(p,{__archiveUrl:h})]}async getSatisfying(e,r,o,a){let n=[];for(let u of o){if(u.identHash!==e.identHash)continue;let A=W.tryParseRange(u.reference,{requireProtocol:Wn});if(!(!A||!b1e.default.valid(A.selector))){if(A.params?.__archiveUrl){let p=W.makeRange({protocol:Wn,selector:A.selector,source:null,params:null}),[h]=await a.resolver.getCandidates(W.makeDescriptor(e,p),r,a);if(u.reference!==h.reference)continue}n.push(u)}}return{locators:n,sorted:!1}}async resolve(e,r){throw new Error(\"Unreachable\")}};var ow={};zt(ow,{getGitHead:()=>Lvt,getPublishAccess:()=>mBe,getReadmeContent:()=>yBe,makePublishBody:()=>Tvt});Ye();Ye();Pt();var Aj={};zt(Aj,{PackCommand:()=>_0,default:()=>dvt,packUtils:()=>wA});Ye();Ye();Ye();Pt();qt();var wA={};zt(wA,{genPackList:()=>XQ,genPackStream:()=>uj,genPackageManifest:()=>sBe,hasPackScripts:()=>lj,prepareForPack:()=>cj});Ye();Pt();var aj=$e(Zo()),nBe=$e($2e()),iBe=ve(\"zlib\"),svt=[\"/package.json\",\"/readme\",\"/readme.*\",\"/license\",\"/license.*\",\"/licence\",\"/licence.*\",\"/changelog\",\"/changelog.*\"],ovt=[\"/package.tgz\",\".github\",\".git\",\".hg\",\"node_modules\",\".npmignore\",\".gitignore\",\".#*\",\".DS_Store\"];async function lj(t){return!!(un.hasWorkspaceScript(t,\"prepack\")||un.hasWorkspaceScript(t,\"postpack\"))}async function cj(t,{report:e},r){await un.maybeExecuteWorkspaceLifecycleScript(t,\"prepack\",{report:e});try{let o=z.join(t.cwd,Ot.fileName);await oe.existsPromise(o)&&await t.manifest.loadFile(o,{baseFs:oe}),await r()}finally{await un.maybeExecuteWorkspaceLifecycleScript(t,\"postpack\",{report:e})}}async function uj(t,e){typeof e>\"u\"&&(e=await XQ(t));let r=new Set;for(let n of t.manifest.publishConfig?.executableFiles??new Set)r.add(z.normalize(n));for(let n of t.manifest.bin.values())r.add(z.normalize(n));let o=nBe.default.pack();process.nextTick(async()=>{for(let n of e){let u=z.normalize(n),A=z.resolve(t.cwd,u),p=z.join(\"package\",u),h=await oe.lstatPromise(A),E={name:p,mtime:new Date(vi.SAFE_TIME*1e3)},I=r.has(u)?493:420,v,x,C=new Promise((N,U)=>{v=N,x=U}),R=N=>{N?x(N):v()};if(h.isFile()){let N;u===\"package.json\"?N=Buffer.from(JSON.stringify(await sBe(t),null,2)):N=await oe.readFilePromise(A),o.entry({...E,mode:I,type:\"file\"},N,R)}else h.isSymbolicLink()?o.entry({...E,mode:I,type:\"symlink\",linkname:await oe.readlinkPromise(A)},R):R(new Error(`Unsupported file type ${h.mode} for ${le.fromPortablePath(u)}`));await C}o.finalize()});let a=(0,iBe.createGzip)();return o.pipe(a),a}async function sBe(t){let e=JSON.parse(JSON.stringify(t.manifest.raw));return await t.project.configuration.triggerHook(r=>r.beforeWorkspacePacking,t,e),e}async function XQ(t){let e=t.project,r=e.configuration,o={accept:[],reject:[]};for(let I of ovt)o.reject.push(I);for(let I of svt)o.accept.push(I);o.reject.push(r.get(\"rcFilename\"));let a=I=>{if(I===null||!I.startsWith(`${t.cwd}/`))return;let v=z.relative(t.cwd,I),x=z.resolve(Bt.root,v);o.reject.push(x)};a(z.resolve(e.cwd,dr.lockfile)),a(r.get(\"cacheFolder\")),a(r.get(\"globalFolder\")),a(r.get(\"installStatePath\")),a(r.get(\"virtualFolder\")),a(r.get(\"yarnPath\")),await r.triggerHook(I=>I.populateYarnPaths,e,I=>{a(I)});for(let I of e.workspaces){let v=z.relative(t.cwd,I.cwd);v!==\"\"&&!v.match(/^(\\.\\.)?\\//)&&o.reject.push(`/${v}`)}let n={accept:[],reject:[]},u=t.manifest.publishConfig?.main??t.manifest.main,A=t.manifest.publishConfig?.module??t.manifest.module,p=t.manifest.publishConfig?.browser??t.manifest.browser,h=t.manifest.publishConfig?.bin??t.manifest.bin;u!=null&&n.accept.push(z.resolve(Bt.root,u)),A!=null&&n.accept.push(z.resolve(Bt.root,A)),typeof p==\"string\"&&n.accept.push(z.resolve(Bt.root,p));for(let I of h.values())n.accept.push(z.resolve(Bt.root,I));if(p instanceof Map)for(let[I,v]of p.entries())n.accept.push(z.resolve(Bt.root,I)),typeof v==\"string\"&&n.accept.push(z.resolve(Bt.root,v));let E=t.manifest.files!==null;if(E){n.reject.push(\"/*\");for(let I of t.manifest.files)oBe(n.accept,I,{cwd:Bt.root})}return await avt(t.cwd,{hasExplicitFileList:E,globalList:o,ignoreList:n})}async function avt(t,{hasExplicitFileList:e,globalList:r,ignoreList:o}){let a=[],n=new Hu(t),u=[[Bt.root,[o]]];for(;u.length>0;){let[A,p]=u.pop(),h=await n.lstatPromise(A);if(!tBe(A,{globalList:r,ignoreLists:h.isDirectory()?null:p}))if(h.isDirectory()){let E=await n.readdirPromise(A),I=!1,v=!1;if(!e||A!==Bt.root)for(let R of E)I=I||R===\".gitignore\",v=v||R===\".npmignore\";let x=v?await eBe(n,A,\".npmignore\"):I?await eBe(n,A,\".gitignore\"):null,C=x!==null?[x].concat(p):p;tBe(A,{globalList:r,ignoreLists:p})&&(C=[...p,{accept:[],reject:[\"**/*\"]}]);for(let R of E)u.push([z.resolve(A,R),C])}else(h.isFile()||h.isSymbolicLink())&&a.push(z.relative(Bt.root,A))}return a.sort()}async function eBe(t,e,r){let o={accept:[],reject:[]},a=await t.readFilePromise(z.join(e,r),\"utf8\");for(let n of a.split(/\\n/g))oBe(o.reject,n,{cwd:e});return o}function lvt(t,{cwd:e}){let r=t[0]===\"!\";return r&&(t=t.slice(1)),t.match(/\\.{0,1}\\//)&&(t=z.resolve(e,t)),r&&(t=`!${t}`),t}function oBe(t,e,{cwd:r}){let o=e.trim();o===\"\"||o[0]===\"#\"||t.push(lvt(o,{cwd:r}))}function tBe(t,{globalList:e,ignoreLists:r}){let o=JQ(t,e.accept);if(o!==0)return o===2;let a=JQ(t,e.reject);if(a!==0)return a===1;if(r!==null)for(let n of r){let u=JQ(t,n.accept);if(u!==0)return u===2;let A=JQ(t,n.reject);if(A!==0)return A===1}return!1}function JQ(t,e){let r=e,o=[];for(let a=0;a<e.length;++a)e[a][0]!==\"!\"?r!==e&&r.push(e[a]):(r===e&&(r=e.slice(0,a)),o.push(e[a].slice(1)));return rBe(t,o)?2:rBe(t,r)?1:0}function rBe(t,e){let r=e,o=[];for(let a=0;a<e.length;++a)e[a].includes(\"/\")?r!==e&&r.push(e[a]):(r===e&&(r=e.slice(0,a)),o.push(e[a]));return!!(aj.default.isMatch(t,r,{dot:!0,nocase:!0})||aj.default.isMatch(t,o,{dot:!0,basename:!0,nocase:!0}))}var _0=class extends ut{constructor(){super(...arguments);this.installIfNeeded=ge.Boolean(\"--install-if-needed\",!1,{description:\"Run a preliminary `yarn install` if the package contains build scripts\"});this.dryRun=ge.Boolean(\"-n,--dry-run\",!1,{description:\"Print the file paths without actually generating the package archive\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.out=ge.String(\"-o,--out\",{description:\"Create the archive at the specified path\"});this.filename=ge.String(\"--filename\",{hidden:!0})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new nr(o.cwd,this.context.cwd);await lj(a)&&(this.installIfNeeded?await o.install({cache:await Nr.find(r),report:new Qi}):await o.restoreInstallState());let n=this.out??this.filename,u=typeof n<\"u\"?z.resolve(this.context.cwd,cvt(n,{workspace:a})):z.resolve(a.cwd,\"package.tgz\");return(await Lt.start({configuration:r,stdout:this.context.stdout,json:this.json},async p=>{await cj(a,{report:p},async()=>{p.reportJson({base:le.fromPortablePath(a.cwd)});let h=await XQ(a);for(let E of h)p.reportInfo(null,le.fromPortablePath(E)),p.reportJson({location:le.fromPortablePath(E)});if(!this.dryRun){let E=await uj(a,h),I=oe.createWriteStream(u);E.pipe(I),await new Promise(v=>{I.on(\"finish\",v)})}}),this.dryRun||(p.reportInfo(0,`Package archive generated in ${de.pretty(r,u,de.Type.PATH)}`),p.reportJson({output:le.fromPortablePath(u)}))})).exitCode()}};_0.paths=[[\"pack\"]],_0.usage=nt.Usage({description:\"generate a tarball from the active workspace\",details:\"\\n      This command will turn the active workspace into a compressed archive suitable for publishing. The archive will by default be stored at the root of the workspace (`package.tgz`).\\n\\n      If the `-o,---out` is set the archive will be created at the specified path. The `%s` and `%v` variables can be used within the path and will be respectively replaced by the package name and version.\\n    \",examples:[[\"Create an archive from the active workspace\",\"yarn pack\"],[\"List the files that would be made part of the workspace's archive\",\"yarn pack --dry-run\"],[\"Name and output the archive in a dedicated folder\",\"yarn pack --out /artifacts/%s-%v.tgz\"]]});function cvt(t,{workspace:e}){let r=t.replace(\"%s\",uvt(e)).replace(\"%v\",Avt(e));return le.toPortablePath(r)}function uvt(t){return t.manifest.name!==null?W.slugifyIdent(t.manifest.name):\"package\"}function Avt(t){return t.manifest.version!==null?t.manifest.version:\"unknown\"}var fvt=[\"dependencies\",\"devDependencies\",\"peerDependencies\"],pvt=\"workspace:\",hvt=(t,e)=>{e.publishConfig&&(e.publishConfig.type&&(e.type=e.publishConfig.type),e.publishConfig.main&&(e.main=e.publishConfig.main),e.publishConfig.browser&&(e.browser=e.publishConfig.browser),e.publishConfig.module&&(e.module=e.publishConfig.module),e.publishConfig.exports&&(e.exports=e.publishConfig.exports),e.publishConfig.imports&&(e.imports=e.publishConfig.imports),e.publishConfig.bin&&(e.bin=e.publishConfig.bin));let r=t.project;for(let o of fvt)for(let a of t.manifest.getForScope(o).values()){let n=r.tryWorkspaceByDescriptor(a),u=W.parseRange(a.range);if(u.protocol===pvt)if(n===null){if(r.tryWorkspaceByIdent(a)===null)throw new Jt(21,`${W.prettyDescriptor(r.configuration,a)}: No local workspace found for this range`)}else{let A;W.areDescriptorsEqual(a,n.anchoredDescriptor)||u.selector===\"*\"?A=n.manifest.version??\"0.0.0\":u.selector===\"~\"||u.selector===\"^\"?A=`${u.selector}${n.manifest.version??\"0.0.0\"}`:A=u.selector;let p=o===\"dependencies\"?W.makeDescriptor(a,\"unknown\"):null,h=p!==null&&t.manifest.ensureDependencyMeta(p).optional?\"optionalDependencies\":o;e[h][W.stringifyIdent(a)]=A}}},gvt={hooks:{beforeWorkspacePacking:hvt},commands:[_0]},dvt=gvt;var gBe=ve(\"crypto\"),dBe=$e(hBe());async function Tvt(t,e,{access:r,tag:o,registry:a,gitHead:n}){let u=t.manifest.name,A=t.manifest.version,p=W.stringifyIdent(u),h=(0,gBe.createHash)(\"sha1\").update(e).digest(\"hex\"),E=dBe.default.fromData(e).toString(),I=r??mBe(t,u),v=await yBe(t),x=await wA.genPackageManifest(t),C=`${p}-${A}.tgz`,R=new URL(`${ac(a)}/${p}/-/${C}`);return{_id:p,_attachments:{[C]:{content_type:\"application/octet-stream\",data:e.toString(\"base64\"),length:e.length}},name:p,access:I,[\"dist-tags\"]:{[o]:A},versions:{[A]:{...x,_id:`${p}@${A}`,name:p,version:A,gitHead:n,dist:{shasum:h,integrity:E,tarball:R.toString()}}},readme:v}}async function Lvt(t){try{let{stdout:e}=await Ur.execvp(\"git\",[\"rev-parse\",\"--revs-only\",\"HEAD\"],{cwd:t});return e.trim()===\"\"?void 0:e.trim()}catch{return}}function mBe(t,e){let r=t.project.configuration;return t.manifest.publishConfig&&typeof t.manifest.publishConfig.access==\"string\"?t.manifest.publishConfig.access:r.get(\"npmPublishAccess\")!==null?r.get(\"npmPublishAccess\"):e.scope?\"restricted\":\"public\"}async function yBe(t){let e=le.toPortablePath(`${t.cwd}/README.md`),r=t.manifest.name,a=`# ${W.stringifyIdent(r)}\n`;try{a=await oe.readFilePromise(e,\"utf8\")}catch(n){if(n.code===\"ENOENT\")return a;throw n}return a}var gj={npmAlwaysAuth:{description:\"URL of the selected npm registry (note: npm enterprise isn't supported)\",type:\"BOOLEAN\",default:!1},npmAuthIdent:{description:\"Authentication identity for the npm registry (_auth in npm and yarn v1)\",type:\"SECRET\",default:null},npmAuthToken:{description:\"Authentication token for the npm registry (_authToken in npm and yarn v1)\",type:\"SECRET\",default:null}},EBe={npmAuditRegistry:{description:\"Registry to query for audit reports\",type:\"STRING\",default:null},npmPublishRegistry:{description:\"Registry to push packages to\",type:\"STRING\",default:null},npmRegistryServer:{description:\"URL of the selected npm registry (note: npm enterprise isn't supported)\",type:\"STRING\",default:\"https://registry.yarnpkg.com\"}},Nvt={configuration:{...gj,...EBe,npmScopes:{description:\"Settings per package scope\",type:\"MAP\",valueDefinition:{description:\"\",type:\"SHAPE\",properties:{...gj,...EBe}}},npmRegistries:{description:\"Settings per registry\",type:\"MAP\",normalizeKeys:ac,valueDefinition:{description:\"\",type:\"SHAPE\",properties:{...gj}}}},fetchers:[fv,ml],resolvers:[pv,hv,gv]},Ovt=Nvt;var Dj={};zt(Dj,{NpmAuditCommand:()=>q0,NpmInfoCommand:()=>G0,NpmLoginCommand:()=>j0,NpmLogoutCommand:()=>Y0,NpmPublishCommand:()=>W0,NpmTagAddCommand:()=>z0,NpmTagListCommand:()=>K0,NpmTagRemoveCommand:()=>V0,NpmWhoamiCommand:()=>J0,default:()=>jvt,npmAuditTypes:()=>Rv,npmAuditUtils:()=>ZQ});Ye();Ye();qt();var wj=$e(Zo());$a();var Rv={};zt(Rv,{Environment:()=>Qv,Severity:()=>Fv});var Qv=(o=>(o.All=\"all\",o.Production=\"production\",o.Development=\"development\",o))(Qv||{}),Fv=(n=>(n.Info=\"info\",n.Low=\"low\",n.Moderate=\"moderate\",n.High=\"high\",n.Critical=\"critical\",n))(Fv||{});var ZQ={};zt(ZQ,{allSeverities:()=>aw,getPackages:()=>Cj,getReportTree:()=>yj,getSeverityInclusions:()=>mj,getTopLevelDependencies:()=>Ej});Ye();var CBe=$e(Jn());var aw=[\"info\",\"low\",\"moderate\",\"high\",\"critical\"];function mj(t){if(typeof t>\"u\")return new Set(aw);let e=aw.indexOf(t),r=aw.slice(e);return new Set(r)}function yj(t){let e={},r={children:e};for(let[o,a]of _e.sortMap(Object.entries(t),n=>n[0]))for(let n of _e.sortMap(a,u=>`${u.id}`))e[`${o}/${n.id}`]={value:de.tuple(de.Type.IDENT,W.parseIdent(o)),children:{ID:typeof n.id<\"u\"&&{label:\"ID\",value:de.tuple(de.Type.ID,n.id)},Issue:{label:\"Issue\",value:de.tuple(de.Type.NO_HINT,n.title)},URL:typeof n.url<\"u\"&&{label:\"URL\",value:de.tuple(de.Type.URL,n.url)},Severity:{label:\"Severity\",value:de.tuple(de.Type.NO_HINT,n.severity)},[\"Vulnerable Versions\"]:{label:\"Vulnerable Versions\",value:de.tuple(de.Type.RANGE,n.vulnerable_versions)},[\"Tree Versions\"]:{label:\"Tree Versions\",children:[...n.versions].sort(CBe.default.compare).map(u=>({value:de.tuple(de.Type.REFERENCE,u)}))},Dependents:{label:\"Dependents\",children:_e.sortMap(n.dependents,u=>W.stringifyLocator(u)).map(u=>({value:de.tuple(de.Type.LOCATOR,u)}))}}};return r}function Ej(t,e,{all:r,environment:o}){let a=[],n=r?t.workspaces:[e],u=[\"all\",\"production\"].includes(o),A=[\"all\",\"development\"].includes(o);for(let p of n)for(let h of p.anchoredPackage.dependencies.values())(p.manifest.devDependencies.has(h.identHash)?!A:!u)||a.push({workspace:p,dependency:h});return a}function Cj(t,e,{recursive:r}){let o=new Map,a=new Set,n=[],u=(A,p)=>{let h=t.storedResolutions.get(p.descriptorHash);if(typeof h>\"u\")throw new Error(\"Assertion failed: The resolution should have been registered\");if(!a.has(h))a.add(h);else return;let E=t.storedPackages.get(h);if(typeof E>\"u\")throw new Error(\"Assertion failed: The package should have been registered\");if(W.ensureDevirtualizedLocator(E).reference.startsWith(\"npm:\")&&E.version!==null){let v=W.stringifyIdent(E),x=_e.getMapWithDefault(o,v);_e.getArrayWithDefault(x,E.version).push(A)}if(r)for(let v of E.dependencies.values())n.push([E,v])};for(let{workspace:A,dependency:p}of e)n.push([A.anchoredLocator,p]);for(;n.length>0;){let[A,p]=n.shift();u(A,p)}return o}var q0=class extends ut{constructor(){super(...arguments);this.all=ge.Boolean(\"-A,--all\",!1,{description:\"Audit dependencies from all workspaces\"});this.recursive=ge.Boolean(\"-R,--recursive\",!1,{description:\"Audit transitive dependencies as well\"});this.environment=ge.String(\"--environment\",\"all\",{description:\"Which environments to cover\",validator:Ks(Qv)});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.noDeprecations=ge.Boolean(\"--no-deprecations\",!1,{description:\"Don't warn about deprecated packages\"});this.severity=ge.String(\"--severity\",\"info\",{description:\"Minimal severity requested for packages to be displayed\",validator:Ks(Fv)});this.excludes=ge.Array(\"--exclude\",[],{description:\"Array of glob patterns of packages to exclude from audit\"});this.ignores=ge.Array(\"--ignore\",[],{description:\"Array of glob patterns of advisory ID's to ignore in the audit report\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new nr(o.cwd,this.context.cwd);await o.restoreInstallState();let n=Ej(o,a,{all:this.all,environment:this.environment}),u=Cj(o,n,{recursive:this.recursive}),A=Array.from(new Set([...r.get(\"npmAuditExcludePackages\"),...this.excludes])),p=Object.create(null);for(let[N,U]of u)A.some(V=>wj.default.isMatch(N,V))||(p[N]=[...U.keys()]);let h=$n.getAuditRegistry({configuration:r}),E,I=await fA.start({configuration:r,stdout:this.context.stdout},async()=>{let N=Zr.post(\"/-/npm/v1/security/advisories/bulk\",p,{authType:Zr.AuthType.BEST_EFFORT,configuration:r,jsonResponse:!0,registry:h}),U=this.noDeprecations?[]:await Promise.all(Array.from(Object.entries(p),async([te,ae])=>{let fe=await Zr.getPackageMetadata(W.parseIdent(te),{project:o});return _e.mapAndFilter(ae,ue=>{let{deprecated:me}=fe.versions[ue];return me?[te,ue,me]:_e.mapAndFilter.skip})})),V=await N;for(let[te,ae,fe]of U.flat(1))Object.hasOwn(V,te)&&V[te].some(ue=>kr.satisfiesWithPrereleases(ae,ue.vulnerable_versions))||(V[te]??=[],V[te].push({id:`${te} (deprecation)`,title:fe.trim()||\"This package has been deprecated.\",severity:\"moderate\",vulnerable_versions:ae}));E=V});if(I.hasErrors())return I.exitCode();let v=mj(this.severity),x=Array.from(new Set([...r.get(\"npmAuditIgnoreAdvisories\"),...this.ignores])),C=Object.create(null);for(let[N,U]of Object.entries(E)){let V=U.filter(te=>!wj.default.isMatch(`${te.id}`,x)&&v.has(te.severity));V.length>0&&(C[N]=V.map(te=>{let ae=u.get(N);if(typeof ae>\"u\")throw new Error(\"Assertion failed: Expected the registry to only return packages that were requested\");let fe=[...ae.keys()].filter(me=>kr.satisfiesWithPrereleases(me,te.vulnerable_versions)),ue=new Map;for(let me of fe)for(let he of ae.get(me))ue.set(he.locatorHash,he);return{...te,versions:fe,dependents:[...ue.values()]}}))}let R=Object.keys(C).length>0;return R?($s.emitTree(yj(C),{configuration:r,json:this.json,stdout:this.context.stdout,separators:2}),1):(await Lt.start({configuration:r,includeFooter:!1,json:this.json,stdout:this.context.stdout},async N=>{N.reportInfo(1,\"No audit suggestions\")}),R?1:0)}};q0.paths=[[\"npm\",\"audit\"]],q0.usage=nt.Usage({description:\"perform a vulnerability audit against the installed packages\",details:`\n      This command checks for known security reports on the packages you use. The reports are by default extracted from the npm registry, and may or may not be relevant to your actual program (not all vulnerabilities affect all code paths).\n\n      For consistency with our other commands the default is to only check the direct dependencies for the active workspace. To extend this search to all workspaces, use \\`-A,--all\\`. To extend this search to both direct and transitive dependencies, use \\`-R,--recursive\\`.\n\n      Applying the \\`--severity\\` flag will limit the audit table to vulnerabilities of the corresponding severity and above. Valid values are ${aw.map(r=>`\\`${r}\\``).join(\", \")}.\n\n      If the \\`--json\\` flag is set, Yarn will print the output exactly as received from the registry. Regardless of this flag, the process will exit with a non-zero exit code if a report is found for the selected packages.\n\n      If certain packages produce false positives for a particular environment, the \\`--exclude\\` flag can be used to exclude any number of packages from the audit. This can also be set in the configuration file with the \\`npmAuditExcludePackages\\` option.\n\n      If particular advisories are needed to be ignored, the \\`--ignore\\` flag can be used with Advisory ID's to ignore any number of advisories in the audit report. This can also be set in the configuration file with the \\`npmAuditIgnoreAdvisories\\` option.\n\n      To understand the dependency tree requiring vulnerable packages, check the raw report with the \\`--json\\` flag or use \\`yarn why package\\` to get more information as to who depends on them.\n    `,examples:[[\"Checks for known security issues with the installed packages. The output is a list of known issues.\",\"yarn npm audit\"],[\"Audit dependencies in all workspaces\",\"yarn npm audit --all\"],[\"Limit auditing to `dependencies` (excludes `devDependencies`)\",\"yarn npm audit --environment production\"],[\"Show audit report as valid JSON\",\"yarn npm audit --json\"],[\"Audit all direct and transitive dependencies\",\"yarn npm audit --recursive\"],[\"Output moderate (or more severe) vulnerabilities\",\"yarn npm audit --severity moderate\"],[\"Exclude certain packages\",\"yarn npm audit --exclude package1 --exclude package2\"],[\"Ignore specific advisories\",\"yarn npm audit --ignore 1234567 --ignore 7654321\"]]});Ye();Ye();Pt();qt();var Ij=$e(Jn()),Bj=ve(\"util\"),G0=class extends ut{constructor(){super(...arguments);this.fields=ge.String(\"-f,--fields\",{description:\"A comma-separated list of manifest fields that should be displayed\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.packages=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd),a=typeof this.fields<\"u\"?new Set([\"name\",...this.fields.split(/\\s*,\\s*/)]):null,n=[],u=!1,A=await Lt.start({configuration:r,includeFooter:!1,json:this.json,stdout:this.context.stdout},async p=>{for(let h of this.packages){let E;if(h===\".\"){let ae=o.topLevelWorkspace;if(!ae.manifest.name)throw new it(`Missing ${de.pretty(r,\"name\",de.Type.CODE)} field in ${le.fromPortablePath(z.join(ae.cwd,dr.manifest))}`);E=W.makeDescriptor(ae.manifest.name,\"unknown\")}else E=W.parseDescriptor(h);let I=Zr.getIdentUrl(E),v=vj(await Zr.get(I,{configuration:r,ident:E,jsonResponse:!0,customErrorMessage:Zr.customPackageError})),x=Object.keys(v.versions).sort(Ij.default.compareLoose),R=v[\"dist-tags\"].latest||x[x.length-1],N=kr.validRange(E.range);if(N){let ae=Ij.default.maxSatisfying(x,N);ae!==null?R=ae:(p.reportWarning(0,`Unmet range ${W.prettyRange(r,E.range)}; falling back to the latest version`),u=!0)}else Object.hasOwn(v[\"dist-tags\"],E.range)?R=v[\"dist-tags\"][E.range]:E.range!==\"unknown\"&&(p.reportWarning(0,`Unknown tag ${W.prettyRange(r,E.range)}; falling back to the latest version`),u=!0);let U=v.versions[R],V={...v,...U,version:R,versions:x},te;if(a!==null){te={};for(let ae of a){let fe=V[ae];if(typeof fe<\"u\")te[ae]=fe;else{p.reportWarning(1,`The ${de.pretty(r,ae,de.Type.CODE)} field doesn't exist inside ${W.prettyIdent(r,E)}'s information`),u=!0;continue}}}else this.json||(delete V.dist,delete V.readme,delete V.users),te=V;p.reportJson(te),this.json||n.push(te)}});Bj.inspect.styles.name=\"cyan\";for(let p of n)(p!==n[0]||u)&&this.context.stdout.write(`\n`),this.context.stdout.write(`${(0,Bj.inspect)(p,{depth:1/0,colors:!0,compact:!1})}\n`);return A.exitCode()}};G0.paths=[[\"npm\",\"info\"]],G0.usage=nt.Usage({category:\"Npm-related commands\",description:\"show information about a package\",details:\"\\n      This command fetches information about a package from the npm registry and prints it in a tree format.\\n\\n      The package does not have to be installed locally, but needs to have been published (in particular, local changes will be ignored even for workspaces).\\n\\n      Append `@<range>` to the package argument to provide information specific to the latest version that satisfies the range or to the corresponding tagged version. If the range is invalid or if there is no version satisfying the range, the command will print a warning and fall back to the latest version.\\n\\n      If the `-f,--fields` option is set, it's a comma-separated list of fields which will be used to only display part of the package information.\\n\\n      By default, this command won't return the `dist`, `readme`, and `users` fields, since they are often very long. To explicitly request those fields, explicitly list them with the `--fields` flag or request the output in JSON mode.\\n    \",examples:[[\"Show all available information about react (except the `dist`, `readme`, and `users` fields)\",\"yarn npm info react\"],[\"Show all available information about react as valid JSON (including the `dist`, `readme`, and `users` fields)\",\"yarn npm info react --json\"],[\"Show all available information about react@16.12.0\",\"yarn npm info react@16.12.0\"],[\"Show all available information about react@next\",\"yarn npm info react@next\"],[\"Show the description of react\",\"yarn npm info react --fields description\"],[\"Show all available versions of react\",\"yarn npm info react --fields versions\"],[\"Show the readme of react\",\"yarn npm info react --fields readme\"],[\"Show a few fields of react\",\"yarn npm info react --fields homepage,repository\"]]});function vj(t){if(Array.isArray(t)){let e=[];for(let r of t)r=vj(r),r&&e.push(r);return e}else if(typeof t==\"object\"&&t!==null){let e={};for(let r of Object.keys(t)){if(r.startsWith(\"_\"))continue;let o=vj(t[r]);o&&(e[r]=o)}return e}else return t||null}Ye();Ye();qt();var wBe=$e(f2()),j0=class extends ut{constructor(){super(...arguments);this.scope=ge.String(\"-s,--scope\",{description:\"Login to the registry configured for a given scope\"});this.publish=ge.Boolean(\"--publish\",!1,{description:\"Login to the publish registry\"});this.alwaysAuth=ge.Boolean(\"--always-auth\",{description:\"Set the npmAlwaysAuth configuration\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),o=await $Q({configuration:r,cwd:this.context.cwd,publish:this.publish,scope:this.scope});return(await Lt.start({configuration:r,stdout:this.context.stdout,includeFooter:!1},async n=>{let u=await _vt({configuration:r,registry:o,report:n,stdin:this.context.stdin,stdout:this.context.stdout}),A=await Mvt(o,u,r);return await Uvt(o,A,{alwaysAuth:this.alwaysAuth,scope:this.scope}),n.reportInfo(0,\"Successfully logged in\")})).exitCode()}};j0.paths=[[\"npm\",\"login\"]],j0.usage=nt.Usage({category:\"Npm-related commands\",description:\"store new login info to access the npm registry\",details:\"\\n      This command will ask you for your username, password, and 2FA One-Time-Password (when it applies). It will then modify your local configuration (in your home folder, never in the project itself) to reference the new tokens thus generated.\\n\\n      Adding the `-s,--scope` flag will cause the authentication to be done against whatever registry is configured for the associated scope (see also `npmScopes`).\\n\\n      Adding the `--publish` flag will cause the authentication to be done against the registry used when publishing the package (see also `publishConfig.registry` and `npmPublishRegistry`).\\n    \",examples:[[\"Login to the default registry\",\"yarn npm login\"],[\"Login to the registry linked to the @my-scope registry\",\"yarn npm login --scope my-scope\"],[\"Login to the publish registry for the current package\",\"yarn npm login --publish\"]]});async function $Q({scope:t,publish:e,configuration:r,cwd:o}){return t&&e?$n.getScopeRegistry(t,{configuration:r,type:$n.RegistryType.PUBLISH_REGISTRY}):t?$n.getScopeRegistry(t,{configuration:r}):e?$n.getPublishRegistry((await fC(r,o)).manifest,{configuration:r}):$n.getDefaultRegistry({configuration:r})}async function Mvt(t,e,r){let o=`/-/user/org.couchdb.user:${encodeURIComponent(e.name)}`,a={_id:`org.couchdb.user:${e.name}`,name:e.name,password:e.password,type:\"user\",roles:[],date:new Date().toISOString()},n={attemptedAs:e.name,configuration:r,registry:t,jsonResponse:!0,authType:Zr.AuthType.NO_AUTH};try{return(await Zr.put(o,a,n)).token}catch(E){if(!(E.originalError?.name===\"HTTPError\"&&E.originalError?.response.statusCode===409))throw E}let u={...n,authType:Zr.AuthType.NO_AUTH,headers:{authorization:`Basic ${Buffer.from(`${e.name}:${e.password}`).toString(\"base64\")}`}},A=await Zr.get(o,u);for(let[E,I]of Object.entries(A))(!a[E]||E===\"roles\")&&(a[E]=I);let p=`${o}/-rev/${a._rev}`;return(await Zr.put(p,a,u)).token}async function Uvt(t,e,{alwaysAuth:r,scope:o}){let a=u=>A=>{let p=_e.isIndexableObject(A)?A:{},h=p[u],E=_e.isIndexableObject(h)?h:{};return{...p,[u]:{...E,...r!==void 0?{npmAlwaysAuth:r}:{},npmAuthToken:e}}},n=o?{npmScopes:a(o)}:{npmRegistries:a(t)};return await Ke.updateHomeConfiguration(n)}async function _vt({configuration:t,registry:e,report:r,stdin:o,stdout:a}){r.reportInfo(0,`Logging in to ${de.pretty(t,e,de.Type.URL)}`);let n=!1;if(e.match(/^https:\\/\\/npm\\.pkg\\.github\\.com(\\/|$)/)&&(r.reportInfo(0,\"You seem to be using the GitHub Package Registry. Tokens must be generated with the 'repo', 'write:packages', and 'read:packages' permissions.\"),n=!0),r.reportSeparator(),t.env.YARN_IS_TEST_ENV)return{name:t.env.YARN_INJECT_NPM_USER||\"\",password:t.env.YARN_INJECT_NPM_PASSWORD||\"\"};let u=await(0,wBe.prompt)([{type:\"input\",name:\"name\",message:\"Username:\",required:!0,onCancel:()=>process.exit(130),stdin:o,stdout:a},{type:\"password\",name:\"password\",message:n?\"Token:\":\"Password:\",required:!0,onCancel:()=>process.exit(130),stdin:o,stdout:a}]);return r.reportSeparator(),u}Ye();Ye();qt();var lw=new Set([\"npmAuthIdent\",\"npmAuthToken\"]),Y0=class extends ut{constructor(){super(...arguments);this.scope=ge.String(\"-s,--scope\",{description:\"Logout of the registry configured for a given scope\"});this.publish=ge.Boolean(\"--publish\",!1,{description:\"Logout of the publish registry\"});this.all=ge.Boolean(\"-A,--all\",!1,{description:\"Logout of all registries\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),o=async()=>{let n=await $Q({configuration:r,cwd:this.context.cwd,publish:this.publish,scope:this.scope}),u=await Ke.find(this.context.cwd,this.context.plugins),A=W.makeIdent(this.scope??null,\"pkg\");return!$n.getAuthConfiguration(n,{configuration:u,ident:A}).get(\"npmAuthToken\")};return(await Lt.start({configuration:r,stdout:this.context.stdout},async n=>{if(this.all&&(await qvt(),n.reportInfo(0,\"Successfully logged out from everything\")),this.scope){await IBe(\"npmScopes\",this.scope),await o()?n.reportInfo(0,`Successfully logged out from ${this.scope}`):n.reportWarning(0,\"Scope authentication settings removed, but some other ones settings still apply to it\");return}let u=await $Q({configuration:r,cwd:this.context.cwd,publish:this.publish});await IBe(\"npmRegistries\",u),await o()?n.reportInfo(0,`Successfully logged out from ${u}`):n.reportWarning(0,\"Registry authentication settings removed, but some other ones settings still apply to it\")})).exitCode()}};Y0.paths=[[\"npm\",\"logout\"]],Y0.usage=nt.Usage({category:\"Npm-related commands\",description:\"logout of the npm registry\",details:\"\\n      This command will log you out by modifying your local configuration (in your home folder, never in the project itself) to delete all credentials linked to a registry.\\n\\n      Adding the `-s,--scope` flag will cause the deletion to be done against whatever registry is configured for the associated scope (see also `npmScopes`).\\n\\n      Adding the `--publish` flag will cause the deletion to be done against the registry used when publishing the package (see also `publishConfig.registry` and `npmPublishRegistry`).\\n\\n      Adding the `-A,--all` flag will cause the deletion to be done against all registries and scopes.\\n    \",examples:[[\"Logout of the default registry\",\"yarn npm logout\"],[\"Logout of the @my-scope scope\",\"yarn npm logout --scope my-scope\"],[\"Logout of the publish registry for the current package\",\"yarn npm logout --publish\"],[\"Logout of all registries\",\"yarn npm logout --all\"]]});function Hvt(t,e){let r=t[e];if(!_e.isIndexableObject(r))return!1;let o=new Set(Object.keys(r));if([...lw].every(n=>!o.has(n)))return!1;for(let n of lw)o.delete(n);if(o.size===0)return t[e]=void 0,!0;let a={...r};for(let n of lw)delete a[n];return t[e]=a,!0}async function qvt(){let t=e=>{let r=!1,o=_e.isIndexableObject(e)?{...e}:{};o.npmAuthToken&&(delete o.npmAuthToken,r=!0);for(let a of Object.keys(o))Hvt(o,a)&&(r=!0);if(Object.keys(o).length!==0)return r?o:e};return await Ke.updateHomeConfiguration({npmRegistries:t,npmScopes:t})}async function IBe(t,e){return await Ke.updateHomeConfiguration({[t]:r=>{let o=_e.isIndexableObject(r)?r:{};if(!Object.hasOwn(o,e))return r;let a=o[e],n=_e.isIndexableObject(a)?a:{},u=new Set(Object.keys(n));if([...lw].every(p=>!u.has(p)))return r;for(let p of lw)u.delete(p);if(u.size===0)return Object.keys(o).length===1?void 0:{...o,[e]:void 0};let A={};for(let p of lw)A[p]=void 0;return{...o,[e]:{...n,...A}}}})}Ye();qt();var W0=class extends ut{constructor(){super(...arguments);this.access=ge.String(\"--access\",{description:\"The access for the published package (public or restricted)\"});this.tag=ge.String(\"--tag\",\"latest\",{description:\"The tag on the registry that the package should be attached to\"});this.tolerateRepublish=ge.Boolean(\"--tolerate-republish\",!1,{description:\"Warn and exit when republishing an already existing version of a package\"});this.otp=ge.String(\"--otp\",{description:\"The OTP token to use with the command\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new nr(o.cwd,this.context.cwd);if(a.manifest.private)throw new it(\"Private workspaces cannot be published\");if(a.manifest.name===null||a.manifest.version===null)throw new it(\"Workspaces must have valid names and versions to be published on an external registry\");await o.restoreInstallState();let n=a.manifest.name,u=a.manifest.version,A=$n.getPublishRegistry(a.manifest,{configuration:r});return(await Lt.start({configuration:r,stdout:this.context.stdout},async h=>{if(this.tolerateRepublish)try{let E=await Zr.get(Zr.getIdentUrl(n),{configuration:r,registry:A,ident:n,jsonResponse:!0});if(!Object.hasOwn(E,\"versions\"))throw new Jt(15,'Registry returned invalid data for - missing \"versions\" field');if(Object.hasOwn(E.versions,u)){h.reportWarning(0,`Registry already knows about version ${u}; skipping.`);return}}catch(E){if(E.originalError?.response?.statusCode!==404)throw E}await un.maybeExecuteWorkspaceLifecycleScript(a,\"prepublish\",{report:h}),await wA.prepareForPack(a,{report:h},async()=>{let E=await wA.genPackList(a);for(let R of E)h.reportInfo(null,R);let I=await wA.genPackStream(a,E),v=await _e.bufferStream(I),x=await ow.getGitHead(a.cwd),C=await ow.makePublishBody(a,v,{access:this.access,tag:this.tag,registry:A,gitHead:x});await Zr.put(Zr.getIdentUrl(n),C,{configuration:r,registry:A,ident:n,otp:this.otp,jsonResponse:!0})}),h.reportInfo(0,\"Package archive published\")})).exitCode()}};W0.paths=[[\"npm\",\"publish\"]],W0.usage=nt.Usage({category:\"Npm-related commands\",description:\"publish the active workspace to the npm registry\",details:'\\n      This command will pack the active workspace into a fresh archive and upload it to the npm registry.\\n\\n      The package will by default be attached to the `latest` tag on the registry, but this behavior can be overridden by using the `--tag` option.\\n\\n      Note that for legacy reasons scoped packages are by default published with an access set to `restricted` (aka \"private packages\"). This requires you to register for a paid npm plan. In case you simply wish to publish a public scoped package to the registry (for free), just add the `--access public` flag. This behavior can be enabled by default through the `npmPublishAccess` settings.\\n    ',examples:[[\"Publish the active workspace\",\"yarn npm publish\"]]});Ye();qt();var BBe=$e(Jn());Ye();Pt();qt();var K0=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.package=ge.String({required:!1})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n;if(typeof this.package<\"u\")n=W.parseIdent(this.package);else{if(!a)throw new nr(o.cwd,this.context.cwd);if(!a.manifest.name)throw new it(`Missing 'name' field in ${le.fromPortablePath(z.join(a.cwd,dr.manifest))}`);n=a.manifest.name}let u=await Tv(n,r),p={children:_e.sortMap(Object.entries(u),([h])=>h).map(([h,E])=>({value:de.tuple(de.Type.RESOLUTION,{descriptor:W.makeDescriptor(n,h),locator:W.makeLocator(n,E)})}))};return $s.emitTree(p,{configuration:r,json:this.json,stdout:this.context.stdout})}};K0.paths=[[\"npm\",\"tag\",\"list\"]],K0.usage=nt.Usage({category:\"Npm-related commands\",description:\"list all dist-tags of a package\",details:`\n      This command will list all tags of a package from the npm registry.\n\n      If the package is not specified, Yarn will default to the current workspace.\n    `,examples:[[\"List all tags of package `my-pkg`\",\"yarn npm tag list my-pkg\"]]});async function Tv(t,e){let r=`/-/package${Zr.getIdentUrl(t)}/dist-tags`;return Zr.get(r,{configuration:e,ident:t,jsonResponse:!0,customErrorMessage:Zr.customPackageError})}var z0=class extends ut{constructor(){super(...arguments);this.package=ge.String();this.tag=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new nr(o.cwd,this.context.cwd);let n=W.parseDescriptor(this.package,!0),u=n.range;if(!BBe.default.valid(u))throw new it(`The range ${de.pretty(r,n.range,de.Type.RANGE)} must be a valid semver version`);let A=$n.getPublishRegistry(a.manifest,{configuration:r}),p=de.pretty(r,n,de.Type.IDENT),h=de.pretty(r,u,de.Type.RANGE),E=de.pretty(r,this.tag,de.Type.CODE);return(await Lt.start({configuration:r,stdout:this.context.stdout},async v=>{let x=await Tv(n,r);Object.hasOwn(x,this.tag)&&x[this.tag]===u&&v.reportWarning(0,`Tag ${E} is already set to version ${h}`);let C=`/-/package${Zr.getIdentUrl(n)}/dist-tags/${encodeURIComponent(this.tag)}`;await Zr.put(C,u,{configuration:r,registry:A,ident:n,jsonRequest:!0,jsonResponse:!0}),v.reportInfo(0,`Tag ${E} added to version ${h} of package ${p}`)})).exitCode()}};z0.paths=[[\"npm\",\"tag\",\"add\"]],z0.usage=nt.Usage({category:\"Npm-related commands\",description:\"add a tag for a specific version of a package\",details:`\n      This command will add a tag to the npm registry for a specific version of a package. If the tag already exists, it will be overwritten.\n    `,examples:[[\"Add a `beta` tag for version `2.3.4-beta.4` of package `my-pkg`\",\"yarn npm tag add my-pkg@2.3.4-beta.4 beta\"]]});Ye();qt();var V0=class extends ut{constructor(){super(...arguments);this.package=ge.String();this.tag=ge.String()}async execute(){if(this.tag===\"latest\")throw new it(\"The 'latest' tag cannot be removed.\");let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new nr(o.cwd,this.context.cwd);let n=W.parseIdent(this.package),u=$n.getPublishRegistry(a.manifest,{configuration:r}),A=de.pretty(r,this.tag,de.Type.CODE),p=de.pretty(r,n,de.Type.IDENT),h=await Tv(n,r);if(!Object.hasOwn(h,this.tag))throw new it(`${A} is not a tag of package ${p}`);return(await Lt.start({configuration:r,stdout:this.context.stdout},async I=>{let v=`/-/package${Zr.getIdentUrl(n)}/dist-tags/${encodeURIComponent(this.tag)}`;await Zr.del(v,{configuration:r,registry:u,ident:n,jsonResponse:!0}),I.reportInfo(0,`Tag ${A} removed from package ${p}`)})).exitCode()}};V0.paths=[[\"npm\",\"tag\",\"remove\"]],V0.usage=nt.Usage({category:\"Npm-related commands\",description:\"remove a tag from a package\",details:`\n      This command will remove a tag from a package from the npm registry.\n    `,examples:[[\"Remove the `beta` tag from package `my-pkg`\",\"yarn npm tag remove my-pkg beta\"]]});Ye();Ye();qt();var J0=class extends ut{constructor(){super(...arguments);this.scope=ge.String(\"-s,--scope\",{description:\"Print username for the registry configured for a given scope\"});this.publish=ge.Boolean(\"--publish\",!1,{description:\"Print username for the publish registry\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),o;return this.scope&&this.publish?o=$n.getScopeRegistry(this.scope,{configuration:r,type:$n.RegistryType.PUBLISH_REGISTRY}):this.scope?o=$n.getScopeRegistry(this.scope,{configuration:r}):this.publish?o=$n.getPublishRegistry((await fC(r,this.context.cwd)).manifest,{configuration:r}):o=$n.getDefaultRegistry({configuration:r}),(await Lt.start({configuration:r,stdout:this.context.stdout},async n=>{let u;try{u=await Zr.get(\"/-/whoami\",{configuration:r,registry:o,authType:Zr.AuthType.ALWAYS_AUTH,jsonResponse:!0,ident:this.scope?W.makeIdent(this.scope,\"\"):void 0})}catch(A){if(A.response?.statusCode===401||A.response?.statusCode===403){n.reportError(41,\"Authentication failed - your credentials may have expired\");return}else throw A}n.reportInfo(0,u.username)})).exitCode()}};J0.paths=[[\"npm\",\"whoami\"]],J0.usage=nt.Usage({category:\"Npm-related commands\",description:\"display the name of the authenticated user\",details:\"\\n      Print the username associated with the current authentication settings to the standard output.\\n\\n      When using `-s,--scope`, the username printed will be the one that matches the authentication settings of the registry associated with the given scope (those settings can be overriden using the `npmRegistries` map, and the registry associated with the scope is configured via the `npmScopes` map).\\n\\n      When using `--publish`, the registry we'll select will by default be the one used when publishing packages (`publishConfig.registry` or `npmPublishRegistry` if available, otherwise we'll fallback to the regular `npmRegistryServer`).\\n    \",examples:[[\"Print username for the default registry\",\"yarn npm whoami\"],[\"Print username for the registry on a given scope\",\"yarn npm whoami --scope company\"]]});var Gvt={configuration:{npmPublishAccess:{description:\"Default access of the published packages\",type:\"STRING\",default:null},npmAuditExcludePackages:{description:\"Array of glob patterns of packages to exclude from npm audit\",type:\"STRING\",default:[],isArray:!0},npmAuditIgnoreAdvisories:{description:\"Array of glob patterns of advisory IDs to exclude from npm audit\",type:\"STRING\",default:[],isArray:!0}},commands:[q0,G0,j0,Y0,W0,z0,K0,V0,J0]},jvt=Gvt;var Fj={};zt(Fj,{PatchCommand:()=>$0,PatchCommitCommand:()=>Z0,PatchFetcher:()=>Uv,PatchResolver:()=>_v,default:()=>lDt,patchUtils:()=>Pm});Ye();Ye();Pt();iA();var Pm={};zt(Pm,{applyPatchFile:()=>tF,diffFolders:()=>kj,ensureUnpatchedDescriptor:()=>Pj,ensureUnpatchedLocator:()=>nF,extractPackageToDisk:()=>xj,extractPatchFlags:()=>kBe,isParentRequired:()=>bj,isPatchDescriptor:()=>rF,isPatchLocator:()=>X0,loadPatchFiles:()=>Mv,makeDescriptor:()=>iF,makeLocator:()=>Sj,makePatchHash:()=>Qj,parseDescriptor:()=>Nv,parseLocator:()=>Ov,parsePatchFile:()=>Lv,unpatchDescriptor:()=>sDt,unpatchLocator:()=>oDt});Ye();Pt();Ye();Pt();var Yvt=/^@@ -(\\d+)(,(\\d+))? \\+(\\d+)(,(\\d+))? @@.*/;function cw(t){return z.relative(Bt.root,z.resolve(Bt.root,le.toPortablePath(t)))}function Wvt(t){let e=t.trim().match(Yvt);if(!e)throw new Error(`Bad header line: '${t}'`);return{original:{start:Math.max(Number(e[1]),1),length:Number(e[3]||1)},patched:{start:Math.max(Number(e[4]),1),length:Number(e[6]||1)}}}var Kvt=420,zvt=493;var vBe=()=>({semverExclusivity:null,diffLineFromPath:null,diffLineToPath:null,oldMode:null,newMode:null,deletedFileMode:null,newFileMode:null,renameFrom:null,renameTo:null,beforeHash:null,afterHash:null,fromPath:null,toPath:null,hunks:null}),Vvt=t=>({header:Wvt(t),parts:[]}),Jvt={[\"@\"]:\"header\",[\"-\"]:\"deletion\",[\"+\"]:\"insertion\",[\" \"]:\"context\",[\"\\\\\"]:\"pragma\",undefined:\"context\"};function Xvt(t){let e=[],r=vBe(),o=\"parsing header\",a=null,n=null;function u(){a&&(n&&(a.parts.push(n),n=null),r.hunks.push(a),a=null)}function A(){u(),e.push(r),r=vBe()}for(let p=0;p<t.length;p++){let h=t[p];if(o===\"parsing header\")if(h.startsWith(\"@@\"))o=\"parsing hunks\",r.hunks=[],p-=1;else if(h.startsWith(\"diff --git \")){r&&r.diffLineFromPath&&A();let E=h.match(/^diff --git a\\/(.*?) b\\/(.*?)\\s*$/);if(!E)throw new Error(`Bad diff line: ${h}`);r.diffLineFromPath=E[1],r.diffLineToPath=E[2]}else if(h.startsWith(\"old mode \"))r.oldMode=h.slice(9).trim();else if(h.startsWith(\"new mode \"))r.newMode=h.slice(9).trim();else if(h.startsWith(\"deleted file mode \"))r.deletedFileMode=h.slice(18).trim();else if(h.startsWith(\"new file mode \"))r.newFileMode=h.slice(14).trim();else if(h.startsWith(\"rename from \"))r.renameFrom=h.slice(12).trim();else if(h.startsWith(\"rename to \"))r.renameTo=h.slice(10).trim();else if(h.startsWith(\"index \")){let E=h.match(/(\\w+)\\.\\.(\\w+)/);if(!E)continue;r.beforeHash=E[1],r.afterHash=E[2]}else h.startsWith(\"semver exclusivity \")?r.semverExclusivity=h.slice(19).trim():h.startsWith(\"--- \")?r.fromPath=h.slice(6).trim():h.startsWith(\"+++ \")&&(r.toPath=h.slice(6).trim());else{let E=Jvt[h[0]]||null;switch(E){case\"header\":u(),a=Vvt(h);break;case null:o=\"parsing header\",A(),p-=1;break;case\"pragma\":{if(!h.startsWith(\"\\\\ No newline at end of file\"))throw new Error(`Unrecognized pragma in patch file: ${h}`);if(!n)throw new Error(\"Bad parser state: No newline at EOF pragma encountered without context\");n.noNewlineAtEndOfFile=!0}break;case\"context\":case\"deletion\":case\"insertion\":{if(!a)throw new Error(\"Bad parser state: Hunk lines encountered before hunk header\");n&&n.type!==E&&(a.parts.push(n),n=null),n||(n={type:E,lines:[],noNewlineAtEndOfFile:!1}),n.lines.push(h.slice(1))}break;default:_e.assertNever(E);break}}}A();for(let{hunks:p}of e)if(p)for(let h of p)$vt(h);return e}function Zvt(t){let e=[];for(let r of t){let{semverExclusivity:o,diffLineFromPath:a,diffLineToPath:n,oldMode:u,newMode:A,deletedFileMode:p,newFileMode:h,renameFrom:E,renameTo:I,beforeHash:v,afterHash:x,fromPath:C,toPath:R,hunks:N}=r,U=E?\"rename\":p?\"file deletion\":h?\"file creation\":N&&N.length>0?\"patch\":\"mode change\",V=null;switch(U){case\"rename\":{if(!E||!I)throw new Error(\"Bad parser state: rename from & to not given\");e.push({type:\"rename\",semverExclusivity:o,fromPath:cw(E),toPath:cw(I)}),V=I}break;case\"file deletion\":{let te=a||C;if(!te)throw new Error(\"Bad parse state: no path given for file deletion\");e.push({type:\"file deletion\",semverExclusivity:o,hunk:N&&N[0]||null,path:cw(te),mode:eF(p),hash:v})}break;case\"file creation\":{let te=n||R;if(!te)throw new Error(\"Bad parse state: no path given for file creation\");e.push({type:\"file creation\",semverExclusivity:o,hunk:N&&N[0]||null,path:cw(te),mode:eF(h),hash:x})}break;case\"patch\":case\"mode change\":V=R||n;break;default:_e.assertNever(U);break}V&&u&&A&&u!==A&&e.push({type:\"mode change\",semverExclusivity:o,path:cw(V),oldMode:eF(u),newMode:eF(A)}),V&&N&&N.length&&e.push({type:\"patch\",semverExclusivity:o,path:cw(V),hunks:N,beforeHash:v,afterHash:x})}if(e.length===0)throw new Error(\"Unable to parse patch file: No changes found. Make sure the patch is a valid UTF8 encoded string\");return e}function eF(t){let e=parseInt(t,8)&511;if(e!==Kvt&&e!==zvt)throw new Error(`Unexpected file mode string: ${t}`);return e}function Lv(t){let e=t.split(/\\n/g);return e[e.length-1]===\"\"&&e.pop(),Zvt(Xvt(e))}function $vt(t){let e=0,r=0;for(let{type:o,lines:a}of t.parts)switch(o){case\"context\":r+=a.length,e+=a.length;break;case\"deletion\":e+=a.length;break;case\"insertion\":r+=a.length;break;default:_e.assertNever(o);break}if(e!==t.header.original.length||r!==t.header.patched.length){let o=a=>a<0?a:`+${a}`;throw new Error(`hunk header integrity check failed (expected @@ ${o(t.header.original.length)} ${o(t.header.patched.length)} @@, got @@ ${o(e)} ${o(r)} @@)`)}}Ye();Pt();var uw=class extends Error{constructor(r,o){super(`Cannot apply hunk #${r+1}`);this.hunk=o}};async function Aw(t,e,r){let o=await t.lstatPromise(e),a=await r();typeof a<\"u\"&&(e=a),await t.lutimesPromise(e,o.atime,o.mtime)}async function tF(t,{baseFs:e=new Tn,dryRun:r=!1,version:o=null}={}){for(let a of t)if(!(a.semverExclusivity!==null&&o!==null&&!kr.satisfiesWithPrereleases(o,a.semverExclusivity)))switch(a.type){case\"file deletion\":if(r){if(!e.existsSync(a.path))throw new Error(`Trying to delete a file that doesn't exist: ${a.path}`)}else await Aw(e,z.dirname(a.path),async()=>{await e.unlinkPromise(a.path)});break;case\"rename\":if(r){if(!e.existsSync(a.fromPath))throw new Error(`Trying to move a file that doesn't exist: ${a.fromPath}`)}else await Aw(e,z.dirname(a.fromPath),async()=>{await Aw(e,z.dirname(a.toPath),async()=>{await Aw(e,a.fromPath,async()=>(await e.movePromise(a.fromPath,a.toPath),a.toPath))})});break;case\"file creation\":if(r){if(e.existsSync(a.path))throw new Error(`Trying to create a file that already exists: ${a.path}`)}else{let n=a.hunk?a.hunk.parts[0].lines.join(`\n`)+(a.hunk.parts[0].noNewlineAtEndOfFile?\"\":`\n`):\"\";await e.mkdirpPromise(z.dirname(a.path),{chmod:493,utimes:[vi.SAFE_TIME,vi.SAFE_TIME]}),await e.writeFilePromise(a.path,n,{mode:a.mode}),await e.utimesPromise(a.path,vi.SAFE_TIME,vi.SAFE_TIME)}break;case\"patch\":await Aw(e,a.path,async()=>{await rDt(a,{baseFs:e,dryRun:r})});break;case\"mode change\":{let u=(await e.statPromise(a.path)).mode;if(DBe(a.newMode)!==DBe(u))continue;await Aw(e,a.path,async()=>{await e.chmodPromise(a.path,a.newMode)})}break;default:_e.assertNever(a);break}}function DBe(t){return(t&64)>0}function PBe(t){return t.replace(/\\s+$/,\"\")}function tDt(t,e){return PBe(t)===PBe(e)}async function rDt({hunks:t,path:e},{baseFs:r,dryRun:o=!1}){let a=await r.statSync(e).mode,u=(await r.readFileSync(e,\"utf8\")).split(/\\n/),A=[],p=0,h=0;for(let I of t){let v=Math.max(h,I.header.patched.start+p),x=Math.max(0,v-h),C=Math.max(0,u.length-v-I.header.original.length),R=Math.max(x,C),N=0,U=0,V=null;for(;N<=R;){if(N<=x&&(U=v-N,V=SBe(I,u,U),V!==null)){N=-N;break}if(N<=C&&(U=v+N,V=SBe(I,u,U),V!==null))break;N+=1}if(V===null)throw new uw(t.indexOf(I),I);A.push(V),p+=N,h=U+I.header.original.length}if(o)return;let E=0;for(let I of A)for(let v of I)switch(v.type){case\"splice\":{let x=v.index+E;u.splice(x,v.numToDelete,...v.linesToInsert),E+=v.linesToInsert.length-v.numToDelete}break;case\"pop\":u.pop();break;case\"push\":u.push(v.line);break;default:_e.assertNever(v);break}await r.writeFilePromise(e,u.join(`\n`),{mode:a})}function SBe(t,e,r){let o=[];for(let a of t.parts)switch(a.type){case\"context\":case\"deletion\":{for(let n of a.lines){let u=e[r];if(u==null||!tDt(u,n))return null;r+=1}a.type===\"deletion\"&&(o.push({type:\"splice\",index:r-a.lines.length,numToDelete:a.lines.length,linesToInsert:[]}),a.noNewlineAtEndOfFile&&o.push({type:\"push\",line:\"\"}))}break;case\"insertion\":o.push({type:\"splice\",index:r,numToDelete:0,linesToInsert:a.lines}),a.noNewlineAtEndOfFile&&o.push({type:\"pop\"});break;default:_e.assertNever(a.type);break}return o}var iDt=/^builtin<([^>]+)>$/;function fw(t,e){let{protocol:r,source:o,selector:a,params:n}=W.parseRange(t);if(r!==\"patch:\")throw new Error(\"Invalid patch range\");if(o===null)throw new Error(\"Patch locators must explicitly define their source\");let u=a?a.split(/&/).map(E=>le.toPortablePath(E)):[],A=n&&typeof n.locator==\"string\"?W.parseLocator(n.locator):null,p=n&&typeof n.version==\"string\"?n.version:null,h=e(o);return{parentLocator:A,sourceItem:h,patchPaths:u,sourceVersion:p}}function rF(t){return t.range.startsWith(\"patch:\")}function X0(t){return t.reference.startsWith(\"patch:\")}function Nv(t){let{sourceItem:e,...r}=fw(t.range,W.parseDescriptor);return{...r,sourceDescriptor:e}}function Ov(t){let{sourceItem:e,...r}=fw(t.reference,W.parseLocator);return{...r,sourceLocator:e}}function sDt(t){let{sourceItem:e}=fw(t.range,W.parseDescriptor);return e}function oDt(t){let{sourceItem:e}=fw(t.reference,W.parseLocator);return e}function Pj(t){if(!rF(t))return t;let{sourceItem:e}=fw(t.range,W.parseDescriptor);return e}function nF(t){if(!X0(t))return t;let{sourceItem:e}=fw(t.reference,W.parseLocator);return e}function bBe({parentLocator:t,sourceItem:e,patchPaths:r,sourceVersion:o,patchHash:a},n){let u=t!==null?{locator:W.stringifyLocator(t)}:{},A=typeof o<\"u\"?{version:o}:{},p=typeof a<\"u\"?{hash:a}:{};return W.makeRange({protocol:\"patch:\",source:n(e),selector:r.join(\"&\"),params:{...A,...p,...u}})}function iF(t,{parentLocator:e,sourceDescriptor:r,patchPaths:o}){return W.makeDescriptor(t,bBe({parentLocator:e,sourceItem:r,patchPaths:o},W.stringifyDescriptor))}function Sj(t,{parentLocator:e,sourcePackage:r,patchPaths:o,patchHash:a}){return W.makeLocator(t,bBe({parentLocator:e,sourceItem:r,sourceVersion:r.version,patchPaths:o,patchHash:a},W.stringifyLocator))}function xBe({onAbsolute:t,onRelative:e,onProject:r,onBuiltin:o},a){let n=a.lastIndexOf(\"!\");n!==-1&&(a=a.slice(n+1));let u=a.match(iDt);return u!==null?o(u[1]):a.startsWith(\"~/\")?r(a.slice(2)):z.isAbsolute(a)?t(a):e(a)}function kBe(t){let e=t.lastIndexOf(\"!\");return{optional:(e!==-1?new Set(t.slice(0,e).split(/!/)):new Set).has(\"optional\")}}function bj(t){return xBe({onAbsolute:()=>!1,onRelative:()=>!0,onProject:()=>!1,onBuiltin:()=>!1},t)}async function Mv(t,e,r){let o=t!==null?await r.fetcher.fetch(t,r):null,a=o&&o.localPath?{packageFs:new gn(Bt.root),prefixPath:z.relative(Bt.root,o.localPath)}:o;o&&o!==a&&o.releaseFs&&o.releaseFs();let n=await _e.releaseAfterUseAsync(async()=>await Promise.all(e.map(async u=>{let A=kBe(u),p=await xBe({onAbsolute:async h=>await oe.readFilePromise(h,\"utf8\"),onRelative:async h=>{if(a===null)throw new Error(\"Assertion failed: The parent locator should have been fetched\");return await a.packageFs.readFilePromise(z.join(a.prefixPath,h),\"utf8\")},onProject:async h=>await oe.readFilePromise(z.join(r.project.cwd,h),\"utf8\"),onBuiltin:async h=>await r.project.configuration.firstHook(E=>E.getBuiltinPatch,r.project,h)},u);return{...A,source:p}})));for(let u of n)typeof u.source==\"string\"&&(u.source=u.source.replace(/\\r\\n?/g,`\n`));return n}async function xj(t,{cache:e,project:r}){let o=r.storedPackages.get(t.locatorHash);if(typeof o>\"u\")throw new Error(\"Assertion failed: Expected the package to be registered\");let a=nF(t),n=r.storedChecksums,u=new Qi,A=await oe.mktempPromise(),p=z.join(A,\"source\"),h=z.join(A,\"user\"),E=z.join(A,\".yarn-patch.json\"),I=r.configuration.makeFetcher(),v=[];try{let x,C;if(t.locatorHash===a.locatorHash){let R=await I.fetch(t,{cache:e,project:r,fetcher:I,checksums:n,report:u});v.push(()=>R.releaseFs?.()),x=R,C=R}else x=await I.fetch(t,{cache:e,project:r,fetcher:I,checksums:n,report:u}),v.push(()=>x.releaseFs?.()),C=await I.fetch(t,{cache:e,project:r,fetcher:I,checksums:n,report:u}),v.push(()=>C.releaseFs?.());await Promise.all([oe.copyPromise(p,x.prefixPath,{baseFs:x.packageFs}),oe.copyPromise(h,C.prefixPath,{baseFs:C.packageFs}),oe.writeJsonPromise(E,{locator:W.stringifyLocator(t),version:o.version})])}finally{for(let x of v)x()}return oe.detachTemp(A),h}async function kj(t,e){let r=le.fromPortablePath(t).replace(/\\\\/g,\"/\"),o=le.fromPortablePath(e).replace(/\\\\/g,\"/\"),{stdout:a,stderr:n}=await Ur.execvp(\"git\",[\"-c\",\"core.safecrlf=false\",\"diff\",\"--src-prefix=a/\",\"--dst-prefix=b/\",\"--ignore-cr-at-eol\",\"--full-index\",\"--no-index\",\"--no-renames\",\"--text\",r,o],{cwd:le.toPortablePath(process.cwd()),env:{...process.env,GIT_CONFIG_NOSYSTEM:\"1\",HOME:\"\",XDG_CONFIG_HOME:\"\",USERPROFILE:\"\"}});if(n.length>0)throw new Error(`Unable to diff directories. Make sure you have a recent version of 'git' available in PATH.\nThe following error was reported by 'git':\n${n}`);let u=r.startsWith(\"/\")?A=>A.slice(1):A=>A;return a.replace(new RegExp(`(a|b)(${_e.escapeRegExp(`/${u(r)}/`)})`,\"g\"),\"$1/\").replace(new RegExp(`(a|b)${_e.escapeRegExp(`/${u(o)}/`)}`,\"g\"),\"$1/\").replace(new RegExp(_e.escapeRegExp(`${r}/`),\"g\"),\"\").replace(new RegExp(_e.escapeRegExp(`${o}/`),\"g\"),\"\")}function Qj(t,e){let r=[];for(let{source:o}of t){if(o===null)continue;let a=Lv(o);for(let n of a){let{semverExclusivity:u,...A}=n;u!==null&&e!==null&&!kr.satisfiesWithPrereleases(e,u)||r.push(JSON.stringify(A))}}return wn.makeHash(`${3}`,...r).slice(0,6)}Ye();function QBe(t,{configuration:e,report:r}){for(let o of t.parts)for(let a of o.lines)switch(o.type){case\"context\":r.reportInfo(null,`  ${de.pretty(e,a,\"grey\")}`);break;case\"deletion\":r.reportError(28,`- ${de.pretty(e,a,de.Type.REMOVED)}`);break;case\"insertion\":r.reportError(28,`+ ${de.pretty(e,a,de.Type.ADDED)}`);break;default:_e.assertNever(o.type)}}var Uv=class{supports(e,r){return!!X0(e)}getLocalPath(e,r){return null}async fetch(e,r){let o=r.checksums.get(e.locatorHash)||null,[a,n,u]=await r.cache.fetchPackageFromCache(e,o,{onHit:()=>r.report.reportCacheHit(e),onMiss:()=>r.report.reportCacheMiss(e,`${W.prettyLocator(r.project.configuration,e)} can't be found in the cache and will be fetched from the disk`),loader:()=>this.patchPackage(e,r),...r.cacheOptions});return{packageFs:a,releaseFs:n,prefixPath:W.getIdentVendorPath(e),localPath:this.getLocalPath(e,r),checksum:u}}async patchPackage(e,r){let{parentLocator:o,sourceLocator:a,sourceVersion:n,patchPaths:u}=Ov(e),A=await Mv(o,u,r),p=await oe.mktempPromise(),h=z.join(p,\"current.zip\"),E=await r.fetcher.fetch(a,r),I=W.getIdentVendorPath(e),v=new Ji(h,{create:!0,level:r.project.configuration.get(\"compressionLevel\")});await _e.releaseAfterUseAsync(async()=>{await v.copyPromise(I,E.prefixPath,{baseFs:E.packageFs,stableSort:!0})},E.releaseFs),v.saveAndClose();for(let{source:x,optional:C}of A){if(x===null)continue;let R=new Ji(h,{level:r.project.configuration.get(\"compressionLevel\")}),N=new gn(z.resolve(Bt.root,I),{baseFs:R});try{await tF(Lv(x),{baseFs:N,version:n})}catch(U){if(!(U instanceof uw))throw U;let V=r.project.configuration.get(\"enableInlineHunks\"),te=!V&&!C?\" (set enableInlineHunks for details)\":\"\",ae=`${W.prettyLocator(r.project.configuration,e)}: ${U.message}${te}`,fe=ue=>{!V||QBe(U.hunk,{configuration:r.project.configuration,report:ue})};if(R.discardAndClose(),C){r.report.reportWarningOnce(66,ae,{reportExtra:fe});continue}else throw new Jt(66,ae,fe)}R.saveAndClose()}return new Ji(h,{level:r.project.configuration.get(\"compressionLevel\")})}};Ye();var _v=class{supportsDescriptor(e,r){return!!rF(e)}supportsLocator(e,r){return!!X0(e)}shouldPersistResolution(e,r){return!1}bindDescriptor(e,r,o){let{patchPaths:a}=Nv(e);return a.every(n=>!bj(n))?e:W.bindDescriptor(e,{locator:W.stringifyLocator(r)})}getResolutionDependencies(e,r){let{sourceDescriptor:o}=Nv(e);return{sourceDescriptor:r.project.configuration.normalizeDependency(o)}}async getCandidates(e,r,o){if(!o.fetchOptions)throw new Error(\"Assertion failed: This resolver cannot be used unless a fetcher is configured\");let{parentLocator:a,patchPaths:n}=Nv(e),u=await Mv(a,n,o.fetchOptions),A=r.sourceDescriptor;if(typeof A>\"u\")throw new Error(\"Assertion failed: The dependency should have been resolved\");let p=Qj(u,A.version);return[Sj(e,{parentLocator:a,sourcePackage:A,patchPaths:n,patchHash:p})]}async getSatisfying(e,r,o,a){let[n]=await this.getCandidates(e,r,a);return{locators:o.filter(u=>u.locatorHash===n.locatorHash),sorted:!1}}async resolve(e,r){let{sourceLocator:o}=Ov(e);return{...await r.resolver.resolve(o,r),...e}}};Ye();Pt();qt();var Z0=class extends ut{constructor(){super(...arguments);this.save=ge.Boolean(\"-s,--save\",!1,{description:\"Add the patch to your resolution entries\"});this.patchFolder=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new nr(o.cwd,this.context.cwd);await o.restoreInstallState();let n=z.resolve(this.context.cwd,le.toPortablePath(this.patchFolder)),u=z.join(n,\"../source\"),A=z.join(n,\"../.yarn-patch.json\");if(!oe.existsSync(u))throw new it(\"The argument folder didn't get created by 'yarn patch'\");let p=await kj(u,n),h=await oe.readJsonPromise(A),E=W.parseLocator(h.locator,!0);if(!o.storedPackages.has(E.locatorHash))throw new it(\"No package found in the project for the given locator\");if(!this.save){this.context.stdout.write(p);return}let I=r.get(\"patchFolder\"),v=z.join(I,`${W.slugifyLocator(E)}.patch`);await oe.mkdirPromise(I,{recursive:!0}),await oe.writeFilePromise(v,p);let x=[],C=new Map;for(let R of o.storedPackages.values()){if(W.isVirtualLocator(R))continue;let N=R.dependencies.get(E.identHash);if(!N)continue;let U=W.ensureDevirtualizedDescriptor(N),V=Pj(U),te=o.storedResolutions.get(V.descriptorHash);if(!te)throw new Error(\"Assertion failed: Expected the resolution to have been registered\");if(!o.storedPackages.get(te))throw new Error(\"Assertion failed: Expected the package to have been registered\");let fe=o.tryWorkspaceByLocator(R);if(fe)x.push(fe);else{let ue=o.originalPackages.get(R.locatorHash);if(!ue)throw new Error(\"Assertion failed: Expected the original package to have been registered\");let me=ue.dependencies.get(N.identHash);if(!me)throw new Error(\"Assertion failed: Expected the original dependency to have been registered\");C.set(me.descriptorHash,me)}}for(let R of x)for(let N of Ot.hardDependencies){let U=R.manifest[N].get(E.identHash);if(!U)continue;let V=iF(U,{parentLocator:null,sourceDescriptor:W.convertLocatorToDescriptor(E),patchPaths:[z.join(dr.home,z.relative(o.cwd,v))]});R.manifest[N].set(U.identHash,V)}for(let R of C.values()){let N=iF(R,{parentLocator:null,sourceDescriptor:W.convertLocatorToDescriptor(E),patchPaths:[z.join(dr.home,z.relative(o.cwd,v))]});o.topLevelWorkspace.manifest.resolutions.push({pattern:{descriptor:{fullName:W.stringifyIdent(N),description:R.range}},reference:N.range})}await o.persist()}};Z0.paths=[[\"patch-commit\"]],Z0.usage=nt.Usage({description:\"generate a patch out of a directory\",details:\"\\n      By default, this will print a patchfile on stdout based on the diff between the folder passed in and the original version of the package. Such file is suitable for consumption with the `patch:` protocol.\\n\\n      With the `-s,--save` option set, the patchfile won't be printed on stdout anymore and will instead be stored within a local file (by default kept within `.yarn/patches`, but configurable via the `patchFolder` setting). A `resolutions` entry will also be added to your top-level manifest, referencing the patched package via the `patch:` protocol.\\n\\n      Note that only folders generated by `yarn patch` are accepted as valid input for `yarn patch-commit`.\\n    \"});Ye();Pt();qt();var $0=class extends ut{constructor(){super(...arguments);this.update=ge.Boolean(\"-u,--update\",!1,{description:\"Reapply local patches that already apply to this packages\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.package=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Nr.find(r);if(!a)throw new nr(o.cwd,this.context.cwd);await o.restoreInstallState();let u=W.parseLocator(this.package);if(u.reference===\"unknown\"){let A=_e.mapAndFilter([...o.storedPackages.values()],p=>p.identHash!==u.identHash?_e.mapAndFilter.skip:W.isVirtualLocator(p)?_e.mapAndFilter.skip:X0(p)!==this.update?_e.mapAndFilter.skip:p);if(A.length===0)throw new it(\"No package found in the project for the given locator\");if(A.length>1)throw new it(`Multiple candidate packages found; explicitly choose one of them (use \\`yarn why <package>\\` to get more information as to who depends on them):\n${A.map(p=>`\n- ${W.prettyLocator(r,p)}`).join(\"\")}`);u=A[0]}if(!o.storedPackages.has(u.locatorHash))throw new it(\"No package found in the project for the given locator\");await Lt.start({configuration:r,json:this.json,stdout:this.context.stdout},async A=>{let p=nF(u),h=await xj(u,{cache:n,project:o});A.reportJson({locator:W.stringifyLocator(p),path:le.fromPortablePath(h)});let E=this.update?\" along with its current modifications\":\"\";A.reportInfo(0,`Package ${W.prettyLocator(r,p)} got extracted with success${E}!`),A.reportInfo(0,`You can now edit the following folder: ${de.pretty(r,le.fromPortablePath(h),\"magenta\")}`),A.reportInfo(0,`Once you are done run ${de.pretty(r,`yarn patch-commit -s ${process.platform===\"win32\"?'\"':\"\"}${le.fromPortablePath(h)}${process.platform===\"win32\"?'\"':\"\"}`,\"cyan\")} and Yarn will store a patchfile based on your changes.`)})}};$0.paths=[[\"patch\"]],$0.usage=nt.Usage({description:\"prepare a package for patching\",details:\"\\n      This command will cause a package to be extracted in a temporary directory intended to be editable at will.\\n\\n      Once you're done with your changes, run `yarn patch-commit -s path` (with `path` being the temporary directory you received) to generate a patchfile and register it into your top-level manifest via the `patch:` protocol. Run `yarn patch-commit -h` for more details.\\n\\n      Calling the command when you already have a patch won't import it by default (in other words, the default behavior is to reset existing patches). However, adding the `-u,--update` flag will import any current patch.\\n    \"});var aDt={configuration:{enableInlineHunks:{description:\"If true, the installs will print unmatched patch hunks\",type:\"BOOLEAN\",default:!1},patchFolder:{description:\"Folder where the patch files must be written\",type:\"ABSOLUTE_PATH\",default:\"./.yarn/patches\"}},commands:[Z0,$0],fetchers:[Uv],resolvers:[_v]},lDt=aDt;var Lj={};zt(Lj,{PnpmLinker:()=>Hv,default:()=>pDt});Ye();Pt();qt();var Hv=class{getCustomDataKey(){return JSON.stringify({name:\"PnpmLinker\",version:3})}supportsPackage(e,r){return this.isEnabled(r)}async findPackageLocation(e,r){if(!this.isEnabled(r))throw new Error(\"Assertion failed: Expected the pnpm linker to be enabled\");let o=this.getCustomDataKey(),a=r.project.linkersCustomData.get(o);if(!a)throw new it(`The project in ${de.pretty(r.project.configuration,`${r.project.cwd}/package.json`,de.Type.PATH)} doesn't seem to have been installed - running an install there might help`);let n=a.pathsByLocator.get(e.locatorHash);if(typeof n>\"u\")throw new it(`Couldn't find ${W.prettyLocator(r.project.configuration,e)} in the currently installed pnpm map - running an install might help`);return n.packageLocation}async findPackageLocator(e,r){if(!this.isEnabled(r))return null;let o=this.getCustomDataKey(),a=r.project.linkersCustomData.get(o);if(!a)throw new it(`The project in ${de.pretty(r.project.configuration,`${r.project.cwd}/package.json`,de.Type.PATH)} doesn't seem to have been installed - running an install there might help`);let n=e.match(/(^.*\\/node_modules\\/(@[^/]*\\/)?[^/]+)(\\/.*$)/);if(n){let p=a.locatorByPath.get(n[1]);if(p)return p}let u=e,A=e;do{A=u,u=z.dirname(A);let p=a.locatorByPath.get(A);if(p)return p}while(u!==A);return null}makeInstaller(e){return new Rj(e)}isEnabled(e){return e.project.configuration.get(\"nodeLinker\")===\"pnpm\"}},Rj=class{constructor(e){this.opts=e;this.asyncActions=new _e.AsyncActions(10);this.customData={pathsByLocator:new Map,locatorByPath:new Map};this.indexFolderPromise=PD(oe,{indexPath:z.join(e.project.configuration.get(\"globalFolder\"),\"index\")})}attachCustomData(e){}async installPackage(e,r,o){switch(e.linkType){case\"SOFT\":return this.installPackageSoft(e,r,o);case\"HARD\":return this.installPackageHard(e,r,o)}throw new Error(\"Assertion failed: Unsupported package link type\")}async installPackageSoft(e,r,o){let a=z.resolve(r.packageFs.getRealPath(),r.prefixPath),n=this.opts.project.tryWorkspaceByLocator(e)?z.join(a,dr.nodeModules):null;return this.customData.pathsByLocator.set(e.locatorHash,{packageLocation:a,dependenciesLocation:n}),{packageLocation:a,buildRequest:null}}async installPackageHard(e,r,o){let a=cDt(e,{project:this.opts.project}),n=a.packageLocation;this.customData.locatorByPath.set(n,W.stringifyLocator(e)),this.customData.pathsByLocator.set(e.locatorHash,a),o.holdFetchResult(this.asyncActions.set(e.locatorHash,async()=>{await oe.mkdirPromise(n,{recursive:!0}),await oe.copyPromise(n,r.prefixPath,{baseFs:r.packageFs,overwrite:!1,linkStrategy:{type:\"HardlinkFromIndex\",indexPath:await this.indexFolderPromise,autoRepair:!0}})}));let A=W.isVirtualLocator(e)?W.devirtualizeLocator(e):e,p={manifest:await Ot.tryFind(r.prefixPath,{baseFs:r.packageFs})??new Ot,misc:{hasBindingGyp:yA.hasBindingGyp(r)}},h=this.opts.project.getDependencyMeta(A,e.version),E=yA.extractBuildRequest(e,p,h,{configuration:this.opts.project.configuration});return{packageLocation:n,buildRequest:E}}async attachInternalDependencies(e,r){if(this.opts.project.configuration.get(\"nodeLinker\")!==\"pnpm\"||!FBe(e,{project:this.opts.project}))return;let o=this.customData.pathsByLocator.get(e.locatorHash);if(typeof o>\"u\")throw new Error(`Assertion failed: Expected the package to have been registered (${W.stringifyLocator(e)})`);let{dependenciesLocation:a}=o;!a||this.asyncActions.reduce(e.locatorHash,async n=>{await oe.mkdirPromise(a,{recursive:!0});let u=await uDt(a),A=new Map(u),p=[n],h=(I,v)=>{let x=v;FBe(v,{project:this.opts.project})||(this.opts.report.reportWarningOnce(0,\"The pnpm linker doesn't support providing different versions to workspaces' peer dependencies\"),x=W.devirtualizeLocator(v));let C=this.customData.pathsByLocator.get(x.locatorHash);if(typeof C>\"u\")throw new Error(`Assertion failed: Expected the package to have been registered (${W.stringifyLocator(v)})`);let R=W.stringifyIdent(I),N=z.join(a,R),U=z.relative(z.dirname(N),C.packageLocation),V=A.get(R);A.delete(R),p.push(Promise.resolve().then(async()=>{if(V){if(V.isSymbolicLink()&&await oe.readlinkPromise(N)===U)return;await oe.removePromise(N)}await oe.mkdirpPromise(z.dirname(N)),process.platform==\"win32\"&&this.opts.project.configuration.get(\"winLinkType\")===\"junctions\"?await oe.symlinkPromise(C.packageLocation,N,\"junction\"):await oe.symlinkPromise(U,N)}))},E=!1;for(let[I,v]of r)I.identHash===e.identHash&&(E=!0),h(I,v);!E&&!this.opts.project.tryWorkspaceByLocator(e)&&h(W.convertLocatorToDescriptor(e),e),p.push(ADt(a,A)),await Promise.all(p)})}async attachExternalDependents(e,r){throw new Error(\"External dependencies haven't been implemented for the pnpm linker\")}async finalizeInstall(){let e=TBe(this.opts.project);if(this.opts.project.configuration.get(\"nodeLinker\")!==\"pnpm\")await oe.removePromise(e);else{let r;try{r=new Set(await oe.readdirPromise(e))}catch{r=new Set}for(let{dependenciesLocation:o}of this.customData.pathsByLocator.values()){if(!o)continue;let a=z.contains(e,o);if(a===null)continue;let[n]=a.split(z.sep);r.delete(n)}await Promise.all([...r].map(async o=>{await oe.removePromise(z.join(e,o))}))}return await this.asyncActions.wait(),await Tj(e),this.opts.project.configuration.get(\"nodeLinker\")!==\"node-modules\"&&await Tj(RBe(this.opts.project)),{customData:this.customData}}};function RBe(t){return z.join(t.cwd,dr.nodeModules)}function TBe(t){return z.join(RBe(t),\".store\")}function cDt(t,{project:e}){let r=W.slugifyLocator(t),o=TBe(e),a=z.join(o,r,\"package\"),n=z.join(o,r,dr.nodeModules);return{packageLocation:a,dependenciesLocation:n}}function FBe(t,{project:e}){return!W.isVirtualLocator(t)||!e.tryWorkspaceByLocator(t)}async function uDt(t){let e=new Map,r=[];try{r=await oe.readdirPromise(t,{withFileTypes:!0})}catch(o){if(o.code!==\"ENOENT\")throw o}try{for(let o of r)if(!o.name.startsWith(\".\"))if(o.name.startsWith(\"@\")){let a=await oe.readdirPromise(z.join(t,o.name),{withFileTypes:!0});if(a.length===0)e.set(o.name,o);else for(let n of a)e.set(`${o.name}/${n.name}`,n)}else e.set(o.name,o)}catch(o){if(o.code!==\"ENOENT\")throw o}return e}async function ADt(t,e){let r=[],o=new Set;for(let a of e.keys()){r.push(oe.removePromise(z.join(t,a)));let n=W.tryParseIdent(a)?.scope;n&&o.add(`@${n}`)}return Promise.all(r).then(()=>Promise.all([...o].map(a=>Tj(z.join(t,a)))))}async function Tj(t){try{await oe.rmdirPromise(t)}catch(e){if(e.code!==\"ENOENT\"&&e.code!==\"ENOTEMPTY\")throw e}}var fDt={linkers:[Hv]},pDt=fDt;var qj={};zt(qj,{StageCommand:()=>eg,default:()=>vDt,stageUtils:()=>oF});Ye();Pt();qt();Ye();Pt();var oF={};zt(oF,{ActionType:()=>Nj,checkConsensus:()=>sF,expandDirectory:()=>Uj,findConsensus:()=>_j,findVcsRoot:()=>Oj,genCommitMessage:()=>Hj,getCommitPrefix:()=>LBe,isYarnFile:()=>Mj});Pt();var Nj=(n=>(n[n.CREATE=0]=\"CREATE\",n[n.DELETE=1]=\"DELETE\",n[n.ADD=2]=\"ADD\",n[n.REMOVE=3]=\"REMOVE\",n[n.MODIFY=4]=\"MODIFY\",n))(Nj||{});async function Oj(t,{marker:e}){do if(!oe.existsSync(z.join(t,e)))t=z.dirname(t);else return t;while(t!==\"/\");return null}function Mj(t,{roots:e,names:r}){if(r.has(z.basename(t)))return!0;do if(!e.has(t))t=z.dirname(t);else return!0;while(t!==\"/\");return!1}function Uj(t){let e=[],r=[t];for(;r.length>0;){let o=r.pop(),a=oe.readdirSync(o);for(let n of a){let u=z.resolve(o,n);oe.lstatSync(u).isDirectory()?r.push(u):e.push(u)}}return e}function sF(t,e){let r=0,o=0;for(let a of t)a!==\"wip\"&&(e.test(a)?r+=1:o+=1);return r>=o}function _j(t){let e=sF(t,/^(\\w\\(\\w+\\):\\s*)?\\w+s/),r=sF(t,/^(\\w\\(\\w+\\):\\s*)?[A-Z]/),o=sF(t,/^\\w\\(\\w+\\):/);return{useThirdPerson:e,useUpperCase:r,useComponent:o}}function LBe(t){return t.useComponent?\"chore(yarn): \":\"\"}var hDt=new Map([[0,\"create\"],[1,\"delete\"],[2,\"add\"],[3,\"remove\"],[4,\"update\"]]);function Hj(t,e){let r=LBe(t),o=[],a=e.slice().sort((n,u)=>n[0]-u[0]);for(;a.length>0;){let[n,u]=a.shift(),A=hDt.get(n);t.useUpperCase&&o.length===0&&(A=`${A[0].toUpperCase()}${A.slice(1)}`),t.useThirdPerson&&(A+=\"s\");let p=[u];for(;a.length>0&&a[0][0]===n;){let[,E]=a.shift();p.push(E)}p.sort();let h=p.shift();p.length===1?h+=\" (and one other)\":p.length>1&&(h+=` (and ${p.length} others)`),o.push(`${A} ${h}`)}return`${r}${o.join(\", \")}`}var gDt=\"Commit generated via `yarn stage`\",dDt=11;async function NBe(t){let{code:e,stdout:r}=await Ur.execvp(\"git\",[\"log\",\"-1\",\"--pretty=format:%H\"],{cwd:t});return e===0?r.trim():null}async function mDt(t,e){let r=[],o=e.filter(h=>z.basename(h.path)===\"package.json\");for(let{action:h,path:E}of o){let I=z.relative(t,E);if(h===4){let v=await NBe(t),{stdout:x}=await Ur.execvp(\"git\",[\"show\",`${v}:${I}`],{cwd:t,strict:!0}),C=await Ot.fromText(x),R=await Ot.fromFile(E),N=new Map([...R.dependencies,...R.devDependencies]),U=new Map([...C.dependencies,...C.devDependencies]);for(let[V,te]of U){let ae=W.stringifyIdent(te),fe=N.get(V);fe?fe.range!==te.range&&r.push([4,`${ae} to ${fe.range}`]):r.push([3,ae])}for(let[V,te]of N)U.has(V)||r.push([2,W.stringifyIdent(te)])}else if(h===0){let v=await Ot.fromFile(E);v.name?r.push([0,W.stringifyIdent(v.name)]):r.push([0,\"a package\"])}else if(h===1){let v=await NBe(t),{stdout:x}=await Ur.execvp(\"git\",[\"show\",`${v}:${I}`],{cwd:t,strict:!0}),C=await Ot.fromText(x);C.name?r.push([1,W.stringifyIdent(C.name)]):r.push([1,\"a package\"])}else throw new Error(\"Assertion failed: Unsupported action type\")}let{code:a,stdout:n}=await Ur.execvp(\"git\",[\"log\",`-${dDt}`,\"--pretty=format:%s\"],{cwd:t}),u=a===0?n.split(/\\n/g).filter(h=>h!==\"\"):[],A=_j(u);return Hj(A,r)}var yDt={[0]:[\" A \",\"?? \"],[4]:[\" M \"],[1]:[\" D \"]},EDt={[0]:[\"A  \"],[4]:[\"M  \"],[1]:[\"D  \"]},OBe={async findRoot(t){return await Oj(t,{marker:\".git\"})},async filterChanges(t,e,r,o){let{stdout:a}=await Ur.execvp(\"git\",[\"status\",\"-s\"],{cwd:t,strict:!0}),n=a.toString().split(/\\n/g),u=o?.staged?EDt:yDt;return[].concat(...n.map(p=>{if(p===\"\")return[];let h=p.slice(0,3),E=z.resolve(t,p.slice(3));if(!o?.staged&&h===\"?? \"&&p.endsWith(\"/\"))return Uj(E).map(I=>({action:0,path:I}));{let v=[0,4,1].find(x=>u[x].includes(h));return v!==void 0?[{action:v,path:E}]:[]}})).filter(p=>Mj(p.path,{roots:e,names:r}))},async genCommitMessage(t,e){return await mDt(t,e)},async makeStage(t,e){let r=e.map(o=>le.fromPortablePath(o.path));await Ur.execvp(\"git\",[\"add\",\"--\",...r],{cwd:t,strict:!0})},async makeCommit(t,e,r){let o=e.map(a=>le.fromPortablePath(a.path));await Ur.execvp(\"git\",[\"add\",\"-N\",\"--\",...o],{cwd:t,strict:!0}),await Ur.execvp(\"git\",[\"commit\",\"-m\",`${r}\n\n${gDt}\n`,\"--\",...o],{cwd:t,strict:!0})},async makeReset(t,e){let r=e.map(o=>le.fromPortablePath(o.path));await Ur.execvp(\"git\",[\"reset\",\"HEAD\",\"--\",...r],{cwd:t,strict:!0})}};var CDt=[OBe],eg=class extends ut{constructor(){super(...arguments);this.commit=ge.Boolean(\"-c,--commit\",!1,{description:\"Commit the staged files\"});this.reset=ge.Boolean(\"-r,--reset\",!1,{description:\"Remove all files from the staging area\"});this.dryRun=ge.Boolean(\"-n,--dry-run\",!1,{description:\"Print the commit message and the list of modified files without staging / committing\"});this.update=ge.Boolean(\"-u,--update\",!1,{hidden:!0})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o}=await St.find(r,this.context.cwd),{driver:a,root:n}=await wDt(o.cwd),u=[r.get(\"cacheFolder\"),r.get(\"globalFolder\"),r.get(\"virtualFolder\"),r.get(\"yarnPath\")];await r.triggerHook(I=>I.populateYarnPaths,o,I=>{u.push(I)});let A=new Set;for(let I of u)for(let v of IDt(n,I))A.add(v);let p=new Set([r.get(\"rcFilename\"),dr.lockfile,dr.manifest]),h=await a.filterChanges(n,A,p),E=await a.genCommitMessage(n,h);if(this.dryRun)if(this.commit)this.context.stdout.write(`${E}\n`);else for(let I of h)this.context.stdout.write(`${le.fromPortablePath(I.path)}\n`);else if(this.reset){let I=await a.filterChanges(n,A,p,{staged:!0});I.length===0?this.context.stdout.write(\"No staged changes found!\"):await a.makeReset(n,I)}else h.length===0?this.context.stdout.write(\"No changes found!\"):this.commit?await a.makeCommit(n,h,E):(await a.makeStage(n,h),this.context.stdout.write(E))}};eg.paths=[[\"stage\"]],eg.usage=nt.Usage({description:\"add all yarn files to your vcs\",details:\"\\n      This command will add to your staging area the files belonging to Yarn (typically any modified `package.json` and `.yarnrc.yml` files, but also linker-generated files, cache data, etc). It will take your ignore list into account, so the cache files won't be added if the cache is ignored in a `.gitignore` file (assuming you use Git).\\n\\n      Running `--reset` will instead remove them from the staging area (the changes will still be there, but won't be committed until you stage them back).\\n\\n      Since the staging area is a non-existent concept in Mercurial, Yarn will always create a new commit when running this command on Mercurial repositories. You can get this behavior when using Git by using the `--commit` flag which will directly create a commit.\\n    \",examples:[[\"Adds all modified project files to the staging area\",\"yarn stage\"],[\"Creates a new commit containing all modified project files\",\"yarn stage --commit\"]]});async function wDt(t){let e=null,r=null;for(let o of CDt)if((r=await o.findRoot(t))!==null){e=o;break}if(e===null||r===null)throw new it(\"No stage driver has been found for your current project\");return{driver:e,root:r}}function IDt(t,e){let r=[];if(e===null)return r;for(;;){(e===t||e.startsWith(`${t}/`))&&r.push(e);let o;try{o=oe.statSync(e)}catch{break}if(o.isSymbolicLink())e=z.resolve(z.dirname(e),oe.readlinkSync(e));else break}return r}var BDt={commands:[eg]},vDt=BDt;var Gj={};zt(Gj,{default:()=>FDt});Ye();Ye();Pt();var _Be=$e(Jn());Ye();var MBe=$e(JH()),DDt=\"e8e1bd300d860104bb8c58453ffa1eb4\",PDt=\"OFCNCOG2CU\",UBe=async(t,e)=>{let r=W.stringifyIdent(t),a=SDt(e).initIndex(\"npm-search\");try{return(await a.getObject(r,{attributesToRetrieve:[\"types\"]})).types?.ts===\"definitely-typed\"}catch{return!1}},SDt=t=>(0,MBe.default)(PDt,DDt,{requester:{async send(r){try{let o=await nn.request(r.url,r.data||null,{configuration:t,headers:r.headers});return{content:o.body,isTimedOut:!1,status:o.statusCode}}catch(o){return{content:o.response.body,isTimedOut:!1,status:o.response.statusCode}}}}});var HBe=t=>t.scope?`${t.scope}__${t.name}`:`${t.name}`,bDt=async(t,e,r,o)=>{if(r.scope===\"types\")return;let{project:a}=t,{configuration:n}=a;if(!(n.get(\"tsEnableAutoTypes\")??(oe.existsSync(z.join(t.cwd,\"tsconfig.json\"))||oe.existsSync(z.join(a.cwd,\"tsconfig.json\")))))return;let A=n.makeResolver(),p={project:a,resolver:A,report:new Qi};if(!await UBe(r,n))return;let E=HBe(r),I=W.parseRange(r.range).selector;if(!kr.validRange(I)){let N=n.normalizeDependency(r),U=await A.getCandidates(N,{},p);I=W.parseRange(U[0].reference).selector}let v=_Be.default.coerce(I);if(v===null)return;let x=`${Xc.Modifier.CARET}${v.major}`,C=W.makeDescriptor(W.makeIdent(\"types\",E),x),R=_e.mapAndFind(a.workspaces,N=>{let U=N.manifest.dependencies.get(r.identHash)?.descriptorHash,V=N.manifest.devDependencies.get(r.identHash)?.descriptorHash;if(U!==r.descriptorHash&&V!==r.descriptorHash)return _e.mapAndFind.skip;let te=[];for(let ae of Ot.allDependencies){let fe=N.manifest[ae].get(C.identHash);typeof fe>\"u\"||te.push([ae,fe])}return te.length===0?_e.mapAndFind.skip:te});if(typeof R<\"u\")for(let[N,U]of R)t.manifest[N].set(U.identHash,U);else{try{let N=n.normalizeDependency(C);if((await A.getCandidates(N,{},p)).length===0)return}catch{return}t.manifest[Xc.Target.DEVELOPMENT].set(C.identHash,C)}},xDt=async(t,e,r)=>{if(r.scope===\"types\")return;let{project:o}=t,{configuration:a}=o;if(!(a.get(\"tsEnableAutoTypes\")??(oe.existsSync(z.join(t.cwd,\"tsconfig.json\"))||oe.existsSync(z.join(o.cwd,\"tsconfig.json\")))))return;let u=HBe(r),A=W.makeIdent(\"types\",u);for(let p of Ot.allDependencies)typeof t.manifest[p].get(A.identHash)>\"u\"||t.manifest[p].delete(A.identHash)},kDt=(t,e)=>{e.publishConfig&&e.publishConfig.typings&&(e.typings=e.publishConfig.typings),e.publishConfig&&e.publishConfig.types&&(e.types=e.publishConfig.types)},QDt={configuration:{tsEnableAutoTypes:{description:\"Whether Yarn should auto-install @types/ dependencies on 'yarn add'\",type:\"BOOLEAN\",isNullable:!0,default:null}},hooks:{afterWorkspaceDependencyAddition:bDt,afterWorkspaceDependencyRemoval:xDt,beforeWorkspacePacking:kDt}},FDt=QDt;var zj={};zt(zj,{VersionApplyCommand:()=>tg,VersionCheckCommand:()=>rg,VersionCommand:()=>ng,default:()=>XDt,versionUtils:()=>dw});Ye();Ye();qt();var dw={};zt(dw,{Decision:()=>hw,applyPrerelease:()=>KBe,applyReleases:()=>Kj,applyStrategy:()=>lF,clearVersionFiles:()=>jj,getUndecidedDependentWorkspaces:()=>Gv,getUndecidedWorkspaces:()=>aF,openVersionFile:()=>gw,requireMoreDecisions:()=>zDt,resolveVersionFiles:()=>qv,suggestStrategy:()=>Wj,updateVersionFiles:()=>Yj,validateReleaseDecision:()=>pw});Ye();Pt();Nl();qt();var WBe=$e(YBe()),vA=$e(Jn()),KDt=/^(>=|[~^]|)(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(-(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(\\+[0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*)?$/,hw=(u=>(u.UNDECIDED=\"undecided\",u.DECLINE=\"decline\",u.MAJOR=\"major\",u.MINOR=\"minor\",u.PATCH=\"patch\",u.PRERELEASE=\"prerelease\",u))(hw||{});function pw(t){let e=vA.default.valid(t);return e||_e.validateEnum((0,WBe.default)(hw,\"UNDECIDED\"),t)}async function qv(t,{prerelease:e=null}={}){let r=new Map,o=t.configuration.get(\"deferredVersionFolder\");if(!oe.existsSync(o))return r;let a=await oe.readdirPromise(o);for(let n of a){if(!n.endsWith(\".yml\"))continue;let u=z.join(o,n),A=await oe.readFilePromise(u,\"utf8\"),p=Ki(A);for(let[h,E]of Object.entries(p.releases||{})){if(E===\"decline\")continue;let I=W.parseIdent(h),v=t.tryWorkspaceByIdent(I);if(v===null)throw new Error(`Assertion failed: Expected a release definition file to only reference existing workspaces (${z.basename(u)} references ${h})`);if(v.manifest.version===null)throw new Error(`Assertion failed: Expected the workspace to have a version (${W.prettyLocator(t.configuration,v.anchoredLocator)})`);let x=v.manifest.raw.stableVersion??v.manifest.version,C=r.get(v),R=lF(x,pw(E));if(R===null)throw new Error(`Assertion failed: Expected ${x} to support being bumped via strategy ${E}`);let N=typeof C<\"u\"?vA.default.gt(R,C)?R:C:R;r.set(v,N)}}return e&&(r=new Map([...r].map(([n,u])=>[n,KBe(u,{current:n.manifest.version,prerelease:e})]))),r}async function jj(t){let e=t.configuration.get(\"deferredVersionFolder\");!oe.existsSync(e)||await oe.removePromise(e)}async function Yj(t,e){let r=new Set(e),o=t.configuration.get(\"deferredVersionFolder\");if(!oe.existsSync(o))return;let a=await oe.readdirPromise(o);for(let n of a){if(!n.endsWith(\".yml\"))continue;let u=z.join(o,n),A=await oe.readFilePromise(u,\"utf8\"),p=Ki(A),h=p?.releases;if(!!h){for(let E of Object.keys(h)){let I=W.parseIdent(E),v=t.tryWorkspaceByIdent(I);(v===null||r.has(v))&&delete p.releases[E]}Object.keys(p.releases).length>0?await oe.changeFilePromise(u,Ba(new Ba.PreserveOrdering(p))):await oe.unlinkPromise(u)}}}async function gw(t,{allowEmpty:e=!1}={}){let r=t.configuration;if(r.projectCwd===null)throw new it(\"This command can only be run from within a Yarn project\");let o=await ra.fetchRoot(r.projectCwd),a=o!==null?await ra.fetchBase(o,{baseRefs:r.get(\"changesetBaseRefs\")}):null,n=o!==null?await ra.fetchChangedFiles(o,{base:a.hash,project:t}):[],u=r.get(\"deferredVersionFolder\"),A=n.filter(x=>z.contains(u,x)!==null);if(A.length>1)throw new it(`Your current branch contains multiple versioning files; this isn't supported:\n- ${A.map(x=>le.fromPortablePath(x)).join(`\n- `)}`);let p=new Set(_e.mapAndFilter(n,x=>{let C=t.tryWorkspaceByFilePath(x);return C===null?_e.mapAndFilter.skip:C}));if(A.length===0&&p.size===0&&!e)return null;let h=A.length===1?A[0]:z.join(u,`${wn.makeHash(Math.random().toString()).slice(0,8)}.yml`),E=oe.existsSync(h)?await oe.readFilePromise(h,\"utf8\"):\"{}\",I=Ki(E),v=new Map;for(let x of I.declined||[]){let C=W.parseIdent(x),R=t.getWorkspaceByIdent(C);v.set(R,\"decline\")}for(let[x,C]of Object.entries(I.releases||{})){let R=W.parseIdent(x),N=t.getWorkspaceByIdent(R);v.set(N,pw(C))}return{project:t,root:o,baseHash:a!==null?a.hash:null,baseTitle:a!==null?a.title:null,changedFiles:new Set(n),changedWorkspaces:p,releaseRoots:new Set([...p].filter(x=>x.manifest.version!==null)),releases:v,async saveAll(){let x={},C=[],R=[];for(let N of t.workspaces){if(N.manifest.version===null)continue;let U=W.stringifyIdent(N.anchoredLocator),V=v.get(N);V===\"decline\"?C.push(U):typeof V<\"u\"?x[U]=pw(V):p.has(N)&&R.push(U)}await oe.mkdirPromise(z.dirname(h),{recursive:!0}),await oe.changeFilePromise(h,Ba(new Ba.PreserveOrdering({releases:Object.keys(x).length>0?x:void 0,declined:C.length>0?C:void 0,undecided:R.length>0?R:void 0})))}}}function zDt(t){return aF(t).size>0||Gv(t).length>0}function aF(t){let e=new Set;for(let r of t.changedWorkspaces)r.manifest.version!==null&&(t.releases.has(r)||e.add(r));return e}function Gv(t,{include:e=new Set}={}){let r=[],o=new Map(_e.mapAndFilter([...t.releases],([n,u])=>u===\"decline\"?_e.mapAndFilter.skip:[n.anchoredLocator.locatorHash,n])),a=new Map(_e.mapAndFilter([...t.releases],([n,u])=>u!==\"decline\"?_e.mapAndFilter.skip:[n.anchoredLocator.locatorHash,n]));for(let n of t.project.workspaces)if(!(!e.has(n)&&(a.has(n.anchoredLocator.locatorHash)||o.has(n.anchoredLocator.locatorHash)))&&n.manifest.version!==null)for(let u of Ot.hardDependencies)for(let A of n.manifest.getForScope(u).values()){let p=t.project.tryWorkspaceByDescriptor(A);p!==null&&o.has(p.anchoredLocator.locatorHash)&&r.push([n,p])}return r}function Wj(t,e){let r=vA.default.clean(e);for(let o of Object.values(hw))if(o!==\"undecided\"&&o!==\"decline\"&&vA.default.inc(t,o)===r)return o;return null}function lF(t,e){if(vA.default.valid(e))return e;if(t===null)throw new it(`Cannot apply the release strategy \"${e}\" unless the workspace already has a valid version`);if(!vA.default.valid(t))throw new it(`Cannot apply the release strategy \"${e}\" on a non-semver version (${t})`);let r=vA.default.inc(t,e);if(r===null)throw new it(`Cannot apply the release strategy \"${e}\" on the specified version (${t})`);return r}function Kj(t,e,{report:r}){let o=new Map;for(let a of t.workspaces)for(let n of Ot.allDependencies)for(let u of a.manifest[n].values()){let A=t.tryWorkspaceByDescriptor(u);if(A===null||!e.has(A))continue;_e.getArrayWithDefault(o,A).push([a,n,u.identHash])}for(let[a,n]of e){let u=a.manifest.version;a.manifest.version=n,vA.default.prerelease(n)===null?delete a.manifest.raw.stableVersion:a.manifest.raw.stableVersion||(a.manifest.raw.stableVersion=u);let A=a.manifest.name!==null?W.stringifyIdent(a.manifest.name):null;r.reportInfo(0,`${W.prettyLocator(t.configuration,a.anchoredLocator)}: Bumped to ${n}`),r.reportJson({cwd:le.fromPortablePath(a.cwd),ident:A,oldVersion:u,newVersion:n});let p=o.get(a);if(!(typeof p>\"u\"))for(let[h,E,I]of p){let v=h.manifest[E].get(I);if(typeof v>\"u\")throw new Error(\"Assertion failed: The dependency should have existed\");let x=v.range,C=!1;if(x.startsWith(Xn.protocol)&&(x=x.slice(Xn.protocol.length),C=!0,x===a.relativeCwd))continue;let R=x.match(KDt);if(!R){r.reportWarning(0,`Couldn't auto-upgrade range ${x} (in ${W.prettyLocator(t.configuration,h.anchoredLocator)})`);continue}let N=`${R[1]}${n}`;C&&(N=`${Xn.protocol}${N}`);let U=W.makeDescriptor(v,N);h.manifest[E].set(I,U)}}}var VDt=new Map([[\"%n\",{extract:t=>t.length>=1?[t[0],t.slice(1)]:null,generate:(t=0)=>`${t+1}`}]]);function KBe(t,{current:e,prerelease:r}){let o=new vA.default.SemVer(e),a=o.prerelease.slice(),n=[];o.prerelease=[],o.format()!==t&&(a.length=0);let u=!0,A=r.split(/\\./g);for(let p of A){let h=VDt.get(p);if(typeof h>\"u\")n.push(p),a[0]===p?a.shift():u=!1;else{let E=u?h.extract(a):null;E!==null&&typeof E[0]==\"number\"?(n.push(h.generate(E[0])),a=E[1]):(n.push(h.generate()),u=!1)}}return o.prerelease&&(o.prerelease=[]),`${t}-${n.join(\".\")}`}var tg=class extends ut{constructor(){super(...arguments);this.all=ge.Boolean(\"--all\",!1,{description:\"Apply the deferred version changes on all workspaces\"});this.dryRun=ge.Boolean(\"--dry-run\",!1,{description:\"Print the versions without actually generating the package archive\"});this.prerelease=ge.String(\"--prerelease\",{description:\"Add a prerelease identifier to new versions\",tolerateBoolean:!0});this.recursive=ge.Boolean(\"-R,--recursive\",{description:\"Release the transitive workspaces as well\"});this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"})}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Nr.find(r);if(!a)throw new nr(o.cwd,this.context.cwd);await o.restoreInstallState({restoreResolutions:!1});let u=await Lt.start({configuration:r,json:this.json,stdout:this.context.stdout},async A=>{let p=this.prerelease?typeof this.prerelease!=\"boolean\"?this.prerelease:\"rc.%n\":null,h=await qv(o,{prerelease:p}),E=new Map;if(this.all)E=h;else{let I=this.recursive?a.getRecursiveWorkspaceDependencies():[a];for(let v of I){let x=h.get(v);typeof x<\"u\"&&E.set(v,x)}}if(E.size===0){let I=h.size>0?\" Did you want to add --all?\":\"\";A.reportWarning(0,`The current workspace doesn't seem to require a version bump.${I}`);return}Kj(o,E,{report:A}),this.dryRun||(p||(this.all?await jj(o):await Yj(o,[...E.keys()])),A.reportSeparator())});return this.dryRun||u.hasErrors()?u.exitCode():await o.installWithNewReport({json:this.json,stdout:this.context.stdout},{cache:n})}};tg.paths=[[\"version\",\"apply\"]],tg.usage=nt.Usage({category:\"Release-related commands\",description:\"apply all the deferred version bumps at once\",details:`\n      This command will apply the deferred version changes and remove their definitions from the repository.\n\n      Note that if \\`--prerelease\\` is set, the given prerelease identifier (by default \\`rc.%n\\`) will be used on all new versions and the version definitions will be kept as-is.\n\n      By default only the current workspace will be bumped, but you can configure this behavior by using one of:\n\n      - \\`--recursive\\` to also apply the version bump on its dependencies\n      - \\`--all\\` to apply the version bump on all packages in the repository\n\n      Note that this command will also update the \\`workspace:\\` references across all your local workspaces, thus ensuring that they keep referring to the same workspaces even after the version bump.\n    `,examples:[[\"Apply the version change to the local workspace\",\"yarn version apply\"],[\"Apply the version change to all the workspaces in the local workspace\",\"yarn version apply --all\"]]});Ye();Pt();qt();var cF=$e(Jn());var rg=class extends ut{constructor(){super(...arguments);this.interactive=ge.Boolean(\"-i,--interactive\",{description:\"Open an interactive interface used to set version bumps\"})}async execute(){return this.interactive?await this.executeInteractive():await this.executeStandard()}async executeInteractive(){bC(this.context);let{Gem:r}=await Promise.resolve().then(()=>(cQ(),Bq)),{ScrollableItems:o}=await Promise.resolve().then(()=>(pQ(),fQ)),{FocusRequest:a}=await Promise.resolve().then(()=>(Dq(),Vwe)),{useListInput:n}=await Promise.resolve().then(()=>(AQ(),Jwe)),{renderForm:u}=await Promise.resolve().then(()=>(mQ(),dQ)),{Box:A,Text:p}=await Promise.resolve().then(()=>$e(sc())),{default:h,useCallback:E,useState:I}=await Promise.resolve().then(()=>$e(on())),v=await Ke.find(this.context.cwd,this.context.plugins),{project:x,workspace:C}=await St.find(v,this.context.cwd);if(!C)throw new nr(x.cwd,this.context.cwd);await x.restoreInstallState();let R=await gw(x);if(R===null||R.releaseRoots.size===0)return 0;if(R.root===null)throw new it(\"This command can only be run on Git repositories\");let N=()=>h.createElement(A,{flexDirection:\"row\",paddingBottom:1},h.createElement(A,{flexDirection:\"column\",width:60},h.createElement(A,null,h.createElement(p,null,\"Press \",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<up>\"),\"/\",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<down>\"),\" to select workspaces.\")),h.createElement(A,null,h.createElement(p,null,\"Press \",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<left>\"),\"/\",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<right>\"),\" to select release strategies.\"))),h.createElement(A,{flexDirection:\"column\"},h.createElement(A,{marginLeft:1},h.createElement(p,null,\"Press \",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<enter>\"),\" to save.\")),h.createElement(A,{marginLeft:1},h.createElement(p,null,\"Press \",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<ctrl+c>\"),\" to abort.\")))),U=({workspace:me,active:he,decision:Be,setDecision:we})=>{let g=me.manifest.raw.stableVersion??me.manifest.version;if(g===null)throw new Error(`Assertion failed: The version should have been set (${W.prettyLocator(v,me.anchoredLocator)})`);if(cF.default.prerelease(g)!==null)throw new Error(`Assertion failed: Prerelease identifiers shouldn't be found (${g})`);let Ee=[\"undecided\",\"decline\",\"patch\",\"minor\",\"major\"];n(Be,Ee,{active:he,minus:\"left\",plus:\"right\",set:we});let Pe=Be===\"undecided\"?h.createElement(p,{color:\"yellow\"},g):Be===\"decline\"?h.createElement(p,{color:\"green\"},g):h.createElement(p,null,h.createElement(p,{color:\"magenta\"},g),\" \\u2192 \",h.createElement(p,{color:\"green\"},cF.default.valid(Be)?Be:cF.default.inc(g,Be)));return h.createElement(A,{flexDirection:\"column\"},h.createElement(A,null,h.createElement(p,null,W.prettyLocator(v,me.anchoredLocator),\" - \",Pe)),h.createElement(A,null,Ee.map(ce=>h.createElement(A,{key:ce,paddingLeft:2},h.createElement(p,null,h.createElement(r,{active:ce===Be}),\" \",ce)))))},V=me=>{let he=new Set(R.releaseRoots),Be=new Map([...me].filter(([we])=>he.has(we)));for(;;){let we=Gv({project:R.project,releases:Be}),g=!1;if(we.length>0){for(let[Ee]of we)if(!he.has(Ee)){he.add(Ee),g=!0;let Pe=me.get(Ee);typeof Pe<\"u\"&&Be.set(Ee,Pe)}}if(!g)break}return{relevantWorkspaces:he,relevantReleases:Be}},te=()=>{let[me,he]=I(()=>new Map(R.releases)),Be=E((we,g)=>{let Ee=new Map(me);g!==\"undecided\"?Ee.set(we,g):Ee.delete(we);let{relevantReleases:Pe}=V(Ee);he(Pe)},[me,he]);return[me,Be]},ae=({workspaces:me,releases:he})=>{let Be=[];Be.push(`${me.size} total`);let we=0,g=0;for(let Ee of me){let Pe=he.get(Ee);typeof Pe>\"u\"?g+=1:Pe!==\"decline\"&&(we+=1)}return Be.push(`${we} release${we===1?\"\":\"s\"}`),Be.push(`${g} remaining`),h.createElement(p,{color:\"yellow\"},Be.join(\", \"))},ue=await u(({useSubmit:me})=>{let[he,Be]=te();me(he);let{relevantWorkspaces:we}=V(he),g=new Set([...we].filter(ne=>!R.releaseRoots.has(ne))),[Ee,Pe]=I(0),ce=E(ne=>{switch(ne){case a.BEFORE:Pe(Ee-1);break;case a.AFTER:Pe(Ee+1);break}},[Ee,Pe]);return h.createElement(A,{flexDirection:\"column\"},h.createElement(N,null),h.createElement(A,null,h.createElement(p,{wrap:\"wrap\"},\"The following files have been modified in your local checkout.\")),h.createElement(A,{flexDirection:\"column\",marginTop:1,paddingLeft:2},[...R.changedFiles].map(ne=>h.createElement(A,{key:ne},h.createElement(p,null,h.createElement(p,{color:\"grey\"},le.fromPortablePath(R.root)),le.sep,le.relative(le.fromPortablePath(R.root),le.fromPortablePath(ne)))))),R.releaseRoots.size>0&&h.createElement(h.Fragment,null,h.createElement(A,{marginTop:1},h.createElement(p,{wrap:\"wrap\"},\"Because of those files having been modified, the following workspaces may need to be released again (note that private workspaces are also shown here, because even though they won't be published, releasing them will allow us to flag their dependents for potential re-release):\")),g.size>3?h.createElement(A,{marginTop:1},h.createElement(ae,{workspaces:R.releaseRoots,releases:he})):null,h.createElement(A,{marginTop:1,flexDirection:\"column\"},h.createElement(o,{active:Ee%2===0,radius:1,size:2,onFocusRequest:ce},[...R.releaseRoots].map(ne=>h.createElement(U,{key:ne.cwd,workspace:ne,decision:he.get(ne)||\"undecided\",setDecision:ee=>Be(ne,ee)}))))),g.size>0?h.createElement(h.Fragment,null,h.createElement(A,{marginTop:1},h.createElement(p,{wrap:\"wrap\"},\"The following workspaces depend on other workspaces that have been marked for release, and thus may need to be released as well:\")),h.createElement(A,null,h.createElement(p,null,\"(Press \",h.createElement(p,{bold:!0,color:\"cyanBright\"},\"<tab>\"),\" to move the focus between the workspace groups.)\")),g.size>5?h.createElement(A,{marginTop:1},h.createElement(ae,{workspaces:g,releases:he})):null,h.createElement(A,{marginTop:1,flexDirection:\"column\"},h.createElement(o,{active:Ee%2===1,radius:2,size:2,onFocusRequest:ce},[...g].map(ne=>h.createElement(U,{key:ne.cwd,workspace:ne,decision:he.get(ne)||\"undecided\",setDecision:ee=>Be(ne,ee)}))))):null)},{versionFile:R},{stdin:this.context.stdin,stdout:this.context.stdout,stderr:this.context.stderr});if(typeof ue>\"u\")return 1;R.releases.clear();for(let[me,he]of ue)R.releases.set(me,he);await R.saveAll()}async executeStandard(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new nr(o.cwd,this.context.cwd);return await o.restoreInstallState(),(await Lt.start({configuration:r,stdout:this.context.stdout},async u=>{let A=await gw(o);if(A===null||A.releaseRoots.size===0)return;if(A.root===null)throw new it(\"This command can only be run on Git repositories\");if(u.reportInfo(0,`Your PR was started right after ${de.pretty(r,A.baseHash.slice(0,7),\"yellow\")} ${de.pretty(r,A.baseTitle,\"magenta\")}`),A.changedFiles.size>0){u.reportInfo(0,\"You have changed the following files since then:\"),u.reportSeparator();for(let v of A.changedFiles)u.reportInfo(null,`${de.pretty(r,le.fromPortablePath(A.root),\"gray\")}${le.sep}${le.relative(le.fromPortablePath(A.root),le.fromPortablePath(v))}`)}let p=!1,h=!1,E=aF(A);if(E.size>0){p||u.reportSeparator();for(let v of E)u.reportError(0,`${W.prettyLocator(r,v.anchoredLocator)} has been modified but doesn't have a release strategy attached`);p=!0}let I=Gv(A);for(let[v,x]of I)h||u.reportSeparator(),u.reportError(0,`${W.prettyLocator(r,v.anchoredLocator)} doesn't have a release strategy attached, but depends on ${W.prettyWorkspace(r,x)} which is planned for release.`),h=!0;(p||h)&&(u.reportSeparator(),u.reportInfo(0,\"This command detected that at least some workspaces have received modifications without explicit instructions as to how they had to be released (if needed).\"),u.reportInfo(0,\"To correct these errors, run `yarn version check --interactive` then follow the instructions.\"))})).exitCode()}};rg.paths=[[\"version\",\"check\"]],rg.usage=nt.Usage({category:\"Release-related commands\",description:\"check that all the relevant packages have been bumped\",details:\"\\n      **Warning:** This command currently requires Git.\\n\\n      This command will check that all the packages covered by the files listed in argument have been properly bumped or declined to bump.\\n\\n      In the case of a bump, the check will also cover transitive packages - meaning that should `Foo` be bumped, a package `Bar` depending on `Foo` will require a decision as to whether `Bar` will need to be bumped. This check doesn't cross packages that have declined to bump.\\n\\n      In case no arguments are passed to the function, the list of modified files will be generated by comparing the HEAD against `master`.\\n    \",examples:[[\"Check whether the modified packages need a bump\",\"yarn version check\"]]});Ye();qt();var uF=$e(Jn());var ng=class extends ut{constructor(){super(...arguments);this.deferred=ge.Boolean(\"-d,--deferred\",{description:\"Prepare the version to be bumped during the next release cycle\"});this.immediate=ge.Boolean(\"-i,--immediate\",{description:\"Bump the version immediately\"});this.strategy=ge.String()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!a)throw new nr(o.cwd,this.context.cwd);let n=r.get(\"preferDeferredVersions\");this.deferred&&(n=!0),this.immediate&&(n=!1);let u=uF.default.valid(this.strategy),A=this.strategy===\"decline\",p;if(u)if(a.manifest.version!==null){let E=Wj(a.manifest.version,this.strategy);E!==null?p=E:p=this.strategy}else p=this.strategy;else{let E=a.manifest.version;if(!A){if(E===null)throw new it(\"Can't bump the version if there wasn't a version to begin with - use 0.0.0 as initial version then run the command again.\");if(typeof E!=\"string\"||!uF.default.valid(E))throw new it(`Can't bump the version (${E}) if it's not valid semver`)}p=pw(this.strategy)}if(!n){let I=(await qv(o)).get(a);if(typeof I<\"u\"&&p!==\"decline\"){let v=lF(a.manifest.version,p);if(uF.default.lt(v,I))throw new it(`Can't bump the version to one that would be lower than the current deferred one (${I})`)}}let h=await gw(o,{allowEmpty:!0});return h.releases.set(a,p),await h.saveAll(),n?0:await this.cli.run([\"version\",\"apply\"])}};ng.paths=[[\"version\"]],ng.usage=nt.Usage({category:\"Release-related commands\",description:\"apply a new version to the current package\",details:\"\\n      This command will bump the version number for the given package, following the specified strategy:\\n\\n      - If `major`, the first number from the semver range will be increased (`X.0.0`).\\n      - If `minor`, the second number from the semver range will be increased (`0.X.0`).\\n      - If `patch`, the third number from the semver range will be increased (`0.0.X`).\\n      - If prefixed by `pre` (`premajor`, ...), a `-0` suffix will be set (`0.0.0-0`).\\n      - If `prerelease`, the suffix will be increased (`0.0.0-X`); the third number from the semver range will also be increased if there was no suffix in the previous version.\\n      - If `decline`, the nonce will be increased for `yarn version check` to pass without version bump.\\n      - If a valid semver range, it will be used as new version.\\n      - If unspecified, Yarn will ask you for guidance.\\n\\n      For more information about the `--deferred` flag, consult our documentation (https://yarnpkg.com/features/release-workflow#deferred-versioning).\\n    \",examples:[[\"Immediately bump the version to the next major\",\"yarn version major\"],[\"Prepare the version to be bumped to the next major\",\"yarn version major --deferred\"]]});var JDt={configuration:{deferredVersionFolder:{description:\"Folder where are stored the versioning files\",type:\"ABSOLUTE_PATH\",default:\"./.yarn/versions\"},preferDeferredVersions:{description:\"If true, running `yarn version` will assume the `--deferred` flag unless `--immediate` is set\",type:\"BOOLEAN\",default:!1}},commands:[tg,rg,ng]},XDt=JDt;var Vj={};zt(Vj,{WorkspacesFocusCommand:()=>ig,WorkspacesForeachCommand:()=>lp,default:()=>ePt});Ye();Ye();qt();var ig=class extends ut{constructor(){super(...arguments);this.json=ge.Boolean(\"--json\",!1,{description:\"Format the output as an NDJSON stream\"});this.production=ge.Boolean(\"--production\",!1,{description:\"Only install regular dependencies by omitting dev dependencies\"});this.all=ge.Boolean(\"-A,--all\",!1,{description:\"Install the entire project\"});this.workspaces=ge.Rest()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd),n=await Nr.find(r);await o.restoreInstallState({restoreResolutions:!1});let u;if(this.all)u=new Set(o.workspaces);else if(this.workspaces.length===0){if(!a)throw new nr(o.cwd,this.context.cwd);u=new Set([a])}else u=new Set(this.workspaces.map(A=>o.getWorkspaceByIdent(W.parseIdent(A))));for(let A of u)for(let p of this.production?[\"dependencies\"]:Ot.hardDependencies)for(let h of A.manifest.getForScope(p).values()){let E=o.tryWorkspaceByDescriptor(h);E!==null&&u.add(E)}for(let A of o.workspaces)u.has(A)?this.production&&A.manifest.devDependencies.clear():(A.manifest.installConfig=A.manifest.installConfig||{},A.manifest.installConfig.selfReferences=!1,A.manifest.dependencies.clear(),A.manifest.devDependencies.clear(),A.manifest.peerDependencies.clear(),A.manifest.scripts.clear());return await o.installWithNewReport({json:this.json,stdout:this.context.stdout},{cache:n,persistProject:!1})}};ig.paths=[[\"workspaces\",\"focus\"]],ig.usage=nt.Usage({category:\"Workspace-related commands\",description:\"install a single workspace and its dependencies\",details:\"\\n      This command will run an install as if the specified workspaces (and all other workspaces they depend on) were the only ones in the project. If no workspaces are explicitly listed, the active one will be assumed.\\n\\n      Note that this command is only very moderately useful when using zero-installs, since the cache will contain all the packages anyway - meaning that the only difference between a full install and a focused install would just be a few extra lines in the `.pnp.cjs` file, at the cost of introducing an extra complexity.\\n\\n      If the `-A,--all` flag is set, the entire project will be installed. Combine with `--production` to replicate the old `yarn install --production`.\\n    \"});Ye();Ye();Ye();qt();var mw=$e(Zo()),VBe=$e(sd());$a();var lp=class extends ut{constructor(){super(...arguments);this.from=ge.Array(\"--from\",{description:\"An array of glob pattern idents or paths from which to base any recursion\"});this.all=ge.Boolean(\"-A,--all\",{description:\"Run the command on all workspaces of a project\"});this.recursive=ge.Boolean(\"-R,--recursive\",{description:\"Run the command on the current workspace and all of its recursive dependencies\"});this.worktree=ge.Boolean(\"-W,--worktree\",{description:\"Run the command on all workspaces of the current worktree\"});this.verbose=ge.Counter(\"-v,--verbose\",{description:\"Increase level of logging verbosity up to 2 times\"});this.parallel=ge.Boolean(\"-p,--parallel\",!1,{description:\"Run the commands in parallel\"});this.interlaced=ge.Boolean(\"-i,--interlaced\",!1,{description:\"Print the output of commands in real-time instead of buffering it\"});this.jobs=ge.String(\"-j,--jobs\",{description:\"The maximum number of parallel tasks that the execution will be limited to; or `unlimited`\",validator:TT([Ks([\"unlimited\"]),aI(RT(),[NT(),LT(1)])])});this.topological=ge.Boolean(\"-t,--topological\",!1,{description:\"Run the command after all workspaces it depends on (regular) have finished\"});this.topologicalDev=ge.Boolean(\"--topological-dev\",!1,{description:\"Run the command after all workspaces it depends on (regular + dev) have finished\"});this.include=ge.Array(\"--include\",[],{description:\"An array of glob pattern idents or paths; only matching workspaces will be traversed\"});this.exclude=ge.Array(\"--exclude\",[],{description:\"An array of glob pattern idents or paths; matching workspaces won't be traversed\"});this.publicOnly=ge.Boolean(\"--no-private\",{description:\"Avoid running the command on private workspaces\"});this.since=ge.String(\"--since\",{description:\"Only include workspaces that have been changed since the specified ref.\",tolerateBoolean:!0});this.dryRun=ge.Boolean(\"-n,--dry-run\",{description:\"Print the commands that would be run, without actually running them\"});this.commandName=ge.String();this.args=ge.Proxy()}async execute(){let r=await Ke.find(this.context.cwd,this.context.plugins),{project:o,workspace:a}=await St.find(r,this.context.cwd);if(!this.all&&!a)throw new nr(o.cwd,this.context.cwd);await o.restoreInstallState();let n=this.cli.process([this.commandName,...this.args]),u=n.path.length===1&&n.path[0]===\"run\"&&typeof n.scriptName<\"u\"?n.scriptName:null;if(n.path.length===0)throw new it(\"Invalid subcommand name for iteration - use the 'run' keyword if you wish to execute a script\");let A=we=>{!this.dryRun||this.context.stdout.write(`${we}\n`)},p=()=>{let we=this.from.map(g=>mw.default.matcher(g));return o.workspaces.filter(g=>{let Ee=W.stringifyIdent(g.anchoredLocator),Pe=g.relativeCwd;return we.some(ce=>ce(Ee)||ce(Pe))})},h=[];if(this.since?(A(\"Option --since is set; selecting the changed workspaces as root for workspace selection\"),h=Array.from(await ra.fetchChangedWorkspaces({ref:this.since,project:o}))):this.from?(A(\"Option --from is set; selecting the specified workspaces\"),h=[...p()]):this.worktree?(A(\"Option --worktree is set; selecting the current workspace\"),h=[a]):this.recursive?(A(\"Option --recursive is set; selecting the current workspace\"),h=[a]):this.all&&(A(\"Option --all is set; selecting all workspaces\"),h=[...o.workspaces]),this.dryRun&&!this.all){for(let we of h)A(`\n- ${we.relativeCwd}\n  ${W.prettyLocator(r,we.anchoredLocator)}`);h.length>0&&A(\"\")}let E;if(this.recursive?this.since?(A(\"Option --recursive --since is set; recursively selecting all dependent workspaces\"),E=new Set(h.map(we=>[...we.getRecursiveWorkspaceDependents()]).flat())):(A(\"Option --recursive is set; recursively selecting all transitive dependencies\"),E=new Set(h.map(we=>[...we.getRecursiveWorkspaceDependencies()]).flat())):this.worktree?(A(\"Option --worktree is set; recursively selecting all nested workspaces\"),E=new Set(h.map(we=>[...we.getRecursiveWorkspaceChildren()]).flat())):E=null,E!==null&&(h=[...new Set([...h,...E])],this.dryRun))for(let we of E)A(`\n- ${we.relativeCwd}\n  ${W.prettyLocator(r,we.anchoredLocator)}`);let I=[],v=!1;if(u?.includes(\":\")){for(let we of o.workspaces)if(we.manifest.scripts.has(u)&&(v=!v,v===!1))break}for(let we of h){if(u&&!we.manifest.scripts.has(u)&&!v&&!(await un.getWorkspaceAccessibleBinaries(we)).has(u)){A(`Excluding ${we.relativeCwd} because it doesn't have a \"${u}\" script`);continue}if(!(u===r.env.npm_lifecycle_event&&we.cwd===a.cwd)){if(this.include.length>0&&!mw.default.isMatch(W.stringifyIdent(we.anchoredLocator),this.include)&&!mw.default.isMatch(we.relativeCwd,this.include)){A(`Excluding ${we.relativeCwd} because it doesn't match the --include filter`);continue}if(this.exclude.length>0&&(mw.default.isMatch(W.stringifyIdent(we.anchoredLocator),this.exclude)||mw.default.isMatch(we.relativeCwd,this.exclude))){A(`Excluding ${we.relativeCwd} because it matches the --include filter`);continue}if(this.publicOnly&&we.manifest.private===!0){A(`Excluding ${we.relativeCwd} because it's a private workspace and --no-private was set`);continue}I.push(we)}}if(this.dryRun)return 0;let x=this.verbose??(this.context.stdout.isTTY?1/0:0),C=x>0,R=x>1,N=this.parallel?this.jobs===\"unlimited\"?1/0:Number(this.jobs)||Math.ceil(Vi.availableParallelism()/2):1,U=N===1?!1:this.parallel,V=U?this.interlaced:!0,te=(0,VBe.default)(N),ae=new Map,fe=new Set,ue=0,me=null,he=!1,Be=await Lt.start({configuration:r,stdout:this.context.stdout,includePrefix:!1},async we=>{let g=async(Ee,{commandIndex:Pe})=>{if(he)return-1;!U&&R&&Pe>1&&we.reportSeparator();let ce=ZDt(Ee,{configuration:r,label:C,commandIndex:Pe}),[ne,ee]=zBe(we,{prefix:ce,interlaced:V}),[Ie,Fe]=zBe(we,{prefix:ce,interlaced:V});try{R&&we.reportInfo(null,`${ce?`${ce} `:\"\"}Process started`);let At=Date.now(),H=await this.cli.run([this.commandName,...this.args],{cwd:Ee.cwd,stdout:ne,stderr:Ie})||0;ne.end(),Ie.end(),await ee,await Fe;let at=Date.now();if(R){let Re=r.get(\"enableTimers\")?`, completed in ${de.pretty(r,at-At,de.Type.DURATION)}`:\"\";we.reportInfo(null,`${ce?`${ce} `:\"\"}Process exited (exit code ${H})${Re}`)}return H===130&&(he=!0,me=H),H}catch(At){throw ne.end(),Ie.end(),await ee,await Fe,At}};for(let Ee of I)ae.set(Ee.anchoredLocator.locatorHash,Ee);for(;ae.size>0&&!we.hasErrors();){let Ee=[];for(let[ne,ee]of ae){if(fe.has(ee.anchoredDescriptor.descriptorHash))continue;let Ie=!0;if(this.topological||this.topologicalDev){let Fe=this.topologicalDev?new Map([...ee.manifest.dependencies,...ee.manifest.devDependencies]):ee.manifest.dependencies;for(let At of Fe.values()){let H=o.tryWorkspaceByDescriptor(At);if(Ie=H===null||!ae.has(H.anchoredLocator.locatorHash),!Ie)break}}if(!!Ie&&(fe.add(ee.anchoredDescriptor.descriptorHash),Ee.push(te(async()=>{let Fe=await g(ee,{commandIndex:++ue});return ae.delete(ne),fe.delete(ee.anchoredDescriptor.descriptorHash),Fe})),!U))break}if(Ee.length===0){let ne=Array.from(ae.values()).map(ee=>W.prettyLocator(r,ee.anchoredLocator)).join(\", \");we.reportError(3,`Dependency cycle detected (${ne})`);return}let ce=(await Promise.all(Ee)).find(ne=>ne!==0);me===null&&(me=typeof ce<\"u\"?1:me),(this.topological||this.topologicalDev)&&typeof ce<\"u\"&&we.reportError(0,\"The command failed for workspaces that are depended upon by other workspaces; can't satisfy the dependency graph\")}});return me!==null?me:Be.exitCode()}};lp.paths=[[\"workspaces\",\"foreach\"]],lp.usage=nt.Usage({category:\"Workspace-related commands\",description:\"run a command on all workspaces\",details:\"\\n      This command will run a given sub-command on current and all its descendant workspaces. Various flags can alter the exact behavior of the command:\\n\\n      - If `-p,--parallel` is set, the commands will be ran in parallel; they'll by default be limited to a number of parallel tasks roughly equal to half your core number, but that can be overridden via `-j,--jobs`, or disabled by setting `-j unlimited`.\\n\\n      - If `-p,--parallel` and `-i,--interlaced` are both set, Yarn will print the lines from the output as it receives them. If `-i,--interlaced` wasn't set, it would instead buffer the output from each process and print the resulting buffers only after their source processes have exited.\\n\\n      - If `-t,--topological` is set, Yarn will only run the command after all workspaces that it depends on through the `dependencies` field have successfully finished executing. If `--topological-dev` is set, both the `dependencies` and `devDependencies` fields will be considered when figuring out the wait points.\\n\\n      - If `-A,--all` is set, Yarn will run the command on all the workspaces of a project.\\n\\n      - If `-R,--recursive` is set, Yarn will find workspaces to run the command on by recursively evaluating `dependencies` and `devDependencies` fields, instead of looking at the `workspaces` fields.\\n\\n      - If `-W,--worktree` is set, Yarn will find workspaces to run the command on by looking at the current worktree.\\n\\n      - If `--from` is set, Yarn will use the packages matching the 'from' glob as the starting point for any recursive search.\\n\\n      - If `--since` is set, Yarn will only run the command on workspaces that have been modified since the specified ref. By default Yarn will use the refs specified by the `changesetBaseRefs` configuration option.\\n\\n      - If `--dry-run` is set, Yarn will explain what it would do without actually doing anything.\\n\\n      - The command may apply to only some workspaces through the use of `--include` which acts as a whitelist. The `--exclude` flag will do the opposite and will be a list of packages that mustn't execute the script. Both flags accept glob patterns (if valid Idents and supported by [micromatch](https://github.com/micromatch/micromatch)). Make sure to escape the patterns, to prevent your own shell from trying to expand them.\\n\\n      The `-v,--verbose` flag can be passed up to twice: once to prefix output lines with the originating workspace's name, and again to include start/finish/timing log lines. Maximum verbosity is enabled by default in terminal environments.\\n\\n      If the command is `run` and the script being run does not exist the child workspace will be skipped without error.\\n    \",examples:[[\"Publish all packages\",\"yarn workspaces foreach -A npm publish --tolerate-republish\"],[\"Run the build script on all descendant packages\",\"yarn workspaces foreach -A run build\"],[\"Run the build script on current and all descendant packages in parallel, building package dependencies first\",\"yarn workspaces foreach -Apt run build\"],[\"Run the build script on several packages and all their dependencies, building dependencies first\",\"yarn workspaces foreach -Rpt --from '{workspace-a,workspace-b}' run build\"]]}),lp.schema=[cI(\"all\",Yu.Forbids,[\"from\",\"recursive\",\"since\",\"worktree\"],{missingIf:\"undefined\"}),OT([\"all\",\"recursive\",\"since\",\"worktree\"],{missingIf:\"undefined\"})];function zBe(t,{prefix:e,interlaced:r}){let o=t.createStreamReporter(e),a=new _e.DefaultStream;a.pipe(o,{end:!1}),a.on(\"finish\",()=>{o.end()});let n=new Promise(A=>{o.on(\"finish\",()=>{A(a.active)})});if(r)return[a,n];let u=new _e.BufferStream;return u.pipe(a,{end:!1}),u.on(\"finish\",()=>{a.end()}),[u,n]}function ZDt(t,{configuration:e,commandIndex:r,label:o}){if(!o)return null;let n=`[${W.stringifyIdent(t.anchoredLocator)}]:`,u=[\"#2E86AB\",\"#A23B72\",\"#F18F01\",\"#C73E1D\",\"#CCE2A3\"],A=u[r%u.length];return de.pretty(e,n,A)}var $Dt={commands:[ig,lp]},ePt=$Dt;var pC=()=>({modules:new Map([[\"@yarnpkg/cli\",a2],[\"@yarnpkg/core\",o2],[\"@yarnpkg/fslib\",zw],[\"@yarnpkg/libzip\",x1],[\"@yarnpkg/parsers\",rI],[\"@yarnpkg/shell\",T1],[\"clipanion\",hI],[\"semver\",tPt],[\"typanion\",zo],[\"@yarnpkg/plugin-essentials\",$8],[\"@yarnpkg/plugin-compat\",iH],[\"@yarnpkg/plugin-constraints\",wH],[\"@yarnpkg/plugin-dlx\",IH],[\"@yarnpkg/plugin-exec\",DH],[\"@yarnpkg/plugin-file\",SH],[\"@yarnpkg/plugin-git\",Z8],[\"@yarnpkg/plugin-github\",kH],[\"@yarnpkg/plugin-http\",QH],[\"@yarnpkg/plugin-init\",FH],[\"@yarnpkg/plugin-interactive-tools\",Tq],[\"@yarnpkg/plugin-link\",Lq],[\"@yarnpkg/plugin-nm\",yG],[\"@yarnpkg/plugin-npm\",dj],[\"@yarnpkg/plugin-npm-cli\",Dj],[\"@yarnpkg/plugin-pack\",Aj],[\"@yarnpkg/plugin-patch\",Fj],[\"@yarnpkg/plugin-pnp\",oG],[\"@yarnpkg/plugin-pnpm\",Lj],[\"@yarnpkg/plugin-stage\",qj],[\"@yarnpkg/plugin-typescript\",Gj],[\"@yarnpkg/plugin-version\",zj],[\"@yarnpkg/plugin-workspace-tools\",Vj]]),plugins:new Set([\"@yarnpkg/plugin-essentials\",\"@yarnpkg/plugin-compat\",\"@yarnpkg/plugin-constraints\",\"@yarnpkg/plugin-dlx\",\"@yarnpkg/plugin-exec\",\"@yarnpkg/plugin-file\",\"@yarnpkg/plugin-git\",\"@yarnpkg/plugin-github\",\"@yarnpkg/plugin-http\",\"@yarnpkg/plugin-init\",\"@yarnpkg/plugin-interactive-tools\",\"@yarnpkg/plugin-link\",\"@yarnpkg/plugin-nm\",\"@yarnpkg/plugin-npm\",\"@yarnpkg/plugin-npm-cli\",\"@yarnpkg/plugin-pack\",\"@yarnpkg/plugin-patch\",\"@yarnpkg/plugin-pnp\",\"@yarnpkg/plugin-pnpm\",\"@yarnpkg/plugin-stage\",\"@yarnpkg/plugin-typescript\",\"@yarnpkg/plugin-version\",\"@yarnpkg/plugin-workspace-tools\"])});function ZBe({cwd:t,pluginConfiguration:e}){let r=new as({binaryLabel:\"Yarn Package Manager\",binaryName:\"yarn\",binaryVersion:rn??\"<unknown>\"});return Object.assign(r,{defaultContext:{...as.defaultContext,cwd:t,plugins:e,quiet:!1,stdin:process.stdin,stdout:process.stdout,stderr:process.stderr}})}function rPt(t){if(_e.parseOptionalBoolean(process.env.YARN_IGNORE_NODE))return!0;let r=process.versions.node,o=\">=18.12.0\";if(kr.satisfiesWithPrereleases(r,o))return!0;let a=new it(`This tool requires a Node version compatible with ${o} (got ${r}). Upgrade Node, or set \\`YARN_IGNORE_NODE=1\\` in your environment.`);return as.defaultContext.stdout.write(t.error(a)),!1}async function $Be({selfPath:t,pluginConfiguration:e}){return await Ke.find(le.toPortablePath(process.cwd()),e,{strict:!1,usePathCheck:t})}function nPt(t,e,{yarnPath:r}){if(!oe.existsSync(r))return t.error(new Error(`The \"yarn-path\" option has been set, but the specified location doesn't exist (${r}).`)),1;process.on(\"SIGINT\",()=>{});let o={stdio:\"inherit\",env:{...process.env,YARN_IGNORE_PATH:\"1\"}};try{(0,JBe.execFileSync)(process.execPath,[le.fromPortablePath(r),...e],o)}catch(a){return a.status??1}return 0}function iPt(t,e){let r=null,o=e;return e.length>=2&&e[0]===\"--cwd\"?(r=le.toPortablePath(e[1]),o=e.slice(2)):e.length>=1&&e[0].startsWith(\"--cwd=\")?(r=le.toPortablePath(e[0].slice(6)),o=e.slice(1)):e[0]===\"add\"&&e[e.length-2]===\"--cwd\"&&(r=le.toPortablePath(e[e.length-1]),o=e.slice(0,e.length-2)),t.defaultContext.cwd=r!==null?z.resolve(r):z.cwd(),o}function sPt(t,{configuration:e}){if(!e.get(\"enableTelemetry\")||XBe.isCI||!process.stdout.isTTY)return;Ke.telemetry=new uC(e,\"puba9cdc10ec5790a2cf4969dd413a47270\");let o=/^@yarnpkg\\/plugin-(.*)$/;for(let a of e.plugins.keys())AC.has(a.match(o)?.[1]??\"\")&&Ke.telemetry?.reportPluginName(a);t.binaryVersion&&Ke.telemetry.reportVersion(t.binaryVersion)}function eve(t,{configuration:e}){for(let r of e.plugins.values())for(let o of r.commands||[])t.register(o)}async function oPt(t,e,{selfPath:r,pluginConfiguration:o}){if(!rPt(t))return 1;let a=await $Be({selfPath:r,pluginConfiguration:o}),n=a.get(\"yarnPath\"),u=a.get(\"ignorePath\");if(n&&!u)return nPt(t,e,{yarnPath:n});delete process.env.YARN_IGNORE_PATH;let A=iPt(t,e);sPt(t,{configuration:a}),eve(t,{configuration:a});let p=t.process(A,t.defaultContext);return p.help||Ke.telemetry?.reportCommandName(p.path.join(\" \")),await t.run(p,t.defaultContext)}async function ehe({cwd:t=z.cwd(),pluginConfiguration:e=pC()}={}){let r=ZBe({cwd:t,pluginConfiguration:e}),o=await $Be({pluginConfiguration:e,selfPath:null});return eve(r,{configuration:o}),r}async function nk(t,{cwd:e=z.cwd(),selfPath:r,pluginConfiguration:o}){let a=ZBe({cwd:e,pluginConfiguration:o});try{process.exitCode=await oPt(a,t,{selfPath:r,pluginConfiguration:o})}catch(n){as.defaultContext.stdout.write(a.error(n)),process.exitCode=1}finally{await oe.rmtempPromise()}}nk(process.argv.slice(2),{cwd:z.cwd(),selfPath:le.toPortablePath(le.resolve(process.argv[1])),pluginConfiguration:pC()});})();\n/*\nobject-assign\n(c) Sindre Sorhus\n@license MIT\n*/\n/*!\n * buildToken\n * Builds OAuth token prefix (helper function)\n *\n * @name buildToken\n * @function\n * @param {GitUrl} obj The parsed Git url object.\n * @return {String} token prefix\n */\n/*!\n * fill-range <https://github.com/jonschlinkert/fill-range>\n *\n * Copyright (c) 2014-present, Jon Schlinkert.\n * Licensed under the MIT License.\n */\n/*!\n * is-extglob <https://github.com/jonschlinkert/is-extglob>\n *\n * Copyright (c) 2014-2016, Jon Schlinkert.\n * Licensed under the MIT License.\n */\n/*!\n * is-glob <https://github.com/jonschlinkert/is-glob>\n *\n * Copyright (c) 2014-2017, Jon Schlinkert.\n * Released under the MIT License.\n */\n/*!\n * is-number <https://github.com/jonschlinkert/is-number>\n *\n * Copyright (c) 2014-present, Jon Schlinkert.\n * Released under the MIT License.\n */\n/*!\n * is-windows <https://github.com/jonschlinkert/is-windows>\n *\n * Copyright © 2015-2018, Jon Schlinkert.\n * Released under the MIT License.\n */\n/*!\n * to-regex-range <https://github.com/micromatch/to-regex-range>\n *\n * Copyright (c) 2015-present, Jon Schlinkert.\n * Released under the MIT License.\n */\n/**\n  @license\n  Copyright (c) 2015, Rebecca Turner\n\n  Permission to use, copy, modify, and/or distribute this software for any\n  purpose with or without fee is hereby granted, provided that the above\n  copyright notice and this permission notice appear in all copies.\n\n  THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\n  REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND\n  FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\n  INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\n  LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\n  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\n  PERFORMANCE OF THIS SOFTWARE.\n */\n/**\n  @license\n  Copyright Joyent, Inc. and other Node contributors.\n\n  Permission is hereby granted, free of charge, to any person obtaining a\n  copy of this software and associated documentation files (the\n  \"Software\"), to deal in the Software without restriction, including\n  without limitation the rights to use, copy, modify, merge, publish,\n  distribute, sublicense, and/or sell copies of the Software, and to permit\n  persons to whom the Software is furnished to do so, subject to the\n  following conditions:\n\n  The above copyright notice and this permission notice shall be included\n  in all copies or substantial portions of the Software.\n\n  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n  NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n  DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n  OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n  USE OR OTHER DEALINGS IN THE SOFTWARE.\n*/\n/**\n  @license\n  Copyright Node.js contributors. All rights reserved.\n\n  Permission is hereby granted, free of charge, to any person obtaining a copy\n  of this software and associated documentation files (the \"Software\"), to\n  deal in the Software without restriction, including without limitation the\n  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n  sell copies of the Software, and to permit persons to whom the Software is\n  furnished to do so, subject to the following conditions:\n\n  The above copyright notice and this permission notice shall be included in\n  all copies or substantial portions of the Software.\n\n  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n  IN THE SOFTWARE.\n*/\n/**\n  @license\n  The MIT License (MIT)\n\n  Copyright (c) 2014 Blake Embrey (hello@blakeembrey.com)\n\n  Permission is hereby granted, free of charge, to any person obtaining a copy\n  of this software and associated documentation files (the \"Software\"), to deal\n  in the Software without restriction, including without limitation the rights\n  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  copies of the Software, and to permit persons to whom the Software is\n  furnished to do so, subject to the following conditions:\n\n  The above copyright notice and this permission notice shall be included in\n  all copies or substantial portions of the Software.\n\n  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  THE SOFTWARE.\n*/\n/** @license React v0.18.0\n * scheduler.production.min.js\n *\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n/** @license React v0.24.0\n * react-reconciler.production.min.js\n *\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n/** @license React v16.13.1\n * react.production.min.js\n *\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n"
  },
  {
    "path": "examples/react-native/app/App.tsx",
    "content": "/**\n * Sample React Native App\n * https://github.com/facebook/react-native\n *\n * @format\n */\n\nimport React from 'react';\nimport {\n  Button,\n  SafeAreaView,\n  ScrollView,\n  StatusBar,\n  StyleSheet,\n  Text,\n  useColorScheme,\n  View,\n} from 'react-native';\nimport Toast from 'react-native-toast-message';\nimport {\n  Identify,\n  identify,\n  init,\n  track,\n} from '@amplitude/analytics-react-native';\n\nimport {Colors, Header} from 'react-native/Libraries/NewAppScreen';\n\n// Module-scope init mirrors the reproduce pattern from issue #181 — the SDK's\n// full module graph loads before any component renders, so any top-level\n// crash in the SDK (e.g. CJS circular-dep regression) surfaces on app launch.\ninit('YOUR_API_KEY');\n\nfunction App(): React.JSX.Element {\n  const isDarkMode = useColorScheme() === 'dark';\n\n  const backgroundStyle = {\n    backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,\n  };\n\n  const showToast = (message: string) => {\n    Toast.show({\n      type: 'success',\n      text1: 'Amplitude Response',\n      text2: message,\n    });\n  };\n\n  const trackEventAndShowToast = (eventName: string) => {\n    track(eventName).promise.then(e => {\n      showToast(e.message);\n    });\n  };\n\n  const trackIdentifyAndShowToast = () => {\n    identify(new Identify().set('react-native-test', 'yes')).promise.then(e => {\n      showToast(e.message);\n    });\n  };\n\n  return (\n    <SafeAreaView style={backgroundStyle}>\n      <StatusBar\n        barStyle={isDarkMode ? 'light-content' : 'dark-content'}\n        backgroundColor={backgroundStyle.backgroundColor}\n      />\n      <ScrollView\n        contentInsetAdjustmentBehavior=\"automatic\"\n        style={backgroundStyle}>\n        <Header />\n        <View style={styles.container}>\n          <Text style={styles.title}>Test Amplitude App</Text>\n          <Button\n            title=\"Track Event\"\n            onPress={() => trackEventAndShowToast('test_event')}\n          />\n          <Button title=\"Track Identify\" onPress={trackIdentifyAndShowToast} />\n        </View>\n      </ScrollView>\n      <Toast />\n    </SafeAreaView>\n  );\n}\n\nconst styles = StyleSheet.create({\n  container: {\n    gap: 10,\n  },\n  title: {\n    textAlign: 'center',\n    color: 'black',\n  },\n});\n\nexport default App;\n"
  },
  {
    "path": "examples/react-native/app/Gemfile",
    "content": "source 'https://rubygems.org'\n\n# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version\nruby \">= 2.6.10\"\n\n# Cocoapods 1.15 introduced a bug which break the build. We will remove the upper\n# bound in the template on Cocoapods with next React Native release.\ngem 'cocoapods', '>= 1.13', '< 1.15'\ngem 'activesupport', '>= 6.1.7.5', '< 7.1.0'\n"
  },
  {
    "path": "examples/react-native/app/README.md",
    "content": "This is a minimal [**React Native**](https://reactnative.dev) example that exercises the Amplitude React Native SDK from the local workspace. It is wired up to consume the SDK via `workspace:*`, so changes to the SDK source are picked up on the next Metro bundle.\n\n- [Amplitude React Native SDK docs](https://www.docs.developers.amplitude.com/data/sdks/react-native-sdk/)\n- [React Native environment setup](https://reactnative.dev/docs/environment-setup)\n\n# Prerequisites\n\n- **Node `>=18`** (CI uses Node 20) — check: `node -v`\n- **[pnpm](https://pnpm.io/installation)** — check: `pnpm -v`\n- **Xcode + iOS Simulator** (for iOS) — check: `xcodebuild -version && xcrun simctl list devices iOS available | head`\n- **Ruby 3.2.x** and Bundler — used for CocoaPods. Matches CI. macOS system Ruby (2.6) hits an `activesupport` `Logger` load-order bug, and Ruby 4.x is too new for the pinned cocoapods (`< 1.15`). Install with `brew install ruby@3.2`. **brew's `ruby@3.2` is keg-only** — installing it does NOT put it on your PATH automatically. You must export PATH in every shell that runs `bundle`/`pod` commands, or add the export to `~/.zshrc` to make it persistent. See [Setup](#setup) step 3 for the exact commands. Check: `ruby -v` (expect `3.2.x`) and `bundle -v`.\n- **UTF-8 locale** in the shell that runs `pod install`: `export LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8`. Without it, cocoapods 1.14.3 crashes with `Unicode Normalization not appropriate for ASCII-8BIT`. Check: `echo \"$LANG\"` (expect a `*.UTF-8` value).\n- **Android SDK** (for Android) — see [React Native environment setup](https://reactnative.dev/docs/environment-setup). Check: `echo \"$ANDROID_SDK_ROOT\"` and `adb --version`.\n\n# Setup\n\nRun these from the **repo root** unless noted. The app is a pnpm workspace package and no longer has its own lockfile.\n\n```bash\n# 1. Install workspace dependencies (from repo root)\npnpm install --frozen-lockfile\n\n# 2. Build the SDK and its workspace deps so Metro/Xcode can resolve workspace:*\npnpm --filter @amplitude/analytics-react-native... build\n\n# 3. Activate Ruby 3.2 and a UTF-8 locale for this shell.\n#    brew's ruby@3.2 is keg-only, so this export is required in every shell\n#    that runs bundle/pod commands. Add to ~/.zshrc to make it persistent.\nexport PATH=\"/opt/homebrew/opt/ruby@3.2/bin:$PATH\"\nexport LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8\n\n# Verify — both must succeed BEFORE running bundle install:\nruby -v       # expect 3.2.x  (if 2.6, the export above didn't take effect in this shell)\nwhich ruby    # expect /opt/homebrew/opt/ruby@3.2/bin/ruby\n\n# 4. Install CocoaPods for iOS\ncd examples/react-native/app/ios\nbundle install\nbundle exec pod install\n```\n\nWhat step 4 does:\n\n- `bundle install` reads [`Gemfile`](Gemfile) / `Gemfile.lock` and installs the project's Ruby gems (CocoaPods 1.14.x plus its transitive deps) into `vendor/bundle/`. This pins CocoaPods to a version the React Native 0.74 build is known to work with — the [`Gemfile`](Gemfile) constrains `cocoapods < 1.15` to avoid a 1.15-only RN build break.\n- `bundle exec pod install` runs that pinned `pod` binary (not whatever `pod` is on your global PATH). It reads `ios/Podfile`, downloads the iOS native dependencies — React Native core, Hermes, plus auto-linked native modules like `@react-native-async-storage/async-storage` — and generates `ios/app.xcworkspace`, which is the workspace Xcode actually builds against.\n\n# Configure\n\nReplace `YOUR_API_KEY` in [`App.tsx`](App.tsx) with your Amplitude project's API key.\n\n`init` is called at module scope rather than inside the component so any top-level SDK crash (e.g. a CJS circular-dep regression) surfaces on app launch.\n\n# Run\n\nFrom `examples/react-native/app`:\n\n```bash\n# Terminal 1: start Metro\npnpm start\n\n# Terminal 2: launch the app\npnpm ios\n# or\npnpm android\n```\n\n# Smoke test (Maestro)\n\nA [Maestro](https://maestro.mobile.dev/) flow at [`.maestro/smoke.yaml`](.maestro/smoke.yaml) launches the app and asserts that \"Test Amplitude App\" is visible within 15s.\n\n```bash\n# Install Maestro\ncurl -fsSL \"https://get.maestro.mobile.dev\" | bash\n\n# With a simulator booted and the app installed (e.g. via `pnpm ios`):\ncd examples/react-native/app\nmaestro test .maestro/smoke.yaml\n```\n\n# Monorepo notes\n\nThree pieces make the workspace setup work — keep them in sync if you change any of them:\n\n- [`package.json`](package.json) declares `\"@amplitude/analytics-react-native\": \"workspace:*\"` so the example consumes local SDK source instead of the published version.\n- [`.npmrc`](../../../.npmrc) at the repo root hoists `react-native`, `@babel/*`, `@react-native*`, and `metro*` packages. Metro cannot traverse pnpm's nested `.pnpm` store, so these need to be visible from a flat `node_modules`.\n- [`metro.config.js`](metro.config.js) sets `watchFolders` and `nodeModulesPaths` to include the workspace root so Metro picks up SDK edits and resolves the hoisted deps.\n\nThe app is registered as a workspace package in [`pnpm-workspace.yaml`](../../../pnpm-workspace.yaml).\n\n# CI\n\nPull requests run an iOS Maestro smoke test via [`.github/workflows/rn-smoke.yml`](../../../.github/workflows/rn-smoke.yml) on `macos-14` with an iPhone 15 simulator. If a local build fails, the workflow is the canonical reproduction — its step order matches this README.\n\n# Troubleshooting\n\n### Metro can't find `react-native` or `@babel/runtime`\n\nRe-run `pnpm install` at the **repo root** so hoisted deps land in the root `node_modules`. An install run from inside the app directory is not equivalent.\n\n### `ruby -v` still shows 2.6 after `brew install ruby@3.2`\n\nbrew's `ruby@3.2` is keg-only and is not added to your PATH automatically. Run the export, then re-verify:\n\n```bash\nexport PATH=\"/opt/homebrew/opt/ruby@3.2/bin:$PATH\"\nwhich ruby   # must be /opt/homebrew/opt/ruby@3.2/bin/ruby\nruby -v      # must be 3.2.x\n```\n\nThe export only applies to the shell where you ran it. To persist across shells, add it to `~/.zshrc`.\n\n### `bundle` fails with `Could not find 'bundler' (4.0.9)`\n\nYou're running `/usr/bin/bundle` (system Ruby 2.6's bundler), which doesn't have the bundler version that `Gemfile.lock` requires. Same fix: put `ruby@3.2` on PATH first (see above), then `which bundle` should resolve to `/opt/homebrew/opt/ruby@3.2/bin/bundle`.\n\n### `bundle exec pod install` fails with `uninitialized constant ActiveSupport::LoggerThreadSafeLevel::Logger`\n\nYou're on Ruby 2.6 (macOS system Ruby). `activesupport` 6.1.7.x has a `Logger` constant load-order bug on Ruby 2.6 that's fixed on 2.7+. Switch to Ruby 3.2 as above, then remove `vendor/bundle` and `Gemfile.lock` and re-run `bundle install`.\n\n### `bundle exec pod install` fails with `cannot load such file -- kconv`\n\nYou're on Ruby 4.0+. `kconv` was removed and cocoapods 1.14.3 still depends on it. Use Ruby 3.2 (see above).\n\n### `bundle exec pod install` fails with `Unicode Normalization not appropriate for ASCII-8BIT`\n\nThe shell isn't using a UTF-8 locale. `export LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8` and retry. CocoaPods itself prints this hint in its output.\n\n### iOS build fails with `'yoga/<sub>/<name>.h' file not found` (also `React-rendererdebug` / `React-logger` `ScanDependencies` failures)\n\nThe first `pod install` on a fresh clone can leave Yoga's private headers incomplete — usually because the repo's checked-in `Podfile.lock` was generated by a newer cocoapods (`1.16.2`) than the one the `Gemfile` pins (`< 1.15`). The install prints a warning: *\"The version of CocoaPods used to generate the lockfile (1.16.2) is higher than the version of the current executable (1.14.3). Incompatibility issues may arise.\"* In that state, the build then fails on missing headers like `yoga/numeric/Comparison.h`, `yoga/algorithm/PixelGrid.h`, `yoga/debug/AssertFatal.h`. Wipe and reinstall:\n\n```bash\ncd examples/react-native/app/ios\ntrash Pods Podfile.lock   # or rm -rf\nbundle exec pod install   # regenerates a 1.14.3 lockfile and full Yoga headers\n```\n\nThen re-run `pnpm ios` from `examples/react-native/app`.\n\n### Could not determine the dependencies of task ':app:compileDebugJavaWithJavac'\n\n```\nerror Failed to install the app. Make sure you have the Android development environment set up: https://reactnative.dev/docs/environment-setup.\nError: Command failed: ./gradlew app:installDebug -PreactNativeDevServerPort=8081\n\nFAILURE: Build failed with an exception.\n\n* What went wrong:\nCould not determine the dependencies of task ':app:compileDebugJavaWithJavac'.\n> SDK location not found. Define location with an ANDROID_SDK_ROOT environment variable or by setting the sdk.dir path in your project's local properties file at ...\n```\n\nThe path to the Android SDK is missing from the environment — see step 3 in the [Android development environment](https://reactnative.dev/docs/environment-setup) guide.\n\nFor macOS or Linux, set `ANDROID_SDK_ROOT` in your shell:\n\n```bash\nexport ANDROID_SDK_ROOT=$HOME/Library/Android/sdk\nexport PATH=$PATH:$ANDROID_SDK_ROOT/emulator\nexport PATH=$PATH:$ANDROID_SDK_ROOT/platform-tools\n```\n"
  },
  {
    "path": "examples/react-native/app/__tests__/App.test.tsx",
    "content": "/**\n * @format\n */\n\n// Mock the SDK before importing App so its module-scope init (issue #181 reproduce\n// pattern) doesn't actually load the SDK's native dependencies in the jest env.\n// The Maestro smoke test exercises real SDK init; this jest test only verifies\n// that App renders without throwing.\njest.mock('@amplitude/analytics-react-native', () => ({\n  init: jest.fn(),\n  track: jest.fn(() => ({promise: Promise.resolve({message: 'mocked'})})),\n  identify: jest.fn(() => ({promise: Promise.resolve({message: 'mocked'})})),\n  Identify: jest\n    .fn()\n    .mockImplementation(() => ({set: jest.fn().mockReturnThis()})),\n}));\n\nimport 'react-native';\nimport React from 'react';\nimport App from '../App';\n\n// Note: import explicitly to use the types shipped with jest.\nimport {it} from '@jest/globals';\n\n// Note: test renderer must be required after react-native.\nimport renderer from 'react-test-renderer';\n\nit('renders correctly', () => {\n  renderer.create(<App />);\n});\n"
  },
  {
    "path": "examples/react-native/app/android/app/build.gradle",
    "content": "apply plugin: \"com.android.application\"\napply plugin: \"org.jetbrains.kotlin.android\"\napply plugin: \"com.facebook.react\"\n\n/**\n * This is the configuration block to customize your React Native Android app.\n * By default you don't need to apply any configuration, just uncomment the lines you need.\n */\nreact {\n    /* Folders */\n    //   The root of your project, i.e. where \"package.json\" lives. Default is '..'\n    // root = file(\"../\")\n    //   The folder where the react-native NPM package is. Default is ../node_modules/react-native\n    // reactNativeDir = file(\"../node_modules/react-native\")\n    //   The folder where the react-native Codegen package is. Default is ../node_modules/@react-native/codegen\n    // codegenDir = file(\"../node_modules/@react-native/codegen\")\n    //   The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js\n    // cliFile = file(\"../node_modules/react-native/cli.js\")\n\n    /* Variants */\n    //   The list of variants to that are debuggable. For those we're going to\n    //   skip the bundling of the JS bundle and the assets. By default is just 'debug'.\n    //   If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants.\n    // debuggableVariants = [\"liteDebug\", \"prodDebug\"]\n\n    /* Bundling */\n    //   A list containing the node command and its flags. Default is just 'node'.\n    // nodeExecutableAndArgs = [\"node\"]\n    //\n    //   The command to run when bundling. By default is 'bundle'\n    // bundleCommand = \"ram-bundle\"\n    //\n    //   The path to the CLI configuration file. Default is empty.\n    // bundleConfig = file(../rn-cli.config.js)\n    //\n    //   The name of the generated asset file containing your JS bundle\n    // bundleAssetName = \"MyApplication.android.bundle\"\n    //\n    //   The entry file for bundle generation. Default is 'index.android.js' or 'index.js'\n    // entryFile = file(\"../js/MyApplication.android.js\")\n    //\n    //   A list of extra flags to pass to the 'bundle' commands.\n    //   See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle\n    // extraPackagerArgs = []\n\n    /* Hermes Commands */\n    //   The hermes compiler command to run. By default it is 'hermesc'\n    // hermesCommand = \"$rootDir/my-custom-hermesc/bin/hermesc\"\n    //\n    //   The list of flags to pass to the Hermes compiler. By default is \"-O\", \"-output-source-map\"\n    // hermesFlags = [\"-O\", \"-output-source-map\"]\n}\n\n/**\n * Set this to true to Run Proguard on Release builds to minify the Java bytecode.\n */\ndef enableProguardInReleaseBuilds = false\n\n/**\n * The preferred build flavor of JavaScriptCore (JSC)\n *\n * For example, to use the international variant, you can use:\n * `def jscFlavor = 'org.webkit:android-jsc-intl:+'`\n *\n * The international variant includes ICU i18n library and necessary data\n * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that\n * give correct results when using with locales other than en-US. Note that\n * this variant is about 6MiB larger per architecture than default.\n */\ndef jscFlavor = 'org.webkit:android-jsc:+'\n\nandroid {\n    ndkVersion rootProject.ext.ndkVersion\n    buildToolsVersion rootProject.ext.buildToolsVersion\n    compileSdk rootProject.ext.compileSdkVersion\n\n    namespace \"com.app\"\n    defaultConfig {\n        applicationId \"com.app\"\n        minSdkVersion rootProject.ext.minSdkVersion\n        targetSdkVersion rootProject.ext.targetSdkVersion\n        versionCode 1\n        versionName \"1.0\"\n    }\n    signingConfigs {\n        debug {\n            storeFile file('debug.keystore')\n            storePassword 'android'\n            keyAlias 'androiddebugkey'\n            keyPassword 'android'\n        }\n    }\n    buildTypes {\n        debug {\n            signingConfig signingConfigs.debug\n        }\n        release {\n            // Caution! In production, you need to generate your own keystore file.\n            // see https://reactnative.dev/docs/signed-apk-android.\n            signingConfig signingConfigs.debug\n            minifyEnabled enableProguardInReleaseBuilds\n            proguardFiles getDefaultProguardFile(\"proguard-android.txt\"), \"proguard-rules.pro\"\n        }\n    }\n}\n\ndependencies {\n    // The version of react-native is set by the React Native Gradle Plugin\n    implementation(\"com.facebook.react:react-android\")\n\n    if (hermesEnabled.toBoolean()) {\n        implementation(\"com.facebook.react:hermes-android\")\n    } else {\n        implementation jscFlavor\n    }\n}\n\napply from: file(\"../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle\"); applyNativeModulesAppBuildGradle(project)\n"
  },
  {
    "path": "examples/react-native/app/android/app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n"
  },
  {
    "path": "examples/react-native/app/android/app/src/debug/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <application\n        android:usesCleartextTraffic=\"true\"\n        tools:targetApi=\"28\"\n        tools:ignore=\"GoogleAppIndexingWarning\"/>\n</manifest>\n"
  },
  {
    "path": "examples/react-native/app/android/app/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n\n    <application\n      android:name=\".MainApplication\"\n      android:label=\"@string/app_name\"\n      android:icon=\"@mipmap/ic_launcher\"\n      android:roundIcon=\"@mipmap/ic_launcher_round\"\n      android:allowBackup=\"false\"\n      android:theme=\"@style/AppTheme\">\n      <activity\n        android:name=\".MainActivity\"\n        android:label=\"@string/app_name\"\n        android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode\"\n        android:launchMode=\"singleTask\"\n        android:windowSoftInputMode=\"adjustResize\"\n        android:exported=\"true\">\n        <intent-filter>\n            <action android:name=\"android.intent.action.MAIN\" />\n            <category android:name=\"android.intent.category.LAUNCHER\" />\n        </intent-filter>\n      </activity>\n    </application>\n</manifest>\n"
  },
  {
    "path": "examples/react-native/app/android/app/src/main/java/com/app/MainActivity.kt",
    "content": "package com.app\n\nimport com.facebook.react.ReactActivity\nimport com.facebook.react.ReactActivityDelegate\nimport com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled\nimport com.facebook.react.defaults.DefaultReactActivityDelegate\n\nclass MainActivity : ReactActivity() {\n\n  /**\n   * Returns the name of the main component registered from JavaScript. This is used to schedule\n   * rendering of the component.\n   */\n  override fun getMainComponentName(): String = \"app\"\n\n  /**\n   * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate]\n   * which allows you to enable New Architecture with a single boolean flags [fabricEnabled]\n   */\n  override fun createReactActivityDelegate(): ReactActivityDelegate =\n      DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled)\n}\n"
  },
  {
    "path": "examples/react-native/app/android/app/src/main/java/com/app/MainApplication.kt",
    "content": "package com.app\n\nimport android.app.Application\nimport com.facebook.react.PackageList\nimport com.facebook.react.ReactApplication\nimport com.facebook.react.ReactHost\nimport com.facebook.react.ReactNativeHost\nimport com.facebook.react.ReactPackage\nimport com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load\nimport com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost\nimport com.facebook.react.defaults.DefaultReactNativeHost\nimport com.facebook.soloader.SoLoader\n\nclass MainApplication : Application(), ReactApplication {\n\n  override val reactNativeHost: ReactNativeHost =\n      object : DefaultReactNativeHost(this) {\n        override fun getPackages(): List<ReactPackage> =\n            PackageList(this).packages.apply {\n              // Packages that cannot be autolinked yet can be added manually here, for example:\n              // add(MyReactNativePackage())\n            }\n\n        override fun getJSMainModuleName(): String = \"index\"\n\n        override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG\n\n        override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED\n        override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED\n      }\n\n  override val reactHost: ReactHost\n    get() = getDefaultReactHost(applicationContext, reactNativeHost)\n\n  override fun onCreate() {\n    super.onCreate()\n    SoLoader.init(this, false)\n    if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {\n      // If you opted-in for the New Architecture, we load the native entry point for this app.\n      load()\n    }\n  }\n}\n"
  },
  {
    "path": "examples/react-native/app/android/app/src/main/res/drawable/rn_edit_text_material.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Copyright (C) 2014 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n<inset xmlns:android=\"http://schemas.android.com/apk/res/android\"\n       android:insetLeft=\"@dimen/abc_edit_text_inset_horizontal_material\"\n       android:insetRight=\"@dimen/abc_edit_text_inset_horizontal_material\"\n       android:insetTop=\"@dimen/abc_edit_text_inset_top_material\"\n       android:insetBottom=\"@dimen/abc_edit_text_inset_bottom_material\"\n       >\n\n    <selector>\n        <!--\n          This file is a copy of abc_edit_text_material (https://bit.ly/3k8fX7I).\n          The item below with state_pressed=\"false\" and state_focused=\"false\" causes a NullPointerException.\n          NullPointerException:tempt to invoke virtual method 'android.graphics.drawable.Drawable android.graphics.drawable.Drawable$ConstantState.newDrawable(android.content.res.Resources)'\n\n          <item android:state_pressed=\"false\" android:state_focused=\"false\" android:drawable=\"@drawable/abc_textfield_default_mtrl_alpha\"/>\n\n          For more info, see https://bit.ly/3CdLStv (react-native/pull/29452) and https://bit.ly/3nxOMoR.\n        -->\n        <item android:state_enabled=\"false\" android:drawable=\"@drawable/abc_textfield_default_mtrl_alpha\"/>\n        <item android:drawable=\"@drawable/abc_textfield_activated_mtrl_alpha\"/>\n    </selector>\n\n</inset>\n"
  },
  {
    "path": "examples/react-native/app/android/app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">app</string>\n</resources>\n"
  },
  {
    "path": "examples/react-native/app/android/app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.DayNight.NoActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"android:editTextBackground\">@drawable/rn_edit_text_material</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "examples/react-native/app/android/build.gradle",
    "content": "buildscript {\n    ext {\n        buildToolsVersion = \"34.0.0\"\n        minSdkVersion = 23\n        compileSdkVersion = 34\n        targetSdkVersion = 34\n        ndkVersion = \"26.1.10909125\"\n        kotlinVersion = \"1.9.22\"\n    }\n    repositories {\n        google()\n        mavenCentral()\n    }\n    dependencies {\n        classpath(\"com.android.tools.build:gradle\")\n        classpath(\"com.facebook.react:react-native-gradle-plugin\")\n        classpath(\"org.jetbrains.kotlin:kotlin-gradle-plugin\")\n    }\n}\n\napply plugin: \"com.facebook.react.rootproject\"\n"
  },
  {
    "path": "examples/react-native/app/android/gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-8.6-all.zip\nnetworkTimeout=10000\nvalidateDistributionUrl=true\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "examples/react-native/app/android/gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\n# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m\norg.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m\n\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n\n# AndroidX package structure to make it clearer which packages are bundled with the\n# Android operating system, and which are packaged with your app's APK\n# https://developer.android.com/topic/libraries/support-library/androidx-rn\nandroid.useAndroidX=true\n# Automatically convert third-party libraries to use AndroidX\nandroid.enableJetifier=true\n\n# Use this property to specify which architecture you want to build.\n# You can also override it from the CLI using\n# ./gradlew <task> -PreactNativeArchitectures=x86_64\nreactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64\n\n# Use this property to enable support to the new architecture.\n# This will allow you to use TurboModules and the Fabric render in\n# your application. You should enable this flag either if you want\n# to write custom TurboModules/Fabric components OR use libraries that\n# are providing them.\nnewArchEnabled=false\n\n# Use this property to enable or disable the Hermes JS engine.\n# If set to false, you will be using JSC instead.\nhermesEnabled=true\n"
  },
  {
    "path": "examples/react-native/app/android/gradlew",
    "content": "#!/bin/sh\n\n#\n# Copyright © 2015-2021 the original authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##############################################################################\n#\n#   Gradle start up script for POSIX generated by Gradle.\n#\n#   Important for running:\n#\n#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is\n#       noncompliant, but you have some other compliant shell such as ksh or\n#       bash, then to run this script, type that shell name before the whole\n#       command line, like:\n#\n#           ksh Gradle\n#\n#       Busybox and similar reduced shells will NOT work, because this script\n#       requires all of these POSIX shell features:\n#         * functions;\n#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,\n#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;\n#         * compound commands having a testable exit status, especially «case»;\n#         * various built-in commands including «command», «set», and «ulimit».\n#\n#   Important for patching:\n#\n#   (2) This script targets any POSIX shell, so it avoids extensions provided\n#       by Bash, Ksh, etc; in particular arrays are avoided.\n#\n#       The \"traditional\" practice of packing multiple parameters into a\n#       space-separated string is a well documented source of bugs and security\n#       problems, so this is (mostly) avoided, by progressively accumulating\n#       options in \"$@\", and eventually passing that to Java.\n#\n#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,\n#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;\n#       see the in-line comments for details.\n#\n#       There are tweaks for specific operating systems such as AIX, CygWin,\n#       Darwin, MinGW, and NonStop.\n#\n#   (3) This script is generated from the Groovy template\n#       https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt\n#       within the Gradle project.\n#\n#       You can find Gradle at https://github.com/gradle/gradle/.\n#\n##############################################################################\n\n# Attempt to set APP_HOME\n\n# Resolve links: $0 may be a link\napp_path=$0\n\n# Need this for daisy-chained symlinks.\nwhile\n    APP_HOME=${app_path%\"${app_path##*/}\"}  # leaves a trailing /; empty if no leading path\n    [ -h \"$app_path\" ]\ndo\n    ls=$( ls -ld \"$app_path\" )\n    link=${ls#*' -> '}\n    case $link in             #(\n      /*)   app_path=$link ;; #(\n      *)    app_path=$APP_HOME$link ;;\n    esac\ndone\n\n# This is normally unused\n# shellcheck disable=SC2034\nAPP_BASE_NAME=${0##*/}\n# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)\nAPP_HOME=$( cd \"${APP_HOME:-./}\" > /dev/null && pwd -P ) || exit\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=maximum\n\nwarn () {\n    echo \"$*\"\n} >&2\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n} >&2\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"$( uname )\" in                #(\n  CYGWIN* )         cygwin=true  ;; #(\n  Darwin* )         darwin=true  ;; #(\n  MSYS* | MINGW* )  msys=true    ;; #(\n  NONSTOP* )        nonstop=true ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=$JAVA_HOME/jre/sh/java\n    else\n        JAVACMD=$JAVA_HOME/bin/java\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=java\n    if ! command -v java >/dev/null 2>&1\n    then\n        die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nfi\n\n# Increase the maximum file descriptors if we can.\nif ! \"$cygwin\" && ! \"$darwin\" && ! \"$nonstop\" ; then\n    case $MAX_FD in #(\n      max*)\n        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.\n        # shellcheck disable=SC2039,SC3045\n        MAX_FD=$( ulimit -H -n ) ||\n            warn \"Could not query maximum file descriptor limit\"\n    esac\n    case $MAX_FD in  #(\n      '' | soft) :;; #(\n      *)\n        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.\n        # shellcheck disable=SC2039,SC3045\n        ulimit -n \"$MAX_FD\" ||\n            warn \"Could not set maximum file descriptor limit to $MAX_FD\"\n    esac\nfi\n\n# Collect all arguments for the java command, stacking in reverse order:\n#   * args from the command line\n#   * the main class name\n#   * -classpath\n#   * -D...appname settings\n#   * --module-path (only if needed)\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.\n\n# For Cygwin or MSYS, switch paths to Windows format before running java\nif \"$cygwin\" || \"$msys\" ; then\n    APP_HOME=$( cygpath --path --mixed \"$APP_HOME\" )\n    CLASSPATH=$( cygpath --path --mixed \"$CLASSPATH\" )\n\n    JAVACMD=$( cygpath --unix \"$JAVACMD\" )\n\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    for arg do\n        if\n            case $arg in                                #(\n              -*)   false ;;                            # don't mess with options #(\n              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath\n                    [ -e \"$t\" ] ;;                      #(\n              *)    false ;;\n            esac\n        then\n            arg=$( cygpath --path --ignore --mixed \"$arg\" )\n        fi\n        # Roll the args list around exactly as many times as the number of\n        # args, so each arg winds up back in the position where it started, but\n        # possibly modified.\n        #\n        # NB: a `for` loop captures its iteration list before it begins, so\n        # changing the positional parameters here affects neither the number of\n        # iterations, nor the values presented in `arg`.\n        shift                   # remove old arg\n        set -- \"$@\" \"$arg\"      # push replacement arg\n    done\nfi\n\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Collect all arguments for the java command:\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,\n#     and any embedded shellness will be escaped.\n#   * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be\n#     treated as '${Hostname}' itself on the command line.\n\nset -- \\\n        \"-Dorg.gradle.appname=$APP_BASE_NAME\" \\\n        -classpath \"$CLASSPATH\" \\\n        org.gradle.wrapper.GradleWrapperMain \\\n        \"$@\"\n\n# Stop when \"xargs\" is not available.\nif ! command -v xargs >/dev/null 2>&1\nthen\n    die \"xargs is not available\"\nfi\n\n# Use \"xargs\" to parse quoted args.\n#\n# With -n1 it outputs one arg per line, with the quotes and backslashes removed.\n#\n# In Bash we could simply go:\n#\n#   readarray ARGS < <( xargs -n1 <<<\"$var\" ) &&\n#   set -- \"${ARGS[@]}\" \"$@\"\n#\n# but POSIX shell has neither arrays nor command substitution, so instead we\n# post-process each arg (as a line of input to sed) to backslash-escape any\n# character that might be a shell metacharacter, then use eval to reverse\n# that process (while maintaining the separation between arguments), and wrap\n# the whole thing up as a single \"set\" statement.\n#\n# This will of course break if any of these variables contains a newline or\n# an unmatched quote.\n#\n\neval \"set -- $(\n        printf '%s\\n' \"$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\" |\n        xargs -n1 |\n        sed ' s~[^-[:alnum:]+,./:=@_]~\\\\&~g; ' |\n        tr '\\n' ' '\n    )\" '\"$@\"'\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "examples/react-native/app/android/gradlew.bat",
    "content": "@rem\r\n@rem Copyright 2015 the original author or authors.\r\n@rem\r\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\r\n@rem you may not use this file except in compliance with the License.\r\n@rem You may obtain a copy of the License at\r\n@rem\r\n@rem      https://www.apache.org/licenses/LICENSE-2.0\r\n@rem\r\n@rem Unless required by applicable law or agreed to in writing, software\r\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\r\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n@rem See the License for the specific language governing permissions and\r\n@rem limitations under the License.\r\n@rem\r\n\r\n@if \"%DEBUG%\"==\"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\"==\"\" set DIRNAME=.\r\n@rem This is normally unused\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Resolve any \".\" and \"..\" in APP_HOME to make it shorter.\r\nfor %%i in (\"%APP_HOME%\") do set APP_HOME=%%~fi\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif %ERRORLEVEL% equ 0 goto execute\r\n\r\necho. 1>&2\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2\r\necho. 1>&2\r\necho Please set the JAVA_HOME variable in your environment to match the 1>&2\r\necho location of your Java installation. 1>&2\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto execute\r\n\r\necho. 1>&2\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2\r\necho. 1>&2\r\necho Please set the JAVA_HOME variable in your environment to match the 1>&2\r\necho location of your Java installation. 1>&2\r\n\r\ngoto fail\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %*\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif %ERRORLEVEL% equ 0 goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nset EXIT_CODE=%ERRORLEVEL%\r\nif %EXIT_CODE% equ 0 set EXIT_CODE=1\r\nif not \"\"==\"%GRADLE_EXIT_CONSOLE%\" exit %EXIT_CODE%\r\nexit /b %EXIT_CODE%\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "examples/react-native/app/android/settings.gradle",
    "content": "rootProject.name = 'app'\napply from: file(\"../node_modules/@react-native-community/cli-platform-android/native_modules.gradle\"); applyNativeModulesSettingsGradle(settings)\ninclude ':app'\nincludeBuild('../node_modules/@react-native/gradle-plugin')\n"
  },
  {
    "path": "examples/react-native/app/app.json",
    "content": "{\n  \"name\": \"app\",\n  \"displayName\": \"app\"\n}\n"
  },
  {
    "path": "examples/react-native/app/babel.config.js",
    "content": "module.exports = {\n  presets: ['module:@react-native/babel-preset'],\n};\n"
  },
  {
    "path": "examples/react-native/app/index.js",
    "content": "/**\n * @format\n */\n\nimport {AppRegistry} from 'react-native';\nimport App from './App';\nimport {name as appName} from './app.json';\n\nAppRegistry.registerComponent(appName, () => App);\n"
  },
  {
    "path": "examples/react-native/app/ios/.xcode.env",
    "content": "# This `.xcode.env` file is versioned and is used to source the environment\n# used when running script phases inside Xcode.\n# To customize your local environment, you can create an `.xcode.env.local`\n# file that is not versioned.\n\n# NODE_BINARY variable contains the PATH to the node executable.\n#\n# Customize the NODE_BINARY variable here.\n# For example, to use nvm with brew, add the following line\n# . \"$(brew --prefix nvm)/nvm.sh\" --no-use\nexport NODE_BINARY=$(command -v node)\n"
  },
  {
    "path": "examples/react-native/app/ios/Podfile",
    "content": "# Resolve react_native_pods.rb with node to allow for hoisting\nrequire Pod::Executable.execute_command('node', ['-p',\n  'require.resolve(\n    \"react-native/scripts/react_native_pods.rb\",\n    {paths: [process.argv[1]]},\n  )', __dir__]).strip\n\nplatform :ios, min_ios_version_supported\nprepare_react_native_project!\n\nlinkage = ENV['USE_FRAMEWORKS']\nif linkage != nil\n  Pod::UI.puts \"Configuring Pod with #{linkage}ally linked Frameworks\".green\n  use_frameworks! :linkage => linkage.to_sym\nend\n\ntarget 'app' do\n  config = use_native_modules!\n\n  use_react_native!(\n    :path => config[:reactNativePath],\n    # An absolute path to your application root.\n    :app_path => \"#{Pod::Config.instance.installation_root}/..\"\n  )\n\n  target 'appTests' do\n    inherit! :complete\n    # Pods for testing\n  end\n\n  post_install do |installer|\n    # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202\n    react_native_post_install(\n      installer,\n      config[:reactNativePath],\n      :mac_catalyst_enabled => false,\n      # :ccache_enabled => true\n    )\n  end\nend\n"
  },
  {
    "path": "examples/react-native/app/ios/app/AppDelegate.h",
    "content": "#import <RCTAppDelegate.h>\n#import <UIKit/UIKit.h>\n\n@interface AppDelegate : RCTAppDelegate\n\n@end\n"
  },
  {
    "path": "examples/react-native/app/ios/app/AppDelegate.mm",
    "content": "#import \"AppDelegate.h\"\n\n#import <React/RCTBundleURLProvider.h>\n\n@implementation AppDelegate\n\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions\n{\n  self.moduleName = @\"app\";\n  // You can add your custom initial props in the dictionary below.\n  // They will be passed down to the ViewController used by React Native.\n  self.initialProps = @{};\n\n  return [super application:application didFinishLaunchingWithOptions:launchOptions];\n}\n\n- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge\n{\n  return [self bundleURL];\n}\n\n- (NSURL *)bundleURL\n{\n#if DEBUG\n  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@\"index\"];\n#else\n  return [[NSBundle mainBundle] URLForResource:@\"main\" withExtension:@\"jsbundle\"];\n#endif\n}\n\n@end\n"
  },
  {
    "path": "examples/react-native/app/ios/app/Images.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"2x\",\n      \"size\" : \"20x20\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"3x\",\n      \"size\" : \"20x20\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"2x\",\n      \"size\" : \"29x29\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"3x\",\n      \"size\" : \"29x29\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"2x\",\n      \"size\" : \"40x40\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"3x\",\n      \"size\" : \"40x40\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"2x\",\n      \"size\" : \"60x60\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"3x\",\n      \"size\" : \"60x60\"\n    },\n    {\n      \"idiom\" : \"ios-marketing\",\n      \"scale\" : \"1x\",\n      \"size\" : \"1024x1024\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "examples/react-native/app/ios/app/Images.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}\n"
  },
  {
    "path": "examples/react-native/app/ios/app/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>app</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>$(MARKETING_VERSION)</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>NSAppTransportSecurity</key>\n\t<dict>\n\t\t<key>NSAllowsArbitraryLoads</key>\n\t\t<false/>\n\t\t<key>NSAllowsLocalNetworking</key>\n\t\t<true/>\n\t</dict>\n\t<key>NSLocationWhenInUseUsageDescription</key>\n\t<string></string>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>arm64</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UIViewControllerBasedStatusBarAppearance</key>\n\t<false/>\n</dict>\n</plist>\n"
  },
  {
    "path": "examples/react-native/app/ios/app/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"15702\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <device id=\"retina4_7\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"15704\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <label opaque=\"NO\" clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"app\" textAlignment=\"center\" lineBreakMode=\"middleTruncation\" baselineAdjustment=\"alignBaselines\" minimumFontSize=\"18\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"GJd-Yh-RWb\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"202\" width=\"375\" height=\"43\"/>\n                                <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"36\"/>\n                                <nil key=\"highlightedColor\"/>\n                            </label>\n                            <label opaque=\"NO\" clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Powered by React Native\" textAlignment=\"center\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" minimumFontSize=\"9\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"MN2-I3-ftu\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"626\" width=\"375\" height=\"21\"/>\n                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                <nil key=\"highlightedColor\"/>\n                            </label>\n                        </subviews>\n                        <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\" cocoaTouchSystemColor=\"whiteColor\"/>\n                        <constraints>\n                            <constraint firstItem=\"Bcu-3y-fUS\" firstAttribute=\"bottom\" secondItem=\"MN2-I3-ftu\" secondAttribute=\"bottom\" constant=\"20\" id=\"OZV-Vh-mqD\"/>\n                            <constraint firstItem=\"Bcu-3y-fUS\" firstAttribute=\"centerX\" secondItem=\"GJd-Yh-RWb\" secondAttribute=\"centerX\" id=\"Q3B-4B-g5h\"/>\n                            <constraint firstItem=\"MN2-I3-ftu\" firstAttribute=\"centerX\" secondItem=\"Bcu-3y-fUS\" secondAttribute=\"centerX\" id=\"akx-eg-2ui\"/>\n                            <constraint firstItem=\"MN2-I3-ftu\" firstAttribute=\"leading\" secondItem=\"Bcu-3y-fUS\" secondAttribute=\"leading\" id=\"i1E-0Y-4RG\"/>\n                            <constraint firstItem=\"GJd-Yh-RWb\" firstAttribute=\"centerY\" secondItem=\"Ze5-6b-2t3\" secondAttribute=\"bottom\" multiplier=\"1/3\" constant=\"1\" id=\"moa-c2-u7t\"/>\n                            <constraint firstItem=\"GJd-Yh-RWb\" firstAttribute=\"leading\" secondItem=\"Bcu-3y-fUS\" secondAttribute=\"leading\" symbolic=\"YES\" id=\"x7j-FC-K8j\"/>\n                        </constraints>\n                        <viewLayoutGuide key=\"safeArea\" id=\"Bcu-3y-fUS\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"52.173913043478265\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "examples/react-native/app/ios/app/PrivacyInfo.xcprivacy",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>NSPrivacyAccessedAPITypes</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>NSPrivacyAccessedAPIType</key>\n\t\t\t<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>\n\t\t\t<key>NSPrivacyAccessedAPITypeReasons</key>\n\t\t\t<array>\n\t\t\t\t<string>C617.1</string>\n\t\t\t</array>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>NSPrivacyAccessedAPIType</key>\n\t\t\t<string>NSPrivacyAccessedAPICategoryUserDefaults</string>\n\t\t\t<key>NSPrivacyAccessedAPITypeReasons</key>\n\t\t\t<array>\n\t\t\t\t<string>CA92.1</string>\n\t\t\t</array>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>NSPrivacyAccessedAPIType</key>\n\t\t\t<string>NSPrivacyAccessedAPICategorySystemBootTime</string>\n\t\t\t<key>NSPrivacyAccessedAPITypeReasons</key>\n\t\t\t<array>\n\t\t\t\t<string>35F9.1</string>\n\t\t\t</array>\n\t\t</dict>\n\t</array>\n\t<key>NSPrivacyCollectedDataTypes</key>\n\t<array/>\n\t<key>NSPrivacyTracking</key>\n\t<false/>\n</dict>\n</plist>\n"
  },
  {
    "path": "examples/react-native/app/ios/app/main.m",
    "content": "#import <UIKit/UIKit.h>\n\n#import \"AppDelegate.h\"\n\nint main(int argc, char *argv[])\n{\n  @autoreleasepool {\n    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));\n  }\n}\n"
  },
  {
    "path": "examples/react-native/app/ios/app.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t00E356F31AD99517003FC87E /* appTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* appTests.m */; };\n\t\t0C80B921A6F3F58F76C31292 /* libPods-app.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DCACB8F33CDC322A6C60F78 /* libPods-app.a */; };\n\t\t13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; };\n\t\t13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };\n\t\t13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };\n\t\t7699B88040F8A987B510C191 /* libPods-app-appTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 19F6CBCC0A4E27FBF8BF4A61 /* libPods-app-appTests.a */; };\n\t\t81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };\n\t\tCA1C30F36C1C0E52F754A635 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = F82C0122EF21DCFFD6F06133 /* PrivacyInfo.xcprivacy */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\t00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 13B07F861A680F5B00A75B9A;\n\t\t\tremoteInfo = app;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXFileReference section */\n\t\t00E356EE1AD99517003FC87E /* appTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = appTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t00E356F21AD99517003FC87E /* appTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = appTests.m; sourceTree = \"<group>\"; };\n\t\t13B07F961A680F5B00A75B9A /* app.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = app.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = app/AppDelegate.h; sourceTree = \"<group>\"; };\n\t\t13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = app/AppDelegate.mm; sourceTree = \"<group>\"; };\n\t\t13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = app/Images.xcassets; sourceTree = \"<group>\"; };\n\t\t13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = app/Info.plist; sourceTree = \"<group>\"; };\n\t\t13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = app/main.m; sourceTree = \"<group>\"; };\n\t\t13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = PrivacyInfo.xcprivacy; path = app/PrivacyInfo.xcprivacy; sourceTree = \"<group>\"; };\n\t\t19F6CBCC0A4E27FBF8BF4A61 /* libPods-app-appTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = \"libPods-app-appTests.a\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t3B4392A12AC88292D35C810B /* Pods-app.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-app.debug.xcconfig\"; path = \"Target Support Files/Pods-app/Pods-app.debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t5709B34CF0A7D63546082F79 /* Pods-app.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-app.release.xcconfig\"; path = \"Target Support Files/Pods-app/Pods-app.release.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t5B7EB9410499542E8C5724F5 /* Pods-app-appTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-app-appTests.debug.xcconfig\"; path = \"Target Support Files/Pods-app-appTests/Pods-app-appTests.debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t5DCACB8F33CDC322A6C60F78 /* libPods-app.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = \"libPods-app.a\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = app/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\t89C6BE57DB24E9ADA2F236DE /* Pods-app-appTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-app-appTests.release.xcconfig\"; path = \"Target Support Files/Pods-app-appTests/Pods-app-appTests.release.xcconfig\"; sourceTree = \"<group>\"; };\n\t\tED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };\n\t\tF82C0122EF21DCFFD6F06133 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xml; name = PrivacyInfo.xcprivacy; path = app/PrivacyInfo.xcprivacy; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t00E356EB1AD99517003FC87E /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t7699B88040F8A987B510C191 /* libPods-app-appTests.a in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t13B07F8C1A680F5B00A75B9A /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t0C80B921A6F3F58F76C31292 /* libPods-app.a in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t00E356EF1AD99517003FC87E /* appTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t00E356F21AD99517003FC87E /* appTests.m */,\n\t\t\t\t00E356F01AD99517003FC87E /* Supporting Files */,\n\t\t\t);\n\t\t\tpath = appTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t00E356F01AD99517003FC87E /* Supporting Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t00E356F11AD99517003FC87E /* Info.plist */,\n\t\t\t);\n\t\t\tname = \"Supporting Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t13B07FAE1A68108700A75B9A /* app */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t13B07FAF1A68108700A75B9A /* AppDelegate.h */,\n\t\t\t\t13B07FB01A68108700A75B9A /* AppDelegate.mm */,\n\t\t\t\t13B07FB51A68108700A75B9A /* Images.xcassets */,\n\t\t\t\t13B07FB61A68108700A75B9A /* Info.plist */,\n\t\t\t\t81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */,\n\t\t\t\t13B07FB71A68108700A75B9A /* main.m */,\n\t\t\t\t13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */,\n\t\t\t\tF82C0122EF21DCFFD6F06133 /* PrivacyInfo.xcprivacy */,\n\t\t\t);\n\t\t\tname = app;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2D16E6871FA4F8E400B85C8A /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tED297162215061F000B7C4FE /* JavaScriptCore.framework */,\n\t\t\t\t5DCACB8F33CDC322A6C60F78 /* libPods-app.a */,\n\t\t\t\t19F6CBCC0A4E27FBF8BF4A61 /* libPods-app-appTests.a */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t832341AE1AAA6A7D00B99B32 /* Libraries */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t);\n\t\t\tname = Libraries;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t83CBB9F61A601CBA00E9B192 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t13B07FAE1A68108700A75B9A /* app */,\n\t\t\t\t832341AE1AAA6A7D00B99B32 /* Libraries */,\n\t\t\t\t00E356EF1AD99517003FC87E /* appTests */,\n\t\t\t\t83CBBA001A601CBA00E9B192 /* Products */,\n\t\t\t\t2D16E6871FA4F8E400B85C8A /* Frameworks */,\n\t\t\t\tBBD78D7AC51CEA395F1C20DB /* Pods */,\n\t\t\t);\n\t\t\tindentWidth = 2;\n\t\t\tsourceTree = \"<group>\";\n\t\t\ttabWidth = 2;\n\t\t\tusesTabs = 0;\n\t\t};\n\t\t83CBBA001A601CBA00E9B192 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t13B07F961A680F5B00A75B9A /* app.app */,\n\t\t\t\t00E356EE1AD99517003FC87E /* appTests.xctest */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tBBD78D7AC51CEA395F1C20DB /* Pods */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3B4392A12AC88292D35C810B /* Pods-app.debug.xcconfig */,\n\t\t\t\t5709B34CF0A7D63546082F79 /* Pods-app.release.xcconfig */,\n\t\t\t\t5B7EB9410499542E8C5724F5 /* Pods-app-appTests.debug.xcconfig */,\n\t\t\t\t89C6BE57DB24E9ADA2F236DE /* Pods-app-appTests.release.xcconfig */,\n\t\t\t);\n\t\t\tpath = Pods;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t00E356ED1AD99517003FC87E /* appTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget \"appTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tA55EABD7B0C7F3A422A6CC61 /* [CP] Check Pods Manifest.lock */,\n\t\t\t\t00E356EA1AD99517003FC87E /* Sources */,\n\t\t\t\t00E356EB1AD99517003FC87E /* Frameworks */,\n\t\t\t\t00E356EC1AD99517003FC87E /* Resources */,\n\t\t\t\tC59DA0FBD6956966B86A3779 /* [CP] Embed Pods Frameworks */,\n\t\t\t\tF6A41C54EA430FDDC6A6ED99 /* [CP] Copy Pods Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t00E356F51AD99517003FC87E /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = appTests;\n\t\t\tproductName = appTests;\n\t\t\tproductReference = 00E356EE1AD99517003FC87E /* appTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n\t\t13B07F861A680F5B00A75B9A /* app */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget \"app\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tC38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */,\n\t\t\t\t13B07F871A680F5B00A75B9A /* Sources */,\n\t\t\t\t13B07F8C1A680F5B00A75B9A /* Frameworks */,\n\t\t\t\t13B07F8E1A680F5B00A75B9A /* Resources */,\n\t\t\t\t00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,\n\t\t\t\t00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */,\n\t\t\t\tE235C05ADACE081382539298 /* [CP] Copy Pods Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = app;\n\t\t\tproductName = app;\n\t\t\tproductReference = 13B07F961A680F5B00A75B9A /* app.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t83CBB9F71A601CBA00E9B192 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastUpgradeCheck = 1210;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t00E356ED1AD99517003FC87E = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 6.2;\n\t\t\t\t\t\tTestTargetID = 13B07F861A680F5B00A75B9A;\n\t\t\t\t\t};\n\t\t\t\t\t13B07F861A680F5B00A75B9A = {\n\t\t\t\t\t\tLastSwiftMigration = 1120;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject \"app\" */;\n\t\t\tcompatibilityVersion = \"Xcode 12.0\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 83CBB9F61A601CBA00E9B192;\n\t\t\tproductRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t13B07F861A680F5B00A75B9A /* app */,\n\t\t\t\t00E356ED1AD99517003FC87E /* appTests */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t00E356EC1AD99517003FC87E /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t13B07F8E1A680F5B00A75B9A /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */,\n\t\t\t\t13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,\n\t\t\t\tCA1C30F36C1C0E52F754A635 /* PrivacyInfo.xcprivacy in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\t00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"$(SRCROOT)/.xcode.env.local\",\n\t\t\t\t\"$(SRCROOT)/.xcode.env\",\n\t\t\t);\n\t\t\tname = \"Bundle React Native code and images\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"set -e\\n\\nWITH_ENVIRONMENT=\\\"$REACT_NATIVE_PATH/scripts/xcode/with-environment.sh\\\"\\nREACT_NATIVE_XCODE=\\\"$REACT_NATIVE_PATH/scripts/react-native-xcode.sh\\\"\\n\\n/bin/sh -c \\\"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\\\"\\n\";\n\t\t};\n\t\t00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-app/Pods-app-frameworks-${CONFIGURATION}-input-files.xcfilelist\",\n\t\t\t);\n\t\t\tname = \"[CP] Embed Pods Frameworks\";\n\t\t\toutputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-app/Pods-app-frameworks-${CONFIGURATION}-output-files.xcfilelist\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-app/Pods-app-frameworks.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tA55EABD7B0C7F3A422A6CC61 /* [CP] Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\",\n\t\t\t\t\"${PODS_ROOT}/Manifest.lock\",\n\t\t\t);\n\t\t\tname = \"[CP] Check Pods Manifest.lock\";\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t\t\"$(DERIVED_FILE_DIR)/Pods-app-appTests-checkManifestLockResult.txt\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [ $? != 0 ] ; then\\n    # print error to STDERR\\n    echo \\\"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\\" >&2\\n    exit 1\\nfi\\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\\necho \\\"SUCCESS\\\" > \\\"${SCRIPT_OUTPUT_FILE_0}\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tC38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\",\n\t\t\t\t\"${PODS_ROOT}/Manifest.lock\",\n\t\t\t);\n\t\t\tname = \"[CP] Check Pods Manifest.lock\";\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t\t\"$(DERIVED_FILE_DIR)/Pods-app-checkManifestLockResult.txt\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [ $? != 0 ] ; then\\n    # print error to STDERR\\n    echo \\\"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\\" >&2\\n    exit 1\\nfi\\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\\necho \\\"SUCCESS\\\" > \\\"${SCRIPT_OUTPUT_FILE_0}\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tC59DA0FBD6956966B86A3779 /* [CP] Embed Pods Frameworks */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-app-appTests/Pods-app-appTests-frameworks-${CONFIGURATION}-input-files.xcfilelist\",\n\t\t\t);\n\t\t\tname = \"[CP] Embed Pods Frameworks\";\n\t\t\toutputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-app-appTests/Pods-app-appTests-frameworks-${CONFIGURATION}-output-files.xcfilelist\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-app-appTests/Pods-app-appTests-frameworks.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tE235C05ADACE081382539298 /* [CP] Copy Pods Resources */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-app/Pods-app-resources-${CONFIGURATION}-input-files.xcfilelist\",\n\t\t\t);\n\t\t\tname = \"[CP] Copy Pods Resources\";\n\t\t\toutputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-app/Pods-app-resources-${CONFIGURATION}-output-files.xcfilelist\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-app/Pods-app-resources.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tF6A41C54EA430FDDC6A6ED99 /* [CP] Copy Pods Resources */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-app-appTests/Pods-app-appTests-resources-${CONFIGURATION}-input-files.xcfilelist\",\n\t\t\t);\n\t\t\tname = \"[CP] Copy Pods Resources\";\n\t\t\toutputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-app-appTests/Pods-app-appTests-resources-${CONFIGURATION}-output-files.xcfilelist\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-app-appTests/Pods-app-appTests-resources.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t00E356EA1AD99517003FC87E /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t00E356F31AD99517003FC87E /* appTests.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t13B07F871A680F5B00A75B9A /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */,\n\t\t\t\t13B07FC11A68108700A75B9A /* main.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\t00E356F51AD99517003FC87E /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 13B07F861A680F5B00A75B9A /* app */;\n\t\t\ttargetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin XCBuildConfiguration section */\n\t\t00E356F61AD99517003FC87E /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 5B7EB9410499542E8C5724F5 /* Pods-app-appTests.debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = appTests/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 13.4;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t\t\"@loader_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tOTHER_LDFLAGS = (\n\t\t\t\t\t\"-ObjC\",\n\t\t\t\t\t\"-lc++\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/app.app/app\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t00E356F71AD99517003FC87E /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 89C6BE57DB24E9ADA2F236DE /* Pods-app-appTests.release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tINFOPLIST_FILE = appTests/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 13.4;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t\t\"@loader_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tOTHER_LDFLAGS = (\n\t\t\t\t\t\"-ObjC\",\n\t\t\t\t\t\"-lc++\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/app.app/app\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t13B07F941A680F5B00A75B9A /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 3B4392A12AC88292D35C810B /* Pods-app.debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_TEAM = 7CA8BGS9U9;\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tINFOPLIST_FILE = app/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tOTHER_LDFLAGS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"-ObjC\",\n\t\t\t\t\t\"-lc++\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\t\"PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]\" = org.reactjs.native.example.app.test;\n\t\t\t\tPRODUCT_NAME = app;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t13B07F951A680F5B00A75B9A /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 5709B34CF0A7D63546082F79 /* Pods-app.release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_TEAM = 7CA8BGS9U9;\n\t\t\t\tINFOPLIST_FILE = app/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tOTHER_LDFLAGS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"-ObjC\",\n\t\t\t\t\t\"-lc++\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\t\"PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]\" = org.reactjs.native.example.app.test;\n\t\t\t\tPRODUCT_NAME = app;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t83CBBA201A601CBA00E9B192 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCC = \"\";\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"c++20\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tCXX = \"\";\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\t\"EXCLUDED_ARCHS[sdk=iphonesimulator*]\" = \"\";\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_SYMBOLS_PRIVATE_EXTERN = NO;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 13.4;\n\t\t\t\tLD = \"\";\n\t\t\t\tLDPLUSPLUS = \"\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t/usr/lib/swift,\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tLIBRARY_SEARCH_PATHS = (\n\t\t\t\t\t\"\\\"$(SDKROOT)/usr/lib/swift\\\"\",\n\t\t\t\t\t\"\\\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\\\"\",\n\t\t\t\t\t\"\\\"$(inherited)\\\"\",\n\t\t\t\t);\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tOTHER_CPLUSPLUSFLAGS = (\n\t\t\t\t\t\"$(OTHER_CFLAGS)\",\n\t\t\t\t\t\"-DFOLLY_NO_CONFIG\",\n\t\t\t\t\t\"-DFOLLY_MOBILE=1\",\n\t\t\t\t\t\"-DFOLLY_USE_LIBCPP=1\",\n\t\t\t\t\t\"-DFOLLY_CFG_NO_COROUTINES=1\",\n\t\t\t\t\t\"-DFOLLY_HAVE_CLOCK_GETTIME=1\",\n\t\t\t\t);\n\t\t\t\tOTHER_LDFLAGS = \"$(inherited)\";\n\t\t\t\tREACT_NATIVE_PATH = \"${PODS_ROOT}/../../node_modules/react-native\";\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tUSE_HERMES = true;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t83CBBA211A601CBA00E9B192 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCC = \"\";\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"c++20\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = YES;\n\t\t\t\tCXX = \"\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\t\"EXCLUDED_ARCHS[sdk=iphonesimulator*]\" = \"\";\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 13.4;\n\t\t\t\tLD = \"\";\n\t\t\t\tLDPLUSPLUS = \"\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t/usr/lib/swift,\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tLIBRARY_SEARCH_PATHS = (\n\t\t\t\t\t\"\\\"$(SDKROOT)/usr/lib/swift\\\"\",\n\t\t\t\t\t\"\\\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\\\"\",\n\t\t\t\t\t\"\\\"$(inherited)\\\"\",\n\t\t\t\t);\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tOTHER_CPLUSPLUSFLAGS = (\n\t\t\t\t\t\"$(OTHER_CFLAGS)\",\n\t\t\t\t\t\"-DFOLLY_NO_CONFIG\",\n\t\t\t\t\t\"-DFOLLY_MOBILE=1\",\n\t\t\t\t\t\"-DFOLLY_USE_LIBCPP=1\",\n\t\t\t\t\t\"-DFOLLY_CFG_NO_COROUTINES=1\",\n\t\t\t\t\t\"-DFOLLY_HAVE_CLOCK_GETTIME=1\",\n\t\t\t\t);\n\t\t\t\tOTHER_LDFLAGS = \"$(inherited)\";\n\t\t\t\tREACT_NATIVE_PATH = \"${PODS_ROOT}/../../node_modules/react-native\";\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tUSE_HERMES = true;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget \"appTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t00E356F61AD99517003FC87E /* Debug */,\n\t\t\t\t00E356F71AD99517003FC87E /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget \"app\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t13B07F941A680F5B00A75B9A /* Debug */,\n\t\t\t\t13B07F951A680F5B00A75B9A /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject \"app\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t83CBBA201A601CBA00E9B192 /* Debug */,\n\t\t\t\t83CBBA211A601CBA00E9B192 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;\n}\n"
  },
  {
    "path": "examples/react-native/app/ios/app.xcodeproj/xcshareddata/xcschemes/app.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1210\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"13B07F861A680F5B00A75B9A\"\n               BuildableName = \"app.app\"\n               BlueprintName = \"app\"\n               ReferencedContainer = \"container:app.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"00E356ED1AD99517003FC87E\"\n               BuildableName = \"appTests.xctest\"\n               BlueprintName = \"appTests\"\n               ReferencedContainer = \"container:app.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"13B07F861A680F5B00A75B9A\"\n            BuildableName = \"app.app\"\n            BlueprintName = \"app\"\n            ReferencedContainer = \"container:app.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"13B07F861A680F5B00A75B9A\"\n            BuildableName = \"app.app\"\n            BlueprintName = \"app\"\n            ReferencedContainer = \"container:app.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "examples/react-native/app/ios/app.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"group:app.xcodeproj\">\n   </FileRef>\n   <FileRef\n      location = \"group:Pods/Pods.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "examples/react-native/app/ios/app.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "examples/react-native/app/ios/appTests/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "examples/react-native/app/ios/appTests/appTests.m",
    "content": "#import <UIKit/UIKit.h>\n#import <XCTest/XCTest.h>\n\n#import <React/RCTLog.h>\n#import <React/RCTRootView.h>\n\n#define TIMEOUT_SECONDS 600\n#define TEXT_TO_LOOK_FOR @\"Welcome to React\"\n\n@interface appTests : XCTestCase\n\n@end\n\n@implementation appTests\n\n- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL (^)(UIView *view))test\n{\n  if (test(view)) {\n    return YES;\n  }\n  for (UIView *subview in [view subviews]) {\n    if ([self findSubviewInView:subview matching:test]) {\n      return YES;\n    }\n  }\n  return NO;\n}\n\n- (void)testRendersWelcomeScreen\n{\n  UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController];\n  NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];\n  BOOL foundElement = NO;\n\n  __block NSString *redboxError = nil;\n#ifdef DEBUG\n  RCTSetLogFunction(\n      ^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {\n        if (level >= RCTLogLevelError) {\n          redboxError = message;\n        }\n      });\n#endif\n\n  while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {\n    [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];\n    [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];\n\n    foundElement = [self findSubviewInView:vc.view\n                                  matching:^BOOL(UIView *view) {\n                                    if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {\n                                      return YES;\n                                    }\n                                    return NO;\n                                  }];\n  }\n\n#ifdef DEBUG\n  RCTSetLogFunction(RCTDefaultLogFunction);\n#endif\n\n  XCTAssertNil(redboxError, @\"RedBox error: %@\", redboxError);\n  XCTAssertTrue(foundElement, @\"Couldn't find element with text '%@' in %d seconds\", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);\n}\n\n@end\n"
  },
  {
    "path": "examples/react-native/app/jest.config.js",
    "content": "module.exports = {\n  preset: 'react-native',\n  // The default `react-native` preset ignores `node_modules/(?!(jest-)?react-native|@react-native(-community)?)/`,\n  // which assumes RN packages live at `node_modules/<pkg>/`. With pnpm they live at\n  // `node_modules/.pnpm/<id>/node_modules/<pkg>/`, so the default pattern skips\n  // transformation and Jest chokes on the Flow types inside @react-native/js-polyfills.\n  // This pattern matches RN packages anywhere in the path.\n  transformIgnorePatterns: [\n    'node_modules/(?!.*(?:(?:jest-)?react-native|@react-native|@react-native-community|@react-native-async-storage|react-native-toast-message))',\n  ],\n  // AsyncStorage's native binding isn't available in jest. Map every import of it\n  // (from this app OR from `@amplitude/analytics-react-native` in the workspace) to\n  // the official mock. Using moduleNameMapper instead of jest.mock so the mock applies\n  // across all pnpm-resolved copies of the package.\n  moduleNameMapper: {\n    '^@react-native-async-storage/async-storage$':\n      '<rootDir>/../../../node_modules/@react-native-async-storage/async-storage/jest/async-storage-mock.js',\n  },\n};\n"
  },
  {
    "path": "examples/react-native/app/metro.config.js",
    "content": "const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');\nconst path = require('path');\n\nconst projectRoot = __dirname;\nconst workspaceRoot = path.resolve(projectRoot, '../../..');\n\nconst defaultConfig = getDefaultConfig(projectRoot);\n\nconst config = {\n  watchFolders: [workspaceRoot],\n  resolver: {\n    nodeModulesPaths: [\n      path.resolve(projectRoot, 'node_modules'),\n      path.resolve(workspaceRoot, 'node_modules'),\n    ],\n    // `packages/analytics-react-native` has react-native@0.70.6 as a devDep\n    // (its own dev/test target), while this example app uses 0.74.1. Without\n    // an alias, Metro's hierarchical lookup would resolve `react-native`\n    // imports inside the SDK to the SDK's local copy and bundle two RN\n    // versions. Force every `react-native`/`react` import to the app's copy.\n    extraNodeModules: {\n      'react-native': path.resolve(projectRoot, 'node_modules/react-native'),\n      react: path.resolve(projectRoot, 'node_modules/react'),\n    },\n  },\n};\n\nmodule.exports = mergeConfig(defaultConfig, config);\n"
  },
  {
    "path": "examples/react-native/app/package.json",
    "content": "{\n  \"name\": \"app\",\n  \"version\": \"0.0.1\",\n  \"private\": true,\n  \"scripts\": {\n    \"android\": \"react-native run-android\",\n    \"ios\": \"react-native run-ios\",\n    \"lint\": \"eslint .\",\n    \"start\": \"react-native start\",\n    \"test\": \"jest\"\n  },\n  \"dependencies\": {\n    \"@amplitude/analytics-react-native\": \"workspace:*\",\n    \"@react-native-async-storage/async-storage\": \"^1.23.1\",\n    \"react\": \"18.2.0\",\n    \"react-native\": \"0.74.1\",\n    \"react-native-toast-message\": \"^2.2.0\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.20.0\",\n    \"@babel/preset-env\": \"^7.20.0\",\n    \"@babel/runtime\": \"^7.20.0\",\n    \"@react-native/babel-preset\": \"0.74.83\",\n    \"@react-native/eslint-config\": \"0.74.83\",\n    \"@react-native/metro-config\": \"0.74.83\",\n    \"@react-native/typescript-config\": \"0.74.83\",\n    \"@types/react\": \"^18.2.6\",\n    \"@types/react-test-renderer\": \"^18.0.0\",\n    \"babel-jest\": \"^29.6.3\",\n    \"eslint\": \"^8.19.0\",\n    \"jest\": \"^29.6.3\",\n    \"prettier\": \"2.8.8\",\n    \"react-test-renderer\": \"18.2.0\",\n    \"typescript\": \"5.0.4\"\n  },\n  \"engines\": {\n    \"node\": \">=18\"\n  }\n}\n"
  },
  {
    "path": "examples/react-native/app/tsconfig.json",
    "content": "{\n  \"extends\": \"@react-native/typescript-config/tsconfig.json\"\n}\n"
  },
  {
    "path": "examples/react-native/expo-app/.expo-shared/assets.json",
    "content": "{\n  \"12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb\": true,\n  \"40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd\": true\n}\n"
  },
  {
    "path": "examples/react-native/expo-app/.gitignore",
    "content": "node_modules/\n.expo/\ndist/\nnpm-debug.*\n*.jks\n*.p8\n*.p12\n*.key\n*.mobileprovision\n*.orig.*\nweb-build/\n\n# macOS\n.DS_Store\n\n# @generated expo-cli sync-e7dcf75f4e856f7b6f3239b3f3a7dd614ee755a8\n# The following patterns were generated by expo-cli\n\n# OSX\n#\n.DS_Store\n\n# Xcode\n#\nbuild/\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\nxcuserdata\n*.xccheckout\n*.moved-aside\nDerivedData\n*.hmap\n*.ipa\n*.xcuserstate\nproject.xcworkspace\n\n# Android/IntelliJ\n#\nbuild/\n.idea\n.gradle\nlocal.properties\n*.iml\n*.hprof\n\n# node.js\n#\nnode_modules/\nnpm-debug.log\nyarn-error.log\n\n# BUCK\nbuck-out/\n\\.buckd/\n*.keystore\n!debug.keystore\n\n# Bundle artifacts\n*.jsbundle\n\n# CocoaPods\n/ios/Pods/\n\n# Expo\n.expo/\nweb-build/\ndist/\n\n# @end expo-cli"
  },
  {
    "path": "examples/react-native/expo-app/App.tsx",
    "content": "import {StatusBar} from 'expo-status-bar';\nimport {StyleSheet, Text, View} from 'react-native';\nimport {useEffect} from 'react';\nimport {identify, Identify, init, track} from '@amplitude/analytics-react-native';\nimport {LogLevel} from '@amplitude/analytics-types';\n\nexport default function App() {\n  useEffect(() => {\n    (async () => {\n        await init('API_KEY', 'example_user_id', {\n            logLevel: LogLevel.Verbose,\n        }).promise;\n        track('test');\n        await identify(new Identify().set('react-native-test', 'yes')).promise;\n    })();\n  }, []);\n  return (\n    <View style={styles.container}>\n      <Text>Open up App.tsx to start working on your app!</Text>\n      <StatusBar style=\"auto\" />\n    </View>\n  );\n}\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    backgroundColor: '#fff',\n    alignItems: 'center',\n    justifyContent: 'center',\n  },\n});\n"
  },
  {
    "path": "examples/react-native/expo-app/README.md",
    "content": "# React-Native Example App (Expo)\n## Documentation\n- [React Native SDK](https://www.docs.developers.amplitude.com/data/sdks/react-native-sdk/)\n\n## Setup\n```\n# cd into Amplitude-TypeScript/examples/react-native/expo-app directory\npnpm install\n```\n\n## Run\n### Prerequisite\n- [Setting up the development environment](https://reactnative.dev/docs/environment-setup)\n- [Install expo](https://docs.expo.dev/get-started/installation/)\n- Update the `API_KEY` in `App.tsx` file.\n\n### Android\n```\n# cd into Amplitude-TypeScript/examples/react-native/expo-app directory\npnpm run android\n```\n\n### iOS\n```\n# cd into Amplitude-TypeScript/examples/react-native/expo-app directory\npnpm run ios\n```\n\n### Web\n```\n# cd into Amplitude-TypeScript/examples/react-native/expo-app directory\npnpm run web\n```\n"
  },
  {
    "path": "examples/react-native/expo-app/android/.gitignore",
    "content": "# OSX\n#\n.DS_Store\n\n# Android/IntelliJ\n#\nbuild/\n.idea\n.gradle\nlocal.properties\n*.iml\n*.hprof\n\n# BUCK\nbuck-out/\n\\.buckd/\n*.keystore\n!debug.keystore\n\n# Bundle artifacts\n*.jsbundle\n"
  },
  {
    "path": "examples/react-native/expo-app/android/app/BUCK",
    "content": "# To learn about Buck see [Docs](https://buckbuild.com/).\n# To run your application with Buck:\n# - install Buck\n# - `npm start` - to start the packager\n# - `cd android`\n# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname \"CN=Android Debug,O=Android,C=US\"`\n# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck\n# - `buck install -r android/app` - compile, install and run application\n#\n\nload(\":build_defs.bzl\", \"create_aar_targets\", \"create_jar_targets\")\n\nlib_deps = []\n\ncreate_aar_targets(glob([\"libs/*.aar\"]))\n\ncreate_jar_targets(glob([\"libs/*.jar\"]))\n\nandroid_library(\n    name = \"all-libs\",\n    exported_deps = lib_deps,\n)\n\nandroid_library(\n    name = \"app-code\",\n    srcs = glob([\n        \"src/main/java/**/*.java\",\n    ]),\n    deps = [\n        \":all-libs\",\n        \":build_config\",\n        \":res\",\n    ],\n)\n\nandroid_build_config(\n    name = \"build_config\",\n    package = \"com.amplitude.expoapp\",\n)\n\nandroid_resource(\n    name = \"res\",\n    package = \"com.amplitude.expoapp\",\n    res = \"src/main/res\",\n)\n\nandroid_binary(\n    name = \"app\",\n    keystore = \"//android/keystores:debug\",\n    manifest = \"src/main/AndroidManifest.xml\",\n    package_type = \"debug\",\n    deps = [\n        \":app-code\",\n    ],\n)\n"
  },
  {
    "path": "examples/react-native/expo-app/android/app/build.gradle",
    "content": "apply plugin: \"com.android.application\"\n\nimport com.android.build.OutputFile\nimport org.apache.tools.ant.taskdefs.condition.Os\n\n/**\n * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets\n * and bundleReleaseJsAndAssets).\n * These basically call `react-native bundle` with the correct arguments during the Android build\n * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the\n * bundle directly from the development server. Below you can see all the possible configurations\n * and their defaults. If you decide to add a configuration block, make sure to add it before the\n * `apply from: \"../../node_modules/react-native/react.gradle\"` line.\n *\n * project.ext.react = [\n *   // the name of the generated asset file containing your JS bundle\n *   bundleAssetName: \"index.android.bundle\",\n *\n *   // the entry file for bundle generation. If none specified and\n *   // \"index.android.js\" exists, it will be used. Otherwise \"index.js\" is\n *   // default. Can be overridden with ENTRY_FILE environment variable.\n *   entryFile: \"index.android.js\",\n *\n *   // https://reactnative.dev/docs/performance#enable-the-ram-format\n *   bundleCommand: \"ram-bundle\",\n *\n *   // whether to bundle JS and assets in debug mode\n *   bundleInDebug: false,\n *\n *   // whether to bundle JS and assets in release mode\n *   bundleInRelease: true,\n *\n *   // whether to bundle JS and assets in another build variant (if configured).\n *   // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants\n *   // The configuration property can be in the following formats\n *   //         'bundleIn${productFlavor}${buildType}'\n *   //         'bundleIn${buildType}'\n *   // bundleInFreeDebug: true,\n *   // bundleInPaidRelease: true,\n *   // bundleInBeta: true,\n *\n *   // whether to disable dev mode in custom build variants (by default only disabled in release)\n *   // for example: to disable dev mode in the staging build type (if configured)\n *   devDisabledInStaging: true,\n *   // The configuration property can be in the following formats\n *   //         'devDisabledIn${productFlavor}${buildType}'\n *   //         'devDisabledIn${buildType}'\n *\n *   // the root of your project, i.e. where \"package.json\" lives\n *   root: \"../../\",\n *\n *   // where to put the JS bundle asset in debug mode\n *   jsBundleDirDebug: \"$buildDir/intermediates/assets/debug\",\n *\n *   // where to put the JS bundle asset in release mode\n *   jsBundleDirRelease: \"$buildDir/intermediates/assets/release\",\n *\n *   // where to put drawable resources / React Native assets, e.g. the ones you use via\n *   // require('./image.png')), in debug mode\n *   resourcesDirDebug: \"$buildDir/intermediates/res/merged/debug\",\n *\n *   // where to put drawable resources / React Native assets, e.g. the ones you use via\n *   // require('./image.png')), in release mode\n *   resourcesDirRelease: \"$buildDir/intermediates/res/merged/release\",\n *\n *   // by default the gradle tasks are skipped if none of the JS files or assets change; this means\n *   // that we don't look at files in android/ or ios/ to determine whether the tasks are up to\n *   // date; if you have any other folders that you want to ignore for performance reasons (gradle\n *   // indexes the entire tree), add them here. Alternatively, if you have JS files in android/\n *   // for example, you might want to remove it from here.\n *   inputExcludes: [\"android/**\", \"ios/**\"],\n *\n *   // override which node gets called and with what additional arguments\n *   nodeExecutableAndArgs: [\"node\"],\n *\n *   // supply additional arguments to the packager\n *   extraPackagerArgs: []\n * ]\n */\n\ndef projectRoot = rootDir.getAbsoluteFile().getParentFile().getAbsolutePath()\n\ndef reactNativeRoot = new File([\"node\", \"--print\", \"require.resolve('react-native/package.json')\"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath()\n\nproject.ext.react = [\n    entryFile: [\"node\", \"-e\", \"require('expo/scripts/resolveAppEntry')\", projectRoot, \"android\"].execute(null, rootDir).text.trim(),\n    enableHermes: (findProperty('expo.jsEngine') ?: \"jsc\") == \"hermes\",\n    hermesCommand: new File([\"node\", \"--print\", \"require.resolve('react-native/package.json')\"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath() + \"/sdks/hermesc/%OS-BIN%/hermesc\",\n    cliPath: \"${reactNativeRoot}/cli.js\",\n    composeSourceMapsPath: \"${reactNativeRoot}/scripts/compose-source-maps.js\",\n]\n\napply from: new File(reactNativeRoot, \"react.gradle\")\n\n/**\n * Set this to true to create two separate APKs instead of one:\n *   - An APK that only works on ARM devices\n *   - An APK that only works on x86 devices\n * The advantage is the size of the APK is reduced by about 4MB.\n * Upload all the APKs to the Play Store and people will download\n * the correct one based on the CPU architecture of their device.\n */\ndef enableSeparateBuildPerCPUArchitecture = false\n\n/**\n * Run Proguard to shrink the Java bytecode in release builds.\n */\ndef enableProguardInReleaseBuilds = (findProperty('android.enableProguardInReleaseBuilds') ?: false).toBoolean()\n\n/**\n * The preferred build flavor of JavaScriptCore.\n *\n * For example, to use the international variant, you can use:\n * `def jscFlavor = 'org.webkit:android-jsc-intl:+'`\n *\n * The international variant includes ICU i18n library and necessary data\n * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that\n * give correct results when using with locales other than en-US.  Note that\n * this variant is about 6MiB larger per architecture than default.\n */\ndef jscFlavor = 'org.webkit:android-jsc:+'\n\n/**\n * Whether to enable the Hermes VM.\n *\n * This should be set on project.ext.react and that value will be read here. If it is not set\n * on project.ext.react, JavaScript will not be compiled to Hermes Bytecode\n * and the benefits of using Hermes will therefore be sharply reduced.\n */\ndef enableHermes = project.ext.react.get(\"enableHermes\", false);\n\n/**\n * Architectures to build native code for.\n */\ndef reactNativeArchitectures() {\n    def value = project.getProperties().get(\"reactNativeArchitectures\")\n    return value ? value.split(\",\") : [\"armeabi-v7a\", \"x86\", \"x86_64\", \"arm64-v8a\"]\n}\n\nandroid {\n    ndkVersion rootProject.ext.ndkVersion\n\n    compileSdkVersion rootProject.ext.compileSdkVersion\n\n    defaultConfig {\n        applicationId 'com.amplitude.expoapp'\n        minSdkVersion rootProject.ext.minSdkVersion\n        targetSdkVersion rootProject.ext.targetSdkVersion\n        versionCode 1\n        versionName \"1.0.0\"\n        buildConfigField \"boolean\", \"IS_NEW_ARCHITECTURE_ENABLED\", isNewArchitectureEnabled().toString()\n\n        if (isNewArchitectureEnabled()) {\n            // We configure the NDK build only if you decide to opt-in for the New Architecture.\n            externalNativeBuild {\n                ndkBuild {\n                    arguments \"APP_PLATFORM=android-21\",\n                        \"APP_STL=c++_shared\",\n                        \"NDK_TOOLCHAIN_VERSION=clang\",\n                        \"GENERATED_SRC_DIR=$buildDir/generated/source\",\n                        \"PROJECT_BUILD_DIR=$buildDir\",\n                        \"REACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid\",\n                        \"REACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build\"\n                    cFlags \"-Wall\", \"-Werror\", \"-fexceptions\", \"-frtti\", \"-DWITH_INSPECTOR=1\"\n                    cppFlags \"-std=c++17\"\n                    // Make sure this target name is the same you specify inside the\n                    // src/main/jni/Android.mk file for the `LOCAL_MODULE` variable.\n                    targets \"expoapp_appmodules\"\n\n                    // Fix for windows limit on number of character in file paths and in command lines\n                    if (Os.isFamily(Os.FAMILY_WINDOWS)) {\n                        arguments \"NDK_APP_SHORT_COMMANDS=true\"\n                    }\n                }\n            }\n            if (!enableSeparateBuildPerCPUArchitecture) {\n                ndk {\n                    abiFilters (*reactNativeArchitectures())\n                }\n            }\n        }\n    }\n\n    if (isNewArchitectureEnabled()) {\n        // We configure the NDK build only if you decide to opt-in for the New Architecture.\n        externalNativeBuild {\n            ndkBuild {\n                path \"$projectDir/src/main/jni/Android.mk\"\n            }\n        }\n        def reactAndroidProjectDir = project(':ReactAndroid').projectDir\n        def packageReactNdkDebugLibs = tasks.register(\"packageReactNdkDebugLibs\", Copy) {\n            dependsOn(\":ReactAndroid:packageReactNdkDebugLibsForBuck\")\n            from(\"$reactAndroidProjectDir/src/main/jni/prebuilt/lib\")\n            into(\"$buildDir/react-ndk/exported\")\n        }\n        def packageReactNdkReleaseLibs = tasks.register(\"packageReactNdkReleaseLibs\", Copy) {\n            dependsOn(\":ReactAndroid:packageReactNdkReleaseLibsForBuck\")\n            from(\"$reactAndroidProjectDir/src/main/jni/prebuilt/lib\")\n            into(\"$buildDir/react-ndk/exported\")\n        }\n        afterEvaluate {\n            // If you wish to add a custom TurboModule or component locally,\n            // you should uncomment this line.\n            // preBuild.dependsOn(\"generateCodegenArtifactsFromSchema\")\n            preDebugBuild.dependsOn(packageReactNdkDebugLibs)\n            preReleaseBuild.dependsOn(packageReactNdkReleaseLibs)\n\n            // Due to a bug inside AGP, we have to explicitly set a dependency\n            // between configureNdkBuild* tasks and the preBuild tasks.\n            // This can be removed once this is solved: https://issuetracker.google.com/issues/207403732\n            configureNdkBuildRelease.dependsOn(preReleaseBuild)\n            configureNdkBuildDebug.dependsOn(preDebugBuild)\n            reactNativeArchitectures().each { architecture ->\n                tasks.findByName(\"configureNdkBuildDebug[${architecture}]\")?.configure {\n                    dependsOn(\"preDebugBuild\")\n                }\n                tasks.findByName(\"configureNdkBuildRelease[${architecture}]\")?.configure {\n                    dependsOn(\"preReleaseBuild\")\n                }\n            }\n        }\n    }\n\n    splits {\n        abi {\n            reset()\n            enable enableSeparateBuildPerCPUArchitecture\n            universalApk false  // If true, also generate a universal APK\n            include (*reactNativeArchitectures())\n        }\n    }\n    signingConfigs {\n        debug {\n            storeFile file('debug.keystore')\n            storePassword 'android'\n            keyAlias 'androiddebugkey'\n            keyPassword 'android'\n        }\n    }\n    buildTypes {\n        debug {\n            signingConfig signingConfigs.debug\n        }\n        release {\n            // Caution! In production, you need to generate your own keystore file.\n            // see https://reactnative.dev/docs/signed-apk-android.\n            signingConfig signingConfigs.debug\n            minifyEnabled enableProguardInReleaseBuilds\n            proguardFiles getDefaultProguardFile(\"proguard-android.txt\"), \"proguard-rules.pro\"\n        }\n    }\n\n    // applicationVariants are e.g. debug, release\n    applicationVariants.all { variant ->\n        variant.outputs.each { output ->\n            // For each separate APK per architecture, set a unique version code as described here:\n            // https://developer.android.com/studio/build/configure-apk-splits.html\n            def versionCodes = [\"armeabi-v7a\": 1, \"x86\": 2, \"arm64-v8a\": 3, \"x86_64\": 4]\n            def abi = output.getFilter(OutputFile.ABI)\n            if (abi != null) {  // null for the universal-debug, universal-release variants\n                output.versionCodeOverride =\n                        versionCodes.get(abi) * 1048576 + defaultConfig.versionCode\n            }\n\n        }\n    }\n}\n\n// Apply static values from `gradle.properties` to the `android.packagingOptions`\n// Accepts values in comma delimited lists, example:\n// android.packagingOptions.pickFirsts=/LICENSE,**/picasa.ini\n[\"pickFirsts\", \"excludes\", \"merges\", \"doNotStrip\"].each { prop ->\n    // Split option: 'foo,bar' -> ['foo', 'bar']\n    def options = (findProperty(\"android.packagingOptions.$prop\") ?: \"\").split(\",\");\n    // Trim all elements in place.\n    for (i in 0..<options.size()) options[i] = options[i].trim();\n    // `[] - \"\"` is essentially `[\"\"].filter(Boolean)` removing all empty strings.\n    options -= \"\"\n\n    if (options.length > 0) {\n        println \"android.packagingOptions.$prop += $options ($options.length)\"\n        // Ex: android.packagingOptions.pickFirsts += '**/SCCS/**'\n        options.each {\n            android.packagingOptions[prop] += it\n        }\n    }\n}\n\ndependencies {\n    implementation fileTree(dir: \"libs\", include: [\"*.jar\"])\n\n    //noinspection GradleDynamicVersion\n    implementation \"com.facebook.react:react-native:+\"  // From node_modules\n\n    def isGifEnabled = (findProperty('expo.gif.enabled') ?: \"\") == \"true\";\n    def isWebpEnabled = (findProperty('expo.webp.enabled') ?: \"\") == \"true\";\n    def isWebpAnimatedEnabled = (findProperty('expo.webp.animated') ?: \"\") == \"true\";\n    def frescoVersion = rootProject.ext.frescoVersion\n\n    // If your app supports Android versions before Ice Cream Sandwich (API level 14)\n    if (isGifEnabled || isWebpEnabled) {\n        implementation \"com.facebook.fresco:fresco:${frescoVersion}\"\n        implementation \"com.facebook.fresco:imagepipeline-okhttp3:${frescoVersion}\"\n    }\n\n    if (isGifEnabled) {\n        // For animated gif support\n        implementation \"com.facebook.fresco:animated-gif:${frescoVersion}\"\n    }\n\n    if (isWebpEnabled) {\n        // For webp support\n        implementation \"com.facebook.fresco:webpsupport:${frescoVersion}\"\n        if (isWebpAnimatedEnabled) {\n            // Animated webp support\n            implementation \"com.facebook.fresco:animated-webp:${frescoVersion}\"\n        }\n    }\n\n    implementation \"androidx.swiperefreshlayout:swiperefreshlayout:1.0.0\"\n    debugImplementation(\"com.facebook.flipper:flipper:${FLIPPER_VERSION}\") {\n        exclude group:'com.facebook.fbjni'\n    }\n    debugImplementation(\"com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}\") {\n        exclude group:'com.facebook.flipper'\n        exclude group:'com.squareup.okhttp3', module:'okhttp'\n    }\n    debugImplementation(\"com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}\") {\n        exclude group:'com.facebook.flipper'\n    }\n\n    if (enableHermes) {\n        //noinspection GradleDynamicVersion\n        implementation(\"com.facebook.react:hermes-engine:+\") { // From node_modules\n            exclude group:'com.facebook.fbjni'\n        }\n    } else {\n        implementation jscFlavor\n    }\n}\n\nif (isNewArchitectureEnabled()) {\n    // If new architecture is enabled, we let you build RN from source\n    // Otherwise we fallback to a prebuilt .aar bundled in the NPM package.\n    // This will be applied to all the imported transtitive dependency.\n    configurations.all {\n        resolutionStrategy.dependencySubstitution {\n            substitute(module(\"com.facebook.react:react-native\"))\n                    .using(project(\":ReactAndroid\"))\n                    .because(\"On New Architecture we're building React Native from source\")\n            substitute(module(\"com.facebook.react:hermes-engine\"))\n                    .using(project(\":ReactAndroid:hermes-engine\"))\n                    .because(\"On New Architecture we're building Hermes from source\")\n        }\n    }\n}\n\n// Run this once to be able to run the application with BUCK\n// puts all compile dependencies into folder libs for BUCK to use\ntask copyDownloadableDepsToLibs(type: Copy) {\n    from configurations.implementation\n    into 'libs'\n}\n\napply from: new File([\"node\", \"--print\", \"require.resolve('@react-native-community/cli-platform-android/package.json')\"].execute(null, rootDir).text.trim(), \"../native_modules.gradle\");\napplyNativeModulesAppBuildGradle(project)\n\ndef isNewArchitectureEnabled() {\n    // To opt-in for the New Architecture, you can either:\n    // - Set `newArchEnabled` to true inside the `gradle.properties` file\n    // - Invoke gradle with `-newArchEnabled=true`\n    // - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true`\n    return project.hasProperty(\"newArchEnabled\") && project.newArchEnabled == \"true\"\n}\n"
  },
  {
    "path": "examples/react-native/expo-app/android/app/build_defs.bzl",
    "content": "\"\"\"Helper definitions to glob .aar and .jar targets\"\"\"\n\ndef create_aar_targets(aarfiles):\n    for aarfile in aarfiles:\n        name = \"aars__\" + aarfile[aarfile.rindex(\"/\") + 1:aarfile.rindex(\".aar\")]\n        lib_deps.append(\":\" + name)\n        android_prebuilt_aar(\n            name = name,\n            aar = aarfile,\n        )\n\ndef create_jar_targets(jarfiles):\n    for jarfile in jarfiles:\n        name = \"jars__\" + jarfile[jarfile.rindex(\"/\") + 1:jarfile.rindex(\".jar\")]\n        lib_deps.append(\":\" + name)\n        prebuilt_jar(\n            name = name,\n            binary_jar = jarfile,\n        )\n"
  },
  {
    "path": "examples/react-native/expo-app/android/app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# react-native-reanimated\n-keep class com.swmansion.reanimated.** { *; }\n-keep class com.facebook.react.turbomodule.** { *; }\n\n# Add any project specific keep options here:\n"
  },
  {
    "path": "examples/react-native/expo-app/android/app/src/debug/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <uses-permission android:name=\"android.permission.SYSTEM_ALERT_WINDOW\"/>\n\n    <application android:usesCleartextTraffic=\"true\" tools:targetApi=\"28\" tools:ignore=\"GoogleAppIndexingWarning\" />\n</manifest>\n"
  },
  {
    "path": "examples/react-native/expo-app/android/app/src/debug/java/com/amplitude/expoapp/ReactNativeFlipper.java",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * <p>This source code is licensed under the MIT license found in the LICENSE file in the root\n * directory of this source tree.\n */\npackage com.amplitude.expoapp;\n\nimport android.content.Context;\nimport com.facebook.flipper.android.AndroidFlipperClient;\nimport com.facebook.flipper.android.utils.FlipperUtils;\nimport com.facebook.flipper.core.FlipperClient;\nimport com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin;\nimport com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin;\nimport com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin;\nimport com.facebook.flipper.plugins.inspector.DescriptorMapping;\nimport com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;\nimport com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;\nimport com.facebook.flipper.plugins.network.NetworkFlipperPlugin;\nimport com.facebook.flipper.plugins.react.ReactFlipperPlugin;\nimport com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;\nimport com.facebook.react.ReactInstanceManager;\nimport com.facebook.react.bridge.ReactContext;\nimport com.facebook.react.modules.network.NetworkingModule;\nimport okhttp3.OkHttpClient;\n\npublic class ReactNativeFlipper {\n  public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {\n    if (FlipperUtils.shouldEnableFlipper(context)) {\n      final FlipperClient client = AndroidFlipperClient.getInstance(context);\n      client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));\n      client.addPlugin(new ReactFlipperPlugin());\n      client.addPlugin(new DatabasesFlipperPlugin(context));\n      client.addPlugin(new SharedPreferencesFlipperPlugin(context));\n      client.addPlugin(CrashReporterPlugin.getInstance());\n      NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();\n      NetworkingModule.setCustomClientBuilder(\n          new NetworkingModule.CustomClientBuilder() {\n            @Override\n            public void apply(OkHttpClient.Builder builder) {\n              builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));\n            }\n          });\n      client.addPlugin(networkFlipperPlugin);\n      client.start();\n      // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized\n      // Hence we run if after all native modules have been initialized\n      ReactContext reactContext = reactInstanceManager.getCurrentReactContext();\n      if (reactContext == null) {\n        reactInstanceManager.addReactInstanceEventListener(\n            new ReactInstanceManager.ReactInstanceEventListener() {\n              @Override\n              public void onReactContextInitialized(ReactContext reactContext) {\n                reactInstanceManager.removeReactInstanceEventListener(this);\n                reactContext.runOnNativeModulesQueueThread(\n                    new Runnable() {\n                      @Override\n                      public void run() {\n                        client.addPlugin(new FrescoFlipperPlugin());\n                      }\n                    });\n              }\n            });\n      } else {\n        client.addPlugin(new FrescoFlipperPlugin());\n      }\n    }\n  }\n}"
  },
  {
    "path": "examples/react-native/expo-app/android/app/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" package=\"com.amplitude.expoapp\">\n  <uses-permission android:name=\"android.permission.INTERNET\"/>\n  <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\"/>\n  <uses-permission android:name=\"android.permission.SYSTEM_ALERT_WINDOW\"/>\n  <uses-permission android:name=\"android.permission.VIBRATE\"/>\n  <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>\n  <queries>\n    <intent>\n      <action android:name=\"android.intent.action.VIEW\"/>\n      <category android:name=\"android.intent.category.BROWSABLE\"/>\n      <data android:scheme=\"https\"/>\n    </intent>\n  </queries>\n  <application android:name=\".MainApplication\" android:label=\"@string/app_name\" android:icon=\"@mipmap/ic_launcher\" android:roundIcon=\"@mipmap/ic_launcher_round\" android:allowBackup=\"true\" android:theme=\"@style/AppTheme\" android:usesCleartextTraffic=\"true\">\n    <meta-data android:name=\"expo.modules.updates.ENABLED\" android:value=\"true\"/>\n    <meta-data android:name=\"expo.modules.updates.EXPO_SDK_VERSION\" android:value=\"45.0.0\"/>\n    <meta-data android:name=\"expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH\" android:value=\"ALWAYS\"/>\n    <meta-data android:name=\"expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS\" android:value=\"0\"/>\n    <meta-data android:name=\"expo.modules.updates.EXPO_UPDATE_URL\" android:value=\"https://exp.host/@anonymous/expo-app\"/>\n    <activity android:name=\".MainActivity\" android:label=\"@string/app_name\" android:configChanges=\"keyboard|keyboardHidden|orientation|screenSize|uiMode\" android:launchMode=\"singleTask\" android:windowSoftInputMode=\"adjustResize\" android:theme=\"@style/Theme.App.SplashScreen\" android:exported=\"true\" android:screenOrientation=\"portrait\">\n      <intent-filter>\n        <action android:name=\"android.intent.action.MAIN\"/>\n        <category android:name=\"android.intent.category.LAUNCHER\"/>\n      </intent-filter>\n      <intent-filter>\n        <action android:name=\"android.intent.action.VIEW\"/>\n        <category android:name=\"android.intent.category.DEFAULT\"/>\n        <category android:name=\"android.intent.category.BROWSABLE\"/>\n        <data android:scheme=\"com.amplitude.expoapp\"/>\n      </intent-filter>\n    </activity>\n    <activity android:name=\"com.facebook.react.devsupport.DevSettingsActivity\" android:exported=\"false\"/>\n  </application>\n</manifest>"
  },
  {
    "path": "examples/react-native/expo-app/android/app/src/main/java/com/amplitude/expoapp/MainActivity.java",
    "content": "package com.amplitude.expoapp;\n\nimport android.os.Build;\nimport android.os.Bundle;\n\nimport com.facebook.react.ReactActivity;\nimport com.facebook.react.ReactActivityDelegate;\nimport com.facebook.react.ReactRootView;\n\nimport expo.modules.ReactActivityDelegateWrapper;\n\npublic class MainActivity extends ReactActivity {\n  @Override\n  protected void onCreate(Bundle savedInstanceState) {\n    // Set the theme to AppTheme BEFORE onCreate to support \n    // coloring the background, status bar, and navigation bar.\n    // This is required for expo-splash-screen.\n    setTheme(R.style.AppTheme);\n    super.onCreate(null);\n  }\n\n  /**\n   * Returns the name of the main component registered from JavaScript.\n   * This is used to schedule rendering of the component.\n   */\n  @Override\n  protected String getMainComponentName() {\n    return \"main\";\n  }\n\n  @Override\n  protected ReactActivityDelegate createReactActivityDelegate() {\n    return new ReactActivityDelegateWrapper(this,\n      new ReactActivityDelegate(this, getMainComponentName())\n    );\n  }\n\n  /**\n   * Align the back button behavior with Android S\n   * where moving root activities to background instead of finishing activities.\n   * @see <a href=\"https://developer.android.com/reference/android/app/Activity#onBackPressed()\">onBackPressed</a>\n   */\n  @Override\n  public void invokeDefaultOnBackPressed() {\n    if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) {\n      if (!moveTaskToBack(false)) {\n        // For non-root activities, use the default implementation to finish them.\n        super.invokeDefaultOnBackPressed();\n      }\n      return;\n    }\n\n    // Use the default back button implementation on Android S\n    // because it's doing more than {@link Activity#moveTaskToBack} in fact.\n    super.invokeDefaultOnBackPressed();\n  }\n}\n"
  },
  {
    "path": "examples/react-native/expo-app/android/app/src/main/java/com/amplitude/expoapp/MainApplication.java",
    "content": "package com.amplitude.expoapp;\n\nimport android.app.Application;\nimport android.content.Context;\nimport android.content.res.Configuration;\nimport androidx.annotation.NonNull;\n\nimport com.facebook.react.PackageList;\nimport com.facebook.react.ReactApplication;\nimport com.facebook.react.ReactInstanceManager;\nimport com.facebook.react.ReactNativeHost;\nimport com.facebook.react.ReactPackage;\nimport com.facebook.react.config.ReactFeatureFlags;\nimport com.facebook.soloader.SoLoader;\nimport com.amplitude.expoapp.newarchitecture.MainApplicationReactNativeHost;\n\nimport expo.modules.ApplicationLifecycleDispatcher;\nimport expo.modules.ReactNativeHostWrapper;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.util.List;\n\npublic class MainApplication extends Application implements ReactApplication {\n  private final ReactNativeHost mReactNativeHost = new ReactNativeHostWrapper(\n    this,\n    new ReactNativeHost(this) {\n    @Override\n    public boolean getUseDeveloperSupport() {\n      return BuildConfig.DEBUG;\n    }\n\n    @Override\n    protected List<ReactPackage> getPackages() {\n      @SuppressWarnings(\"UnnecessaryLocalVariable\")\n      List<ReactPackage> packages = new PackageList(this).getPackages();\n      // Packages that cannot be autolinked yet can be added manually here, for example:\n      // packages.add(new MyReactNativePackage());\n      return packages;\n    }\n\n    @Override\n    protected String getJSMainModuleName() {\n      return \"index\";\n    }\n  });\n\n  private final ReactNativeHost mNewArchitectureNativeHost =\n      new ReactNativeHostWrapper(this, new MainApplicationReactNativeHost(this));\n\n  @Override\n  public ReactNativeHost getReactNativeHost() {\n    if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {\n      return mNewArchitectureNativeHost;\n    } else {\n      return mReactNativeHost;\n    }\n  }\n\n  @Override\n  public void onCreate() {\n    super.onCreate();\n    // If you opted-in for the New Architecture, we enable the TurboModule system\n    ReactFeatureFlags.useTurboModules = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;\n    SoLoader.init(this, /* native exopackage */ false);\n\n    initializeFlipper(this, getReactNativeHost().getReactInstanceManager());\n    ApplicationLifecycleDispatcher.onApplicationCreate(this);\n  }\n\n  @Override\n  public void onConfigurationChanged(@NonNull Configuration newConfig) {\n    super.onConfigurationChanged(newConfig);\n    ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig);\n  }\n\n  /**\n   * Loads Flipper in React Native templates. Call this in the onCreate method with something like\n   * initializeFlipper(this, getReactNativeHost().getReactInstanceManager());\n   *\n   * @param context\n   * @param reactInstanceManager\n   */\n  private static void initializeFlipper(\n      Context context, ReactInstanceManager reactInstanceManager) {\n    if (BuildConfig.DEBUG) {\n      try {\n        /*\n         We use reflection here to pick up the class that initializes Flipper,\n        since Flipper library is not available in release mode\n        */\n        Class<?> aClass = Class.forName(\"com.amplitude.expoapp.ReactNativeFlipper\");\n        aClass\n            .getMethod(\"initializeFlipper\", Context.class, ReactInstanceManager.class)\n            .invoke(null, context, reactInstanceManager);\n      } catch (ClassNotFoundException e) {\n        e.printStackTrace();\n      } catch (NoSuchMethodException e) {\n        e.printStackTrace();\n      } catch (IllegalAccessException e) {\n        e.printStackTrace();\n      } catch (InvocationTargetException e) {\n        e.printStackTrace();\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "examples/react-native/expo-app/android/app/src/main/java/com/amplitude/expoapp/newarchitecture/MainApplicationReactNativeHost.java",
    "content": "package com.amplitude.expoapp.newarchitecture;\n\nimport android.app.Application;\nimport androidx.annotation.NonNull;\nimport com.facebook.react.PackageList;\nimport com.facebook.react.ReactInstanceManager;\nimport com.facebook.react.ReactNativeHost;\nimport com.facebook.react.ReactPackage;\nimport com.facebook.react.ReactPackageTurboModuleManagerDelegate;\nimport com.facebook.react.bridge.JSIModulePackage;\nimport com.facebook.react.bridge.JSIModuleProvider;\nimport com.facebook.react.bridge.JSIModuleSpec;\nimport com.facebook.react.bridge.JSIModuleType;\nimport com.facebook.react.bridge.JavaScriptContextHolder;\nimport com.facebook.react.bridge.ReactApplicationContext;\nimport com.facebook.react.bridge.UIManager;\nimport com.facebook.react.fabric.ComponentFactory;\nimport com.facebook.react.fabric.CoreComponentsRegistry;\nimport com.facebook.react.fabric.EmptyReactNativeConfig;\nimport com.facebook.react.fabric.FabricJSIModuleProvider;\nimport com.facebook.react.uimanager.ViewManagerRegistry;\nimport com.amplitude.expoapp.BuildConfig;\nimport com.amplitude.expoapp.newarchitecture.components.MainComponentsRegistry;\nimport com.amplitude.expoapp.newarchitecture.modules.MainApplicationTurboModuleManagerDelegate;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * A {@link ReactNativeHost} that helps you load everything needed for the New Architecture, both\n * TurboModule delegates and the Fabric Renderer.\n *\n * <p>Please note that this class is used ONLY if you opt-in for the New Architecture (see the\n * `newArchEnabled` property). Is ignored otherwise.\n */\npublic class MainApplicationReactNativeHost extends ReactNativeHost {\n  public MainApplicationReactNativeHost(Application application) {\n    super(application);\n  }\n\n  @Override\n  public boolean getUseDeveloperSupport() {\n    return BuildConfig.DEBUG;\n  }\n\n  @Override\n  protected List<ReactPackage> getPackages() {\n    List<ReactPackage> packages = new PackageList(this).getPackages();\n    // Packages that cannot be autolinked yet can be added manually here, for example:\n    //     packages.add(new MyReactNativePackage());\n    // TurboModules must also be loaded here providing a valid TurboReactPackage implementation:\n    //     packages.add(new TurboReactPackage() { ... });\n    // If you have custom Fabric Components, their ViewManagers should also be loaded here\n    // inside a ReactPackage.\n    return packages;\n  }\n\n  @Override\n  protected String getJSMainModuleName() {\n    return \"index\";\n  }\n\n  @NonNull\n  @Override\n  protected ReactPackageTurboModuleManagerDelegate.Builder\n      getReactPackageTurboModuleManagerDelegateBuilder() {\n    // Here we provide the ReactPackageTurboModuleManagerDelegate Builder. This is necessary\n    // for the new architecture and to use TurboModules correctly.\n    return new MainApplicationTurboModuleManagerDelegate.Builder();\n  }\n\n  @Override\n  protected JSIModulePackage getJSIModulePackage() {\n    return new JSIModulePackage() {\n      @Override\n      public List<JSIModuleSpec> getJSIModules(\n          final ReactApplicationContext reactApplicationContext,\n          final JavaScriptContextHolder jsContext) {\n        final List<JSIModuleSpec> specs = new ArrayList<>();\n\n        // Here we provide a new JSIModuleSpec that will be responsible of providing the\n        // custom Fabric Components.\n        specs.add(\n            new JSIModuleSpec() {\n              @Override\n              public JSIModuleType getJSIModuleType() {\n                return JSIModuleType.UIManager;\n              }\n\n              @Override\n              public JSIModuleProvider<UIManager> getJSIModuleProvider() {\n                final ComponentFactory componentFactory = new ComponentFactory();\n                CoreComponentsRegistry.register(componentFactory);\n\n                // Here we register a Components Registry.\n                // The one that is generated with the template contains no components\n                // and just provides you the one from React Native core.\n                MainComponentsRegistry.register(componentFactory);\n\n                final ReactInstanceManager reactInstanceManager = getReactInstanceManager();\n\n                ViewManagerRegistry viewManagerRegistry =\n                    new ViewManagerRegistry(\n                        reactInstanceManager.getOrCreateViewManagers(reactApplicationContext));\n\n                return new FabricJSIModuleProvider(\n                    reactApplicationContext,\n                    componentFactory,\n                    new EmptyReactNativeConfig(),\n                    viewManagerRegistry);\n              }\n            });\n        return specs;\n      }\n    };\n  }\n}\n"
  },
  {
    "path": "examples/react-native/expo-app/android/app/src/main/java/com/amplitude/expoapp/newarchitecture/components/MainComponentsRegistry.java",
    "content": "package com.amplitude.expoapp.newarchitecture.components;\n\nimport com.facebook.jni.HybridData;\nimport com.facebook.proguard.annotations.DoNotStrip;\nimport com.facebook.react.fabric.ComponentFactory;\nimport com.facebook.soloader.SoLoader;\n\n/**\n * Class responsible to load the custom Fabric Components. This class has native methods and needs a\n * corresponding C++ implementation/header file to work correctly (already placed inside the jni/\n * folder for you).\n *\n * <p>Please note that this class is used ONLY if you opt-in for the New Architecture (see the\n * `newArchEnabled` property). Is ignored otherwise.\n */\n@DoNotStrip\npublic class MainComponentsRegistry {\n  static {\n    SoLoader.loadLibrary(\"fabricjni\");\n  }\n\n  @DoNotStrip private final HybridData mHybridData;\n\n  @DoNotStrip\n  private native HybridData initHybrid(ComponentFactory componentFactory);\n\n  @DoNotStrip\n  private MainComponentsRegistry(ComponentFactory componentFactory) {\n    mHybridData = initHybrid(componentFactory);\n  }\n\n  @DoNotStrip\n  public static MainComponentsRegistry register(ComponentFactory componentFactory) {\n    return new MainComponentsRegistry(componentFactory);\n  }\n}\n"
  },
  {
    "path": "examples/react-native/expo-app/android/app/src/main/java/com/amplitude/expoapp/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate.java",
    "content": "package com.amplitude.expoapp.newarchitecture.modules;\n\nimport com.facebook.jni.HybridData;\nimport com.facebook.react.ReactPackage;\nimport com.facebook.react.ReactPackageTurboModuleManagerDelegate;\nimport com.facebook.react.bridge.ReactApplicationContext;\nimport com.facebook.soloader.SoLoader;\nimport java.util.List;\n\n/**\n * Class responsible to load the TurboModules. This class has native methods and needs a\n * corresponding C++ implementation/header file to work correctly (already placed inside the jni/\n * folder for you).\n *\n * <p>Please note that this class is used ONLY if you opt-in for the New Architecture (see the\n * `newArchEnabled` property). Is ignored otherwise.\n */\npublic class MainApplicationTurboModuleManagerDelegate\n    extends ReactPackageTurboModuleManagerDelegate {\n\n  private static volatile boolean sIsSoLibraryLoaded;\n\n  protected MainApplicationTurboModuleManagerDelegate(\n      ReactApplicationContext reactApplicationContext, List<ReactPackage> packages) {\n    super(reactApplicationContext, packages);\n  }\n\n  protected native HybridData initHybrid();\n\n  native boolean canCreateTurboModule(String moduleName);\n\n  public static class Builder extends ReactPackageTurboModuleManagerDelegate.Builder {\n    protected MainApplicationTurboModuleManagerDelegate build(\n        ReactApplicationContext context, List<ReactPackage> packages) {\n      return new MainApplicationTurboModuleManagerDelegate(context, packages);\n    }\n  }\n\n  @Override\n  protected synchronized void maybeLoadOtherSoLibraries() {\n    if (!sIsSoLibraryLoaded) {\n      // If you change the name of your application .so file in the Android.mk file,\n      // make sure you update the name here as well.\n      SoLoader.loadLibrary(\"expoapp_appmodules\");\n      sIsSoLibraryLoaded = true;\n    }\n  }\n}\n"
  },
  {
    "path": "examples/react-native/expo-app/android/app/src/main/jni/Android.mk",
    "content": "THIS_DIR := $(call my-dir)\n\ninclude $(REACT_ANDROID_DIR)/Android-prebuilt.mk\n\n# If you wish to add a custom TurboModule or Fabric component in your app you\n# will have to include the following autogenerated makefile.\n# include $(GENERATED_SRC_DIR)/codegen/jni/Android.mk\ninclude $(CLEAR_VARS)\n\nLOCAL_PATH := $(THIS_DIR)\n\n# You can customize the name of your application .so file here.\nLOCAL_MODULE := expoapp_appmodules\n\nLOCAL_C_INCLUDES := $(LOCAL_PATH)\nLOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp)\nLOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)\n\n# If you wish to add a custom TurboModule or Fabric component in your app you\n# will have to uncomment those lines to include the generated source \n# files from the codegen (placed in $(GENERATED_SRC_DIR)/codegen/jni)\n#\n# LOCAL_C_INCLUDES += $(GENERATED_SRC_DIR)/codegen/jni\n# LOCAL_SRC_FILES += $(wildcard $(GENERATED_SRC_DIR)/codegen/jni/*.cpp)\n# LOCAL_EXPORT_C_INCLUDES += $(GENERATED_SRC_DIR)/codegen/jni\n\n# Here you should add any native library you wish to depend on.\nLOCAL_SHARED_LIBRARIES := \\\n  libfabricjni \\\n  libfbjni \\\n  libfolly_futures \\\n  libfolly_json \\\n  libglog \\\n  libjsi \\\n  libreact_codegen_rncore \\\n  libreact_debug \\\n  libreact_nativemodule_core \\\n  libreact_render_componentregistry \\\n  libreact_render_core \\\n  libreact_render_debug \\\n  libreact_render_graphics \\\n  librrc_view \\\n  libruntimeexecutor \\\n  libturbomodulejsijni \\\n  libyoga\n\nLOCAL_CFLAGS := -DLOG_TAG=\\\"ReactNative\\\" -fexceptions -frtti -std=c++17 -Wall\n\ninclude $(BUILD_SHARED_LIBRARY)\n"
  },
  {
    "path": "examples/react-native/expo-app/android/app/src/main/jni/MainApplicationModuleProvider.cpp",
    "content": "#include \"MainApplicationModuleProvider.h\"\n\n#include <rncore.h>\n\nnamespace facebook {\nnamespace react {\n\nstd::shared_ptr<TurboModule> MainApplicationModuleProvider(\n    const std::string moduleName,\n    const JavaTurboModule::InitParams &params) {\n  // Here you can provide your own module provider for TurboModules coming from\n  // either your application or from external libraries. The approach to follow\n  // is similar to the following (for a library called `samplelibrary`:\n  //\n  // auto module = samplelibrary_ModuleProvider(moduleName, params);\n  // if (module != nullptr) {\n  //    return module;\n  // }\n  // return rncore_ModuleProvider(moduleName, params);\n  return rncore_ModuleProvider(moduleName, params);\n}\n\n} // namespace react\n} // namespace facebook\n"
  },
  {
    "path": "examples/react-native/expo-app/android/app/src/main/jni/MainApplicationModuleProvider.h",
    "content": "#pragma once\n\n#include <memory>\n#include <string>\n\n#include <ReactCommon/JavaTurboModule.h>\n\nnamespace facebook {\nnamespace react {\n\nstd::shared_ptr<TurboModule> MainApplicationModuleProvider(\n    const std::string moduleName,\n    const JavaTurboModule::InitParams &params);\n\n} // namespace react\n} // namespace facebook\n"
  },
  {
    "path": "examples/react-native/expo-app/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp",
    "content": "#include \"MainApplicationTurboModuleManagerDelegate.h\"\n#include \"MainApplicationModuleProvider.h\"\n\nnamespace facebook {\nnamespace react {\n\njni::local_ref<MainApplicationTurboModuleManagerDelegate::jhybriddata>\nMainApplicationTurboModuleManagerDelegate::initHybrid(\n    jni::alias_ref<jhybridobject>) {\n  return makeCxxInstance();\n}\n\nvoid MainApplicationTurboModuleManagerDelegate::registerNatives() {\n  registerHybrid({\n      makeNativeMethod(\n          \"initHybrid\", MainApplicationTurboModuleManagerDelegate::initHybrid),\n      makeNativeMethod(\n          \"canCreateTurboModule\",\n          MainApplicationTurboModuleManagerDelegate::canCreateTurboModule),\n  });\n}\n\nstd::shared_ptr<TurboModule>\nMainApplicationTurboModuleManagerDelegate::getTurboModule(\n    const std::string name,\n    const std::shared_ptr<CallInvoker> jsInvoker) {\n  // Not implemented yet: provide pure-C++ NativeModules here.\n  return nullptr;\n}\n\nstd::shared_ptr<TurboModule>\nMainApplicationTurboModuleManagerDelegate::getTurboModule(\n    const std::string name,\n    const JavaTurboModule::InitParams &params) {\n  return MainApplicationModuleProvider(name, params);\n}\n\nbool MainApplicationTurboModuleManagerDelegate::canCreateTurboModule(\n    std::string name) {\n  return getTurboModule(name, nullptr) != nullptr ||\n      getTurboModule(name, {.moduleName = name}) != nullptr;\n}\n\n} // namespace react\n} // namespace facebook\n"
  },
  {
    "path": "examples/react-native/expo-app/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h",
    "content": "#include <memory>\n#include <string>\n\n#include <ReactCommon/TurboModuleManagerDelegate.h>\n#include <fbjni/fbjni.h>\n\nnamespace facebook {\nnamespace react {\n\nclass MainApplicationTurboModuleManagerDelegate\n    : public jni::HybridClass<\n          MainApplicationTurboModuleManagerDelegate,\n          TurboModuleManagerDelegate> {\n public:\n  // Adapt it to the package you used for your Java class.\n  static constexpr auto kJavaDescriptor =\n      \"Lcom/amplitude/expoapp/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate;\";\n\n  static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jhybridobject>);\n\n  static void registerNatives();\n\n  std::shared_ptr<TurboModule> getTurboModule(\n      const std::string name,\n      const std::shared_ptr<CallInvoker> jsInvoker) override;\n  std::shared_ptr<TurboModule> getTurboModule(\n      const std::string name,\n      const JavaTurboModule::InitParams &params) override;\n\n  /**\n   * Test-only method. Allows user to verify whether a TurboModule can be\n   * created by instances of this class.\n   */\n  bool canCreateTurboModule(std::string name);\n};\n\n} // namespace react\n} // namespace facebook\n"
  },
  {
    "path": "examples/react-native/expo-app/android/app/src/main/jni/MainComponentsRegistry.cpp",
    "content": "#include \"MainComponentsRegistry.h\"\n\n#include <CoreComponentsRegistry.h>\n#include <fbjni/fbjni.h>\n#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>\n#include <react/renderer/components/rncore/ComponentDescriptors.h>\n\nnamespace facebook {\nnamespace react {\n\nMainComponentsRegistry::MainComponentsRegistry(ComponentFactory *delegate) {}\n\nstd::shared_ptr<ComponentDescriptorProviderRegistry const>\nMainComponentsRegistry::sharedProviderRegistry() {\n  auto providerRegistry = CoreComponentsRegistry::sharedProviderRegistry();\n\n  // Custom Fabric Components go here. You can register custom\n  // components coming from your App or from 3rd party libraries here.\n  //\n  // providerRegistry->add(concreteComponentDescriptorProvider<\n  //        AocViewerComponentDescriptor>());\n  return providerRegistry;\n}\n\njni::local_ref<MainComponentsRegistry::jhybriddata>\nMainComponentsRegistry::initHybrid(\n    jni::alias_ref<jclass>,\n    ComponentFactory *delegate) {\n  auto instance = makeCxxInstance(delegate);\n\n  auto buildRegistryFunction =\n      [](EventDispatcher::Weak const &eventDispatcher,\n         ContextContainer::Shared const &contextContainer)\n      -> ComponentDescriptorRegistry::Shared {\n    auto registry = MainComponentsRegistry::sharedProviderRegistry()\n                        ->createComponentDescriptorRegistry(\n                            {eventDispatcher, contextContainer});\n\n    auto mutableRegistry =\n        std::const_pointer_cast<ComponentDescriptorRegistry>(registry);\n\n    mutableRegistry->setFallbackComponentDescriptor(\n        std::make_shared<UnimplementedNativeViewComponentDescriptor>(\n            ComponentDescriptorParameters{\n                eventDispatcher, contextContainer, nullptr}));\n\n    return registry;\n  };\n\n  delegate->buildRegistryFunction = buildRegistryFunction;\n  return instance;\n}\n\nvoid MainComponentsRegistry::registerNatives() {\n  registerHybrid({\n      makeNativeMethod(\"initHybrid\", MainComponentsRegistry::initHybrid),\n  });\n}\n\n} // namespace react\n} // namespace facebook\n"
  },
  {
    "path": "examples/react-native/expo-app/android/app/src/main/jni/MainComponentsRegistry.h",
    "content": "#pragma once\n\n#include <ComponentFactory.h>\n#include <fbjni/fbjni.h>\n#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>\n#include <react/renderer/componentregistry/ComponentDescriptorRegistry.h>\n\nnamespace facebook {\nnamespace react {\n\nclass MainComponentsRegistry\n    : public facebook::jni::HybridClass<MainComponentsRegistry> {\n public:\n  // Adapt it to the package you used for your Java class.\n  constexpr static auto kJavaDescriptor =\n      \"Lcom/amplitude/expoapp/newarchitecture/components/MainComponentsRegistry;\";\n\n  static void registerNatives();\n\n  MainComponentsRegistry(ComponentFactory *delegate);\n\n private:\n  static std::shared_ptr<ComponentDescriptorProviderRegistry const>\n  sharedProviderRegistry();\n\n  static jni::local_ref<jhybriddata> initHybrid(\n      jni::alias_ref<jclass>,\n      ComponentFactory *delegate);\n};\n\n} // namespace react\n} // namespace facebook\n"
  },
  {
    "path": "examples/react-native/expo-app/android/app/src/main/jni/OnLoad.cpp",
    "content": "#include <fbjni/fbjni.h>\n#include \"MainApplicationTurboModuleManagerDelegate.h\"\n#include \"MainComponentsRegistry.h\"\n\nJNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {\n  return facebook::jni::initialize(vm, [] {\n    facebook::react::MainApplicationTurboModuleManagerDelegate::\n        registerNatives();\n    facebook::react::MainComponentsRegistry::registerNatives();\n  });\n}\n"
  },
  {
    "path": "examples/react-native/expo-app/android/app/src/main/res/drawable/rn_edit_text_material.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Copyright (C) 2014 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n<inset xmlns:android=\"http://schemas.android.com/apk/res/android\"\n       android:insetLeft=\"@dimen/abc_edit_text_inset_horizontal_material\"\n       android:insetRight=\"@dimen/abc_edit_text_inset_horizontal_material\"\n       android:insetTop=\"@dimen/abc_edit_text_inset_top_material\"\n       android:insetBottom=\"@dimen/abc_edit_text_inset_bottom_material\">\n\n    <selector>\n        <!-- \n          This file is a copy of abc_edit_text_material (https://bit.ly/3k8fX7I).\n          The item below with state_pressed=\"false\" and state_focused=\"false\" causes a NullPointerException.\n          NullPointerException:tempt to invoke virtual method 'android.graphics.drawable.Drawable android.graphics.drawable.Drawable$ConstantState.newDrawable(android.content.res.Resources)'\n\n          <item android:state_pressed=\"false\" android:state_focused=\"false\" android:drawable=\"@drawable/abc_textfield_default_mtrl_alpha\"/>\n\n          For more info, see https://bit.ly/3CdLStv (react-native/pull/29452) and https://bit.ly/3nxOMoR.\n        -->\n        <item android:state_enabled=\"false\" android:drawable=\"@drawable/abc_textfield_default_mtrl_alpha\"/>\n        <item android:drawable=\"@drawable/abc_textfield_activated_mtrl_alpha\"/>\n    </selector>\n\n</inset>\n"
  },
  {
    "path": "examples/react-native/expo-app/android/app/src/main/res/drawable/splashscreen.xml",
    "content": "<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n  <item android:drawable=\"@color/splashscreen_background\"/>\n</layer-list>"
  },
  {
    "path": "examples/react-native/expo-app/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@color/iconBackground\"/>\n    <foreground android:drawable=\"@mipmap/ic_launcher_foreground\"/>\n</adaptive-icon>"
  },
  {
    "path": "examples/react-native/expo-app/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@color/iconBackground\"/>\n    <foreground android:drawable=\"@mipmap/ic_launcher_foreground\"/>\n</adaptive-icon>"
  },
  {
    "path": "examples/react-native/expo-app/android/app/src/main/res/values/colors.xml",
    "content": "<resources>\n  <color name=\"splashscreen_background\">#ffffff</color>\n  <color name=\"iconBackground\">#FFFFFF</color>\n  <color name=\"colorPrimary\">#023c69</color>\n  <color name=\"colorPrimaryDark\">#ffffff</color>\n</resources>"
  },
  {
    "path": "examples/react-native/expo-app/android/app/src/main/res/values/strings.xml",
    "content": "<resources>\n  <string name=\"app_name\">expo-app</string>\n  <string name=\"expo_splash_screen_resize_mode\" translatable=\"false\">contain</string>\n  <string name=\"expo_splash_screen_status_bar_translucent\" translatable=\"false\">false</string>\n</resources>"
  },
  {
    "path": "examples/react-native/expo-app/android/app/src/main/res/values/styles.xml",
    "content": "<resources xmlns:tools=\"http://schemas.android.com/tools\">\n  <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.NoActionBar\">\n    <item name=\"android:textColor\">@android:color/black</item>\n    <item name=\"android:editTextStyle\">@style/ResetEditText</item>\n    <item name=\"android:editTextBackground\">@drawable/rn_edit_text_material</item>\n    <item name=\"colorPrimary\">@color/colorPrimary</item>\n    <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n  </style>\n  <style name=\"ResetEditText\" parent=\"@android:style/Widget.EditText\">\n    <item name=\"android:padding\">0dp</item>\n    <item name=\"android:textColorHint\">#c8c8c8</item>\n    <item name=\"android:textColor\">@android:color/black</item>\n  </style>\n  <style name=\"Theme.App.SplashScreen\" parent=\"AppTheme\">\n    <item name=\"android:windowBackground\">@drawable/splashscreen</item>\n  </style>\n</resources>"
  },
  {
    "path": "examples/react-native/expo-app/android/app/src/main/res/values-night/colors.xml",
    "content": "<resources/>"
  },
  {
    "path": "examples/react-native/expo-app/android/build.gradle",
    "content": "import org.apache.tools.ant.taskdefs.condition.Os\n\n// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    ext {\n        buildToolsVersion = findProperty('android.buildToolsVersion') ?: '31.0.0'\n        minSdkVersion = Integer.parseInt(findProperty('android.minSdkVersion') ?: '21')\n        compileSdkVersion = Integer.parseInt(findProperty('android.compileSdkVersion') ?: '31')\n        targetSdkVersion = Integer.parseInt(findProperty('android.targetSdkVersion') ?: '31')\n        if (findProperty('android.kotlinVersion')) {\n            kotlinVersion = findProperty('android.kotlinVersion')\n        }\n        frescoVersion = findProperty('expo.frescoVersion') ?: '2.5.0'\n\n        if (System.properties['os.arch'] == 'aarch64') {\n            // For M1 Users we need to use the NDK 24 which added support for aarch64\n            ndkVersion = '24.0.8215888'\n        } else {\n            // Otherwise we default to the side-by-side NDK version from AGP.\n            ndkVersion = '21.4.7075529'\n        }\n    }\n    repositories {\n        google()\n        mavenCentral()\n    }\n    dependencies {\n        classpath('com.android.tools.build:gradle:7.2.1')\n        classpath('com.facebook.react:react-native-gradle-plugin')\n        classpath('de.undercouch:gradle-download-task:5.0.1')\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\ndef REACT_NATIVE_VERSION = new File(['node', '--print', \"JSON.parse(require('fs').readFileSync(require.resolve('react-native/package.json'), 'utf-8')).version\"].execute(null, rootDir).text.trim())\n\nallprojects {\n    configurations.all {\n        resolutionStrategy {\n            force \"com.facebook.react:react-native:\" + REACT_NATIVE_VERSION\n        }\n    }\n\n    repositories {\n        mavenLocal()\n        maven {\n            // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm\n            url(new File(['node', '--print', \"require.resolve('react-native/package.json')\"].execute(null, rootDir).text.trim(), '../android'))\n        }\n        maven {\n            // Android JSC is installed from npm\n            url(new File(['node', '--print', \"require.resolve('jsc-android/package.json')\"].execute(null, rootDir).text.trim(), '../dist'))\n        }\n\n        google()\n        mavenCentral {\n            // We don't want to fetch react-native from Maven Central as there are\n            // older versions over there.\n            content {\n                excludeGroup 'com.facebook.react'\n            }\n        }\n        maven { url 'https://www.jitpack.io' }\n    }\n}\n"
  },
  {
    "path": "examples/react-native/expo-app/android/gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-7.3.3-all.zip\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "examples/react-native/expo-app/android/gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\n# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m\norg.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m\n\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n\n# AndroidX package structure to make it clearer which packages are bundled with the\n# Android operating system, and which are packaged with your app's APK\n# https://developer.android.com/topic/libraries/support-library/androidx-rn\nandroid.useAndroidX=true\n\n# Automatically convert third-party libraries to use AndroidX\nandroid.enableJetifier=true\n\n# Version of flipper SDK to use with React Native\nFLIPPER_VERSION=0.125.0\n\n# Use this property to specify which architecture you want to build.\n# You can also override it from the CLI using\n# ./gradlew <task> -PreactNativeArchitectures=x86_64\nreactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64\n\n# Use this property to enable support to the new architecture.\n# This will allow you to use TurboModules and the Fabric render in\n# your application. You should enable this flag either if you want\n# to write custom TurboModules/Fabric components OR use libraries that\n# are providing them.\nnewArchEnabled=false\n\n# The hosted JavaScript engine\n# Supported values: expo.jsEngine = \"hermes\" | \"jsc\"\nexpo.jsEngine=jsc\n\n# Enable GIF support in React Native images (~200 B increase)\nexpo.gif.enabled=true\n# Enable webp support in React Native images (~85 KB increase)\nexpo.webp.enabled=true\n# Enable animated webp support (~3.4 MB increase)\n# Disabled by default because iOS doesn't support animated webp\nexpo.webp.animated=false\n"
  },
  {
    "path": "examples/react-native/expo-app/android/gradlew",
    "content": "#!/bin/sh\n\n#\n# Copyright © 2015-2021 the original authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##############################################################################\n#\n#   Gradle start up script for POSIX generated by Gradle.\n#\n#   Important for running:\n#\n#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is\n#       noncompliant, but you have some other compliant shell such as ksh or\n#       bash, then to run this script, type that shell name before the whole\n#       command line, like:\n#\n#           ksh Gradle\n#\n#       Busybox and similar reduced shells will NOT work, because this script\n#       requires all of these POSIX shell features:\n#         * functions;\n#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,\n#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;\n#         * compound commands having a testable exit status, especially «case»;\n#         * various built-in commands including «command», «set», and «ulimit».\n#\n#   Important for patching:\n#\n#   (2) This script targets any POSIX shell, so it avoids extensions provided\n#       by Bash, Ksh, etc; in particular arrays are avoided.\n#\n#       The \"traditional\" practice of packing multiple parameters into a\n#       space-separated string is a well documented source of bugs and security\n#       problems, so this is (mostly) avoided, by progressively accumulating\n#       options in \"$@\", and eventually passing that to Java.\n#\n#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,\n#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;\n#       see the in-line comments for details.\n#\n#       There are tweaks for specific operating systems such as AIX, CygWin,\n#       Darwin, MinGW, and NonStop.\n#\n#   (3) This script is generated from the Groovy template\n#       https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt\n#       within the Gradle project.\n#\n#       You can find Gradle at https://github.com/gradle/gradle/.\n#\n##############################################################################\n\n# Attempt to set APP_HOME\n\n# Resolve links: $0 may be a link\napp_path=$0\n\n# Need this for daisy-chained symlinks.\nwhile\n    APP_HOME=${app_path%\"${app_path##*/}\"}  # leaves a trailing /; empty if no leading path\n    [ -h \"$app_path\" ]\ndo\n    ls=$( ls -ld \"$app_path\" )\n    link=${ls#*' -> '}\n    case $link in             #(\n      /*)   app_path=$link ;; #(\n      *)    app_path=$APP_HOME$link ;;\n    esac\ndone\n\nAPP_HOME=$( cd \"${APP_HOME:-./}\" && pwd -P ) || exit\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=${0##*/}\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=maximum\n\nwarn () {\n    echo \"$*\"\n} >&2\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n} >&2\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"$( uname )\" in                #(\n  CYGWIN* )         cygwin=true  ;; #(\n  Darwin* )         darwin=true  ;; #(\n  MSYS* | MINGW* )  msys=true    ;; #(\n  NONSTOP* )        nonstop=true ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=$JAVA_HOME/jre/sh/java\n    else\n        JAVACMD=$JAVA_HOME/bin/java\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=java\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif ! \"$cygwin\" && ! \"$darwin\" && ! \"$nonstop\" ; then\n    case $MAX_FD in #(\n      max*)\n        MAX_FD=$( ulimit -H -n ) ||\n            warn \"Could not query maximum file descriptor limit\"\n    esac\n    case $MAX_FD in  #(\n      '' | soft) :;; #(\n      *)\n        ulimit -n \"$MAX_FD\" ||\n            warn \"Could not set maximum file descriptor limit to $MAX_FD\"\n    esac\nfi\n\n# Collect all arguments for the java command, stacking in reverse order:\n#   * args from the command line\n#   * the main class name\n#   * -classpath\n#   * -D...appname settings\n#   * --module-path (only if needed)\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.\n\n# For Cygwin or MSYS, switch paths to Windows format before running java\nif \"$cygwin\" || \"$msys\" ; then\n    APP_HOME=$( cygpath --path --mixed \"$APP_HOME\" )\n    CLASSPATH=$( cygpath --path --mixed \"$CLASSPATH\" )\n\n    JAVACMD=$( cygpath --unix \"$JAVACMD\" )\n\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    for arg do\n        if\n            case $arg in                                #(\n              -*)   false ;;                            # don't mess with options #(\n              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath\n                    [ -e \"$t\" ] ;;                      #(\n              *)    false ;;\n            esac\n        then\n            arg=$( cygpath --path --ignore --mixed \"$arg\" )\n        fi\n        # Roll the args list around exactly as many times as the number of\n        # args, so each arg winds up back in the position where it started, but\n        # possibly modified.\n        #\n        # NB: a `for` loop captures its iteration list before it begins, so\n        # changing the positional parameters here affects neither the number of\n        # iterations, nor the values presented in `arg`.\n        shift                   # remove old arg\n        set -- \"$@\" \"$arg\"      # push replacement arg\n    done\nfi\n\n# Collect all arguments for the java command;\n#   * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of\n#     shell script including quotes and variable substitutions, so put them in\n#     double quotes to make sure that they get re-expanded; and\n#   * put everything else in single quotes, so that it's not re-expanded.\n\nset -- \\\n        \"-Dorg.gradle.appname=$APP_BASE_NAME\" \\\n        -classpath \"$CLASSPATH\" \\\n        org.gradle.wrapper.GradleWrapperMain \\\n        \"$@\"\n\n# Use \"xargs\" to parse quoted args.\n#\n# With -n1 it outputs one arg per line, with the quotes and backslashes removed.\n#\n# In Bash we could simply go:\n#\n#   readarray ARGS < <( xargs -n1 <<<\"$var\" ) &&\n#   set -- \"${ARGS[@]}\" \"$@\"\n#\n# but POSIX shell has neither arrays nor command substitution, so instead we\n# post-process each arg (as a line of input to sed) to backslash-escape any\n# character that might be a shell metacharacter, then use eval to reverse\n# that process (while maintaining the separation between arguments), and wrap\n# the whole thing up as a single \"set\" statement.\n#\n# This will of course break if any of these variables contains a newline or\n# an unmatched quote.\n#\n\neval \"set -- $(\n        printf '%s\\n' \"$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\" |\n        xargs -n1 |\n        sed ' s~[^-[:alnum:]+,./:=@_]~\\\\&~g; ' |\n        tr '\\n' ' '\n    )\" '\"$@\"'\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "examples/react-native/expo-app/android/gradlew.bat",
    "content": "@rem\r\n@rem Copyright 2015 the original author or authors.\r\n@rem\r\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\r\n@rem you may not use this file except in compliance with the License.\r\n@rem You may obtain a copy of the License at\r\n@rem\r\n@rem      https://www.apache.org/licenses/LICENSE-2.0\r\n@rem\r\n@rem Unless required by applicable law or agreed to in writing, software\r\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\r\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n@rem See the License for the specific language governing permissions and\r\n@rem limitations under the License.\r\n@rem\r\n\r\n@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Resolve any \".\" and \"..\" in APP_HOME to make it shorter.\r\nfor %%i in (\"%APP_HOME%\") do set APP_HOME=%%~fi\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto execute\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto execute\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %*\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "examples/react-native/expo-app/android/settings.gradle",
    "content": "rootProject.name = 'expo-app'\n\napply from: new File([\"node\", \"--print\", \"require.resolve('expo/package.json')\"].execute(null, rootDir).text.trim(), \"../scripts/autolinking.gradle\");\nuseExpoModules()\n\napply from: new File([\"node\", \"--print\", \"require.resolve('@react-native-community/cli-platform-android/package.json')\"].execute(null, rootDir).text.trim(), \"../native_modules.gradle\");\napplyNativeModulesSettingsGradle(settings)\n\ninclude ':app'\nincludeBuild(new File([\"node\", \"--print\", \"require.resolve('react-native-gradle-plugin/package.json')\"].execute(null, rootDir).text.trim()).getParentFile())\n\nif (settings.hasProperty(\"newArchEnabled\") && settings.newArchEnabled == \"true\") {\n  include(\":ReactAndroid\")\n  project(\":ReactAndroid\").projectDir = new File([\"node\", \"--print\", \"require.resolve('react-native/package.json')\"].execute(null, rootDir).text.trim(), \"../ReactAndroid\");\n  include(\":ReactAndroid:hermes-engine\")\n  project(\":ReactAndroid:hermes-engine\").projectDir = new File([\"node\", \"--print\", \"require.resolve('react-native/package.json')\"].execute(null, rootDir).text.trim(), \"../ReactAndroid/hermes-engine\");\n}\n"
  },
  {
    "path": "examples/react-native/expo-app/app.json",
    "content": "{\n  \"expo\": {\n    \"name\": \"expo-app\",\n    \"slug\": \"expo-app\",\n    \"version\": \"1.0.0\",\n    \"orientation\": \"portrait\",\n    \"icon\": \"./assets/icon.png\",\n    \"userInterfaceStyle\": \"light\",\n    \"splash\": {\n      \"image\": \"./assets/splash.png\",\n      \"resizeMode\": \"contain\",\n      \"backgroundColor\": \"#ffffff\"\n    },\n    \"updates\": {\n      \"fallbackToCacheTimeout\": 0\n    },\n    \"assetBundlePatterns\": [\n      \"**/*\"\n    ],\n    \"ios\": {\n      \"supportsTablet\": true,\n      \"bundleIdentifier\": \"com.amplitude.expo-app\"\n    },\n    \"android\": {\n      \"adaptiveIcon\": {\n        \"foregroundImage\": \"./assets/adaptive-icon.png\",\n        \"backgroundColor\": \"#FFFFFF\"\n      },\n      \"package\": \"com.amplitude.expoapp\"\n    },\n    \"web\": {\n      \"favicon\": \"./assets/favicon.png\"\n    }\n  }\n}\n"
  },
  {
    "path": "examples/react-native/expo-app/babel.config.js",
    "content": "module.exports = function(api) {\n  api.cache(true);\n  return {\n    presets: ['babel-preset-expo'],\n  };\n};\n"
  },
  {
    "path": "examples/react-native/expo-app/index.js",
    "content": "import { registerRootComponent } from 'expo';\n\nimport App from './App';\n\n// registerRootComponent calls AppRegistry.registerComponent('main', () => App);\n// It also ensures that whether you load the app in Expo Go or in a native build,\n// the environment is set up appropriately\nregisterRootComponent(App);\n"
  },
  {
    "path": "examples/react-native/expo-app/ios/.gitignore",
    "content": "# OSX\n#\n.DS_Store\n\n# Xcode\n#\nbuild/\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\nxcuserdata\n*.xccheckout\n*.moved-aside\nDerivedData\n*.hmap\n*.ipa\n*.xcuserstate\nproject.xcworkspace\n\n# Bundle artifacts\n*.jsbundle\n\n# CocoaPods\n/Pods/\n"
  },
  {
    "path": "examples/react-native/expo-app/ios/Podfile",
    "content": "require File.join(File.dirname(`node --print \"require.resolve('expo/package.json')\"`), \"scripts/autolinking\")\nrequire File.join(File.dirname(`node --print \"require.resolve('react-native/package.json')\"`), \"scripts/react_native_pods\")\nrequire File.join(File.dirname(`node --print \"require.resolve('@react-native-community/cli-platform-ios/package.json')\"`), \"native_modules\")\n\nrequire 'json'\npodfile_properties = JSON.parse(File.read(File.join(__dir__, 'Podfile.properties.json'))) rescue {}\n\nplatform :ios, podfile_properties['ios.deploymentTarget'] || '12.0'\ninstall! 'cocoapods',\n  :deterministic_uuids => false\n\ntarget 'expoapp' do\n  use_expo_modules!\n  config = use_native_modules!\n\n  use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks']\n\n  # Flags change depending on the env values.\n  flags = get_default_flags()\n\n  use_react_native!(\n    :path => config[:reactNativePath],\n    :hermes_enabled => flags[:hermes_enabled] || podfile_properties['expo.jsEngine'] == 'hermes',\n    :fabric_enabled => flags[:fabric_enabled],\n    # An absolute path to your application root.\n    :app_path => \"#{Dir.pwd}/..\"\n  )\n\n  # Uncomment to opt-in to using Flipper\n  # Note that if you have use_frameworks! enabled, Flipper will not work\n  #\n  # if !ENV['CI']\n  #   use_flipper!()\n  # end\n\n  post_install do |installer|\n    react_native_post_install(installer)\n    __apply_Xcode_12_5_M1_post_install_workaround(installer)\n  end\n\n  post_integrate do |installer|\n    begin\n      expo_patch_react_imports!(installer)\n    rescue => e\n      Pod::UI.warn e\n    end\n  end\n\nend\n"
  },
  {
    "path": "examples/react-native/expo-app/ios/Podfile.properties.json",
    "content": "{\n  \"expo.jsEngine\": \"jsc\"\n}\n"
  },
  {
    "path": "examples/react-native/expo-app/ios/expoapp/AppDelegate.h",
    "content": "#import <Foundation/Foundation.h>\n#import <React/RCTBridgeDelegate.h>\n#import <UIKit/UIKit.h>\n\n#import <Expo/Expo.h>\n\n@interface AppDelegate : EXAppDelegateWrapper <RCTBridgeDelegate>\n\n@end\n"
  },
  {
    "path": "examples/react-native/expo-app/ios/expoapp/AppDelegate.mm",
    "content": "#import \"AppDelegate.h\"\n\n#import <React/RCTBridge.h>\n#import <React/RCTBundleURLProvider.h>\n#import <React/RCTRootView.h>\n#import <React/RCTLinkingManager.h>\n#import <React/RCTConvert.h>\n\n#import <React/RCTAppSetupUtils.h>\n\n#if RCT_NEW_ARCH_ENABLED\n#import <React/CoreModulesPlugins.h>\n#import <React/RCTCxxBridgeDelegate.h>\n#import <React/RCTFabricSurfaceHostingProxyRootView.h>\n#import <React/RCTSurfacePresenter.h>\n#import <React/RCTSurfacePresenterBridgeAdapter.h>\n#import <ReactCommon/RCTTurboModuleManager.h>\n\n#import <react/config/ReactNativeConfig.h>\n\n@interface AppDelegate () <RCTCxxBridgeDelegate, RCTTurboModuleManagerDelegate> {\n  RCTTurboModuleManager *_turboModuleManager;\n  RCTSurfacePresenterBridgeAdapter *_bridgeAdapter;\n  std::shared_ptr<const facebook::react::ReactNativeConfig> _reactNativeConfig;\n  facebook::react::ContextContainer::Shared _contextContainer;\n}\n@end\n#endif\n\n@implementation AppDelegate\n\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions\n{\n  RCTAppSetupPrepareApp(application);\n\n  RCTBridge *bridge = [self.reactDelegate createBridgeWithDelegate:self launchOptions:launchOptions];\n\n#if RCT_NEW_ARCH_ENABLED\n  _contextContainer = std::make_shared<facebook::react::ContextContainer const>();\n  _reactNativeConfig = std::make_shared<facebook::react::EmptyReactNativeConfig const>();\n  _contextContainer->insert(\"ReactNativeConfig\", _reactNativeConfig);\n  _bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge contextContainer:_contextContainer];\n  bridge.surfacePresenter = _bridgeAdapter.surfacePresenter;\n#endif\n\n  UIView *rootView = [self.reactDelegate createRootViewWithBridge:bridge moduleName:@\"main\" initialProperties:nil];\n\n  rootView.backgroundColor = [UIColor whiteColor];\n  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];\n  UIViewController *rootViewController = [self.reactDelegate createRootViewController];\n  rootViewController.view = rootView;\n  self.window.rootViewController = rootViewController;\n  [self.window makeKeyAndVisible];\n\n  [super application:application didFinishLaunchingWithOptions:launchOptions];\n\n  return YES;\n}\n\n- (NSArray<id<RCTBridgeModule>> *)extraModulesForBridge:(RCTBridge *)bridge\n{\n  // If you'd like to export some custom RCTBridgeModules, add them here!\n  return @[];\n}\n\n- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge\n{\n#if DEBUG\n  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@\"index\"];\n#else\n  return [[NSBundle mainBundle] URLForResource:@\"main\" withExtension:@\"jsbundle\"];\n#endif\n}\n\n// Linking API\n- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {\n  return [super application:application openURL:url options:options] || [RCTLinkingManager application:application openURL:url options:options];\n}\n\n// Universal Links\n- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {\n  BOOL result = [RCTLinkingManager application:application continueUserActivity:userActivity restorationHandler:restorationHandler];\n  return [super application:application continueUserActivity:userActivity restorationHandler:restorationHandler] || result;\n}\n\n// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries\n- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken\n{\n  return [super application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];\n}\n\n// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries\n- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error\n{\n  return [super application:application didFailToRegisterForRemoteNotificationsWithError:error];\n}\n\n// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries\n- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler\n{\n  return [super application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];\n}\n\n#if RCT_NEW_ARCH_ENABLED\n\n#pragma mark - RCTCxxBridgeDelegate\n\n- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:(RCTBridge *)bridge\n{\n  _turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge\n                                                             delegate:self\n                                                            jsInvoker:bridge.jsCallInvoker];\n  return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager);\n}\n\n#pragma mark RCTTurboModuleManagerDelegate\n\n- (Class)getModuleClassFromName:(const char *)name\n{\n  return RCTCoreModulesClassProvider(name);\n}\n\n- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name\n                                                      jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker\n{\n  return nullptr;\n}\n\n- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name\n                                                     initParams:\n                                                         (const facebook::react::ObjCTurboModule::InitParams &)params\n{\n  return nullptr;\n}\n\n- (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass\n{\n  return RCTAppSetupDefaultModuleFromClass(moduleClass);\n}\n\n#endif\n\n@end\n"
  },
  {
    "path": "examples/react-native/expo-app/ios/expoapp/Images.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\": [\n    {\n      \"idiom\": \"iphone\",\n      \"size\": \"20x20\",\n      \"scale\": \"2x\",\n      \"filename\": \"App-Icon-20x20@2x.png\"\n    },\n    {\n      \"idiom\": \"iphone\",\n      \"size\": \"20x20\",\n      \"scale\": \"3x\",\n      \"filename\": \"App-Icon-20x20@3x.png\"\n    },\n    {\n      \"idiom\": \"iphone\",\n      \"size\": \"29x29\",\n      \"scale\": \"1x\",\n      \"filename\": \"App-Icon-29x29@1x.png\"\n    },\n    {\n      \"idiom\": \"iphone\",\n      \"size\": \"29x29\",\n      \"scale\": \"2x\",\n      \"filename\": \"App-Icon-29x29@2x.png\"\n    },\n    {\n      \"idiom\": \"iphone\",\n      \"size\": \"29x29\",\n      \"scale\": \"3x\",\n      \"filename\": \"App-Icon-29x29@3x.png\"\n    },\n    {\n      \"idiom\": \"iphone\",\n      \"size\": \"40x40\",\n      \"scale\": \"2x\",\n      \"filename\": \"App-Icon-40x40@2x.png\"\n    },\n    {\n      \"idiom\": \"iphone\",\n      \"size\": \"40x40\",\n      \"scale\": \"3x\",\n      \"filename\": \"App-Icon-40x40@3x.png\"\n    },\n    {\n      \"idiom\": \"iphone\",\n      \"size\": \"60x60\",\n      \"scale\": \"2x\",\n      \"filename\": \"App-Icon-60x60@2x.png\"\n    },\n    {\n      \"idiom\": \"iphone\",\n      \"size\": \"60x60\",\n      \"scale\": \"3x\",\n      \"filename\": \"App-Icon-60x60@3x.png\"\n    },\n    {\n      \"idiom\": \"ipad\",\n      \"size\": \"20x20\",\n      \"scale\": \"1x\",\n      \"filename\": \"App-Icon-20x20@1x.png\"\n    },\n    {\n      \"idiom\": \"ipad\",\n      \"size\": \"20x20\",\n      \"scale\": \"2x\",\n      \"filename\": \"App-Icon-20x20@2x.png\"\n    },\n    {\n      \"idiom\": \"ipad\",\n      \"size\": \"29x29\",\n      \"scale\": \"1x\",\n      \"filename\": \"App-Icon-29x29@1x.png\"\n    },\n    {\n      \"idiom\": \"ipad\",\n      \"size\": \"29x29\",\n      \"scale\": \"2x\",\n      \"filename\": \"App-Icon-29x29@2x.png\"\n    },\n    {\n      \"idiom\": \"ipad\",\n      \"size\": \"40x40\",\n      \"scale\": \"1x\",\n      \"filename\": \"App-Icon-40x40@1x.png\"\n    },\n    {\n      \"idiom\": \"ipad\",\n      \"size\": \"40x40\",\n      \"scale\": \"2x\",\n      \"filename\": \"App-Icon-40x40@2x.png\"\n    },\n    {\n      \"idiom\": \"ipad\",\n      \"size\": \"76x76\",\n      \"scale\": \"1x\",\n      \"filename\": \"App-Icon-76x76@1x.png\"\n    },\n    {\n      \"idiom\": \"ipad\",\n      \"size\": \"76x76\",\n      \"scale\": \"2x\",\n      \"filename\": \"App-Icon-76x76@2x.png\"\n    },\n    {\n      \"idiom\": \"ipad\",\n      \"size\": \"83.5x83.5\",\n      \"scale\": \"2x\",\n      \"filename\": \"App-Icon-83.5x83.5@2x.png\"\n    },\n    {\n      \"idiom\": \"ios-marketing\",\n      \"size\": \"1024x1024\",\n      \"scale\": \"1x\",\n      \"filename\": \"ItunesArtwork@2x.png\"\n    }\n  ],\n  \"info\": {\n    \"version\": 1,\n    \"author\": \"expo\"\n  }\n}"
  },
  {
    "path": "examples/react-native/expo-app/ios/expoapp/Images.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"expo\"\n  }\n}\n"
  },
  {
    "path": "examples/react-native/expo-app/ios/expoapp/Images.xcassets/SplashScreen.imageset/Contents.json",
    "content": "{\n  \"images\": [\n    {\n      \"idiom\": \"universal\",\n      \"filename\": \"image.png\",\n      \"scale\": \"1x\"\n    },\n    {\n      \"idiom\": \"universal\",\n      \"scale\": \"2x\"\n    },\n    {\n      \"idiom\": \"universal\",\n      \"scale\": \"3x\"\n    }\n  ],\n  \"info\": {\n    \"version\": 1,\n    \"author\": \"expo\"\n  }\n}"
  },
  {
    "path": "examples/react-native/expo-app/ios/expoapp/Images.xcassets/SplashScreenBackground.imageset/Contents.json",
    "content": "{\n  \"images\": [\n    {\n      \"idiom\": \"universal\",\n      \"filename\": \"image.png\",\n      \"scale\": \"1x\"\n    },\n    {\n      \"idiom\": \"universal\",\n      \"scale\": \"2x\"\n    },\n    {\n      \"idiom\": \"universal\",\n      \"scale\": \"3x\"\n    }\n  ],\n  \"info\": {\n    \"version\": 1,\n    \"author\": \"expo\"\n  }\n}"
  },
  {
    "path": "examples/react-native/expo-app/ios/expoapp/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n  <dict>\n    <key>CFBundleDevelopmentRegion</key>\n    <string>$(DEVELOPMENT_LANGUAGE)</string>\n    <key>CFBundleDisplayName</key>\n    <string>expo-app</string>\n    <key>CFBundleExecutable</key>\n    <string>$(EXECUTABLE_NAME)</string>\n    <key>CFBundleIdentifier</key>\n    <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n    <key>CFBundleInfoDictionaryVersion</key>\n    <string>6.0</string>\n    <key>CFBundleName</key>\n    <string>$(PRODUCT_NAME)</string>\n    <key>CFBundlePackageType</key>\n    <string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n    <key>CFBundleShortVersionString</key>\n    <string>1.0.0</string>\n    <key>CFBundleSignature</key>\n    <string>????</string>\n    <key>CFBundleURLTypes</key>\n    <array>\n      <dict>\n        <key>CFBundleURLSchemes</key>\n        <array>\n          <string>com.amplitude.expo-app</string>\n        </array>\n      </dict>\n    </array>\n    <key>CFBundleVersion</key>\n    <string>1</string>\n    <key>LSRequiresIPhoneOS</key>\n    <true/>\n    <key>NSAppTransportSecurity</key>\n    <dict>\n      <key>NSAllowsArbitraryLoads</key>\n      <true/>\n      <key>NSExceptionDomains</key>\n      <dict>\n        <key>localhost</key>\n        <dict>\n          <key>NSExceptionAllowsInsecureHTTPLoads</key>\n          <true/>\n        </dict>\n      </dict>\n    </dict>\n    <key>UILaunchStoryboardName</key>\n    <string>SplashScreen</string>\n    <key>UIRequiredDeviceCapabilities</key>\n    <array>\n      <string>armv7</string>\n    </array>\n    <key>UIRequiresFullScreen</key>\n    <false/>\n    <key>UIStatusBarStyle</key>\n    <string>UIStatusBarStyleDefault</string>\n    <key>UISupportedInterfaceOrientations</key>\n    <array>\n      <string>UIInterfaceOrientationPortrait</string>\n      <string>UIInterfaceOrientationPortraitUpsideDown</string>\n    </array>\n    <key>UISupportedInterfaceOrientations~ipad</key>\n    <array>\n      <string>UIInterfaceOrientationPortrait</string>\n      <string>UIInterfaceOrientationPortraitUpsideDown</string>\n      <string>UIInterfaceOrientationLandscapeLeft</string>\n      <string>UIInterfaceOrientationLandscapeRight</string>\n    </array>\n    <key>UIUserInterfaceStyle</key>\n    <string>Light</string>\n    <key>UIViewControllerBasedStatusBarAppearance</key>\n    <false/>\n  </dict>\n</plist>"
  },
  {
    "path": "examples/react-native/expo-app/ios/expoapp/SplashScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"16096\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"EXPO-VIEWCONTROLLER-1\">\n    <device id=\"retina5_5\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"16087\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <scene sceneID=\"EXPO-SCENE-1\">\n            <objects>\n                <viewController storyboardIdentifier=\"SplashScreenViewController\" id=\"EXPO-VIEWCONTROLLER-1\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" insetsLayoutMarginsFromSafeArea=\"NO\" id=\"EXPO-ContainerView\" userLabel=\"ContainerView\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"414\" height=\"736\"/>\n                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                        <subviews>\n                            <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" insetsLayoutMarginsFromSafeArea=\"NO\" image=\"SplashScreenBackground\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"EXPO-SplashScreenBackground\" userLabel=\"SplashScreenBackground\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"414\" height=\"736\"/>\n                            </imageView>\n                            <imageView id=\"EXPO-SplashScreen\" userLabel=\"SplashScreen\" image=\"SplashScreen\" contentMode=\"scaleAspectFit\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" clipsSubviews=\"true\" userInteractionEnabled=\"false\" translatesAutoresizingMaskIntoConstraints=\"false\">\n                                <rect key=\"frame\" x=\"0\" y=\"0\" width=\"414\" height=\"736\"/>\n                            </imageView>\n                        </subviews>\n                        <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\"/>\n                        <constraints>\n                            <constraint firstItem=\"EXPO-SplashScreenBackground\" firstAttribute=\"top\" secondItem=\"EXPO-ContainerView\" secondAttribute=\"top\" id=\"1gX-mQ-vu6\"/>\n                            <constraint firstItem=\"EXPO-SplashScreenBackground\" firstAttribute=\"leading\" secondItem=\"EXPO-ContainerView\" secondAttribute=\"leading\" id=\"6tX-OG-Sck\"/>\n                            <constraint firstItem=\"EXPO-SplashScreenBackground\" firstAttribute=\"trailing\" secondItem=\"EXPO-ContainerView\" secondAttribute=\"trailing\" id=\"ABX-8g-7v4\"/>\n                            <constraint firstItem=\"EXPO-SplashScreenBackground\" firstAttribute=\"bottom\" secondItem=\"EXPO-ContainerView\" secondAttribute=\"bottom\" id=\"jkI-2V-eW5\"/>\n                            <constraint firstItem=\"EXPO-SplashScreen\" firstAttribute=\"top\" secondItem=\"EXPO-ContainerView\" secondAttribute=\"top\" id=\"83fcb9b545b870ba44c24f0feeb116490c499c52\"/>\n                            <constraint firstItem=\"EXPO-SplashScreen\" firstAttribute=\"leading\" secondItem=\"EXPO-ContainerView\" secondAttribute=\"leading\" id=\"61d16215e44b98e39d0a2c74fdbfaaa22601b12c\"/>\n                            <constraint firstItem=\"EXPO-SplashScreen\" firstAttribute=\"trailing\" secondItem=\"EXPO-ContainerView\" secondAttribute=\"trailing\" id=\"f934da460e9ab5acae3ad9987d5b676a108796c1\"/>\n                            <constraint firstItem=\"EXPO-SplashScreen\" firstAttribute=\"bottom\" secondItem=\"EXPO-ContainerView\" secondAttribute=\"bottom\" id=\"d6a0be88096b36fb132659aa90203d39139deda9\"/>\n                        </constraints>\n                        <viewLayoutGuide key=\"safeArea\" id=\"Rmq-lb-GrQ\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"EXPO-PLACEHOLDER-1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"140.625\" y=\"129.4921875\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"SplashScreenBackground\" width=\"1\" height=\"1\"/>\n        <image name=\"SplashScreen\" width=\"414\" height=\"736\"/>\n    </resources>\n</document>"
  },
  {
    "path": "examples/react-native/expo-app/ios/expoapp/Supporting/Expo.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n  <dict>\n    <key>EXUpdatesCheckOnLaunch</key>\n    <string>ALWAYS</string>\n    <key>EXUpdatesEnabled</key>\n    <true/>\n    <key>EXUpdatesLaunchWaitMs</key>\n    <integer>0</integer>\n    <key>EXUpdatesSDKVersion</key>\n    <string>45.0.0</string>\n    <key>EXUpdatesURL</key>\n    <string>https://exp.host/@anonymous/expo-app</string>\n  </dict>\n</plist>"
  },
  {
    "path": "examples/react-native/expo-app/ios/expoapp/expoapp.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n  <dict>\n    <key>aps-environment</key>\n    <string>development</string>\n  </dict>\n</plist>"
  },
  {
    "path": "examples/react-native/expo-app/ios/expoapp/main.m",
    "content": "#import <UIKit/UIKit.h>\n\n#import \"AppDelegate.h\"\n\nint main(int argc, char * argv[]) {\n  @autoreleasepool {\n    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));\n  }\n}\n\n"
  },
  {
    "path": "examples/react-native/expo-app/ios/expoapp/noop-file.swift",
    "content": "//\n// @generated\n// A blank Swift file must be created for native modules with Swift files to work correctly.\n//\n"
  },
  {
    "path": "examples/react-native/expo-app/ios/expoapp.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; };\n\t\t13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };\n\t\t13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };\n\t\t3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */; };\n\t\t45A2AAA973284537BADECAC2 /* noop-file.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE0DC0B99CA44B888CC99960 /* noop-file.swift */; };\n\t\t96905EF65AED1B983A6B3ABC /* libPods-expoapp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 58EEBF8E8E6FB1BC6CAF49B5 /* libPods-expoapp.a */; };\n\t\tB18059E884C0ABDD17F3DC3D /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAC715A2D49A985799AEE119 /* ExpoModulesProvider.swift */; };\n\t\tBB2F792D24A3F905000567C9 /* Expo.plist in Resources */ = {isa = PBXBuildFile; fileRef = BB2F792C24A3F905000567C9 /* Expo.plist */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = \"<group>\"; };\n\t\t13B07F961A680F5B00A75B9A /* expoapp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = expoapp.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = expoapp/AppDelegate.h; sourceTree = \"<group>\"; };\n\t\t13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = expoapp/AppDelegate.mm; sourceTree = \"<group>\"; };\n\t\t13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = expoapp/Images.xcassets; sourceTree = \"<group>\"; };\n\t\t13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = expoapp/Info.plist; sourceTree = \"<group>\"; };\n\t\t13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = expoapp/main.m; sourceTree = \"<group>\"; };\n\t\t58EEBF8E8E6FB1BC6CAF49B5 /* libPods-expoapp.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = \"libPods-expoapp.a\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t6C2E3173556A471DD304B334 /* Pods-expoapp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-expoapp.debug.xcconfig\"; path = \"Target Support Files/Pods-expoapp/Pods-expoapp.debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t7A4D352CD337FB3A3BF06240 /* Pods-expoapp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-expoapp.release.xcconfig\"; path = \"Target Support Files/Pods-expoapp/Pods-expoapp.release.xcconfig\"; sourceTree = \"<group>\"; };\n\t\tAA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = SplashScreen.storyboard; path = expoapp/SplashScreen.storyboard; sourceTree = \"<group>\"; };\n\t\tBB2F792C24A3F905000567C9 /* Expo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Expo.plist; sourceTree = \"<group>\"; };\n\t\tED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };\n\t\tFAC715A2D49A985799AEE119 /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = \"Pods/Target Support Files/Pods-expoapp/ExpoModulesProvider.swift\"; sourceTree = \"<group>\"; };\n\t\tFE0DC0B99CA44B888CC99960 /* noop-file.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; name = \"noop-file.swift\"; path = \"expoapp/noop-file.swift\"; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t13B07F8C1A680F5B00A75B9A /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t96905EF65AED1B983A6B3ABC /* libPods-expoapp.a in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t13B07FAE1A68108700A75B9A /* expoapp */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tBB2F792B24A3F905000567C9 /* Supporting */,\n\t\t\t\t008F07F21AC5B25A0029DE68 /* main.jsbundle */,\n\t\t\t\t13B07FAF1A68108700A75B9A /* AppDelegate.h */,\n\t\t\t\t13B07FB01A68108700A75B9A /* AppDelegate.mm */,\n\t\t\t\t13B07FB51A68108700A75B9A /* Images.xcassets */,\n\t\t\t\t13B07FB61A68108700A75B9A /* Info.plist */,\n\t\t\t\t13B07FB71A68108700A75B9A /* main.m */,\n\t\t\t\tAA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */,\n\t\t\t\tFE0DC0B99CA44B888CC99960 /* noop-file.swift */,\n\t\t\t);\n\t\t\tname = expoapp;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2D16E6871FA4F8E400B85C8A /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tED297162215061F000B7C4FE /* JavaScriptCore.framework */,\n\t\t\t\t58EEBF8E8E6FB1BC6CAF49B5 /* libPods-expoapp.a */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t832341AE1AAA6A7D00B99B32 /* Libraries */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t);\n\t\t\tname = Libraries;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t83CBB9F61A601CBA00E9B192 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t13B07FAE1A68108700A75B9A /* expoapp */,\n\t\t\t\t832341AE1AAA6A7D00B99B32 /* Libraries */,\n\t\t\t\t83CBBA001A601CBA00E9B192 /* Products */,\n\t\t\t\t2D16E6871FA4F8E400B85C8A /* Frameworks */,\n\t\t\t\tD65327D7A22EEC0BE12398D9 /* Pods */,\n\t\t\t\tD7E4C46ADA2E9064B798F356 /* ExpoModulesProviders */,\n\t\t\t);\n\t\t\tindentWidth = 2;\n\t\t\tsourceTree = \"<group>\";\n\t\t\ttabWidth = 2;\n\t\t\tusesTabs = 0;\n\t\t};\n\t\t83CBBA001A601CBA00E9B192 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t13B07F961A680F5B00A75B9A /* expoapp.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t92DBD88DE9BF7D494EA9DA96 /* expoapp */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tFAC715A2D49A985799AEE119 /* ExpoModulesProvider.swift */,\n\t\t\t);\n\t\t\tname = expoapp;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tBB2F792B24A3F905000567C9 /* Supporting */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tBB2F792C24A3F905000567C9 /* Expo.plist */,\n\t\t\t);\n\t\t\tname = Supporting;\n\t\t\tpath = expoapp/Supporting;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD65327D7A22EEC0BE12398D9 /* Pods */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t6C2E3173556A471DD304B334 /* Pods-expoapp.debug.xcconfig */,\n\t\t\t\t7A4D352CD337FB3A3BF06240 /* Pods-expoapp.release.xcconfig */,\n\t\t\t);\n\t\t\tpath = Pods;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD7E4C46ADA2E9064B798F356 /* ExpoModulesProviders */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t92DBD88DE9BF7D494EA9DA96 /* expoapp */,\n\t\t\t);\n\t\t\tname = ExpoModulesProviders;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t13B07F861A680F5B00A75B9A /* expoapp */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget \"expoapp\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t08A4A3CD28434E44B6B9DE2E /* [CP] Check Pods Manifest.lock */,\n\t\t\t\tFD10A7F022414F080027D42C /* Start Packager */,\n\t\t\t\t13B07F871A680F5B00A75B9A /* Sources */,\n\t\t\t\t13B07F8C1A680F5B00A75B9A /* Frameworks */,\n\t\t\t\t13B07F8E1A680F5B00A75B9A /* Resources */,\n\t\t\t\t00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,\n\t\t\t\t800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = expoapp;\n\t\t\tproductName = expoapp;\n\t\t\tproductReference = 13B07F961A680F5B00A75B9A /* expoapp.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t83CBB9F71A601CBA00E9B192 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastUpgradeCheck = 1130;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t13B07F861A680F5B00A75B9A = {\n\t\t\t\t\t\tLastSwiftMigration = 1250;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject \"expoapp\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 83CBB9F61A601CBA00E9B192;\n\t\t\tproductRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t13B07F861A680F5B00A75B9A /* expoapp */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t13B07F8E1A680F5B00A75B9A /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tBB2F792D24A3F905000567C9 /* Expo.plist in Resources */,\n\t\t\t\t13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,\n\t\t\t\t3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\t00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"Bundle React Native code and images\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"export NODE_BINARY=node\\n\\n# The project root by default is one level up from the ios directory\\nexport PROJECT_ROOT=\\\"$PROJECT_DIR\\\"/..\\n\\n`node --print \\\"require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/react-native-xcode.sh'\\\"`\\n\";\n\t\t};\n\t\t08A4A3CD28434E44B6B9DE2E /* [CP] Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\",\n\t\t\t\t\"${PODS_ROOT}/Manifest.lock\",\n\t\t\t);\n\t\t\tname = \"[CP] Check Pods Manifest.lock\";\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t\t\"$(DERIVED_FILE_DIR)/Pods-expoapp-checkManifestLockResult.txt\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [ $? != 0 ] ; then\\n    # print error to STDERR\\n    echo \\\"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\\" >&2\\n    exit 1\\nfi\\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\\necho \\\"SUCCESS\\\" > \\\"${SCRIPT_OUTPUT_FILE_0}\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\t800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-expoapp/Pods-expoapp-resources.sh\",\n\t\t\t\t\"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/EXConstants.bundle\",\n\t\t\t\t\"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle\",\n\t\t\t);\n\t\t\tname = \"[CP] Copy Pods Resources\";\n\t\t\toutputPaths = (\n\t\t\t\t\"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXConstants.bundle\",\n\t\t\t\t\"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-expoapp/Pods-expoapp-resources.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tFD10A7F022414F080027D42C /* Start Packager */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"Start Packager\";\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"export RCT_METRO_PORT=\\\"${RCT_METRO_PORT:=8081}\\\"\\necho \\\"export RCT_METRO_PORT=${RCT_METRO_PORT}\\\" > `node --print \\\"require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/.packager.env'\\\"`\\nif [ -z \\\"${RCT_NO_LAUNCH_PACKAGER+xxx}\\\" ] ; then\\n  if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\\n    if ! curl -s \\\"http://localhost:${RCT_METRO_PORT}/status\\\" | grep -q \\\"packager-status:running\\\" ; then\\n      echo \\\"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\\\"\\n      exit 2\\n    fi\\n  else\\n    open `node --print \\\"require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/launchPackager.command'\\\"` || echo \\\"Can't start packager automatically\\\"\\n  fi\\nfi\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t13B07F871A680F5B00A75B9A /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */,\n\t\t\t\t13B07FC11A68108700A75B9A /* main.m in Sources */,\n\t\t\t\tB18059E884C0ABDD17F3DC3D /* ExpoModulesProvider.swift in Sources */,\n\t\t\t\t45A2AAA973284537BADECAC2 /* noop-file.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\t13B07F941A680F5B00A75B9A /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 6C2E3173556A471DD304B334 /* Pods-expoapp.debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = expoapp/expoapp.entitlements;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"FB_SONARKIT_ENABLED=1\",\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = expoapp/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tOTHER_LDFLAGS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"-ObjC\",\n\t\t\t\t\t\"-lc++\",\n\t\t\t\t);\n\t\t\t\tOTHER_SWIFT_FLAGS = \"$(inherited) -D EXPO_CONFIGURATION_DEBUG\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.amplitude.expo-app\";\n\t\t\t\tPRODUCT_NAME = \"expoapp\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t13B07F951A680F5B00A75B9A /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 7A4D352CD337FB3A3BF06240 /* Pods-expoapp.release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = expoapp/expoapp.entitlements;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tINFOPLIST_FILE = expoapp/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tOTHER_LDFLAGS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"-ObjC\",\n\t\t\t\t\t\"-lc++\",\n\t\t\t\t);\n\t\t\t\tOTHER_SWIFT_FLAGS = \"$(inherited) -D EXPO_CONFIGURATION_RELEASE\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.amplitude.expo-app\";\n\t\t\t\tPRODUCT_NAME = \"expoapp\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t83CBBA201A601CBA00E9B192 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"c++17\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\t\"EXCLUDED_ARCHS[sdk=iphonesimulator*]\" = \"\";\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_SYMBOLS_PRIVATE_EXTERN = NO;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"/usr/lib/swift $(inherited)\";\n\t\t\t\tLIBRARY_SEARCH_PATHS = \"\\\"$(inherited)\\\"\";\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t83CBBA211A601CBA00E9B192 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"c++17\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = YES;\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\t\"EXCLUDED_ARCHS[sdk=iphonesimulator*]\" = \"\";\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"/usr/lib/swift $(inherited)\";\n\t\t\t\tLIBRARY_SEARCH_PATHS = \"\\\"$(inherited)\\\"\";\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget \"expoapp\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t13B07F941A680F5B00A75B9A /* Debug */,\n\t\t\t\t13B07F951A680F5B00A75B9A /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject \"expoapp\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t83CBBA201A601CBA00E9B192 /* Debug */,\n\t\t\t\t83CBBA211A601CBA00E9B192 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;\n}\n"
  },
  {
    "path": "examples/react-native/expo-app/ios/expoapp.xcodeproj/xcshareddata/xcschemes/expoapp.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1130\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"13B07F861A680F5B00A75B9A\"\n               BuildableName = \"expoapp.app\"\n               BlueprintName = \"expoapp\"\n               ReferencedContainer = \"container:expoapp.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"00E356ED1AD99517003FC87E\"\n               BuildableName = \"expoappTests.xctest\"\n               BlueprintName = \"expoappTests\"\n               ReferencedContainer = \"container:expoapp.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"13B07F861A680F5B00A75B9A\"\n            BuildableName = \"expoapp.app\"\n            BlueprintName = \"expoapp\"\n            ReferencedContainer = \"container:expoapp.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"13B07F861A680F5B00A75B9A\"\n            BuildableName = \"expoapp.app\"\n            BlueprintName = \"expoapp\"\n            ReferencedContainer = \"container:expoapp.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "examples/react-native/expo-app/ios/expoapp.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"group:expoapp.xcodeproj\">\n   </FileRef>\n   <FileRef\n      location = \"group:Pods/Pods.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "examples/react-native/expo-app/ios/expoapp.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "examples/react-native/expo-app/metro.config.js",
    "content": "// Learn more https://docs.expo.io/guides/customizing-metro\nconst { getDefaultConfig } = require('expo/metro-config');\n\nmodule.exports = getDefaultConfig(__dirname);\n"
  },
  {
    "path": "examples/react-native/expo-app/package.json",
    "content": "{\n  \"name\": \"expo-app\",\n  \"version\": \"1.0.0\",\n  \"scripts\": {\n    \"start\": \"expo start --dev-client\",\n    \"android\": \"expo run:android\",\n    \"ios\": \"expo run:ios\",\n    \"web\": \"expo start --web\",\n    \"eject\": \"expo eject\"\n  },\n  \"dependencies\": {\n    \"@amplitude/analytics-react-native\": \"0.7.0\",\n    \"@react-native-async-storage/async-storage\": \"~1.17.11\",\n    \"expo\": \"~48.0.0\",\n    \"expo-splash-screen\": \"~0.17.5\",\n    \"expo-status-bar\": \"~1.4.2\",\n    \"react\": \"18.2.0\",\n    \"react-dom\": \"18.2.0\",\n    \"react-native\": \"0.70.6\",\n    \"react-native-web\": \"0.18.10\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.20.5\",\n    \"@types/react\": \"~18.0.26\",\n    \"@types/react-native\": \"~0.70.8\",\n    \"typescript\": \"~4.9.4\"\n  },\n  \"private\": true\n}\n"
  },
  {
    "path": "examples/react-native/expo-app/tsconfig.json",
    "content": "{\n  \"extends\": \"expo/tsconfig.base\",\n  \"compilerOptions\": {\n    \"strict\": true\n  }\n}\n"
  },
  {
    "path": "examples/unified/react-app/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.js\n\n# testing\n/coverage\n\n# production\n/build\n\n# misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n"
  },
  {
    "path": "examples/unified/react-app/README.md",
    "content": "# Getting Started with Create React App\n\nThis project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).\n\n## Available Scripts\n\nIn the project directory, you can run:\n\n### `pnpm start`\n\nRuns the app in the development mode.\\\nOpen [http://localhost:3000](http://localhost:3000) to view it in the browser.\n\nThe page will reload if you make edits.\\\nYou will also see any lint errors in the console.\n\n### `pnpm test`\n\nLaunches the test runner in the interactive watch mode.\\\nSee the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.\n\n### `pnpm run build`\n\nBuilds the app for production to the `build` folder.\\\nIt correctly bundles React in production mode and optimizes the build for the best performance.\n\nThe build is minified and the filenames include the hashes.\\\nYour app is ready to be deployed!\n\nSee the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.\n\n### `pnpm run eject`\n\n**Note: this is a one-way operation. Once you `eject`, you can’t go back!**\n\nIf you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.\n\nInstead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.\n\nYou don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.\n\n## Learn More\n\nYou can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).\n\nTo learn React, check out the [React documentation](https://reactjs.org/).\n"
  },
  {
    "path": "examples/unified/react-app/package.json",
    "content": "{\n  \"name\": \"react-app\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"dependencies\": {\n    \"@amplitude/unified\": \"^1.0.0-beta.30\",\n    \"@testing-library/jest-dom\": \"^5.16.5\",\n    \"@testing-library/react\": \"^13.4.0\",\n    \"@testing-library/user-event\": \"^14.4.3\",\n    \"@types/jest\": \"^29.2.4\",\n    \"@types/node\": \"^18.11.14\",\n    \"@types/react\": \"^18.0.26\",\n    \"@types/react-dom\": \"^18.0.9\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"react-scripts\": \"5.0.1\",\n    \"typescript\": \"^4.6.3\",\n    \"web-vitals\": \"^3.1.0\"\n  },\n  \"scripts\": {\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"test\": \"react-scripts test\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"eslintConfig\": {\n    \"extends\": [\n      \"react-app\",\n      \"react-app/jest\"\n    ]\n  },\n  \"browserslist\": {\n    \"production\": [\n      \">0.2%\",\n      \"not dead\",\n      \"not op_mini all\"\n    ],\n    \"development\": [\n      \"last 1 chrome version\",\n      \"last 1 firefox version\",\n      \"last 1 safari version\"\n    ]\n  }\n}\n"
  },
  {
    "path": "examples/unified/react-app/public/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <link rel=\"icon\" href=\"%PUBLIC_URL%/favicon.ico\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <meta name=\"theme-color\" content=\"#000000\" />\n    <meta\n      name=\"description\"\n      content=\"Web site created using create-react-app\"\n    />\n    <link rel=\"apple-touch-icon\" href=\"%PUBLIC_URL%/logo192.png\" />\n    <!--\n      manifest.json provides metadata used when your web app is installed on a\n      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/\n    -->\n    <link rel=\"manifest\" href=\"%PUBLIC_URL%/manifest.json\" />\n    <!--\n      Notice the use of %PUBLIC_URL% in the tags above.\n      It will be replaced with the URL of the `public` folder during the build.\n      Only files inside the `public` folder can be referenced from the HTML.\n\n      Unlike \"/favicon.ico\" or \"favicon.ico\", \"%PUBLIC_URL%/favicon.ico\" will\n      work correctly both with client-side routing and a non-root public URL.\n      Learn how to configure a non-root public URL by running `npm run build`.\n    -->\n    <title>React App</title>\n  </head>\n  <body>\n    <noscript>You need to enable JavaScript to run this app.</noscript>\n    <div id=\"root\"></div>\n    <!--\n      This HTML file is a template.\n      If you open it directly in the browser, you will see an empty page.\n\n      You can add webfonts, meta tags, or analytics to this file.\n      The build step will place the bundled scripts into the <body> tag.\n\n      To begin the development, run `npm start` or `yarn start`.\n      To create a production bundle, use `npm run build` or `yarn build`.\n    -->\n  </body>\n</html>\n"
  },
  {
    "path": "examples/unified/react-app/public/manifest.json",
    "content": "{\n  \"short_name\": \"React App\",\n  \"name\": \"Create React App Sample\",\n  \"icons\": [\n    {\n      \"src\": \"favicon.ico\",\n      \"sizes\": \"64x64 32x32 24x24 16x16\",\n      \"type\": \"image/x-icon\"\n    },\n    {\n      \"src\": \"logo192.png\",\n      \"type\": \"image/png\",\n      \"sizes\": \"192x192\"\n    },\n    {\n      \"src\": \"logo512.png\",\n      \"type\": \"image/png\",\n      \"sizes\": \"512x512\"\n    }\n  ],\n  \"start_url\": \".\",\n  \"display\": \"standalone\",\n  \"theme_color\": \"#000000\",\n  \"background_color\": \"#ffffff\"\n}\n"
  },
  {
    "path": "examples/unified/react-app/public/robots.txt",
    "content": "# https://www.robotstxt.org/robotstxt.html\nUser-agent: *\nDisallow:\n"
  },
  {
    "path": "examples/unified/react-app/src/App.css",
    "content": ".App {\n  text-align: center;\n}\n\n.App-logo {\n  height: 40vmin;\n  pointer-events: none;\n}\n\n@media (prefers-reduced-motion: no-preference) {\n  .App-logo {\n    animation: App-logo-spin infinite 20s linear;\n  }\n}\n\n.App-header {\n  background-color: #282c34;\n  min-height: 100vh;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n  font-size: calc(10px + 2vmin);\n  color: white;\n}\n\n.App-link {\n  color: #61dafb;\n}\n\n@keyframes App-logo-spin {\n  from {\n    transform: rotate(0deg);\n  }\n  to {\n    transform: rotate(360deg);\n  }\n}\n"
  },
  {
    "path": "examples/unified/react-app/src/App.tsx",
    "content": "import React, { useEffect } from 'react';\nimport logo from './logo.svg';\nimport './App.css';\nimport { track, identify, setGroup, groupIdentify, Identify } from '@amplitude/unified';\n\nfunction App() {\n  useEffect(() => {\n    track('Page View', {\n      name: 'App',\n    });\n  }, []);\n\n  return (\n    <div className=\"App\">\n      <header className=\"App-header\">\n        <img src={logo} className=\"App-logo\" alt=\"logo\" />\n        <h2>Amplitude Analytics Browser Example with React</h2>\n\n        <button onClick={() => identify(new Identify().set('role', 'engineer'))}>\n          Identify\n        </button>\n\n        <button onClick={() => setGroup('org', 'engineering')}>\n          Group\n        </button>\n\n        <button onClick={() => groupIdentify('org', 'engineering', new Identify().set('technology', 'react.js'))}>\n          Group Identify\n        </button>\n\n        <button onClick={() => track('Button Click', { name: 'App' })}>\n          Track\n        </button>\n      </header>\n    </div>\n  );\n}\n\nexport default App;\n"
  },
  {
    "path": "examples/unified/react-app/src/index.css",
    "content": "body {\n  margin: 0;\n  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',\n    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',\n    sans-serif;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\ncode {\n  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',\n    monospace;\n}\n"
  },
  {
    "path": "examples/unified/react-app/src/index.tsx",
    "content": "import React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport './index.css';\nimport App from './App';\nimport reportWebVitals from './reportWebVitals';\nimport * as amplitude from '@amplitude/unified';\n\namplitude.initAll('API_KEY');\n\nconst root = ReactDOM.createRoot(\n  document.getElementById('root') as HTMLElement\n);\nroot.render(\n  <React.StrictMode>\n    <App />\n  </React.StrictMode>\n);\n\n// If you want to start measuring performance in your app, pass a function\n// to log results (for example: reportWebVitals(console.log))\n// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals\nreportWebVitals();\n"
  },
  {
    "path": "examples/unified/react-app/src/reportWebVitals.ts",
    "content": "import { ReportHandler } from 'web-vitals';\n\nconst reportWebVitals = (onPerfEntry?: ReportHandler) => {\n  if (onPerfEntry && onPerfEntry instanceof Function) {\n    import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {\n      getCLS(onPerfEntry);\n      getFID(onPerfEntry);\n      getFCP(onPerfEntry);\n      getLCP(onPerfEntry);\n      getTTFB(onPerfEntry);\n    });\n  }\n};\n\nexport default reportWebVitals;\n"
  },
  {
    "path": "examples/unified/react-app/src/setupTests.ts",
    "content": "// jest-dom adds custom jest matchers for asserting on DOM nodes.\n// allows you to do things like:\n// expect(element).toHaveTextContent(/react/i)\n// learn more: https://github.com/testing-library/jest-dom\nimport '@testing-library/jest-dom';\n"
  },
  {
    "path": "examples/unified/react-app/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es5\",\n    \"lib\": [\n      \"dom\",\n      \"dom.iterable\",\n      \"esnext\"\n    ],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"esModuleInterop\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"strict\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"noFallthroughCasesInSwitch\": true,\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"noEmit\": true,\n    \"jsx\": \"react-jsx\"\n  },\n  \"include\": [\n    \"src\"\n  ]\n}\n"
  },
  {
    "path": "jest.config.js",
    "content": "module.exports = {\n  preset: 'ts-jest',\n  transform: {\n    '^.+\\\\.ts$': 'ts-jest',\n  },\n  moduleFileExtensions: ['ts', 'js', 'json'],\n  collectCoverage: true,\n  collectCoverageFrom: ['**/src/**/*.ts'],\n  coverageReporters: ['lcov', 'text-summary'],\n  restoreMocks: true,\n  coverageThreshold: {\n    global: {\n      branches: 100,\n      functions: 100,\n      lines: 100,\n      statements: 100,\n    }\n  },\n  verbose: true,\n  modulePathIgnorePatterns: ['<rootDir>/lib'],\n  testPathIgnorePatterns: ['/e2e/', '/examples/react-native/']\n};\n"
  },
  {
    "path": "lerna.json",
    "content": "{\n  \"packages\": [\"packages/*\"],\n  \"version\": \"independent\",\n  \"npmClient\": \"pnpm\",\n  \"command\": {\n    \"version\": {\n      \"allowBranch\": [\"main\", \"hotfix/*\"],\n      \"conventionalCommits\": true,\n      \"message\": \"chore(release): publish\",\n      \"preid\": \"beta\",\n      \"exact\": true,\n    }\n  },\n  \"$schema\": \"node_modules/lerna/schemas/lerna-schema.json\"\n}\n"
  },
  {
    "path": "nx.json",
    "content": "{\n  \"extends\": \"nx/presets/npm.json\",\n  \"$schema\": \"./node_modules/nx/schemas/nx-schema.json\",\n  \"targetDefaults\": {\n    \"build\": {\n      \"dependsOn\": [\"^build\"],\n      \"inputs\": [\"production\", \"^production\"],\n      \"cache\": true\n    },\n    \"test\": {\n      \"dependsOn\": [\"build\"],\n      \"cache\": true\n    },\n    \"test:playwright\": {\n      \"cache\": true\n    },\n    \"lint\": {\n      \"inputs\": [\"default\", \"{workspaceRoot}/.eslintrc.js\"],\n      \"cache\": true\n    },\n    \"typecheck\": {\n      \"inputs\": [\"default\", \"^production\"],\n      \"cache\": true\n    }\n  },\n  \"namedInputs\": {\n    \"default\": [\"{projectRoot}/**/*\", \"sharedGlobals\"],\n    \"production\": [\n      \"default\",\n      \"!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)\",\n      \"!{projectRoot}/tsconfig.spec.json\",\n      \"!{projectRoot}/jest.config.[jt]s\",\n      \"!{projectRoot}/**/*.test.[jt]s?(x)\",\n      \"!{projectRoot}/test/**/*\",\n      \"!{projectRoot}/lib/**/*\",\n      \"!{projectRoot}/coverage/**/*\"\n    ],\n    \"sharedGlobals\": [\"{workspaceRoot}/nx.json\"]\n  },\n  \"defaultBase\": \"main\"\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"private\": true,\n  \"workspaces\": [\n    \"packages/*\"\n  ],\n  \"scripts\": {\n    \"build\": \"lerna run build --stream --include-dependencies --skip-nx-cache\",\n    \"build:vite\": \"rm -rf ./test-server/dist/ && vite build\",\n    \"build:nx-affected\": \"nx affected --target=build\",\n    \"watch\": \"nx run-many --target=watch --all --parallel 9999 --output-style=stream --maxParallel=0\",\n    \"clean\": \"lerna run clean --stream && rimraf node_modules docs\",\n    \"deploy:version\": \"lerna version\",\n    \"deploy:version:dry-run\": \"DRY_RUN=true lerna version --no-push --no-git-tag-version --allow-branch \\\"$(git rev-parse --abbrev-ref HEAD)\\\" --conventional-prerelease --no-changelog --no-push --no-git-tag-version\",\n    \"deploy:publish\": \"pnpm -r --filter \\\"./packages/**\\\" publish --no-git-checks\",\n    \"deploy:publish:dry-run\": \"DRY_RUN=true pnpm -r --filter \\\"./packages/**\\\" publish --dry-run --no-git-checks\",\n    \"deploy:pack\": \"DRY_RUN=true pnpm -r --filter \\\"./packages/**\\\" pack\",\n    \"dev\": \"concurrently \\\"pnpm run watch\\\" \\\"vite dev --open\\\"\",\n    \"dev:ssh\": \"pnpm run setup-dev-ssh && export SSH=true && pnpm run dev\",\n    \"docs\": \"typedoc\",\n    \"docs:check\": \"typedoc --emit none\",\n    \"fix\": \"lerna run fix --stream\",\n    \"generate-signed-cert\": \"sh ./scripts/dev/generate-signed-cert.sh\",\n    \"setup-local-domain\": \"sh ./scripts/dev/setup-local-domain.sh\",\n    \"setup-dev-ssh\": \"sh ./scripts/dev/setup-dev-ssh.sh\",\n    \"lint\": \"lerna run lint --stream\",\n    \"lint:nx-cache\": \"nx run-many --target=lint --all\",\n    \"lint:nx-affected\": \"nx affected --target=lint\",\n    \"lint:staged\": \"lint-staged\",\n    \"postinstall\": \"husky install\",\n    \"proxy\": \"node example-proxy/amplitude-proxy-server.js\",\n    \"proxy:dev\": \"nodemon example-proxy/amplitude-proxy-server.js\",\n    \"start\": \"vite preview --clearScreen=false\",\n    \"test\": \"lerna run test --stream\",\n    \"test:nx-cache\": \"nx run-many --target=test --all\",\n    \"test:nx-affected\": \"nx affected --target=test\",\n    \"test:examples\": \"jest --env=jsdom --coverage=false examples --setupFiles ./jest.setup.examples.js\",\n    \"test:unit\": \"lerna run test --stream --ignore @amplitude/analytics-*-test\",\n    \"test:e2e\": \"lerna run test --stream --scope @amplitude/analytics-*-test\",\n    \"test:e2e:remote-config\": \"pnpm build:vite && concurrently --kill-others --success first \\\"sh packages/e2e-remote-config/remote-config-test.sh\\\" \\\"pnpm start -- --port 5173 --clearScreen=false\\\"\",\n    \"test:e2e:remote-config:staging\": \"pnpm build:vite && concurrently --kill-others --success first \\\"sh packages/e2e-remote-config/remote-config-test-staging.sh\\\" \\\"pnpm start -- --port 5173 --clearScreen=false\\\"\",\n    \"test:playwright\": \"lerna run test:playwright --stream\",\n    \"test:playwright:ui\": \"playwright test --ui\",\n    \"test:playwright:debug\": \"playwright test --debug\",\n    \"test:playwright:ci\": \"playwright test\",\n    \"graph\": \"nx graph\",\n    \"version\": \"git add -A\"\n  },\n  \"devDependencies\": {\n    \"@amplitude/analytics-browser\": \"workspace:*\",\n    \"@aws-sdk/client-s3\": \"^3.0.0\",\n    \"@commitlint/cli\": \"^17.3.0\",\n    \"@commitlint/config-conventional\": \"^17.3.0\",\n    \"@nx/workspace\": \"^21.2.1\",\n    \"@playwright/test\": \"1.55.0\",\n    \"@types/jest\": \"^29.2.4\",\n    \"@types/node\": \"^18.11.14\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.46.1\",\n    \"@typescript-eslint/parser\": \"^5.46.1\",\n    \"axios\": \"^1.6.0\",\n    \"babel-core\": \"^6.26.3\",\n    \"babel-preset-env\": \"^1.7.0\",\n    \"concurrently\": \"^9.1.2\",\n    \"cors\": \"^2.8.5\",\n    \"eslint\": \"^8.29.0\",\n    \"eslint-config-prettier\": \"^8.5.0\",\n    \"eslint-import-resolver-typescript\": \"^4.4.4\",\n    \"eslint-plugin-import\": \"^2.32.0\",\n    \"eslint-plugin-jest\": \"^27.1.6\",\n    \"eslint-plugin-playwright\": \"^2.2.0\",\n    \"express\": \"^4.18.2\",\n    \"fake-indexeddb\": \"4.0.2\",\n    \"glob\": \"^10.3.10\",\n    \"husky\": \"^8.0.2\",\n    \"jest\": \"^29.3.1\",\n    \"jest-environment-jsdom\": \"^29.3.1\",\n    \"lerna\": \"^9.0.0\",\n    \"lint-staged\": \"^15.2.0\",\n    \"morgan\": \"^1.10.0\",\n    \"nodemon\": \"^3.0.1\",\n    \"nx\": \"^21.2.1\",\n    \"prettier\": \"^2.8.1\",\n    \"rimraf\": \"^3.0.2\",\n    \"source-map\": \"^0.7.4\",\n    \"ts-jest\": \"^29.0.3\",\n    \"tslib\": \"^2.4.1\",\n    \"typedoc\": \"^0.23.22\",\n    \"typescript\": \"^4.9.4\",\n    \"vite\": \"^6.3.4\",\n    \"yargs\": \"^17.7.1\"\n  },\n  \"lint-staged\": {\n    \"*.ts\": [\n      \"eslint --fix\",\n      \"prettier --write\"\n    ]\n  },\n  \"dependencies\": {\n    \"tslib\": \"^2.4.1\"\n  },\n  \"packageManager\": \"pnpm@10.26.1+sha512.664074abc367d2c9324fdc18037097ce0a8f126034160f709928e9e9f95d98714347044e5c3164d65bd5da6c59c6be362b107546292a8eecb7999196e5ce58fa\",\n  \"pnpm\": {\n    \"overrides\": {\n      \"typescript\": \"^4.9.4\"\n    }\n  }\n}\n"
  },
  {
    "path": "packages/analytics-browser/.eslintignore",
    "content": "playground/\n"
  },
  {
    "path": "packages/analytics-browser/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.42.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.42.2...@amplitude/analytics-browser@2.42.3) (2026-05-13)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.42.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.42.1...@amplitude/analytics-browser@2.42.2) (2026-05-11)\n\n\n### Bug Fixes\n\n* **analytics-browser:** remove plugin-session-replay-browser template ([#1746](https://github.com/amplitude/Amplitude-TypeScript/issues/1746)) ([809abdc](https://github.com/amplitude/Amplitude-TypeScript/commit/809abdca353926f9518547bcb967b6bd14b23e57))\n\n\n\n\n\n## [2.42.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.42.0...@amplitude/analytics-browser@2.42.1) (2026-05-05)\n\n\n### Bug Fixes\n\n* **analytics-browser:** make autocapture opt-in within Chrome Extension ([#1710](https://github.com/amplitude/Amplitude-TypeScript/issues/1710)) ([de5ff6e](https://github.com/amplitude/Amplitude-TypeScript/commit/de5ff6e4fc9bfcf5d880fb291c796614ef86cc59))\n\n\n\n\n\n# [2.42.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.41.1...@amplitude/analytics-browser@2.42.0) (2026-04-28)\n\n\n### Features\n\n* remove experimental request body compression backdoor ([#1699](https://github.com/amplitude/Amplitude-TypeScript/issues/1699)) ([98ecb9d](https://github.com/amplitude/Amplitude-TypeScript/commit/98ecb9dc1f3658cf6d0dfae1e9784335c9d33b5e))\n\n\n\n\n\n## [2.41.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.41.0...@amplitude/analytics-browser@2.41.1) (2026-04-22)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n# [2.41.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.40.0...@amplitude/analytics-browser@2.41.0) (2026-04-21)\n\n\n### Features\n\n* add long task tracking ([#1622](https://github.com/amplitude/Amplitude-TypeScript/issues/1622)) ([d995e1f](https://github.com/amplitude/Amplitude-TypeScript/commit/d995e1f2c098441808d65f6c171e171587e37ac2))\n\n\n\n\n\n# [2.40.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.39.0...@amplitude/analytics-browser@2.40.0) (2026-04-14)\n\n\n### Features\n\n* **analytics-browser:** event property attribution ([#1628](https://github.com/amplitude/Amplitude-TypeScript/issues/1628)) ([6d37e79](https://github.com/amplitude/Amplitude-TypeScript/commit/6d37e797976e0e77dc11046b9259eb4b80259996))\n\n\n\n\n\n# [2.39.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.38.1...@amplitude/analytics-browser@2.39.0) (2026-04-09)\n\n\n### Bug Fixes\n\n* **plugin-custom-enrichment:** allow disable custom enrichment plugin over remote config settings ([#1638](https://github.com/amplitude/Amplitude-TypeScript/issues/1638)) ([385c4de](https://github.com/amplitude/Amplitude-TypeScript/commit/385c4ded2b2622fde1ac0930495805e11353d55f))\n\n\n### Features\n\n* **analytics-browser:** [experimental] add video tracking function ([#1652](https://github.com/amplitude/Amplitude-TypeScript/issues/1652)) ([3af90e2](https://github.com/amplitude/Amplitude-TypeScript/commit/3af90e2f662d9ed82c56a506c8d2ef6d5da85bd8))\n\n\n\n\n\n## [2.38.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.38.0...@amplitude/analytics-browser@2.38.1) (2026-04-01)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n# [2.38.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.37.2...@amplitude/analytics-browser@2.38.0) (2026-03-26)\n\n\n### Features\n\n* **autocapture:** add viewportContentUpdated support to remote config ([#1621](https://github.com/amplitude/Amplitude-TypeScript/issues/1621)) ([f40b150](https://github.com/amplitude/Amplitude-TypeScript/commit/f40b150ddb44da9c69bc97da69f9ba003d1eb7d6))\n\n\n\n\n\n## [2.37.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.37.1...@amplitude/analytics-browser@2.37.2) (2026-03-24)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.37.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.37.0...@amplitude/analytics-browser@2.37.1) (2026-03-23)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n# [2.37.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.36.8...@amplitude/analytics-browser@2.37.0) (2026-03-20)\n\n\n### Features\n\n* **plugin-custom-enrichment:** add plugin based on remote config settings ([#1586](https://github.com/amplitude/Amplitude-TypeScript/issues/1586)) ([617ebfe](https://github.com/amplitude/Amplitude-TypeScript/commit/617ebfe7aaee04b0aef3db09b48ed11bad9a6ca3))\n\n\n\n\n\n## [2.36.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.36.7...@amplitude/analytics-browser@2.36.8) (2026-03-19)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.36.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.36.6...@amplitude/analytics-browser@2.36.7) (2026-03-17)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.36.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.36.5...@amplitude/analytics-browser@2.36.6) (2026-03-16)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.36.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.36.4...@amplitude/analytics-browser@2.36.5) (2026-03-13)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.36.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.36.3...@amplitude/analytics-browser@2.36.4) (2026-03-12)\n\n\n### Bug Fixes\n\n* **analytics-browser:** skip localhost + single word domain on TLD check ([#1584](https://github.com/amplitude/Amplitude-TypeScript/issues/1584)) ([a07861e](https://github.com/amplitude/Amplitude-TypeScript/commit/a07861e24bebeab641b4fb4cd474532a16e4e0e5))\n* **analytics-core:** remote config should not retry client side error except 429 ([#1590](https://github.com/amplitude/Amplitude-TypeScript/issues/1590)) ([b1445cb](https://github.com/amplitude/Amplitude-TypeScript/commit/b1445cb43272281ceb60da5055283fb42c494068))\n\n\n\n\n\n## [2.36.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.36.2...@amplitude/analytics-browser@2.36.3) (2026-03-09)\n\n\n### Bug Fixes\n\n* **analytics-browser:** Safari cookie writing race condition + extra exception catching ([#1578](https://github.com/amplitude/Amplitude-TypeScript/issues/1578)) ([bbcc6d7](https://github.com/amplitude/Amplitude-TypeScript/commit/bbcc6d77342a78388fce3fdf8b01d208e6403acf))\n* **analytics-browser:** skip known 2lds in TLD check ([#1575](https://github.com/amplitude/Amplitude-TypeScript/issues/1575)) ([1aaab18](https://github.com/amplitude/Amplitude-TypeScript/commit/1aaab1855d6739d4ac7c952e71427bff34844a74))\n\n\n\n\n\n## [2.36.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.36.1...@amplitude/analytics-browser@2.36.2) (2026-03-05)\n\n\n### Bug Fixes\n\n* make getTopLevelDomain and isEnabled synchronous to avoid re-entrancy ([#1564](https://github.com/amplitude/Amplitude-TypeScript/issues/1564)) ([ab9b09f](https://github.com/amplitude/Amplitude-TypeScript/commit/ab9b09f9ec9b9583f92c7cdffb7194cc30e0ea9f))\n\n\n\n\n\n## [2.36.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.36.0...@amplitude/analytics-browser@2.36.1) (2026-03-03)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n# [2.36.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.35.4...@amplitude/analytics-browser@2.36.0) (2026-03-03)\n\n\n### Bug Fixes\n\n* make default excluded referrers work better ([#1559](https://github.com/amplitude/Amplitude-TypeScript/issues/1559)) ([4bcca98](https://github.com/amplitude/Amplitude-TypeScript/commit/4bcca98e414833d7b7b3e4938ce46f55e6dad472))\n\n\n### Features\n\n* **analytics-browser:** add config attribution.excludeInternalReferrers ([#1548](https://github.com/amplitude/Amplitude-TypeScript/issues/1548)) ([df16648](https://github.com/amplitude/Amplitude-TypeScript/commit/df1664856bea96afde1dbac8dc523b4d69925c2a))\n* **analytics-browser:** support gzip request body compression ([#1542](https://github.com/amplitude/Amplitude-TypeScript/issues/1542)) ([0d2a7d2](https://github.com/amplitude/Amplitude-TypeScript/commit/0d2a7d2d873c86d8854dad16109af461ad392166))\n* manual opt in gzip ([#1568](https://github.com/amplitude/Amplitude-TypeScript/issues/1568)) ([303c130](https://github.com/amplitude/Amplitude-TypeScript/commit/303c130429c51b0913f3903db4ace5263e1c78e7))\n\n\n\n\n\n## [2.35.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.35.3...@amplitude/analytics-browser@2.35.4) (2026-02-26)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.35.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.35.2...@amplitude/analytics-browser@2.35.3) (2026-02-24)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.35.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.35.1...@amplitude/analytics-browser@2.35.2) (2026-02-20)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.35.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.35.0...@amplitude/analytics-browser@2.35.1) (2026-02-19)\n\n\n### Bug Fixes\n\n* **analytics-browser:** prevent circular reference in logBrowserOptions ([#1537](https://github.com/amplitude/Amplitude-TypeScript/issues/1537)) ([23b4fdb](https://github.com/amplitude/Amplitude-TypeScript/commit/23b4fdb106a242e4f64b81842f4227bcf771432b))\n\n\n\n\n\n# [2.35.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.34.1...@amplitude/analytics-browser@2.35.0) (2026-02-17)\n\n\n### Features\n\n* **analytics-browser:** add setIdentity() ([#1517](https://github.com/amplitude/Amplitude-TypeScript/issues/1517)) ([314b3c1](https://github.com/amplitude/Amplitude-TypeScript/commit/314b3c1b7ee5b0ef135848a66156eb2874daec5f))\n\n\n\n\n\n## [2.34.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.34.0...@amplitude/analytics-browser@2.34.1) (2026-02-10)\n\n\n### Bug Fixes\n\n* **analytics-browser:** defer session_start and attribution when optOut is \"true\" ([#1509](https://github.com/amplitude/Amplitude-TypeScript/issues/1509)) ([3a3818d](https://github.com/amplitude/Amplitude-TypeScript/commit/3a3818d19bd84e4aa8405e10f8538886dd647f38))\n* **analytics-browser:** prevent Form from being bound to 2x ([#1527](https://github.com/amplitude/Amplitude-TypeScript/issues/1527)) ([9ec707f](https://github.com/amplitude/Amplitude-TypeScript/commit/9ec707fc785bdd552bb6db89c9213c6293f71a3e))\n* **analytics-core:** add ValidPropertyType type ([#1525](https://github.com/amplitude/Amplitude-TypeScript/issues/1525)) ([f63c657](https://github.com/amplitude/Amplitude-TypeScript/commit/f63c6570f95acab087ad47d9ce9442fe42765a2c))\n\n\n\n\n\n# [2.34.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.33.5...@amplitude/analytics-browser@2.34.0) (2026-01-26)\n\n\n### Features\n\n* **analytics-browser:** add shouldTrackSubmit for custom form validation ([#1500](https://github.com/amplitude/Amplitude-TypeScript/issues/1500)) ([1d76745](https://github.com/amplitude/Amplitude-TypeScript/commit/1d76745dc202e27d188bfe47ae76d69806bbb566))\n\n\n\n\n\n## [2.33.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.33.4...@amplitude/analytics-browser@2.33.5) (2026-01-21)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.33.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.33.3...@amplitude/analytics-browser@2.33.4) (2026-01-15)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.33.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.33.2...@amplitude/analytics-browser@2.33.3) (2026-01-14)\n\n\n### Bug Fixes\n\n* **analytics-browser:** re-entrant error in cookies.isEnabled ([#1493](https://github.com/amplitude/Amplitude-TypeScript/issues/1493)) ([ed4f62c](https://github.com/amplitude/Amplitude-TypeScript/commit/ed4f62cb57a389deb1b67f3fdb310e30caf7e3e2))\n\n\n\n\n\n## [2.33.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.33.1...@amplitude/analytics-browser@2.33.2) (2026-01-14)\n\n\n### Bug Fixes\n\n* **analytics-browser:** two cookie problem resolution ([#1490](https://github.com/amplitude/Amplitude-TypeScript/issues/1490)) ([506638a](https://github.com/amplitude/Amplitude-TypeScript/commit/506638a2a412dc3843b0da9450325f70ff465422))\n* **deps:** bump node-forge from 1.3.1 to 1.3.3 in /packages/analytics-browser/playground/react-spa ([#1438](https://github.com/amplitude/Amplitude-TypeScript/issues/1438)) ([ffacc88](https://github.com/amplitude/Amplitude-TypeScript/commit/ffacc8888217249e6c8084ef7327872e1fa375ca))\n\n\n\n\n\n## [2.33.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.33.0...@amplitude/analytics-browser@2.33.1) (2025-12-30)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n# [2.33.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.32.2...@amplitude/analytics-browser@2.33.0) (2025-12-24)\n\n\n### Features\n\n* **analytics-browser:** add support to set headers for transport pro… ([#1444](https://github.com/amplitude/Amplitude-TypeScript/issues/1444)) ([c277239](https://github.com/amplitude/Amplitude-TypeScript/commit/c277239d317106496f7a08fc2933e72e391be9de))\n\n\n\n\n\n## [2.32.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.32.1...@amplitude/analytics-browser@2.32.2) (2025-12-16)\n\n\n### Bug Fixes\n\n* **analytics-browser:** remoteConfig.fetchRemoteConfig was broken ([#1434](https://github.com/amplitude/Amplitude-TypeScript/issues/1434)) ([43540d0](https://github.com/amplitude/Amplitude-TypeScript/commit/43540d0cc26baf491feebda3973343153626dcb9))\n\n\n\n\n\n## [2.32.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.32.0...@amplitude/analytics-browser@2.32.1) (2025-12-12)\n\n\n### Bug Fixes\n\n* **analytics-browser:** diagnostics track user agent ([#1428](https://github.com/amplitude/Amplitude-TypeScript/issues/1428)) ([11c14ed](https://github.com/amplitude/Amplitude-TypeScript/commit/11c14ede71725140fcdd86d3ab1dc277cc586729))\n\n\n\n\n\n# [2.32.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.31.4...@amplitude/analytics-browser@2.32.0) (2025-12-09)\n\n\n### Features\n\n* diagnostics uncaught sdk errors installed by script  ([#1419](https://github.com/amplitude/Amplitude-TypeScript/issues/1419)) ([dc0b3cc](https://github.com/amplitude/Amplitude-TypeScript/commit/dc0b3cc9df5915d1bfb773b64099c70fc9408fda))\n\n\n\n\n\n## [2.31.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.31.3...@amplitude/analytics-browser@2.31.4) (2025-12-08)\n\n\n### Bug Fixes\n\n* identify call race condition ([#1424](https://github.com/amplitude/Amplitude-TypeScript/issues/1424)) ([1aaaff5](https://github.com/amplitude/Amplitude-TypeScript/commit/1aaaff581a21ed4cedb50430550a66310e20ce8b))\n\n\n\n\n\n## [2.31.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.31.2...@amplitude/analytics-browser@2.31.3) (2025-11-21)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.31.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.31.1...@amplitude/analytics-browser@2.31.2) (2025-11-20)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.31.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.31.0...@amplitude/analytics-browser@2.31.1) (2025-11-17)\n\n\n### Bug Fixes\n\n* **analytics-core:** record unsuccessful response ([#1405](https://github.com/amplitude/Amplitude-TypeScript/issues/1405)) ([7e842fe](https://github.com/amplitude/Amplitude-TypeScript/commit/7e842feb0aa36ec4274b97a205b19613f3b5c642))\n\n\n\n\n\n# [2.31.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.30.1...@amplitude/analytics-browser@2.31.0) (2025-11-17)\n\n\n### Features\n\n* **analytics-browser:** add reset listener API ([#1393](https://github.com/amplitude/Amplitude-TypeScript/issues/1393)) ([7bd85e5](https://github.com/amplitude/Amplitude-TypeScript/commit/7bd85e51b01cefdb43b8474d930e8c219b739323))\n* **analytics-browser:** diagnostics remote config ([#1397](https://github.com/amplitude/Amplitude-TypeScript/issues/1397)) ([50dc4dd](https://github.com/amplitude/Amplitude-TypeScript/commit/50dc4dd3dee17facdb483c3411fd6d00a1f2c127))\n\n\n\n\n\n## [2.30.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.30.0...@amplitude/analytics-browser@2.30.1) (2025-11-05)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n# [2.30.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.29.0...@amplitude/analytics-browser@2.30.0) (2025-10-29)\n\n\n### Features\n\n* more diagnostics metrics ([#1371](https://github.com/amplitude/Amplitude-TypeScript/issues/1371)) ([40e255c](https://github.com/amplitude/Amplitude-TypeScript/commit/40e255c89c98f4ffffd883296d3d8a9947326aaa))\n\n\n\n\n\n# [2.29.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.28.0...@amplitude/analytics-browser@2.29.0) (2025-10-23)\n\n\n### Features\n\n* **autocapture:** set page url enrichment plugin to default on and add/fix tests ([#1287](https://github.com/amplitude/Amplitude-TypeScript/issues/1287)) ([d96d7dd](https://github.com/amplitude/Amplitude-TypeScript/commit/d96d7dd7db156eae51a342b4956db2530ca64d29))\n\n\n\n\n\n# [2.28.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.27.1...@amplitude/analytics-browser@2.28.0) (2025-10-23)\n\n\n### Features\n\n* **analytics-browser:** add remote config server url to proxy remote config requests ([#1348](https://github.com/amplitude/Amplitude-TypeScript/issues/1348)) ([461b598](https://github.com/amplitude/Amplitude-TypeScript/commit/461b59876a75af0d97fd639c35ce08f6b0f4c24b))\n\n\n\n\n\n## [2.27.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.27.0...@amplitude/analytics-browser@2.27.1) (2025-10-21)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n# [2.27.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.26.2...@amplitude/analytics-browser@2.27.0) (2025-10-17)\n\n\n### Features\n\n* make web-vitals autocapture GA ([#1347](https://github.com/amplitude/Amplitude-TypeScript/issues/1347)) ([178862f](https://github.com/amplitude/Amplitude-TypeScript/commit/178862f87e6ea8a882c1d612f48692ab1ab65e14))\n\n\n\n\n\n## [2.26.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.26.1...@amplitude/analytics-browser@2.26.2) (2025-10-15)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.26.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.26.0...@amplitude/analytics-browser@2.26.1) (2025-10-14)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n# [2.26.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.25.4...@amplitude/analytics-browser@2.26.0) (2025-10-14)\n\n\n### Bug Fixes\n\n* **analytics-browser:** remove analytics-remote-config dependency ([#1336](https://github.com/amplitude/Amplitude-TypeScript/issues/1336)) ([36ccea0](https://github.com/amplitude/Amplitude-TypeScript/commit/36ccea0156c500304983d2e7d53b40432ecb19e4))\n\n\n### Features\n\n* **plugin-network-capture-browser:** enable networkTracking by default when autocapture=true ([#1333](https://github.com/amplitude/Amplitude-TypeScript/issues/1333)) ([27e365b](https://github.com/amplitude/Amplitude-TypeScript/commit/27e365b76fe757a7161b85e5dc5795549c4ab1eb))\n\n\n\n\n\n## [2.25.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.25.3...@amplitude/analytics-browser@2.25.4) (2025-10-07)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.25.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.25.2...@amplitude/analytics-browser@2.25.3) (2025-10-06)\n\n\n### Bug Fixes\n\n* Allow timestamp override for experiment events ([#1317](https://github.com/amplitude/Amplitude-TypeScript/issues/1317)) ([055b998](https://github.com/amplitude/Amplitude-TypeScript/commit/055b99898bcff8f59755f92937b628e3852a5c35))\n* resolve pluralization issue frustrationInteractions ([#1320](https://github.com/amplitude/Amplitude-TypeScript/issues/1320)) ([3bd89d0](https://github.com/amplitude/Amplitude-TypeScript/commit/3bd89d073bb949b525fa6f65f66ad6511df4da34))\n\n\n\n\n\n## [2.25.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.25.1...@amplitude/analytics-browser@2.25.2) (2025-10-03)\n\n\n### Bug Fixes\n\n* add diagnostics to client and track autocapture getHierachy block time ([#1312](https://github.com/amplitude/Amplitude-TypeScript/issues/1312)) ([a919e22](https://github.com/amplitude/Amplitude-TypeScript/commit/a919e223428083a87954cffa50bc765baa5360b0))\n* **analytics-browser:** suppress unnecessary url warnings ([#1315](https://github.com/amplitude/Amplitude-TypeScript/issues/1315)) ([c65c726](https://github.com/amplitude/Amplitude-TypeScript/commit/c65c72604113cac24e877eb0ec9e160fd7d84a1a))\n* support timestamp override for Experiment events ([dc9640d](https://github.com/amplitude/Amplitude-TypeScript/commit/dc9640d1d8915a544fcf7dcad12704cb317d35cd))\n* undo debug statement issue from last PR ([#1319](https://github.com/amplitude/Amplitude-TypeScript/issues/1319)) ([6a98015](https://github.com/amplitude/Amplitude-TypeScript/commit/6a9801501c3f75ea9d580e20d15890e391b37cb6))\n\n\n### Reverts\n\n* **analytics-browser:** revert \"fix: support timestamp override for Experiment events\" ([#1316](https://github.com/amplitude/Amplitude-TypeScript/issues/1316)) ([bf4584b](https://github.com/amplitude/Amplitude-TypeScript/commit/bf4584b4426a7f6a1b4ec779a26fda50cfcd8389))\n\n\n\n\n\n## [2.25.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.25.0...@amplitude/analytics-browser@2.25.1) (2025-10-01)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n# [2.25.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.24.2...@amplitude/analytics-browser@2.25.0) (2025-09-25)\n\n\n### Features\n\n* **analytics-browser:** add \"identify\" to config ([#1303](https://github.com/amplitude/Amplitude-TypeScript/issues/1303)) ([693720c](https://github.com/amplitude/Amplitude-TypeScript/commit/693720c348eaac0ffef8b88454deae06ceca0bb4))\n\n\n\n\n\n## [2.24.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.24.1...@amplitude/analytics-browser@2.24.2) (2025-09-23)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.24.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.24.0...@amplitude/analytics-browser@2.24.1) (2025-09-18)\n\n\n### Bug Fixes\n\n* networkTracking support remote config headers ([#1288](https://github.com/amplitude/Amplitude-TypeScript/issues/1288)) ([1d0b476](https://github.com/amplitude/Amplitude-TypeScript/commit/1d0b476b5e5afc56e542961a63857696b9f47a04))\n\n\n\n\n\n# [2.24.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.23.7...@amplitude/analytics-browser@2.24.0) (2025-09-12)\n\n\n### Features\n\n* **analytics-browser:** add urlsRegex to remote capture rule for network tracking ([#1284](https://github.com/amplitude/Amplitude-TypeScript/issues/1284)) ([04392c9](https://github.com/amplitude/Amplitude-TypeScript/commit/04392c96844f5328e8d04d7c3840ad273ce38a43))\n* **analytics-browser:** make frustrationInteractions GA ([#1286](https://github.com/amplitude/Amplitude-TypeScript/issues/1286)) ([40d62be](https://github.com/amplitude/Amplitude-TypeScript/commit/40d62be5e1713a3756464f83bd15d25fe1294956))\n\n\n\n\n\n## [2.23.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.23.6...@amplitude/analytics-browser@2.23.7) (2025-09-09)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.23.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.23.5...@amplitude/analytics-browser@2.23.6) (2025-09-05)\n\n\n### Bug Fixes\n\n* Use original marketing cookies set by web experiment pre-redirect ([#1280](https://github.com/amplitude/Amplitude-TypeScript/issues/1280)) ([cb32969](https://github.com/amplitude/Amplitude-TypeScript/commit/cb329695d9654790f79aa23eaa8ba67b73e67974))\n\n\n\n\n\n## [2.23.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.23.4...@amplitude/analytics-browser@2.23.5) (2025-08-28)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.23.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.23.3...@amplitude/analytics-browser@2.23.4) (2025-08-26)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.23.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.23.2...@amplitude/analytics-browser@2.23.3) (2025-08-25)\n\n\n### Bug Fixes\n\n* add missing BrowserClient attributes ([#1272](https://github.com/amplitude/Amplitude-TypeScript/issues/1272)) ([678be79](https://github.com/amplitude/Amplitude-TypeScript/commit/678be79a3b4864300471d433a63c000c4b098c77))\n\n\n\n\n\n## [2.23.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.23.1...@amplitude/analytics-browser@2.23.2) (2025-08-25)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.23.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.23.0...@amplitude/analytics-browser@2.23.1) (2025-08-22)\n\n\n### Bug Fixes\n\n* **analytics-core:** fix typo in Reddit click-id ([#1267](https://github.com/amplitude/Amplitude-TypeScript/issues/1267)) ([43e581d](https://github.com/amplitude/Amplitude-TypeScript/commit/43e581d6465546a38373f758f179eee103172755))\n\n\n\n\n\n# [2.23.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.22.2...@amplitude/analytics-browser@2.23.0) (2025-08-21)\n\n\n### Features\n\n* **analytics-browser:** add urls matching attribute to network capture rules (experimental) ([#1252](https://github.com/amplitude/Amplitude-TypeScript/issues/1252)) ([c28a98c](https://github.com/amplitude/Amplitude-TypeScript/commit/c28a98c13536d3eb2472edcce6ec225539db00aa))\n\n\n\n\n\n## [2.22.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.22.1...@amplitude/analytics-browser@2.22.2) (2025-08-13)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.22.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.22.0...@amplitude/analytics-browser@2.22.1) (2025-08-08)\n\n\n### Bug Fixes\n\n* add function to translate remoteConfig to localConfig ([#1232](https://github.com/amplitude/Amplitude-TypeScript/issues/1232)) ([ae53401](https://github.com/amplitude/Amplitude-TypeScript/commit/ae5340141d8c55544ae3ac0fefa80e54f478ba04))\n\n\n\n\n\n# [2.22.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.21.1...@amplitude/analytics-browser@2.22.0) (2025-08-05)\n\n\n### Bug Fixes\n\n* **analtyics-browser): Revert \"feat(analytics-browser:** add page-url-previous-page plugin\" ([#1237](https://github.com/amplitude/Amplitude-TypeScript/issues/1237)) ([dfd7340](https://github.com/amplitude/Amplitude-TypeScript/commit/dfd7340f6519e647a814b3c66913b0c96b0567cf))\n* **analytics-browser:** use the new remote config client ([#1191](https://github.com/amplitude/Amplitude-TypeScript/issues/1191)) ([9af61ea](https://github.com/amplitude/Amplitude-TypeScript/commit/9af61ea1f29fa97644910f37440562e5a6d5eeba))\n\n\n### Features\n\n* **analytics-browser:** add page-url-previous-page plugin ([#1110](https://github.com/amplitude/Amplitude-TypeScript/issues/1110)) ([dc053ed](https://github.com/amplitude/Amplitude-TypeScript/commit/dc053ed9f0b6378fce6a49f6a6e4196f3622bd25))\n* **plugin-page-url-enrichment-browser:** AMP-130401 create Page URL Enrichment plugin for additional Page URL related properties ([#1238](https://github.com/amplitude/Amplitude-TypeScript/issues/1238)) ([4673be8](https://github.com/amplitude/Amplitude-TypeScript/commit/4673be86ab5535fdca66d1743ef4ee071d5fdef7))\n\n\n\n\n\n## [2.21.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.21.0...@amplitude/analytics-browser@2.21.1) (2025-07-30)\n\n\n### Bug Fixes\n\n* **analytics-browser:** support evaluation window for cross domain t… ([#1227](https://github.com/amplitude/Amplitude-TypeScript/issues/1227)) ([498224e](https://github.com/amplitude/Amplitude-TypeScript/commit/498224eb91296390193f9541debc14a75b677925))\n\n\n\n\n\n# [2.21.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.20.1...@amplitude/analytics-browser@2.21.0) (2025-07-29)\n\n\n### Bug Fixes\n\n* **analytics-react-native:** migrate to analytics-core v2 ([#1216](https://github.com/amplitude/Amplitude-TypeScript/issues/1216)) ([76e85a1](https://github.com/amplitude/Amplitude-TypeScript/commit/76e85a1daa704a1c4c44d0176a56c8dd8d4ad3f1))\n\n\n### Features\n\n* **analytics-core:** expose unified AmplitudeContext and AnalyticsClient ([#1222](https://github.com/amplitude/Amplitude-TypeScript/issues/1222)) ([7e32712](https://github.com/amplitude/Amplitude-TypeScript/commit/7e327128b4032592897dc6bb50dedda053ad8eda))\n\n\n\n\n\n## [2.20.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.20.0...@amplitude/analytics-browser@2.20.1) (2025-07-18)\n\n\n### Bug Fixes\n\n* **analytics-browser:** disable frustrationInteractions and webVitals when autocapture=true ([#1214](https://github.com/amplitude/Amplitude-TypeScript/issues/1214)) ([b16efb9](https://github.com/amplitude/Amplitude-TypeScript/commit/b16efb98d4e8a1b94114f8e0dbf0501c4984123a))\n\n\n\n\n\n# [2.20.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.19.0...@amplitude/analytics-browser@2.20.0) (2025-07-17)\n\n\n### Features\n\n* **analytics-browser:** support autocapture.webVitals ([#1195](https://github.com/amplitude/Amplitude-TypeScript/issues/1195)) ([a186f52](https://github.com/amplitude/Amplitude-TypeScript/commit/a186f523a28d8a322842566b892f50bcf2643142))\n\n\n\n\n\n# [2.19.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.18.2...@amplitude/analytics-browser@2.19.0) (2025-07-15)\n\n\n### Features\n\n* **analytics-browser:** add experimental frustrationInteractions ([#1209](https://github.com/amplitude/Amplitude-TypeScript/issues/1209)) ([e321744](https://github.com/amplitude/Amplitude-TypeScript/commit/e3217444c58be15e779ff1fd54a55027c93f5db0))\n\n\n\n\n\n## [2.18.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.18.1...@amplitude/analytics-browser@2.18.2) (2025-07-11)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.18.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.18.0...@amplitude/analytics-browser@2.18.1) (2025-07-08)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n# [2.18.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.17.12...@amplitude/analytics-browser@2.18.0) (2025-06-30)\n\n\n### Features\n\n* add getOptOut() and getIdentity() ([#1174](https://github.com/amplitude/Amplitude-TypeScript/issues/1174)) ([72017c8](https://github.com/amplitude/Amplitude-TypeScript/commit/72017c8a1a54d929542e883e61d61168f214a780))\n\n\n\n\n\n## [2.17.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.17.11...@amplitude/analytics-browser@2.17.12) (2025-06-26)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.17.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.17.10...@amplitude/analytics-browser@2.17.11) (2025-06-25)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.17.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.17.9...@amplitude/analytics-browser@2.17.10) (2025-06-16)\n\n\n### Bug Fixes\n\n* guard globalScope missing \"addEventListener\" ([#1154](https://github.com/amplitude/Amplitude-TypeScript/issues/1154)) ([7cf775f](https://github.com/amplitude/Amplitude-TypeScript/commit/7cf775f320375b86fa15710444e101f3905b4836))\n\n\n\n\n\n## [2.17.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.17.8...@amplitude/analytics-browser@2.17.9) (2025-06-11)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.17.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.17.7...@amplitude/analytics-browser@2.17.8) (2025-06-03)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.17.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.17.7-main.0...@amplitude/analytics-browser@2.17.7) (2025-05-27)\n\n\n### Bug Fixes\n\n* **analytics-browser:** support autocapture.networkTracking as object ([#1095](https://github.com/amplitude/Amplitude-TypeScript/issues/1095)) ([121abc7](https://github.com/amplitude/Amplitude-TypeScript/commit/121abc7e69a354cc704de7cbe493b8c79fa6eacd))\n\n\n### Reverts\n\n* \"chore(release): publish\" ([#1094](https://github.com/amplitude/Amplitude-TypeScript/issues/1094)) ([f6db1ee](https://github.com/amplitude/Amplitude-TypeScript/commit/f6db1eed32ed77c7ce626624dc55972971f3b27d))\n\n\n\n\n\n## [2.17.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.17.5...@amplitude/analytics-browser@2.17.6) (2025-05-14)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.17.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.17.4...@amplitude/analytics-browser@2.17.5) (2025-05-13)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.17.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.17.3...@amplitude/analytics-browser@2.17.4) (2025-05-07)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.17.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.17.2...@amplitude/analytics-browser@2.17.3) (2025-05-05)\n\n\n### Bug Fixes\n\n* **analytics-browser:** use performance.now in network capture ([#1060](https://github.com/amplitude/Amplitude-TypeScript/issues/1060)) ([70917e2](https://github.com/amplitude/Amplitude-TypeScript/commit/70917e26369d27adf62e6b9a44a39599a312b3ef))\n\n\n\n\n\n## [2.17.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.17.1...@amplitude/analytics-browser@2.17.2) (2025-05-02)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.17.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.17.0...@amplitude/analytics-browser@2.17.1) (2025-05-02)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n# [2.17.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.16.1...@amplitude/analytics-browser@2.17.0) (2025-05-02)\n\n\n### Features\n\n* **analytics-browser:** autocapture network errors ([#1050](https://github.com/amplitude/Amplitude-TypeScript/issues/1050)) ([104350f](https://github.com/amplitude/Amplitude-TypeScript/commit/104350ffe8b1bd1a7090482ac3bf24d85672bd43))\n\n\n\n\n\n## [2.16.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.16.0...@amplitude/analytics-browser@2.16.1) (2025-04-30)\n\n\n### Bug Fixes\n\n* **analytics-browser:** fix TS2742 by re-exporting types ([#1049](https://github.com/amplitude/Amplitude-TypeScript/issues/1049)) ([c2bffac](https://github.com/amplitude/Amplitude-TypeScript/commit/c2bffac7fc06e19b6c227c89635836c635d0385b))\n* **analytics-browser:** reapply fix for default config values not being used for fetchRemoteConfig ([#1048](https://github.com/amplitude/Amplitude-TypeScript/issues/1048)) ([95bf251](https://github.com/amplitude/Amplitude-TypeScript/commit/95bf2519d8dd6c24a6d79b369cffc0fdf41f2f2d))\n\n\n\n\n\n# [2.16.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.15.0...@amplitude/analytics-browser@2.16.0) (2025-04-22)\n\n\n### Bug Fixes\n\n* **analytics-browser:** default values for config were not being used for fetchRemoteConfig ([#1037](https://github.com/amplitude/Amplitude-TypeScript/issues/1037)) ([9310364](https://github.com/amplitude/Amplitude-TypeScript/commit/9310364a3b022fdc891b44d84c5161c92bd4fc6d))\n\n\n### Features\n\n* **analytics-browser:** allow initialization of remote config property pageUrlAllowlistRegex ([#1021](https://github.com/amplitude/Amplitude-TypeScript/issues/1021)) ([7bdb80b](https://github.com/amplitude/Amplitude-TypeScript/commit/7bdb80b5397288cfda0f657a337cde0aa901db2b))\n\n\n\n\n\n# [2.15.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.14.0...@amplitude/analytics-browser@2.15.0) (2025-04-17)\n\n\n### Bug Fixes\n\n* **analytics-core:** add support for experiment plugin ([#1033](https://github.com/amplitude/Amplitude-TypeScript/issues/1033)) ([69a20c7](https://github.com/amplitude/Amplitude-TypeScript/commit/69a20c7a895eb4bb4668583ea3371d0ca2df18d2))\n\n\n### Features\n\n* **analytics-core:** new plugin interfaces onXXXchanged() ([#1025](https://github.com/amplitude/Amplitude-TypeScript/issues/1025)) ([e6fd23b](https://github.com/amplitude/Amplitude-TypeScript/commit/e6fd23b17809d0c7d94e7627636b200166d41a0f))\n\n\n\n\n\n# [2.14.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.13.3...@amplitude/analytics-browser@2.14.0) (2025-04-15)\n\n\n### Features\n\n* **analytics-browser:** plugin host ([#1013](https://github.com/amplitude/Amplitude-TypeScript/issues/1013)) ([a4af4c7](https://github.com/amplitude/Amplitude-TypeScript/commit/a4af4c7490384e749132f84d0385db5583c2b742))\n\n\n\n\n\n## [2.13.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.13.2...@amplitude/analytics-browser@2.13.3) (2025-04-10)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.13.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.13.1...@amplitude/analytics-browser@2.13.2) (2025-04-07)\n\n\n### Bug Fixes\n\n* remove log statements ([#1019](https://github.com/amplitude/Amplitude-TypeScript/issues/1019)) ([c6dd24e](https://github.com/amplitude/Amplitude-TypeScript/commit/c6dd24e18751cc3f02b94fcfc7677c2cc9025293))\n\n\n\n\n\n## [2.13.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.13.0...@amplitude/analytics-browser@2.13.1) (2025-04-07)\n\n\n### Bug Fixes\n\n* **analytics-browser:** add try/catch when accessing localStorage ([#1017](https://github.com/amplitude/Amplitude-TypeScript/issues/1017)) ([7c8a9dd](https://github.com/amplitude/Amplitude-TypeScript/commit/7c8a9ddd329a8a780328396966544080313574cb))\n\n\n\n\n\n# [2.13.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.12.2...@amplitude/analytics-browser@2.13.0) (2025-04-02)\n\n\n### Bug Fixes\n\n* **analytics-browser:** export more types ([#1011](https://github.com/amplitude/Amplitude-TypeScript/issues/1011)) ([561afc2](https://github.com/amplitude/Amplitude-TypeScript/commit/561afc2538da25867db02646829b2eb81693abcd))\n\n\n### Features\n\n* **analytics-browser:** set default for fetchRemoteConfig option to true ([#1008](https://github.com/amplitude/Amplitude-TypeScript/issues/1008)) ([5138cd1](https://github.com/amplitude/Amplitude-TypeScript/commit/5138cd16be1ff3bb57c38ec0eae5098a1b7933fc))\n\n\n\n\n\n## [2.12.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.12.1...@amplitude/analytics-browser@2.12.2) (2025-03-24)\n\n\n### Bug Fixes\n\n* **analytics-browser:** re-export enums from analytics-types ([#1005](https://github.com/amplitude/Amplitude-TypeScript/issues/1005)) ([01a497e](https://github.com/amplitude/Amplitude-TypeScript/commit/01a497ea79513c9995db5852e38f8661f28edb77))\n* **analytics-browser:** should track file download and form interaction when plugins are installed after page loads ([#1003](https://github.com/amplitude/Amplitude-TypeScript/issues/1003)) ([6066677](https://github.com/amplitude/Amplitude-TypeScript/commit/6066677f65aefbe67d4b3efbfb96ba5a95264230))\n\n\n\n\n\n## [2.12.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.12.0...@amplitude/analytics-browser@2.12.1) (2025-03-21)\n\n\n### Bug Fixes\n\n* **analytics-browser:** replace analytics-types with analytics-core ([#993](https://github.com/amplitude/Amplitude-TypeScript/issues/993)) ([f180f05](https://github.com/amplitude/Amplitude-TypeScript/commit/f180f05854393bf18d94f1753d284778ba3b5377))\n\n\n\n\n\n# [2.12.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.11.13...@amplitude/analytics-browser@2.12.0) (2025-03-14)\n\n\n### Features\n\n* **analytics-core:** merge analytics-client-common  ([#977](https://github.com/amplitude/Amplitude-TypeScript/issues/977)) ([1746ae5](https://github.com/amplitude/Amplitude-TypeScript/commit/1746ae5efb1ecd0e7586bc22ff8a704a6928c26a))\n* **analytics-core:** merge analytics-types ([#989](https://github.com/amplitude/Amplitude-TypeScript/issues/989)) ([9f7ed68](https://github.com/amplitude/Amplitude-TypeScript/commit/9f7ed68e8ec468f5c597ce427c70ffd855dde629))\n\n\n\n\n\n## [2.11.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.11.12...@amplitude/analytics-browser@2.11.13) (2025-02-28)\n\n\n### Bug Fixes\n\n* **analytics-core:** should not flush until previous request resolves ([#964](https://github.com/amplitude/Amplitude-TypeScript/issues/964)) ([771ce55](https://github.com/amplitude/Amplitude-TypeScript/commit/771ce556cb131b71ddb28461268a6feb5f3a1b1d))\n\n\n### Reverts\n\n* Revert \"chore(release): publish\" ([d392f62](https://github.com/amplitude/Amplitude-TypeScript/commit/d392f6290b8bb4dd955d6e6f20b00191679489c4))\n\n\n\n\n\n## [2.11.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.11.11...@amplitude/analytics-browser@2.11.12) (2025-02-14)\n\n\n### Bug Fixes\n\n* **analytics-browser:** form tracking accesses element attributes through getAttribute ([#959](https://github.com/amplitude/Amplitude-TypeScript/issues/959)) ([28305b1](https://github.com/amplitude/Amplitude-TypeScript/commit/28305b16a6361494ed4de5a4805dba520273e1c1))\n\n\n\n\n\n## [2.11.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.11.10...@amplitude/analytics-browser@2.11.11) (2024-12-31)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.11.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.11.9...@amplitude/analytics-browser@2.11.10) (2024-12-17)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.11.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.11.8...@amplitude/analytics-browser@2.11.9) (2024-11-05)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.11.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.11.7...@amplitude/analytics-browser@2.11.8) (2024-10-21)\n\n\n### Bug Fixes\n\n* **analytics-browser:** should track file download when with url params ([#898](https://github.com/amplitude/Amplitude-TypeScript/issues/898)) ([03c9604](https://github.com/amplitude/Amplitude-TypeScript/commit/03c960456445eb1e76ae983e01ac2676c579f65a))\n\n\n\n\n\n## [2.11.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.11.6...@amplitude/analytics-browser@2.11.7) (2024-09-26)\n\n\n### Bug Fixes\n\n* disable network checker if navigator is unavailable ([1e0456e](https://github.com/amplitude/Amplitude-TypeScript/commit/1e0456eb4eb780d8ad100487cc06a7a768c75bfe))\n\n\n\n\n\n## [2.11.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.11.5...@amplitude/analytics-browser@2.11.6) (2024-09-18)\n\n\n### Bug Fixes\n\n* **analytics-browser:** bump autocapture plugin version ([#880](https://github.com/amplitude/Amplitude-TypeScript/issues/880)) ([30eb04a](https://github.com/amplitude/Amplitude-TypeScript/commit/30eb04aa670d4637496c10ede373314893a374c1))\n\n\n\n\n\n## [2.11.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.11.4...@amplitude/analytics-browser@2.11.5) (2024-09-17)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.11.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.11.3...@amplitude/analytics-browser@2.11.4) (2024-09-16)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.11.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.11.2...@amplitude/analytics-browser@2.11.3) (2024-09-10)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n\n\n\n\n## [2.11.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.11.1...@amplitude/analytics-browser@2.11.2) (2024-09-05)\n\n\n### Bug Fixes\n\n* **browser:** bump plugin-autocapture-browser package ([#864](https://github.com/amplitude/Amplitude-TypeScript/issues/864)) ([6e14acf](https://github.com/amplitude/Amplitude-TypeScript/commit/6e14acf4e15f09ada5f4a6641997619efd93bc77))\n\n\n\n\n\n## [2.11.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.11.0...@amplitude/analytics-browser@2.11.1) (2024-08-23)\n\n\n### Bug Fixes\n\n* **browser:** remove fetchIDB from remote config ([91c89d1](https://github.com/amplitude/Amplitude-TypeScript/commit/91c89d16fbdaa8bc6091c7fd193d63314a0da101))\n\n\n\n\n\n# [2.11.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.10.0...@amplitude/analytics-browser@2.11.0) (2024-08-13)\n\n\n### Features\n\n* support remote config for each autocapture field ([#848](https://github.com/amplitude/Amplitude-TypeScript/issues/848)) ([939d49f](https://github.com/amplitude/Amplitude-TypeScript/commit/939d49f488bda8bbe4fa57cd2a2ab23f75540fc5))\n\n\n\n\n\n# [2.10.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.9.3...@amplitude/analytics-browser@2.10.0) (2024-08-02)\n\n\n### Features\n\n* remote config ([#832](https://github.com/amplitude/Amplitude-TypeScript/issues/832)) ([c415f79](https://github.com/amplitude/Amplitude-TypeScript/commit/c415f792a98253ac60885eb1dc7e53b78ca47dcb)), closes [#769](https://github.com/amplitude/Amplitude-TypeScript/issues/769) [#772](https://github.com/amplitude/Amplitude-TypeScript/issues/772) [#780](https://github.com/amplitude/Amplitude-TypeScript/issues/780) [#782](https://github.com/amplitude/Amplitude-TypeScript/issues/782) [#811](https://github.com/amplitude/Amplitude-TypeScript/issues/811) [#828](https://github.com/amplitude/Amplitude-TypeScript/issues/828)\n\n\n\n\n\n## [2.9.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.9.2...@amplitude/analytics-browser@2.9.3) (2024-06-26)\n\n\n### Bug Fixes\n\n* **analytics-browser:** fall back to MemoryStorage when localStorage is disabled ([#793](https://github.com/amplitude/Amplitude-TypeScript/issues/793)) ([bb7664e](https://github.com/amplitude/Amplitude-TypeScript/commit/bb7664ea082eba9fe9f584302bb9a0402365aa2a))\n\n\n\n\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.9.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.9.1...@amplitude/analytics-browser@2.9.2) (2024-06-24)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.9.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.9.0...@amplitude/analytics-browser@2.9.1) (2024-06-24)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.9.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.8.1...@amplitude/analytics-browser@2.9.0) (2024-06-17)\n\n### Bug Fixes\n\n- adding ability to enable debug logs using cookies\n  ([bc36f08](https://github.com/amplitude/Amplitude-TypeScript/commit/bc36f0893b27d96a676120dadd50dd756921de46))\n- don't use global window directly\n  ([7a88927](https://github.com/amplitude/Amplitude-TypeScript/commit/7a88927efe30b15b91d33b2fd05ce76d985c7a9a))\n- response with non-json format ([#758](https://github.com/amplitude/Amplitude-TypeScript/issues/758))\n  ([3d234ca](https://github.com/amplitude/Amplitude-TypeScript/commit/3d234ca5a71bacf9ab7f82a115cb2010e94a3a33))\n\n### Features\n\n- **analytics-browser:** consume remote config ([#769](https://github.com/amplitude/Amplitude-TypeScript/issues/769))\n  ([9c4e03c](https://github.com/amplitude/Amplitude-TypeScript/commit/9c4e03c3b3989213ac04410c8b9bf5e78ed393cf))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.8.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.8.0...@amplitude/analytics-browser@2.8.1) (2024-05-24)\n\n### Bug Fixes\n\n- success response with no body ([#755](https://github.com/amplitude/Amplitude-TypeScript/issues/755))\n  ([5d1eb72](https://github.com/amplitude/Amplitude-TypeScript/commit/5d1eb72bf9114acd884e709660eeedb0511ef4af))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.8.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.7.4...@amplitude/analytics-browser@2.8.0) (2024-05-21)\n\n### Features\n\n- support sessionId from url for cross domain tracking\n  ([#753](https://github.com/amplitude/Amplitude-TypeScript/issues/753))\n  ([691d725](https://github.com/amplitude/Amplitude-TypeScript/commit/691d725131b5dfba497084fcf101a4e6e22bbd59))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.7.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.7.3...@amplitude/analytics-browser@2.7.4) (2024-05-17)\n\n### Bug Fixes\n\n- fix the session event fire too often issue ([#751](https://github.com/amplitude/Amplitude-TypeScript/issues/751))\n  ([69bc69b](https://github.com/amplitude/Amplitude-TypeScript/commit/69bc69bd8e05b36ca76079dc9a01552315aaef5a))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.7.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.7.2...@amplitude/analytics-browser@2.7.3) (2024-05-15)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.7.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.7.1...@amplitude/analytics-browser@2.7.2) (2024-05-07)\n\n### Bug Fixes\n\n- location is polyfilled to an empty object ([#738](https://github.com/amplitude/Amplitude-TypeScript/issues/738))\n  ([130add9](https://github.com/amplitude/Amplitude-TypeScript/commit/130add99485c0d33e6a8ce32168212a2453025e4))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.7.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.7.0...@amplitude/analytics-browser@2.7.1) (2024-05-03)\n\n### Reverts\n\n- Revert \"fix: have session and device IDs ready before plugin setup (#691)\"\n  ([7411a6d](https://github.com/amplitude/Amplitude-TypeScript/commit/7411a6ddf22119aa7c1b0928035a1b31624e47f3)), closes\n  [#691](https://github.com/amplitude/Amplitude-TypeScript/issues/691)\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.7.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.6.3-beta.0...@amplitude/analytics-browser@2.7.0) (2024-04-29)\n\n### Bug Fixes\n\n- [AMP-95816] fix pageCounter bug ([#720](https://github.com/amplitude/Amplitude-TypeScript/issues/720))\n  ([8899853](https://github.com/amplitude/Amplitude-TypeScript/commit/88998534b3bd3c88e66fb88bafd41768e41d377c))\n\n### Features\n\n- update bookmarklet to use autocapture plugin ([#728](https://github.com/amplitude/Amplitude-TypeScript/issues/728))\n  ([6bbb69d](https://github.com/amplitude/Amplitude-TypeScript/commit/6bbb69d971dfabab533c60930551bb5e3578bed0))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.6.3-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.6.2...@amplitude/analytics-browser@2.6.3-beta.0) (2024-04-19)\n\n### Bug Fixes\n\n- fetch the campaign in SPA at session start ([#723](https://github.com/amplitude/Amplitude-TypeScript/issues/723))\n  ([6961717](https://github.com/amplitude/Amplitude-TypeScript/commit/696171780d6e3e02d3531f230bdceb3c36d8af38))\n- fix web attribution identify and session start order\n  ([#696](https://github.com/amplitude/Amplitude-TypeScript/issues/696))\n  ([2f077da](https://github.com/amplitude/Amplitude-TypeScript/commit/2f077da7b528ed6f23f7459b7c961c099dbcb1bb))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.6.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.6.2-beta.0...@amplitude/analytics-browser@2.6.2) (2024-04-09)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.6.2-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.6.1...@amplitude/analytics-browser@2.6.2-beta.0) (2024-03-28)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.6.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.6.0...@amplitude/analytics-browser@2.6.1) (2024-03-27)\n\n### Bug Fixes\n\n- adding more tests\n  ([68ca5ab](https://github.com/amplitude/Amplitude-TypeScript/commit/68ca5ab74ddeda559a7a476f6780cbbb84a16c07))\n- fix failing tests\n  ([77e3a60](https://github.com/amplitude/Amplitude-TypeScript/commit/77e3a603ce69c5f9fe63742b07e9f734f0e62fa5))\n- have session and device IDs ready before plugin setup\n  ([#691](https://github.com/amplitude/Amplitude-TypeScript/issues/691))\n  ([83e3eca](https://github.com/amplitude/Amplitude-TypeScript/commit/83e3eca5a529838a19f6c2afb59e1d8a5f2ac650))\n- register download and form listeners after window is loaded\n  ([ccd3766](https://github.com/amplitude/Amplitude-TypeScript/commit/ccd3766d2b2433147a8051e7fdce17b477bd2a2d))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.6.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.5.3...@amplitude/analytics-browser@2.6.0) (2024-03-23)\n\n### Features\n\n- update bookmarklet snippet ([#679](https://github.com/amplitude/Amplitude-TypeScript/issues/679))\n  ([790311c](https://github.com/amplitude/Amplitude-TypeScript/commit/790311c1286237c9e081789789b2693a5d67160e))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.5.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.5.2...@amplitude/analytics-browser@2.5.3) (2024-03-12)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.5.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.5.1...@amplitude/analytics-browser@2.5.2) (2024-02-27)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.5.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.5.0...@amplitude/analytics-browser@2.5.1) (2024-02-23)\n\n### Bug Fixes\n\n- fix typo for pageCounter ([#668](https://github.com/amplitude/Amplitude-TypeScript/issues/668))\n  ([ffc1f25](https://github.com/amplitude/Amplitude-TypeScript/commit/ffc1f25137db536885eff13d3920edd02cc4aa46))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.5.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.4.1...@amplitude/analytics-browser@2.5.0) (2024-02-23)\n\n### Features\n\n- landing page improvement ([#667](https://github.com/amplitude/Amplitude-TypeScript/issues/667))\n  ([5f365f0](https://github.com/amplitude/Amplitude-TypeScript/commit/5f365f0b933ee890aee1d9ac083576f09b0defc3))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.4.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.4.0...@amplitude/analytics-browser@2.4.1) (2024-02-13)\n\n### Bug Fixes\n\n- should not install page view tracking plugin based on config\n  ([#662](https://github.com/amplitude/Amplitude-TypeScript/issues/662))\n  ([178a7f0](https://github.com/amplitude/Amplitude-TypeScript/commit/178a7f0c7943a1b0fed4855c13cea3ee2376f04d))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.4.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.3.8...@amplitude/analytics-browser@2.4.0) (2024-01-24)\n\n### Features\n\n- add offline mode ([#644](https://github.com/amplitude/Amplitude-TypeScript/issues/644))\n  ([f2cd717](https://github.com/amplitude/Amplitude-TypeScript/commit/f2cd717316eef66b101153cb8eedf37fadc6de0c))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.3.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.3.7...@amplitude/analytics-browser@2.3.8) (2023-12-20)\n\n### Reverts\n\n- update attribution plugin to apply utm params to the `session_start` event\n  ([#638](https://github.com/amplitude/Amplitude-TypeScript/issues/638))\n  ([c820279](https://github.com/amplitude/Amplitude-TypeScript/commit/c820279cbef2123d890beb7861d7edbbc3926f6e))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.3.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.3.6...@amplitude/analytics-browser@2.3.7) (2023-12-12)\n\n### Bug Fixes\n\n- ignore non-string form.id ([#629](https://github.com/amplitude/Amplitude-TypeScript/issues/629))\n  ([690af77](https://github.com/amplitude/Amplitude-TypeScript/commit/690af774d9bc36c6c4a76311a9bbe189c1a698d1))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.3.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.3.6-beta.0...@amplitude/analytics-browser@2.3.6) (2023-12-01)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.3.6-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.3.5...@amplitude/analytics-browser@2.3.6-beta.0) (2023-11-22)\n\n### Bug Fixes\n\n- update attribution plugin to apply utm params to the `session_start` event\n  ([#619](https://github.com/amplitude/Amplitude-TypeScript/issues/619))\n  ([bf45ca6](https://github.com/amplitude/Amplitude-TypeScript/commit/bf45ca6c17ac8d656cb6c5bb4f4fa19ff344ac85))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.3.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.3.4...@amplitude/analytics-browser@2.3.5) (2023-11-16)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.3.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.3.3...@amplitude/analytics-browser@2.3.4) (2023-11-16)\n\n### Bug Fixes\n\n- npm latest tag ([#623](https://github.com/amplitude/Amplitude-TypeScript/issues/623))\n  ([7b2b6d1](https://github.com/amplitude/Amplitude-TypeScript/commit/7b2b6d111592a277039101913072c19a724fa199))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.3.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.3.2...@amplitude/analytics-browser@2.3.3) (2023-10-18)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.3.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.3.1...@amplitude/analytics-browser@2.3.2) (2023-09-26)\n\n### Bug Fixes\n\n- update README for lerna to pickup package changes\n  ([#593](https://github.com/amplitude/Amplitude-TypeScript/issues/593))\n  ([a170820](https://github.com/amplitude/Amplitude-TypeScript/commit/a1708203483d2abf9c2feb78545ecc3c1afebfe5))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.3.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.3.0...@amplitude/analytics-browser@2.3.1) (2023-09-18)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.3.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.2.3...@amplitude/analytics-browser@2.3.0) (2023-09-15)\n\n### Features\n\n- add bookmarklet ([#529](https://github.com/amplitude/Amplitude-TypeScript/issues/529))\n  ([4a93304](https://github.com/amplitude/Amplitude-TypeScript/commit/4a933046a9caa707b4a7767265f5e3dba9bb32f3))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.2.2...@amplitude/analytics-browser@2.2.3) (2023-08-31)\n\n### Bug Fixes\n\n- ignore non-string form.name values for form interaction tracking\n  ([#572](https://github.com/amplitude/Amplitude-TypeScript/issues/572))\n  ([80816c9](https://github.com/amplitude/Amplitude-TypeScript/commit/80816c92b64d3e839688c7654c08c1503501e2ed))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.2.1...@amplitude/analytics-browser@2.2.2) (2023-08-29)\n\n### Bug Fixes\n\n- allow DET warning to be suppressed ([#569](https://github.com/amplitude/Amplitude-TypeScript/issues/569))\n  ([b9d232c](https://github.com/amplitude/Amplitude-TypeScript/commit/b9d232c4c5c37d0e53b9097ed4415c0e917c518e))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.2.0...@amplitude/analytics-browser@2.2.1) (2023-08-24)\n\n### Bug Fixes\n\n- **browser:** allow cookie options to be customized\n  [#548](https://github.com/amplitude/Amplitude-TypeScript/issues/548)\n  ([#552](https://github.com/amplitude/Amplitude-TypeScript/issues/552))\n  ([5c483f4](https://github.com/amplitude/Amplitude-TypeScript/commit/5c483f4aeefe19b4d6e09c03a39b54113205fa96))\n- fix web attribution behavior for no referrer in the same session\n  ([#554](https://github.com/amplitude/Amplitude-TypeScript/issues/554))\n  ([ed54eb2](https://github.com/amplitude/Amplitude-TypeScript/commit/ed54eb28810a3edb3326f82bdd7aed901ec9452f))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.2.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.1.3...@amplitude/analytics-browser@2.2.0) (2023-08-15)\n\n### Features\n\n- limit LocalStorage ([#528](https://github.com/amplitude/Amplitude-TypeScript/issues/528))\n  ([232a607](https://github.com/amplitude/Amplitude-TypeScript/commit/232a607108baba4427723352212c650e09ee01a6))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.1.2...@amplitude/analytics-browser@2.1.3) (2023-07-27)\n\n### Bug Fixes\n\n- get trackingOptions from config ([#505](https://github.com/amplitude/Amplitude-TypeScript/issues/505))\n  ([602d8ed](https://github.com/amplitude/Amplitude-TypeScript/commit/602d8edbe8c6f76d9f2b3480bf9081e5ea9fb9a5))\n- should use trackingOptions ([#508](https://github.com/amplitude/Amplitude-TypeScript/issues/508))\n  ([596e3b6](https://github.com/amplitude/Amplitude-TypeScript/commit/596e3b6328af4673d45c895b14f6472a3e4e42ed))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.1.1...@amplitude/analytics-browser@2.1.2) (2023-07-03)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.1.0...@amplitude/analytics-browser@2.1.1) (2023-06-30)\n\n### Bug Fixes\n\n- allow plugins to teardown to remove listeners ([#460](https://github.com/amplitude/Amplitude-TypeScript/issues/460))\n  ([c337363](https://github.com/amplitude/Amplitude-TypeScript/commit/c337363c25b0a1285e8df455511516fc0a9bec7e))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.1.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.0.1...@amplitude/analytics-browser@2.1.0) (2023-06-22)\n\n### Features\n\n- **storage:** add support for sessionStorage as identityStorage\n  ([#435](https://github.com/amplitude/Amplitude-TypeScript/issues/435))\n  ([8596f6a](https://github.com/amplitude/Amplitude-TypeScript/commit/8596f6a340a32b08a3f55a337723c39c6c57cbf1)), closes\n  [#434](https://github.com/amplitude/Amplitude-TypeScript/issues/434)\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.0.0...@amplitude/analytics-browser@2.0.1) (2023-06-21)\n\n### Bug Fixes\n\n- adds logs when default tracking is enabled ([#436](https://github.com/amplitude/Amplitude-TypeScript/issues/436))\n  ([ff32f91](https://github.com/amplitude/Amplitude-TypeScript/commit/ff32f9112bab9380c24abdf897e04aa3e540f341))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.0.0-beta.10...@amplitude/analytics-browser@2.0.0) (2023-06-14)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.0.0-beta.9...@amplitude/analytics-browser@2.0.0-beta.10) (2023-06-14)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.0.0-beta.8...@amplitude/analytics-browser@2.0.0-beta.9) (2023-06-14)\n\n### Bug Fixes\n\n- extend session on new events ([#432](https://github.com/amplitude/Amplitude-TypeScript/issues/432))\n  ([8bb049d](https://github.com/amplitude/Amplitude-TypeScript/commit/8bb049df4c6b99ff44303cf2aaeb7357ae90b362))\n\n### Features\n\n- added extendSession() method to Browser Client ([#425](https://github.com/amplitude/Amplitude-TypeScript/issues/425))\n  ([#433](https://github.com/amplitude/Amplitude-TypeScript/issues/433))\n  ([0f5fccc](https://github.com/amplitude/Amplitude-TypeScript/commit/0f5fccc83d3f7f0a80adc4a0807fbd7e71c72e4a))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.0.0-beta.7...@amplitude/analytics-browser@2.0.0-beta.8) (2023-06-13)\n\n### Features\n\n- add option for instance name ([#428](https://github.com/amplitude/Amplitude-TypeScript/issues/428))\n  ([1a8ff7d](https://github.com/amplitude/Amplitude-TypeScript/commit/1a8ff7d665d2a936db7cb42f4cde5350379b7cae))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.0.0-beta.6...@amplitude/analytics-browser@2.0.0-beta.7) (2023-06-13)\n\n### Bug Fixes\n\n- don't automatically start new session on setUserId\n  ([#427](https://github.com/amplitude/Amplitude-TypeScript/issues/427))\n  ([d40b5c3](https://github.com/amplitude/Amplitude-TypeScript/commit/d40b5c305e1d67d988e70608ba01789b8f0abb2b))\n- sest sion end events being assigned to a different session id\n  ([#426](https://github.com/amplitude/Amplitude-TypeScript/issues/426))\n  ([7d52037](https://github.com/amplitude/Amplitude-TypeScript/commit/7d52037280159ddb176e5e1ef64577bd97edfc36))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.0.0-beta.5...@amplitude/analytics-browser@2.0.0-beta.6) (2023-06-09)\n\n### Bug Fixes\n\n- set cookie expiration from options ([#423](https://github.com/amplitude/Amplitude-TypeScript/issues/423))\n  ([69e8e70](https://github.com/amplitude/Amplitude-TypeScript/commit/69e8e700b929b02eb1792f1a4f6b8e6eb306cd7f))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.0.0-beta.4...@amplitude/analytics-browser@2.0.0-beta.5) (2023-06-08)\n\n### Features\n\n- simplify init interface ([#416](https://github.com/amplitude/Amplitude-TypeScript/issues/416))\n  ([93752da](https://github.com/amplitude/Amplitude-TypeScript/commit/93752da1e6ed521263c6d5295a37fc5dc7f3de86))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.0.0-beta.3...@amplitude/analytics-browser@2.0.0-beta.4) (2023-06-07)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.0.0-beta.2...@amplitude/analytics-browser@2.0.0-beta.3) (2023-06-07)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@2.0.0-beta.1...@amplitude/analytics-browser@2.0.0-beta.2) (2023-06-06)\n\n### Bug Fixes\n\n- simplify plugins and eliminate enums ([#407](https://github.com/amplitude/Amplitude-TypeScript/issues/407))\n  ([890ec66](https://github.com/amplitude/Amplitude-TypeScript/commit/890ec6695a8b25cd6988e9f7ae584d4ba2835f67))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.10.5...@amplitude/analytics-browser@2.0.0-beta.1) (2023-06-06)\n\n### Features\n\n- allow cross subdomain excluded referrer ([#391](https://github.com/amplitude/Amplitude-TypeScript/issues/391))\n  ([f34f64b](https://github.com/amplitude/Amplitude-TypeScript/commit/f34f64b68bbd328da354afae61ca416d7055a734))\n- make default event tracking enabled by default ([#386](https://github.com/amplitude/Amplitude-TypeScript/issues/386))\n  ([242f42d](https://github.com/amplitude/Amplitude-TypeScript/commit/242f42dd2e46eaec95c827795e04f74fba39c35f))\n- simplify browser SDK options and plugin options interface\n  ([#384](https://github.com/amplitude/Amplitude-TypeScript/issues/384))\n  ([b464cfb](https://github.com/amplitude/Amplitude-TypeScript/commit/b464cfb8e09d722bf06ed3c11955f77465a23daf))\n- simplify user identity storage options/configuration\n  ([#390](https://github.com/amplitude/Amplitude-TypeScript/issues/390))\n  ([f8cf0cc](https://github.com/amplitude/Amplitude-TypeScript/commit/f8cf0cca8c2a17738f13878642fa5b37c0070f77))\n- use server side user agent parser ([#382](https://github.com/amplitude/Amplitude-TypeScript/issues/382))\n  ([69bd255](https://github.com/amplitude/Amplitude-TypeScript/commit/69bd2558cb37d027064b6459cc2887c219196973))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.10.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.10.4...@amplitude/analytics-browser@1.10.5) (2023-06-05)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.10.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.10.3...@amplitude/analytics-browser@1.10.4) (2023-06-02)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.10.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.10.2...@amplitude/analytics-browser@1.10.3) (2023-05-04)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.10.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.10.1...@amplitude/analytics-browser@1.10.2) (2023-04-27)\n\n### Bug Fixes\n\n- add connector event listener after plugins and queued functions\n  ([#378](https://github.com/amplitude/Amplitude-TypeScript/issues/378))\n  ([a2fc8b6](https://github.com/amplitude/Amplitude-TypeScript/commit/a2fc8b6a7ec87dd8eab6538c1e9929c57804b899))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.10.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.10.0...@amplitude/analytics-browser@1.10.1) (2023-04-27)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.10.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.9.4...@amplitude/analytics-browser@1.10.0) (2023-04-25)\n\n### Features\n\n- persist last event id - to be used on next initialization\n  ([#374](https://github.com/amplitude/Amplitude-TypeScript/issues/374))\n  ([4fd7691](https://github.com/amplitude/Amplitude-TypeScript/commit/4fd76911142969bbc76d6d6e2cb986331201af37))\n- send user_agent with events ([#375](https://github.com/amplitude/Amplitude-TypeScript/issues/375))\n  ([26086b5](https://github.com/amplitude/Amplitude-TypeScript/commit/26086b543d7f0ee2d35e09b43199b5c26ed24e36))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.9.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.9.3...@amplitude/analytics-browser@1.9.4) (2023-04-06)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.9.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.9.2...@amplitude/analytics-browser@1.9.3) (2023-03-31)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.9.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.9.2-beta.0...@amplitude/analytics-browser@1.9.2) (2023-03-31)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.9.2-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.9.1...@amplitude/analytics-browser@1.9.2-beta.0) (2023-03-31)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.9.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.9.1-beta.1...@amplitude/analytics-browser@1.9.1) (2023-03-03)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.9.1-beta.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.9.1-beta.0...@amplitude/analytics-browser@1.9.1-beta.1) (2023-03-03)\n\n### Bug Fixes\n\n- event types and properties for default events ([#341](https://github.com/amplitude/Amplitude-TypeScript/issues/341))\n  ([707522d](https://github.com/amplitude/Amplitude-TypeScript/commit/707522d440d5aa3be48809afcb44a4147f103903))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.9.1-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.9.0...@amplitude/analytics-browser@1.9.1-beta.0) (2023-03-03)\n\n### Bug Fixes\n\n- push user id and device id changes to analytics connector\n  ([#342](https://github.com/amplitude/Amplitude-TypeScript/issues/342))\n  ([3214b08](https://github.com/amplitude/Amplitude-TypeScript/commit/3214b0836eb03e39b5753b1e6be30e1c2f5770ca))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.9.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.9.0-beta.4...@amplitude/analytics-browser@1.9.0) (2023-02-27)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.9.0-beta.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.9.0-beta.3...@amplitude/analytics-browser@1.9.0-beta.4) (2023-02-27)\n\n### Bug Fixes\n\n- attach listener to nested nodes ([#339](https://github.com/amplitude/Amplitude-TypeScript/issues/339))\n  ([f6d19c4](https://github.com/amplitude/Amplitude-TypeScript/commit/f6d19c4ef72d44fac6072e677d4de87fd198e5dd))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.9.0-beta.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.9.0-beta.2...@amplitude/analytics-browser@1.9.0-beta.3) (2023-02-26)\n\n### Bug Fixes\n\n- improve error handling for file download tracking\n  ([#338](https://github.com/amplitude/Amplitude-TypeScript/issues/338))\n  ([46cf131](https://github.com/amplitude/Amplitude-TypeScript/commit/46cf131945539ec634a74b257088bf7fe67e2181))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.9.0-beta.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.9.0-beta.1...@amplitude/analytics-browser@1.9.0-beta.2) (2023-02-25)\n\n### Bug Fixes\n\n- inconsistent user and device id on session events\n  ([#337](https://github.com/amplitude/Amplitude-TypeScript/issues/337))\n  ([0dfbc6c](https://github.com/amplitude/Amplitude-TypeScript/commit/0dfbc6c78335a7578fc0207d91c1ef9845950f16))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.9.0-beta.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.9.0-beta.0...@amplitude/analytics-browser@1.9.0-beta.1) (2023-02-24)\n\n### Bug Fixes\n\n- improper cookie usage ([#330](https://github.com/amplitude/Amplitude-TypeScript/issues/330))\n  ([e670091](https://github.com/amplitude/Amplitude-TypeScript/commit/e670091e59014bb35bd9b3ec2a7192f259393575))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.9.0-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.8.0...@amplitude/analytics-browser@1.9.0-beta.0) (2023-02-24)\n\n### Bug Fixes\n\n- consolidate web attribution and page view tracking plugins for marketing analytics use case\n  ([c268997](https://github.com/amplitude/Amplitude-TypeScript/commit/c26899787611daeda7fca288e260bbc42a831130))\n- update event types of default events\n  ([5bd7887](https://github.com/amplitude/Amplitude-TypeScript/commit/5bd7887abce9cc893a624747108d5df35aa23da4))\n\n### Features\n\n- add form interaction and file download plugins\n  ([22b10f1](https://github.com/amplitude/Amplitude-TypeScript/commit/22b10f1dada8ab264f9bd74a4065c06e9aec4334))\n- add session start/end event tracker ([#332](https://github.com/amplitude/Amplitude-TypeScript/issues/332))\n  ([e26cf15](https://github.com/amplitude/Amplitude-TypeScript/commit/e26cf15503c59d3b25bd54391bb330a8c634eca3))\n- allow custom page view event type ([#335](https://github.com/amplitude/Amplitude-TypeScript/issues/335))\n  ([0a4f8ed](https://github.com/amplitude/Amplitude-TypeScript/commit/0a4f8ede6e30ec3450ac0a468cf22b9266b0b23c))\n- pass amplitude instance to plugin.setup for enhanced plugin capabilities\n  ([#328](https://github.com/amplitude/Amplitude-TypeScript/issues/328))\n  ([91eeaa0](https://github.com/amplitude/Amplitude-TypeScript/commit/91eeaa0d6bff6bde39538bb54548a938df784462))\n- retrofit web attribution and page view plugins to browser SDK\n  ([#331](https://github.com/amplitude/Amplitude-TypeScript/issues/331))\n  ([ba845d3](https://github.com/amplitude/Amplitude-TypeScript/commit/ba845d3329bd6bebe3b89f24f4f316088c2d62b9))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.8.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.7.1...@amplitude/analytics-browser@1.8.0) (2023-02-09)\n\n### Features\n\n- add file download tracker plugin ([#322](https://github.com/amplitude/Amplitude-TypeScript/issues/322))\n  ([1604409](https://github.com/amplitude/Amplitude-TypeScript/commit/16044091135b0983f2edb3931ddf5d2c213be3fc))\n- add form interaction event tracker plugin ([#323](https://github.com/amplitude/Amplitude-TypeScript/issues/323))\n  ([f6ee918](https://github.com/amplitude/Amplitude-TypeScript/commit/f6ee918a22138f6be260580a5b48ecff60ff950f))\n- add named instances for google tag manager use case\n  ([#326](https://github.com/amplitude/Amplitude-TypeScript/issues/326))\n  ([327ef9a](https://github.com/amplitude/Amplitude-TypeScript/commit/327ef9a3d097f892e41814cb02b90453e2d39ed5))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.7.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.7.0...@amplitude/analytics-browser@1.7.1) (2023-02-02)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.7.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.7.0-beta.0...@amplitude/analytics-browser@1.7.0) (2023-01-31)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.7.0-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.6.8...@amplitude/analytics-browser@1.7.0-beta.0) (2023-01-26)\n\n### Features\n\n- allow opt out of deleting legacy sdk cookies\n  ([c6a82fb](https://github.com/amplitude/Amplitude-TypeScript/commit/c6a82fb52e1301e427116891d1f31208bcfc6548))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.6.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.6.7...@amplitude/analytics-browser@1.6.8) (2023-01-11)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.6.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.6.6...@amplitude/analytics-browser@1.6.7) (2022-12-21)\n\n### Bug Fixes\n\n- upgrade dependencies to resolve dependabot vulnerability alerts\n  ([#299](https://github.com/amplitude/Amplitude-TypeScript/issues/299))\n  ([7dd1cd1](https://github.com/amplitude/Amplitude-TypeScript/commit/7dd1cd1b23a71981a4ad90b4b30cc9b7d28c4412))\n\n### Reverts\n\n- Revert \"Updated dependencies\"\n  ([7ca9964](https://github.com/amplitude/Amplitude-TypeScript/commit/7ca9964781e4b900c6c027bdddf2ae1e7428ba18))\n\n## [1.6.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.6.5...@amplitude/analytics-browser@1.6.6) (2022-12-06)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n## [1.6.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.6.4...@amplitude/analytics-browser@1.6.5) (2022-12-05)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n## [1.6.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.6.3...@amplitude/analytics-browser@1.6.4) (2022-11-28)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n## [1.6.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.6.2...@amplitude/analytics-browser@1.6.3) (2022-11-22)\n\n### Bug Fixes\n\n- removed es6 syntax to support GTM usage ([#282](https://github.com/amplitude/Amplitude-TypeScript/issues/282))\n  ([29f885a](https://github.com/amplitude/Amplitude-TypeScript/commit/29f885ae2258949124c1a450354525c2cc5316cf))\n\n## [1.6.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.6.1...@amplitude/analytics-browser@1.6.2) (2022-11-15)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n## [1.6.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.6.0...@amplitude/analytics-browser@1.6.1) (2022-11-01)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# [1.6.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.5.8...@amplitude/analytics-browser@1.6.0) (2022-11-01)\n\n### Features\n\n- enhance logger with debug information ([#254](https://github.com/amplitude/Amplitude-TypeScript/issues/254))\n  ([5c6175e](https://github.com/amplitude/Amplitude-TypeScript/commit/5c6175e9372cbeea264ddb34c6cc68148063d4f7))\n\n## [1.5.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.5.7...@amplitude/analytics-browser@1.5.8) (2022-10-26)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n## [1.5.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.5.7-beta.1...@amplitude/analytics-browser@1.5.7) (2022-10-25)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n## [1.5.7-beta.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.5.7-beta.0...@amplitude/analytics-browser@1.5.7-beta.1) (2022-10-25)\n\n### Reverts\n\n- add logging around cookie storage ([#256](https://github.com/amplitude/Amplitude-TypeScript/issues/256))\n  ([12016e7](https://github.com/amplitude/Amplitude-TypeScript/commit/12016e7eddb7bec885883c0ebf1619fc447beb87))\n\n## [1.5.7-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.5.6...@amplitude/analytics-browser@1.5.7-beta.0) (2022-10-25)\n\n### Bug Fixes\n\n- add logging around cookie storage ([#255](https://github.com/amplitude/Amplitude-TypeScript/issues/255))\n  ([dee9d32](https://github.com/amplitude/Amplitude-TypeScript/commit/dee9d3299b90b71576a8c435c26a03c1dcabdae4))\n\n## [1.5.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.5.5...@amplitude/analytics-browser@1.5.6) (2022-10-25)\n\n### Bug Fixes\n\n- add safe check for global scope before loading SDK\n  ([#252](https://github.com/amplitude/Amplitude-TypeScript/issues/252))\n  ([a3f4f6f](https://github.com/amplitude/Amplitude-TypeScript/commit/a3f4f6f7b11abd9cdbdf064e31e32d5fc3e92031))\n- invoke pre-init track fns after attribution ([#253](https://github.com/amplitude/Amplitude-TypeScript/issues/253))\n  ([b8996d7](https://github.com/amplitude/Amplitude-TypeScript/commit/b8996d793f74d388c1a96e0cde5c0ac060c1e565))\n\n## [1.5.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.5.4...@amplitude/analytics-browser@1.5.5) (2022-10-14)\n\n### Bug Fixes\n\n- globalThis polyfill ([#250](https://github.com/amplitude/Amplitude-TypeScript/issues/250))\n  ([c52f263](https://github.com/amplitude/Amplitude-TypeScript/commit/c52f2631f7a1884a7bac89538407681f6224a27e))\n- run queued functions after attribution in browser-client.ts\n  ([#249](https://github.com/amplitude/Amplitude-TypeScript/issues/249))\n  ([751b7ca](https://github.com/amplitude/Amplitude-TypeScript/commit/751b7ca6b0f05131dc932b89dd89e8979e334b4b))\n- update userId/deviceId in identify call if eventOptions contains userId/deviceId\n  ([#244](https://github.com/amplitude/Amplitude-TypeScript/issues/244))\n  ([578cbe2](https://github.com/amplitude/Amplitude-TypeScript/commit/578cbe218de84d7fdd4930f75820beda6f85ce6d))\n\n## [1.5.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.5.3...@amplitude/analytics-browser@1.5.4) (2022-10-04)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n## [1.5.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.5.2...@amplitude/analytics-browser@1.5.3) (2022-09-30)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n## [1.5.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.5.1...@amplitude/analytics-browser@1.5.2) (2022-09-30)\n\n### Bug Fixes\n\n- cover the case when apiKey is missing in the runtime\n  ([#240](https://github.com/amplitude/Amplitude-TypeScript/issues/240))\n  ([308bbe8](https://github.com/amplitude/Amplitude-TypeScript/commit/308bbe8337cbab366a0ca255f2d665101f4781a0))\n\n## [1.5.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.5.1-beta.1...@amplitude/analytics-browser@1.5.1) (2022-09-28)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n## [1.5.1-beta.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.5.1-beta.0...@amplitude/analytics-browser@1.5.1-beta.1) (2022-09-27)\n\n### Bug Fixes\n\n- define correct dependencies for @amplitude/analytics-connector\n  ([#234](https://github.com/amplitude/Amplitude-TypeScript/issues/234))\n  ([41c1351](https://github.com/amplitude/Amplitude-TypeScript/commit/41c1351e441b890b016ba123c4ed5747a4c33adb))\n\n## [1.5.1-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.5.0...@amplitude/analytics-browser@1.5.1-beta.0) (2022-09-26)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# [1.5.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.4.1...@amplitude/analytics-browser@1.5.0) (2022-09-26)\n\n### Features\n\n- add analytics-marketing-analytics-browser package\n  ([#215](https://github.com/amplitude/Amplitude-TypeScript/issues/215))\n  ([8ce4f52](https://github.com/amplitude/Amplitude-TypeScript/commit/8ce4f5288868c7f63fd08be82510b4ed9029381a))\n\n## [1.4.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.4.0...@amplitude/analytics-browser@1.4.1) (2022-09-22)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# [1.4.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.3.0...@amplitude/analytics-browser@1.4.0) (2022-09-16)\n\n### Features\n\n- new marketing analytics plugin ([#213](https://github.com/amplitude/Amplitude-TypeScript/issues/213))\n  ([02ff174](https://github.com/amplitude/Amplitude-TypeScript/commit/02ff174e3361173dbf15ed3acf72e950810e174f))\n\n# [1.3.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.2.3...@amplitude/analytics-browser@1.3.0) (2022-09-08)\n\n### Features\n\n- add ingestion_metadata field ([#212](https://github.com/amplitude/Amplitude-TypeScript/issues/212))\n  ([ebe8448](https://github.com/amplitude/Amplitude-TypeScript/commit/ebe8448b23609134f846e18da2e769158ca30bf1))\n\n## [1.2.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.2.2...@amplitude/analytics-browser@1.2.3) (2022-08-31)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n## [1.2.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.2.1...@amplitude/analytics-browser@1.2.2) (2022-08-29)\n\n### Bug Fixes\n\n- add conditional check for window.location.search\n  ([#198](https://github.com/amplitude/Amplitude-TypeScript/issues/198))\n  ([e61b4db](https://github.com/amplitude/Amplitude-TypeScript/commit/e61b4db25e2e7677a3dcb2c8e71f26bcac9a9fd5))\n\n## [1.2.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.2.0...@amplitude/analytics-browser@1.2.1) (2022-08-23)\n\n### Bug Fixes\n\n- pass options to testStorage ([#201](https://github.com/amplitude/Amplitude-TypeScript/issues/201))\n  ([6e22eb0](https://github.com/amplitude/Amplitude-TypeScript/commit/6e22eb0c101c743b15bb49d9491082fd1fe1d90e))\n\n# [1.2.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.1.5...@amplitude/analytics-browser@1.2.0) (2022-08-18)\n\n### Bug Fixes\n\n- handle parsing malformed urls for web attribution\n  ([#192](https://github.com/amplitude/Amplitude-TypeScript/issues/192))\n  ([cd254d6](https://github.com/amplitude/Amplitude-TypeScript/commit/cd254d6319d8bc7d92affc263ec12c9c39f82fb2))\n- prevent concurrent init calls ([#191](https://github.com/amplitude/Amplitude-TypeScript/issues/191))\n  ([efda076](https://github.com/amplitude/Amplitude-TypeScript/commit/efda0760f4f1e92e47a3150985e18efcc3b108d9))\n- removes unused tracking options ([#193](https://github.com/amplitude/Amplitude-TypeScript/issues/193))\n  ([2b57a8e](https://github.com/amplitude/Amplitude-TypeScript/commit/2b57a8e07971312b40c8287e2daddcfb2b55a832))\n\n### Features\n\n- adds create instance api ([#188](https://github.com/amplitude/Amplitude-TypeScript/issues/188))\n  ([050c1d9](https://github.com/amplitude/Amplitude-TypeScript/commit/050c1d96cedbc9e68aedf6fd55e85d2d3dc2fee4))\n\n## [1.1.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.1.4...@amplitude/analytics-browser@1.1.5) (2022-08-16)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n## [1.1.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.1.3...@amplitude/analytics-browser@1.1.4) (2022-08-13)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n## [1.1.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.1.2...@amplitude/analytics-browser@1.1.3) (2022-08-12)\n\n### Bug Fixes\n\n- add callable queue when init is pending ([#181](https://github.com/amplitude/Amplitude-TypeScript/issues/181))\n  ([d8fc361](https://github.com/amplitude/Amplitude-TypeScript/commit/d8fc36195b96e2c10ccc5106027beaa7e970e0c0))\n\n## [1.1.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.1.1...@amplitude/analytics-browser@1.1.2) (2022-08-02)\n\n### Bug Fixes\n\n- implement integration with experiment sdk for browser\n  ([#156](https://github.com/amplitude/Amplitude-TypeScript/issues/156))\n  ([075ba84](https://github.com/amplitude/Amplitude-TypeScript/commit/075ba84bb4d05fb6a256272d19c03cb692cb0c28))\n\n## [1.1.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.1.0...@amplitude/analytics-browser@1.1.1) (2022-07-30)\n\n### Bug Fixes\n\n- fixes auto gen of snippet instructions ([#160](https://github.com/amplitude/Amplitude-TypeScript/issues/160))\n  ([bbdf284](https://github.com/amplitude/Amplitude-TypeScript/commit/bbdf2840665f58507391ccdd9ca1398676bab194))\n\n# [1.1.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.0.3...@amplitude/analytics-browser@1.1.0) (2022-07-29)\n\n### Features\n\n- add reset method for resetting userId and deviceId\n  ([#157](https://github.com/amplitude/Amplitude-TypeScript/issues/157))\n  ([8bfc864](https://github.com/amplitude/Amplitude-TypeScript/commit/8bfc864b15dd7e427556a50bc3de6b43b2485189))\n\n## [1.0.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.0.2...@amplitude/analytics-browser@1.0.3) (2022-07-22)\n\n### Bug Fixes\n\n- missing tracked events before init issue ([#144](https://github.com/amplitude/Amplitude-TypeScript/issues/144))\n  ([60d0f68](https://github.com/amplitude/Amplitude-TypeScript/commit/60d0f6848087f7b8fc3c870d55489a238e841b26))\n- removes saveEvents config ([#147](https://github.com/amplitude/Amplitude-TypeScript/issues/147))\n  ([6fde736](https://github.com/amplitude/Amplitude-TypeScript/commit/6fde736ca8a865462522082a8085673756dbcc7d))\n- update default flush config for node ([#152](https://github.com/amplitude/Amplitude-TypeScript/issues/152))\n  ([2445dff](https://github.com/amplitude/Amplitude-TypeScript/commit/2445dff0842e7e0a2b7ee767ab926b5a93348214))\n\n## [1.0.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.0.1...@amplitude/analytics-browser@1.0.2) (2022-07-15)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n## [1.0.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@1.0.0...@amplitude/analytics-browser@1.0.1) (2022-07-13)\n\n### Bug Fixes\n\n- added flush to snippet template ([#131](https://github.com/amplitude/Amplitude-TypeScript/issues/131))\n  ([97cf2b9](https://github.com/amplitude/Amplitude-TypeScript/commit/97cf2b90e852f4e2e72df8e2ba6b05f5583ac35a))\n\n# [1.0.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@0.7.1...@amplitude/analytics-browser@1.0.0) (2022-06-29)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n## [0.7.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@0.7.0...@amplitude/analytics-browser@0.7.1) (2022-06-29)\n\n### Bug Fixes\n\n- encode cookies and set top level domain ([#130](https://github.com/amplitude/Amplitude-TypeScript/issues/130))\n  ([0276dc4](https://github.com/amplitude/Amplitude-TypeScript/commit/0276dc4b3a24f96612cac94d742e7382ceed32bf))\n- remove Awaited type to support older versions of typescript\n  ([#121](https://github.com/amplitude/Amplitude-TypeScript/issues/121))\n  ([23d36f8](https://github.com/amplitude/Amplitude-TypeScript/commit/23d36f8aade258b995132dafd725ada00e400916))\n\n# [0.7.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@0.6.1...@amplitude/analytics-browser@0.7.0) (2022-06-29)\n\n### Features\n\n- add flush() api to send all events immediately ([#125](https://github.com/amplitude/Amplitude-TypeScript/issues/125))\n  ([b5dbcbb](https://github.com/amplitude/Amplitude-TypeScript/commit/b5dbcbb803c76ee5ade7ea85f76fbea50d8bab49))\n- make storage interface async to enable react-native\n  ([#122](https://github.com/amplitude/Amplitude-TypeScript/issues/122))\n  ([42bb39c](https://github.com/amplitude/Amplitude-TypeScript/commit/42bb39c967db015d5899487618d066f3540c9f18))\n\n## [0.6.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@0.6.0...@amplitude/analytics-browser@0.6.1) (2022-06-24)\n\n### Bug Fixes\n\n- opt in auto page tracking ([#123](https://github.com/amplitude/Amplitude-TypeScript/issues/123))\n  ([6db195b](https://github.com/amplitude/Amplitude-TypeScript/commit/6db195b7e46b1db48ff6c237a57a4503ae4c056e))\n\n# [0.6.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@0.5.1...@amplitude/analytics-browser@0.6.0) (2022-06-24)\n\n### Features\n\n- add marketing campaign tracking ([#112](https://github.com/amplitude/Amplitude-TypeScript/issues/112))\n  ([bca73ed](https://github.com/amplitude/Amplitude-TypeScript/commit/bca73ede308ecb1663986a99600657732969d60c))\n\n## [0.5.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@0.5.0...@amplitude/analytics-browser@0.5.1) (2022-06-21)\n\n### Bug Fixes\n\n- remove userId and deviceId from createIdentifyEvent and createGroupIdentifyEvent\n  ([#119](https://github.com/amplitude/Amplitude-TypeScript/issues/119))\n  ([e7726bb](https://github.com/amplitude/Amplitude-TypeScript/commit/e7726bb9ba16c390638b51042169ede9e083e331))\n\n# [0.5.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@0.4.1...@amplitude/analytics-browser@0.5.0) (2022-06-17)\n\n### Bug Fixes\n\n- allow setting undefined user id via setUserId() ([#116](https://github.com/amplitude/Amplitude-TypeScript/issues/116))\n  ([46f63b5](https://github.com/amplitude/Amplitude-TypeScript/commit/46f63b549fda76fb84cddb8fb26c5671bba7df82))\n- upgrade to @amplitude/ua-parser-js@0.7.31 ([#108](https://github.com/amplitude/Amplitude-TypeScript/issues/108))\n  ([91ab888](https://github.com/amplitude/Amplitude-TypeScript/commit/91ab888dcf55eb8b8e4cc65ff28493ad84fad350))\n\n### Features\n\n- add Plan option to config ([#117](https://github.com/amplitude/Amplitude-TypeScript/issues/117))\n  ([194d7e6](https://github.com/amplitude/Amplitude-TypeScript/commit/194d7e66af0209cb8155cf6aa0b05a5dcb170f9d))\n- add regenerateDeviceId method ([#111](https://github.com/amplitude/Amplitude-TypeScript/issues/111))\n  ([8980233](https://github.com/amplitude/Amplitude-TypeScript/commit/89802339bedaf682845271c1c1edca68e37eb5ec))\n- introduce NodeJS package ([#92](https://github.com/amplitude/Amplitude-TypeScript/issues/92))\n  ([476fb44](https://github.com/amplitude/Amplitude-TypeScript/commit/476fb44efcf2dfcd84af6f0ef45e141ad87dac43))\n\n## [0.4.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@0.4.0...@amplitude/analytics-browser@0.4.1) (2022-05-17)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# [0.4.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@0.3.1...@amplitude/analytics-browser@0.4.0) (2022-05-12)\n\n### Bug Fixes\n\n- cookie expires prematurely due to incorrectly used option\n  ([#91](https://github.com/amplitude/Amplitude-TypeScript/issues/91))\n  ([d6cbf49](https://github.com/amplitude/Amplitude-TypeScript/commit/d6cbf49ac044f32c8bd784079179bd76fa36b403))\n\n### Features\n\n- parse old cookies and convert to new format ([#85](https://github.com/amplitude/Amplitude-TypeScript/issues/85))\n  ([bda78be](https://github.com/amplitude/Amplitude-TypeScript/commit/bda78be5d2de335e7b1ff6da413b20d3dc751aca))\n\n## [0.3.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@0.3.0...@amplitude/analytics-browser@0.3.1) (2022-04-09)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# [0.3.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@0.2.4...@amplitude/analytics-browser@0.3.0) (2022-04-09)\n\n### Bug Fixes\n\n- fix error handling in fetch client ([#79](https://github.com/amplitude/Amplitude-TypeScript/issues/79))\n  ([749925f](https://github.com/amplitude/Amplitude-TypeScript/commit/749925f907ba72f0e67f3828da99151d00278e6b))\n\n### Features\n\n- minify snippet file and add script to update readme for minified snippet\n  ([#77](https://github.com/amplitude/Amplitude-TypeScript/issues/77))\n  ([9917e44](https://github.com/amplitude/Amplitude-TypeScript/commit/9917e44738a62251abea328c83d98922450387ca))\n\n## [0.2.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@0.2.3...@amplitude/analytics-browser@0.2.4) (2022-04-06)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n## [0.2.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@0.2.2...@amplitude/analytics-browser@0.2.3) (2022-04-02)\n\n### Bug Fixes\n\n- move types to analytics-types ([#70](https://github.com/amplitude/Amplitude-TypeScript/issues/70))\n  ([0cb4155](https://github.com/amplitude/Amplitude-TypeScript/commit/0cb41556f2f6be41a7b4838d33ce517289d4d880))\n\n## [0.2.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@0.2.1...@amplitude/analytics-browser@0.2.2) (2022-04-01)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n## [0.2.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@0.2.0...@amplitude/analytics-browser@0.2.1) (2022-04-01)\n\n**Note:** Version bump only for package @amplitude/analytics-browser\n\n# [0.2.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@0.1.1...@amplitude/analytics-browser@0.2.0) (2022-04-01)\n\n### Bug Fixes\n\n- context plugin library version\n  ([8d29c6f](https://github.com/amplitude/Amplitude-TypeScript/commit/8d29c6f4a612510188d920ac243c0bdb116fe02c))\n\n### Features\n\n- add snippet promise support ([#64](https://github.com/amplitude/Amplitude-TypeScript/issues/64))\n  ([4d23c98](https://github.com/amplitude/Amplitude-TypeScript/commit/4d23c98c25c7caa4cd5e63b2a37398f711991288))\n\n## [0.1.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser@0.1.0...@amplitude/analytics-browser@0.1.1) (2022-03-31)\n\n### Bug Fixes\n\n- add missing dependency\n  ([6283f64](https://github.com/amplitude/Amplitude-TypeScript/commit/6283f64dc40b070d68a0243a93ab58d95d436664))\n- move src/version update to npm prepare\n  ([2101ab9](https://github.com/amplitude/Amplitude-TypeScript/commit/2101ab92ee874dd1536071c65318dd9c6fac123f))\n\n# 0.1.0 (2022-03-31)\n\n### Bug Fixes\n\n- address issues with usage in service worker and server-side rendering\n  ([#46](https://github.com/amplitude/Amplitude-TypeScript/issues/46))\n  ([28131b8](https://github.com/amplitude/Amplitude-TypeScript/commit/28131b85a0d86bfb8276993d8152f815d2a3d74d))\n- couple plugins with config instance ([#43](https://github.com/amplitude/Amplitude-TypeScript/issues/43))\n  ([abf687a](https://github.com/amplitude/Amplitude-TypeScript/commit/abf687a5d7a395638d8154f65ececc9b5464c366))\n- deserialize json stored in cookies and local storage\n  ([#11](https://github.com/amplitude/Amplitude-TypeScript/issues/11))\n  ([e4346f7](https://github.com/amplitude/Amplitude-TypeScript/commit/e4346f73e020f59ea8fce1af968b7aedd4a73ba0))\n- snippet install script and public interface ([#57](https://github.com/amplitude/Amplitude-TypeScript/issues/57))\n  ([93f5b89](https://github.com/amplitude/Amplitude-TypeScript/commit/93f5b89c40d49e81f61daf66cea5627b768f58b5))\n- update cookies last event time ([#54](https://github.com/amplitude/Amplitude-TypeScript/issues/54))\n  ([73a26ca](https://github.com/amplitude/Amplitude-TypeScript/commit/73a26ca87c0b8ae3be0b58d1789bf874cb0cf814))\n- update event results callback parameter ([#29](https://github.com/amplitude/Amplitude-TypeScript/issues/29))\n  ([1acd3c0](https://github.com/amplitude/Amplitude-TypeScript/commit/1acd3c02310e5e9a2b7ab19140f7d6249e9a8452))\n- update logger config to logger provider ([#19](https://github.com/amplitude/Amplitude-TypeScript/issues/19))\n  ([ef89d9f](https://github.com/amplitude/Amplitude-TypeScript/commit/ef89d9f5ffdc9dd88c3652ac36705c79741f53d1))\n- update tracking options for browser client ([#23](https://github.com/amplitude/Amplitude-TypeScript/issues/23))\n  ([acb9960](https://github.com/amplitude/Amplitude-TypeScript/commit/acb99608012d6c885d94971fdd855526356edc6c))\n- updates library event field in context plugin ([#28](https://github.com/amplitude/Amplitude-TypeScript/issues/28))\n  ([4821675](https://github.com/amplitude/Amplitude-TypeScript/commit/48216752f2105b6f2f71114913c5d9e19d192c7c))\n- use config reference as plugin instance property ([#21](https://github.com/amplitude/Amplitude-TypeScript/issues/21))\n  ([38c2e33](https://github.com/amplitude/Amplitude-TypeScript/commit/38c2e3334b27063e23275c020207f647acbbaf6f))\n- use uuid for default device id ([#20](https://github.com/amplitude/Amplitude-TypeScript/issues/20))\n  ([7f058e8](https://github.com/amplitude/Amplitude-TypeScript/commit/7f058e8723b9611ffb8fccb9ba80ba9bb296be4e))\n- window reference and intellisense type def for IDE\n  ([#55](https://github.com/amplitude/Amplitude-TypeScript/issues/55))\n  ([14eef98](https://github.com/amplitude/Amplitude-TypeScript/commit/14eef98fe7e7275ba8222586922101b326d28c43))\n\n### Features\n\n- add amplitude built-in plugins ([#22](https://github.com/amplitude/Amplitude-TypeScript/issues/22))\n  ([443a424](https://github.com/amplitude/Amplitude-TypeScript/commit/443a424d6dfd3a2c867f528f953429151de96ed0))\n- add context plugin ([#13](https://github.com/amplitude/Amplitude-TypeScript/issues/13))\n  ([3d63991](https://github.com/amplitude/Amplitude-TypeScript/commit/3d639917905b25cab0bb012286b8ba487d0f63fb))\n- add EU and batch endpoint support ([#50](https://github.com/amplitude/Amplitude-TypeScript/issues/50))\n  ([af6be60](https://github.com/amplitude/Amplitude-TypeScript/commit/af6be606a0e049657129ddbcbbf83c3dff844443))\n- add getter and setter for config and group ([#45](https://github.com/amplitude/Amplitude-TypeScript/issues/45))\n  ([60e0073](https://github.com/amplitude/Amplitude-TypeScript/commit/60e00734a73002dffc98ddf6171ee74c5ac53aa4))\n- add partner_id in event options ([#38](https://github.com/amplitude/Amplitude-TypeScript/issues/38))\n  ([880fe57](https://github.com/amplitude/Amplitude-TypeScript/commit/880fe57e5813d8bbe05c2a2a9428bd8a0a1e7d08))\n- add serverZone check while calling getApiHost ([#51](https://github.com/amplitude/Amplitude-TypeScript/issues/51))\n  ([fa3014d](https://github.com/amplitude/Amplitude-TypeScript/commit/fa3014dd730e624b6320769edbdf35350d0edc3d))\n- add snippet installation ([#36](https://github.com/amplitude/Amplitude-TypeScript/issues/36))\n  ([85348d5](https://github.com/amplitude/Amplitude-TypeScript/commit/85348d5ff719bf30ed3a93ed11dd97ed98ff862a))\n- adds session management ([#15](https://github.com/amplitude/Amplitude-TypeScript/issues/15))\n  ([e23a563](https://github.com/amplitude/Amplitude-TypeScript/commit/e23a563c27befa5a3dc31ee55c559359e0159de3))\n- attribution tracking ([#24](https://github.com/amplitude/Amplitude-TypeScript/issues/24))\n  ([c12678e](https://github.com/amplitude/Amplitude-TypeScript/commit/c12678e2aad98d333982ddb1ea4afb67a050bb1d))\n- browser init config ([#6](https://github.com/amplitude/Amplitude-TypeScript/issues/6))\n  ([c5a0992](https://github.com/amplitude/Amplitude-TypeScript/commit/c5a09925e64f8a613eeab612ee6efb43419f39b4))\n- create browser folder structure ([#5](https://github.com/amplitude/Amplitude-TypeScript/issues/5))\n  ([b1b279d](https://github.com/amplitude/Amplitude-TypeScript/commit/b1b279da067af7a5ca0c797b4f45fc154e3c2ae4))\n- create cookie/events storage providers ([#7](https://github.com/amplitude/Amplitude-TypeScript/issues/7))\n  ([b3d6fab](https://github.com/amplitude/Amplitude-TypeScript/commit/b3d6fab5239d0d14854af9aa8a0c31826447ac48))\n- create transport providers (fetch/xhr/sendBeacon) ([#8](https://github.com/amplitude/Amplitude-TypeScript/issues/8))\n  ([5ad3477](https://github.com/amplitude/Amplitude-TypeScript/commit/5ad3477974c779d696088922f56cae38a89f911c))\n- expose core apis ([#37](https://github.com/amplitude/Amplitude-TypeScript/issues/37))\n  ([ea034de](https://github.com/amplitude/Amplitude-TypeScript/commit/ea034de03737570ae42e9b844835744362cc73df))\n- implement save events to storage on destination plugin\n  ([#26](https://github.com/amplitude/Amplitude-TypeScript/issues/26))\n  ([5f47677](https://github.com/amplitude/Amplitude-TypeScript/commit/5f476773f0a546db15de45fc40725a138a037c97))\n- implements optOut config ([#30](https://github.com/amplitude/Amplitude-TypeScript/issues/30))\n  ([bdf1eb0](https://github.com/amplitude/Amplitude-TypeScript/commit/bdf1eb0c46f535947f66162639dd0b23f154ce28))\n- improve browser config logic ([#56](https://github.com/amplitude/Amplitude-TypeScript/issues/56))\n  ([3054c68](https://github.com/amplitude/Amplitude-TypeScript/commit/3054c6856dd8f8ed49c9326f25c14b672890915b))\n- introduce amplitude sdk promises ([#52](https://github.com/amplitude/Amplitude-TypeScript/issues/52))\n  ([75f79c0](https://github.com/amplitude/Amplitude-TypeScript/commit/75f79c023b136b9148b79514f65515342e9b3d37))\n- set transport api ([#58](https://github.com/amplitude/Amplitude-TypeScript/issues/58))\n  ([addd2dd](https://github.com/amplitude/Amplitude-TypeScript/commit/addd2dd70d25b6977ad7faa044da518bf7b9295b))\n- update track event ([#25](https://github.com/amplitude/Amplitude-TypeScript/issues/25))\n  ([bcccd65](https://github.com/amplitude/Amplitude-TypeScript/commit/bcccd659f83bd235ce7cb59848e259e14e1df392))\n"
  },
  {
    "path": "packages/analytics-browser/README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://amplitude.com\" target=\"_blank\" align=\"center\">\n    <img src=\"https://static.amplitude.com/lightning/46c85bfd91905de8047f1ee65c7c93d6fa9ee6ea/static/media/amplitude-logo-with-text.4fb9e463.svg\" width=\"280\">\n  </a>\n  <br />\n</p>\n\n# @amplitude/analytics-browser\n\nOfficial Amplitude SDK for Web\n\n# Doc\n\nSee our [Analytics SDK for Browser](https://amplitude.github.io/Amplitude-TypeScript/modules/_amplitude_analytics_browser.html) Reference for a list and description of all available SDK methods.\n\n# Installation and Quick Start\n\nPlease visit our :100:[Developer Center](https://www.docs.developers.amplitude.com/data/sdks/browser-2/) for instructions on installing and using our the SDK.\n\n## Installation\n\nTo get started with using Amplitude Browser SDK, install the package to your project via npm, yarn or script loader.\n\n### Installing via package manager\n\nThis SDK is available as a package on npm registry named `@amplitude/analytics-browser`. You can install the package using npm or yarn CLI.\n\n#### Using npm CLI\n\n```sh\nnpm install @amplitude/analytics-browser\n```\n\n#### Using yarn CLI\n\n```sh\n# yarn\nyarn add @amplitude/analytics-browser\n```\n\nImport the package into your project and initialize it with your API key.\n\n```ts\nimport * as amplitude from '@amplitude/analytics-browser';\n\namplitude.init('<YOUR_API_KEY>');\n```\n\n### Installing via script loader\n\nThis SDK is also available through CDN. Copy the script loader below and paste before the `</head>` tag of every page you want to track and initialize it with your API key.\n\n<!-- README_SNIPPET_BLOCK -->\n```html\n<script type=\"text/javascript\">\n!function(){\"use strict\";!function(e,t){var r=e.amplitude||{_q:[],_iq:{}};if(r.invoked)e.console&&console.error&&console.error(\"Amplitude snippet has been loaded.\");else{var n=function(e,t){e.prototype[t]=function(){return this._q.push({name:t,args:Array.prototype.slice.call(arguments,0)}),this}},s=function(e,t,r){return function(n){e._q.push({name:t,args:Array.prototype.slice.call(r,0),resolve:n})}},o=function(e,t,r){e[t]=function(){if(r)return{promise:new Promise(s(e,t,Array.prototype.slice.call(arguments)))};!function(e,t,r){e._q.push({name:t,args:Array.prototype.slice.call(r,0)})}(e,t,Array.prototype.slice.call(arguments))}},i=function(e){for(var t=0;t<y.length;t++)o(e,y[t],!1);for(var r=0;r<g.length;r++)o(e,g[r],!0)};r.invoked=!0;var c=t.createElement(\"script\");c.type=\"text/javascript\",c.integrity=\"sha384-hmnfWlRQ5S6H/wCNnDtjTifF4/Jpkj4yezjl1CxwuhX54oCx83KDHuOdZKVIkdrR\",c.crossOrigin=\"anonymous\",c.async=!0,c.src=\"https://cdn.amplitude.com/libs/analytics-browser-2.42.3-min.js.gz\",c.onload=function(){e.amplitude.runQueuedFunctions||console.log(\"[Amplitude] Error: could not load SDK\")};var a=t.getElementsByTagName(\"script\")[0];a.parentNode.insertBefore(c,a);for(var u=function(){return this._q=[],this},l=[\"add\",\"append\",\"clearAll\",\"prepend\",\"set\",\"setOnce\",\"unset\",\"preInsert\",\"postInsert\",\"remove\",\"getUserProperties\"],p=0;p<l.length;p++)n(u,l[p]);r.Identify=u;for(var d=function(){return this._q=[],this},f=[\"getEventProperties\",\"setProductId\",\"setQuantity\",\"setPrice\",\"setRevenue\",\"setRevenueType\",\"setReceipt\",\"setReceiptSig\",\"setCurrency\",\"setEventProperties\"],v=0;v<f.length;v++)n(d,f[v]);r.Revenue=d;var y=[\"getDeviceId\",\"setDeviceId\",\"getSessionId\",\"setSessionId\",\"getUserId\",\"setUserId\",\"setOptOut\",\"setTransport\",\"reset\",\"extendSession\"],g=[\"init\",\"add\",\"remove\",\"track\",\"logEvent\",\"identify\",\"groupIdentify\",\"setGroup\",\"revenue\",\"flush\"];i(r),r.createInstance=function(e){return r._iq[e]={_q:[]},i(r._iq[e]),r._iq[e]},e.amplitude=r}}(window,document)}();\n\namplitude.init(\"<YOUR_API_KEY>\");\n</script>\n```\n<!-- / OF README_SNIPPET_BLOCK -->\n\n## Tracking events\n\nOnce the SDK is initialize, you can start tracking events.\n\n```ts\namplitude.track('Page Viewed');\n```\n\nFor in-depth documentation, please visit to our [Developer Center](https://www.docs.developers.amplitude.com/data/sdks/sdk-quickstart/#browser).\n"
  },
  {
    "path": "packages/analytics-browser/e2e/cookie-consent.spec.ts",
    "content": "import { test, expect } from '@playwright/test';\nimport { parseRequestBody } from './helpers';\n\ntest.describe('Cookie Consent Page', () => {\n  let requests: any[] = [];\n\n  test.beforeEach(async ({ page }) => {\n    requests = [];\n    await page.route('https://api2.amplitude.com/2/httpapi', async (route) => {\n      const request = route.request();\n      const data = parseRequestBody(request);\n      if (data) {\n        requests.push(data);\n      }\n      await route.continue();\n    });\n  });\n\n  test('should track events only after cookie consent is given', async ({ page }) => {\n    // Navigate to the cookie consent page\n    await page.goto('/browser-sdk/cookie-consent.html');\n    \n    // Wait for the page to load and cookie banner to appear\n    await expect(page.locator('#cookie-banner')).toBeVisible();\n    await expect(page.locator('#consent-status')).toContainText('Cookie consent not given yet');\n    await expect(page.locator('#sdk-status')).toContainText('Amplitude SDK not initialized');\n\n    // Click the button to track event before cookie consent\n    await page.click('#track-before-consent-btn');\n    \n    // Wait a moment to ensure any potential requests would have been made\n    await page.waitForTimeout(1000);\n    \n    // Assert: no network request made by Amplitude (since SDK is not initialized)\n    expect(requests.length).toBe(0);\n    \n    // Click on accept button of the cookie consent banner\n    await page.click('#accept-cookies-btn');\n    \n    // Wait for cookie banner to disappear and SDK to initialize\n    await expect(page.locator('#cookie-banner')).not.toBeVisible();\n    await expect(page.locator('#consent-status')).toContainText('Cookie consent given');\n    await expect(page.locator('#sdk-status')).toContainText('Amplitude SDK initialized');\n    \n    // Wait for all network requests to complete\n    await page.waitForLoadState('networkidle');\n    // Check every 500ms for up to 10 seconds\n    for (let i = 0; i < 20; i++) {\n      if (requests.length === 1) break;\n      await page.waitForTimeout(500);\n    }\n\n    // Assert: two events should be sent\n    expect(requests.length).toBe(1);\n    \n    const events = requests[0].events;\n    expect(events.length).toBe(2);\n    \n    // Verify the first event is \"before cookie consent\"\n    expect(events[0].event_type).toBe('before cookie consent');\n    expect(events[0].event_properties.page).toBe('cookie-consent-demo');\n    expect(events[0].event_properties.consent_status).toBe('not_given');\n    expect(events[0].user_id).toBe('test-user-cookie-consent');\n    \n    // Verify the second event is \"SDK Initialized After Consent\"  \n    expect(events[1].event_type).toBe('SDK Initialized After Consent');\n    expect(events[1].event_properties.consent_method).toBe('cookie_banner');\n    expect(events[1].user_id).toBe('test-user-cookie-consent');\n  });\n\n  test('should not initialize SDK when cookie consent is declined', async ({ page }) => {\n    // Capture console logs\n    const consoleLogs: string[] = [];\n    page.on('console', msg => {\n      consoleLogs.push(msg.text());\n    });\n\n    // Navigate to the cookie consent page\n    await page.goto('/browser-sdk/cookie-consent.html');\n    \n    // Wait for the page to load and cookie banner to appear\n    await expect(page.locator('#cookie-banner')).toBeVisible();\n\n    // Click the button to track event before cookie consent\n    await page.click('#track-before-consent-btn');\n    \n    // Wait a moment to ensure any potential requests would have been made\n    await page.waitForTimeout(1000);\n    \n    // Assert: no network request made by Amplitude\n    expect(requests.length).toBe(0);\n\n    // Click on decline button of the cookie consent banner\n    await page.click('#decline-cookies-btn');\n    \n    // Wait for cookie banner to disappear\n    await expect(page.locator('#cookie-banner')).not.toBeVisible();\n    \n    // Verify SDK status remains uninitialized\n    await expect(page.locator('#consent-status')).toContainText('Cookie consent not given yet');\n    await expect(page.locator('#sdk-status')).toContainText('Amplitude SDK not initialized');\n    \n    // Wait for potential network requests\n    await page.waitForTimeout(3000);\n\n    // Assert: still no network requests should be made\n    expect(requests.length).toBe(0);\n\n    // Assert: no console log contains \"Amplitude SDK initialized successfully\"\n    const hasInitializationLog = consoleLogs.some(log => log.includes('Amplitude SDK initialized successfully'));\n    expect(hasInitializationLog).toBe(false);\n  });\n}); "
  },
  {
    "path": "packages/analytics-browser/e2e/cookies-is-enabled.spec.ts",
    "content": "import { test, expect } from '@playwright/test';\n\nconst RUNS = 10;\n\ntest.describe('CookieStorage', () => {\n  // Regression Test to cover re-entrancy issues fixed by https://github.com/amplitude/Amplitude-TypeScript/pull/1539\n  test('.isEnabled works when called multiple times concurrently', async ({ page }) => {\n    const consoleErrors: string[] = [];\n\n    await page.addInitScript(() => {\n      // runs before any page script\n      (window as any).IS_PLAYWRIGHT = true;\n    });\n\n    page.on('console', (msg) => {\n      if (msg.type() === 'error') {\n        consoleErrors.push(msg.text());\n      }\n    });\n\n    const pageErrors: string[] = [];\n    page.on('pageerror', (err) => {\n      pageErrors.push(err.message);\n    });\n\n    for (let i = 0; i < RUNS; i++) {\n      await page.goto('/cookies/is-enabled.html');\n      expect(pageErrors, `Expected no page errors, but got: ${pageErrors.join('; ')}`).toHaveLength(0);\n      expect(consoleErrors, `Expected no console.error calls, but got: ${consoleErrors.join('; ')}`).toHaveLength(0);\n    }\n  });\n});\n"
  },
  {
    "path": "packages/analytics-browser/e2e/events.spec.ts",
    "content": "import { test, expect, Page } from '@playwright/test';\nimport { parseRequestBody } from './helpers';\n\ninterface StorageState {\n  origins: Array<{\n    origin: string;\n    localStorage: Array<{\n      name: string;\n      value: string;\n    }>;\n  }>;\n}\n\nasync function getUnsentEvents(page: Page): Promise<any[]> {\n  const storage = await page.context().storageState() as StorageState;\n  const unsentItems = storage.origins[0].localStorage\n    .filter(item => item.name.startsWith('AMP_unsent_'));\n  \n  if (unsentItems.length === 0) {\n    return [];\n  }\n  \n  return JSON.parse(unsentItems[0].value);\n}\n\ntest.describe('Events Page', () => {\n  let requests: any[] = [];\n\n  test.beforeEach(async ({ page }) => {\n    requests = [];\n    await page.route('https://api2.amplitude.com/2/httpapi', async (route) => {\n      const request = route.request();\n      const data = parseRequestBody(request);\n      if (data) {\n        requests.push(data);\n      }\n      await route.continue();\n    });\n  });\n\n  test('should track events in sequence', async ({ page }) => {\n    // Navigate to the events page\n    await page.goto('/browser-sdk/events-precision.html');\n    \n    // Wait for all status elements to be present\n    const statusElements = [\n      'event1-status',\n      'event2-status',\n      'event3-status',\n      'event4-status'\n    ];\n\n    // Wait for all events to complete (status changes to 'complete')\n    for (const id of statusElements) {\n      await expect(page.locator(`#${id}`)).toHaveClass(/complete/);\n    }\n\n    // Verify the final state of all status elements\n    for (const id of statusElements) {\n      const element = page.locator(`#${id}`);\n      await expect(element).toHaveClass(/complete/);\n      await expect(element).toHaveText(/Tracked Event/);\n    }\n\n    // Wait for all network requests to complete\n    await page.waitForLoadState('networkidle');\n    await page.waitForTimeout(1000);\n\n    const events = requests[0].events;\n    // Verify the network requests\n    expect(events.length).toBe(4);\n    events.forEach((event: any, index: number) => {\n      expect(event.event_type).toBe(`Event ${index + 1}`);\n      expect(event.user_id).toBe('test-user');\n    });\n  });\n\n  test('should track events even if offline', async ({ page }) => {\n    // Navigate to the events page\n    await page.goto('/browser-sdk/events-precision.html');\n    \n    // Set browser to offline mode\n    await page.context().setOffline(true);\n    \n    // Wait for all status elements to be present\n    const statusElements = [\n      'event1-status',\n      'event2-status',\n      'event3-status',\n      'event4-status'\n    ];\n\n    // Wait for all events to complete (status changes to 'complete')\n    for (const id of statusElements) {\n      await expect(page.locator(`#${id}`)).toHaveClass(/complete/);\n    }\n\n    // Verify the final state of all status elements\n    for (const id of statusElements) {\n      const element = page.locator(`#${id}`);\n      await expect(element).toHaveClass(/complete/);\n      await expect(element).toHaveText(/Tracked Event/);\n    }\n\n    // Verify no requests were sent while offline\n    expect(requests.length).toBe(0);\n\n    // Wait for localStorage to be populated\n    await page.waitForFunction(() => {\n      return Object.keys((globalThis as any).localStorage)\n        .some(key => key.startsWith('AMP_unsent_'));\n    });\n\n    // Check localStorage for queued events\n    const unsentValues = await getUnsentEvents(page);\n    expect(unsentValues.length).toBe(4);\n    \n    // Parse the stored events\n    const storedEvents: any[][] = [];\n    const storage = await page.context().storageState() as StorageState;\n    const unsentItems = storage.origins[0].localStorage\n      .filter(item => item.name.startsWith('AMP_unsent_'));\n    for (const item of unsentItems) {\n      storedEvents.push(JSON.parse(item.value));\n    }\n\n    // Verify events are in localStorage\n    expect(storedEvents.length).toBeGreaterThan(0);\n    const queuedEvents = storedEvents.flat();\n    expect(queuedEvents.length).toBe(4);\n    queuedEvents.forEach((event: any, index: number) => {\n      expect(event.event_type).toBe(`Event ${index + 1}`);\n      expect(event.user_id).toBe('test-user');\n    });\n\n    // Set browser back to online mode\n    await page.context().setOffline(false);\n\n    // Wait for all network requests to complete\n    await page.waitForLoadState('networkidle');\n    await page.waitForTimeout(1000);\n\n    const events = requests[0].events;\n    // Verify the network requests\n    expect(events.length).toBe(4);\n    events.forEach((event: any, index: number) => {\n      expect(event.event_type).toBe(`Event ${index + 1}`);\n      expect(event.user_id).toBe('test-user');\n    });\n\n    // Verify localStorage is cleared after sending\n    await page.waitForTimeout(1000);\n    const finalUnsentValues = await getUnsentEvents(page);\n    expect(finalUnsentValues.length).toBe(0);\n  });\n}); "
  },
  {
    "path": "packages/analytics-browser/e2e/helpers.ts",
    "content": "import { gunzipSync } from 'zlib';\nimport type { Request } from '@playwright/test';\n\n/**\n * Parse request body as JSON. Decompresses gzip when Content-Encoding: gzip is set.\n * Uses postDataBuffer() for gzip so we get raw bytes; uses postData() for plain JSON.\n */\nexport function parseRequestBody(request: Request): Record<string, unknown> | undefined {\n  const contentEncoding = request.headers()['content-encoding'];\n\n  if (contentEncoding === 'gzip') {\n    const buffer = request.postDataBuffer();\n    if (!buffer || buffer.length === 0) return undefined;\n    const bodyStr = gunzipSync(buffer).toString('utf8');\n    return JSON.parse(bodyStr) as Record<string, unknown>;\n  }\n\n  const postData = request.postData();\n  if (!postData) return undefined;\n  return JSON.parse(postData) as Record<string, unknown>;\n}\n"
  },
  {
    "path": "packages/analytics-browser/e2e/iframe-sandbox.spec.ts",
    "content": "import { test, expect } from '@playwright/test';\n\ntest('iframe-sandbox parent page has no uncaught exceptions', async ({ page }) => {\n  const errors: Error[] = [];\n  page.on('pageerror', (err) => errors.push(err));\n\n  await page.goto('/iframe-sandbox/parent.html', { waitUntil: 'networkidle' });\n\n  // Allow iframe content (child.html with Amplitude) to load and run\n  const iframe = page.frameLocator('iframe[src*=\"child.html\"]');\n  await iframe.locator('body').waitFor({ state: 'visible', timeout: 10000 });\n\n  // just test that the errors are the expected errors\n  // until we make the SDK handle the iframe sandbox environment more gracefully\n  const expectedErrors = [\n    `Failed to read the 'cookie' property from 'Document'`,\n    `SecurityError: The operation is insecure`,\n  ];\n  const unexpectedErrors = [\n    `Access to the Locks API is denied in this context`,\n  ];\n  for (const error of errors) {\n    expect(expectedErrors.find((err) => error.message.includes(err))).toBeDefined();\n    expect(unexpectedErrors.find((err) => error.message.includes(err))).toBeUndefined();\n  }\n  expect(errors.length <= 3).toBe(true);\n});\n"
  },
  {
    "path": "packages/analytics-browser/e2e/proxy-server.spec.ts",
    "content": "import { test, expect } from '@playwright/test';\nimport { parseRequestBody } from './helpers';\n\n// Extend the Window interface to include amplitude\ndeclare global {\n  interface Window {\n    amplitude: any;\n  }\n}\n\ntest.describe('Proxy Server Integration', () => {\n  let proxyRequests: any[] = [];\n\n  test.beforeEach(async ({ page }) => {\n    proxyRequests = [];\n    \n    // Intercept calls to the proxy server\n    await page.route('http://localhost:3001/2/httpapi', async (route) => {\n      const request = route.request();\n      const data = parseRequestBody(request);\n\n      if (data) {\n        proxyRequests.push({\n        url: request.url(),\n        method: request.method(),\n        headers: request.headers(),\n        data: data\n        });\n      }\n      \n      // Continue the request to the actual proxy server\n      await route.continue();\n    });\n  });\n\n  test('should track multiple events through proxy server', async ({ page }) => {\n    // Navigate to the proxy test page\n    await page.goto('/proxy-test.html');\n    \n    // Wait for the page to load\n    await page.waitForLoadState('networkidle');\n    await page.waitForTimeout(1000);\n    \n    // Send multiple events\n    const events = [\n      { name: 'FAKE-EVENT-1', properties: { index: 1 } },\n      { name: 'FAKE-EVENT-2', properties: { index: 2 } },\n      { name: 'FAKE-EVENT-3', properties: { index: 3 } }\n    ];\n    \n    for (const event of events) {\n      await page.evaluate((eventData) => {\n        // @ts-ignore - window is available in browser context\n        return window.amplitude.track(eventData.name, {\n          source: 'playwright-test',\n          timestamp: Date.now(),\n          ...eventData.properties\n        });\n      }, event);\n      \n      // Small delay between events\n      await page.waitForTimeout(500);\n    }\n    \n    // Wait for all network requests to complete\n    await page.waitForTimeout(2000);\n    \n    // Verify that requests were made to the proxy server\n    expect(proxyRequests.length).toBeGreaterThan(0);\n    \n    // Collect all events from all requests\n    const allEvents: any[] = [];\n    proxyRequests.forEach(request => {\n      if (request.data && request.data.events) {\n        allEvents.push(...request.data.events);\n      }\n    });\n    \n    // Verify we have at least 3 events\n    expect(allEvents.length).toBeGreaterThanOrEqual(3);\n    \n    // Verify each event was tracked\n    events.forEach(event => {\n      const trackedEvent = allEvents.find((e: any) => e.event_type === event.name);\n      expect(trackedEvent).toBeDefined();\n      expect(trackedEvent.event_type).toBe(event.name);\n      expect(trackedEvent.event_properties.source).toBe('playwright-test');\n      expect(trackedEvent.event_properties.index).toBe(event.properties.index);\n    });\n  });\n}); "
  },
  {
    "path": "packages/analytics-browser/e2e/title.spec.ts",
    "content": "import { test, expect } from '@playwright/test';\n\ntest('should have correct title', async ({ page }) => {\n  const errors: Error[] = [];\n  page.on('pageerror', (err) => errors.push(err));\n\n  // Add error handling for navigation\n  try {\n    // Navigate to the specified URL with retry logic\n    const response = await page.goto('http://localhost:5173/browser-sdk/index.html', {\n      waitUntil: 'networkidle',\n      timeout: 30000,\n    });\n\n    // Check if the response was successful\n    expect(response?.status()).toBe(200);\n\n    // Get the page title\n    const title = await page.title();\n\n    // Assert that the title is what we expect\n    expect(title).toBeTruthy();\n\n    // Ensure no uncaught errors were thrown on the page\n    expect(errors).toEqual([]);\n  } catch (error) {\n    console.error('Navigation failed:', error);\n    throw error;\n  }\n});\n"
  },
  {
    "path": "packages/analytics-browser/generated/amplitude-bookmarklet-snippet.js",
    "content": "\"use strict\";\n\n/**\n * Create a bookmark with this code snippet in the browser, update the apiKey, userId, and serverZone, and click the bookmark on any website to run.\n * Script will fail to load if the website has a Content Security Policy (CSP) that blocks third-party inline scripts.\n */\n!function (window, document) {\n  var amplitude = window.amplitude || {\n    _q: [],\n    _iq: {}\n  };\n  if (amplitude.invoked) window.console && console.error && console.error('Amplitude snippet has been loaded.');else {\n    var proxy = function proxy(obj, fn) {\n      obj.prototype[fn] = function () {\n        this._q.push({\n          name: fn,\n          args: Array.prototype.slice.call(arguments, 0)\n        });\n        return this;\n      };\n    };\n    var getPromiseResult = function getPromiseResult(instance, fn, args) {\n      return function (resolve) {\n        instance._q.push({\n          name: fn,\n          args: Array.prototype.slice.call(args, 0),\n          resolve: resolve\n        });\n      };\n    };\n    var proxyMain = function proxyMain(instance, fn, isPromise) {\n      instance[fn] = function () {\n        if (isPromise) return {\n          promise: new Promise(getPromiseResult(instance, fn, Array.prototype.slice.call(arguments)))\n        };\n      };\n    };\n    var setUpProxy = function setUpProxy(instance) {\n      for (var k = 0; k < funcs.length; k++) {\n        proxyMain(instance, funcs[k], false);\n      }\n      for (var l = 0; l < funcsWithPromise.length; l++) {\n        proxyMain(instance, funcsWithPromise[l], true);\n      }\n    };\n    amplitude.invoked = true;\n    var s = document.getElementsByTagName('script')[0];\n    var autoTrackingPluginScript = document.createElement('script');\n    autoTrackingPluginScript.src = 'https://cdn.amplitude.com/libs/plugin-autocapture-browser-0.9.0-min.js.gz';\n    autoTrackingPluginScript.async = false;\n    s.parentNode.insertBefore(autoTrackingPluginScript, s);\n    var as = document.createElement('script');\n    as.type = 'text/javascript';\n    as.integrity = 'sha384-hmnfWlRQ5S6H/wCNnDtjTifF4/Jpkj4yezjl1CxwuhX54oCx83KDHuOdZKVIkdrR';\n    as.crossOrigin = 'anonymous';\n    as.async = false;\n    as.src = 'https://cdn.amplitude.com/libs/analytics-browser-2.42.3-min.js.gz';\n    as.onload = function () {\n      if (!window.amplitude.runQueuedFunctions) {\n        console.log('[Amplitude] Error: could not load SDK');\n      }\n      window.amplitude.init('YOUR_API_KEY', 'YOUR_USER_ID', {\n        instanceName: 'amplitude-bookmarklet',\n        serverZone: 'YOUR_SERVER_ZONE',\n        ingestionMetadata: {\n          sourceName: 'browser-typescript-bookmarklet',\n          sourceVersion: '1.0.0'\n        },\n        optOut: false\n      });\n      if (amplitudeAutocapturePlugin && amplitudeAutocapturePlugin.autocapturePlugin && typeof amplitudeAutocapturePlugin.autocapturePlugin === 'function') {\n        window.amplitude.add(amplitudeAutocapturePlugin.autocapturePlugin());\n      }\n      alert('Amplitude is now tracking events!');\n    };\n    s.parentNode.insertBefore(as, s);\n    var Identify = function Identify() {\n      this._q = [];\n      return this;\n    };\n    var identifyFuncs = ['add', 'append', 'clearAll', 'prepend', 'set', 'setOnce', 'unset', 'preInsert', 'postInsert', 'remove', 'getUserProperties'];\n    for (var i = 0; i < identifyFuncs.length; i++) {\n      proxy(Identify, identifyFuncs[i]);\n    }\n    amplitude.Identify = Identify;\n    var Revenue = function Revenue() {\n      this._q = [];\n      return this;\n    };\n    var revenueFuncs = ['getEventProperties', 'setProductId', 'setQuantity', 'setPrice', 'setRevenue', 'setRevenueType', 'setReceipt', 'setReceiptSig', 'setCurrency', 'setEventProperties'];\n    for (var j = 0; j < revenueFuncs.length; j++) {\n      proxy(Revenue, revenueFuncs[j]);\n    }\n    amplitude.Revenue = Revenue;\n    var funcs = ['getDeviceId', 'setDeviceId', 'getSessionId', 'setSessionId', 'getUserId', 'setUserId', 'setOptOut', 'setTransport', 'reset', 'extendSession'];\n    var funcsWithPromise = ['init', 'add', 'remove', 'track', 'logEvent', 'identify', 'groupIdentify', 'setGroup', 'revenue', 'flush'];\n    setUpProxy(amplitude);\n    amplitude.createInstance = function (instanceName) {\n      amplitude._iq[instanceName] = {\n        _q: []\n      };\n      setUpProxy(amplitude._iq[instanceName]);\n      return amplitude._iq[instanceName];\n    };\n    window.amplitude = amplitude;\n  }\n}(window, document);"
  },
  {
    "path": "packages/analytics-browser/generated/amplitude-gtm-snippet.js",
    "content": "\"use strict\";\n\n/**\n * Imported in client browser via <script> tag\n * Async capabilities: Interally creates stubbed window.amplitudeGTM object until real SDK loaded\n * Stubbed functions keep track of funciton calls and their arguments\n * These are sent once real SDK loaded through another <script> tag\n */\n!function (window, document) {\n  var amplitude = window.amplitudeGTM || {\n    _q: [],\n    _iq: {}\n  };\n  if (amplitude.invoked) window.console && console.error && console.error('Amplitude snippet has been loaded.');else {\n    var proxy = function proxy(obj, fn) {\n      obj.prototype[fn] = function () {\n        this._q.push({\n          name: fn,\n          args: Array.prototype.slice.call(arguments, 0)\n        });\n        return this;\n      };\n    };\n    var getPromiseResult = function getPromiseResult(instance, fn, args) {\n      return function (resolve) {\n        instance._q.push({\n          name: fn,\n          args: Array.prototype.slice.call(args, 0),\n          resolve: resolve\n        });\n      };\n    };\n    var proxyInstance = function proxyInstance(instance, fn, args) {\n      instance._q.push({\n        name: fn,\n        args: Array.prototype.slice.call(args, 0)\n      });\n    };\n    var proxyMain = function proxyMain(instance, fn, isPromise) {\n      instance[fn] = function () {\n        if (isPromise) return {\n          promise: new Promise(getPromiseResult(instance, fn, Array.prototype.slice.call(arguments)))\n        };\n        proxyInstance(instance, fn, Array.prototype.slice.call(arguments));\n      };\n    };\n    var setUpProxy = function setUpProxy(instance) {\n      for (var k = 0; k < funcs.length; k++) {\n        proxyMain(instance, funcs[k], false);\n      }\n      for (var l = 0; l < funcsWithPromise.length; l++) {\n        proxyMain(instance, funcsWithPromise[l], true);\n      }\n    };\n    amplitude.invoked = true;\n    var as = document.createElement('script');\n    as.type = 'text/javascript';\n    as.integrity = 'sha384-oOfG5gAMp0FoZRb5bhEDx4bOECoOHyHvYtN675gKLVLVUNrpWhyp/LOOLzbXX+Hv';\n    as.crossOrigin = 'anonymous';\n    as.async = true;\n    as.src = 'https://cdn.amplitude.com/libs/analytics-browser-gtm-2.42.3-min.js.gz';\n    as.onload = function () {\n      if (!window.amplitudeGTM.runQueuedFunctions) {\n        console.log('[Amplitude] Error: could not load SDK');\n      }\n    };\n    var s = document.getElementsByTagName('script')[0];\n    s.parentNode.insertBefore(as, s);\n    var Identify = function Identify() {\n      this._q = [];\n      return this;\n    };\n    var identifyFuncs = ['add', 'append', 'clearAll', 'prepend', 'set', 'setOnce', 'unset', 'preInsert', 'postInsert', 'remove', 'getUserProperties'];\n    for (var i = 0; i < identifyFuncs.length; i++) {\n      proxy(Identify, identifyFuncs[i]);\n    }\n    amplitude.Identify = Identify;\n    var Revenue = function Revenue() {\n      this._q = [];\n      return this;\n    };\n    var revenueFuncs = ['getEventProperties', 'setProductId', 'setQuantity', 'setPrice', 'setRevenue', 'setRevenueType', 'setReceipt', 'setReceiptSig', 'setCurrency', 'setEventProperties'];\n    for (var j = 0; j < revenueFuncs.length; j++) {\n      proxy(Revenue, revenueFuncs[j]);\n    }\n    amplitude.Revenue = Revenue;\n    var funcs = ['getDeviceId', 'setDeviceId', 'getSessionId', 'setSessionId', 'getUserId', 'setUserId', 'setOptOut', 'setTransport', 'reset', 'extendSession'];\n    var funcsWithPromise = ['init', 'add', 'remove', 'track', 'logEvent', 'identify', 'groupIdentify', 'setGroup', 'revenue', 'flush'];\n    setUpProxy(amplitude);\n    amplitude.createInstance = function (instanceName) {\n      amplitude._iq[instanceName] = {\n        _q: []\n      };\n      setUpProxy(amplitude._iq[instanceName]);\n      return amplitude._iq[instanceName];\n    };\n    window.amplitudeGTM = amplitude;\n    if (!window.amplitude) {\n      window.amplitude = window.amplitudeGTM;\n    }\n  }\n}(window, document);"
  },
  {
    "path": "packages/analytics-browser/generated/amplitude-snippet.js",
    "content": "\"use strict\";\n\n/**\n * Imported in client browser via <script> tag\n * Async capabilities: Interally creates stubbed window.amplitude object until real SDK loaded\n * Stubbed functions keep track of funciton calls and their arguments\n * These are sent once real SDK loaded through another <script> tag\n */\n!function (window, document) {\n  var amplitude = window.amplitude || {\n    _q: [],\n    _iq: {}\n  };\n  if (amplitude.invoked) window.console && console.error && console.error('Amplitude snippet has been loaded.');else {\n    var proxy = function proxy(obj, fn) {\n      obj.prototype[fn] = function () {\n        this._q.push({\n          name: fn,\n          args: Array.prototype.slice.call(arguments, 0)\n        });\n        return this;\n      };\n    };\n    var getPromiseResult = function getPromiseResult(instance, fn, args) {\n      return function (resolve) {\n        instance._q.push({\n          name: fn,\n          args: Array.prototype.slice.call(args, 0),\n          resolve: resolve\n        });\n      };\n    };\n    var proxyInstance = function proxyInstance(instance, fn, args) {\n      instance._q.push({\n        name: fn,\n        args: Array.prototype.slice.call(args, 0)\n      });\n    };\n    var proxyMain = function proxyMain(instance, fn, isPromise) {\n      instance[fn] = function () {\n        if (isPromise) return {\n          promise: new Promise(getPromiseResult(instance, fn, Array.prototype.slice.call(arguments)))\n        };\n        proxyInstance(instance, fn, Array.prototype.slice.call(arguments));\n      };\n    };\n    var setUpProxy = function setUpProxy(instance) {\n      for (var k = 0; k < funcs.length; k++) {\n        proxyMain(instance, funcs[k], false);\n      }\n      for (var l = 0; l < funcsWithPromise.length; l++) {\n        proxyMain(instance, funcsWithPromise[l], true);\n      }\n    };\n    amplitude.invoked = true;\n    var as = document.createElement('script');\n    as.type = 'text/javascript';\n    as.integrity = 'sha384-hmnfWlRQ5S6H/wCNnDtjTifF4/Jpkj4yezjl1CxwuhX54oCx83KDHuOdZKVIkdrR';\n    as.crossOrigin = 'anonymous';\n    as.async = true;\n    as.src = 'https://cdn.amplitude.com/libs/analytics-browser-2.42.3-min.js.gz';\n    as.onload = function () {\n      if (!window.amplitude.runQueuedFunctions) {\n        console.log('[Amplitude] Error: could not load SDK');\n      }\n    };\n    var s = document.getElementsByTagName('script')[0];\n    s.parentNode.insertBefore(as, s);\n    var Identify = function Identify() {\n      this._q = [];\n      return this;\n    };\n    var identifyFuncs = ['add', 'append', 'clearAll', 'prepend', 'set', 'setOnce', 'unset', 'preInsert', 'postInsert', 'remove', 'getUserProperties'];\n    for (var i = 0; i < identifyFuncs.length; i++) {\n      proxy(Identify, identifyFuncs[i]);\n    }\n    amplitude.Identify = Identify;\n    var Revenue = function Revenue() {\n      this._q = [];\n      return this;\n    };\n    var revenueFuncs = ['getEventProperties', 'setProductId', 'setQuantity', 'setPrice', 'setRevenue', 'setRevenueType', 'setReceipt', 'setReceiptSig', 'setCurrency', 'setEventProperties'];\n    for (var j = 0; j < revenueFuncs.length; j++) {\n      proxy(Revenue, revenueFuncs[j]);\n    }\n    amplitude.Revenue = Revenue;\n    var funcs = ['getDeviceId', 'setDeviceId', 'getSessionId', 'setSessionId', 'getUserId', 'setUserId', 'setOptOut', 'setTransport', 'reset', 'extendSession'];\n    var funcsWithPromise = ['init', 'add', 'remove', 'track', 'logEvent', 'identify', 'groupIdentify', 'setGroup', 'revenue', 'flush'];\n    setUpProxy(amplitude);\n    amplitude.createInstance = function (instanceName) {\n      amplitude._iq[instanceName] = {\n        _q: []\n      };\n      setUpProxy(amplitude._iq[instanceName]);\n      return amplitude._iq[instanceName];\n    };\n    window.amplitude = amplitude;\n  }\n}(window, document);"
  },
  {
    "path": "packages/analytics-browser/jest.config.js",
    "content": "const baseConfig = require('../../jest.config.js');\nconst package = require('./package');\n\nmodule.exports = {\n  ...baseConfig,\n  displayName: package.name,\n  setupFiles: ['./test/setup.js'],\n  rootDir: '.',\n  testEnvironment: 'jsdom',\n  coveragePathIgnorePatterns: ['snippet-index.ts', 'global-scope.ts'],\n};\n"
  },
  {
    "path": "packages/analytics-browser/package.json",
    "content": "{\n  \"name\": \"@amplitude/analytics-browser\",\n  \"version\": \"2.42.3\",\n  \"description\": \"Official Amplitude SDK for Web\",\n  \"keywords\": [\n    \"analytics\",\n    \"amplitude\"\n  ],\n  \"author\": \"Amplitude Inc\",\n  \"homepage\": \"https://github.com/amplitude/Amplitude-TypeScript\",\n  \"license\": \"MIT\",\n  \"main\": \"lib/cjs/index.js\",\n  \"module\": \"lib/esm/index.js\",\n  \"types\": \"lib/esm/index.d.ts\",\n  \"sideEffects\": false,\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"tag\": \"latest\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/amplitude/Amplitude-TypeScript.git\"\n  },\n  \"scripts\": {\n    \"build\": \"pnpm bundle && pnpm build:es5 && pnpm build:esm\",\n    \"bundle\": \"rollup --config rollup.config.js\",\n    \"build:es5\": \"tsc -p ./tsconfig.es5.json\",\n    \"build:esm\": \"tsc -p ./tsconfig.esm.json\",\n    \"watch\": \"tsc -p ./tsconfig.esm.json --watch\",\n    \"clean\": \"rimraf node_modules lib coverage\",\n    \"fix\": \"pnpm fix:eslint & pnpm fix:prettier\",\n    \"fix:eslint\": \"eslint '{src,test}/**/*.ts' --fix\",\n    \"fix:prettier\": \"prettier --write \\\"{src,test}/**/*.ts\\\"\",\n    \"lint\": \"pnpm lint:eslint & pnpm lint:prettier\",\n    \"lint:eslint\": \"eslint '{src,test}/**/*.ts'\",\n    \"lint:prettier\": \"prettier --check \\\"{src,test}/**/*.ts\\\"\",\n    \"playground:html\": \"cp lib/scripts/amplitude-min.js playground/html/amplitude.js && http-server ./playground/html\",\n    \"playground:react-spa\": \"cp lib/scripts/amplitude-min.js playground/react-spa/public/amplitude.js && cd ./playground/react-spa && pnpm install && pnpm start\",\n    \"publish\": \"pnpm publish:s3 && pnpm publish:gtm-snippet\",\n    \"publish:s3\": \"node ../../scripts/publish/upload-to-s3.js\",\n    \"publish:gtm-snippet\": \"cd ../gtm-snippet && pnpm build && pnpm publish:s3\",\n    \"test\": \"jest\",\n    \"test:playwright\": \"playwright test\",\n    \"typecheck\": \"tsc -p ./tsconfig.json\",\n    \"version\": \"pnpm version-file && GENERATE_SNIPPET=true pnpm build && cp lib/scripts/amplitude-min.js playground/html/amplitude.js && cp lib/scripts/amplitude-min.js playground/react-spa/public/amplitude.js\",\n    \"version-file\": \"node -p \\\"'export const VERSION = \\\\'' + require('./package.json').version + '\\\\';'\\\" > src/version.ts\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/amplitude/Amplitude-TypeScript/issues\"\n  },\n  \"dependencies\": {\n    \"@amplitude/analytics-core\": \"workspace:*\",\n    \"@amplitude/plugin-autocapture-browser\": \"workspace:*\",\n    \"@amplitude/plugin-custom-enrichment-browser\": \"workspace:*\",\n    \"@amplitude/plugin-event-property-attribution-browser\": \"workspace:*\",\n    \"@amplitude/plugin-network-capture-browser\": \"workspace:*\",\n    \"@amplitude/plugin-page-url-enrichment-browser\": \"workspace:*\",\n    \"@amplitude/plugin-page-view-tracking-browser\": \"workspace:*\",\n    \"@amplitude/plugin-web-vitals-browser\": \"workspace:*\",\n    \"tslib\": \"^2.4.1\"\n  },\n  \"devDependencies\": {\n    \"@aws-sdk/client-s3\": \"^3.229.0\",\n    \"@rollup/plugin-commonjs\": \"^23.0.4\",\n    \"@rollup/plugin-node-resolve\": \"^15.0.1\",\n    \"@rollup/plugin-typescript\": \"^10.0.1\",\n    \"fake-indexeddb\": \"4.0.2\",\n    \"http-server\": \"^14.1.1\",\n    \"isomorphic-fetch\": \"^3.0.0\",\n    \"rollup\": \"^2.79.1\",\n    \"rollup-plugin-execute\": \"^1.1.1\",\n    \"rollup-plugin-gzip\": \"^3.1.0\",\n    \"rollup-plugin-sourcemaps\": \"^0.6.3\",\n    \"rollup-plugin-terser\": \"^7.0.2\"\n  },\n  \"files\": [\n    \"lib\"\n  ]\n}\n"
  },
  {
    "path": "packages/analytics-browser/playground/html/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n    <title>Amplitude SDK Playground</title>\n  </head>\n  <script src=\"./amplitude.js\"></script>\n\t\n  <script>\n    amplitude.init('API_KEY', 'playground.user@amplitude.com');\n  </script>\n  <body>\n    <h1>Amplitude SDK Playground</h1>\n    <p>This playground has Amplitude SDK script loaded, initialized, and available as <code>amplitude</code>.</p>\n    <ul>\n      <li>Check if you have a valid API KEY</li>\n      <li>Open Developer Tools</li>\n      <li>Go to Console tab</li>\n      <li>Play with the SDK</li>\n    </ul>\n  </body>\n</html>\n"
  },
  {
    "path": "packages/analytics-browser/playground/react-spa/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.js\n\n# testing\n/coverage\n\n# production\n/build\n\n# misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n"
  },
  {
    "path": "packages/analytics-browser/playground/react-spa/README.md",
    "content": "# Getting Started with Create React App\n\nThis project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).\n\n## Available Scripts\n\nIn the project directory, you can run:\n\n### `npm start`\n\nRuns the app in the development mode.\\\nOpen [http://localhost:3000](http://localhost:3000) to view it in the browser.\n\nThe page will reload if you make edits.\\\nYou will also see any lint errors in the console.\n\n### `npm run start:dev`\n\nRuns the app in the development mode with the local build of analytics-browser script.\\\nOpen [http://localhost:3000](http://localhost:3000) to view it in the browser.\n\nThe page will reload if you make edits.\\\nYou will also see any lint errors in the console.\n\n### `npm test`\n\nLaunches the test runner in the interactive watch mode.\\\nSee the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.\n\n### `npm run build`\n\nBuilds the app for production to the `build` folder.\\\nIt correctly bundles React in production mode and optimizes the build for the best performance.\n\nThe build is minified and the filenames include the hashes.\\\nYour app is ready to be deployed!\n\nSee the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.\n\n### `npm run eject`\n\n**Note: this is a one-way operation. Once you `eject`, you can’t go back!**\n\nIf you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.\n\nInstead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.\n\nYou don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.\n\n## Learn More\n\nYou can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).\n\nTo learn React, check out the [React documentation](https://reactjs.org/).\n"
  },
  {
    "path": "packages/analytics-browser/playground/react-spa/package.json",
    "content": "{\n  \"name\": \"react-app\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"dependencies\": {\n    \"@testing-library/jest-dom\": \"^5.16.5\",\n    \"@testing-library/react\": \"^13.4.0\",\n    \"@testing-library/user-event\": \"^14.4.3\",\n    \"@types/jest\": \"^29.2.4\",\n    \"@types/node\": \"^18.11.14\",\n    \"@types/react\": \"^18.0.26\",\n    \"@types/react-dom\": \"^18.0.9\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"react-helmet\": \"^6.1.0\",\n    \"react-router-dom\": \"^6.22.1\",\n    \"react-scripts\": \"5.0.1\",\n    \"typescript\": \"^4.6.3\",\n    \"web-vitals\": \"^3.1.0\"\n  },\n  \"scripts\": {\n    \"buildSDK\": \"cd ../../../analytics-browser && yarn build\",\n    \"installSDK\": \"cp ../../../analytics-browser/lib/scripts/amplitude-min.js ./public/amplitude.js\",\n    \"start:dev\": \"yarn buildSDK && yarn installSDK && yarn start\",\n    \"start\": \"react-scripts start\",\n    \"build\": \"react-scripts build\",\n    \"test\": \"react-scripts test\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"eslintConfig\": {\n    \"extends\": [\n      \"react-app\",\n      \"react-app/jest\"\n    ]\n  },\n  \"browserslist\": {\n    \"production\": [\n      \">0.2%\",\n      \"not dead\",\n      \"not op_mini all\"\n    ],\n    \"development\": [\n      \"last 1 chrome version\",\n      \"last 1 firefox version\",\n      \"last 1 safari version\"\n    ]\n  }\n}\n"
  },
  {
    "path": "packages/analytics-browser/playground/react-spa/public/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <link rel=\"icon\" href=\"%PUBLIC_URL%/favicon.ico\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <meta name=\"theme-color\" content=\"#000000\" />\n    <meta\n      name=\"description\"\n      content=\"Web site created using create-react-app\"\n    />\n    <link rel=\"apple-touch-icon\" href=\"%PUBLIC_URL%/logo192.png\" />\n    <!--\n      manifest.json provides metadata used when your web app is installed on a\n      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/\n    -->\n    <link rel=\"manifest\" href=\"%PUBLIC_URL%/manifest.json\" />\n    <!--\n      Notice the use of %PUBLIC_URL% in the tags above.\n      It will be replaced with the URL of the `public` folder during the build.\n      Only files inside the `public` folder can be referenced from the HTML.\n\n      Unlike \"/favicon.ico\" or \"favicon.ico\", \"%PUBLIC_URL%/favicon.ico\" will\n      work correctly both with client-side routing and a non-root public URL.\n      Learn how to configure a non-root public URL by running `npm run build`.\n    -->\n    <script src=\"./amplitude.js\"></script>\n    \n    <script>\n      /*\n       Calling init() requires an API key\n       ```\n         amplitude.init(API_KEY)\n       ```\n\n       Optionally, a user id can be provided when calling init()\n       ```\n        amplitude.init(API_KEY, 'example.react.user@amplitude.com')\n       ```\n\n       Optionally, a config object can be provided. Refer to https://amplitude.github.io/Amplitude-TypeScript/interfaces/Types.BrowserConfig.html\n       for object properties.\n      */\n\n      amplitude.init('API-KEY', 'spa-react-123@amplitude.com');\n    </script>\n    <title>React App</title>\n  </head>\n  <body>\n    <noscript>You need to enable JavaScript to run this app.</noscript>\n    <div id=\"root\"></div>\n    <!--\n      This HTML file is a template.\n      If you open it directly in the browser, you will see an empty page.\n\n      You can add webfonts, meta tags, or analytics to this file.\n      The build step will place the bundled scripts into the <body> tag.\n\n      To begin the development, run `npm start` or `yarn start`.\n      To create a production bundle, use `npm run build` or `yarn build`.\n    -->\n  </body>\n</html>\n"
  },
  {
    "path": "packages/analytics-browser/playground/react-spa/public/manifest.json",
    "content": "{\n  \"short_name\": \"React App\",\n  \"name\": \"Create React App Sample\",\n  \"icons\": [\n    {\n      \"src\": \"favicon.ico\",\n      \"sizes\": \"64x64 32x32 24x24 16x16\",\n      \"type\": \"image/x-icon\"\n    },\n    {\n      \"src\": \"logo192.png\",\n      \"type\": \"image/png\",\n      \"sizes\": \"192x192\"\n    },\n    {\n      \"src\": \"logo512.png\",\n      \"type\": \"image/png\",\n      \"sizes\": \"512x512\"\n    }\n  ],\n  \"start_url\": \".\",\n  \"display\": \"standalone\",\n  \"theme_color\": \"#000000\",\n  \"background_color\": \"#ffffff\"\n}\n"
  },
  {
    "path": "packages/analytics-browser/playground/react-spa/public/robots.txt",
    "content": "# https://www.robotstxt.org/robotstxt.html\nUser-agent: *\nDisallow:\n"
  },
  {
    "path": "packages/analytics-browser/playground/react-spa/src/App.css",
    "content": ".App {\n  text-align: center;\n}\n\n.App-logo {\n  height: 40vmin;\n  pointer-events: none;\n}\n\n@media (prefers-reduced-motion: no-preference) {\n  .App-logo {\n    animation: App-logo-spin infinite 20s linear;\n  }\n}\n\n.App-header {\n  background-color: #282c34;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n  font-size: calc(10px + 2vmin);\n  color: white;\n}\n\n.App-link {\n  color: #61dafb;\n}\n\nul.header {\n  background-color: #111;\n  padding: 0;\n}\n\nul.header li {\n  display: inline;\n  list-style-type: none;\n  margin: 0;\n}\n\nul.header li a {\n  color: #fff;\n  font-weight: 700;\n  text-decoration: none;\n  padding: 20px;\n  display: inline-block;\n}\n\nbutton {\n  margin: 30px;\n}\n\n@keyframes App-logo-spin {\n  from {\n    transform: rotate(0deg);\n  }\n  to {\n    transform: rotate(360deg);\n  }\n}\n"
  },
  {
    "path": "packages/analytics-browser/playground/react-spa/src/App.test.tsx",
    "content": "import { render, screen } from '@testing-library/react';\nimport App from './App';\n\ntest('renders learn react link', () => {\n  render(<App />);\n  const linkElement = screen.getByText(/learn react/i);\n  expect(linkElement).toBeInTheDocument();\n});\n"
  },
  {
    "path": "packages/analytics-browser/playground/react-spa/src/App.tsx",
    "content": "import logo from './logo.svg';\nimport './App.css';\nimport {\n    Route,\n    Routes,\n    NavLink,\n    HashRouter\n  } from \"react-router-dom\";\n\nimport Home from \"./Home\";\nimport Other from \"./Other\";\nimport Contact from \"./Contact\";\n\nfunction App() {\n  return (\n    <HashRouter>\n    <div className=\"App\">\n      <header className=\"App-header\">\n        <img src={logo} className=\"App-logo\" alt=\"logo\" />\n      </header>\n      <div>\n            <h1>Amplitude Analytics Browser Example with React</h1>\n            <ul className=\"header\">\n              <li><NavLink to=\"/home\">Home</NavLink></li>\n              <li><NavLink to=\"/other\">Other</NavLink></li>\n              <li><NavLink to=\"/contact\">Contact</NavLink></li>\n            </ul>\n            <div className=\"content\">\n                <Routes>\n                 <Route path=\"/home\"  element={<Home/>}/>\n                 <Route path=\"/other\"  element={<Other/>}/>\n                 <Route path=\"/contact\"  element={<Contact/>}/>\n               </Routes>\n            </div>\n          </div>\n    </div>\n    </HashRouter>\n  );\n}\n\nexport default App;\n"
  },
  {
    "path": "packages/analytics-browser/playground/react-spa/src/Contact.tsx",
    "content": "function Contact() {\n  return (\n   <div>Please file a bug in the <a href='https://github.com/amplitude/Amplitude-TypeScript'>github repo</a> if there has any issue.</div>\n  );\n}\n\nexport default Contact;\n"
  },
  {
    "path": "packages/analytics-browser/playground/react-spa/src/Home.tsx",
    "content": "function Home() {\n  return (\n    <div>\n    <h1>Please test the track function</h1>\n    <button onClick={() => (window as any).amplitude.track('Button Click', { name: 'App' })}>\n        Track\n    </button>\n    </div>\n  );\n}\n\nexport default Home;\n"
  },
  {
    "path": "packages/analytics-browser/playground/react-spa/src/Other.tsx",
    "content": "function Other() {\n  return (\n    <div>\n    <h1>Test other functions here</h1>\n    <button onClick={() => (window as any).amplitude.identify(new (window as any).amplitude.Identify().set('role', 'engineer'))}>\n        Identify\n    </button>\n    <button onClick={() => (window as any).amplitude.setGroup('org', 'engineering')}>\n        Group\n    </button>\n    <button onClick={() => (window as any).amplitude.groupIdentify('org', 'engineering', new (window as any).amplitude.Identify().set('technology', 'react.js'))}>\n          Group Identify\n    </button>\n    </div>\n\n  );\n}\n\nexport default Other;\n"
  },
  {
    "path": "packages/analytics-browser/playground/react-spa/src/index.css",
    "content": "body {\n  margin: 0;\n  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',\n    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',\n    sans-serif;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\ncode {\n  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',\n    monospace;\n}\n"
  },
  {
    "path": "packages/analytics-browser/playground/react-spa/src/index.tsx",
    "content": "import React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport './index.css';\nimport App from './App';\n\nconst root = ReactDOM.createRoot(\n  document.getElementById('root') as HTMLElement\n);\nroot.render(\n  <React.StrictMode>\n    <App />\n  </React.StrictMode>\n);"
  },
  {
    "path": "packages/analytics-browser/playground/react-spa/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es5\",\n    \"lib\": [\n      \"dom\",\n      \"dom.iterable\",\n      \"esnext\"\n    ],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"esModuleInterop\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"strict\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"noFallthroughCasesInSwitch\": true,\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"noEmit\": true,\n    \"jsx\": \"react-jsx\"\n  },\n  \"include\": [\n    \"src\"\n  ]\n}\n"
  },
  {
    "path": "packages/analytics-browser/playwright.config.ts",
    "content": "import { defineConfig } from '@playwright/test';\nimport baseConfig from '../../playwright.config';\n\nexport default defineConfig({\n  ...baseConfig,\n});\n"
  },
  {
    "path": "packages/analytics-browser/rollup.config.js",
    "content": "import { umd, iife, snippet, iifeGTM, snippetGTM, bookmarklet } from '../../scripts/build/rollup.config';\n\nexport default [umd, iife, snippet, iifeGTM, snippetGTM, bookmarklet];\n"
  },
  {
    "path": "packages/analytics-browser/src/__mocks__/det-notification.ts",
    "content": "export const detNotify = () => undefined;\n\nexport const resetNotify = () => undefined;\n"
  },
  {
    "path": "packages/analytics-browser/src/attribution/helpers.ts",
    "content": "import {\n  createIdentifyEvent,\n  Identify,\n  ILogger,\n  Campaign,\n  BASE_CAMPAIGN,\n  getGlobalScope,\n  TrackingMethod,\n} from '@amplitude/analytics-core';\n\nimport { ExcludeInternalReferrersOptions, EXCLUDE_INTERNAL_REFERRERS_CONDITIONS } from '../types';\n\nexport interface Options {\n  excludeReferrers?: (string | RegExp)[];\n  excludeInternalReferrers?: true | false | ExcludeInternalReferrersOptions;\n  initialEmptyValue?: string;\n  resetSessionOnNewCampaign?: boolean;\n  trackingMethod?: TrackingMethod | TrackingMethod[];\n  fallbackAttributionEvent?: boolean;\n  optOut?: boolean;\n}\n\nconst domainWithoutSubdomain = (domain: string) => {\n  const parts = domain.split('.');\n\n  if (parts.length <= 2) {\n    return domain;\n  }\n\n  return parts.slice(parts.length - 2, parts.length).join('.');\n};\n\n//Direct traffic mean no external referral, no UTMs, no click-ids, and no other customer identified marketing campaign url params.\nconst isDirectTraffic = (current: Campaign) => {\n  return Object.values(current).every((value) => !value);\n};\n\nconst isEmptyCampaign = (campaign: Campaign) => {\n  const campaignWithoutReferrer = { ...campaign, referring_domain: undefined, referrer: undefined };\n  return Object.values(campaignWithoutReferrer).every((value) => !value);\n};\n\nexport const isNewCampaign = (\n  current: Campaign,\n  previous: Campaign | undefined,\n  options: Options,\n  logger: ILogger,\n  isNewSession = true,\n  topLevelDomain?: string,\n) => {\n  const { referrer, referring_domain, ...currentCampaign } = current;\n  const { referrer: _previous_referrer, referring_domain: prevReferringDomain, ...previousCampaign } = previous || {};\n\n  const { excludeInternalReferrers } = options;\n\n  if (excludeInternalReferrers) {\n    const condition = getExcludeInternalReferrersCondition(excludeInternalReferrers, logger);\n    if (\n      !(condition instanceof TypeError) &&\n      current.referring_domain &&\n      isInternalReferrer(current.referring_domain, topLevelDomain)\n    ) {\n      if (condition === 'always') {\n        debugLogInternalReferrerExclude(condition, current.referring_domain, logger);\n        return false;\n      } else if (condition === 'ifEmptyCampaign' && isEmptyCampaign(current)) {\n        debugLogInternalReferrerExclude(condition, current.referring_domain, logger);\n        return false;\n      }\n    }\n  }\n\n  if (isExcludedReferrer(options.excludeReferrers, current.referring_domain)) {\n    // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n    logger.debug(`This is not a new campaign because ${current.referring_domain} is in the exclude referrer list.`);\n    return false;\n  }\n\n  //In the same session, direct traffic should not override or unset any persisting query params\n  if (!isNewSession && isDirectTraffic(current) && previous) {\n    logger.debug('This is not a new campaign because this is a direct traffic in the same session.');\n    return false;\n  }\n\n  const hasNewCampaign = JSON.stringify(currentCampaign) !== JSON.stringify(previousCampaign);\n  const hasNewDomain =\n    domainWithoutSubdomain(referring_domain || '') !== domainWithoutSubdomain(prevReferringDomain || '');\n\n  const result = !previous || hasNewCampaign || hasNewDomain;\n\n  if (!result) {\n    logger.debug(\"This is not a new campaign because it's the same as the previous one.\");\n  } else {\n    logger.debug(`This is a new campaign. An $identify event will be sent.`);\n  }\n\n  return result;\n};\n\nexport const isExcludedReferrer = (excludeReferrers: (string | RegExp)[] = [], referringDomain = '') => {\n  return excludeReferrers.some((value) =>\n    value instanceof RegExp ? value.test(referringDomain) : value === referringDomain,\n  );\n};\n\nexport const isSubdomainOf = (subDomain: string, domain: string) => {\n  const cookieDomainWithLeadingDot = domain.startsWith('.') ? domain : `.${domain}`;\n  const subDomainWithLeadingDot = subDomain.startsWith('.') ? subDomain : `.${subDomain}`;\n  if (subDomainWithLeadingDot.endsWith(cookieDomainWithLeadingDot)) return true;\n  return false;\n};\n\nexport const createCampaignEvent = (campaign: Campaign, options: Options) => {\n  const campaignParameters: Campaign = {\n    // This object definition allows undefined keys to be iterated on\n    // in .reduce() to build indentify object\n    ...BASE_CAMPAIGN,\n    ...campaign,\n  };\n  const identifyEvent = Object.entries(campaignParameters).reduce((identify, [key, value]) => {\n    identify.setOnce(`initial_${key}`, value ?? options.initialEmptyValue ?? 'EMPTY');\n    if (value) {\n      return identify.set(key, value);\n    }\n    return identify.unset(key);\n  }, new Identify());\n\n  return createIdentifyEvent(identifyEvent);\n};\n\nexport const getDefaultExcludedReferrers = (cookieDomain: string | undefined) => {\n  let domain = cookieDomain;\n  if (domain) {\n    if (domain.startsWith('.')) {\n      domain = domain.substring(1);\n    }\n    return [new RegExp(`${domain.replace('.', '\\\\.')}$`)];\n  }\n  return [];\n};\n\n/**\n * Parses the excludeInternalReferrers configuration to determine the condition on which to\n * exclude internal referrers for campaign attribution.\n *\n * If the config is invalid type, log and return a TypeError.\n *\n * (this does explicit type checking so don't have to rely on TS compiler to catch invalid types)\n *\n * @param excludeInternalReferrers - attribution.excludeInternalReferrers configuration\n * @param logger - logger instance to log error when TypeError\n * @returns The condition if the config is valid, TypeError if the config is invalid.\n */\nconst getExcludeInternalReferrersCondition = (\n  excludeInternalReferrers: ExcludeInternalReferrersOptions | boolean,\n  logger: ILogger,\n): ExcludeInternalReferrersOptions['condition'] | TypeError => {\n  if (excludeInternalReferrers === true) {\n    return EXCLUDE_INTERNAL_REFERRERS_CONDITIONS.always;\n  }\n  if (typeof excludeInternalReferrers === 'object') {\n    const { condition } = excludeInternalReferrers;\n    if (typeof condition === 'string' && Object.keys(EXCLUDE_INTERNAL_REFERRERS_CONDITIONS).includes(condition)) {\n      return condition;\n    } else if (typeof condition === 'undefined') {\n      return EXCLUDE_INTERNAL_REFERRERS_CONDITIONS.always;\n    }\n  }\n  const errorMessage = `Invalid configuration provided for attribution.excludeInternalReferrers: ${JSON.stringify(\n    excludeInternalReferrers,\n  )}`;\n  logger.error(errorMessage);\n  return new TypeError(errorMessage);\n};\n\n// helper function to log debug message when internal referrer is excluded\n// (added this to prevent code duplication and improve readability)\nfunction debugLogInternalReferrerExclude(\n  condition: ExcludeInternalReferrersOptions['condition'],\n  referringDomain: string,\n  logger: ILogger,\n) {\n  const baseMessage = `This is not a new campaign because referring_domain=${referringDomain} is on the same domain as the current page and it is configured to exclude internal referrers`;\n  if (condition === 'always') {\n    logger.debug(baseMessage);\n  } else if (condition === 'ifEmptyCampaign') {\n    logger.debug(`${baseMessage} with empty campaign parameters`);\n  }\n}\n\n// list of domains that are known ccTLDs that are commonly used\n// and are in the Public Suffix List (https://publicsuffix.org/)\nexport const KNOWN_2LDS = [\n  'ac.in',\n  'ac.jp',\n  'ac.kr',\n  'ac.th',\n  'ac.uk',\n  'ac.za',\n  'appspot.com',\n  'asn.au',\n  'azurewebsites.net',\n  'cloudfront.net',\n  'myshopify.com',\n  'blogspot.com',\n  'co.ca',\n  'co.in',\n  'co.jp',\n  'co.kr',\n  'co.nz',\n  'co.th',\n  'co.uk',\n  'co.za',\n  'com.ar',\n  'com.au',\n  'com.br',\n  'com.cn',\n  'com.hk',\n  'com.in',\n  'com.jp',\n  'com.kr',\n  'com.mx',\n  'com.pl',\n  'com.sg',\n  'com.tr',\n  'com.tw',\n  'ed.jp',\n  'edu.au',\n  'edu.br',\n  'edu.cn',\n  'edu.hk',\n  'edu.sg',\n  'edu.th',\n  'edu.tr',\n  'edu.tw',\n  'firebaseapp.com',\n  'fly.dev',\n  'gc.ca',\n  'geek.nz',\n  'github.io',\n  'gitlab.io',\n  'go.jp',\n  'go.kr',\n  'go.th',\n  'gob.ar',\n  'gob.mx',\n  'gov.au',\n  'gov.br',\n  'gov.cn',\n  'gov.hk',\n  'gov.in',\n  'gov.pl',\n  'gov.sg',\n  'gov.tr',\n  'gov.tw',\n  'gov.uk',\n  'gov.za',\n  'govt.nz',\n  'gr.jp',\n  'herokuapp.com',\n  'id.au',\n  'idv.hk',\n  'iwi.nz',\n  'lg.jp',\n  'ltd.uk',\n  'maori.nz',\n  'me.uk',\n  'mil.kr',\n  'ne.jp',\n  'ne.kr',\n  'net.au',\n  'net.br',\n  'net.cn',\n  'net.hk',\n  'net.in',\n  'net.nz',\n  'net.pl',\n  'net.sg',\n  'net.tr',\n  'net.tw',\n  'net.za',\n  'onrender.com',\n  'or.jp',\n  'or.kr',\n  'or.th',\n  'org.ar',\n  'org.au',\n  'org.br',\n  'org.cn',\n  'org.hk',\n  'org.in',\n  'org.mx',\n  'org.nz',\n  'org.pl',\n  'org.sg',\n  'org.tw',\n  'org.uk',\n  'org.za',\n  'pages.dev',\n  'pe.kr',\n  'plc.uk',\n  're.kr',\n  'res.in',\n  'sch.uk',\n  'vercel.app',\n  'netlify.app',\n  'workers.dev',\n];\n\nexport const getDomain = (hostnameParam?: string) => {\n  /* istanbul ignore next */\n  const hostname = hostnameParam || getGlobalScope()?.location?.hostname;\n  if (!hostname) {\n    return '';\n  }\n  const parts = hostname.split('.');\n  let tld = parts[parts.length - 1];\n  let name = parts[parts.length - 2];\n  if (KNOWN_2LDS.find((tld) => hostname.endsWith(`.${tld}`))) {\n    tld = parts[parts.length - 2] + '.' + parts[parts.length - 1];\n    name = parts[parts.length - 3];\n  }\n\n  if (!name) return tld;\n\n  return `${name}.${tld}`;\n};\n\nconst isInternalReferrer = (referringDomain: string, topLevelDomain?: string) => {\n  const globalScope = getGlobalScope();\n  /* istanbul ignore if */\n  if (!globalScope) return false;\n  // if referring domain is subdomain of config.cookieDomain, return true\n  const internalDomain = (topLevelDomain || '').trim() || getDomain(globalScope.location.hostname);\n  return isSubdomainOf(referringDomain, internalDomain);\n};\n"
  },
  {
    "path": "packages/analytics-browser/src/attribution/tracking-methods.ts",
    "content": "import { AttributionOptions, TrackingMethod } from '@amplitude/analytics-core';\n\nexport const USER_PROPERTY_TRACKING_METHOD: TrackingMethod = 'userProperty';\nexport const EVENT_PROPERTY_TRACKING_METHOD: TrackingMethod = 'eventProperty';\n\nconst isTrackingMethod = (value: unknown): value is TrackingMethod =>\n  value === USER_PROPERTY_TRACKING_METHOD || value === EVENT_PROPERTY_TRACKING_METHOD;\n\n/**\n * Normalizes attribution tracking methods from runtime config, drops unsupported values,\n * and falls back to the legacy default when nothing valid is provided.\n */\nexport const normalizeTrackingMethod = (trackingMethod?: unknown): TrackingMethod[] => {\n  const normalized = [\n    ...new Set((Array.isArray(trackingMethod) ? trackingMethod : [trackingMethod]).filter(isTrackingMethod)),\n  ];\n\n  return normalized.length > 0 ? normalized : [USER_PROPERTY_TRACKING_METHOD];\n};\n\nexport const hasTrackingMethod = (options: AttributionOptions, trackingMethod: TrackingMethod) =>\n  normalizeTrackingMethod(options.trackingMethod).includes(trackingMethod);\n\nexport const isUserPropertyAttributionEnabled = (options: AttributionOptions) =>\n  hasTrackingMethod(options, USER_PROPERTY_TRACKING_METHOD);\n\nexport const isEventPropertyAttributionEnabled = (options: AttributionOptions) =>\n  hasTrackingMethod(options, EVENT_PROPERTY_TRACKING_METHOD);\n"
  },
  {
    "path": "packages/analytics-browser/src/attribution/web-attribution.ts",
    "content": "import {\n  BrowserConfig,\n  ILogger,\n  Storage,\n  getStorageKey,\n  isNewSession,\n  Campaign,\n  BASE_CAMPAIGN,\n  CampaignParser,\n} from '@amplitude/analytics-core';\nimport { Options, getDefaultExcludedReferrers, createCampaignEvent, isNewCampaign } from './helpers';\n\nexport class WebAttribution {\n  options: Options;\n  storage: Storage<Campaign>;\n  storageKey: string;\n  webExpStorageKey: string;\n  previousCampaign?: Campaign;\n  currentCampaign: Campaign;\n  shouldTrackNewCampaign = false;\n  sessionTimeout: number;\n  lastEventTime?: number;\n  logger: ILogger;\n  topLevelDomain?: string;\n  constructor(options: Options, config: BrowserConfig) {\n    this.options = {\n      initialEmptyValue: 'EMPTY',\n      resetSessionOnNewCampaign: false,\n      excludeReferrers: getDefaultExcludedReferrers(config.cookieOptions?.domain || config.topLevelDomain),\n      optOut: config.optOut,\n      ...options,\n    };\n    this.storage = config.cookieStorage as unknown as Storage<Campaign>;\n    this.storageKey = getStorageKey(config.apiKey, 'MKTG');\n    this.webExpStorageKey = getStorageKey(config.apiKey, 'MKTG_ORIGINAL');\n    this.currentCampaign = BASE_CAMPAIGN;\n    this.sessionTimeout = config.sessionTimeout;\n    this.lastEventTime = config.lastEventTime;\n    this.logger = config.loggerProvider;\n    this.topLevelDomain = config.topLevelDomain;\n    config.loggerProvider.log('Installing web attribution tracking.');\n  }\n\n  async init() {\n    // skip attribution if optOut is true\n    if (this.options.optOut) {\n      return;\n    }\n\n    [this.currentCampaign, this.previousCampaign] = await this.fetchCampaign();\n    const isEventInNewSession = !this.lastEventTime ? true : isNewSession(this.sessionTimeout, this.lastEventTime);\n\n    if (\n      isNewCampaign(\n        this.currentCampaign,\n        this.previousCampaign,\n        this.options,\n        this.logger,\n        isEventInNewSession,\n        this.topLevelDomain,\n      )\n    ) {\n      this.shouldTrackNewCampaign = true;\n      await this.storage.set(this.storageKey, this.currentCampaign);\n    }\n  }\n\n  async fetchCampaign() {\n    const originalCampaign = await this.storage.get(this.webExpStorageKey);\n    if (originalCampaign) {\n      await this.storage.remove(this.webExpStorageKey);\n    }\n    return await Promise.all([originalCampaign || new CampaignParser().parse(), this.storage.get(this.storageKey)]);\n  }\n\n  /**\n   * This can be called when enable web attribution and either\n   * 1. set a new session\n   * 2. has new campaign and enable resetSessionOnNewCampaign\n   */\n  generateCampaignEvent(event_id?: number) {\n    // Mark this campaign has been tracked\n    this.shouldTrackNewCampaign = false;\n    const campaignEvent = createCampaignEvent(this.currentCampaign, this.options);\n    if (event_id) {\n      campaignEvent.event_id = event_id;\n    }\n    return campaignEvent;\n  }\n\n  shouldSetSessionIdOnNewCampaign() {\n    return this.shouldTrackNewCampaign && !!this.options.resetSessionOnNewCampaign;\n  }\n}\n"
  },
  {
    "path": "packages/analytics-browser/src/browser-client-factory.ts",
    "content": "import { debugWrapper, getClientLogConfig, getClientStates, BrowserClient } from '@amplitude/analytics-core';\nimport { AmplitudeBrowser } from './browser-client';\n\nexport const createInstance = (): BrowserClient => {\n  const client = new AmplitudeBrowser();\n  return {\n    init: debugWrapper(\n      client.init.bind(client),\n      'init',\n      getClientLogConfig(client),\n      getClientStates(client, ['config']),\n    ),\n    add: debugWrapper(\n      client.add.bind(client),\n      'add',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.plugins']),\n    ),\n    remove: debugWrapper(\n      client.remove.bind(client),\n      'remove',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.plugins']),\n    ),\n    track: debugWrapper(\n      client.track.bind(client),\n      'track',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.queue.length']),\n    ),\n    logEvent: debugWrapper(\n      client.logEvent.bind(client),\n      'logEvent',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.queue.length']),\n    ),\n    identify: debugWrapper(\n      client.identify.bind(client),\n      'identify',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.queue.length']),\n    ),\n    groupIdentify: debugWrapper(\n      client.groupIdentify.bind(client),\n      'groupIdentify',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.queue.length']),\n    ),\n    setGroup: debugWrapper(\n      client.setGroup.bind(client),\n      'setGroup',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.queue.length']),\n    ),\n    revenue: debugWrapper(\n      client.revenue.bind(client),\n      'revenue',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.queue.length']),\n    ),\n    flush: debugWrapper(\n      client.flush.bind(client),\n      'flush',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.queue.length']),\n    ),\n    getUserId: debugWrapper(\n      client.getUserId.bind(client),\n      'getUserId',\n      getClientLogConfig(client),\n      getClientStates(client, ['config', 'config.userId']),\n    ),\n    setUserId: debugWrapper(\n      client.setUserId.bind(client),\n      'setUserId',\n      getClientLogConfig(client),\n      getClientStates(client, ['config', 'config.userId']),\n    ),\n    getDeviceId: debugWrapper(\n      client.getDeviceId.bind(client),\n      'getDeviceId',\n      getClientLogConfig(client),\n      getClientStates(client, ['config', 'config.deviceId']),\n    ),\n    setDeviceId: debugWrapper(\n      client.setDeviceId.bind(client),\n      'setDeviceId',\n      getClientLogConfig(client),\n      getClientStates(client, ['config', 'config.deviceId']),\n    ),\n    reset: debugWrapper(\n      client.reset.bind(client),\n      'reset',\n      getClientLogConfig(client),\n      getClientStates(client, ['config', 'config.userId', 'config.deviceId']),\n    ),\n    getSessionId: debugWrapper(\n      client.getSessionId.bind(client),\n      'getSessionId',\n      getClientLogConfig(client),\n      getClientStates(client, ['config']),\n    ),\n    setSessionId: debugWrapper(\n      client.setSessionId.bind(client),\n      'setSessionId',\n      getClientLogConfig(client),\n      getClientStates(client, ['config']),\n    ),\n    extendSession: debugWrapper(\n      client.extendSession.bind(client),\n      'extendSession',\n      getClientLogConfig(client),\n      getClientStates(client, ['config']),\n    ),\n    setOptOut: debugWrapper(\n      client.setOptOut.bind(client),\n      'setOptOut',\n      getClientLogConfig(client),\n      getClientStates(client, ['config']),\n    ),\n    setTransport: debugWrapper(\n      client.setTransport.bind(client),\n      'setTransport',\n      getClientLogConfig(client),\n      getClientStates(client, ['config']),\n    ),\n    getIdentity: debugWrapper(\n      client.getIdentity.bind(client),\n      'getIdentity',\n      getClientLogConfig(client),\n      getClientStates(client, ['config']),\n    ),\n    setIdentity: debugWrapper(\n      client.setIdentity.bind(client),\n      'setIdentity',\n      getClientLogConfig(client),\n      getClientStates(client, ['config', 'config.userId', 'config.deviceId']),\n    ),\n    getOptOut: debugWrapper(\n      client.getOptOut.bind(client),\n      'getOptOut',\n      getClientLogConfig(client),\n      getClientStates(client, ['config']),\n    ),\n    _setDiagnosticsSampleRate: debugWrapper(\n      client._setDiagnosticsSampleRate.bind(client),\n      '_setDiagnosticsSampleRate',\n      getClientLogConfig(client),\n      getClientStates(client, ['config']),\n    ),\n  };\n};\n\nexport default createInstance();\n"
  },
  {
    "path": "packages/analytics-browser/src/browser-client.ts",
    "content": "import {\n  AmplitudeCore,\n  Destination,\n  Identify,\n  returnWrapper,\n  Revenue,\n  UUID,\n  getAnalyticsConnector,\n  setConnectorDeviceId,\n  setConnectorUserId,\n  isNewSession,\n  IdentityEventSender,\n  getQueryParams,\n  Event,\n  EventOptions,\n  IIdentify,\n  IRevenue,\n  TransportTypeOrOptions,\n  OfflineDisabled,\n  Result,\n  BrowserOptions,\n  BrowserConfig,\n  BrowserClient,\n  AnalyticsClient,\n  AnalyticsIdentity,\n  IRemoteConfigClient,\n  RemoteConfigClient,\n  RemoteConfig,\n  Source,\n  DiagnosticsClient,\n  createIdentifyEvent,\n  Logger,\n  safeJsonStringify,\n  LogLevel,\n} from '@amplitude/analytics-core';\nimport {\n  getAttributionTrackingConfig,\n  getPageViewTrackingConfig,\n  getElementInteractionsConfig,\n  getNetworkTrackingConfig,\n  isAttributionTrackingEnabled,\n  isSessionTrackingEnabled,\n  isFileDownloadTrackingEnabled,\n  isFormInteractionTrackingEnabled,\n  isElementInteractionsEnabled,\n  isPageViewTrackingEnabled,\n  isNetworkTrackingEnabled,\n  isWebVitalsEnabled,\n  isFrustrationInteractionsEnabled,\n  getFrustrationInteractionsConfig,\n  isPerformanceTrackingEnabled,\n  getPerformanceTrackingConfig,\n  isPageUrlEnrichmentEnabled,\n  isCustomEnrichmentEnabled,\n} from './default-tracking';\nimport { convertProxyObjectToRealObject, isInstanceProxy } from './utils/snippet-helper';\nimport { Context } from './plugins/context';\nimport { useBrowserConfig, createTransport, shouldFetchRemoteConfig } from './config';\nimport { pageViewTrackingPlugin } from '@amplitude/plugin-page-view-tracking-browser';\nimport { formInteractionTracking } from './plugins/form-interaction-tracking';\nimport { fileDownloadTracking } from './plugins/file-download-tracking';\nimport { DEFAULT_SESSION_END_EVENT, DEFAULT_SESSION_START_EVENT, DEFAULT_SERVER_ZONE } from './constants';\nimport { detNotify } from './det-notification';\nimport { networkConnectivityCheckerPlugin } from './plugins/network-connectivity-checker';\nimport { updateBrowserConfigWithRemoteConfig } from './config/joined-config';\nimport { autocapturePlugin, frustrationPlugin, performancePlugin } from '@amplitude/plugin-autocapture-browser';\nimport { plugin as networkCapturePlugin } from '@amplitude/plugin-network-capture-browser';\nimport { webVitalsPlugin } from '@amplitude/plugin-web-vitals-browser';\nimport { WebAttribution } from './attribution/web-attribution';\nimport { eventPropertyTrackingPlugin } from '@amplitude/plugin-event-property-attribution-browser';\nimport { LIBPREFIX } from './lib-prefix';\nimport { VERSION } from './version';\nimport { pageUrlEnrichmentPlugin } from '@amplitude/plugin-page-url-enrichment-browser';\nimport { customEnrichmentPlugin } from '@amplitude/plugin-custom-enrichment-browser';\nimport { isEventPropertyAttributionEnabled, isUserPropertyAttributionEnabled } from './attribution/tracking-methods';\n\nconst UNSPECIFIED_SESSION_ID = -1;\n\n/**\n * Exported for `@amplitude/unified` or integration with blade plugins.\n * If you only use `@amplitude/analytics-browser`, use `amplitude.init()` or `amplitude.createInstance()` instead.\n */\nexport class AmplitudeBrowser extends AmplitudeCore implements BrowserClient, AnalyticsClient {\n  // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n  // @ts-ignore\n  config: BrowserConfig;\n  previousSessionDeviceId: string | undefined;\n  previousSessionUserId: string | undefined;\n  webAttribution: WebAttribution | undefined;\n\n  // Backdoor to set diagnostics sample rate\n  // by calling amplitude._setDiagnosticsSampleRate(1); before amplitude.init()\n  _diagnosticsSampleRate = 0;\n\n  init(apiKey = '', userIdOrOptions?: string | BrowserOptions, maybeOptions?: BrowserOptions) {\n    let userId: string | undefined;\n    let options: BrowserOptions | undefined;\n    if (arguments.length > 2) {\n      userId = userIdOrOptions as string | undefined;\n      options = maybeOptions;\n    } else {\n      if (typeof userIdOrOptions === 'string') {\n        userId = userIdOrOptions;\n        options = undefined;\n      } else {\n        userId = userIdOrOptions?.userId;\n        options = userIdOrOptions;\n      }\n    }\n    return returnWrapper(this._init({ ...options, userId, apiKey }));\n  }\n  protected async _init(options: BrowserOptions & { apiKey: string }) {\n    // Step 1: Block concurrent initialization\n    if (this.initializing) {\n      return;\n    }\n    this.initializing = true;\n\n    // Step 2: Create browser config\n    // Step 2.1: Determine if we should fetch remote config BEFORE creating browser config\n    // This allows us to get diagnostics settings before creating the DiagnosticsClient\n    const fetchRemoteConfig = shouldFetchRemoteConfig(options);\n\n    // Set up early dependencies needed for remote config client\n    // These use options directly or fall back to defaults\n    const loggerProvider = options.loggerProvider ?? new Logger();\n    if (!options.loggerProvider) {\n      loggerProvider.enable(options.logLevel ?? LogLevel.Warn);\n    }\n    const serverZone = options.serverZone ?? DEFAULT_SERVER_ZONE;\n\n    let remoteConfigClient: IRemoteConfigClient | undefined;\n    let diagnosticsSampleRate = this._diagnosticsSampleRate;\n    let enableDiagnostics = options.enableDiagnostics ?? true;\n\n    // Step 2.2: Fetch diagnostics config FIRST to get sample rate for DiagnosticsClient\n    // We want to create DiagnosticsClient as early as possible so it can track more data\n    /* istanbul ignore next */\n    if (fetchRemoteConfig) {\n      remoteConfigClient = new RemoteConfigClient(\n        options.apiKey,\n        loggerProvider,\n        serverZone,\n        /* istanbul ignore next */ options.remoteConfig?.serverUrl,\n      );\n\n      // Fetch diagnostics config first to get sample rate\n      await new Promise<void>((resolve) => {\n        // Disable coverage for this line because remote config client will always be defined in this case.\n        // istanbul ignore next\n        remoteConfigClient?.subscribe(\n          'configs.diagnostics.browserSDK',\n          'all',\n          (remoteConfig: RemoteConfig | null, source: Source, lastFetch: Date) => {\n            loggerProvider.debug(\n              'Diagnostics remote configuration received:',\n              JSON.stringify(\n                {\n                  remoteConfig,\n                  source,\n                  lastFetch,\n                },\n                null,\n                2,\n              ),\n            );\n            if (remoteConfig) {\n              // Validate and set sampleRate (must be a valid number)\n              const sampleRate = remoteConfig.sampleRate as number;\n              if (typeof sampleRate === 'number' && !isNaN(sampleRate)) {\n                diagnosticsSampleRate = sampleRate;\n              }\n\n              // Validate and set enabled (must be a boolean)\n              const enabled = remoteConfig.enabled as boolean;\n              if (typeof enabled === 'boolean') {\n                enableDiagnostics = enabled;\n              }\n            }\n            resolve();\n          },\n        );\n      });\n    }\n\n    // Step 2.3: Initialize diagnostics client as early as possible\n    // Now we have the sample rate from remote config (if fetched)\n    const diagnosticsClient = new DiagnosticsClient(options.apiKey, loggerProvider, serverZone, {\n      enabled: enableDiagnostics,\n      sampleRate: diagnosticsSampleRate,\n    });\n    diagnosticsClient.setTag('library', `${LIBPREFIX}/${VERSION}`);\n    if (typeof navigator !== 'undefined') {\n      diagnosticsClient.setTag('user_agent', navigator.userAgent);\n    }\n\n    // Step 2.4: Create browser config with diagnosticsClient and earlyConfig\n    // earlyConfig ensures consistent logger/serverZone/diagnostics settings across all components\n    const browserOptions = await useBrowserConfig(options.apiKey, options, this, diagnosticsClient, {\n      loggerProvider,\n      serverZone,\n      enableDiagnostics,\n      diagnosticsSampleRate,\n    });\n\n    // Step 2.5: Fetch analytics SDK remote config\n    // This is fetched after DiagnosticsClient is created so diagnostics can track any issues\n    /* istanbul ignore next */\n    if (fetchRemoteConfig && remoteConfigClient) {\n      await new Promise<void>((resolve) => {\n        // Disable coverage for this line because remote config client will always be defined in this case.\n        // istanbul ignore next\n        remoteConfigClient?.subscribe(\n          'configs.analyticsSDK.browserSDK',\n          'all',\n          (remoteConfig: RemoteConfig | null, source: Source, lastFetch: Date) => {\n            browserOptions.loggerProvider.debug(\n              'Remote configuration received:',\n              JSON.stringify(\n                {\n                  remoteConfig,\n                  source,\n                  lastFetch,\n                },\n                null,\n                2,\n              ),\n            );\n            if (remoteConfig) {\n              updateBrowserConfigWithRemoteConfig(remoteConfig, browserOptions);\n            }\n            // Resolve the promise on first callback (initial config)\n            resolve();\n          },\n        );\n      });\n    }\n\n    await super._init(browserOptions);\n    this.logBrowserOptions(browserOptions);\n\n    this.config.remoteConfigClient = remoteConfigClient;\n\n    const attributionTrackingOptions = getAttributionTrackingConfig(this.config);\n\n    // Add web attribution plugin\n    if (\n      isAttributionTrackingEnabled(this.config.defaultTracking) &&\n      isUserPropertyAttributionEnabled(attributionTrackingOptions)\n    ) {\n      if (this.config.optOut) {\n        this.timeline.addOptOutListener(async (optOut) => {\n          if (!optOut) {\n            this.webAttribution = new WebAttribution(attributionTrackingOptions, this.config);\n            await this.webAttribution.init();\n          }\n        });\n      }\n      this.webAttribution = new WebAttribution(attributionTrackingOptions, this.config);\n      // Fetch the current campaign, check if need to track web attribution later\n      await this.webAttribution.init();\n    }\n\n    // Step 3: Set session ID\n    // Priority 1: `options.sessionId`\n    // Priority 2: sessionId from url if it's Number and ampTimestamp is valid\n    // Priority 3: last known sessionId from user identity storage\n    // Default: `Date.now()`\n    // Session ID is handled differently than device ID and user ID due to session events\n    const queryParams = getQueryParams();\n\n    // Check if ampTimestamp is present and valid\n    const ampTimestamp = queryParams.ampTimestamp ? Number(queryParams.ampTimestamp) : undefined;\n    const isWithinTimeLimit = ampTimestamp ? Date.now() < ampTimestamp : true;\n\n    // check if we need to set the sessionId\n    const querySessionId =\n      isWithinTimeLimit && !Number.isNaN(Number(queryParams.ampSessionId))\n        ? Number(queryParams.ampSessionId)\n        : undefined;\n\n    let deferredSessionId = this.config.deferredSessionId;\n    if (deferredSessionId === UNSPECIFIED_SESSION_ID && !this.config.optOut) {\n      deferredSessionId = Date.now();\n    }\n\n    this.setSessionId(options.sessionId ?? querySessionId ?? deferredSessionId ?? this.config.sessionId);\n\n    if (this.config.optOut) {\n      this.timeline.addOptOutListener(async (optOut) => {\n        if (!optOut && this.config.deferredSessionId) {\n          if (this.config.deferredSessionId === UNSPECIFIED_SESSION_ID) {\n            this.setSessionId(undefined);\n          } else {\n            this.setSessionId(this.config.deferredSessionId);\n          }\n        }\n      });\n    }\n\n    // Set up the analytics connector to integrate with the experiment SDK.\n    // Send events from the experiment SDK and forward identifies to the\n    // identity store.\n    const connector = getAnalyticsConnector(options.instanceName);\n    connector.identityStore.setIdentity({\n      userId: this.config.userId,\n      deviceId: this.config.deviceId,\n    });\n\n    // Step 4: Install plugins\n    // Do not track any events before this\n    if (this.config.offline !== OfflineDisabled) {\n      await this.add(networkConnectivityCheckerPlugin()).promise;\n    }\n    await this.add(new Destination({ diagnosticsClient })).promise;\n    await this.add(new Context()).promise;\n    await this.add(new IdentityEventSender()).promise;\n\n    // Notify if DET is enabled\n    detNotify(this.config);\n\n    if (isFileDownloadTrackingEnabled(this.config.defaultTracking)) {\n      this.config.loggerProvider.debug('Adding file download tracking plugin');\n      await this.add(fileDownloadTracking()).promise;\n    }\n\n    if (isFormInteractionTrackingEnabled(this.config.defaultTracking)) {\n      this.config.loggerProvider.debug('Adding form interaction plugin');\n      await this.add(formInteractionTracking()).promise;\n    }\n\n    // Add page view plugin\n    if (isPageViewTrackingEnabled(this.config.defaultTracking)) {\n      if (!this.config.optOut) {\n        this.config.loggerProvider.debug('Adding page view tracking plugin');\n        await this.add(pageViewTrackingPlugin(getPageViewTrackingConfig(this.config))).promise;\n      } else {\n        this.timeline.addOptOutListener(async (optOut) => {\n          /* istanbul ignore if */\n          if (optOut) {\n            return;\n          }\n          this.config.loggerProvider.debug('Adding page view tracking plugin');\n          await this.add(pageViewTrackingPlugin(getPageViewTrackingConfig(this.config))).promise;\n        });\n      }\n    }\n\n    if (\n      isAttributionTrackingEnabled(this.config.defaultTracking) &&\n      isEventPropertyAttributionEnabled(attributionTrackingOptions)\n    ) {\n      this.config.loggerProvider.debug('Adding event property attribution plugin');\n      await this.add(eventPropertyTrackingPlugin(attributionTrackingOptions)).promise;\n    }\n\n    if (isElementInteractionsEnabled(this.config.autocapture)) {\n      this.config.loggerProvider.debug('Adding user interactions plugin (autocapture plugin)');\n      await this.add(autocapturePlugin(getElementInteractionsConfig(this.config), { diagnosticsClient })).promise;\n    }\n\n    if (isFrustrationInteractionsEnabled(this.config.autocapture)) {\n      this.config.loggerProvider.debug('Adding frustration interactions plugin');\n      await this.add(frustrationPlugin(getFrustrationInteractionsConfig(this.config))).promise;\n    }\n\n    if (isNetworkTrackingEnabled(this.config.autocapture)) {\n      this.config.loggerProvider.debug('Adding network tracking plugin');\n      await this.add(networkCapturePlugin(getNetworkTrackingConfig(this.config))).promise;\n    }\n\n    if (isWebVitalsEnabled(this.config.autocapture)) {\n      this.config.loggerProvider.debug('Adding web vitals plugin');\n      await this.add(webVitalsPlugin()).promise;\n    }\n\n    if (isPerformanceTrackingEnabled(this.config.autocapture)) {\n      this.config.loggerProvider.debug('Adding performance tracking plugin');\n      await this.add(performancePlugin(getPerformanceTrackingConfig(this.config))).promise;\n    }\n\n    if (isPageUrlEnrichmentEnabled(this.config.autocapture)) {\n      this.config.loggerProvider.debug('Adding referrer page url plugin');\n      await this.add(pageUrlEnrichmentPlugin()).promise;\n    }\n\n    if (isCustomEnrichmentEnabled(this.config.customEnrichment)) {\n      this.config.loggerProvider.debug('Adding custom enrichment plugin');\n      await this.add(customEnrichmentPlugin()).promise;\n    }\n\n    this.initializing = false;\n\n    // Step 6: Run queued dispatch functions\n    await this.runQueuedFunctions('dispatchQ');\n\n    // Step 7: Add the event receiver after running remaining queued functions.\n    connector.eventBridge.setEventReceiver((event) => {\n      const { time, ...cleanEventProperties } = event.eventProperties || {};\n      const eventOptions = typeof time === 'number' ? { time } : undefined;\n      void this.track(event.eventType, cleanEventProperties, eventOptions);\n    });\n  }\n\n  getUserId() {\n    return this.config?.userId;\n  }\n\n  setUserId(userId: string | undefined) {\n    if (!this.config) {\n      this.q.push(this.setUserId.bind(this, userId));\n      return;\n    }\n    this.config.loggerProvider.debug('function setUserId: ', userId);\n    if (userId !== this.config.userId || userId === undefined) {\n      this.config.userId = userId;\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n      this.timeline.onIdentityChanged({ userId: userId });\n      setConnectorUserId(userId, this.config.instanceName);\n    }\n  }\n\n  getDeviceId() {\n    return this.config?.deviceId;\n  }\n\n  setDeviceId(deviceId: string) {\n    if (!this.config) {\n      this.q.push(this.setDeviceId.bind(this, deviceId));\n      return;\n    }\n    this.config.loggerProvider.debug('function setDeviceId: ', deviceId);\n    if (deviceId !== this.config.deviceId) {\n      this.config.deviceId = deviceId;\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n      this.timeline.onIdentityChanged({ deviceId: deviceId });\n      setConnectorDeviceId(deviceId, this.config.instanceName);\n    }\n  }\n\n  reset() {\n    this.setDeviceId(UUID());\n    this.setUserId(undefined);\n    this.timeline.onReset();\n  }\n\n  getIdentity() {\n    return {\n      deviceId: this.config?.deviceId,\n      userId: this.config?.userId,\n      userProperties: this.userProperties,\n    };\n  }\n\n  setIdentity(identity: Partial<AnalyticsIdentity>) {\n    // Handle userId change\n    if ('userId' in identity) {\n      this.setUserId(identity.userId);\n    }\n\n    // Handle deviceId change\n    if ('deviceId' in identity && identity.deviceId) {\n      this.setDeviceId(identity.deviceId);\n    }\n\n    // Handle userProperties change - auto-send identify\n    if ('userProperties' in identity) {\n      this.userProperties = identity.userProperties;\n      // Auto-send identify event with $set operations\n      const identifyObj = new Identify();\n      // istanbul ignore next\n      const userProperties = identity.userProperties ?? {};\n      for (const [key, value] of Object.entries(userProperties)) {\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n        identifyObj.set(key, value);\n      }\n      // The identify event processing in core-client already calls onIdentityChanged,\n      // so we don't need to call it explicitly here to avoid duplicate notifications.\n      this.identify(identifyObj);\n    }\n  }\n\n  getOptOut(): boolean | undefined {\n    return this.config?.optOut;\n  }\n\n  getSessionId() {\n    return this.config?.sessionId;\n  }\n\n  setSessionId(sessionId: number | undefined) {\n    const promises: Promise<Result>[] = [];\n    if (!this.config) {\n      this.q.push(this.setSessionId.bind(this, sessionId));\n      return returnWrapper(Promise.resolve());\n    }\n    // do not start a new session if optOut is true\n    if (this.config.optOut) {\n      // save the sessionId to storage to be used when optOut is false\n      this.config.deferredSessionId = sessionId ?? UNSPECIFIED_SESSION_ID;\n      return returnWrapper(Promise.resolve());\n    }\n\n    // default sessionId to current time\n    if (sessionId === undefined) {\n      sessionId = Date.now();\n    }\n\n    // Prevents starting a new session with the same session ID\n    if (sessionId === this.config.sessionId) {\n      return returnWrapper(Promise.resolve());\n    }\n\n    this.config.loggerProvider.debug('function setSessionId: ', sessionId);\n\n    const previousSessionId = this.getSessionId();\n    if (previousSessionId !== sessionId) {\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n      this.timeline.onSessionIdChanged(sessionId);\n    }\n\n    const lastEventTime = this.config.lastEventTime;\n    let lastEventId = this.config.lastEventId ?? -1;\n\n    this.config.sessionId = sessionId;\n    this.config.lastEventTime = undefined;\n    this.config.pageCounter = 0;\n\n    if (isSessionTrackingEnabled(this.config.defaultTracking)) {\n      if (previousSessionId && lastEventTime) {\n        promises.push(\n          this.track(DEFAULT_SESSION_END_EVENT, undefined, {\n            device_id: this.previousSessionDeviceId,\n            event_id: ++lastEventId,\n            session_id: previousSessionId,\n            time: lastEventTime + 1,\n            user_id: this.previousSessionUserId,\n          }).promise,\n        );\n      }\n      this.config.lastEventTime = this.config.sessionId;\n    }\n\n    // Fire web attribution event when enable webAttribution tracking\n    // 1. has new campaign (call setSessionId from init function)\n    // 2. or shouldTrackNewCampaign (call setSessionId from async process(event) when there has new campaign and resetSessionOnNewCampaign = true )\n    const isCampaignEventTracked = this.trackCampaignEventIfNeeded(++lastEventId, promises);\n\n    // track the identify event if an Identify object is provided in the config\n    if (this.config.identify) {\n      promises.push(this.track(createIdentifyEvent(this.config.identify)).promise);\n    }\n\n    if (isSessionTrackingEnabled(this.config.defaultTracking)) {\n      promises.push(\n        this.track(DEFAULT_SESSION_START_EVENT, undefined, {\n          event_id: isCampaignEventTracked ? ++lastEventId : lastEventId,\n          session_id: this.config.sessionId,\n          time: this.config.lastEventTime,\n        }).promise,\n      );\n    }\n\n    this.previousSessionDeviceId = this.config.deviceId;\n    this.previousSessionUserId = this.config.userId;\n    return returnWrapper(Promise.all(promises));\n  }\n\n  extendSession() {\n    if (!this.config) {\n      this.q.push(this.extendSession.bind(this));\n      return;\n    }\n    this.config.lastEventTime = Date.now();\n  }\n\n  setTransport(transport: TransportTypeOrOptions) {\n    if (!this.config) {\n      this.q.push(this.setTransport.bind(this, transport));\n      return;\n    }\n    this.config.transportProvider = createTransport(transport);\n  }\n\n  identify(identify: IIdentify, eventOptions?: EventOptions) {\n    if (isInstanceProxy(identify)) {\n      const queue = identify._q;\n      identify._q = [];\n      identify = convertProxyObjectToRealObject(new Identify(), queue);\n    }\n    if (eventOptions?.user_id) {\n      this.setUserId(eventOptions.user_id);\n    }\n    if (eventOptions?.device_id) {\n      this.setDeviceId(eventOptions.device_id);\n    }\n    return super.identify(identify, eventOptions);\n  }\n\n  groupIdentify(groupType: string, groupName: string | string[], identify: IIdentify, eventOptions?: EventOptions) {\n    if (isInstanceProxy(identify)) {\n      const queue = identify._q;\n      identify._q = [];\n      identify = convertProxyObjectToRealObject(new Identify(), queue);\n    }\n    return super.groupIdentify(groupType, groupName, identify, eventOptions);\n  }\n\n  revenue(revenue: IRevenue, eventOptions?: EventOptions) {\n    if (isInstanceProxy(revenue)) {\n      const queue = revenue._q;\n      revenue._q = [];\n      revenue = convertProxyObjectToRealObject(new Revenue(), queue);\n    }\n    return super.revenue(revenue, eventOptions);\n  }\n\n  private trackCampaignEventIfNeeded(lastEventId?: number, promises?: Promise<Result>[]) {\n    if (\n      !this.webAttribution ||\n      !this.webAttribution.shouldTrackNewCampaign ||\n      !isUserPropertyAttributionEnabled(this.webAttribution.options)\n    ) {\n      return false;\n    }\n\n    const campaignEvent = this.webAttribution.generateCampaignEvent(lastEventId);\n    if (promises) {\n      promises.push(this.track(campaignEvent).promise);\n    } else {\n      this.track(campaignEvent);\n    }\n    this.config.loggerProvider.log('Tracking attribution.');\n    return true;\n  }\n\n  async process(event: Event) {\n    const currentTime = Date.now();\n    const isEventInNewSession = isNewSession(this.config.sessionTimeout, this.config.lastEventTime);\n    const shouldSetSessionIdOnNewCampaign =\n      this.webAttribution && this.webAttribution.shouldSetSessionIdOnNewCampaign();\n\n    if (\n      event.event_type !== DEFAULT_SESSION_START_EVENT &&\n      event.event_type !== DEFAULT_SESSION_END_EVENT &&\n      (!event.session_id || event.session_id === this.getSessionId())\n    ) {\n      if (isEventInNewSession || shouldSetSessionIdOnNewCampaign) {\n        this.setSessionId(currentTime);\n        if (shouldSetSessionIdOnNewCampaign) {\n          this.config.loggerProvider.log('Created a new session for new campaign.');\n        }\n      } else if (!isEventInNewSession) {\n        // Web attribution should be tracked during the middle of a session\n        // if there has been a chance in the campaign information.\n        this.trackCampaignEventIfNeeded();\n      }\n    }\n\n    return super.process(event);\n  }\n\n  private logBrowserOptions(browserConfig: BrowserOptions & { apiKey: string }) {\n    try {\n      const browserConfigCopy = {\n        ...browserConfig,\n        apiKey: browserConfig.apiKey.substring(0, 10) + '********',\n      };\n      this.config.loggerProvider.debug(\n        'Initialized Amplitude with BrowserConfig:',\n        safeJsonStringify(browserConfigCopy),\n      );\n    } catch (e) {\n      /* istanbul ignore next */\n      this.config.loggerProvider.error('Error logging browser config', e);\n    }\n  }\n\n  /**\n   * @experimental\n   * WARNING: This method is for internal testing only and is not part of the public API.\n   * It may be changed or removed at any time without notice.\n   *\n   * Sets the diagnostics sample rate before amplitude.init()\n   * @param sampleRate - The sample rate to set\n   */\n  _setDiagnosticsSampleRate(sampleRate: number): void {\n    if (sampleRate > 1 || sampleRate < 0) {\n      return;\n    }\n    // Set diagnostics sample rate before initializing the config\n    if (!this.config) {\n      this._diagnosticsSampleRate = sampleRate;\n      return;\n    }\n  }\n}\n"
  },
  {
    "path": "packages/analytics-browser/src/config/joined-config.ts",
    "content": "import {\n  AutocaptureOptions,\n  type ElementInteractionsOptions,\n  BrowserConfig,\n  CustomEnrichmentOptions,\n  RemoteConfig,\n  NetworkTrackingOptions,\n  NetworkCaptureRule,\n  SAFE_HEADERS,\n} from '@amplitude/analytics-core';\n\nexport interface AutocaptureOptionsRemoteConfig extends AutocaptureOptions {\n  elementInteractions?: boolean | ElementInteractionsOptionsRemoteConfig;\n  networkTracking?: boolean | NetworkTrackingOptionsRemoteConfig;\n}\nexport interface ElementInteractionsOptionsRemoteConfig extends ElementInteractionsOptions {\n  /**\n   * Related to pageUrlAllowlist but holds regex strings which will be initialized and appended to pageUrlAllowlist\n   */\n  pageUrlAllowlistRegex?: string[];\n}\n\nexport interface NetworkCaptureRuleRemoteConfig extends NetworkCaptureRule {\n  /**\n   * Related to urls but holds regex strings which will be initialized and appended to urls\n   */\n  urlsRegex?: string[];\n}\n\nexport interface NetworkTrackingOptionsRemoteConfig extends NetworkTrackingOptions {\n  /**\n   * Related to pageUrlAllowlist but holds regex strings which will be initialized and appended to pageUrlAllowlist\n   */\n  captureRules?: NetworkCaptureRuleRemoteConfig[];\n}\n\n// Type alias for the remote config structure we expect (this is what comes from the filtered browserSDK config)\ntype RemoteConfigBrowserSDK = {\n  autocapture?: AutocaptureOptionsRemoteConfig | boolean;\n  customEnrichment?: CustomEnrichmentOptions | boolean;\n};\n\n/**\n * Performs a deep transformation of a remote config object so that\n * it matches the expected schema of the local config.\n *\n * Specifically, it normalizes nested `enabled` flags into concise union types.\n *\n * ### Transformation Rules:\n * - If an object has `enabled: true`, it is replaced by the same object without the `enabled` field.\n * - If it has only `enabled: true`, it is replaced with `true`.\n * - If it has `enabled: false`, it is replaced with `false` regardless of other fields.\n *\n * ### Examples:\n * Input:  { prop: { enabled: true, hello: 'world' }}\n * Output: { prop: { hello: 'world' } }\n *\n * Input:  { prop: { enabled: true }}\n * Output: { prop: true }\n *\n * Input:  { prop: { enabled: false, hello: 'world' }}\n * Output: { prop: false }\n *\n * Input:  { prop: { hello: 'world' }}\n * Output: { prop: { hello: 'world' } } // No change\n *\n * @param config Remote config object to be transformed\n * @returns Transformed config object compatible with local schema\n */\nexport function translateRemoteConfigToLocal(config?: Record<string, any>) {\n  // Disabling type checking rules because remote config comes from a remote source\n  // and this function needs to handle any unexpected values\n  /* eslint-disable @typescript-eslint/no-unsafe-member-access,\n     @typescript-eslint/no-unsafe-assignment,\n     @typescript-eslint/no-unsafe-argument\n */\n  if (typeof config !== 'object' || config === null) {\n    return;\n  }\n\n  // translations are not applied on array properties\n  if (Array.isArray(config)) {\n    return;\n  }\n\n  const propertyNames = Object.keys(config);\n  for (const propertyName of propertyNames) {\n    try {\n      const value = config[propertyName];\n      // transform objects with { enabled } property to boolean | object\n      if (typeof value?.enabled === 'boolean') {\n        if (value.enabled) {\n          // if enabled is true, set the value to the rest of the object\n          // or true if the object has no other properties\n          delete value.enabled;\n          if (Object.keys(value).length === 0) {\n            (config as any)[propertyName] = true;\n          }\n        } else {\n          // If enabled is false, set the value to false\n          (config as any)[propertyName] = false;\n        }\n      }\n\n      // recursively translate properties of the value\n      translateRemoteConfigToLocal(value as Record<string, any>);\n    } catch (e) {\n      // a failure here means that an accessor threw an error\n      // so don't translate it\n      // TODO(diagnostics): add a diagnostic event for this\n    }\n  }\n\n  // translate remote responseHeaders and requestHeaders to local responseHeaders and requestHeaders\n  try {\n    if (config.autocapture?.networkTracking?.captureRules?.length) {\n      for (const rule of config.autocapture.networkTracking.captureRules) {\n        for (const header of ['responseHeaders', 'requestHeaders']) {\n          const { captureSafeHeaders, allowlist } = rule[header] ?? {};\n          if (!captureSafeHeaders && !allowlist) {\n            continue;\n          }\n          // if allowlist is not an array, remote config contract is violated, remove it\n          if (allowlist !== undefined && !Array.isArray(allowlist)) {\n            delete rule[header];\n            continue;\n          }\n          rule[header] = [...(captureSafeHeaders ? SAFE_HEADERS : []), ...(allowlist ?? [])];\n        }\n      }\n    }\n  } catch (e) {\n    /* istanbul ignore next */\n    // surprise exception, so don't translate it\n  }\n\n  // translate frustrationInteractions pluralization\n  const frustrationInteractions = config.autocapture?.frustrationInteractions;\n  if (frustrationInteractions) {\n    if (frustrationInteractions.rageClick) {\n      frustrationInteractions.rageClicks = frustrationInteractions.rageClick;\n      delete frustrationInteractions.rageClick;\n    }\n    if (frustrationInteractions.deadClick) {\n      frustrationInteractions.deadClicks = frustrationInteractions.deadClick;\n      delete frustrationInteractions.deadClick;\n    }\n  }\n\n  // normalize viewportContentUpdated inside elementInteractions\n  try {\n    const elementInteractions = config.autocapture?.elementInteractions;\n    if (elementInteractions && typeof elementInteractions === 'object') {\n      // { enabled: true } (no other fields) collapses to `true`; convert back to {} for the SDK.\n      if (elementInteractions.viewportContentUpdated === true) {\n        elementInteractions.viewportContentUpdated = {};\n      }\n      // { enabled: false, ... } collapses to `false`; convert back to { enabled: false } for the SDK.\n      if (elementInteractions.viewportContentUpdated === false) {\n        elementInteractions.viewportContentUpdated = { enabled: false };\n      }\n      // Migrate deprecated top-level exposureDuration to viewportContentUpdated.exposureDuration\n      if (elementInteractions.exposureDuration !== undefined) {\n        const viewportContentUpdated = elementInteractions.viewportContentUpdated;\n        if (viewportContentUpdated === undefined) {\n          elementInteractions.viewportContentUpdated = { exposureDuration: elementInteractions.exposureDuration };\n        } else if (\n          typeof viewportContentUpdated === 'object' &&\n          viewportContentUpdated.exposureDuration === undefined &&\n          viewportContentUpdated.enabled !== false\n        ) {\n          viewportContentUpdated.exposureDuration = elementInteractions.exposureDuration;\n        }\n        delete elementInteractions.exposureDuration;\n      }\n    }\n  } catch (e) {\n    /* istanbul ignore next */\n    // surprise exception, so don't translate it\n  }\n}\n\nfunction mergeUrls(urlsExact: (string | RegExp)[], urlsRegex: string[] | undefined, browserConfig: BrowserConfig) {\n  // Convert string patterns to RegExp objects, warn on invalid patterns and skip them\n  const regexList = [];\n  for (const pattern of urlsRegex ?? []) {\n    try {\n      regexList.push(new RegExp(pattern));\n    } catch (regexError) {\n      browserConfig.loggerProvider.warn(`Invalid regex pattern: ${pattern}`, regexError);\n    }\n  }\n\n  return urlsExact.concat(regexList);\n}\n\n/**\n * Updates the browser config in place by applying remote configuration settings.\n * Primarily merges autocapture settings from the remote config into the browser config.\n *\n * @param remoteConfig - The remote configuration to apply, or null if none available\n * @param browserConfig - The browser config object to update (modified in place)\n */\nexport function updateBrowserConfigWithRemoteConfig(\n  remoteConfig: RemoteConfig | null,\n  browserConfig: BrowserConfig,\n): void {\n  if (!remoteConfig) {\n    return;\n  }\n\n  // translate remote config to local compatible format\n  translateRemoteConfigToLocal(remoteConfig);\n\n  try {\n    browserConfig.loggerProvider.debug(\n      'Update browser config with remote configuration:',\n      JSON.stringify(remoteConfig),\n    );\n\n    // type cast error will be thrown if remoteConfig is not a valid RemoteConfigBrowserSDK\n    // and it will be caught by the try-catch block\n    const typedRemoteConfig = remoteConfig as RemoteConfigBrowserSDK;\n\n    // merge remoteConfig.autocapture and browserConfig.autocapture\n    // if a field is in remoteConfig.autocapture, use that value\n    // if a field is not in remoteConfig.autocapture, use the value from browserConfig.autocapture\n    if (typedRemoteConfig && 'autocapture' in typedRemoteConfig) {\n      if (typeof typedRemoteConfig.autocapture === 'boolean') {\n        browserConfig.autocapture = typedRemoteConfig.autocapture;\n      }\n\n      if (typeof typedRemoteConfig.autocapture === 'object' && typedRemoteConfig.autocapture !== null) {\n        const transformedAutocaptureRemoteConfig = { ...typedRemoteConfig.autocapture };\n\n        if (browserConfig.autocapture === undefined) {\n          browserConfig.autocapture = typedRemoteConfig.autocapture;\n        }\n\n        // Handle Element Interactions config initialization\n        if (\n          typeof typedRemoteConfig.autocapture.elementInteractions === 'object' &&\n          typedRemoteConfig.autocapture.elementInteractions !== null &&\n          typedRemoteConfig.autocapture.elementInteractions.pageUrlAllowlistRegex?.length\n        ) {\n          transformedAutocaptureRemoteConfig.elementInteractions = {\n            ...typedRemoteConfig.autocapture.elementInteractions,\n          };\n          const transformedRcElementInteractions = transformedAutocaptureRemoteConfig.elementInteractions;\n\n          // combine exact allow list and regex allow list into just 'pageUrlAllowlist'\n          const exactAllowList = transformedRcElementInteractions.pageUrlAllowlist ?? [];\n          const urlsRegex = typedRemoteConfig.autocapture.elementInteractions.pageUrlAllowlistRegex;\n          transformedRcElementInteractions.pageUrlAllowlist = mergeUrls(exactAllowList, urlsRegex, browserConfig);\n\n          // clean up the regex allow list\n          delete transformedRcElementInteractions.pageUrlAllowlistRegex;\n        }\n\n        // Handle Network Tracking config initialization\n        if (\n          typeof typedRemoteConfig.autocapture.networkTracking === 'object' &&\n          typedRemoteConfig.autocapture.networkTracking !== null &&\n          typedRemoteConfig.autocapture.networkTracking.captureRules?.length\n        ) {\n          transformedAutocaptureRemoteConfig.networkTracking = {\n            ...typedRemoteConfig.autocapture.networkTracking,\n          };\n          const transformedRcNetworkTracking = transformedAutocaptureRemoteConfig.networkTracking;\n          /* istanbul ignore next */\n          const captureRules = transformedRcNetworkTracking.captureRules ?? [];\n          for (const rule of captureRules) {\n            rule.urls = mergeUrls(rule.urls ?? [], rule.urlsRegex, browserConfig);\n            delete rule.urlsRegex;\n          }\n        }\n\n        if (typeof browserConfig.autocapture === 'boolean') {\n          browserConfig.autocapture = {\n            attribution: browserConfig.autocapture,\n            fileDownloads: browserConfig.autocapture,\n            formInteractions: browserConfig.autocapture,\n            pageViews: browserConfig.autocapture,\n            sessions: browserConfig.autocapture,\n            elementInteractions: browserConfig.autocapture,\n            webVitals: browserConfig.autocapture,\n            frustrationInteractions: browserConfig.autocapture,\n            ...transformedAutocaptureRemoteConfig,\n          };\n        }\n\n        if (typeof browserConfig.autocapture === 'object') {\n          browserConfig.autocapture = {\n            ...browserConfig.autocapture,\n            ...transformedAutocaptureRemoteConfig,\n          };\n        }\n      }\n\n      // Override default tracking options if autocapture is updated by remote config\n      browserConfig.defaultTracking = browserConfig.autocapture;\n    }\n\n    if ('customEnrichment' in typedRemoteConfig && typedRemoteConfig.customEnrichment !== null) {\n      // Respect a locally-explicit false: if the user disabled custom enrichment at init time,\n      // remote config must not re-enable it.\n      if (browserConfig.customEnrichment !== false) {\n        browserConfig.customEnrichment = typedRemoteConfig.customEnrichment;\n      }\n    }\n\n    browserConfig.loggerProvider.debug('Browser config after remote config update:', JSON.stringify(browserConfig));\n  } catch (e) {\n    browserConfig.loggerProvider.error('Failed to apply remote configuration because of error: ', e);\n  }\n}\n"
  },
  {
    "path": "packages/analytics-browser/src/config.ts",
    "content": "import {\n  Config,\n  Logger,\n  ILogger,\n  LogLevel,\n  Event,\n  Storage,\n  IngestionMetadata,\n  ServerZoneType,\n  OfflineDisabled,\n  Plan,\n  IdentityStorageType,\n  TransportTypeOrOptions,\n  MemoryStorage,\n  UUID,\n  CookieStorage,\n  getCookieName,\n  getQueryParams,\n  UserSession,\n  BrowserOptions,\n  BrowserConfig as IBrowserConfig,\n  DefaultTrackingOptions,\n  TrackingOptions,\n  AutocaptureOptions,\n  CookieOptions,\n  RemoteConfigOptions,\n  NetworkTrackingOptions,\n  CustomEnrichmentOptions,\n  IIdentify,\n  IDiagnosticsClient,\n  isDomainEqual,\n  CookieStorageConfig,\n  decodeCookieValue,\n} from '@amplitude/analytics-core';\n\nimport { LocalStorage } from './storage/local-storage';\nimport { SessionStorage } from './storage/session-storage';\nimport { XHRTransport } from './transports/xhr';\nimport { FetchTransport } from './transports/fetch';\nimport { SendBeaconTransport } from './transports/send-beacon';\nimport { parseLegacyCookies } from './cookie-migration';\nimport { DEFAULT_IDENTITY_STORAGE, DEFAULT_SERVER_ZONE } from './constants';\nimport { AmplitudeBrowser } from './browser-client';\nimport { VERSION } from './version';\nimport { getDomain, KNOWN_2LDS } from './attribution/helpers';\n\n// Exported for testing purposes only. Do not expose to public interface.\nexport class BrowserConfig extends Config implements IBrowserConfig {\n  public readonly version = VERSION;\n  protected _cookieStorage: Storage<UserSession>;\n  protected _deviceId?: string;\n  protected _lastEventId?: number;\n  protected _lastEventTime?: number;\n  protected _optOut = false;\n  protected _sessionId?: number;\n  protected _deferredSessionId?: number;\n  protected _userId?: string;\n  protected _pageCounter?: number;\n  protected _debugLogsEnabled?: boolean;\n  constructor(\n    public apiKey: string,\n    public appVersion?: string,\n    cookieStorage: Storage<UserSession> = new MemoryStorage(),\n    public cookieOptions: CookieOptions = {\n      domain: '',\n      expiration: 365,\n      sameSite: 'Lax' as const,\n      secure: false,\n      upgrade: true,\n    },\n    public defaultTracking?: boolean | DefaultTrackingOptions,\n    public autocapture?: boolean | AutocaptureOptions,\n    deviceId?: string,\n    public flushIntervalMillis: number = 1000,\n    public flushMaxRetries: number = 5,\n    public flushQueueSize: number = 30,\n    public identityStorage: IdentityStorageType = DEFAULT_IDENTITY_STORAGE,\n    public ingestionMetadata?: IngestionMetadata,\n    public instanceName?: string,\n    lastEventId?: number,\n    lastEventTime?: number,\n    public loggerProvider: ILogger = new Logger(),\n    public logLevel: LogLevel = LogLevel.Warn,\n    public minIdLength?: number,\n    public offline: boolean | typeof OfflineDisabled = false,\n    optOut = false,\n    public partnerId?: string,\n    public plan?: Plan,\n    public serverUrl: string = '',\n    public serverZone: ServerZoneType = DEFAULT_SERVER_ZONE,\n    sessionId?: number,\n    deferredSessionId?: number,\n    public sessionTimeout: number = 30 * 60 * 1000,\n    public storageProvider: Storage<Event[]> = new LocalStorage({ loggerProvider }),\n    public trackingOptions: Required<TrackingOptions> = {\n      ipAddress: true,\n      language: true,\n      platform: true,\n    },\n    public transport: TransportTypeOrOptions = 'fetch',\n    public useBatch: boolean = false,\n    public fetchRemoteConfig: boolean = true,\n    userId?: string,\n    pageCounter?: number,\n    debugLogsEnabled?: boolean,\n    public networkTrackingOptions?: NetworkTrackingOptions,\n    public identify?: IIdentify,\n    public enableDiagnostics: boolean = true,\n    public diagnosticsSampleRate: number = 0,\n    public diagnosticsClient?: IDiagnosticsClient,\n    public remoteConfig?: RemoteConfigOptions,\n    public topLevelDomain?: string,\n    public enableRequestBodyCompression: boolean = false,\n    public customEnrichment?: boolean | CustomEnrichmentOptions,\n  ) {\n    super({ apiKey, storageProvider, transportProvider: createTransport(transport) });\n    this._cookieStorage = cookieStorage;\n    this.deviceId = deviceId;\n    this.lastEventId = lastEventId;\n    this.lastEventTime = lastEventTime;\n    this.optOut = optOut;\n    this.deferredSessionId = deferredSessionId;\n    this.sessionId = sessionId;\n    this.pageCounter = pageCounter;\n    this.userId = userId;\n    this.debugLogsEnabled = debugLogsEnabled;\n    this.loggerProvider.enable(debugLogsEnabled ? LogLevel.Debug : this.logLevel);\n    this.networkTrackingOptions = networkTrackingOptions;\n    this.identify = identify;\n    this.enableDiagnostics = enableDiagnostics;\n    this.diagnosticsSampleRate = diagnosticsSampleRate;\n    this.diagnosticsClient = diagnosticsClient;\n\n    // Note: The canonical logic for determining fetchRemoteConfig is in shouldFetchRemoteConfig().\n    // This logic is duplicated here to maintain the BrowserConfig constructor contract and ensure\n    // the config object has the correct fetchRemoteConfig value set on its properties.\n    // The value passed to this constructor should already be computed via shouldFetchRemoteConfig().\n    const _fetchRemoteConfig = remoteConfig?.fetchRemoteConfig ?? fetchRemoteConfig;\n    this.remoteConfig = this.remoteConfig || {};\n    this.remoteConfig.fetchRemoteConfig = _fetchRemoteConfig;\n    this.fetchRemoteConfig = _fetchRemoteConfig;\n\n    this.topLevelDomain = topLevelDomain || getDomain();\n  }\n\n  get cookieStorage() {\n    return this._cookieStorage;\n  }\n\n  set cookieStorage(cookieStorage: Storage<UserSession>) {\n    if (this._cookieStorage !== cookieStorage) {\n      this._cookieStorage = cookieStorage;\n      this.updateStorage();\n    }\n  }\n\n  get deviceId() {\n    return this._deviceId;\n  }\n\n  set deviceId(deviceId: string | undefined) {\n    if (this._deviceId !== deviceId) {\n      this._deviceId = deviceId;\n      this.updateStorage();\n    }\n  }\n\n  get userId() {\n    return this._userId;\n  }\n\n  set userId(userId: string | undefined) {\n    if (this._userId !== userId) {\n      this._userId = userId;\n      this.updateStorage();\n    }\n  }\n\n  get sessionId() {\n    return this._sessionId;\n  }\n\n  set sessionId(sessionId: number | undefined) {\n    if (this._sessionId !== sessionId) {\n      this._sessionId = sessionId;\n      // Clear deferredSessionId when sessionId is set to prevent stale values\n      // from overriding legitimate sessionIds on subsequent page loads\n      if (sessionId !== undefined && this._deferredSessionId !== undefined) {\n        this._deferredSessionId = undefined;\n      }\n      this.updateStorage();\n    }\n  }\n\n  get deferredSessionId() {\n    return this._deferredSessionId;\n  }\n\n  set deferredSessionId(deferredSessionId: number | undefined) {\n    if (this._deferredSessionId !== deferredSessionId && deferredSessionId !== this.sessionId) {\n      this._deferredSessionId = deferredSessionId;\n      this.updateStorage();\n    }\n  }\n\n  get optOut() {\n    return this._optOut;\n  }\n\n  set optOut(optOut: boolean) {\n    if (this._optOut !== optOut) {\n      this._optOut = optOut;\n      this.updateStorage();\n    }\n  }\n\n  get lastEventTime() {\n    return this._lastEventTime;\n  }\n\n  set lastEventTime(lastEventTime: number | undefined) {\n    if (this._lastEventTime !== lastEventTime) {\n      this._lastEventTime = lastEventTime;\n      this.updateStorage();\n    }\n  }\n\n  get lastEventId() {\n    return this._lastEventId;\n  }\n\n  set lastEventId(lastEventId: number | undefined) {\n    if (this._lastEventId !== lastEventId) {\n      this._lastEventId = lastEventId;\n      this.updateStorage();\n    }\n  }\n\n  get pageCounter() {\n    return this._pageCounter;\n  }\n\n  set pageCounter(pageCounter: number | undefined) {\n    if (this._pageCounter !== pageCounter) {\n      this._pageCounter = pageCounter;\n      this.updateStorage();\n    }\n  }\n\n  set debugLogsEnabled(debugLogsEnabled: boolean | undefined) {\n    if (this._debugLogsEnabled !== debugLogsEnabled) {\n      this._debugLogsEnabled = debugLogsEnabled;\n      this.updateStorage();\n    }\n  }\n\n  private updateStorage() {\n    const cache = {\n      deviceId: this._deviceId,\n      userId: this._userId,\n      sessionId: this._sessionId,\n      deferredSessionId: this._deferredSessionId,\n      optOut: this._optOut,\n      lastEventTime: this._lastEventTime,\n      lastEventId: this._lastEventId,\n      pageCounter: this._pageCounter,\n      debugLogsEnabled: this._debugLogsEnabled,\n      cookieDomain: undefined as string | undefined,\n    };\n\n    if (this.cookieStorage instanceof CookieStorage) {\n      cache.cookieDomain = this.cookieStorage.options.domain;\n    }\n\n    void this.cookieStorage.set(getCookieName(this.apiKey), cache);\n  }\n}\n\n/**\n * Early-initialized configuration values that are determined before useBrowserConfig is called.\n * These are created early to support DiagnosticsClient and RemoteConfigClient initialization.\n */\nexport interface EarlyConfig {\n  /** Logger instance - shared across DiagnosticsClient, RemoteConfigClient, and BrowserConfig */\n  loggerProvider: ILogger;\n  /** Server zone for API endpoints */\n  serverZone: ServerZoneType;\n  /** Whether diagnostics is enabled (may come from remote config) */\n  enableDiagnostics: boolean;\n  /** Diagnostics sample rate (may come from remote config) */\n  diagnosticsSampleRate: number;\n}\n\nexport const useBrowserConfig = async (\n  apiKey: string,\n  options: BrowserOptions = {},\n  amplitudeInstance: AmplitudeBrowser,\n  diagnosticsClient?: IDiagnosticsClient,\n  earlyConfig?: EarlyConfig,\n): Promise<IBrowserConfig> => {\n  // Step 1: Create identity storage instance\n  const identityStorage = options.identityStorage || DEFAULT_IDENTITY_STORAGE;\n  let defaultCookieDomain = '';\n\n  // use the getTopLevelDomain function to find the TLD only if identity storage\n  // is cookie (because getTopLevelDomain() uses cookies) AND cookie option domain is not set\n  if (\n    identityStorage === DEFAULT_IDENTITY_STORAGE &&\n    !options.cookieOptions?.domain &&\n    options.cookieOptions?.domain !== ''\n  ) {\n    defaultCookieDomain = await getTopLevelDomain(undefined, diagnosticsClient);\n  }\n  const cookieOptions = {\n    domain: options.cookieOptions?.domain ?? defaultCookieDomain,\n    expiration: 365,\n    sameSite: 'Lax' as const,\n    secure: false,\n    upgrade: true,\n    ...options.cookieOptions,\n  };\n\n  const cookieConfig: CookieStorageConfig = {\n    // if more than one cookie with the same key exists,\n    // look for the cookie that has the domain attribute set to cookieOptions.domain\n    duplicateResolverFn: (value: string): boolean => {\n      const decodedValue = decodeCookieValue(value);\n      if (!decodedValue) {\n        return false;\n      }\n      const parsed = JSON.parse(decodedValue) as UserSession;\n      return isDomainEqual(parsed.cookieDomain, cookieOptions.domain);\n    },\n    diagnosticsClient: diagnosticsClient,\n  };\n  const cookieStorage = createCookieStorage<UserSession>(options.identityStorage, cookieOptions, cookieConfig);\n\n  // Step 1: Parse cookies using identity storage instance\n  const legacyCookies = await parseLegacyCookies(apiKey, cookieStorage, options.cookieOptions?.upgrade ?? true);\n  const previousCookies = await cookieStorage.get(getCookieName(apiKey));\n  const queryParams = getQueryParams();\n\n  // Check if ampTimestamp is present and valid\n  const ampTimestamp = queryParams.ampTimestamp ? Number(queryParams.ampTimestamp) : undefined;\n  const isWithinTimeLimit = ampTimestamp ? Date.now() < ampTimestamp : true;\n\n  // Step 3: Reconcile user identity\n  const deviceId =\n    options.deviceId ??\n    (isWithinTimeLimit ? queryParams.ampDeviceId ?? queryParams.deviceId : undefined) ??\n    previousCookies?.deviceId ??\n    legacyCookies.deviceId ??\n    UUID();\n  const lastEventId = previousCookies?.lastEventId ?? legacyCookies.lastEventId;\n  const lastEventTime = previousCookies?.lastEventTime ?? legacyCookies.lastEventTime;\n  const optOut = options.optOut ?? previousCookies?.optOut ?? legacyCookies.optOut;\n  const sessionId = previousCookies?.sessionId ?? legacyCookies.sessionId;\n  const deferredSessionId = previousCookies?.deferredSessionId;\n  const userId = options.userId ?? previousCookies?.userId ?? legacyCookies.userId;\n  amplitudeInstance.previousSessionDeviceId = previousCookies?.deviceId ?? legacyCookies.deviceId;\n  amplitudeInstance.previousSessionUserId = previousCookies?.userId ?? legacyCookies.userId;\n\n  const trackingOptions = {\n    ipAddress: options.trackingOptions?.ipAddress ?? true,\n    language: options.trackingOptions?.language ?? true,\n    platform: options.trackingOptions?.platform ?? true,\n  };\n  const pageCounter = previousCookies?.pageCounter;\n  const debugLogsEnabled = previousCookies?.debugLogsEnabled;\n\n  // Override default tracking options if autocapture is set\n  if (options.autocapture !== undefined) {\n    options.defaultTracking = options.autocapture;\n  }\n\n  const browserConfig = new BrowserConfig(\n    apiKey,\n    options.appVersion,\n    cookieStorage,\n    cookieOptions,\n    options.defaultTracking,\n    options.autocapture,\n    deviceId,\n    options.flushIntervalMillis,\n    options.flushMaxRetries,\n    options.flushQueueSize,\n    identityStorage,\n    options.ingestionMetadata,\n    options.instanceName,\n    lastEventId,\n    lastEventTime,\n    // Use earlyConfig.loggerProvider to ensure consistent logger across DiagnosticsClient/RemoteConfigClient/BrowserConfig\n    earlyConfig?.loggerProvider ?? options.loggerProvider,\n    options.logLevel,\n    options.minIdLength,\n    options.offline,\n    optOut,\n    options.partnerId,\n    options.plan,\n    options.serverUrl,\n    // Use earlyConfig.serverZone to ensure consistent serverZone\n    earlyConfig?.serverZone ?? options.serverZone,\n    sessionId,\n    deferredSessionId,\n    options.sessionTimeout,\n    options.storageProvider,\n    trackingOptions,\n    options.transport,\n    options.useBatch,\n    options.fetchRemoteConfig,\n    userId,\n    pageCounter,\n    debugLogsEnabled,\n    options.networkTrackingOptions,\n    options.identify,\n    // Use earlyConfig values (already has remote config applied), otherwise fall back to options\n    earlyConfig?.enableDiagnostics ?? options.enableDiagnostics,\n    earlyConfig?.diagnosticsSampleRate ?? amplitudeInstance._diagnosticsSampleRate,\n    diagnosticsClient,\n    options.remoteConfig,\n    defaultCookieDomain,\n    options.enableRequestBodyCompression,\n    options.customEnrichment,\n  );\n\n  if (!(await browserConfig.storageProvider.isEnabled())) {\n    browserConfig.loggerProvider.warn(\n      `Storage provider ${browserConfig.storageProvider.constructor.name} is not enabled. Falling back to MemoryStorage.`,\n    );\n    browserConfig.storageProvider = new MemoryStorage();\n  }\n\n  return browserConfig;\n};\n\nexport const createCookieStorage = <T>(\n  identityStorage: IdentityStorageType = DEFAULT_IDENTITY_STORAGE,\n  cookieOptions: CookieOptions = {},\n  cookieConfig?: CookieStorageConfig,\n) => {\n  switch (identityStorage) {\n    case 'localStorage':\n      return new LocalStorage<T>();\n    case 'sessionStorage':\n      return new SessionStorage<T>();\n    case 'none':\n      return new MemoryStorage<T>();\n    case 'cookie':\n    default:\n      return new CookieStorage<T>(\n        {\n          ...cookieOptions,\n          expirationDays: cookieOptions.expiration,\n        },\n        cookieConfig,\n      );\n  }\n};\n\n/**\n * Determines whether to fetch remote config based on options.\n * Extracted to allow early determination before useBrowserConfig is called.\n */\nexport const shouldFetchRemoteConfig = (options: BrowserOptions = {}): boolean => {\n  if (options.remoteConfig?.fetchRemoteConfig === true) {\n    // set to true if remoteConfig explicitly set to true\n    return true;\n  } else if (options.remoteConfig?.fetchRemoteConfig === false || options.fetchRemoteConfig === false) {\n    // set to false if either are set to false explicitly\n    return false;\n  } else {\n    // default to true if both undefined\n    return true;\n  }\n};\n\nexport const createTransport = (transport?: TransportTypeOrOptions) => {\n  const type = typeof transport === 'object' ? transport.type : transport;\n  const headers = typeof transport === 'object' ? transport.headers : undefined;\n\n  if (type === 'xhr') {\n    return new XHRTransport(headers);\n  }\n  if (type === 'beacon') {\n    // SendBeacon does not support custom headers\n    return new SendBeaconTransport();\n  }\n  // Keep a browser-local fetch transport for gzip support.\n  // TODO: Merge back to core FetchTransport after React Native supports gzip.\n  return new FetchTransport(headers);\n};\n\nexport const getTopLevelDomain = async (url?: string, diagnosticsClient?: IDiagnosticsClient) => {\n  if (\n    !(await new CookieStorage<number>(undefined, { diagnosticsClient }).isEnabled()) ||\n    (!url && (typeof location === 'undefined' || !location.hostname))\n  ) {\n    return '';\n  }\n  const host = url ?? location.hostname;\n\n  const parts = host.split('.');\n\n  // if hostname has less than 2 parts, it's not a registrable domain\n  // and the browser won't allow setting domain-scoped cookies for it so return empty string\n  if (parts.length === 1) {\n    return '';\n  }\n\n  const levels = [];\n  let skipLevel = 1;\n\n  // if the hostname ends with a TLD we know is in the Public Suffix List\n  // then the last two parts are definitely not writable as a domain\n  if (KNOWN_2LDS.find((tld) => host.endsWith(`.${tld}`))) {\n    skipLevel = 2;\n  }\n\n  for (let i = parts.length - skipLevel - 1; i >= 0; --i) {\n    levels.push(parts.slice(i).join('.'));\n  }\n  for (let i = 0; i < levels.length; i++) {\n    const domain = levels[i];\n    try {\n      const result = await CookieStorage.isDomainWritable(domain);\n\n      // if the transaction succeeded, the domain is valid\n      if (result) {\n        return '.' + domain;\n      }\n    } catch (e) {\n      /* istanbul ignore if */\n      if (diagnosticsClient) {\n        diagnosticsClient.recordEvent('cookies.tld.failure', {\n          reason: `Unexpected exception checking domain is writable: ${domain}`,\n          error: e instanceof Error ? e.message : String(e),\n        });\n      }\n    }\n  }\n\n  // if the transaction failed, the domain is invalid\n  // record a diagnostic event\n  if (diagnosticsClient) {\n    diagnosticsClient.recordEvent('cookies.tld.failure', {\n      reason: `Could not determine TLD for host ${host}`,\n    });\n  }\n\n  // return an empty string to indicate that we couldn't determine the TLD\n  // so fallback to host-only cookies (scoped to the current host)\n  return '';\n};\n"
  },
  {
    "path": "packages/analytics-browser/src/constants.ts",
    "content": "import { IdentityStorageType, ServerZoneType } from '@amplitude/analytics-core';\n\nexport const DEFAULT_EVENT_PREFIX = '[Amplitude]';\n\nexport const DEFAULT_PAGE_VIEW_EVENT = `${DEFAULT_EVENT_PREFIX} Page Viewed`;\nexport const DEFAULT_FORM_START_EVENT = `${DEFAULT_EVENT_PREFIX} Form Started`;\nexport const DEFAULT_FORM_SUBMIT_EVENT = `${DEFAULT_EVENT_PREFIX} Form Submitted`;\nexport const DEFAULT_FILE_DOWNLOAD_EVENT = `${DEFAULT_EVENT_PREFIX} File Downloaded`;\nexport const DEFAULT_SESSION_START_EVENT = 'session_start';\nexport const DEFAULT_SESSION_END_EVENT = 'session_end';\n\nexport const FILE_EXTENSION = `${DEFAULT_EVENT_PREFIX} File Extension`;\nexport const FILE_NAME = `${DEFAULT_EVENT_PREFIX} File Name`;\nexport const LINK_ID = `${DEFAULT_EVENT_PREFIX} Link ID`;\nexport const LINK_TEXT = `${DEFAULT_EVENT_PREFIX} Link Text`;\nexport const LINK_URL = `${DEFAULT_EVENT_PREFIX} Link URL`;\n\nexport const FORM_ID = `${DEFAULT_EVENT_PREFIX} Form ID`;\nexport const FORM_NAME = `${DEFAULT_EVENT_PREFIX} Form Name`;\nexport const FORM_DESTINATION = `${DEFAULT_EVENT_PREFIX} Form Destination`;\n\nexport const DEFAULT_IDENTITY_STORAGE: IdentityStorageType = 'cookie';\nexport const DEFAULT_SERVER_ZONE: ServerZoneType = 'US';\n"
  },
  {
    "path": "packages/analytics-browser/src/cookie-migration/index.ts",
    "content": "import { getOldCookieName, Storage, UserSession } from '@amplitude/analytics-core';\n\nexport const parseLegacyCookies = async (\n  apiKey: string,\n  cookieStorage: Storage<UserSession>,\n  deleteLegacyCookies = true,\n): Promise<UserSession> => {\n  const cookieName = getOldCookieName(apiKey);\n  const cookies = await cookieStorage.getRaw(cookieName);\n  if (!cookies) {\n    return {\n      optOut: false,\n    };\n  }\n  if (deleteLegacyCookies) {\n    await cookieStorage.remove(cookieName);\n  }\n  const [deviceId, userId, optOut, sessionId, lastEventTime, lastEventId] = cookies.split('.');\n  return {\n    deviceId,\n    userId: decode(userId),\n    sessionId: parseTime(sessionId),\n    lastEventId: parseTime(lastEventId),\n    lastEventTime: parseTime(lastEventTime),\n    optOut: Boolean(optOut),\n  };\n};\n\nexport const parseTime = (num: string) => {\n  const integer = parseInt(num, 32);\n  if (isNaN(integer)) {\n    return undefined;\n  }\n  return integer;\n};\n\nexport const decode = (value?: string): string | undefined => {\n  if (!atob || !escape || !value) {\n    return undefined;\n  }\n  try {\n    return decodeURIComponent(escape(atob(value)));\n  } catch {\n    return undefined;\n  }\n};\n"
  },
  {
    "path": "packages/analytics-browser/src/default-tracking.ts",
    "content": "import {\n  PageTrackingHistoryChanges,\n  PageTrackingOptions,\n  PageTrackingTrackOn,\n  ElementInteractionsOptions,\n  FormInteractionsOptions,\n  BrowserOptions,\n  AutocaptureOptions,\n  AttributionOptions,\n  NetworkTrackingOptions,\n  FrustrationInteractionsOptions,\n  CustomEnrichmentOptions,\n  PerformanceTrackingOptions,\n  isChromeExtension,\n} from '@amplitude/analytics-core';\n\n/**\n * A subset of AutocaptureOptions that includes the autocapture features that\n * are made available to users by default (even if \"config.autocapture === undefined\")\n */\ntype AutocaptureOptionsDefaultAvailable = Pick<\n  AutocaptureOptions,\n  'pageViews' | 'sessions' | 'fileDownloads' | 'formInteractions' | 'attribution' | 'pageUrlEnrichment'\n>;\n\n/**\n * Returns false if autocapture === false or if autocapture[event],\n * otherwise returns true (even if \"config.autocapture === undefined\")\n */\nconst isTrackingEnabled = (\n  autocapture: AutocaptureOptionsDefaultAvailable | boolean | undefined,\n  event: keyof AutocaptureOptionsDefaultAvailable,\n) => {\n  if (typeof autocapture === 'boolean') {\n    return autocapture;\n  }\n\n  if (autocapture?.[event] === false) {\n    return false;\n  }\n\n  if (isChromeExtension()) {\n    return !!autocapture?.[event];\n  }\n\n  return true;\n};\n\nexport const isAttributionTrackingEnabled = (autocapture: AutocaptureOptions | boolean | undefined) =>\n  isTrackingEnabled(autocapture, 'attribution');\n\nexport const isFileDownloadTrackingEnabled = (autocapture: AutocaptureOptions | boolean | undefined) =>\n  isTrackingEnabled(autocapture, 'fileDownloads');\n\nexport const isFormInteractionTrackingEnabled = (autocapture: AutocaptureOptions | boolean | undefined) =>\n  isTrackingEnabled(autocapture, 'formInteractions');\n\nexport const isPageViewTrackingEnabled = (autocapture: AutocaptureOptions | boolean | undefined) =>\n  isTrackingEnabled(autocapture, 'pageViews');\n\nexport const isSessionTrackingEnabled = (autocapture: AutocaptureOptions | boolean | undefined) =>\n  isTrackingEnabled(autocapture, 'sessions');\n\nexport const isPageUrlEnrichmentEnabled = (autocapture: AutocaptureOptions | boolean | undefined) =>\n  isTrackingEnabled(autocapture, 'pageUrlEnrichment');\n\n/**\n * Returns true if\n * 1. if autocapture.networkTracking === true\n * 2. if autocapture.networkTracking === object\n * otherwise returns false\n */\nexport const isNetworkTrackingEnabled = (autocapture: AutocaptureOptions | boolean | undefined) => {\n  if (typeof autocapture === 'boolean') {\n    return autocapture;\n  }\n\n  if (\n    typeof autocapture === 'object' &&\n    (autocapture.networkTracking === true || typeof autocapture.networkTracking === 'object')\n  ) {\n    return true;\n  }\n\n  return false;\n};\n\n/**\n * Returns true if\n * 1. autocapture === true\n * 2. if autocapture.elementInteractions === true\n * 3. if autocapture.elementInteractions === object\n * otherwise returns false\n */\nexport const isElementInteractionsEnabled = (autocapture: AutocaptureOptions | boolean | undefined): boolean => {\n  if (typeof autocapture === 'boolean') {\n    return autocapture;\n  }\n\n  if (\n    typeof autocapture === 'object' &&\n    (autocapture.elementInteractions === true || typeof autocapture.elementInteractions === 'object')\n  ) {\n    return true;\n  }\n\n  return false;\n};\n\n/**\n * Returns true if\n * 1. autocapture === true\n * 2. if autocapture.webVitals === true\n * otherwise returns false\n */\nexport const isWebVitalsEnabled = (autocapture: AutocaptureOptions | boolean | undefined): boolean => {\n  if (typeof autocapture === 'boolean') {\n    return autocapture;\n  }\n\n  if (typeof autocapture === 'object' && autocapture.webVitals === true) {\n    return true;\n  }\n\n  return false;\n};\n\nexport const isFrustrationInteractionsEnabled = (autocapture: AutocaptureOptions | boolean | undefined): boolean => {\n  if (typeof autocapture === 'boolean') {\n    return autocapture;\n  }\n\n  if (\n    typeof autocapture === 'object' &&\n    (autocapture.frustrationInteractions === true || typeof autocapture.frustrationInteractions === 'object')\n  ) {\n    return true;\n  }\n\n  return false;\n};\n\nexport const isPerformanceTrackingEnabled = (autocapture: AutocaptureOptions | boolean | undefined): boolean => {\n  if (\n    typeof autocapture === 'object' &&\n    (autocapture.performanceTracking === true || typeof autocapture.performanceTracking === 'object')\n  ) {\n    return true;\n  }\n\n  return false;\n};\n\nexport const getPerformanceTrackingConfig = (config: BrowserOptions): PerformanceTrackingOptions | undefined => {\n  if (typeof config.autocapture !== 'object') {\n    return undefined;\n  }\n\n  const performanceTracking = config.autocapture.performanceTracking;\n\n  if (performanceTracking === true) {\n    return { mainThreadBlock: true };\n  }\n\n  if (typeof performanceTracking === 'object' && performanceTracking !== null) {\n    return performanceTracking;\n  }\n\n  return undefined;\n};\n\nexport const isCustomEnrichmentEnabled = (customEnrichment: boolean | CustomEnrichmentOptions | undefined) => {\n  if (typeof customEnrichment === 'boolean') {\n    return customEnrichment;\n  }\n\n  if (typeof customEnrichment === 'object' && customEnrichment !== null && customEnrichment.enabled !== false) {\n    return true;\n  }\n\n  return false;\n};\n\nexport const getElementInteractionsConfig = (config: BrowserOptions): ElementInteractionsOptions | undefined => {\n  if (\n    isElementInteractionsEnabled(config.autocapture) &&\n    typeof config.autocapture === 'object' &&\n    typeof config.autocapture.elementInteractions === 'object'\n  ) {\n    return config.autocapture.elementInteractions;\n  }\n  return undefined;\n};\n\nexport const getFrustrationInteractionsConfig = (\n  config: BrowserOptions,\n): FrustrationInteractionsOptions | undefined => {\n  if (\n    isFrustrationInteractionsEnabled(config.autocapture) &&\n    typeof config.autocapture === 'object' &&\n    typeof config.autocapture.frustrationInteractions === 'object'\n  ) {\n    return config.autocapture.frustrationInteractions;\n  }\n  return undefined;\n};\n\nexport const getNetworkTrackingConfig = (config: BrowserOptions): NetworkTrackingOptions | undefined => {\n  if (isNetworkTrackingEnabled(config.autocapture)) {\n    let networkTrackingConfig;\n    if (typeof config.autocapture === 'object' && typeof config.autocapture.networkTracking === 'object') {\n      networkTrackingConfig = config.autocapture.networkTracking;\n    } else if (config.networkTrackingOptions) {\n      networkTrackingConfig = config.networkTrackingOptions;\n    }\n    return {\n      ...networkTrackingConfig,\n      captureRules: networkTrackingConfig?.captureRules?.map((rule) => {\n        // if URLs and hosts are both set, URLs take precedence over hosts\n        if (rule.urls?.length && rule.hosts?.length) {\n          const hostsString = JSON.stringify(rule.hosts);\n          const urlsString = JSON.stringify(rule.urls);\n          /* istanbul ignore next */\n          config.loggerProvider?.warn(\n            `Found network capture rule with both urls='${urlsString}' and hosts='${hostsString}' set. ` +\n              `Definition of urls takes precedence over hosts, so ignoring hosts.`,\n          );\n          return { ...rule, hosts: undefined };\n        }\n        return rule;\n      }),\n    };\n  }\n  return;\n};\n\nexport const getPageViewTrackingConfig = (config: BrowserOptions): PageTrackingOptions => {\n  let trackOn: PageTrackingTrackOn | undefined = () => false;\n  let trackHistoryChanges: PageTrackingHistoryChanges | undefined = undefined;\n  let eventType: string | undefined;\n  const pageCounter = config.pageCounter;\n\n  const isDefaultPageViewTrackingEnabled = isPageViewTrackingEnabled(config.defaultTracking);\n  if (isDefaultPageViewTrackingEnabled) {\n    trackOn = undefined;\n    eventType = undefined;\n\n    if (\n      config.defaultTracking &&\n      typeof config.defaultTracking === 'object' &&\n      config.defaultTracking.pageViews &&\n      typeof config.defaultTracking.pageViews === 'object'\n    ) {\n      if ('trackOn' in config.defaultTracking.pageViews) {\n        trackOn = config.defaultTracking.pageViews.trackOn;\n      }\n\n      if ('trackHistoryChanges' in config.defaultTracking.pageViews) {\n        trackHistoryChanges = config.defaultTracking.pageViews.trackHistoryChanges;\n      }\n\n      if ('eventType' in config.defaultTracking.pageViews && config.defaultTracking.pageViews.eventType) {\n        eventType = config.defaultTracking.pageViews.eventType;\n      }\n    }\n  }\n\n  return {\n    trackOn,\n    trackHistoryChanges,\n    eventType,\n    pageCounter,\n  };\n};\n\nexport const getAttributionTrackingConfig = (config: BrowserOptions): AttributionOptions => {\n  if (\n    isAttributionTrackingEnabled(config.defaultTracking) &&\n    config.defaultTracking &&\n    typeof config.defaultTracking === 'object' &&\n    config.defaultTracking.attribution &&\n    typeof config.defaultTracking.attribution === 'object'\n  ) {\n    return {\n      ...config.defaultTracking.attribution,\n    };\n  }\n\n  return {};\n};\n\nexport const getFormInteractionsConfig = (config: BrowserOptions): FormInteractionsOptions | undefined => {\n  if (\n    isFormInteractionTrackingEnabled(config.defaultTracking) &&\n    config.defaultTracking &&\n    typeof config.defaultTracking === 'object' &&\n    typeof config.defaultTracking.formInteractions === 'object'\n  ) {\n    return config.defaultTracking.formInteractions;\n  }\n  return undefined;\n};\n"
  },
  {
    "path": "packages/analytics-browser/src/det-notification.ts",
    "content": "import { BrowserConfig } from '@amplitude/analytics-core';\n\nlet notified = false;\n\nexport const detNotify = (config: BrowserConfig): void => {\n  if (notified || config.defaultTracking !== undefined) {\n    return;\n  }\n\n  const message = `\\`options.defaultTracking\\` is set to undefined. This implicitly configures your Amplitude instance to track Page Views, Sessions, File Downloads, and Form Interactions. You can suppress this warning by explicitly setting a value to \\`options.defaultTracking\\`. The value must either be a boolean, to enable and disable all default events, or an object, for advanced configuration. For example:\n\namplitude.init(<YOUR_API_KEY>, {\n  defaultTracking: true,\n});\n\nVisit https://www.docs.developers.amplitude.com/data/sdks/browser-2/#tracking-default-events for more details.`;\n  config.loggerProvider.warn(message);\n  notified = true;\n};\n\n/**\n * @private\n * This function is meant for testing purposes only\n */\nexport const resetNotify = () => {\n  notified = false;\n};\n"
  },
  {
    "path": "packages/analytics-browser/src/gtm-snippet-index.ts",
    "content": "import { getGlobalScope } from '@amplitude/analytics-core';\nimport * as amplitudeGTM from './index';\nimport { createInstance } from './browser-client-factory';\nimport { runQueuedFunctions } from './utils/snippet-helper';\n\n// https://developer.mozilla.org/en-US/docs/Glossary/IIFE\n(function () {\n  const GlobalScope = getGlobalScope();\n\n  if (!GlobalScope) {\n    console.error('[Amplitude] Error: GlobalScope is not defined');\n    return;\n  }\n\n  const createNamedInstance = (instanceName?: string) => {\n    const instance = createInstance();\n    const GlobalScope = getGlobalScope();\n    if (GlobalScope && GlobalScope.amplitudeGTM && GlobalScope.amplitudeGTM._iq && instanceName) {\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore\n      GlobalScope.amplitudeGTM._iq[instanceName] = instance;\n    }\n    return instance;\n  };\n\n  GlobalScope.amplitudeGTM = Object.assign(GlobalScope.amplitudeGTM || {}, amplitudeGTM, {\n    createInstance: createNamedInstance,\n  });\n\n  if (GlobalScope.amplitudeGTM.invoked) {\n    const queue = GlobalScope.amplitudeGTM._q;\n    GlobalScope.amplitudeGTM._q = [];\n    runQueuedFunctions(amplitudeGTM, queue);\n\n    const instanceNames = Object.keys(GlobalScope.amplitudeGTM._iq) || [];\n    for (let i = 0; i < instanceNames.length; i++) {\n      const instanceName = instanceNames[i];\n      const instance = Object.assign(GlobalScope.amplitudeGTM._iq[instanceName], createNamedInstance(instanceName));\n      const queue = instance._q;\n      instance._q = [];\n      runQueuedFunctions(instance, queue);\n    }\n  }\n})();\n"
  },
  {
    "path": "packages/analytics-browser/src/index.ts",
    "content": "/* eslint-disable @typescript-eslint/unbound-method */\nimport client from './browser-client-factory';\nexport { createInstance } from './browser-client-factory';\nexport const {\n  add,\n  extendSession,\n  flush,\n  getDeviceId,\n  getIdentity,\n  getOptOut,\n  getSessionId,\n  getUserId,\n  groupIdentify,\n  identify,\n  init,\n  logEvent,\n  remove,\n  reset,\n  revenue,\n  setDeviceId,\n  setGroup,\n  setIdentity,\n  setOptOut,\n  setSessionId,\n  setTransport,\n  setUserId,\n  track,\n  _setDiagnosticsSampleRate,\n} = client;\nexport { AmplitudeBrowser } from './browser-client';\nexport { runQueuedFunctions } from './utils/snippet-helper';\nexport { Revenue, Identify } from '@amplitude/analytics-core';\n\nexport { trackVideo, type VideoCaptureOptions } from './video-capture/video-capture';\n\n// Export types to maintain backward compatibility with `analytics-types`.\n// In the next major version, only export customer-facing types to reduce the public API surface.\nexport * as Types from './types';\n"
  },
  {
    "path": "packages/analytics-browser/src/lib-prefix.ts",
    "content": "export const LIBPREFIX = 'amplitude-ts';\n"
  },
  {
    "path": "packages/analytics-browser/src/plugins/context.ts",
    "content": "import { UUID, getLanguage, Event, BeforePlugin, BrowserConfig } from '@amplitude/analytics-core';\nimport { VERSION } from '../version';\nimport { LIBPREFIX } from '../lib-prefix';\n\nconst BROWSER_PLATFORM = 'Web';\nconst IP_ADDRESS = '$remote';\nexport class Context implements BeforePlugin {\n  name = '@amplitude/plugin-context-browser';\n  type = 'before' as const;\n\n  // this.config is defined in setup() which will always be called first\n  // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n  // @ts-ignore\n  config: BrowserConfig;\n  userAgent: string | undefined;\n  library = `${LIBPREFIX}/${VERSION}`;\n\n  constructor() {\n    /* istanbul ignore else */\n    if (typeof navigator !== 'undefined') {\n      this.userAgent = navigator.userAgent;\n    }\n  }\n\n  setup(config: BrowserConfig): Promise<undefined> {\n    this.config = config;\n\n    return Promise.resolve(undefined);\n  }\n\n  async execute(context: Event): Promise<Event> {\n    const time = new Date().getTime();\n    const lastEventId = this.config.lastEventId ?? -1;\n    const nextEventId = context.event_id ?? lastEventId + 1;\n    this.config.lastEventId = nextEventId;\n    if (!context.time) {\n      this.config.lastEventTime = time;\n    }\n\n    const event: Event = {\n      user_id: this.config.userId,\n      device_id: this.config.deviceId,\n      session_id: this.config.sessionId,\n      time,\n      ...(this.config.appVersion && { app_version: this.config.appVersion }),\n      ...(this.config.trackingOptions.platform && { platform: BROWSER_PLATFORM }),\n      ...(this.config.trackingOptions.language && { language: getLanguage() }),\n      ...(this.config.trackingOptions.ipAddress && { ip: IP_ADDRESS }),\n      insert_id: UUID(),\n      partner_id: this.config.partnerId,\n      plan: this.config.plan,\n      ...(this.config.ingestionMetadata && {\n        ingestion_metadata: {\n          source_name: this.config.ingestionMetadata.sourceName,\n          source_version: this.config.ingestionMetadata.sourceVersion,\n        },\n      }),\n      ...context,\n      event_id: nextEventId,\n      library: this.library,\n      user_agent: this.userAgent,\n    };\n    return event;\n  }\n}\n"
  },
  {
    "path": "packages/analytics-browser/src/plugins/file-download-tracking.ts",
    "content": "import { DEFAULT_FILE_DOWNLOAD_EVENT, FILE_EXTENSION, FILE_NAME, LINK_ID, LINK_TEXT, LINK_URL } from '../constants';\nimport { BrowserConfig } from '../config';\nimport { getGlobalScope, Event, EnrichmentPlugin, BrowserClient } from '@amplitude/analytics-core';\n\ninterface EventListener {\n  element: Element;\n  type: 'click';\n  handler: () => void;\n}\n\nexport const fileDownloadTracking = (): EnrichmentPlugin => {\n  let observer: MutationObserver | undefined;\n  let eventListeners: EventListener[] = [];\n  const addEventListener = (element: Element, type: 'click', handler: () => void) => {\n    element.addEventListener(type, handler);\n    eventListeners.push({\n      element,\n      type,\n      handler,\n    });\n  };\n  const removeClickListeners = () => {\n    eventListeners.forEach(({ element, type, handler }) => {\n      /* istanbul ignore next */\n      element?.removeEventListener(type, handler);\n    });\n    eventListeners = [];\n  };\n\n  const name = '@amplitude/plugin-file-download-tracking-browser';\n  const type = 'enrichment';\n\n  const setup = async (config: BrowserConfig, amplitude: BrowserClient) => {\n    const initializeFileDownloadTracking = () => {\n      /* istanbul ignore if */\n      if (!amplitude) {\n        // TODO: Add required minimum version of @amplitude/analytics-browser\n        config.loggerProvider.warn(\n          'File download tracking requires a later version of @amplitude/analytics-browser. File download events are not tracked.',\n        );\n        return;\n      }\n\n      /* istanbul ignore if */\n      if (typeof document === 'undefined') {\n        return;\n      }\n\n      const addFileDownloadListener = (a: HTMLAnchorElement) => {\n        let url: URL;\n        try {\n          // eslint-disable-next-line no-restricted-globals\n          url = new URL(a.href, window.location.href);\n        } catch {\n          /* istanbul ignore next */\n          return;\n        }\n        const result = ext.exec(url.href);\n        const fileExtension = result?.[1];\n\n        if (fileExtension) {\n          addEventListener(a, 'click', () => {\n            if (fileExtension) {\n              amplitude.track(DEFAULT_FILE_DOWNLOAD_EVENT, {\n                [FILE_EXTENSION]: fileExtension,\n                [FILE_NAME]: url.pathname,\n                [LINK_ID]: a.id,\n                [LINK_TEXT]: a.text,\n                [LINK_URL]: a.href,\n              });\n            }\n          });\n        }\n      };\n\n      const ext =\n        /\\.(pdf|xlsx?|docx?|txt|rtf|csv|exe|key|pp(s|t|tx)|7z|pkg|rar|gz|zip|avi|mov|mp4|mpe?g|wmv|midi?|mp3|wav|wma)(\\?.+)?$/;\n\n      // Adds listener to existing anchor tags\n      const links = Array.from(document.getElementsByTagName('a'));\n      links.forEach(addFileDownloadListener);\n\n      // Adds listener to anchor tags added after initial load\n      /* istanbul ignore else */\n      if (typeof MutationObserver !== 'undefined') {\n        observer = new MutationObserver((mutations) => {\n          mutations.forEach((mutation) => {\n            mutation.addedNodes.forEach((node) => {\n              if (node.nodeName === 'A') {\n                addFileDownloadListener(node as HTMLAnchorElement);\n              }\n              if ('querySelectorAll' in node && typeof node.querySelectorAll === 'function') {\n                Array.from(node.querySelectorAll('a') as HTMLAnchorElement[]).map(addFileDownloadListener);\n              }\n            });\n          });\n        });\n\n        observer.observe(document.body, {\n          subtree: true,\n          childList: true,\n        });\n      }\n    };\n\n    // If the document is already loaded, initialize immediately.\n    /* istanbul ignore else*/\n    if (document.readyState === 'complete') {\n      initializeFileDownloadTracking();\n    } else {\n      // Otherwise, wait for the load event.\n      const window = getGlobalScope();\n      /* istanbul ignore else*/\n      if (window) {\n        window.addEventListener('load', initializeFileDownloadTracking);\n      } else {\n        config.loggerProvider.debug('File download tracking is not installed because global is undefined.');\n      }\n    }\n  };\n\n  const execute = async (event: Event) => event;\n  const teardown = async () => {\n    observer?.disconnect();\n    removeClickListeners();\n  };\n\n  return {\n    name,\n    type,\n    setup,\n    execute,\n    teardown,\n  };\n};\n"
  },
  {
    "path": "packages/analytics-browser/src/plugins/form-interaction-tracking.ts",
    "content": "import {\n  DEFAULT_FORM_START_EVENT,\n  DEFAULT_FORM_SUBMIT_EVENT,\n  FORM_ID,\n  FORM_NAME,\n  FORM_DESTINATION,\n} from '../constants';\nimport { BrowserConfig } from '../config';\nimport {\n  getGlobalScope,\n  Event as AmplitudeEvent,\n  EnrichmentPlugin,\n  BrowserClient,\n  FormInteractionsOptions,\n} from '@amplitude/analytics-core';\nimport { getFormInteractionsConfig } from '../default-tracking';\n\ninterface EventListener {\n  element: Element;\n  type: 'change' | 'submit';\n  handler: (event: Event) => void;\n}\n\nexport const formInteractionTracking = (): EnrichmentPlugin => {\n  let observer: MutationObserver | undefined;\n  let eventListeners: EventListener[] = [];\n\n  const addEventListener = (element: Element, type: 'change' | 'submit', handler: (event: Event) => void) => {\n    element.addEventListener(type, handler);\n    eventListeners.push({\n      element,\n      type,\n      handler,\n    });\n  };\n\n  const removeClickListeners = () => {\n    eventListeners.forEach(({ element, type, handler }) => {\n      /* istanbul ignore next */\n      element?.removeEventListener(type, handler);\n    });\n    eventListeners = [];\n  };\n\n  let formInteractionsConfig: FormInteractionsOptions | undefined;\n\n  const name = '@amplitude/plugin-form-interaction-tracking-browser';\n  const type = 'enrichment';\n  const setup = async (config: BrowserConfig, amplitude: BrowserClient) => {\n    formInteractionsConfig = getFormInteractionsConfig(config);\n\n    const initializeFormTracking = () => {\n      /* istanbul ignore if */\n      if (!amplitude) {\n        // TODO: Add required minimum version of @amplitude/analytics-browser\n        config.loggerProvider.warn(\n          'Form interaction tracking requires a later version of @amplitude/analytics-browser. Form interaction events are not tracked.',\n        );\n        return;\n      }\n\n      /* istanbul ignore if */\n      if (typeof document === 'undefined') {\n        return;\n      }\n\n      const addedFormNodes = new WeakSet<Node>();\n      const addFormInteractionListener = (form: HTMLFormElement) => {\n        if (addedFormNodes.has(form)) {\n          return;\n        }\n        addedFormNodes.add(form);\n\n        let hasFormChanged = false;\n\n        addEventListener(form, 'change', () => {\n          const formDestination = extractFormAction(form);\n          if (!hasFormChanged) {\n            amplitude.track(DEFAULT_FORM_START_EVENT, {\n              [FORM_ID]: stringOrUndefined(form.id),\n              [FORM_NAME]: stringOrUndefined(form.name),\n              [FORM_DESTINATION]: formDestination,\n            });\n          }\n          hasFormChanged = true;\n        });\n\n        addEventListener(form, 'submit', (event: Event) => {\n          const formDestination = extractFormAction(form);\n          if (!hasFormChanged) {\n            amplitude.track(DEFAULT_FORM_START_EVENT, {\n              [FORM_ID]: stringOrUndefined(form.id),\n              [FORM_NAME]: stringOrUndefined(form.name),\n              [FORM_DESTINATION]: formDestination,\n            });\n          }\n          hasFormChanged = true;\n\n          // Check if shouldTrackSubmit callback is provided and use it to determine whether to track form_submit\n          if (formInteractionsConfig?.shouldTrackSubmit !== undefined) {\n            if (\n              typeof formInteractionsConfig.shouldTrackSubmit === 'function' &&\n              typeof SubmitEvent !== 'undefined' &&\n              event instanceof SubmitEvent\n            ) {\n              try {\n                const shouldTrack = formInteractionsConfig.shouldTrackSubmit(event);\n                if (!shouldTrack) {\n                  return;\n                }\n              } catch (e) {\n                config.loggerProvider.warn('shouldTrackSubmit callback threw an error, proceeding with tracking.');\n              }\n            } else {\n              config.loggerProvider.warn(\n                'shouldTrackSubmit is ignored because it is not a function or event is not a SubmitEvent.',\n              );\n            }\n          }\n\n          amplitude.track(DEFAULT_FORM_SUBMIT_EVENT, {\n            [FORM_ID]: stringOrUndefined(form.id),\n            [FORM_NAME]: stringOrUndefined(form.name),\n            [FORM_DESTINATION]: formDestination,\n          });\n          hasFormChanged = false;\n        });\n      };\n\n      // Adds listener to existing anchor tags\n      const forms = Array.from(document.getElementsByTagName('form'));\n      forms.forEach(addFormInteractionListener);\n\n      // Adds listener to anchor tags added after initial load\n      /* istanbul ignore else */\n      if (typeof MutationObserver !== 'undefined') {\n        observer = new MutationObserver((mutations) => {\n          mutations.forEach((mutation) => {\n            mutation.addedNodes.forEach((node) => {\n              if (node.nodeName === 'FORM') {\n                addFormInteractionListener(node as HTMLFormElement);\n              }\n              if ('querySelectorAll' in node && typeof node.querySelectorAll === 'function') {\n                Array.from(node.querySelectorAll('form') as HTMLFormElement[]).map(addFormInteractionListener);\n              }\n            });\n          });\n        });\n\n        observer.observe(document.body, {\n          subtree: true,\n          childList: true,\n        });\n      }\n    };\n\n    // If the document is already loaded, initialize immediately.\n    if (document.readyState === 'complete') {\n      initializeFormTracking();\n    } else {\n      // Otherwise, wait for the load event.\n      // The form interaction plugin observes changes in the dom. For this to work correctly, the observer can only be setup\n      // after the body is built. When Amplitude gets initialized in a script tag, the body tag is still unavailable. So register this\n      // only after the window is loaded\n      const window = getGlobalScope();\n      /* istanbul ignore else*/\n      if (window) {\n        window.addEventListener('load', initializeFormTracking);\n      } else {\n        config.loggerProvider.debug('Form interaction tracking is not installed because global is undefined.');\n      }\n    }\n  };\n  const execute = async (event: AmplitudeEvent) => event;\n  const teardown = async () => {\n    observer?.disconnect();\n    removeClickListeners();\n  };\n\n  return {\n    name,\n    type,\n    setup,\n    execute,\n    teardown,\n  };\n};\n\nexport const stringOrUndefined = <T>(name: T): T extends string ? string : undefined => {\n  /* istanbul ignore if */\n  if (typeof name !== 'string') {\n    // We found instances where the value of `name` is an Element and not a string.\n    // Elements may have circular references and would throw an error when passed to `JSON.stringify(...)`.\n    // If a non-string value is seen, assume there is no value.\n    return undefined as T extends string ? string : undefined;\n  }\n\n  return name as T extends string ? string : undefined;\n};\n\n// Extracts the form action attribute, and normalizes it to a valid URL to preserve the previous behavior of accessing the action property directly.\nexport const extractFormAction = (form: HTMLFormElement): string | null => {\n  let formDestination = form.getAttribute('action');\n  try {\n    // eslint-disable-next-line no-restricted-globals\n    formDestination = new URL(encodeURI(formDestination ?? ''), window.location.href).href;\n  } catch {\n    //\n  }\n  return formDestination;\n};\n"
  },
  {
    "path": "packages/analytics-browser/src/plugins/network-connectivity-checker.ts",
    "content": "import { getGlobalScope, BeforePlugin, BrowserClient, BrowserConfig } from '@amplitude/analytics-core';\n\ninterface EventListener {\n  type: 'online' | 'offline';\n  handler: () => void;\n}\n\nexport const networkConnectivityCheckerPlugin = (): BeforePlugin => {\n  const name = '@amplitude/plugin-network-checker-browser';\n  const type = 'before' as const;\n  const globalScope = getGlobalScope();\n  let eventListeners: EventListener[] = [];\n\n  const addNetworkListener = (type: 'online' | 'offline', handler: () => void) => {\n    /* istanbul ignore next */\n    if (globalScope?.addEventListener) {\n      globalScope?.addEventListener(type, handler);\n      eventListeners.push({\n        type,\n        handler,\n      });\n    }\n  };\n\n  const removeNetworkListeners = () => {\n    eventListeners.forEach(({ type, handler }) => {\n      /* istanbul ignore next */\n      globalScope?.removeEventListener(type, handler);\n    });\n    eventListeners = [];\n  };\n\n  const setup = async (config: BrowserConfig, amplitude: BrowserClient) => {\n    if (typeof navigator === 'undefined') {\n      config.loggerProvider.debug(\n        'Network connectivity checker plugin is disabled because navigator is not available.',\n      );\n      config.offline = false;\n      return;\n    }\n\n    config.offline = !navigator.onLine;\n\n    addNetworkListener('online', () => {\n      config.loggerProvider.debug('Network connectivity changed to online.');\n      config.offline = false;\n      // Flush immediately will cause ERR_NETWORK_CHANGED\n      setTimeout(() => {\n        amplitude.flush();\n      }, config.flushIntervalMillis);\n    });\n\n    addNetworkListener('offline', () => {\n      config.loggerProvider.debug('Network connectivity changed to offline.');\n      config.offline = true;\n    });\n  };\n\n  const teardown = async () => {\n    removeNetworkListeners();\n  };\n\n  return {\n    name,\n    type,\n    setup,\n    teardown,\n  };\n};\n"
  },
  {
    "path": "packages/analytics-browser/src/snippet-index.ts",
    "content": "import { getGlobalScope, registerSdkLoaderMetadata } from '@amplitude/analytics-core';\nimport * as amplitude from './index';\nimport { createInstance } from './browser-client-factory';\nimport { runQueuedFunctions } from './utils/snippet-helper';\n\nregisterSdkLoaderMetadata({\n  scriptUrl: resolveCurrentScriptUrl(),\n});\n\nfunction resolveCurrentScriptUrl(): string | undefined {\n  if (typeof document === 'undefined') {\n    return undefined;\n  }\n\n  const currentScript = document.currentScript as HTMLScriptElement | null;\n  if (currentScript?.src) {\n    return currentScript.src;\n  }\n\n  return undefined;\n}\n\n// https://developer.mozilla.org/en-US/docs/Glossary/IIFE\n(function () {\n  const GlobalScope = getGlobalScope();\n\n  if (!GlobalScope) {\n    console.error('[Amplitude] Error: GlobalScope is not defined');\n    return;\n  }\n\n  const createNamedInstance = (instanceName?: string) => {\n    const instance = createInstance();\n    const GlobalScope = getGlobalScope();\n    if (GlobalScope && GlobalScope.amplitude && GlobalScope.amplitude._iq && instanceName) {\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore\n      GlobalScope.amplitude._iq[instanceName] = instance;\n    }\n    return instance;\n  };\n\n  GlobalScope.amplitude = Object.assign(GlobalScope.amplitude || {}, amplitude, {\n    createInstance: createNamedInstance,\n  });\n\n  if (GlobalScope.amplitude.invoked) {\n    const queue = GlobalScope.amplitude._q;\n    GlobalScope.amplitude._q = [];\n    runQueuedFunctions(amplitude, queue);\n\n    const instanceNames = Object.keys(GlobalScope.amplitude._iq) || [];\n    for (let i = 0; i < instanceNames.length; i++) {\n      const instanceName = instanceNames[i];\n      const instance = Object.assign(GlobalScope.amplitude._iq[instanceName], createNamedInstance(instanceName));\n      const queue = instance._q;\n      instance._q = [];\n      runQueuedFunctions(instance, queue);\n    }\n  }\n})();\n"
  },
  {
    "path": "packages/analytics-browser/src/storage/local-storage.ts",
    "content": "import { getGlobalScope, ILogger, BrowserStorage } from '@amplitude/analytics-core';\n\nconst MAX_ARRAY_LENGTH = 1000;\n\ninterface LocalStorageOptions {\n  loggerProvider?: ILogger;\n}\nexport class LocalStorage<T> extends BrowserStorage<T> {\n  loggerProvider?: ILogger;\n\n  constructor(config?: LocalStorageOptions) {\n    let localStorage;\n\n    try {\n      localStorage = getGlobalScope()?.localStorage;\n    } catch (e) {\n      config?.loggerProvider?.debug(`Failed to access localStorage. error=${JSON.stringify(e)}`);\n      localStorage = undefined;\n    }\n    super(localStorage);\n    this.loggerProvider = config?.loggerProvider;\n  }\n\n  async set(key: string, value: T): Promise<void> {\n    if (Array.isArray(value) && value.length > MAX_ARRAY_LENGTH) {\n      const droppedEventsCount = value.length - MAX_ARRAY_LENGTH;\n      await super.set(key, value.slice(0, MAX_ARRAY_LENGTH) as T);\n      this.loggerProvider?.error(\n        `Failed to save ${droppedEventsCount} events because the queue length exceeded ${MAX_ARRAY_LENGTH}.`,\n      );\n    } else {\n      await super.set(key, value);\n    }\n  }\n}\n"
  },
  {
    "path": "packages/analytics-browser/src/storage/session-storage.ts",
    "content": "import { getGlobalScope, BrowserStorage } from '@amplitude/analytics-core';\n\nexport class SessionStorage<T> extends BrowserStorage<T> {\n  constructor() {\n    super(getGlobalScope()?.sessionStorage);\n  }\n}\n"
  },
  {
    "path": "packages/analytics-browser/src/transports/fetch.ts",
    "content": "import {\n  BaseTransport,\n  compressToGzipArrayBuffer,\n  isCompressionStreamAvailable,\n  MIN_GZIP_UPLOAD_BODY_SIZE_BYTES,\n  Payload,\n  Response,\n  Transport,\n} from '@amplitude/analytics-core';\n\n// Temporary browser-specific fetch transport with gzip support.\n// TODO: Merge this implementation back into @amplitude/analytics-core FetchTransport\n// once React Native SDK supports request body gzip.\nexport class FetchTransport extends BaseTransport implements Transport {\n  private customHeaders: Record<string, string>;\n\n  constructor(customHeaders: Record<string, string> = {}) {\n    super();\n    this.customHeaders = customHeaders;\n  }\n\n  async send(serverUrl: string, payload: Payload, shouldCompressUploadBody = false): Promise<Response | null> {\n    /* istanbul ignore if */\n    if (typeof fetch === 'undefined') {\n      throw new Error('FetchTransport is not supported');\n    }\n\n    const bodyString = JSON.stringify(payload);\n    const shouldCompressBody =\n      shouldCompressUploadBody &&\n      bodyString.length >= MIN_GZIP_UPLOAD_BODY_SIZE_BYTES &&\n      isCompressionStreamAvailable();\n\n    let body: string | ArrayBuffer = bodyString;\n    let headers: Record<string, string> = {\n      'Content-Type': 'application/json',\n      Accept: '*/*',\n    };\n\n    if (shouldCompressBody) {\n      const compressed = await compressToGzipArrayBuffer(bodyString);\n      if (compressed) {\n        headers['Content-Encoding'] = 'gzip';\n        body = compressed;\n      }\n    }\n    headers = {\n      ...this.customHeaders,\n      ...headers,\n    };\n\n    const options: RequestInit = {\n      headers,\n      body,\n      method: 'POST',\n    };\n\n    const response = await fetch(serverUrl, options);\n    const responseText = await response.text();\n    try {\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n      return this.buildResponse(JSON.parse(responseText));\n    } catch {\n      return this.buildResponse({ code: response.status });\n    }\n  }\n}\n"
  },
  {
    "path": "packages/analytics-browser/src/transports/send-beacon.ts",
    "content": "import { BaseTransport, getGlobalScope, Payload, Response, Transport } from '@amplitude/analytics-core';\n\n/**\n * SendBeacon does not support custom headers (e.g. Content-Encoding: gzip),\n * so request body compression is not applied even when enableRequestBodyCompression is true.\n */\nexport class SendBeaconTransport extends BaseTransport implements Transport {\n  constructor() {\n    super();\n  }\n\n  async send(serverUrl: string, payload: Payload, _enableRequestBodyCompression = false): Promise<Response | null> {\n    return new Promise((resolve, reject) => {\n      const globalScope = getGlobalScope();\n      /* istanbul ignore if */\n      if (!globalScope?.navigator.sendBeacon) {\n        throw new Error('SendBeaconTransport is not supported');\n      }\n      try {\n        const data = JSON.stringify(payload);\n        // SendBeacon cannot set Content-Encoding, so we always send uncompressed\n        const success = globalScope.navigator.sendBeacon(serverUrl, data);\n        if (success) {\n          return resolve(\n            this.buildResponse({\n              code: 200,\n              events_ingested: payload.events.length,\n              payload_size_bytes: data.length,\n              server_upload_time: Date.now(),\n            }),\n          );\n        }\n        return resolve(this.buildResponse({ code: 500 }));\n      } catch (e) {\n        reject(e);\n      }\n    });\n  }\n}\n"
  },
  {
    "path": "packages/analytics-browser/src/transports/xhr.ts",
    "content": "import {\n  BaseTransport,\n  compressToGzipArrayBuffer,\n  isCompressionStreamAvailable,\n  MIN_GZIP_UPLOAD_BODY_SIZE_BYTES,\n  Payload,\n  Response,\n  Transport,\n} from '@amplitude/analytics-core';\n\nexport class XHRTransport extends BaseTransport implements Transport {\n  private state = {\n    done: 4,\n  };\n  private customHeaders: Record<string, string>;\n\n  constructor(customHeaders: Record<string, string> = {}) {\n    super();\n    this.customHeaders = customHeaders;\n  }\n\n  async send(serverUrl: string, payload: Payload, shouldCompressUploadBody = false): Promise<Response | null> {\n    return new Promise((resolve, reject) => {\n      /* istanbul ignore if */\n      if (typeof XMLHttpRequest === 'undefined') {\n        reject(new Error('XHRTransport is not supported.'));\n      }\n\n      const xhr = new XMLHttpRequest();\n      xhr.open('POST', serverUrl, true);\n      xhr.onreadystatechange = () => {\n        if (xhr.readyState === this.state.done) {\n          const responseText = xhr.responseText;\n          try {\n            // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n            resolve(this.buildResponse(JSON.parse(responseText)));\n          } catch {\n            resolve(this.buildResponse({ code: xhr.status }));\n          }\n        }\n      };\n\n      let headers: Record<string, string> = {\n        'Content-Type': 'application/json',\n        Accept: '*/*',\n      };\n\n      const bodyString = JSON.stringify(payload);\n      const shouldCompressBody =\n        shouldCompressUploadBody &&\n        bodyString.length >= MIN_GZIP_UPLOAD_BODY_SIZE_BYTES &&\n        isCompressionStreamAvailable();\n\n      const sendBody = (body: string | ArrayBuffer) => {\n        headers = {\n          ...this.customHeaders,\n          ...headers,\n        };\n\n        for (const [key, value] of Object.entries(headers)) {\n          xhr.setRequestHeader(key, value);\n        }\n        xhr.send(body);\n      };\n\n      const doSend = async () => {\n        if (shouldCompressBody) {\n          const compressed = await compressToGzipArrayBuffer(bodyString);\n          if (compressed) {\n            headers['Content-Encoding'] = 'gzip';\n            sendBody(compressed);\n          } else {\n            sendBody(bodyString);\n          }\n        } else {\n          sendBody(bodyString);\n        }\n      };\n      doSend().catch(reject);\n    });\n  }\n}\n"
  },
  {
    "path": "packages/analytics-browser/src/types.ts",
    "content": "/* eslint-disable @typescript-eslint/unbound-method */\nexport {\n  AmplitudeReturn,\n  BaseEvent,\n  EventOptions,\n  BrowserClient,\n  AttributionOptions,\n  AutocaptureOptions,\n  BrowserOptions,\n  BrowserConfig,\n  IConfig,\n  Event,\n  IdentifyEvent,\n  GroupIdentifyEvent,\n  IdentifyOperation,\n  SpecialEventType,\n  IIdentify,\n  IRevenue,\n  RevenueProperty,\n  ILogger,\n  LogLevel,\n  Plugin,\n  BeforePlugin,\n  EnrichmentPlugin,\n  DestinationPlugin,\n  Result,\n  ServerZoneType,\n  ServerZone,\n  IdentityStorageType,\n  Storage,\n  TransportType,\n  OfflineDisabled,\n  Messenger,\n  ElementInteractionsOptions,\n  ActionType,\n  DEFAULT_CSS_SELECTOR_ALLOWLIST,\n  DEFAULT_DATA_ATTRIBUTE_PREFIX,\n  DEFAULT_ACTION_CLICK_ALLOWLIST,\n  Campaign,\n  ClickIdParameters,\n  ReferrerParameters,\n  UTMParameters,\n  ValidPropertyType,\n  ExcludeInternalReferrersOptions,\n  EXCLUDE_INTERNAL_REFERRERS_CONDITIONS,\n} from '@amplitude/analytics-core';\n"
  },
  {
    "path": "packages/analytics-browser/src/utils/snippet-helper.ts",
    "content": "import { Result, AmplitudeReturn } from '@amplitude/analytics-core';\n\ninterface ProxyItem {\n  name: string;\n  args: any[];\n  resolve?: (promise: Promise<Result>) => void;\n}\n\ntype QueueProxy = Array<ProxyItem>;\n\ninterface InstanceProxy {\n  _q: QueueProxy;\n  _iq: Record<string, InstanceProxy>;\n}\n\n/**\n * Applies the proxied functions on the proxied amplitude snippet to an instance of the real object.\n * @ignore\n */\nexport const runQueuedFunctions = (instance: object, queue: QueueProxy) => {\n  convertProxyObjectToRealObject(instance, queue);\n};\n\n/**\n * Applies the proxied functions on the proxied object to an instance of the real object.\n * Used to convert proxied Identify and Revenue objects.\n */\nexport const convertProxyObjectToRealObject = <T>(instance: T, queue: QueueProxy): T => {\n  for (let i = 0; i < queue.length; i++) {\n    const { name, args, resolve } = queue[i];\n    const fn = instance && instance[name as keyof T];\n    if (typeof fn === 'function') {\n      const result = fn.apply(instance, args) as AmplitudeReturn<Result>;\n      if (typeof resolve === 'function') {\n        resolve(result?.promise);\n      }\n    }\n  }\n  return instance;\n};\n\n/**\n * Check if the param is snippet proxy\n */\nexport const isInstanceProxy = (instance: unknown): instance is InstanceProxy => {\n  const instanceProxy = instance as InstanceProxy;\n  return instanceProxy && instanceProxy._q !== undefined;\n};\n"
  },
  {
    "path": "packages/analytics-browser/src/version.ts",
    "content": "export const VERSION = '2.42.3';\n"
  },
  {
    "path": "packages/analytics-browser/src/video-capture/video-capture.ts",
    "content": "import { VideoState, VideoObserver, BrowserClient, EmbeddedVideoPlayer, VideoVendor } from '@amplitude/analytics-core';\n\nexport class VideoCapture {\n  private videoEl: HTMLVideoElement | null = null;\n  private embeddedVideoPlayer: EmbeddedVideoPlayer | null = null;\n  private vendor?: VideoVendor;\n  private extraEventProperties: Record<string, string | number | boolean> = {};\n\n  private listeners: ((previousState: VideoState, nextState: VideoState) => void)[] = [];\n  private onRemoveListeners: (() => void)[] = [];\n\n  constructor(private readonly amplitude: BrowserClient) {}\n\n  /**\n   * Specify a video element to capture events from\n   *\n   * @param videoEl - The HTML video element to capture events from.\n   * @returns The VideoCapture instance.\n   */\n  withVideoElement(videoEl: HTMLVideoElement): VideoCapture {\n    this.videoEl = videoEl;\n    return this;\n  }\n\n  /**\n   * Specify an embedded video player.js instance to capture events from\n   * @param player - The embedded video player.js instance to capture events from.\n   * @returns The VideoCapture instance.\n   */\n  withEmbeddedPlayer(player: EmbeddedVideoPlayer): VideoCapture {\n    this.embeddedVideoPlayer = player;\n    return this;\n  }\n\n  /**\n   * Specify a vendor to capture extra vendor-specific event properties\n   *\n   * @param vendor - The vendor of the video player. Currently only \"mux\" is supported.\n   * @returns The VideoCapture instance.\n   */\n  withVendor(vendor: VideoVendor): VideoCapture {\n    this.vendor = vendor;\n    return this;\n  }\n\n  /**\n   * Specify extra event properties to include in all captured events\n   *\n   * @param properties - The extra event properties to include in the Amplitude event.\n   * @returns The VideoCapture instance.\n   */\n  withExtraEventProperties(properties: Record<string, string | number | boolean>): VideoCapture {\n    this.extraEventProperties = properties;\n    return this;\n  }\n\n  /**\n   * Track a \"Video Content Started\" event every time the video starts playing\n   * @returns The VideoCapture instance.\n   */\n  captureVideoStarted(): VideoCapture {\n    this.listeners.push((previousState, nextState) => {\n      if (previousState.playbackState !== 'playing' && nextState.playbackState === 'playing') {\n        // placeholder for Heartbeat Start Event\n        this.amplitude.track('Video Content Started', {\n          ...nextState.lastEvent,\n          ...this.extraEventProperties,\n        });\n      }\n    });\n    return this;\n  }\n\n  /**\n   * Track a \"Video Content Stopped\" event every time the video stops playing\n   * @returns The VideoCapture instance.\n   */\n  captureVideoStopped(): VideoCapture {\n    this.listeners.push((previousState, nextState) => {\n      if (previousState.playbackState === 'playing' && nextState.playbackState !== 'playing') {\n        // placeholder for Heartbeat Stop Event\n        this.amplitude.track('Video Content Stopped', {\n          ...nextState.lastEvent,\n          watch_duration: nextState.watchTime,\n          ...this.extraEventProperties,\n        });\n      }\n    });\n    return this;\n  }\n\n  // Placeholder: may need a generic state change listener to capture unusual events or to have\n  // more control over the event tracking.\n  // withStateChangeListener(listener: (previousState: VideoState, nextState: VideoState) => void): VideoCapture {\n\n  /**\n   * Start capturing analytics events for the video element\n   * @returns The VideoCapture instance.\n   * @throws An error if the video element is not specified.\n   */\n  start(): VideoCapture {\n    const videoEl = this.videoEl ?? this.embeddedVideoPlayer;\n    if (!videoEl) {\n      throw new Error(\n        'Video element not specified. Use withVideoElement() or withEmbeddedPlayer() to specify the video element.',\n      );\n    }\n    if (this.videoEl && this.embeddedVideoPlayer) {\n      throw new Error(\n        'Both video element and embedded video player specified. Use only one of withVideoElement() or withEmbeddedPlayer() to specify the video element.',\n      );\n    }\n    const videoObserver = new VideoObserver({\n      videoEl,\n      onStateChange: (previousState, nextState) => {\n        this.listeners.forEach((listener) => listener(previousState, nextState));\n      },\n      vendor: this.vendor,\n      isEmbedded: !!this.embeddedVideoPlayer,\n    });\n\n    this.onRemoveListeners.push(() => {\n      videoObserver.destroy();\n    });\n    return this;\n  }\n\n  stop() {\n    this.onRemoveListeners.forEach((listener) => listener());\n    this.onRemoveListeners = [];\n  }\n}\n\nexport type VideoCaptureOptions = {\n  vendor?: VideoVendor;\n  extraEventProperties?: Record<string, string | number | boolean>;\n};\n\n/**\n * Track video analytics events for an HTML video element or embedded video player.js instance.\n *\n * Captures Video Started and Video Stopped events.\n *\n * @experimental This function is experimental and may not be stable.\n * @param amplitude - The Amplitude client instance.\n * @param videoEl - The HTML video element or embedded video player.js instance to capture events from.\n * @param options - The options for the video capture.\n * @returns A function to stop the video capture.\n */\nexport function trackVideo(\n  amplitude: BrowserClient,\n  videoEl: HTMLVideoElement | EmbeddedVideoPlayer,\n  options: VideoCaptureOptions = {},\n): () => void {\n  const videoCapture = new VideoCapture(amplitude);\n  if (videoEl instanceof HTMLVideoElement) {\n    videoCapture.withVideoElement(videoEl);\n  } else {\n    videoCapture.withEmbeddedPlayer(videoEl);\n  }\n  if (options.vendor) {\n    videoCapture.withVendor(options.vendor);\n  }\n  videoCapture\n    .withExtraEventProperties(options.extraEventProperties ?? {})\n    .captureVideoStarted()\n    .captureVideoStopped()\n    .start();\n\n  return () => videoCapture.stop();\n}\n"
  },
  {
    "path": "packages/analytics-browser/test/attribution/helpers.test.ts",
    "content": "import { ExcludeInternalReferrersOptions, getStorageKey, BASE_CAMPAIGN } from '@amplitude/analytics-core';\nimport {\n  isNewCampaign,\n  createCampaignEvent,\n  getDefaultExcludedReferrers,\n  isExcludedReferrer,\n  isSubdomainOf,\n  getDomain,\n} from '../../src/attribution/helpers';\n\nconst loggerProvider = {\n  log: jest.fn(),\n  debug: jest.fn(),\n  warn: jest.fn(),\n  error: jest.fn(),\n  enable: jest.fn(),\n  disable: jest.fn(),\n};\n\ndescribe('getStorageKey', () => {\n  test('should return storage key without explicit suffix and limit', () => {\n    expect(getStorageKey('API_KEY')).toBe('AMP_API_KEY');\n  });\n\n  test('should return storage key', () => {\n    expect(getStorageKey('API_KEY', 'MKTG', 3)).toBe('AMP_MKTG_API');\n  });\n});\n\ndescribe('isNewCampaign', () => {\n  test('should return true for new campaign', () => {\n    const previousCampaign = {\n      ...BASE_CAMPAIGN,\n    };\n    const currentCampaign = {\n      ...BASE_CAMPAIGN,\n      utm_campaign: 'utm_campaign',\n    };\n    expect(isNewCampaign(currentCampaign, previousCampaign, {}, loggerProvider)).toBe(true);\n  });\n\n  test('should return true for new referrer', () => {\n    const previousCampaign = {\n      ...BASE_CAMPAIGN,\n      utm_campaign: 'utm_campaign',\n      referring_domain: 'a.b.c.d',\n    };\n    const currentCampaign = {\n      ...BASE_CAMPAIGN,\n      utm_campaign: 'utm_campaign',\n      referring_domain: 'b.c.d.e',\n    };\n    expect(isNewCampaign(currentCampaign, previousCampaign, {}, loggerProvider)).toBe(true);\n  });\n\n  test('should return false for string excluded referrer', () => {\n    const previousCampaign = {\n      ...BASE_CAMPAIGN,\n    };\n    const currentCampaign = {\n      ...BASE_CAMPAIGN,\n      referring_domain: 'amplitude.com',\n    };\n    expect(\n      isNewCampaign(\n        currentCampaign,\n        previousCampaign,\n        {\n          excludeReferrers: ['amplitude.com'],\n        },\n        loggerProvider,\n      ),\n    ).toBe(false);\n  });\n\n  test('should return false for regexp excluded referrer', () => {\n    const previousCampaign = {\n      ...BASE_CAMPAIGN,\n    };\n    const currentCampaign = {\n      ...BASE_CAMPAIGN,\n      referring_domain: 'amplitude.com',\n    };\n    expect(\n      isNewCampaign(\n        currentCampaign,\n        previousCampaign,\n        {\n          excludeReferrers: getDefaultExcludedReferrers('.amplitude.com'),\n        },\n        loggerProvider,\n      ),\n    ).toBe(false);\n  });\n\n  test('should return false for cross subdomain regexp excluded referrer', () => {\n    const previousCampaign = {\n      ...BASE_CAMPAIGN,\n    };\n    const currentCampaign = {\n      ...BASE_CAMPAIGN,\n      referring_domain: 'analytics.amplitude.com',\n    };\n    expect(\n      isNewCampaign(\n        currentCampaign,\n        previousCampaign,\n        {\n          excludeReferrers: getDefaultExcludedReferrers('.amplitude.com'),\n        },\n        loggerProvider,\n      ),\n    ).toBe(false);\n  });\n\n  test('should return true for undefined previous campaign', () => {\n    const previousCampaign = undefined;\n    const currentCampaign = {\n      ...BASE_CAMPAIGN,\n    };\n    expect(\n      isNewCampaign(\n        currentCampaign,\n        previousCampaign,\n        {\n          excludeReferrers: ['a'],\n        },\n        loggerProvider,\n      ),\n    ).toBe(true);\n  });\n\n  test('should return false for undefined previous campaign and excluded referrer', () => {\n    const previousCampaign = undefined;\n    const currentCampaign = {\n      ...BASE_CAMPAIGN,\n      referring_domain: 'a',\n    };\n    expect(\n      isNewCampaign(\n        currentCampaign,\n        previousCampaign,\n        {\n          excludeReferrers: ['a'],\n        },\n        loggerProvider,\n      ),\n    ).toBe(false);\n  });\n\n  test('should return false for no extra referrer with direct traffic in the same session', () => {\n    const previousCampaign = {\n      ...BASE_CAMPAIGN,\n      utm_campaign: 'utm_campaign',\n      referring_domain: 'a.b.c.d',\n    };\n    const currentCampaign = {\n      ...BASE_CAMPAIGN,\n    };\n\n    expect(isNewCampaign(currentCampaign, previousCampaign, {}, loggerProvider, false)).toBe(false);\n  });\n\n  test('should return true for no referrer with any new campaign in the same session', () => {\n    const previousCampaign = {\n      ...BASE_CAMPAIGN,\n      utm_campaign: 'utm_campaign',\n      referring_domain: 'a.b.c.d',\n    };\n    const currentCampaign = {\n      ...BASE_CAMPAIGN,\n      utm_source: 'utm_source',\n    };\n\n    expect(isNewCampaign(currentCampaign, previousCampaign, {}, loggerProvider, false)).toBe(true);\n  });\n\n  describe('when excludeInternalReferrers', () => {\n    let location: Location;\n\n    beforeAll(() => {\n      location = window.location;\n      Object.defineProperty(window, 'location', {\n        value: {\n          hostname: 'a.b.co.uk',\n        },\n        writable: true,\n      });\n    });\n\n    afterAll(() => {\n      Object.defineProperty(window, 'location', {\n        value: location,\n        writable: true,\n      });\n    });\n\n    describe('is true (or \"always\")', () => {\n      test('should return false if internal referrer', () => {\n        const previousCampaign = {\n          ...BASE_CAMPAIGN,\n          referring_domain: 'a.b.co.uk',\n        };\n        const currentCampaign = {\n          ...BASE_CAMPAIGN,\n          referring_domain: 'b.co.uk',\n        };\n\n        expect(\n          isNewCampaign(currentCampaign, previousCampaign, { excludeInternalReferrers: true }, loggerProvider),\n        ).toBe(false);\n        expect(isNewCampaign(currentCampaign, previousCampaign, { excludeInternalReferrers: {} }, loggerProvider)).toBe(\n          false,\n        );\n      });\n\n      describe('when cookieDomain is specified', () => {\n        test('should return false if internal referrer', () => {\n          const previousCampaign = {\n            ...BASE_CAMPAIGN,\n            referring_domain: 'a.b.co.uk',\n          };\n          const currentCampaign = {\n            ...BASE_CAMPAIGN,\n            referring_domain: 'b.co.uk',\n          };\n          expect(\n            isNewCampaign(\n              currentCampaign,\n              previousCampaign,\n              { excludeInternalReferrers: true },\n              loggerProvider,\n              false,\n              '.b.co.uk',\n            ),\n          ).toBe(false);\n        });\n\n        test('should return true if not internal referrer', () => {\n          const previousCampaign = {\n            ...BASE_CAMPAIGN,\n            referring_domain: 'www.google.com',\n          };\n          const currentCampaign = {\n            ...BASE_CAMPAIGN,\n            referring_domain: 'www.google.co.jp',\n          };\n          expect(\n            isNewCampaign(\n              currentCampaign,\n              previousCampaign,\n              { excludeInternalReferrers: true },\n              loggerProvider,\n              false,\n              '.b.co.uk',\n            ),\n          ).toBe(true);\n        });\n      });\n\n      test('should return true if not internal referrer', () => {\n        const previousCampaign = {\n          ...BASE_CAMPAIGN,\n          referring_domain: 'facebook.com',\n        };\n        const currentCampaign = {\n          ...BASE_CAMPAIGN,\n          referring_domain: 'google.com',\n        };\n        expect(\n          isNewCampaign(currentCampaign, previousCampaign, { excludeInternalReferrers: true }, loggerProvider),\n        ).toBe(true);\n      });\n\n      test('should return false if no referring_domain', () => {\n        const previousCampaign = {\n          ...BASE_CAMPAIGN,\n        };\n        const currentCampaign = {\n          ...BASE_CAMPAIGN,\n        };\n        expect(\n          isNewCampaign(currentCampaign, previousCampaign, { excludeInternalReferrers: true }, loggerProvider),\n        ).toBe(false);\n      });\n\n      test('should return false if no referring domain', () => {\n        const previousCampaign = {\n          ...BASE_CAMPAIGN,\n        };\n        const currentCampaign = {\n          ...BASE_CAMPAIGN,\n        };\n        expect(\n          isNewCampaign(\n            currentCampaign,\n            previousCampaign,\n            { excludeInternalReferrers: { condition: 'always' } },\n            loggerProvider,\n          ),\n        ).toBe(false);\n      });\n    });\n\n    describe('is \"ifEmptyCampaign\"', () => {\n      test('should return false if internal referrer and campaign is empty', () => {\n        const previousCampaign = {\n          ...BASE_CAMPAIGN,\n          referring_domain: 'a.b.co.uk',\n        };\n        const currentCampaign = {\n          ...BASE_CAMPAIGN,\n          referring_domain: 'a.b.co.uk',\n        };\n        expect(\n          isNewCampaign(\n            currentCampaign,\n            previousCampaign,\n            { excludeInternalReferrers: { condition: 'ifEmptyCampaign' } },\n            loggerProvider,\n          ),\n        ).toBe(false);\n      });\n\n      test('should return true if not internal referrer and campaign is not empty', () => {\n        const previousCampaign = {\n          ...BASE_CAMPAIGN,\n          utm_campaign: 'previous_campaign',\n          referring_domain: 'facebook.com',\n        };\n        const currentCampaign = {\n          ...BASE_CAMPAIGN,\n          utm_campaign: 'new_campaign',\n          referring_domain: 'google.com',\n        };\n        expect(\n          isNewCampaign(\n            currentCampaign,\n            previousCampaign,\n            { excludeInternalReferrers: { condition: 'ifEmptyCampaign' } },\n            loggerProvider,\n          ),\n        ).toBe(true);\n      });\n\n      test('should return true if internal referrer and campaign is not empty', () => {\n        const previousCampaign = {\n          ...BASE_CAMPAIGN,\n          utm_campaign: 'previous_campaign',\n          referring_domain: 'a.b.co.uk',\n        };\n        const currentCampaign = {\n          ...BASE_CAMPAIGN,\n          utm_campaign: 'new_campaign',\n          referring_domain: 'a.b.co.uk',\n        };\n        expect(\n          isNewCampaign(\n            currentCampaign,\n            previousCampaign,\n            { excludeInternalReferrers: { condition: 'ifEmptyCampaign' } },\n            loggerProvider,\n          ),\n        ).toBe(true);\n      });\n    });\n\n    describe('is invalid', () => {\n      test('should silently ignore invalid condition', () => {\n        const previousCampaign = {\n          ...BASE_CAMPAIGN,\n          utm_campaign: 'previous_campaign',\n          referring_domain: 'a.b.co.uk',\n        };\n        const currentCampaign = {\n          ...BASE_CAMPAIGN,\n          utm_campaign: 'new_campaign',\n          referring_domain: 'a.b.co.uk',\n        };\n        const excludeInternalReferrers = { condition: 'invalid' } as unknown as ExcludeInternalReferrersOptions;\n        expect(isNewCampaign(currentCampaign, previousCampaign, { excludeInternalReferrers }, loggerProvider)).toBe(\n          true,\n        );\n      });\n    });\n  });\n});\n\ndescribe('isExcludedReferrer', () => {\n  test('should return true with string excluded referrer', () => {\n    expect(isExcludedReferrer(['data.amplitude.com'], 'data.amplitude.com')).toEqual(true);\n  });\n\n  test('should return true with regexp excluded referrer', () => {\n    expect(isExcludedReferrer(getDefaultExcludedReferrers('.amplitude.com'), 'data.amplitude.com')).toEqual(true);\n  });\n});\n\ndescribe('createCampaignEvent', () => {\n  test('should return event', () => {\n    const campaignEvent = createCampaignEvent(\n      {\n        ...BASE_CAMPAIGN,\n        utm_campaign: 'utm_campaign',\n      },\n      {},\n    );\n    expect(campaignEvent).toEqual({\n      event_type: '$identify',\n      user_id: undefined,\n      user_properties: {\n        $set: {\n          utm_campaign: 'utm_campaign',\n        },\n        $setOnce: {\n          initial_dclid: 'EMPTY',\n          initial_fbclid: 'EMPTY',\n          initial_gbraid: 'EMPTY',\n          initial_gclid: 'EMPTY',\n          initial_ko_click_id: 'EMPTY',\n          initial_li_fat_id: 'EMPTY',\n          initial_msclkid: 'EMPTY',\n          initial_wbraid: 'EMPTY',\n          initial_referrer: 'EMPTY',\n          initial_referring_domain: 'EMPTY',\n          initial_rdt_cid: 'EMPTY',\n          initial_ttclid: 'EMPTY',\n          initial_twclid: 'EMPTY',\n          initial_utm_campaign: 'utm_campaign',\n          initial_utm_content: 'EMPTY',\n          initial_utm_id: 'EMPTY',\n          initial_utm_medium: 'EMPTY',\n          initial_utm_source: 'EMPTY',\n          initial_utm_term: 'EMPTY',\n        },\n        $unset: {\n          dclid: '-',\n          fbclid: '-',\n          gbraid: '-',\n          gclid: '-',\n          ko_click_id: '-',\n          li_fat_id: '-',\n          msclkid: '-',\n          wbraid: '-',\n          referrer: '-',\n          referring_domain: '-',\n          rdt_cid: '-',\n          ttclid: '-',\n          twclid: '-',\n          utm_content: '-',\n          utm_id: '-',\n          utm_medium: '-',\n          utm_source: '-',\n          utm_term: '-',\n        },\n      },\n    });\n  });\n\n  test('should return event with custom empty value', () => {\n    const campaignEvent = createCampaignEvent(\n      {\n        ...BASE_CAMPAIGN,\n        utm_campaign: 'utm_campaign',\n      },\n      {\n        initialEmptyValue: '(none)',\n      },\n    );\n    expect(campaignEvent).toEqual({\n      event_type: '$identify',\n      user_id: undefined,\n      user_properties: {\n        $set: {\n          utm_campaign: 'utm_campaign',\n        },\n        $setOnce: {\n          initial_dclid: '(none)',\n          initial_fbclid: '(none)',\n          initial_gbraid: '(none)',\n          initial_gclid: '(none)',\n          initial_ko_click_id: '(none)',\n          initial_li_fat_id: '(none)',\n          initial_msclkid: '(none)',\n          initial_wbraid: '(none)',\n          initial_referrer: '(none)',\n          initial_referring_domain: '(none)',\n          initial_rdt_cid: '(none)',\n          initial_ttclid: '(none)',\n          initial_twclid: '(none)',\n          initial_utm_campaign: 'utm_campaign',\n          initial_utm_content: '(none)',\n          initial_utm_id: '(none)',\n          initial_utm_medium: '(none)',\n          initial_utm_source: '(none)',\n          initial_utm_term: '(none)',\n        },\n        $unset: {\n          dclid: '-',\n          fbclid: '-',\n          gbraid: '-',\n          gclid: '-',\n          ko_click_id: '-',\n          li_fat_id: '-',\n          msclkid: '-',\n          wbraid: '-',\n          referrer: '-',\n          referring_domain: '-',\n          rdt_cid: '-',\n          ttclid: '-',\n          twclid: '-',\n          utm_content: '-',\n          utm_id: '-',\n          utm_medium: '-',\n          utm_source: '-',\n          utm_term: '-',\n        },\n      },\n    });\n  });\n});\n\ndescribe('getDefaultExcludedReferrers', () => {\n  test('should return empty array', () => {\n    const excludedReferrers = getDefaultExcludedReferrers(undefined);\n    expect(excludedReferrers).toEqual([]);\n  });\n\n  test('should return array with regex 1', () => {\n    const excludedReferrers = getDefaultExcludedReferrers('amplitude.com');\n    expect(excludedReferrers).toEqual([new RegExp('amplitude\\\\.com$')]);\n  });\n\n  test('should return array with regex 2', () => {\n    const excludedReferrers = getDefaultExcludedReferrers('.amplitude.com');\n    expect(excludedReferrers).toEqual([new RegExp('amplitude\\\\.com$')]);\n  });\n});\n\ndescribe('isSubdomainOf', () => {\n  test('should return true if subdomain of domain', () => {\n    expect(isSubdomainOf('b.co.uk', 'b.co.uk')).toBe(true); // exact match\n    expect(isSubdomainOf('b.co.uk', '.b.co.uk')).toBe(true); // exact match leading dot\n    expect(isSubdomainOf('a.b.co.uk', '.b.co.uk')).toBe(true);\n    expect(isSubdomainOf('www.b.co.uk', '.b.co.uk')).toBe(true);\n    expect(isSubdomainOf('www.b.co.uk', '.co.uk')).toBe(true);\n    expect(isSubdomainOf('www.b.co.uk', 'co.uk')).toBe(true);\n    expect(isSubdomainOf('.www.b.co.uk', 'b.co.uk')).toBe(true);\n  });\n\n  test('should return false if not subdomain of domain', () => {\n    expect(isSubdomainOf('b.co.uk', 'a.b.co.uk')).toBe(false);\n    expect(isSubdomainOf('b.co.uk', '.a.b.co.uk')).toBe(false);\n    expect(isSubdomainOf('www.b.co.uk', 'google.com')).toBe(false);\n  });\n});\n\ndescribe('getDomain', () => {\n  let location: Location;\n\n  beforeAll(() => {\n    location = window.location;\n    Object.defineProperty(window, 'location', {\n      value: {\n        hostname: 'sub.domain.hello.world.co.uk',\n      },\n      configurable: true,\n    });\n  });\n\n  afterAll(() => {\n    Object.defineProperty(window, 'location', {\n      value: location,\n      configurable: true,\n    });\n  });\n\n  test('should return true if both localhost', () => {\n    expect(getDomain('localhost')).toBe('localhost');\n  });\n\n  test('should return domain of location.hostname if no arg provided', () => {\n    expect(getDomain()).toBe('world.co.uk');\n  });\n\n  test('should return empty if location.hostname is undefined', () => {\n    Object.defineProperty(window, 'location', {\n      value: {\n        hostname: undefined,\n      },\n      configurable: true,\n    });\n    expect(getDomain()).toBe('');\n  });\n});\n"
  },
  {
    "path": "packages/analytics-browser/test/attribution/tracking-methods.test.ts",
    "content": "import {\n  EVENT_PROPERTY_TRACKING_METHOD,\n  USER_PROPERTY_TRACKING_METHOD,\n  hasTrackingMethod,\n  isEventPropertyAttributionEnabled,\n  isUserPropertyAttributionEnabled,\n  normalizeTrackingMethod,\n} from '../../src/attribution/tracking-methods';\n\ndescribe('tracking-methods', () => {\n  test('should default to user property tracking', () => {\n    expect(normalizeTrackingMethod()).toEqual([USER_PROPERTY_TRACKING_METHOD]);\n  });\n\n  test('should normalize and dedupe tracking methods', () => {\n    expect(\n      normalizeTrackingMethod([\n        USER_PROPERTY_TRACKING_METHOD,\n        EVENT_PROPERTY_TRACKING_METHOD,\n        USER_PROPERTY_TRACKING_METHOD,\n      ]),\n    ).toEqual([USER_PROPERTY_TRACKING_METHOD, EVENT_PROPERTY_TRACKING_METHOD]);\n  });\n\n  test('should filter invalid tracking methods and keep supported ones', () => {\n    expect(\n      normalizeTrackingMethod([USER_PROPERTY_TRACKING_METHOD, 'event_property', 123, EVENT_PROPERTY_TRACKING_METHOD]),\n    ).toEqual([USER_PROPERTY_TRACKING_METHOD, EVENT_PROPERTY_TRACKING_METHOD]);\n  });\n\n  test('should fall back to user property tracking when runtime input is invalid', () => {\n    expect(normalizeTrackingMethod('event_property')).toEqual([USER_PROPERTY_TRACKING_METHOD]);\n    expect(normalizeTrackingMethod([123, false, null])).toEqual([USER_PROPERTY_TRACKING_METHOD]);\n  });\n\n  test('should detect enabled tracking methods', () => {\n    const options = {\n      trackingMethod: [USER_PROPERTY_TRACKING_METHOD, EVENT_PROPERTY_TRACKING_METHOD],\n      fallbackAttributionEvent: true,\n    };\n\n    expect(hasTrackingMethod(options, USER_PROPERTY_TRACKING_METHOD)).toBe(true);\n    expect(isUserPropertyAttributionEnabled(options)).toBe(true);\n    expect(isEventPropertyAttributionEnabled(options)).toBe(true);\n    expect(options.fallbackAttributionEvent).toBe(true);\n  });\n\n  test('should enable user property tracking by default', () => {\n    const options = {};\n\n    expect(hasTrackingMethod(options, USER_PROPERTY_TRACKING_METHOD)).toBe(true);\n    expect(isUserPropertyAttributionEnabled(options)).toBe(true);\n    expect(isEventPropertyAttributionEnabled(options)).toBe(false);\n  });\n});\n"
  },
  {
    "path": "packages/analytics-browser/test/attribution/web-attribution.test.ts",
    "content": "import {\n  FetchTransport,\n  CookieStorage,\n  Logger,\n  UUID,\n  AttributionOptions,\n  BrowserConfig,\n  LogLevel,\n  BASE_CAMPAIGN,\n  CampaignParser,\n} from '@amplitude/analytics-core';\nimport { WebAttribution } from '../../src/attribution/web-attribution';\n\ndescribe('shouldTrackNewCampaign', () => {\n  const mockConfig: BrowserConfig = {\n    apiKey: UUID(),\n    flushIntervalMillis: 0,\n    flushMaxRetries: 0,\n    flushQueueSize: 0,\n    logLevel: LogLevel.None,\n    loggerProvider: new Logger(),\n    offline: false,\n    optOut: false,\n    serverUrl: undefined,\n    transportProvider: new FetchTransport(),\n    useBatch: false,\n    cookieOptions: {\n      domain: '.amplitude.com',\n      expiration: 365,\n      sameSite: 'Lax',\n      secure: false,\n      upgrade: true,\n    },\n    cookieStorage: new CookieStorage(),\n    sessionTimeout: 30 * 60 * 1000,\n    trackingOptions: {\n      ipAddress: true,\n      language: true,\n      platform: true,\n    },\n  };\n  const option: AttributionOptions = {};\n\n  test('should track campaign with new campaign', async () => {\n    const overrideMockConfig = {\n      ...mockConfig,\n      cookieOptions: undefined,\n    };\n    const webAttribution = new WebAttribution(option, overrideMockConfig);\n\n    jest.spyOn(CampaignParser.prototype, 'parse').mockResolvedValueOnce({\n      ...BASE_CAMPAIGN,\n      utm_source: 'amp-test',\n    });\n    jest.spyOn(webAttribution.storage, 'get').mockResolvedValueOnce({\n      ...BASE_CAMPAIGN,\n    });\n\n    await webAttribution.init();\n    expect(webAttribution.shouldTrackNewCampaign).toBe(true);\n  });\n\n  test('should not track campaign without new campaign', async () => {\n    const overrideMockConfig = {\n      ...mockConfig,\n      cookieOptions: undefined,\n    };\n    const emptyCampaign = { ...BASE_CAMPAIGN };\n    const webAttribution = new WebAttribution(option, overrideMockConfig);\n\n    jest.spyOn(CampaignParser.prototype, 'parse').mockResolvedValue(emptyCampaign);\n    jest.spyOn(webAttribution.storage, 'get').mockResolvedValue(emptyCampaign);\n\n    await webAttribution.init();\n    expect(webAttribution.shouldTrackNewCampaign).toBe(false);\n  });\n\n  test('should generate campaign event with given eventId', async () => {\n    const webAttribution = new WebAttribution(option, mockConfig);\n    const event_id = 1;\n    const campaignEvent = webAttribution.generateCampaignEvent(event_id);\n    expect(campaignEvent.event_id).toBe(event_id);\n  });\n\n  test('should set session id on a new Campaign', async () => {\n    const option = {\n      resetSessionOnNewCampaign: true,\n    };\n    const webAttribution = new WebAttribution(option, mockConfig);\n    jest.spyOn(webAttribution.storage, 'get').mockResolvedValue(undefined);\n    await webAttribution.init();\n\n    expect(webAttribution.shouldSetSessionIdOnNewCampaign()).toBe(true);\n  });\n\n  test('should not set session id on a new Campaign', async () => {\n    const option = {\n      resetSessionOnNewCampaign: true,\n    };\n    const webAttribution = new WebAttribution(option, mockConfig);\n    await webAttribution.init();\n\n    webAttribution.generateCampaignEvent();\n    expect(webAttribution.shouldSetSessionIdOnNewCampaign()).toBe(false);\n  });\n\n  test('should ignore the campaign for direct traffic in session', async () => {\n    const lastEventTime = Date.now();\n\n    const overrideMockConfig = {\n      ...mockConfig,\n      // In session event\n      lastEventTime,\n    };\n    const webAttribution = new WebAttribution({}, overrideMockConfig);\n    const previousCampaign = {\n      ...BASE_CAMPAIGN,\n      referrer: 'https://www.google.com',\n      referring_domain: 'www.google.com',\n    };\n\n    jest.spyOn(CampaignParser.prototype, 'parse').mockResolvedValue(BASE_CAMPAIGN); // Direct Traffic\n    jest.spyOn(webAttribution.storage, 'get').mockResolvedValue(previousCampaign);\n\n    await webAttribution.init();\n    expect(webAttribution.shouldTrackNewCampaign).toBe(false);\n  });\n\n  test('should not ignore the campaign for direct traffic in new session', async () => {\n    const lastEventTime = Date.now() - 2 * 30 * 60 * 1000;\n\n    const overrideMockConfig = {\n      ...mockConfig,\n      // Out of session event\n      lastEventTime,\n    };\n\n    const webAttribution = new WebAttribution({}, overrideMockConfig);\n    const previousCampaign = {\n      ...BASE_CAMPAIGN,\n      referrer: 'https://www.google.com',\n      referring_domain: 'www.google.com',\n    };\n\n    jest.spyOn(CampaignParser.prototype, 'parse').mockResolvedValue(BASE_CAMPAIGN); // Direct Traffic\n    jest.spyOn(webAttribution.storage, 'get').mockImplementation((key: string) => {\n      if (key === webAttribution.webExpStorageKey) {\n        return Promise.resolve(undefined);\n      }\n      if (key === webAttribution.storageKey) {\n        return Promise.resolve(previousCampaign);\n      }\n      return Promise.resolve(undefined);\n    });\n\n    await webAttribution.init();\n    expect(webAttribution.shouldTrackNewCampaign).toBe(true);\n  });\n\n  test('should use original campaign from MKTG_ORIGINAL when available', async () => {\n    const webAttribution = new WebAttribution({}, mockConfig);\n    const originalCampaign = {\n      ...BASE_CAMPAIGN,\n      utm_source: 'original-source',\n      utm_campaign: 'original-campaign',\n    };\n    const previousCampaign = {\n      ...BASE_CAMPAIGN,\n      utm_source: 'previous-source',\n    };\n\n    jest.spyOn(CampaignParser.prototype, 'parse').mockResolvedValue({\n      ...BASE_CAMPAIGN,\n      utm_source: 'parsed-source',\n    });\n\n    jest.spyOn(webAttribution.storage, 'get').mockImplementation((key: string) => {\n      if (key === webAttribution.webExpStorageKey) {\n        return Promise.resolve(originalCampaign); // Original campaign exists\n      }\n      if (key === webAttribution.storageKey) {\n        return Promise.resolve(previousCampaign);\n      }\n      return Promise.resolve(undefined);\n    });\n\n    const removeSpy = jest.spyOn(webAttribution.storage, 'remove').mockResolvedValue();\n\n    await webAttribution.init();\n\n    expect(webAttribution.currentCampaign).toEqual(originalCampaign);\n    expect(webAttribution.previousCampaign).toEqual(previousCampaign);\n    expect(removeSpy).toHaveBeenCalledWith(webAttribution.webExpStorageKey);\n  });\n});\n"
  },
  {
    "path": "packages/analytics-browser/test/browser-client.test.ts",
    "content": "import {\n  CookieStorage,\n  FetchTransport,\n  getAnalyticsConnector,\n  getCookieName,\n  LogLevel,\n  OfflineDisabled,\n  Status,\n  UserSession,\n  AutocaptureOptions,\n  Identify,\n  RemoteConfigClient,\n  DiagnosticsClient,\n} from '@amplitude/analytics-core';\nimport { WebAttribution } from '../src/attribution/web-attribution';\nimport * as core from '@amplitude/analytics-core';\nimport * as pageViewTracking from '@amplitude/plugin-page-view-tracking-browser';\nimport * as eventPropertyTracking from '@amplitude/plugin-event-property-attribution-browser';\nimport * as autocapture from '@amplitude/plugin-autocapture-browser';\nimport * as networkCapturePlugin from '@amplitude/plugin-network-capture-browser';\nimport * as webVitals from '@amplitude/plugin-web-vitals-browser';\nimport { AmplitudeBrowser } from '../src/browser-client';\nimport * as Config from '../src/config';\nimport * as CookieMigration from '../src/cookie-migration';\nimport * as fileDownloadTracking from '../src/plugins/file-download-tracking';\nimport * as formInteractionTracking from '../src/plugins/form-interaction-tracking';\nimport * as networkConnectivityChecker from '../src/plugins/network-connectivity-checker';\nimport * as SnippetHelper from '../src/utils/snippet-helper';\nimport * as joinedConfig from '../src/config/joined-config';\nimport * as pageUrlEnrichment from '@amplitude/plugin-page-url-enrichment-browser';\nimport * as customEnrichment from '@amplitude/plugin-custom-enrichment-browser';\n\n// Mock RemoteConfigClient constructor\nconst mockRemoteConfigClient = {\n  subscribe: jest\n    .fn()\n    .mockImplementation(\n      (_configKey: string, _eventType: string, callback: (remoteConfig: any, source: any, lastFetch: Date) => void) => {\n        // Call the callback immediately with remoteConfig as null\n        callback(null, 'cache', new Date());\n      },\n    ),\n  unsubscribe: jest.fn(),\n  updateConfigs: jest.fn(),\n};\nlet MockedRemoteConfigClient: jest.SpyInstance;\nlet originalRemoteConfigClient: typeof RemoteConfigClient;\n\njest.mock('web-vitals', () => ({\n  onLCP: jest.fn(),\n  onFCP: jest.fn(),\n  onINP: jest.fn(),\n  onCLS: jest.fn(),\n  onTTFB: jest.fn(),\n}));\n\ndescribe('browser-client', () => {\n  let apiKey = '';\n  let userId = '';\n  let deviceId = '';\n  let client = new AmplitudeBrowser();\n  const testDeviceId = 'test-device-id';\n  const testSessionId = 12345;\n  const url = new URL(`https://www.example.com?ampDeviceId=${testDeviceId}&ampSessionId=${testSessionId}`);\n  const defaultTracking = {\n    attribution: false,\n    fileDownloadTracking: false,\n    formInteractionTracking: false,\n    pageViews: false,\n    sessions: false,\n  };\n\n  beforeEach(() => {\n    client = new AmplitudeBrowser();\n    apiKey = core.UUID();\n    userId = core.UUID();\n    deviceId = core.UUID();\n\n    // Set up RemoteConfigClient mock\n    originalRemoteConfigClient = core.RemoteConfigClient;\n    MockedRemoteConfigClient = jest.fn().mockImplementation(() => mockRemoteConfigClient);\n    Object.defineProperty(core, 'RemoteConfigClient', {\n      value: MockedRemoteConfigClient,\n      writable: true,\n      configurable: true,\n    });\n  });\n\n  afterEach(() => {\n    jest.clearAllMocks();\n    // clean up cookies\n    document.cookie = `AMP_${apiKey}=null; expires=-1`;\n    // clean up RemoteConfigClient mock\n    if (MockedRemoteConfigClient) {\n      Object.defineProperty(core, 'RemoteConfigClient', {\n        value: originalRemoteConfigClient,\n        writable: true,\n        configurable: true,\n      });\n    }\n  });\n\n  describe('plugin', () => {\n    test('should return plugin by name', async () => {\n      const fileDownloadTrackingPlugin = jest.spyOn(fileDownloadTracking, 'fileDownloadTracking');\n      await client.init(apiKey, userId, {\n        optOut: false,\n        defaultTracking: {\n          ...defaultTracking,\n          fileDownloads: true,\n        },\n      }).promise;\n      const result = client.plugin('@amplitude/plugin-file-download-tracking-browser');\n      // result should be fileDownloadTrackingPlugin\n      // comparing with the first call to the spy\n      expect(result).toBe(fileDownloadTrackingPlugin.mock.results[0].value);\n    });\n\n    test('should return undefined when name doesn not exist', async () => {\n      const loggerProvider = {\n        log: jest.fn(),\n        debug: jest.fn(),\n        warn: jest.fn(),\n        error: jest.fn(),\n        enable: jest.fn(),\n        disable: jest.fn(),\n      };\n      await client.init(apiKey, userId, {\n        optOut: false,\n        defaultTracking: {\n          ...defaultTracking,\n          fileDownloads: true,\n        },\n        loggerProvider: loggerProvider,\n      }).promise;\n      const result = client.plugin('plugin-file-download-tracking-browser');\n      // result should be fileDownloadTrackingPlugin\n      // comparing with the first call to the spy\n      expect(result).toBe(undefined);\n      expect(loggerProvider.debug).toHaveBeenCalledWith(\n        'Cannot find plugin with name plugin-file-download-tracking-browser',\n      );\n    });\n  });\n\n  describe('init', () => {\n    test('should call identify when identify is provided', async () => {\n      const trackSpy = jest.spyOn(client, 'track');\n      const identify = new Identify();\n      identify.set('test', '123');\n      await client.init(apiKey, {\n        identify,\n      }).promise;\n      expect(trackSpy).toHaveBeenNthCalledWith(2, {\n        event_type: '$identify',\n        user_properties: { $set: { test: '123' } },\n      });\n    });\n\n    test('should use remote config by default', async () => {\n      await client.init(apiKey).promise;\n      expect(MockedRemoteConfigClient).toHaveBeenCalled();\n    });\n\n    test('should use remote config when fetchRemoteConfig is true', async () => {\n      await client.init(apiKey, {\n        fetchRemoteConfig: true,\n      }).promise;\n      expect(MockedRemoteConfigClient).toHaveBeenCalled();\n    });\n\n    test('should NOT use remote config when fetchRemoteConfig is false', async () => {\n      await client.init(apiKey, {\n        fetchRemoteConfig: false,\n      }).promise;\n      expect(MockedRemoteConfigClient).not.toHaveBeenCalled();\n    });\n\n    test('should pass remoteConfig.serverUrl to RemoteConfigClient when provided', async () => {\n      const customServerUrl = 'https://my-proxy.com/remote-config';\n\n      await client.init(apiKey, {\n        remoteConfig: {\n          serverUrl: customServerUrl,\n        },\n      }).promise;\n\n      expect(MockedRemoteConfigClient).toHaveBeenCalledWith(\n        apiKey,\n        expect.anything(), // loggerProvider\n        'US', // default serverZone\n        customServerUrl, // our custom URL\n      );\n    });\n\n    test('should call updateBrowserConfigWithRemoteConfig when remoteConfig is not null', async () => {\n      const mockRemoteConfig = {\n        autocapture: {\n          elementInteractions: true,\n          pageViews: true,\n        },\n      };\n\n      // Mock the remote config client to return a non-null remoteConfig\n      const mockRemoteConfigClientWithData = {\n        subscribe: jest\n          .fn()\n          .mockImplementation(\n            (\n              _configKey: string,\n              _eventType: string,\n              callback: (remoteConfig: any, source: any, lastFetch: Date) => void,\n            ) => {\n              // Call the callback immediately with a non-null remoteConfig\n              callback(mockRemoteConfig, 'cache', new Date());\n            },\n          ),\n        unsubscribe: jest.fn(),\n        updateConfigs: jest.fn(),\n      };\n\n      // Replace the default mock with our data mock\n      MockedRemoteConfigClient = jest.fn().mockImplementation(() => mockRemoteConfigClientWithData);\n      Object.defineProperty(core, 'RemoteConfigClient', {\n        value: MockedRemoteConfigClient,\n        writable: true,\n        configurable: true,\n      });\n\n      // Spy on the updateBrowserConfigWithRemoteConfig function\n      const updateBrowserConfigSpy = jest.spyOn(joinedConfig, 'updateBrowserConfigWithRemoteConfig');\n\n      await client.init(apiKey, {\n        fetchRemoteConfig: true,\n      }).promise;\n\n      // Verify that updateBrowserConfigWithRemoteConfig was called\n      expect(updateBrowserConfigSpy).toHaveBeenCalledTimes(1);\n      expect(updateBrowserConfigSpy).toHaveBeenCalledWith(\n        mockRemoteConfig,\n        expect.any(Object), // browserOptions\n      );\n\n      updateBrowserConfigSpy.mockRestore();\n    });\n\n    test('should update diagnostics config from remote config', async () => {\n      const mockMainRemoteConfig = {\n        autocapture: {\n          elementInteractions: true,\n        },\n      };\n\n      const mockDiagnosticsRemoteConfig = {\n        enabled: true,\n        sampleRate: 0.25,\n      };\n\n      // Mock the remote config client to return different configs based on the subscription key\n      const mockRemoteConfigClientWithDiagnostics = {\n        subscribe: jest\n          .fn()\n          .mockImplementation(\n            (\n              configKey: string,\n              _eventType: string,\n              callback: (remoteConfig: any, source: any, lastFetch: Date) => void,\n            ) => {\n              // Return different configs based on the subscription key\n              if (configKey === 'configs.analyticsSDK.browserSDK') {\n                callback(mockMainRemoteConfig, 'cache', new Date());\n              } else if (configKey === 'configs.diagnostics.browserSDK') {\n                callback(mockDiagnosticsRemoteConfig, 'cache', new Date());\n              } else {\n                callback(null, 'cache', new Date());\n              }\n            },\n          ),\n        unsubscribe: jest.fn(),\n        updateConfigs: jest.fn(),\n      };\n\n      // Replace the default mock with our data mock\n      MockedRemoteConfigClient = jest.fn().mockImplementation(() => mockRemoteConfigClientWithDiagnostics);\n      Object.defineProperty(core, 'RemoteConfigClient', {\n        value: MockedRemoteConfigClient,\n        writable: true,\n        configurable: true,\n      });\n\n      // Initialize the client\n      await client.init(apiKey, {\n        fetchRemoteConfig: true,\n      }).promise;\n\n      // Verify that subscribe was called with the correct keys\n      expect(mockRemoteConfigClientWithDiagnostics.subscribe).toHaveBeenCalledWith(\n        'configs.analyticsSDK.browserSDK',\n        'all',\n        expect.any(Function),\n      );\n      expect(mockRemoteConfigClientWithDiagnostics.subscribe).toHaveBeenCalledWith(\n        'configs.diagnostics.browserSDK',\n        'all',\n        expect.any(Function),\n      );\n\n      // Verify that the diagnostics config was applied\n      expect(client.config.enableDiagnostics).toBe(true);\n      expect(client.config.diagnosticsSampleRate).toBe(0.25);\n    });\n\n    test.each([\n      {\n        testName: 'should use remote config sample rate of 0 even when _diagnosticsSampleRate is non-zero',\n        setDiagnosticsSampleRate: 0.5,\n        remoteConfigSampleRate: { enabled: true, sampleRate: 0 },\n        expectedSampleRate: 0,\n        expectedEnabled: true,\n        serverZone: undefined,\n        enableDiagnostics: undefined,\n        description: '0 from remote config (not 0.5 from _diagnosticsSampleRate)',\n      },\n      {\n        testName: 'should use _diagnosticsSampleRate when remote config for diagnostics is null',\n        setDiagnosticsSampleRate: 0.75,\n        remoteConfigSampleRate: null,\n        expectedSampleRate: 0.75,\n        expectedEnabled: true,\n        serverZone: undefined,\n        enableDiagnostics: undefined,\n        description: '0.75 from _diagnosticsSampleRate (remote config is null)',\n      },\n      {\n        testName: 'should use provided serverZone and enableDiagnostics options',\n        setDiagnosticsSampleRate: 0,\n        remoteConfigSampleRate: null,\n        expectedSampleRate: 0,\n        expectedEnabled: false,\n        serverZone: 'EU' as const,\n        enableDiagnostics: false,\n        description: 'EU serverZone and enableDiagnostics=false from options',\n      },\n    ])(\n      '$testName',\n      async ({\n        setDiagnosticsSampleRate,\n        remoteConfigSampleRate,\n        expectedSampleRate,\n        expectedEnabled,\n        serverZone,\n        enableDiagnostics,\n      }) => {\n        // Set _diagnosticsSampleRate\n        client._setDiagnosticsSampleRate(setDiagnosticsSampleRate);\n\n        const mockMainRemoteConfig = {\n          autocapture: {\n            elementInteractions: true,\n          },\n        };\n\n        // Mock the remote config client to return different configs based on the subscription key\n        const mockRemoteConfigClientWithDiagnostics = {\n          subscribe: jest\n            .fn()\n            .mockImplementation(\n              (\n                configKey: string,\n                _eventType: string,\n                callback: (remoteConfig: any, source: any, lastFetch: Date) => void,\n              ) => {\n                // Return different configs based on the subscription key\n                if (configKey === 'configs.analyticsSDK.browserSDK') {\n                  callback(mockMainRemoteConfig, 'cache', new Date());\n                } else if (configKey === 'configs.diagnostics.browserSDK') {\n                  callback(remoteConfigSampleRate, 'cache', new Date());\n                } else {\n                  callback(null, 'cache', new Date());\n                }\n              },\n            ),\n          unsubscribe: jest.fn(),\n          updateConfigs: jest.fn(),\n        };\n\n        // Replace the default mock with our data mock\n        MockedRemoteConfigClient = jest.fn().mockImplementation(() => mockRemoteConfigClientWithDiagnostics);\n        Object.defineProperty(core, 'RemoteConfigClient', {\n          value: MockedRemoteConfigClient,\n          writable: true,\n          configurable: true,\n        });\n\n        // Mock DiagnosticsClient to spy on its initialization\n        const mockDiagnosticsClient = {\n          setTag: jest.fn(),\n          enable: jest.fn(),\n          disable: jest.fn(),\n          track: jest.fn(),\n          recordEvent: jest.fn(),\n          increment: jest.fn(),\n        };\n        const diagnosticsClientSpy = jest\n          .spyOn(core, 'DiagnosticsClient')\n          .mockImplementation(() => mockDiagnosticsClient as unknown as DiagnosticsClient);\n\n        // Initialize the client with optional serverZone and enableDiagnostics\n        await client.init(apiKey, {\n          fetchRemoteConfig: true,\n          ...(serverZone !== undefined && { serverZone }),\n          ...(enableDiagnostics !== undefined && { enableDiagnostics }),\n        }).promise;\n\n        // Verify that DiagnosticsClient was called with the expected values\n        expect(diagnosticsClientSpy).toHaveBeenCalledWith(\n          apiKey,\n          expect.any(Object), // loggerProvider\n          serverZone ?? 'US', // serverZone from options or default\n          {\n            enabled: expectedEnabled,\n            sampleRate: expectedSampleRate,\n          },\n        );\n\n        // Verify that the diagnostics config was applied\n        expect(client.config.enableDiagnostics).toBe(expectedEnabled);\n        expect(client.config.diagnosticsSampleRate).toBe(expectedSampleRate);\n\n        // Clean up\n        diagnosticsClientSpy.mockRestore();\n      },\n    );\n\n    test('should initialize client', async () => {\n      const parseLegacyCookies = jest.spyOn(CookieMigration, 'parseLegacyCookies').mockResolvedValueOnce({\n        optOut: false,\n      });\n      await client.init(apiKey, userId, {\n        defaultTracking,\n        identityStorage: 'localStorage',\n      }).promise;\n      expect(parseLegacyCookies).toHaveBeenCalledTimes(1);\n    });\n\n    test('should initialize w/o user id and config', async () => {\n      client.setOptOut(true);\n      await client.init(apiKey).promise;\n      expect(client.getUserId()).toBe(undefined);\n    });\n\n    test('should set initialize with undefined user id', async () => {\n      client.setOptOut(true);\n      await client.init(apiKey, undefined).promise;\n      expect(client.getUserId()).toBe(undefined);\n    });\n\n    test('should initialize w/o config', async () => {\n      client.setOptOut(true);\n      await client.init(apiKey, userId).promise;\n      expect(client.getUserId()).toBe(userId);\n    });\n\n    test('should set user id with top level parameter', async () => {\n      client.setOptOut(true);\n      await client.init(apiKey, undefined, {\n        userId,\n      }).promise;\n      expect(client.getUserId()).toBe(undefined);\n    });\n\n    test('should set user to options.userId', async () => {\n      client.setOptOut(true);\n      await client.init(apiKey, {\n        userId,\n      }).promise;\n      expect(client.getUserId()).toBe(userId);\n    });\n\n    test('should set user id using top level parameter as priority', async () => {\n      client.setOptOut(true);\n      await client.init(apiKey, userId, {\n        userId: 'user@amplitude.com',\n      }).promise;\n      expect(client.getUserId()).toBe(userId);\n    });\n\n    test('should initialize with existing session', async () => {\n      const parseLegacyCookies = jest.spyOn(CookieMigration, 'parseLegacyCookies').mockResolvedValueOnce({\n        optOut: false,\n        lastEventTime: Date.now(),\n      });\n      await client.init(apiKey, userId, {\n        sessionId: Date.now(),\n        defaultTracking,\n      }).promise;\n      expect(parseLegacyCookies).toHaveBeenCalledTimes(1);\n    });\n\n    test('should initialize without error when apiKey is undefined', async () => {\n      const parseLegacyCookies = jest.spyOn(CookieMigration, 'parseLegacyCookies').mockResolvedValueOnce({\n        optOut: false,\n      });\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n      await client.init(undefined as any, userId, {\n        defaultTracking,\n      }).promise;\n      expect(parseLegacyCookies).toHaveBeenCalledTimes(1);\n    });\n\n    test('should init from legacy cookies config', async () => {\n      const parseLegacyCookies = jest.spyOn(CookieMigration, 'parseLegacyCookies').mockResolvedValueOnce({\n        optOut: false,\n        deviceId,\n        sessionId: 1,\n        lastEventTime: Date.now() - 1000,\n      });\n      await client.init(apiKey, userId, {\n        optOut: false,\n        defaultTracking,\n        identityStorage: 'none',\n      }).promise;\n      expect(client.getDeviceId()).toBe(deviceId);\n      expect(client.getSessionId()).toBe(1);\n      expect(parseLegacyCookies).toHaveBeenCalledTimes(1);\n    });\n\n    test('should init from new cookies config', async () => {\n      const parseLegacyCookies = jest.spyOn(CookieMigration, 'parseLegacyCookies').mockResolvedValueOnce({\n        optOut: false,\n      });\n      const cookieStorage = new CookieStorage<UserSession>();\n      await cookieStorage.set(getCookieName(apiKey), {\n        deviceId,\n        lastEventTime: Date.now(),\n        optOut: false,\n        sessionId: 1,\n        userId,\n      });\n      await client.init(apiKey, {\n        defaultTracking,\n      }).promise;\n      expect(client.getUserId()).toBe(userId);\n      expect(client.getDeviceId()).toBe(deviceId);\n      expect(client.getSessionId()).toBe(1);\n      expect(parseLegacyCookies).toHaveBeenCalledTimes(1);\n    });\n\n    test('should call prevent concurrent init executions', async () => {\n      const parseLegacyCookies = jest.spyOn(CookieMigration, 'parseLegacyCookies').mockResolvedValueOnce({\n        optOut: false,\n      });\n      const useBrowserConfig = jest.spyOn(Config, 'useBrowserConfig');\n      await Promise.all([\n        client.init(apiKey, userId, { defaultTracking }).promise,\n        client.init(apiKey, userId, { defaultTracking }).promise,\n        client.init(apiKey, userId, { defaultTracking }).promise,\n      ]);\n      // NOTE: `parseLegacyCookies` and `useBrowserConfig` are only called once despite multiple init calls\n      expect(parseLegacyCookies).toHaveBeenCalledTimes(1);\n      expect(useBrowserConfig).toHaveBeenCalledTimes(1);\n    });\n\n    test('should set user id and device id in analytics connector', async () => {\n      await client.init(apiKey, userId, {\n        optOut: true,\n        defaultTracking,\n        deviceId,\n        identityStorage: 'none',\n      }).promise;\n      expect(client.getDeviceId()).toBe(deviceId);\n      expect(client.getUserId()).toBe(userId);\n      const identity = getAnalyticsConnector().identityStore.getIdentity();\n      expect(identity.deviceId).toBe(deviceId);\n      expect(identity.userId).toBe(userId);\n    });\n\n    test('should set up event bridge and track events', async () => {\n      await client.init(apiKey, userId, {\n        optOut: false,\n        defaultTracking,\n      }).promise;\n      const track = jest.spyOn(client, 'track').mockReturnValueOnce({\n        promise: Promise.resolve({\n          code: 200,\n          message: '',\n          event: {\n            event_type: 'event_type',\n          },\n        }),\n      });\n      getAnalyticsConnector().eventBridge.logEvent({\n        eventType: 'event_type',\n        eventProperties: {\n          k: 'v',\n        },\n      });\n      expect(track).toHaveBeenCalledTimes(1);\n    });\n\n    test('should handle event bridge events with time property in eventProperties', async () => {\n      await client.init(apiKey, userId, {\n        optOut: false,\n        defaultTracking,\n      }).promise;\n      const track = jest.spyOn(client, 'track').mockReturnValueOnce({\n        promise: Promise.resolve({\n          code: 200,\n          message: '',\n          event: {\n            event_type: 'custom_event',\n          },\n        }),\n      });\n\n      const customTime = 12345;\n      getAnalyticsConnector().eventBridge.logEvent({\n        eventType: 'custom_event',\n        eventProperties: {\n          property1: 'value1',\n          property2: 123,\n          time: customTime,\n          property3: true,\n        },\n      });\n\n      expect(track).toHaveBeenCalledTimes(1);\n      expect(track).toHaveBeenCalledWith(\n        'custom_event',\n        {\n          property1: 'value1',\n          property2: 123,\n          property3: true,\n        },\n        { time: customTime },\n      );\n    });\n\n    test('should handle event bridge events with null time property', async () => {\n      await client.init(apiKey, userId, {\n        optOut: false,\n        defaultTracking,\n      }).promise;\n      const track = jest.spyOn(client, 'track').mockReturnValueOnce({\n        promise: Promise.resolve({\n          code: 200,\n          message: '',\n          event: {\n            event_type: 'null_time_event',\n          },\n        }),\n      });\n\n      getAnalyticsConnector().eventBridge.logEvent({\n        eventType: 'null_time_event',\n        eventProperties: {\n          property1: 'value1',\n          time: null,\n          property2: 'value2',\n        },\n      });\n\n      expect(track).toHaveBeenCalledTimes(1);\n      expect(track).toHaveBeenCalledWith(\n        'null_time_event',\n        {\n          property1: 'value1',\n          property2: 'value2',\n        },\n        undefined,\n      );\n    });\n\n    test('should handle event bridge events with no eventProperties', async () => {\n      await client.init(apiKey, userId, {\n        optOut: false,\n        defaultTracking,\n      }).promise;\n      const track = jest.spyOn(client, 'track').mockReturnValueOnce({\n        promise: Promise.resolve({\n          code: 200,\n          message: '',\n          event: {\n            event_type: 'no_props_event',\n          },\n        }),\n      });\n\n      getAnalyticsConnector().eventBridge.logEvent({\n        eventType: 'no_props_event',\n      });\n\n      expect(track).toHaveBeenCalledTimes(1);\n      expect(track).toHaveBeenCalledWith('no_props_event', {}, undefined);\n    });\n\n    test('should add file download and form interaction tracking plugins', async () => {\n      const fileDownloadTrackingPlugin = jest.spyOn(fileDownloadTracking, 'fileDownloadTracking');\n      const formInteractionTrackingPlugin = jest.spyOn(formInteractionTracking, 'formInteractionTracking');\n      await client.init(apiKey, userId, {\n        optOut: false,\n        defaultTracking: {\n          ...defaultTracking,\n          fileDownloads: true,\n          formInteractions: true,\n        },\n      }).promise;\n      expect(fileDownloadTrackingPlugin).toHaveBeenCalledTimes(1);\n      expect(formInteractionTrackingPlugin).toHaveBeenCalledTimes(1);\n    });\n\n    test('should NOT add file download and form interaction tracking plugins', async () => {\n      const fileDownloadTrackingPlugin = jest.spyOn(fileDownloadTracking, 'fileDownloadTracking');\n      const formInteractionTrackingPlugin = jest.spyOn(formInteractionTracking, 'formInteractionTracking');\n      await client.init(apiKey, userId, {\n        optOut: false,\n        defaultTracking: {\n          ...defaultTracking,\n          fileDownloads: false,\n          formInteractions: false,\n        },\n      }).promise;\n      expect(fileDownloadTrackingPlugin).toHaveBeenCalledTimes(0);\n      expect(formInteractionTrackingPlugin).toHaveBeenCalledTimes(0);\n    });\n\n    test('should add network connectivity checker plugin by default', async () => {\n      const networkConnectivityCheckerPlugin = jest.spyOn(\n        networkConnectivityChecker,\n        'networkConnectivityCheckerPlugin',\n      );\n      await client.init(apiKey, userId).promise;\n      expect(networkConnectivityCheckerPlugin).toHaveBeenCalledTimes(1);\n    });\n\n    test('should not add network connectivity checker plugin if offline is disabled', async () => {\n      const networkConnectivityCheckerPlugin = jest.spyOn(\n        networkConnectivityChecker,\n        'networkConnectivityCheckerPlugin',\n      );\n      await client.init(apiKey, userId, {\n        offline: OfflineDisabled,\n      }).promise;\n      expect(networkConnectivityCheckerPlugin).toHaveBeenCalledTimes(0);\n    });\n\n    test('should add frustration interactions plugin when autocapture is set', async () => {\n      const frustrationInteractionsPlugin = jest.spyOn(autocapture, 'frustrationPlugin');\n      await client.init(apiKey, userId, {\n        autocapture: {\n          frustrationInteractions: true,\n        },\n      }).promise;\n      expect(frustrationInteractionsPlugin).toHaveBeenCalledTimes(1);\n    });\n\n    test('should add performance tracking plugin when autocapture.performanceTracking is set', async () => {\n      const performanceTrackingPlugin = jest.spyOn(autocapture, 'performancePlugin');\n      await client.init(apiKey, userId, {\n        autocapture: {\n          performanceTracking: true,\n        },\n      }).promise;\n      expect(performanceTrackingPlugin).toHaveBeenCalledTimes(1);\n      expect(performanceTrackingPlugin).toHaveBeenCalledWith({ mainThreadBlock: true });\n    });\n\n    test('should NOT add performance tracking plugin by default', async () => {\n      const performanceTrackingPlugin = jest.spyOn(autocapture, 'performancePlugin');\n      await client.init(apiKey, userId).promise;\n      expect(performanceTrackingPlugin).toHaveBeenCalledTimes(0);\n    });\n\n    test('should NOT add performance tracking plugin when autocapture=true', async () => {\n      const performanceTrackingPlugin = jest.spyOn(autocapture, 'performancePlugin');\n      await client.init(apiKey, userId, {\n        autocapture: true,\n      }).promise;\n      expect(performanceTrackingPlugin).toHaveBeenCalledTimes(0);\n    });\n\n    test('should register autocapture and performance plugins when both element interactions and performance tracking are enabled', async () => {\n      await client.init(apiKey, userId, {\n        autocapture: {\n          elementInteractions: true,\n          performanceTracking: true,\n        },\n      }).promise;\n      const names = client.timeline.plugins.map((p) => p.name);\n      expect(names).toContain('@amplitude/plugin-autocapture-browser');\n      expect(names).toContain('@amplitude/plugin-performance-browser');\n    });\n\n    test('should add page view tracking plugin by default', async () => {\n      const pageViewTrackingPlugin = jest.spyOn(pageViewTracking, 'pageViewTrackingPlugin');\n      await client.init(apiKey, userId).promise;\n      expect(pageViewTrackingPlugin).toHaveBeenCalledTimes(1);\n    });\n\n    test('should NOT add page view tracking plugin when DET is disabled', async () => {\n      const pageViewTrackingPlugin = jest.spyOn(pageViewTracking, 'pageViewTrackingPlugin');\n      await client.init(apiKey, userId, {\n        defaultTracking: false,\n      }).promise;\n      expect(pageViewTrackingPlugin).toHaveBeenCalledTimes(0);\n    });\n\n    test('should NOT add page view tracking plugin when page view is disabled', async () => {\n      const pageViewTrackingPlugin = jest.spyOn(pageViewTracking, 'pageViewTrackingPlugin');\n      await client.init(apiKey, userId, {\n        defaultTracking: {\n          pageViews: false,\n        },\n      }).promise;\n      expect(pageViewTrackingPlugin).toHaveBeenCalledTimes(0);\n    });\n\n    test('should NOT add default tracking plugins when autocapture is disabled', async () => {\n      const pageViewTrackingPlugin = jest.spyOn(pageViewTracking, 'pageViewTrackingPlugin');\n      const fileDownloadTrackingPlugin = jest.spyOn(fileDownloadTracking, 'fileDownloadTracking');\n      const formInteractionTrackingPlugin = jest.spyOn(formInteractionTracking, 'formInteractionTracking');\n      await client.init(apiKey, userId, {\n        autocapture: {\n          pageViews: false,\n          fileDownloads: false,\n          formInteractions: false,\n        },\n      }).promise;\n      expect(pageViewTrackingPlugin).toHaveBeenCalledTimes(0);\n      expect(fileDownloadTrackingPlugin).toHaveBeenCalledTimes(0);\n      expect(formInteractionTrackingPlugin).toHaveBeenCalledTimes(0);\n    });\n\n    test.each([true, { elementInteractions: true }])(\n      'should add autocapture plugin',\n      async (option: boolean | AutocaptureOptions) => {\n        const autocapturePlugin = jest.spyOn(autocapture, 'autocapturePlugin');\n        await client.init(apiKey, userId, {\n          autocapture: option,\n        }).promise;\n        expect(autocapturePlugin).toHaveBeenCalledTimes(1);\n      },\n    );\n\n    test.each([\n      undefined, // default\n      false, // disabled\n      { elementInteractions: false }, // disabled\n    ])('should NOT add autocapture plugin', async (option: undefined | boolean | AutocaptureOptions) => {\n      const autocapturePlugin = jest.spyOn(autocapture, 'autocapturePlugin');\n      await client.init(apiKey, userId, {\n        autocapture: option,\n      }).promise;\n      expect(autocapturePlugin).toHaveBeenCalledTimes(0);\n    });\n\n    test('should use network tracking plugin when autocapture.networkTracking is on', async () => {\n      const networkTrackingPlugin = jest.spyOn(networkCapturePlugin, 'plugin');\n      await client.init(apiKey, userId, {\n        autocapture: {\n          networkTracking: true,\n        },\n      }).promise;\n      expect(networkTrackingPlugin).toHaveBeenCalledTimes(1);\n    });\n\n    test('should use web vitals plugin when autocapture.webVitals is on', async () => {\n      const webVitalsPlugin = jest.spyOn(webVitals, 'webVitalsPlugin');\n      await client.init(apiKey, userId, {\n        autocapture: {\n          webVitals: true,\n        },\n      }).promise;\n      expect(webVitalsPlugin).toHaveBeenCalledTimes(1);\n    });\n\n    test('should listen for network change to online', async () => {\n      jest.useFakeTimers();\n      const addEventListenerMock = jest.spyOn(window, 'addEventListener');\n      const flush = jest.spyOn(client, 'flush').mockReturnValue({ promise: Promise.resolve() });\n      const loggerProvider = {\n        log: jest.fn(),\n        debug: jest.fn(),\n        warn: jest.fn(),\n        error: jest.fn(),\n        enable: jest.fn(),\n        disable: jest.fn(),\n      };\n\n      await client.init(apiKey, {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n      }).promise;\n      window.dispatchEvent(new Event('online'));\n\n      expect(addEventListenerMock).toHaveBeenCalledWith('online', expect.any(Function));\n      expect(client.config.offline).toBe(false);\n      expect(loggerProvider.debug).toHaveBeenCalledWith('Network connectivity changed to online.');\n\n      jest.advanceTimersByTime(client.config.flushIntervalMillis);\n      expect(flush).toHaveBeenCalledTimes(1);\n\n      jest.useRealTimers();\n      addEventListenerMock.mockRestore();\n      flush.mockRestore();\n    });\n\n    test('should listen for network change to offline', async () => {\n      jest.useFakeTimers();\n      const addEventListenerMock = jest.spyOn(window, 'addEventListener');\n      const loggerProvider = {\n        log: jest.fn(),\n        debug: jest.fn(),\n        warn: jest.fn(),\n        error: jest.fn(),\n        enable: jest.fn(),\n        disable: jest.fn(),\n      };\n\n      await client.init(apiKey, {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n      }).promise;\n      expect(client.config.offline).toBe(false);\n\n      window.dispatchEvent(new Event('offline'));\n      expect(addEventListenerMock).toHaveBeenCalledWith('offline', expect.any(Function));\n      expect(client.config.offline).toBe(true);\n      expect(loggerProvider.debug).toHaveBeenCalledWith('Network connectivity changed to offline.');\n\n      jest.useRealTimers();\n      addEventListenerMock.mockRestore();\n    });\n\n    test('should not support offline mode if global scope returns undefined', async () => {\n      const getGlobalScopeMock = jest.spyOn(core, 'getGlobalScope').mockReturnValueOnce(undefined);\n      const addEventListenerMock = jest.spyOn(window, 'addEventListener');\n\n      await client.init(apiKey, {\n        defaultTracking: false,\n      }).promise;\n\n      window.dispatchEvent(new Event('online'));\n      expect(client.config.offline).toBe(false);\n\n      client.config.offline = true;\n      window.dispatchEvent(new Event('offline'));\n      expect(client.config.offline).toBe(true);\n\n      getGlobalScopeMock.mockRestore();\n      addEventListenerMock.mockRestore();\n    });\n\n    test('should add page url previous page plugin if pageUrlEnrichment is true', async () => {\n      const pageUrlEnrichmentPlugin = jest.spyOn(pageUrlEnrichment, 'pageUrlEnrichmentPlugin');\n      await client.init(apiKey, userId, {\n        autocapture: {\n          pageUrlEnrichment: true,\n        },\n      }).promise;\n      expect(pageUrlEnrichmentPlugin).toHaveBeenCalledTimes(1);\n    });\n\n    test('should NOT add page url previous page plugin if pageUrlEnrichment is false', async () => {\n      const pageUrlEnrichmentPlugin = jest.spyOn(pageUrlEnrichment, 'pageUrlEnrichmentPlugin');\n      await client.init(apiKey, userId, {\n        autocapture: {\n          pageUrlEnrichment: false,\n        },\n      }).promise;\n      expect(pageUrlEnrichmentPlugin).toHaveBeenCalledTimes(0);\n    });\n\n    test('should add page url previous page plugin if pageUrlEnrichment is undefined', async () => {\n      const pageUrlEnrichmentPlugin = jest.spyOn(pageUrlEnrichment, 'pageUrlEnrichmentPlugin');\n      await client.init(apiKey, userId, {\n        autocapture: {},\n      }).promise;\n      expect(pageUrlEnrichmentPlugin).toHaveBeenCalledTimes(1);\n    });\n\n    test('should add event property attribution plugin for event property tracking', async () => {\n      jest.spyOn(core.CampaignParser.prototype, 'parse').mockResolvedValue({\n        ...core.BASE_CAMPAIGN,\n        utm_source: 'amp-test',\n      });\n      const eventPropertyTrackingPlugin = jest.spyOn(eventPropertyTracking, 'eventPropertyTrackingPlugin');\n      const webAttributionInit = jest.spyOn(WebAttribution.prototype, 'init');\n\n      await client.init(apiKey, userId, {\n        fetchRemoteConfig: false,\n        defaultTracking: {\n          attribution: {\n            trackingMethod: 'eventProperty',\n          },\n          pageViews: false,\n          sessions: false,\n        },\n      }).promise;\n\n      expect(eventPropertyTrackingPlugin).toHaveBeenCalledTimes(1);\n      expect(eventPropertyTrackingPlugin).toHaveBeenCalledWith(\n        expect.objectContaining({\n          trackingMethod: 'eventProperty',\n        }),\n      );\n      expect(webAttributionInit).not.toHaveBeenCalled();\n    });\n\n    test('should add web attribution plugin for user property tracking only', async () => {\n      jest.spyOn(core.CampaignParser.prototype, 'parse').mockResolvedValue({\n        ...core.BASE_CAMPAIGN,\n        utm_source: 'amp-test',\n      });\n      const eventPropertyTrackingPlugin = jest.spyOn(eventPropertyTracking, 'eventPropertyTrackingPlugin');\n      const webAttributionInit = jest.spyOn(WebAttribution.prototype, 'init');\n\n      await client.init(apiKey, userId, {\n        fetchRemoteConfig: false,\n        defaultTracking: {\n          attribution: {\n            trackingMethod: 'userProperty',\n          },\n          pageViews: false,\n          sessions: false,\n        },\n      }).promise;\n\n      expect(webAttributionInit).toHaveBeenCalledTimes(1);\n      expect(eventPropertyTrackingPlugin).not.toHaveBeenCalled();\n    });\n\n    test('should add both attribution plugins when both tracking methods are enabled', async () => {\n      jest.spyOn(core.CampaignParser.prototype, 'parse').mockResolvedValue({\n        ...core.BASE_CAMPAIGN,\n        utm_source: 'amp-test',\n      });\n      const eventPropertyTrackingPlugin = jest.spyOn(eventPropertyTracking, 'eventPropertyTrackingPlugin');\n      const webAttributionInit = jest.spyOn(WebAttribution.prototype, 'init');\n\n      await client.init(apiKey, userId, {\n        fetchRemoteConfig: false,\n        defaultTracking: {\n          attribution: {\n            trackingMethod: ['userProperty', 'eventProperty'],\n          },\n          pageViews: false,\n          sessions: false,\n        },\n      }).promise;\n\n      expect(webAttributionInit).toHaveBeenCalledTimes(1);\n      expect(eventPropertyTrackingPlugin).toHaveBeenCalledTimes(1);\n      expect(eventPropertyTrackingPlugin).toHaveBeenCalledWith(\n        expect.objectContaining({\n          trackingMethod: ['userProperty', 'eventProperty'],\n        }),\n      );\n    });\n\n    test('should enrich same-tick track calls with the latest campaign after pushState', async () => {\n      jest\n        .spyOn(core.CampaignParser.prototype, 'parse')\n        .mockResolvedValueOnce({\n          ...core.BASE_CAMPAIGN,\n          utm_source: 'campaign-a',\n        })\n        .mockResolvedValueOnce({\n          ...core.BASE_CAMPAIGN,\n          utm_source: 'campaign-b',\n        });\n      let capturedEvent: core.Event | undefined;\n\n      await client.init(apiKey, userId, {\n        fetchRemoteConfig: false,\n        defaultTracking: {\n          attribution: {\n            trackingMethod: 'eventProperty',\n          },\n          pageViews: false,\n          sessions: false,\n        },\n      }).promise;\n\n      await client.add({\n        name: 'capture-event-property-attribution',\n        type: 'enrichment',\n        setup: async () => {\n          return;\n        },\n        execute: async (event) => {\n          capturedEvent = event;\n          return event;\n        },\n      }).promise;\n\n      window.history.pushState(undefined, '', '/next?utm_source=campaign-b');\n      void client\n        .track('test-event', {\n          existing: 'value',\n        })\n        .promise.catch(() => undefined);\n      await new Promise((resolve) => setTimeout(resolve, 10));\n\n      expect(capturedEvent).toBeDefined();\n      expect(capturedEvent).toEqual(\n        expect.objectContaining({\n          event_type: 'test-event',\n          event_properties: expect.objectContaining({\n            existing: 'value',\n            utm_source: 'campaign-b',\n          }),\n        }),\n      );\n    });\n\n    test('should add custom enrichment plugin when customEnrichment is an object with enabled=true', async () => {\n      const customEnrichmentPlugin = jest.spyOn(customEnrichment, 'customEnrichmentPlugin');\n      await client.init(apiKey, userId, {\n        customEnrichment: { enabled: true, body: 'test' },\n      }).promise;\n      expect(customEnrichmentPlugin).toHaveBeenCalledTimes(1);\n    });\n\n    test('should NOT add custom enrichment plugin when customEnrichment is undefined', async () => {\n      const customEnrichmentPlugin = jest.spyOn(customEnrichment, 'customEnrichmentPlugin');\n      await client.init(apiKey, userId).promise;\n      expect(customEnrichmentPlugin).toHaveBeenCalledTimes(0);\n    });\n\n    test('should NOT add custom enrichment plugin when customEnrichment is an object with enabled=false', async () => {\n      const customEnrichmentPlugin = jest.spyOn(customEnrichment, 'customEnrichmentPlugin');\n      await client.init(apiKey, userId, {\n        customEnrichment: { enabled: false, body: 'test' },\n      }).promise;\n      expect(customEnrichmentPlugin).toHaveBeenCalledTimes(0);\n    });\n\n    test('should NOT add custom enrichment plugin when customEnrichment is false', async () => {\n      const customEnrichmentPluginSpy = jest.spyOn(customEnrichment, 'customEnrichmentPlugin');\n      await client.init(apiKey, userId, {\n        customEnrichment: false,\n      }).promise;\n      expect(customEnrichmentPluginSpy).toHaveBeenCalledTimes(0);\n    });\n\n    test('should NOT add custom enrichment plugin when customEnrichment is false even if remote config enables it', async () => {\n      const mockRemoteConfigWithCustomEnrichment = {\n        subscribe: jest\n          .fn()\n          .mockImplementation(\n            (\n              configKey: string,\n              _eventType: string,\n              callback: (remoteConfig: any, source: any, lastFetch: Date) => void,\n            ) => {\n              if (configKey === 'configs.analyticsSDK.browserSDK') {\n                callback({ customEnrichment: { enabled: true, body: 'return event;' } }, 'cache', new Date());\n              } else {\n                callback(null, 'cache', new Date());\n              }\n            },\n          ),\n        unsubscribe: jest.fn(),\n        updateConfigs: jest.fn(),\n      };\n\n      MockedRemoteConfigClient = jest.fn().mockImplementation(() => mockRemoteConfigWithCustomEnrichment);\n      Object.defineProperty(core, 'RemoteConfigClient', {\n        value: MockedRemoteConfigClient,\n        writable: true,\n        configurable: true,\n      });\n\n      const customEnrichmentPluginSpy = jest.spyOn(customEnrichment, 'customEnrichmentPlugin');\n      await client.init(apiKey, userId, {\n        fetchRemoteConfig: true,\n        customEnrichment: false,\n      }).promise;\n      expect(customEnrichmentPluginSpy).toHaveBeenCalledTimes(0);\n    });\n\n    test.each([[url], [new URL(`https://www.example.com?deviceId=${testDeviceId}`)]])(\n      'should set device id from url',\n      async (mockedUrl) => {\n        const originalLocation = window.location;\n\n        Object.defineProperty(window, 'location', {\n          value: {\n            ...originalLocation,\n            search: mockedUrl.search,\n          } as Location,\n          writable: true,\n        });\n\n        await client.init(apiKey, userId, {\n          defaultTracking: false,\n        }).promise;\n        expect(client.config.deviceId).toEqual(testDeviceId);\n\n        Object.defineProperty(window, 'location', {\n          value: originalLocation,\n          writable: true,\n        });\n      },\n    );\n\n    test('should set session id from url', async () => {\n      const originalLocation = window.location;\n\n      Object.defineProperty(window, 'location', {\n        value: {\n          search: url.search,\n        } as Location,\n        writable: true,\n      });\n\n      const setSessionId = jest.spyOn(client, 'setSessionId');\n\n      await client.init(apiKey, userId, {\n        defaultTracking: {\n          attribution: false,\n          fileDownloads: false,\n          formInteractions: false,\n          pageViews: false,\n          sessions: true,\n        },\n      }).promise;\n      expect(client.config.sessionId).toEqual(testSessionId);\n      expect(setSessionId).toHaveBeenCalledTimes(1);\n      expect(setSessionId).toHaveBeenLastCalledWith(testSessionId);\n\n      Object.defineProperty(window, 'location', {\n        value: originalLocation,\n        writable: true,\n      });\n    });\n\n    test.each([[new URL(`https://www.example.com?ampSessionId=test}`)], [new URL(`https://www.example.com`)]])(\n      'should fall back to other options when session id from url is not Number',\n      async (mockedUrl) => {\n        // Mock window.location\n        const originalLocation = window.location;\n        Object.defineProperty(window, 'location', {\n          value: {\n            search: mockedUrl.search,\n          } as Location,\n          writable: true,\n        });\n\n        // Mock Date.now()\n        const originalDate = Date.now;\n        const currentTimestamp = Date.now();\n        Date.now = jest.fn(() => currentTimestamp);\n\n        const setSessionId = jest.spyOn(client, 'setSessionId');\n        await client.init(apiKey, userId, {\n          defaultTracking: {\n            attribution: false,\n            fileDownloads: false,\n            formInteractions: false,\n            pageViews: false,\n            sessions: true,\n          },\n        }).promise;\n\n        // should call \"setSessionId\" with undefined because \"test\" from ampSessionId is NaN\n        expect(client.config.sessionId).toEqual(currentTimestamp);\n        expect(setSessionId).toHaveBeenCalledTimes(1);\n        expect(setSessionId).toHaveBeenLastCalledWith(undefined);\n\n        // Restore mocks\n        Object.defineProperty(window, 'location', {\n          value: originalLocation,\n          writable: true,\n        });\n        Date.now = originalDate;\n      },\n    );\n\n    describe('config.optOut', () => {\n      describe('when optOut is true', () => {\n        beforeEach(async () => {\n          const identity = new Identify();\n          identity.set('test-property', 'test-value');\n          await client.init(apiKey, userId, {\n            optOut: true,\n            identify: identity,\n          }).promise;\n        });\n\n        test('should defer session + attribution until after optOut changes', async () => {\n          expect(client.config.sessionId).toBeUndefined();\n          client.setOptOut(false);\n          // give the timeline 10 ms to finish calling the onOptOutChanged listeners\n          await new Promise((resolve) => setTimeout(resolve, 10));\n          expect(client.config.sessionId).toBeGreaterThan(0);\n        });\n\n        test('should defer session but use user specified sessionId if provided', async () => {\n          expect(client.config.sessionId).toBeUndefined();\n          const id = Date.now() + 10_000; // future timestamp\n          client.setSessionId(id);\n          client.setOptOut(false);\n          await new Promise((resolve) => setTimeout(resolve, 10));\n          expect(client.config.sessionId).toBe(id);\n        });\n\n        test('should defer session + attribution until another init call with optOut false', async () => {\n          expect(client.config.sessionId).toBeUndefined();\n          await client.init(apiKey, userId, {\n            optOut: false,\n          }).promise;\n          // give the timeline 10 ms to finish calling the onOptOutChanged listeners\n          await new Promise((resolve) => setTimeout(resolve, 10));\n          expect(client.config.sessionId).toBeGreaterThan(0);\n        });\n\n        test('should defer session but use user specified sessionId if set with setSessionId', async () => {\n          expect(client.config.sessionId).toBeUndefined();\n          const id = Date.now() + 10_000; // future timestamp\n          client.setSessionId(id);\n          await client.init(apiKey, userId, {\n            optOut: false,\n          }).promise;\n          await new Promise((resolve) => setTimeout(resolve, 20));\n          expect(client.config.sessionId).toBe(id);\n        });\n\n        test('should defer session but use user specified sessionId if set in init', async () => {\n          expect(client.config.sessionId).toBeUndefined();\n          const id = Date.now() + 10_000; // future timestamp\n          await client.init(apiKey, userId, {\n            optOut: false,\n            sessionId: id,\n          }).promise;\n          expect(client.config.sessionId).toBe(id);\n        });\n\n        test('should not initialize webAttribution when optOut listener receives true', async () => {\n          // Initialize with optOut: true and attribution enabled to set up the listener\n          await client.init(apiKey, userId, {\n            optOut: true,\n            defaultTracking: {\n              attribution: true,\n            },\n          }).promise;\n\n          // Track calls to WebAttribution constructor\n          let webAttributionInitCallCount = 0;\n          /* eslint-disable-next-line @typescript-eslint/unbound-method */\n          const originalInit = WebAttribution.prototype.init;\n          jest.spyOn(WebAttribution.prototype, 'init').mockImplementation(function (this: WebAttribution) {\n            webAttributionInitCallCount++;\n            return originalInit.call(this);\n          });\n\n          // set optOut to false and then true\n          client.setOptOut(false);\n          await new Promise((resolve) => setTimeout(resolve, 10));\n          client.setOptOut(true);\n          await new Promise((resolve) => setTimeout(resolve, 10));\n\n          // should only call init once\n          expect(webAttributionInitCallCount).toBe(1);\n        });\n\n        test('should add event property attribution plugin even when optOut is true', async () => {\n          jest.spyOn(core.CampaignParser.prototype, 'parse').mockResolvedValue({\n            ...core.BASE_CAMPAIGN,\n            utm_source: 'amp-test',\n          });\n          const eventPropertyTrackingPlugin = jest.spyOn(eventPropertyTracking, 'eventPropertyTrackingPlugin');\n\n          await client.init(apiKey, userId, {\n            optOut: true,\n            fetchRemoteConfig: false,\n            defaultTracking: {\n              attribution: {\n                trackingMethod: 'eventProperty',\n              },\n              pageViews: false,\n              sessions: false,\n            },\n          }).promise;\n\n          expect(eventPropertyTrackingPlugin).toHaveBeenCalledTimes(1);\n          expect(eventPropertyTrackingPlugin).toHaveBeenCalledWith(\n            expect.objectContaining({\n              trackingMethod: 'eventProperty',\n            }),\n          );\n        });\n      });\n\n      describe('when optOut is false', () => {\n        let sessionId: number | undefined;\n        beforeEach(async () => {\n          await client.init(apiKey, userId, {\n            optOut: false,\n          }).promise;\n          sessionId = client.config.sessionId;\n        });\n\n        test('should not change sessionId when optOut changes to true', async () => {\n          expect(sessionId).toBeGreaterThan(0);\n          client.setOptOut(true);\n          expect(client.config.sessionId).toBe(sessionId);\n        });\n\n        test('should not change sessionId when another init called again with optOut false', async () => {\n          expect(sessionId).toBeGreaterThan(0);\n          await client.init(apiKey, userId, {\n            optOut: false,\n          }).promise;\n          expect(client.config.sessionId).toBe(sessionId);\n        });\n      });\n    });\n\n    describe('ampTimestamp validation', () => {\n      const originalLocation = window.location;\n      const originalDateNow = Date.now;\n      const currentTime = 1640995200000; // 2022-01-01 00:00:00 UTC\n      const futureTimestamp = currentTime + 300000; // 5 minutes in the future\n      const pastTimestamp = currentTime - 300000; // 5 minutes in the past\n      const mockedUUID = '1234567890';\n\n      beforeEach(() => {\n        Date.now = jest.fn(() => currentTime);\n        // Mock UUID() to return a fixed value\n        jest.spyOn(core, 'UUID').mockReturnValue(mockedUUID);\n      });\n\n      afterEach(() => {\n        Object.defineProperty(window, 'location', {\n          value: originalLocation,\n          writable: true,\n        });\n        Date.now = originalDateNow;\n      });\n\n      test('should use ampSessionId when ampTimestamp is valid (future)', async () => {\n        const urlWithValidTimestamp = new URL(\n          `https://www.example.com?ampSessionId=${testSessionId}&ampTimestamp=${futureTimestamp}`,\n        );\n\n        Object.defineProperty(window, 'location', {\n          value: {\n            ...originalLocation,\n            search: urlWithValidTimestamp.search,\n          } as Location,\n          writable: true,\n        });\n\n        const setSessionId = jest.spyOn(client, 'setSessionId');\n\n        await client.init(apiKey, userId, {\n          defaultTracking: {\n            attribution: false,\n            fileDownloads: false,\n            formInteractions: false,\n            pageViews: false,\n            sessions: true,\n          },\n        }).promise;\n\n        expect(client.config.sessionId).toEqual(testSessionId);\n        expect(setSessionId).toHaveBeenCalledWith(testSessionId);\n      });\n\n      test('should ignore ampSessionId when ampTimestamp is expired (past)', async () => {\n        const urlWithExpiredTimestamp = new URL(\n          `https://www.example.com?ampSessionId=${testSessionId}&ampTimestamp=${pastTimestamp}`,\n        );\n\n        Object.defineProperty(window, 'location', {\n          value: {\n            ...originalLocation,\n            search: urlWithExpiredTimestamp.search,\n          } as Location,\n          writable: true,\n        });\n\n        const setSessionId = jest.spyOn(client, 'setSessionId');\n\n        await client.init(apiKey, userId, {\n          defaultTracking: {\n            attribution: false,\n            fileDownloads: false,\n            formInteractions: false,\n            pageViews: false,\n            sessions: true,\n          },\n        }).promise;\n\n        // Should fall back to Date.now() instead of using expired ampSessionId\n        expect(client.config.sessionId).toEqual(currentTime);\n        expect(setSessionId).toHaveBeenCalledWith(undefined);\n      });\n\n      test('should use ampDeviceId when ampTimestamp is valid (future)', async () => {\n        const urlWithValidTimestamp = new URL(\n          `https://www.example.com?ampDeviceId=${testDeviceId}&ampTimestamp=${futureTimestamp}`,\n        );\n\n        Object.defineProperty(window, 'location', {\n          value: {\n            ...originalLocation,\n            search: urlWithValidTimestamp.search,\n          } as Location,\n          writable: true,\n        });\n\n        await client.init(apiKey, userId, {\n          defaultTracking: false,\n        }).promise;\n\n        expect(client.config.deviceId).toEqual(testDeviceId);\n      });\n\n      test('should ignore ampDeviceId when ampTimestamp is expired (past)', async () => {\n        const urlWithExpiredTimestamp = new URL(\n          `https://www.example.com?ampDeviceId=${testDeviceId}&ampTimestamp=${pastTimestamp}`,\n        );\n\n        Object.defineProperty(window, 'location', {\n          value: {\n            ...originalLocation,\n            search: urlWithExpiredTimestamp.search,\n          } as Location,\n          writable: true,\n        });\n\n        await client.init(apiKey, userId, {\n          defaultTracking: false,\n        }).promise;\n\n        // Should generate new device ID instead of using expired ampDeviceId\n        expect(client.config.deviceId).toEqual(mockedUUID);\n      });\n\n      test('should work as before when ampTimestamp is missing (backward compatibility)', async () => {\n        const urlWithoutTimestamp = new URL(\n          `https://www.example.com?ampSessionId=${testSessionId}&ampDeviceId=${testDeviceId}`,\n        );\n\n        Object.defineProperty(window, 'location', {\n          value: {\n            ...originalLocation,\n            search: urlWithoutTimestamp.search,\n          } as Location,\n          writable: true,\n        });\n\n        const setSessionId = jest.spyOn(client, 'setSessionId');\n\n        await client.init(apiKey, userId, {\n          defaultTracking: {\n            attribution: false,\n            fileDownloads: false,\n            formInteractions: false,\n            pageViews: false,\n            sessions: true,\n          },\n        }).promise;\n\n        // Should use both parameters when timestamp is missing (backward compatibility)\n        expect(client.config.sessionId).toEqual(testSessionId);\n        expect(client.config.deviceId).toEqual(testDeviceId);\n        expect(setSessionId).toHaveBeenCalledWith(testSessionId);\n      });\n\n      test('should handle malformed ampTimestamp gracefully', async () => {\n        const urlWithMalformedTimestamp = new URL(\n          `https://www.example.com?ampSessionId=${testSessionId}&ampDeviceId=${testDeviceId}&ampTimestamp=invalid`,\n        );\n\n        Object.defineProperty(window, 'location', {\n          value: {\n            ...originalLocation,\n            search: urlWithMalformedTimestamp.search,\n          } as Location,\n          writable: true,\n        });\n\n        const setSessionId = jest.spyOn(client, 'setSessionId');\n\n        await client.init(apiKey, userId, {\n          defaultTracking: {\n            attribution: false,\n            fileDownloads: false,\n            formInteractions: false,\n            pageViews: false,\n            sessions: true,\n          },\n        }).promise;\n\n        // Should treat malformed timestamp as missing and use parameters (backward compatibility)\n        expect(client.config.sessionId).toEqual(testSessionId);\n        expect(client.config.deviceId).toEqual(testDeviceId);\n        expect(setSessionId).toHaveBeenCalledWith(testSessionId);\n      });\n\n      test('should use deviceId parameter when ampTimestamp is valid', async () => {\n        const urlWithValidTimestampDeviceId = new URL(\n          `https://www.example.com?deviceId=${testDeviceId}&ampTimestamp=${futureTimestamp}`,\n        );\n\n        Object.defineProperty(window, 'location', {\n          value: {\n            ...originalLocation,\n            search: urlWithValidTimestampDeviceId.search,\n          } as Location,\n          writable: true,\n        });\n\n        await client.init(apiKey, userId, {\n          defaultTracking: false,\n        }).promise;\n\n        expect(client.config.deviceId).toEqual(testDeviceId);\n      });\n\n      test('should ignore deviceId parameter when ampTimestamp is expired', async () => {\n        const urlWithExpiredTimestampDeviceId = new URL(\n          `https://www.example.com?deviceId=${testDeviceId}&ampTimestamp=${pastTimestamp}`,\n        );\n\n        Object.defineProperty(window, 'location', {\n          value: {\n            ...originalLocation,\n            search: urlWithExpiredTimestampDeviceId.search,\n          } as Location,\n          writable: true,\n        });\n\n        await client.init(apiKey, userId, {\n          defaultTracking: false,\n        }).promise;\n\n        // Should generate new device ID instead of using expired deviceId parameter\n        expect(client.config.deviceId).not.toEqual(testDeviceId);\n        expect(client.config.deviceId).toBeDefined();\n        expect(typeof client.config.deviceId).toBe('string');\n        const { deviceId } = client.config;\n        if (typeof deviceId !== 'string') {\n          throw new Error('Expected deviceId to be a string');\n        }\n        expect(deviceId.length).toBeGreaterThan(0);\n      });\n    });\n  });\n\n  describe('getUserId', () => {\n    test('should get user id', async () => {\n      await client.init(apiKey, userId, { defaultTracking }).promise;\n      expect(client.getUserId()).toBe(userId);\n    });\n\n    test('should handle undefined config', async () => {\n      expect(client.getUserId()).toBe(undefined);\n    });\n  });\n\n  describe('setUserId', () => {\n    test('should set user id', async () => {\n      await client.init(apiKey, { defaultTracking }).promise;\n      expect(client.getUserId()).toBe(undefined);\n      client.setUserId(userId);\n      expect(client.getUserId()).toBe(userId);\n    });\n\n    test('should not set user id', async () => {\n      const setSessionId = jest.spyOn(client, 'setSessionId');\n      await client.init(apiKey, userId, { defaultTracking }).promise;\n\n      // Reset mock to isolate mock for `setUserId(...)` call\n      // `setUserId(...)` may have been called on `init(...)`\n      // We do not want to depend on init behavior\n      setSessionId.mockReset();\n\n      expect(client.getUserId()).toBe(userId);\n      client.setUserId(userId);\n      expect(setSessionId).toHaveBeenCalledTimes(0);\n      expect(client.getUserId()).toBe(userId);\n    });\n\n    test('should not send session events on set user', async () => {\n      jest.spyOn(CookieMigration, 'parseLegacyCookies').mockResolvedValueOnce({\n        optOut: false,\n        sessionId: 1,\n        lastEventTime: Date.now() - 1000,\n      });\n      const result = {\n        promise: Promise.resolve({\n          code: 200,\n          event: {\n            event_type: 'a',\n          },\n          message: 'success',\n        }),\n      };\n      const track = jest.spyOn(client, 'track').mockReturnValue(result);\n      await client.init(apiKey, userId, {\n        sessionTimeout: 5000,\n        defaultTracking: {\n          ...defaultTracking,\n          sessions: true,\n        },\n      }).promise;\n\n      // Reset mock to isolate mock for `track(...)` call\n      // `track(...)` may have been called on `init(...)`\n      // We do not want to depend on init behavior\n      track.mockReset();\n\n      client.setUserId(undefined);\n      expect(client.getUserId()).toBe(undefined);\n      expect(track).toHaveBeenCalledTimes(0);\n    });\n\n    test('should defer set user id', () => {\n      return new Promise<void>((resolve) => {\n        void client.init(apiKey, { defaultTracking }).promise.then(() => {\n          expect(client.getUserId()).toBe('user@amplitude.com');\n          resolve();\n        });\n        client.setUserId('user@amplitude.com');\n      });\n    });\n\n    test('should be able to unset user id to undefined', async () => {\n      await client.init(apiKey, userId, {\n        defaultTracking,\n        deviceId,\n      }).promise;\n      expect(client.getUserId()).toBe(userId);\n      expect(client.getDeviceId()).toBe(deviceId);\n\n      client.setUserId(undefined);\n      expect(client.getUserId()).toBe(undefined);\n      expect(client.getDeviceId()).toBe(deviceId);\n    });\n\n    test('should be able to unset user id to undefined after setUserId()', async () => {\n      await client.init(apiKey, {\n        defaultTracking,\n        deviceId,\n      }).promise;\n      expect(client.getUserId()).toBe(undefined);\n      expect(client.getDeviceId()).toBe(deviceId);\n\n      client.setUserId(userId);\n      expect(client.getUserId()).toBe(userId);\n      expect(client.getDeviceId()).toBe(deviceId);\n\n      client.setUserId(undefined);\n      expect(client.getUserId()).toBe(undefined);\n      expect(client.getDeviceId()).toBe(deviceId);\n    });\n  });\n\n  describe('getDeviceId', () => {\n    test('should get device id', async () => {\n      await client.init(apiKey, {\n        defaultTracking,\n        deviceId,\n      }).promise;\n      expect(client.getDeviceId()).toBe(deviceId);\n    });\n\n    test('should handle undefined config', async () => {\n      expect(client.getDeviceId()).toBe(undefined);\n    });\n  });\n\n  describe('setDeviceId', () => {\n    test('should set device id config', async () => {\n      await client.init(apiKey, { defaultTracking }).promise;\n      client.setDeviceId(deviceId);\n      expect(client.getDeviceId()).toBe(deviceId);\n    });\n\n    test('should defer set device id', () => {\n      return new Promise<void>((resolve) => {\n        void client.init(apiKey, { defaultTracking }).promise.then(() => {\n          expect(client.getDeviceId()).toBe('asdfg');\n          resolve();\n        });\n        client.setDeviceId('asdfg');\n      });\n    });\n  });\n\n  describe('reset', () => {\n    test('should reset user id and generate new device id config', async () => {\n      await client.init(apiKey, { defaultTracking }).promise;\n      client.setUserId(userId);\n      client.setDeviceId(deviceId);\n      expect(client.getUserId()).toBe(userId);\n      expect(client.getDeviceId()).toBe(deviceId);\n      client.reset();\n      expect(client.getUserId()).toBe(undefined);\n      expect(client.getDeviceId()).not.toBe(deviceId);\n    });\n\n    test('should invoke plugin onReset hooks', async () => {\n      await client.init(apiKey, { defaultTracking }).promise;\n\n      const onResetMock = jest.fn();\n      const testPlugin = {\n        name: 'test-reset-plugin',\n        type: 'enrichment' as const,\n        setup: jest.fn().mockResolvedValue(undefined),\n        execute: jest.fn().mockImplementation((event) => Promise.resolve(event)),\n        onReset: onResetMock,\n      };\n\n      await client.add(testPlugin).promise;\n      client.reset();\n\n      expect(onResetMock).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('getIdentity', () => {\n    test('should get identity', async () => {\n      const userId = 'test-user-id';\n      const deviceId = 'test-device-id';\n\n      await client.init(apiKey, 'test-user-id', {\n        defaultTracking,\n        deviceId,\n      }).promise;\n      const identify = new Identify();\n      identify.set('test-property', 'test-value');\n      client.identify(identify);\n\n      const identity = client.getIdentity();\n\n      expect(identity).toEqual({\n        deviceId: deviceId,\n        userId: userId,\n        userProperties: {\n          'test-property': 'test-value',\n        },\n      });\n    });\n\n    test('should handle undefined', () => {\n      const identity = client.getIdentity();\n\n      expect(identity).toEqual({\n        deviceId: undefined,\n        userId: undefined,\n        userProperties: undefined,\n      });\n    });\n\n    test('should update identity after setting userId and deviceId', async () => {\n      await client.init(apiKey, { defaultTracking }).promise;\n\n      const initialIdentity = client.getIdentity();\n      expect(initialIdentity.userId).toBe(undefined);\n\n      client.setUserId(userId);\n      client.setDeviceId(deviceId);\n\n      const updatedIdentity = client.getIdentity();\n      expect(updatedIdentity).toEqual({\n        deviceId: deviceId,\n        userId: userId,\n        userProperties: client.userProperties,\n      });\n    });\n  });\n\n  describe('setIdentity', () => {\n    test('should set userId via setIdentity', async () => {\n      await client.init(apiKey, { defaultTracking }).promise;\n      expect(client.getUserId()).toBe(undefined);\n\n      client.setIdentity({ userId: 'new-user-id' });\n\n      expect(client.getUserId()).toBe('new-user-id');\n    });\n\n    test('should set deviceId via setIdentity', async () => {\n      await client.init(apiKey, { defaultTracking }).promise;\n      const initialDeviceId = client.getDeviceId();\n\n      client.setIdentity({ deviceId: 'new-device-id' });\n\n      expect(client.getDeviceId()).toBe('new-device-id');\n      expect(client.getDeviceId()).not.toBe(initialDeviceId);\n    });\n\n    test('should set userProperties and auto-send identify event', async () => {\n      await client.init(apiKey, { defaultTracking }).promise;\n      const identifySpy = jest.spyOn(client, 'identify');\n\n      client.setIdentity({ userProperties: { plan: 'premium', theme: 'dark' } });\n\n      expect(client.userProperties).toEqual({ plan: 'premium', theme: 'dark' });\n      expect(identifySpy).toHaveBeenCalledTimes(1);\n\n      const identity = client.getIdentity();\n      expect(identity.userProperties).toEqual({ plan: 'premium', theme: 'dark' });\n    });\n\n    test('should set userId and userProperties together', async () => {\n      await client.init(apiKey, { defaultTracking }).promise;\n      const identifySpy = jest.spyOn(client, 'identify');\n\n      client.setIdentity({\n        userId: 'new-user-id',\n        userProperties: { name: 'John' },\n      });\n\n      expect(client.getUserId()).toBe('new-user-id');\n      expect(client.userProperties).toEqual({ name: 'John' });\n      expect(identifySpy).toHaveBeenCalledTimes(1);\n    });\n\n    test('should defer setIdentity before init', () => {\n      return new Promise<void>((resolve) => {\n        void client.init(apiKey, { defaultTracking }).promise.then(() => {\n          expect(client.getUserId()).toBe('deferred-user');\n          expect(client.userProperties).toEqual({ deferred: true });\n          resolve();\n        });\n        client.setIdentity({ userId: 'deferred-user', userProperties: { deferred: true } });\n      });\n    });\n\n    test('should notify plugins of identity change', async () => {\n      await client.init(apiKey, { defaultTracking }).promise;\n      const onIdentityChangedMock = jest.fn();\n\n      await client.add({\n        name: 'test-plugin',\n        type: 'enrichment',\n        setup: async () => {\n          return;\n        },\n        execute: async (event) => event,\n        onIdentityChanged: onIdentityChangedMock,\n      }).promise;\n\n      client.setIdentity({ userProperties: { plan: 'premium' } });\n\n      expect(onIdentityChangedMock).toHaveBeenCalledWith({ userProperties: { plan: 'premium' } });\n    });\n  });\n\n  describe('getOptOut', () => {\n    test.each([true, false])('should return opt out value', async (optOut) => {\n      await client.init(apiKey, {\n        defaultTracking,\n        sessionId: 1,\n        optOut,\n      }).promise;\n      expect(client.getOptOut()).toBe(optOut);\n    });\n\n    test('should return undefined if opt out is not set', async () => {\n      expect(client.getOptOut()).toBe(undefined);\n    });\n  });\n\n  describe('getSessionId', () => {\n    test('should get session id', async () => {\n      await client.init(apiKey, {\n        defaultTracking,\n        sessionId: 1,\n      }).promise;\n      expect(client.getSessionId()).toBe(1);\n    });\n\n    test('should handle undefined config', async () => {\n      expect(client.getSessionId()).toBe(undefined);\n    });\n  });\n\n  describe('setSessionId', () => {\n    test('should set session id', async () => {\n      await client.init(apiKey, { defaultTracking }).promise;\n      client.setSessionId(1);\n      expect(client.getSessionId()).toBe(1);\n    });\n\n    test('should set session id with start session event', async () => {\n      const result = {\n        promise: Promise.resolve({\n          code: 200,\n          event: {\n            event_type: 'a',\n          },\n          message: 'success',\n        }),\n      };\n      const track = jest.spyOn(client, 'track').mockReturnValue(result);\n      await client.init(apiKey, {\n        sessionId: 1,\n        defaultTracking: {\n          ...defaultTracking,\n          attribution: false,\n          pageViews: false,\n          sessions: true,\n        },\n      }).promise;\n      client.setSessionId(2);\n      expect(client.getSessionId()).toBe(2);\n      expect(track).toHaveBeenCalledTimes(3);\n    });\n\n    test('should set session id with start and end session event', async () => {\n      jest.spyOn(CookieMigration, 'parseLegacyCookies').mockResolvedValueOnce({\n        optOut: false,\n        sessionId: 1,\n        lastEventId: 100,\n        lastEventTime: Date.now() - 1000,\n      });\n      const result = {\n        promise: Promise.resolve({\n          code: 200,\n          event: {\n            event_type: 'a',\n          },\n          message: 'success',\n        }),\n      };\n      const track = jest.spyOn(client, 'track').mockReturnValue(result);\n      await client.init(apiKey, {\n        sessionTimeout: 5000,\n        defaultTracking: {\n          ...defaultTracking,\n          attribution: false,\n          pageViews: false,\n          sessions: true,\n        },\n      }).promise;\n      client.setSessionId(2);\n      expect(client.getSessionId()).toBe(2);\n      expect(track).toHaveBeenCalledTimes(2);\n    });\n\n    test('should set session id with start and end session event and web attribution event', async () => {\n      jest.spyOn(CookieMigration, 'parseLegacyCookies').mockResolvedValueOnce({\n        optOut: false,\n        sessionId: 1,\n        lastEventId: 100,\n        lastEventTime: Date.now() - 1000,\n      });\n      const result = {\n        promise: Promise.resolve({\n          code: 200,\n          event: {\n            event_type: 'a',\n          },\n          message: 'success',\n        }),\n      };\n      const track = jest.spyOn(client, 'track').mockReturnValue(result);\n      await client.init(apiKey, {\n        sessionTimeout: 5000,\n        defaultTracking: {\n          ...defaultTracking,\n          attribution: true,\n          pageViews: false,\n          sessions: true,\n        },\n      }).promise;\n\n      client.setSessionId(2);\n\n      expect(client.getSessionId()).toBe(2);\n      return new Promise<void>((resolve) => {\n        setTimeout(() => {\n          expect(track).toHaveBeenCalledTimes(3);\n          resolve();\n        }, 4000);\n      });\n    });\n\n    test('should defer set session id', () => {\n      return new Promise<void>((resolve) => {\n        void client.init(apiKey, { defaultTracking }).promise.then(() => {\n          expect(client.getSessionId()).toBe(1);\n          resolve();\n        });\n        client.setSessionId(1);\n      });\n    });\n  });\n\n  describe('extendSession', () => {\n    test('should extend the current session without sending events', async () => {\n      const firstSessionId = 1;\n      const client = new AmplitudeBrowser();\n      await client.init(apiKey, {\n        sessionTimeout: 20,\n        sessionId: firstSessionId,\n        flushQueueSize: 1,\n        flushIntervalMillis: 1,\n        defaultTracking,\n      }).promise;\n      // assert sessionId is set\n      expect(client.config.sessionId).toBe(firstSessionId);\n      expect(client.config.lastEventTime).toBeUndefined();\n\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore\n      jest.spyOn(client.config.transportProvider, 'send').mockReturnValue(\n        Promise.resolve({\n          status: Status.Success,\n          statusCode: 200,\n          body: {\n            eventsIngested: 1,\n            payloadSizeBytes: 1,\n            serverUploadTime: 1,\n          },\n        }),\n      );\n\n      // send an event\n      await client.track('test 1').promise;\n      const eventTime1 = client.config.lastEventTime ?? -1;\n      expect(eventTime1 > 0).toBeTruthy();\n\n      // wait for session to almost expire, then extend it\n      await new Promise<void>((resolve) =>\n        setTimeout(() => {\n          client.extendSession();\n          resolve();\n        }, 15),\n      );\n\n      // assert session id is unchanged\n      expect(client.config.sessionId).toBe(firstSessionId);\n      // assert last event time was updated\n      const extendedLastEventTime = client.config.lastEventTime ?? -1;\n      expect(extendedLastEventTime > 0).toBeTruthy();\n      expect(extendedLastEventTime > eventTime1).toBeTruthy();\n\n      // send another event just before session expires (again)\n      // Mock Date.now() because isNewSession() depends on it\n      const dateNowMocked = jest.spyOn(Date, 'now').mockImplementation(() => extendedLastEventTime + 15);\n      await new Promise<void>((resolve) =>\n        // eslint-disable-next-line @typescript-eslint/no-misused-promises\n        setTimeout(async () => {\n          await client.track('test 2').promise;\n          resolve();\n        }, 10),\n      );\n      dateNowMocked.mockRestore();\n\n      // assert session id is unchanged\n      expect(client.config.sessionId).toBe(firstSessionId);\n      // assert last event time was updated\n      const eventTime2 = client.config.lastEventTime ?? -1;\n      expect(eventTime2 > 0).toBeTruthy();\n      expect(eventTime2 > extendedLastEventTime).toBeTruthy();\n\n      // Wait for session to timeout, without extendSession()\n      await new Promise<void>((resolve) =>\n        // eslint-disable-next-line @typescript-eslint/no-misused-promises\n        setTimeout(async () => {\n          await client.track('test 3').promise;\n          resolve();\n        }, 21),\n      );\n      // assert session id is changed\n      expect(client.config.sessionId).not.toBe(firstSessionId);\n      expect(client.config.sessionId ?? -1 > firstSessionId).toBeTruthy();\n    });\n\n    test('should extend session using proxy', async () => {\n      const lastEventTime = Date.now() - 1000;\n      jest.spyOn(CookieMigration, 'parseLegacyCookies').mockResolvedValueOnce({\n        optOut: false,\n        sessionId: 1,\n        lastEventTime: lastEventTime,\n      });\n\n      const client = new AmplitudeBrowser();\n\n      // call extendSession() before init()\n      client.extendSession();\n\n      // init\n      await client.init(apiKey, {\n        sessionTimeout: 20,\n        flushQueueSize: 1,\n        flushIntervalMillis: 1,\n        defaultTracking,\n      }).promise;\n\n      // assert sessionId is unchanged\n      expect(client.config.sessionId).toBe(1);\n      // assert last event time was updated\n      expect(client.config.lastEventTime).not.toBe(lastEventTime);\n    });\n\n    /**\n     * Tests the reverse case of calling expire sessions\n     */\n    test('should expire session w/o calling extend session using proxy', async () => {\n      const lastEventTime = Date.now() - 1000;\n      jest.spyOn(CookieMigration, 'parseLegacyCookies').mockResolvedValueOnce({\n        optOut: false,\n        sessionId: 1,\n        lastEventTime: lastEventTime,\n      });\n\n      const client = new AmplitudeBrowser();\n\n      // init\n      await client.init(apiKey, {\n        sessionTimeout: 20,\n        flushQueueSize: 1,\n        flushIntervalMillis: 1,\n        defaultTracking,\n      }).promise;\n\n      // assert sessionId is unchanged\n      expect(client.config.sessionId).toBe(1);\n      // assert last event time was updated\n      expect(client.config.lastEventTime).toBe(lastEventTime);\n    });\n  });\n\n  describe('pageCount', () => {\n    test('init pageCounter should be 0', async () => {\n      await client.init(apiKey, { defaultTracking }).promise;\n      expect(client.config.pageCounter).toBe(0);\n    });\n\n    test('should set pageCounter to 0 in new session', async () => {\n      await client.init(apiKey, { defaultTracking }).promise;\n      client.config.pageCounter = 2;\n      expect(client.config.pageCounter).toBe(2);\n      client.setSessionId(Date.now() + 5 * 60 * 60);\n      expect(client.config.pageCounter).toBe(0);\n    });\n  });\n\n  describe('setTransport', () => {\n    test('should set transport', async () => {\n      const fetch = new FetchTransport();\n      const createTransport = jest.spyOn(Config, 'createTransport').mockReturnValueOnce(fetch);\n      await client.init(apiKey, { defaultTracking }).promise;\n      client.setTransport('fetch');\n      expect(createTransport).toHaveBeenCalledTimes(2);\n    });\n\n    test('should keep compression enabled for default endpoints when switching transport', async () => {\n      const createTransport = jest.spyOn(Config, 'createTransport');\n      await client.init(apiKey, { defaultTracking }).promise;\n\n      createTransport.mockClear();\n      client.setTransport('xhr');\n\n      expect(createTransport).toHaveBeenCalledWith('xhr');\n    });\n\n    test('should keep custom endpoint compression setting when switching transport', async () => {\n      const createTransport = jest.spyOn(Config, 'createTransport');\n      await client.init(apiKey, {\n        defaultTracking,\n        serverUrl: 'https://custom.example.com/2/httpapi',\n        enableRequestBodyCompression: false,\n      }).promise;\n\n      createTransport.mockClear();\n      client.setTransport('xhr');\n\n      expect(createTransport).toHaveBeenCalledWith('xhr');\n    });\n\n    test('should defer set transport', () => {\n      return new Promise<void>((resolve) => {\n        const fetch = new FetchTransport();\n        const createTransport = jest.spyOn(Config, 'createTransport').mockReturnValueOnce(fetch);\n        void client.init(apiKey, { defaultTracking }).promise.then(() => {\n          expect(createTransport).toHaveBeenCalledTimes(2);\n          resolve();\n        });\n        client.setTransport('fetch');\n      });\n    });\n  });\n\n  describe('identify', () => {\n    test('should track identify', async () => {\n      const track = jest.spyOn(client, 'dispatch').mockReturnValueOnce(\n        Promise.resolve({\n          code: 200,\n          message: '',\n          event: {\n            event_type: 'event_type',\n          },\n        }),\n      );\n      await client.init(apiKey, {\n        defaultTracking,\n      }).promise;\n      const identifyObject = new core.Identify();\n      const result = await client.identify(identifyObject, { user_id: '123', device_id: '123' }).promise;\n      expect(result.code).toEqual(200);\n      expect(track).toHaveBeenCalledTimes(1);\n    });\n\n    test('should track identify using proxy', async () => {\n      const track = jest.spyOn(client, 'dispatch').mockReturnValueOnce(\n        Promise.resolve({\n          code: 200,\n          message: '',\n          event: {\n            event_type: 'event_type',\n          },\n        }),\n      );\n      const convertProxyObjectToRealObject = jest\n        .spyOn(SnippetHelper, 'convertProxyObjectToRealObject')\n        .mockReturnValueOnce(new core.Identify());\n      await client.init(apiKey, {\n        defaultTracking,\n      }).promise;\n      const identifyObject = {\n        _q: [],\n      };\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore to verify behavior in snippet installation\n      const result = await client.identify(identifyObject).promise;\n      expect(result.code).toEqual(200);\n      expect(track).toHaveBeenCalledTimes(1);\n      expect(convertProxyObjectToRealObject).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('groupIdentify', () => {\n    test('should track group identify', async () => {\n      const track = jest.spyOn(client, 'dispatch').mockReturnValueOnce(\n        Promise.resolve({\n          code: 200,\n          message: '',\n          event: {\n            event_type: 'event_type',\n          },\n        }),\n      );\n      await client.init(apiKey, {\n        defaultTracking,\n      }).promise;\n      const identifyObject = new core.Identify();\n      const result = await client.groupIdentify('g', '1', identifyObject).promise;\n      expect(result.code).toEqual(200);\n      expect(track).toHaveBeenCalledTimes(1);\n    });\n\n    test('should track group identify using proxy', async () => {\n      const track = jest.spyOn(client, 'dispatch').mockReturnValueOnce(\n        Promise.resolve({\n          code: 200,\n          message: '',\n          event: {\n            event_type: 'event_type',\n          },\n        }),\n      );\n      const convertProxyObjectToRealObject = jest\n        .spyOn(SnippetHelper, 'convertProxyObjectToRealObject')\n        .mockReturnValueOnce(new core.Identify());\n      await client.init(apiKey, {\n        defaultTracking,\n      }).promise;\n      const identifyObject = {\n        _q: [],\n      };\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore to verify behavior in snippet installation\n      const result = await client.groupIdentify('g', '1', identifyObject).promise;\n      expect(result.code).toEqual(200);\n      expect(track).toHaveBeenCalledTimes(1);\n      expect(convertProxyObjectToRealObject).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('revenue', () => {\n    test('should track revenue', async () => {\n      const track = jest.spyOn(client, 'dispatch').mockReturnValueOnce(\n        Promise.resolve({\n          code: 200,\n          message: '',\n          event: {\n            event_type: 'event_type',\n          },\n        }),\n      );\n      await client.init(apiKey, {\n        defaultTracking,\n      }).promise;\n      const revenueObject = new core.Revenue();\n      const result = await client.revenue(revenueObject).promise;\n      expect(result.code).toEqual(200);\n      expect(track).toHaveBeenCalledTimes(1);\n    });\n\n    test('should track revenue using proxy', async () => {\n      const track = jest.spyOn(client, 'dispatch').mockReturnValueOnce(\n        Promise.resolve({\n          code: 200,\n          message: '',\n          event: {\n            event_type: 'event_type',\n          },\n        }),\n      );\n      const convertProxyObjectToRealObject = jest\n        .spyOn(SnippetHelper, 'convertProxyObjectToRealObject')\n        .mockReturnValueOnce(new core.Revenue());\n      await client.init(apiKey, {\n        defaultTracking,\n      }).promise;\n      const revenueObject = {\n        _q: [],\n      };\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore to verify behavior in snippet installation\n      const result = await client.revenue(revenueObject).promise;\n      expect(result.code).toEqual(200);\n      expect(track).toHaveBeenCalledTimes(1);\n      expect(convertProxyObjectToRealObject).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('process', () => {\n    test('should process create new session for new campain', async () => {\n      await client.init(apiKey, {\n        optOut: true,\n        logLevel: LogLevel.Warn,\n        defaultTracking: {\n          attribution: {\n            resetSessionOnNewCampaign: true,\n          },\n        },\n      }).promise;\n\n      expect(client.webAttribution).toBeDefined();\n\n      // Making sure client.webAttribution is not undefined\n      if (!client.webAttribution) {\n        client.webAttribution = new WebAttribution({}, client.config);\n      }\n      jest.spyOn(client.webAttribution, 'shouldSetSessionIdOnNewCampaign').mockReturnValueOnce(true);\n      const logSpy = jest.spyOn(client.config.loggerProvider, 'log');\n\n      await client.process({\n        event_type: 'event',\n      });\n\n      expect(logSpy).toHaveBeenCalledWith('Created a new session for new campaign.');\n    });\n    test('should track web attribution if change in campaign information', async () => {\n      const track = jest.spyOn(client, 'dispatch').mockReturnValue(\n        Promise.resolve({\n          code: 200,\n          message: '',\n          event: {\n            event_type: 'event_type',\n          },\n        }),\n      );\n      await client.init(apiKey, {\n        optOut: true,\n        logLevel: LogLevel.Warn,\n        defaultTracking: {\n          attribution: {\n            resetSessionOnNewCampaign: true,\n          },\n        },\n      }).promise;\n\n      client.webAttribution = new WebAttribution({}, { ...client.config, lastEventTime: undefined });\n      client.webAttribution.shouldTrackNewCampaign = true;\n      jest.spyOn(core, 'isNewSession').mockReturnValueOnce(false);\n      await client.process({\n        event_type: 'event',\n      });\n      expect(track).toHaveBeenCalled();\n    });\n\n    test('should proceed with unexpired session', async () => {\n      const setSessionId = jest.spyOn(client, 'setSessionId');\n      await client.init(apiKey, {\n        optOut: true,\n        defaultTracking: false,\n      }).promise;\n      const result = await client.process({\n        event_type: 'event',\n      });\n      // once on init\n      expect(setSessionId).toHaveBeenCalledTimes(1);\n      expect(result.code).toBe(0);\n    });\n\n    test('should proceed with overriden session ID', async () => {\n      const setSessionId = jest.spyOn(client, 'setSessionId');\n      await client.init(apiKey, {\n        optOut: true,\n        defaultTracking: false,\n      }).promise;\n      const result = await client.process({\n        event_type: 'event',\n        session_id: -1,\n      });\n      // once on init\n      expect(setSessionId).toHaveBeenCalledTimes(1);\n      expect(result.code).toBe(0);\n    });\n\n    test('should reset session due to expired session', async () => {\n      const setSessionId = jest.spyOn(client, 'setSessionId');\n      await client.init(apiKey, {\n        optOut: true,\n        defaultTracking: false,\n        // force session to always be expired\n        sessionTimeout: -1,\n      }).promise;\n      const result = await client.process({\n        event_type: 'event',\n      });\n      // once on init\n      // and once on process\n      expect(setSessionId).toHaveBeenCalledTimes(2);\n      expect(result.code).toBe(0);\n    });\n  });\n\n  describe('debug logs through cookie', () => {\n    test('debug logs should be persisted across page loads', async () => {\n      const cookieStorage = new CookieStorage<UserSession>();\n      const cookie: UserSession = {\n        deviceId: '123',\n        userId: '123',\n        sessionId: 123,\n        lastEventTime: Date.now(),\n        optOut: false,\n        debugLogsEnabled: true,\n      };\n      await cookieStorage.set(getCookieName(apiKey), cookie);\n\n      const loggerProvider = {\n        log: jest.fn(),\n        debug: jest.fn(),\n        warn: jest.fn(),\n        error: jest.fn(),\n        enable: jest.fn(),\n        disable: jest.fn(),\n      };\n\n      await client.init(apiKey, {\n        defaultTracking,\n        logLevel: LogLevel.Error,\n        loggerProvider: loggerProvider,\n      }).promise;\n\n      expect(loggerProvider.enable).toHaveBeenCalledWith(LogLevel.Debug);\n      console.log(loggerProvider.enable.mock.calls);\n      expect(loggerProvider.enable).toHaveBeenCalledTimes(1);\n    });\n\n    test('debug logs should not be enabled by default', async () => {\n      const cookieStorage = new CookieStorage<UserSession>();\n      const cookie: UserSession = {\n        deviceId: '123',\n        userId: '123',\n        sessionId: 123,\n        lastEventTime: Date.now(),\n        optOut: false,\n      };\n      await cookieStorage.set(getCookieName(apiKey), cookie);\n\n      const loggerProvider = {\n        log: jest.fn(),\n        debug: jest.fn(),\n        warn: jest.fn(),\n        error: jest.fn(),\n        enable: jest.fn(),\n        disable: jest.fn(),\n      };\n\n      await client.init(apiKey, {\n        defaultTracking,\n        logLevel: LogLevel.Error,\n        loggerProvider: loggerProvider,\n      }).promise;\n\n      expect(loggerProvider.enable).toHaveBeenCalledWith(LogLevel.Error);\n    });\n  });\n\n  describe('_setDiagnosticsSampleRate', () => {\n    test('should set diagnostics sample rate when config is not initialized', () => {\n      expect(client._diagnosticsSampleRate).toBe(0);\n      const sampleRate = 0.1;\n\n      client._setDiagnosticsSampleRate(sampleRate);\n\n      expect(client._diagnosticsSampleRate).toBe(sampleRate);\n    });\n\n    test('should not set diagnostics sample rate when config is already initialized', async () => {\n      expect(client._diagnosticsSampleRate).toBe(0);\n      await client.init(apiKey).promise;\n\n      const initialSampleRate = client._diagnosticsSampleRate;\n      const newSampleRate = 0.5;\n\n      client._setDiagnosticsSampleRate(newSampleRate);\n\n      // Should not change the sample rate when config is already initialized\n      expect(client._diagnosticsSampleRate).toBe(initialSampleRate);\n    });\n\n    test('should early return when diagnostics sample rate is not between 0 and 1', () => {\n      expect(client._diagnosticsSampleRate).toBe(0);\n      const sampleRate = 1.1;\n\n      client._setDiagnosticsSampleRate(sampleRate);\n\n      expect(client._diagnosticsSampleRate).toBe(0);\n    });\n  });\n\n  describe('logBrowserOptions', () => {\n    test('should not throw error on circular reference', async () => {\n      // regression test for https://github.com/amplitude/Amplitude-TypeScript/issues/1521\n      const logBrowserOptions = AmplitudeBrowser.prototype['logBrowserOptions'];\n      const circularReference: any = { a: undefined };\n      circularReference.a = circularReference;\n      const ctx = {\n        config: {\n          loggerProvider: {\n            debug: jest.fn(),\n            error: jest.fn(),\n          },\n        },\n      };\n      const apiKey = '1234567890';\n      logBrowserOptions.call(ctx, { apiKey, ...circularReference });\n      expect(ctx.config.loggerProvider.debug.mock.calls[0][1]).toContain(apiKey.substring(0, 5));\n      expect(ctx.config.loggerProvider.error).not.toHaveBeenCalled();\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-browser/test/config/joined-config.test.ts",
    "content": "import { translateRemoteConfigToLocal, updateBrowserConfigWithRemoteConfig } from '../../src/config/joined-config';\nimport { createConfigurationMock } from '../helpers/mock';\nimport {\n  AutocaptureOptions,\n  NetworkTrackingOptions,\n  SAFE_HEADERS,\n  type BrowserConfig,\n  type ElementInteractionsOptions,\n} from '@amplitude/analytics-core';\n\nfunction expectIsAutocaptureObjectWithElementInteractions(config: BrowserConfig): asserts config is BrowserConfig & {\n  autocapture: BrowserConfig['autocapture'] & { elementInteractions: ElementInteractionsOptions };\n} {\n  expect(config).toHaveProperty('autocapture');\n  expect(config.autocapture).toHaveProperty('elementInteractions');\n}\n\ndescribe('joined-config', () => {\n  let localConfig: BrowserConfig;\n\n  beforeEach(() => {\n    localConfig = { ...createConfigurationMock(), defaultTracking: false, autocapture: false };\n  });\n\n  describe('updateBrowserConfigWithRemoteConfig', () => {\n    test('should not modify local config if remote config is null', () => {\n      const originalConfig = { ...localConfig };\n      updateBrowserConfigWithRemoteConfig(null, localConfig);\n      expect(localConfig).toEqual(originalConfig);\n    });\n\n    test('should disable elementInteractions if remote config sets it to false', () => {\n      localConfig = createConfigurationMock(\n        createConfigurationMock({\n          autocapture: true,\n        }),\n      );\n\n      const remoteConfig = {\n        autocapture: {\n          elementInteractions: false,\n        },\n      };\n\n      const expectedAutocapture = {\n        sessions: true,\n        fileDownloads: true,\n        formInteractions: true,\n        pageViews: true,\n        attribution: true,\n        elementInteractions: false,\n        frustrationInteractions: true,\n        webVitals: true,\n      };\n\n      updateBrowserConfigWithRemoteConfig(remoteConfig, localConfig);\n      expect(localConfig.autocapture).toStrictEqual(expectedAutocapture);\n      expect(localConfig.defaultTracking).toStrictEqual(expectedAutocapture);\n    });\n\n    test('should disable defaultTracking if remote config sets it to false', () => {\n      localConfig = createConfigurationMock(\n        createConfigurationMock({\n          autocapture: true,\n          defaultTracking: true,\n        }),\n      );\n\n      const remoteConfig = {\n        autocapture: {\n          fileDownloads: false,\n          formInteractions: false,\n          pageViews: false,\n          attribution: false,\n          sessions: false,\n        },\n      };\n\n      const expectedAutocapture = {\n        fileDownloads: false,\n        formInteractions: false,\n        pageViews: false,\n        attribution: false,\n        sessions: false,\n        elementInteractions: true,\n        frustrationInteractions: true,\n        webVitals: true,\n      };\n\n      updateBrowserConfigWithRemoteConfig(remoteConfig, localConfig);\n      expect(localConfig.defaultTracking).toStrictEqual(expectedAutocapture);\n      expect(localConfig.autocapture).toStrictEqual(expectedAutocapture);\n    });\n\n    test.each([\n      {\n        sessions: false,\n        fileDownloads: false,\n        formInteractions: false,\n        attribution: false,\n        pageViews: false,\n        frustrationInteractions: false,\n        webVitals: false,\n      },\n      false,\n    ])('should only enable elementInteractions if remote config only sets it to true', (localAutocapture) => {\n      localConfig = createConfigurationMock(\n        createConfigurationMock({\n          autocapture: localAutocapture,\n        }),\n      );\n\n      const remoteConfig = {\n        autocapture: {\n          elementInteractions: true,\n        },\n      };\n\n      const expectedJoinedConfig = {\n        sessions: false,\n        fileDownloads: false,\n        formInteractions: false,\n        attribution: false,\n        pageViews: false,\n        elementInteractions: true,\n        frustrationInteractions: false,\n        webVitals: false,\n      };\n\n      updateBrowserConfigWithRemoteConfig(remoteConfig, localConfig);\n      expect(localConfig.autocapture).toStrictEqual(expectedJoinedConfig);\n      expect(localConfig.defaultTracking).toStrictEqual(expectedJoinedConfig);\n    });\n\n    test('should use remote autocapture if local autocapture is undefined', () => {\n      localConfig = createConfigurationMock(createConfigurationMock({}));\n\n      const remoteConfig = {\n        autocapture: {\n          elementInteractions: false,\n        },\n      };\n\n      updateBrowserConfigWithRemoteConfig(remoteConfig, localConfig);\n      expect(localConfig.autocapture).toStrictEqual(remoteConfig.autocapture);\n      expect(localConfig.defaultTracking).toStrictEqual(remoteConfig.autocapture);\n    });\n\n    test.each([true, false])(\n      'should overwrite local autocapture if remote autocapture is boolean',\n      (remoteAutocapture) => {\n        localConfig = createConfigurationMock(createConfigurationMock({}));\n\n        const remoteConfig = {\n          autocapture: remoteAutocapture,\n        };\n\n        updateBrowserConfigWithRemoteConfig(remoteConfig, localConfig);\n        expect(localConfig.autocapture).toStrictEqual(remoteAutocapture);\n        expect(localConfig.defaultTracking).toStrictEqual(remoteAutocapture);\n      },\n    );\n\n    test('should handle errors gracefully', () => {\n      const logError = jest.spyOn(localConfig.loggerProvider, 'error');\n\n      // Create a problematic remote config that will cause an error when accessed.\n      // This test is necessary because RemoteConfig uses `any` type for value, allowing external\n      // sources to provide malformed data with getters, functions, or other constructs\n      // that could throw errors.\n      const remoteConfig = {\n        autocapture: {\n          get elementInteractions() {\n            throw new Error('Test error');\n          },\n        },\n      };\n\n      updateBrowserConfigWithRemoteConfig(remoteConfig, localConfig);\n      expect(logError).toHaveBeenCalledWith(\n        'Failed to apply remote configuration because of error: ',\n        expect.any(Error),\n      );\n    });\n\n    test('should merge local and remote config', () => {\n      const remoteConfig = {\n        autocapture: true,\n      };\n\n      updateBrowserConfigWithRemoteConfig(remoteConfig, localConfig);\n      expect(localConfig.autocapture).toBe(true);\n      expect(localConfig.defaultTracking).toBe(true);\n    });\n\n    test('should convert pageUrlAllowlistRegex strings to RegExp objects and combine with pageUrlAllowlist', () => {\n      localConfig = createConfigurationMock(createConfigurationMock({}));\n\n      const remoteConfig = {\n        autocapture: {\n          elementInteractions: {\n            pageUrlAllowlist: ['exact-match.com', 'another-exact-match.com'],\n            pageUrlAllowlistRegex: ['^https://.*\\\\.example\\\\.com$', '.*\\\\.amplitude\\\\.com$'],\n          },\n        },\n      };\n\n      updateBrowserConfigWithRemoteConfig(remoteConfig, localConfig);\n\n      // Verify the combined pageUrlAllowlist contains both exact matches and RegExp objects\n      expectIsAutocaptureObjectWithElementInteractions(localConfig);\n      const elementInteractions = localConfig.autocapture?.elementInteractions;\n\n      const pageUrlAllowlist = elementInteractions.pageUrlAllowlist;\n      expect(Array.isArray(pageUrlAllowlist)).toBe(true);\n      expect(pageUrlAllowlist?.length).toBe(4);\n\n      // First two items should be strings\n      expect(pageUrlAllowlist?.[0]).toBe('exact-match.com');\n      expect(pageUrlAllowlist?.[1]).toBe('another-exact-match.com');\n\n      // Last two items should be RegExp objects\n      expect(pageUrlAllowlist?.[2]).toBeInstanceOf(RegExp);\n      expect(pageUrlAllowlist?.[3]).toBeInstanceOf(RegExp);\n      expect(pageUrlAllowlist?.[2].toString()).toBe(new RegExp('^https://.*\\\\.example\\\\.com$').toString());\n      expect(pageUrlAllowlist?.[3].toString()).toBe(new RegExp('.*\\\\.amplitude\\\\.com$').toString());\n\n      // pageUrlAllowlistRegex should have been removed\n      expect(elementInteractions).not.toHaveProperty('pageUrlAllowlistRegex');\n    });\n\n    test('should handle empty pageUrlAllowlist when pageUrlAllowlistRegex is provided', () => {\n      localConfig = createConfigurationMock(createConfigurationMock({}));\n\n      const remoteConfig = {\n        autocapture: {\n          elementInteractions: {\n            pageUrlAllowlistRegex: ['^https://.*\\\\.example\\\\.com$', '.*\\\\.amplitude\\\\.com$'],\n          },\n        },\n      };\n\n      updateBrowserConfigWithRemoteConfig(remoteConfig, localConfig);\n\n      // Verify the pageUrlAllowlist contains only RegExp objects\n      expectIsAutocaptureObjectWithElementInteractions(localConfig);\n      const elementInteractions = localConfig.autocapture?.elementInteractions;\n\n      const pageUrlAllowlist = elementInteractions.pageUrlAllowlist;\n      expect(Array.isArray(pageUrlAllowlist)).toBe(true);\n      expect(pageUrlAllowlist?.length).toBe(2);\n\n      // Both items should be RegExp objects\n      expect(pageUrlAllowlist?.[0]).toBeInstanceOf(RegExp);\n      expect(pageUrlAllowlist?.[1]).toBeInstanceOf(RegExp);\n      expect(pageUrlAllowlist?.[0].toString()).toBe(new RegExp('^https://.*\\\\.example\\\\.com$').toString());\n      expect(pageUrlAllowlist?.[1].toString()).toBe(new RegExp('.*\\\\.amplitude\\\\.com$').toString());\n\n      // pageUrlAllowlistRegex should have been removed\n      expect(elementInteractions).not.toHaveProperty('pageUrlAllowlistRegex');\n    });\n\n    test('should skip and warn on invalid regex patterns', () => {\n      localConfig = createConfigurationMock(createConfigurationMock({}));\n\n      const remoteConfig = {\n        autocapture: {\n          elementInteractions: {\n            pageUrlAllowlistRegex: ['^https://.*\\\\.example\\\\.com$', '***', '.*\\\\.amplitude\\\\.com$'],\n          },\n        },\n      };\n\n      const logWarn = jest.spyOn(localConfig.loggerProvider, 'warn');\n\n      updateBrowserConfigWithRemoteConfig(remoteConfig, localConfig);\n\n      // Verify the pageUrlAllowlist contains only RegExp objects\n      expectIsAutocaptureObjectWithElementInteractions(localConfig);\n      const elementInteractions = localConfig.autocapture?.elementInteractions;\n\n      const pageUrlAllowlist = elementInteractions.pageUrlAllowlist;\n      expect(Array.isArray(pageUrlAllowlist)).toBe(true);\n      expect(pageUrlAllowlist?.length).toBe(2);\n\n      // Both items should be RegExp objects\n      expect(pageUrlAllowlist?.[0]).toBeInstanceOf(RegExp);\n      expect(pageUrlAllowlist?.[1]).toBeInstanceOf(RegExp);\n      expect(pageUrlAllowlist?.[0].toString()).toBe(new RegExp('^https://.*\\\\.example\\\\.com$').toString());\n      expect(pageUrlAllowlist?.[1].toString()).toBe(new RegExp('.*\\\\.amplitude\\\\.com$').toString());\n\n      // pageUrlAllowlistRegex should have been removed\n      expect(elementInteractions).not.toHaveProperty('pageUrlAllowlistRegex');\n\n      expect(logWarn).toHaveBeenCalledWith('Invalid regex pattern: ***', expect.any(Error));\n    });\n\n    test('should not fail or override pageUrlAllowlist when pageUrlAllowlistRegex is undefined', () => {\n      localConfig = createConfigurationMock({});\n\n      // Define the remote configuration with an existing exact match allowlist and pageUrlAllowlistRegex as undefined\n      const remoteConfig = {\n        autocapture: {\n          elementInteractions: {\n            pageUrlAllowlist: ['existing-domain.com', 'another-domain.net'],\n          },\n        },\n      };\n\n      updateBrowserConfigWithRemoteConfig(remoteConfig, localConfig);\n\n      // Assert: Verify that the original pageUrlAllowlist remains unchanged\n      // Ensure the autocapture and elementInteractions objects exist in the joined config\n      expectIsAutocaptureObjectWithElementInteractions(localConfig);\n      const elementInteractions = localConfig.autocapture?.elementInteractions;\n      expect(elementInteractions).toBeDefined();\n\n      const pageUrlAllowlist = elementInteractions.pageUrlAllowlist;\n      expect(Array.isArray(pageUrlAllowlist)).toBe(true);\n      // Expect the list to have the original exact match strings\n      expect(pageUrlAllowlist?.length).toBe(2);\n\n      // Verify that the elements in the allowlist are the original strings\n      expect(pageUrlAllowlist?.[0]).toBe('existing-domain.com');\n      expect(pageUrlAllowlist?.[1]).toBe('another-domain.net');\n\n      // Assert: Verify that the pageUrlAllowlistRegex property has been removed (even if it was undefined)\n      expect(elementInteractions).not.toHaveProperty('pageUrlAllowlistRegex');\n    });\n\n    describe('networkTracking', () => {\n      describe('headers', () => {\n        test('should translate responseHeaders and requestHeaders to local responseHeaders and requestHeaders', () => {\n          localConfig = createConfigurationMock(createConfigurationMock({}));\n\n          const remoteConfig = {\n            autocapture: {\n              networkTracking: {\n                captureRules: [\n                  {\n                    responseHeaders: {\n                      captureSafeHeaders: true,\n                      allowlist: ['content-type', 'x-fake-response-header'],\n                    },\n                    requestHeaders: {\n                      captureSafeHeaders: true,\n                      allowlist: ['content-type', 'x-fake-request-header'],\n                    },\n                  },\n                ],\n              },\n            },\n          };\n\n          updateBrowserConfigWithRemoteConfig(remoteConfig, localConfig);\n\n          const autocapture = localConfig.autocapture as AutocaptureOptions;\n          const networkTracking = autocapture.networkTracking as NetworkTrackingOptions;\n          expect(networkTracking?.captureRules?.[0].responseHeaders).toEqual([\n            ...SAFE_HEADERS,\n            'content-type',\n            'x-fake-response-header',\n          ]);\n          expect(networkTracking?.captureRules?.[0].requestHeaders).toEqual([\n            ...SAFE_HEADERS,\n            'content-type',\n            'x-fake-request-header',\n          ]);\n        });\n\n        test('should translate captureSafeHeaders to local captureSafeHeaders', () => {\n          localConfig = createConfigurationMock(createConfigurationMock({}));\n\n          const remoteConfig = {\n            autocapture: {\n              networkTracking: {\n                captureRules: [\n                  { responseHeaders: { captureSafeHeaders: true }, requestHeaders: { captureSafeHeaders: true } },\n                ],\n              },\n            },\n          };\n\n          updateBrowserConfigWithRemoteConfig(remoteConfig, localConfig);\n\n          const autocapture = localConfig.autocapture as AutocaptureOptions;\n          const networkTracking = autocapture.networkTracking as NetworkTrackingOptions;\n          expect(networkTracking?.captureRules?.[0].responseHeaders).toEqual([...SAFE_HEADERS]);\n          expect(networkTracking?.captureRules?.[0].requestHeaders).toEqual([...SAFE_HEADERS]);\n        });\n\n        test('should translate allowlist to local allowlist', () => {\n          localConfig = createConfigurationMock(createConfigurationMock({}));\n\n          const remoteConfig = {\n            autocapture: {\n              networkTracking: {\n                captureRules: [\n                  {\n                    responseHeaders: { allowlist: ['content-type', 'x-fake-response-header'] },\n                    requestHeaders: { allowlist: ['content-type', 'x-fake-request-header'] },\n                  },\n                ],\n              },\n            },\n          };\n\n          updateBrowserConfigWithRemoteConfig(remoteConfig, localConfig);\n\n          const autocapture = localConfig.autocapture as AutocaptureOptions;\n          const networkTracking = autocapture.networkTracking as NetworkTrackingOptions;\n          expect(networkTracking?.captureRules?.[0].responseHeaders).toEqual([\n            'content-type',\n            'x-fake-response-header',\n          ]);\n          expect(networkTracking?.captureRules?.[0].requestHeaders).toEqual(['content-type', 'x-fake-request-header']);\n        });\n\n        test('if undefined, should not translate', () => {\n          localConfig = createConfigurationMock(createConfigurationMock({}));\n\n          const remoteConfig = {\n            autocapture: {\n              networkTracking: { captureRules: [{ responseHeaders: undefined, requestHeaders: undefined }] },\n            },\n          };\n\n          updateBrowserConfigWithRemoteConfig(remoteConfig, localConfig);\n\n          const autocapture = localConfig.autocapture as AutocaptureOptions;\n          const networkTracking = autocapture.networkTracking as NetworkTrackingOptions;\n          expect(networkTracking?.captureRules?.[0].responseHeaders).toBeUndefined();\n          expect(networkTracking?.captureRules?.[0].requestHeaders).toBeUndefined();\n        });\n\n        test('should not fail if headers are malformed', () => {\n          localConfig = createConfigurationMock(createConfigurationMock({}));\n\n          const remoteConfig = {\n            autocapture: { networkTracking: { captureRules: [{ responseHeaders: { allowlist: { wrong: 'type' } } }] } },\n          };\n\n          updateBrowserConfigWithRemoteConfig(remoteConfig, localConfig);\n\n          const autocapture = localConfig.autocapture as AutocaptureOptions;\n          const networkTracking = autocapture.networkTracking as NetworkTrackingOptions;\n          expect(networkTracking?.captureRules?.[0].responseHeaders).toBeUndefined();\n          expect(networkTracking?.captureRules?.[0].requestHeaders).toBeUndefined();\n        });\n      });\n\n      test('should merge urls and urlsRegex', () => {\n        localConfig = createConfigurationMock(createConfigurationMock({}));\n\n        const remoteConfig = {\n          autocapture: {\n            networkTracking: {\n              captureRules: [\n                {\n                  urls: ['https://example.com/path', /path\\/to/],\n                  urlsRegex: ['^https://.*\\\\.example\\\\.com$', '.*\\\\.amplitude\\\\.com$'],\n                },\n              ],\n            },\n          },\n        };\n\n        updateBrowserConfigWithRemoteConfig(remoteConfig, localConfig);\n\n        const autocapture = localConfig.autocapture as AutocaptureOptions;\n        const networkTracking = autocapture.networkTracking as NetworkTrackingOptions;\n        expect(networkTracking?.captureRules?.[0].urls).toEqual([\n          'https://example.com/path',\n          /path\\/to/,\n          /^https:\\/\\/.*\\.example\\.com$/,\n          /.*\\.amplitude\\.com$/,\n        ]);\n      });\n\n      test('should merge urls if urlsRegex is undefined', () => {\n        localConfig = createConfigurationMock(createConfigurationMock({}));\n\n        const remoteConfig = {\n          autocapture: {\n            networkTracking: {\n              captureRules: [{ urls: ['https://example.com/path', /path\\/to/] }],\n            },\n          },\n        };\n\n        updateBrowserConfigWithRemoteConfig(remoteConfig, localConfig);\n\n        const autocapture = localConfig.autocapture as AutocaptureOptions;\n        const networkTracking = autocapture.networkTracking as NetworkTrackingOptions;\n        expect(networkTracking?.captureRules?.[0].urls).toEqual(['https://example.com/path', /path\\/to/]);\n      });\n\n      test('should merge urls if urls is undefined and urlsRegex is provided', () => {\n        localConfig = createConfigurationMock(createConfigurationMock({}));\n\n        const remoteConfig = {\n          autocapture: {\n            networkTracking: {\n              captureRules: [{ urlsRegex: ['^https://.*\\\\.example\\\\.com$', '.*\\\\.amplitude\\\\.com$'] }],\n            },\n          },\n        };\n\n        updateBrowserConfigWithRemoteConfig(remoteConfig, localConfig);\n\n        const autocapture = localConfig.autocapture as AutocaptureOptions;\n        const networkTracking = autocapture.networkTracking as NetworkTrackingOptions;\n        expect(networkTracking?.captureRules?.[0].urls).toEqual([\n          /^https:\\/\\/.*\\.example\\.com$/,\n          /.*\\.amplitude\\.com$/,\n        ]);\n      });\n\n      test('should not have urls if captureRules is undefined', () => {\n        localConfig = createConfigurationMock(createConfigurationMock({}));\n\n        const remoteConfig = {\n          autocapture: {\n            networkTracking: {},\n          },\n        };\n\n        updateBrowserConfigWithRemoteConfig(remoteConfig, localConfig);\n\n        const autocapture = localConfig.autocapture as AutocaptureOptions;\n        const networkTracking = autocapture.networkTracking as NetworkTrackingOptions;\n        expect(networkTracking?.captureRules).toBeUndefined();\n      });\n    });\n\n    describe('customEnrichment', () => {\n      test('should merge customEnrichment from remote config when enabled', () => {\n        const remoteConfig = {\n          customEnrichment: { enabled: true, body: 'return event;' },\n        };\n\n        updateBrowserConfigWithRemoteConfig(remoteConfig, localConfig);\n        expect(localConfig.customEnrichment).toStrictEqual({ body: 'return event;' });\n      });\n\n      test('should set customEnrichment to false when remote config disables it', () => {\n        localConfig.customEnrichment = { enabled: true, body: 'return event;' };\n\n        const remoteConfig = {\n          customEnrichment: { enabled: false, body: 'return event;' },\n        };\n\n        updateBrowserConfigWithRemoteConfig(remoteConfig, localConfig);\n        expect(localConfig.customEnrichment).toBe(false);\n      });\n\n      test('should not modify customEnrichment if remote config does not include it', () => {\n        localConfig.customEnrichment = { enabled: true, body: 'return event;' };\n\n        const remoteConfig = {\n          autocapture: true,\n        };\n\n        updateBrowserConfigWithRemoteConfig(remoteConfig, localConfig);\n        expect(localConfig.customEnrichment).toStrictEqual({ enabled: true, body: 'return event;' });\n      });\n\n      test('should set customEnrichment to true when remote config has enabled-only', () => {\n        const remoteConfig = {\n          customEnrichment: { enabled: true },\n        };\n\n        updateBrowserConfigWithRemoteConfig(remoteConfig, localConfig);\n        expect(localConfig.customEnrichment).toBe(true);\n      });\n\n      test('should not override customEnrichment when locally set to false', () => {\n        localConfig.customEnrichment = false;\n\n        const remoteConfig = {\n          customEnrichment: { enabled: true, body: 'return event;' },\n        };\n\n        updateBrowserConfigWithRemoteConfig(remoteConfig, localConfig);\n        expect(localConfig.customEnrichment).toBe(false);\n      });\n\n      test('should not modify customEnrichment when remote config delivers null', () => {\n        localConfig.customEnrichment = { enabled: true, body: 'return event;' };\n\n        const remoteConfig = {\n          customEnrichment: null,\n        };\n\n        updateBrowserConfigWithRemoteConfig(remoteConfig as any, localConfig);\n        expect(localConfig.customEnrichment).toStrictEqual({ enabled: true, body: 'return event;' });\n      });\n    });\n  });\n\n  describe('translateRemoteConfigToLocal', () => {\n    describe('should translate property to true when', () => {\n      test('enabled is true and object has no other properties', () => {\n        const remoteConfig = {\n          browserSDK: {\n            autocapture: {\n              frustrationInteractions: {\n                enabled: true,\n              },\n            },\n          },\n        };\n        translateRemoteConfigToLocal(remoteConfig);\n        expect(remoteConfig.browserSDK.autocapture.frustrationInteractions).toBe(true);\n      });\n    });\n    describe('should translate property to false when', () => {\n      test('enabled is false and object has no other properties', () => {\n        const remoteConfig = {\n          browserSDK: {\n            autocapture: {\n              frustrationInteractions: {\n                enabled: false,\n              },\n            },\n          },\n        };\n        translateRemoteConfigToLocal(remoteConfig);\n        expect(remoteConfig.browserSDK.autocapture.frustrationInteractions).toBe(false);\n      });\n      test('enabled is false and object has other properties', () => {\n        const remoteConfig = {\n          browserSDK: {\n            autocapture: {\n              frustrationInteractions: {\n                enabled: false,\n                deadClicks: true,\n                rageClicks: true,\n              },\n            },\n          },\n        };\n        translateRemoteConfigToLocal(remoteConfig);\n        expect(remoteConfig.browserSDK.autocapture.frustrationInteractions).toBe(false);\n      });\n    });\n    describe('should translate property to object when', () => {\n      test('enabled is true and object has other properties', () => {\n        const remoteConfig = {\n          browserSDK: {\n            autocapture: {\n              frustrationInteractions: {\n                enabled: true,\n                deadClicks: true,\n                rageClicks: true,\n              },\n            },\n          },\n        };\n        translateRemoteConfigToLocal(remoteConfig);\n        expect(remoteConfig.browserSDK.autocapture.frustrationInteractions).toEqual({\n          deadClicks: true,\n          rageClicks: true,\n        });\n      });\n    });\n    describe('should not translate property when', () => {\n      test('property is an array', () => {\n        const config = ['a', 'b', 'c'];\n        translateRemoteConfigToLocal(config);\n        expect(config).toEqual(['a', 'b', 'c']);\n      });\n      test('config is null', () => {\n        const config = null;\n        /* eslint-disable-next-line @typescript-eslint/no-unsafe-argument */\n        translateRemoteConfigToLocal(config as any);\n        expect(config).toBeNull();\n      });\n      test('enabled is not present', () => {\n        const config = { prop: { subprop: { hello: true, foobar: null } } };\n        translateRemoteConfigToLocal(config);\n        expect(config).toEqual({ prop: { subprop: { hello: true, foobar: null } } });\n      });\n      test('property is null', () => {\n        const config = { hello: null };\n        translateRemoteConfigToLocal(config);\n        expect(config).toEqual({ hello: null });\n      });\n      test('property is a boolean', () => {\n        const config = { hello: true };\n        translateRemoteConfigToLocal(config);\n        expect(config).toEqual({ hello: true });\n      });\n    });\n    describe('frustrationInteractions', () => {\n      test('should translate rageClick to rageClicks', () => {\n        const remoteConfig = {\n          browserSDK: {\n            autocapture: {\n              frustrationInteractions: { rageClick: true },\n            },\n          },\n        };\n        translateRemoteConfigToLocal(remoteConfig);\n        expect(remoteConfig.browserSDK.autocapture.frustrationInteractions).toEqual({ rageClicks: true });\n      });\n\n      test('should translate deadClick to deadClicks', () => {\n        const remoteConfig = {\n          browserSDK: {\n            autocapture: {\n              frustrationInteractions: { deadClick: true },\n            },\n          },\n        };\n        translateRemoteConfigToLocal(remoteConfig);\n        expect(remoteConfig.browserSDK.autocapture.frustrationInteractions).toEqual({ deadClicks: true });\n      });\n    });\n\n    describe('viewportContentUpdated', () => {\n      describe('enabled normalization', () => {\n        test('should convert viewportContentUpdated: true to an empty object', () => {\n          // { enabled: true } with no other props collapses to the boolean `true` by the generic\n          // pass; this block converts it back to {} so the SDK gets a VCU options object.\n          const config = {\n            autocapture: {\n              elementInteractions: {\n                viewportContentUpdated: true,\n              },\n            },\n          };\n          translateRemoteConfigToLocal(config);\n          expect(config.autocapture.elementInteractions.viewportContentUpdated).toEqual({});\n        });\n\n        test('should preserve viewportContentUpdated when it is already an object with properties', () => {\n          const config = {\n            autocapture: {\n              elementInteractions: {\n                viewportContentUpdated: { exposureDuration: 200 },\n              },\n            },\n          };\n          translateRemoteConfigToLocal(config);\n          expect(config.autocapture.elementInteractions.viewportContentUpdated).toEqual({ exposureDuration: 200 });\n        });\n\n        test('should convert viewportContentUpdated to { enabled: false } when enabled is false', () => {\n          const config = {\n            autocapture: {\n              elementInteractions: {\n                viewportContentUpdated: { enabled: false, exposureDuration: 200 },\n              },\n            },\n          };\n          translateRemoteConfigToLocal(config);\n          expect(config.autocapture.elementInteractions.viewportContentUpdated).toEqual({ enabled: false });\n        });\n\n        test('should not modify elementInteractions when viewportContentUpdated is absent', () => {\n          const config = {\n            autocapture: {\n              elementInteractions: { cssSelectorAllowlist: ['a'] },\n            },\n          };\n          translateRemoteConfigToLocal(config);\n          expect(config.autocapture.elementInteractions).toEqual({ cssSelectorAllowlist: ['a'] });\n        });\n\n        test('should not throw when elementInteractions is false', () => {\n          const config = {\n            autocapture: {\n              elementInteractions: false,\n            },\n          };\n          translateRemoteConfigToLocal(config);\n          expect(config.autocapture.elementInteractions).toBe(false);\n        });\n\n        test('should not throw when autocapture has no elementInteractions', () => {\n          const config = { autocapture: {} };\n          translateRemoteConfigToLocal(config);\n          expect(config.autocapture).toEqual({});\n        });\n\n        test('should handle errors from elementInteractions accessor gracefully', () => {\n          const config = {\n            autocapture: {\n              get elementInteractions() {\n                throw new Error('accessor error');\n              },\n            },\n          };\n          expect(() => translateRemoteConfigToLocal(config)).not.toThrow();\n        });\n      });\n\n      describe('exposureDuration migration', () => {\n        test('should migrate deprecated top-level exposureDuration to viewportContentUpdated when vcu is absent', () => {\n          const config = {\n            autocapture: {\n              elementInteractions: {\n                exposureDuration: 300,\n              } as any,\n            },\n          };\n          translateRemoteConfigToLocal(config);\n          expect(config.autocapture.elementInteractions.viewportContentUpdated).toEqual({ exposureDuration: 300 });\n          expect(config.autocapture.elementInteractions).not.toHaveProperty('exposureDuration');\n        });\n\n        test('should migrate deprecated top-level exposureDuration to viewportContentUpdated when vcu is true', () => {\n          // After the enabled-normalization pass, viewportContentUpdated may still be `true`\n          // (e.g. { enabled: true } → true) before this migration runs.\n          const config = {\n            autocapture: {\n              elementInteractions: {\n                viewportContentUpdated: true,\n                exposureDuration: 300,\n              } as any,\n            },\n          };\n          translateRemoteConfigToLocal(config);\n          expect(config.autocapture.elementInteractions.viewportContentUpdated).toEqual({ exposureDuration: 300 });\n          expect(config.autocapture.elementInteractions).not.toHaveProperty('exposureDuration');\n        });\n\n        test('should migrate deprecated exposureDuration when viewportContentUpdated object has no exposureDuration', () => {\n          const config = {\n            autocapture: {\n              elementInteractions: {\n                viewportContentUpdated: { exposureDuration: undefined },\n                exposureDuration: 300,\n              } as any,\n            },\n          };\n          translateRemoteConfigToLocal(config);\n          expect(config.autocapture.elementInteractions.viewportContentUpdated).toEqual({ exposureDuration: 300 });\n          expect(config.autocapture.elementInteractions).not.toHaveProperty('exposureDuration');\n        });\n\n        test('should not overwrite existing viewportContentUpdated.exposureDuration with deprecated value', () => {\n          const config = {\n            autocapture: {\n              elementInteractions: {\n                viewportContentUpdated: { exposureDuration: 500 },\n                exposureDuration: 300,\n              } as any,\n            },\n          };\n          translateRemoteConfigToLocal(config);\n          expect(config.autocapture.elementInteractions.viewportContentUpdated).toEqual({ exposureDuration: 500 });\n          expect(config.autocapture.elementInteractions).not.toHaveProperty('exposureDuration');\n        });\n\n        test('should remove deprecated exposureDuration and convert false viewportContentUpdated to { enabled: false }', () => {\n          const config = {\n            autocapture: {\n              elementInteractions: {\n                viewportContentUpdated: false,\n                exposureDuration: 300,\n              } as any,\n            },\n          };\n          translateRemoteConfigToLocal(config);\n          expect(config.autocapture.elementInteractions.viewportContentUpdated).toEqual({ enabled: false });\n          expect(config.autocapture.elementInteractions).not.toHaveProperty('exposureDuration');\n        });\n\n        test('should not touch elementInteractions when exposureDuration is absent', () => {\n          const config = {\n            autocapture: {\n              elementInteractions: {\n                viewportContentUpdated: { exposureDuration: 200 },\n              },\n            },\n          };\n          translateRemoteConfigToLocal(config);\n          expect(config.autocapture.elementInteractions.viewportContentUpdated).toEqual({ exposureDuration: 200 });\n          expect(config.autocapture.elementInteractions).not.toHaveProperty('exposureDuration');\n        });\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-browser/test/config.test.ts",
    "content": "import * as Config from '../src/config';\nimport * as LocalStorageModule from '../src/storage/local-storage';\nimport * as SessionStorageModule from '../src/storage/session-storage';\nimport * as core from '@amplitude/analytics-core';\nimport {\n  LogLevel,\n  Storage,\n  UserSession,\n  MemoryStorage,\n  getCookieName,\n  FetchTransport as CoreFetchTransport,\n  Logger,\n  BrowserConfig,\n} from '@amplitude/analytics-core';\nimport * as BrowserUtils from '@amplitude/analytics-core';\nimport { XHRTransport } from '../src/transports/xhr';\nimport { createTransport, useBrowserConfig, shouldFetchRemoteConfig } from '../src/config';\nimport { FetchTransport } from '../src/transports/fetch';\nimport { SendBeaconTransport } from '../src/transports/send-beacon';\nimport { uuidPattern } from './helpers/constants';\nimport { DEFAULT_IDENTITY_STORAGE, DEFAULT_SERVER_ZONE } from '../src/constants';\nimport { AmplitudeBrowser } from '../src/browser-client';\nimport { VERSION } from '../src/version';\n\ndescribe('config', () => {\n  const someUUID: string = expect.stringMatching(uuidPattern) as string;\n  const someCookieStorage: BrowserUtils.CookieStorage<UserSession> = expect.any(\n    BrowserUtils.CookieStorage,\n  ) as BrowserUtils.CookieStorage<UserSession>;\n  const someLocalStorage: LocalStorageModule.LocalStorage<UserSession> = expect.any(\n    LocalStorageModule.LocalStorage,\n  ) as LocalStorageModule.LocalStorage<UserSession>;\n\n  let apiKey = '';\n\n  beforeEach(() => {\n    apiKey = core.UUID();\n  });\n\n  describe('BrowserConfig', () => {\n    test('should create empty config', async () => {\n      const config = new Config.BrowserConfig(apiKey);\n      expect(config).toMatchObject({\n        _cookieStorage: expect.any(MemoryStorage),\n        _optOut: false,\n        apiKey,\n        appVersion: undefined,\n        cookieOptions: {\n          domain: '',\n          expiration: 365,\n          sameSite: 'Lax',\n          secure: false,\n          upgrade: true,\n        },\n        defaultTracking: undefined,\n        identityStorage: DEFAULT_IDENTITY_STORAGE,\n        flushIntervalMillis: 1000,\n        flushMaxRetries: 5,\n        flushQueueSize: 30,\n        loggerProvider: expect.any(Logger),\n        logLevel: LogLevel.Warn,\n        minIdLength: undefined,\n        offline: false,\n        partnerId: undefined,\n        plan: undefined,\n        ingestionMetadata: undefined,\n        serverUrl: '',\n        serverZone: DEFAULT_SERVER_ZONE,\n        sessionTimeout: 1800000,\n        storageProvider: expect.any(LocalStorageModule.LocalStorage),\n        trackingOptions: {\n          ipAddress: true,\n          language: true,\n          platform: true,\n        },\n        transport: 'fetch',\n        transportProvider: expect.any(FetchTransport),\n        useBatch: false,\n        fetchRemoteConfig: true,\n        version: VERSION,\n        enableDiagnostics: true,\n        diagnosticsSampleRate: 0,\n        diagnosticsClient: undefined,\n        remoteConfig: {\n          fetchRemoteConfig: true,\n        },\n      });\n    });\n\n    test('shoud return _optOut', () => {\n      const config = new Config.BrowserConfig(apiKey);\n      expect(config.optOut).toBe(false);\n    });\n\n    test('should default fetchRemoteConfig to true when both remoteConfig.fetchRemoteConfig and fetchRemoteConfig are undefined', () => {\n      // Pass undefined for fetchRemoteConfig to test the ?? true fallback on line 129\n      const config = new Config.BrowserConfig(apiKey);\n      expect(config.fetchRemoteConfig).toBe(true);\n      expect(config.remoteConfig?.fetchRemoteConfig).toBe(true);\n    });\n  });\n\n  describe('useBrowserConfig', () => {\n    test('should create default config', async () => {\n      const getTopLevelDomain = jest.spyOn(Config, 'getTopLevelDomain').mockResolvedValueOnce('.amplitude.com');\n      const logger = new core.Logger();\n      logger.enable(LogLevel.Warn);\n      const config = await Config.useBrowserConfig(apiKey, undefined, new AmplitudeBrowser());\n      expect(config).toEqual({\n        _cookieStorage: someCookieStorage,\n        _deviceId: someUUID,\n        _lastEventId: undefined,\n        _lastEventTime: undefined,\n        _optOut: false,\n        _sessionId: undefined,\n        _userId: undefined,\n        apiKey,\n        appVersion: undefined,\n        cookieOptions: {\n          domain: '.amplitude.com',\n          expiration: 365,\n          sameSite: 'Lax',\n          secure: false,\n          upgrade: true,\n        },\n        defaultTracking: undefined,\n        identityStorage: DEFAULT_IDENTITY_STORAGE,\n        flushIntervalMillis: 1000,\n        flushMaxRetries: 5,\n        flushQueueSize: 30,\n        loggerProvider: logger,\n        logLevel: LogLevel.Warn,\n        minIdLength: undefined,\n        offline: false,\n        partnerId: undefined,\n        plan: undefined,\n        ingestionMetadata: undefined,\n        serverUrl: '',\n        serverZone: DEFAULT_SERVER_ZONE,\n        sessionTimeout: 1800000,\n        storageProvider: someLocalStorage,\n        trackingOptions: {\n          ipAddress: true,\n          language: true,\n          platform: true,\n        },\n        transport: 'fetch',\n        transportProvider: expect.any(FetchTransport),\n        useBatch: false,\n        fetchRemoteConfig: true,\n        version: VERSION,\n        enableDiagnostics: true,\n        diagnosticsSampleRate: 0,\n        diagnosticsClient: undefined,\n        remoteConfig: {\n          fetchRemoteConfig: true,\n        },\n        topLevelDomain: '.amplitude.com',\n        enableRequestBodyCompression: false,\n      });\n      expect(getTopLevelDomain).toHaveBeenCalledTimes(1);\n    });\n\n    test('should fall back to memoryStorage when storageProvider is not enabled', async () => {\n      const localStorageIsEnabledSpy = jest\n        .spyOn(LocalStorageModule.LocalStorage.prototype, 'isEnabled')\n        .mockResolvedValueOnce(false);\n      const loggerProviderSpy = jest.spyOn(core.Logger.prototype, 'warn');\n      const config = await Config.useBrowserConfig(apiKey, undefined, new AmplitudeBrowser());\n      expect(localStorageIsEnabledSpy).toHaveBeenCalledTimes(1);\n      expect(loggerProviderSpy).toHaveBeenCalledWith(\n        'Storage provider LocalStorage is not enabled. Falling back to MemoryStorage.',\n      );\n      expect(config.storageProvider).toEqual(expect.any(MemoryStorage));\n    });\n\n    describe('with location override', () => {\n      const originalLocation = window.location;\n      beforeAll(() => {\n        Object.defineProperty(window, 'location', {\n          value: { hostname: 'amplitude.com' },\n          configurable: true,\n        });\n      });\n      afterAll(() => {\n        Object.defineProperty(window, 'location', { value: originalLocation, configurable: true });\n      });\n      test('should create using cookies/overwrite', async () => {\n        Object.defineProperty(window, 'location', {\n          value: {\n            hostname: 'amplitude.com',\n          },\n          configurable: true,\n        });\n        const cookieStorage = new core.MemoryStorage<UserSession>();\n        await cookieStorage.set(getCookieName(apiKey), {\n          deviceId: 'device-device-device',\n          sessionId: -1,\n          userId: 'user-user-user',\n          lastEventId: 100,\n          lastEventTime: 1,\n          optOut: false,\n        });\n        const logger = new core.Logger();\n        logger.enable(LogLevel.Warn);\n        jest.spyOn(Config, 'createCookieStorage').mockReturnValueOnce(cookieStorage);\n        const config = await Config.useBrowserConfig(\n          apiKey,\n          {\n            deviceId: 'device-device-device',\n            sessionId: -1,\n            userId: 'user-user-user',\n            partnerId: 'partnerId',\n            plan: {\n              version: '0',\n            },\n            ingestionMetadata: {\n              sourceName: 'ampli',\n              sourceVersion: '2.0.0',\n            },\n            sessionTimeout: 1,\n            cookieOptions: {\n              domain: '.amplitude.com',\n              upgrade: false,\n            },\n            defaultTracking: true,\n            offline: true,\n          },\n          new AmplitudeBrowser(),\n        );\n\n        expect(config).toEqual({\n          _cookieStorage: expect.any(MemoryStorage),\n          _deviceId: 'device-device-device',\n          _lastEventId: 100,\n          _lastEventTime: 1,\n          _optOut: false,\n          _sessionId: -1,\n          _userId: 'user-user-user',\n          apiKey,\n          appVersion: undefined,\n          cookieOptions: {\n            domain: '.amplitude.com',\n            expiration: 365,\n            sameSite: 'Lax',\n            secure: false,\n            upgrade: false,\n          },\n          defaultTracking: true,\n          flushIntervalMillis: 1000,\n          flushMaxRetries: 5,\n          flushQueueSize: 30,\n          identityStorage: DEFAULT_IDENTITY_STORAGE,\n          ingestionMetadata: {\n            sourceName: 'ampli',\n            sourceVersion: '2.0.0',\n          },\n          logLevel: 2,\n          loggerProvider: logger,\n          minIdLength: undefined,\n          offline: true,\n          partnerId: 'partnerId',\n          plan: {\n            version: '0',\n          },\n          serverUrl: '',\n          serverZone: DEFAULT_SERVER_ZONE,\n          sessionTimeout: 1,\n          storageProvider: someLocalStorage,\n          trackingOptions: {\n            ipAddress: true,\n            language: true,\n            platform: true,\n          },\n          transport: 'fetch',\n          transportProvider: expect.any(FetchTransport),\n          useBatch: false,\n          fetchRemoteConfig: true,\n          version: VERSION,\n          enableDiagnostics: true,\n          diagnosticsSampleRate: 0,\n          diagnosticsClient: undefined,\n          remoteConfig: {\n            fetchRemoteConfig: true,\n          },\n          topLevelDomain: 'amplitude.com',\n          enableRequestBodyCompression: false,\n        });\n      });\n    });\n\n    test('should change storage', async () => {\n      const config = await Config.useBrowserConfig(\n        apiKey,\n        {\n          userId: 'user@amplitude.com',\n        },\n        new AmplitudeBrowser(),\n      );\n      expect(config.cookieStorage).toEqual(someCookieStorage);\n      const cookie1 = await config.cookieStorage.get(getCookieName(apiKey));\n      expect(cookie1?.userId).toEqual('user@amplitude.com');\n      config.cookieStorage = new LocalStorageModule.LocalStorage();\n      expect(config.cookieStorage).toEqual(someLocalStorage);\n      const cookie2 = await config.cookieStorage.get(getCookieName(apiKey));\n      expect(cookie2?.userId).toEqual('user@amplitude.com');\n    });\n\n    test('should use custom domain', async () => {\n      const config = await Config.useBrowserConfig(\n        apiKey,\n        {\n          cookieOptions: {\n            domain: 'amplitude.com',\n          },\n        },\n        new AmplitudeBrowser(),\n      );\n      expect(config.cookieOptions?.domain).toEqual('amplitude.com');\n    });\n\n    test('should not call getTopLevelDomain when options.cookieOptions.domain is set', async () => {\n      const getTopLevelDomainSpy = jest.spyOn(Config, 'getTopLevelDomain').mockResolvedValue('.amplitude.com');\n      const config = await Config.useBrowserConfig(\n        apiKey,\n        {\n          cookieOptions: {\n            domain: '.example.com',\n          },\n        },\n        new AmplitudeBrowser(),\n      );\n      expect(getTopLevelDomainSpy).not.toHaveBeenCalled();\n      expect(config.cookieOptions?.domain).toEqual('.example.com');\n    });\n\n    test('should not call getTopLevelDomain when options.cookieOptions.domain is empty string', async () => {\n      const getTopLevelDomainSpy = jest.spyOn(Config, 'getTopLevelDomain').mockResolvedValue('.amplitude.com');\n      const config = await Config.useBrowserConfig(\n        apiKey,\n        {\n          cookieOptions: {\n            domain: '',\n          },\n        },\n        new AmplitudeBrowser(),\n      );\n      expect(getTopLevelDomainSpy).not.toHaveBeenCalled();\n      expect(config.cookieOptions?.domain).toEqual('');\n    });\n\n    test.each([\n      [true, true],\n      [undefined, true],\n      [false, false],\n    ])('should use trackingOptions', async (input, expected) => {\n      const config = await Config.useBrowserConfig(\n        apiKey,\n        {\n          trackingOptions: {\n            ipAddress: input,\n            language: input,\n            platform: input,\n          },\n        },\n        new AmplitudeBrowser(),\n      );\n      expect(config.trackingOptions.ipAddress).toEqual(expected);\n      expect(config.trackingOptions.language).toEqual(expected);\n      expect(config.trackingOptions.platform).toEqual(expected);\n    });\n  });\n\n  describe('createCookieStorage', () => {\n    test('should return cookies', async () => {\n      const storage = Config.createCookieStorage(DEFAULT_IDENTITY_STORAGE);\n      expect(storage).toBeInstanceOf(BrowserUtils.CookieStorage);\n    });\n\n    test('should use return storage', async () => {\n      const storage = Config.createCookieStorage('localStorage');\n      expect(storage).toBeInstanceOf(LocalStorageModule.LocalStorage);\n    });\n\n    test('should use return session storage', async () => {\n      const storage = Config.createCookieStorage('sessionStorage');\n      expect(storage).toBeInstanceOf(SessionStorageModule.SessionStorage);\n    });\n\n    test('should use memory', async () => {\n      const storage = Config.createCookieStorage('none');\n      expect(storage).toBeInstanceOf(core.MemoryStorage);\n    });\n  });\n\n  describe('createTransport', () => {\n    test('should return xhr', () => {\n      expect(createTransport('xhr')).toBeInstanceOf(XHRTransport);\n    });\n\n    test('should return beacon', () => {\n      expect(createTransport('beacon')).toBeInstanceOf(SendBeaconTransport);\n    });\n\n    test('should return fetch', () => {\n      expect(createTransport('fetch')).toBeInstanceOf(FetchTransport);\n    });\n\n    test('should return fetch when undefined', () => {\n      expect(createTransport()).toBeInstanceOf(FetchTransport);\n    });\n\n    test('should return xhr with object format', () => {\n      expect(createTransport({ type: 'xhr' })).toBeInstanceOf(XHRTransport);\n    });\n\n    test('should return beacon with object format', () => {\n      expect(createTransport({ type: 'beacon' })).toBeInstanceOf(SendBeaconTransport);\n    });\n\n    test('should return fetch with object format', () => {\n      expect(createTransport({ type: 'fetch' })).toBeInstanceOf(FetchTransport);\n    });\n\n    test('should return fetch when object format has only headers', () => {\n      expect(createTransport({ headers: { Authorization: 'Bearer token' } })).toBeInstanceOf(FetchTransport);\n    });\n\n    test('should return browser fetch transport (temporary copy, not core fetch transport)', () => {\n      const transport = createTransport('fetch');\n      expect(transport).toBeInstanceOf(FetchTransport);\n      expect(transport).not.toBeInstanceOf(CoreFetchTransport);\n    });\n  });\n\n  describe('getTopLevelDomain', () => {\n    test('should return empty string for localhost', async () => {\n      const isDomainWritableSpy = jest.spyOn(BrowserUtils.CookieStorage, 'isDomainWritable');\n      const domain = await Config.getTopLevelDomain(undefined);\n      expect(isDomainWritableSpy).not.toHaveBeenCalled();\n      expect(domain).toBe('');\n      isDomainWritableSpy.mockRestore();\n    });\n\n    test('should return empty string for single part hostname', async () => {\n      const isDomainWritableSpy = jest.spyOn(BrowserUtils.CookieStorage, 'isDomainWritable');\n      const domain = await Config.getTopLevelDomain('mylocaldomain');\n      expect(isDomainWritableSpy).not.toHaveBeenCalled();\n      expect(domain).toBe('');\n    });\n\n    test('should return empty string if no access to cookies', async () => {\n      const testCookieStorage: Storage<number> = {\n        isEnabled: () => Promise.resolve(false),\n        get: jest.fn().mockResolvedValueOnce(Promise.resolve(1)),\n        getRaw: jest.fn().mockResolvedValueOnce(Promise.resolve(1)),\n        set: jest.fn().mockResolvedValueOnce(Promise.resolve(undefined)),\n        remove: jest.fn().mockResolvedValueOnce(Promise.resolve(undefined)),\n        reset: jest.fn().mockResolvedValueOnce(Promise.resolve(undefined)),\n      };\n      jest.spyOn(BrowserUtils, 'CookieStorage').mockReturnValueOnce({\n        ...testCookieStorage,\n        options: {},\n        config: {},\n      } as unknown as BrowserUtils.CookieStorage<unknown>);\n      const domain = await Config.getTopLevelDomain();\n      expect(domain).toBe('');\n    });\n\n    test('should return top level domain', async () => {\n      const testCookieStorage: Storage<number> = {\n        isEnabled: () => Promise.resolve(true),\n        get: jest.fn().mockResolvedValueOnce(Promise.resolve(1)),\n        getRaw: jest.fn().mockResolvedValueOnce(Promise.resolve(1)),\n        set: jest.fn().mockResolvedValueOnce(Promise.resolve(undefined)),\n        remove: jest.fn().mockResolvedValueOnce(Promise.resolve(undefined)),\n        reset: jest.fn().mockResolvedValueOnce(Promise.resolve(undefined)),\n      };\n      const actualCookieStorage = {\n        isEnabled: () => Promise.resolve(true),\n        get: jest.fn().mockResolvedValueOnce(Promise.resolve(undefined)).mockResolvedValueOnce(Promise.resolve(1)),\n        getRaw: jest.fn().mockResolvedValueOnce(Promise.resolve(undefined)).mockResolvedValueOnce(Promise.resolve(1)),\n        set: jest.fn().mockResolvedValue(Promise.resolve(undefined)),\n        remove: jest.fn().mockResolvedValue(Promise.resolve(undefined)),\n        reset: jest.fn().mockResolvedValue(Promise.resolve(undefined)),\n        // CookieStorage.transaction is used by getTopLevelDomain; first domain fails, second succeeds\n        transaction: jest.fn().mockResolvedValueOnce(false).mockResolvedValueOnce(true),\n      } as unknown as BrowserUtils.CookieStorage<number>;\n      jest\n        .spyOn(BrowserUtils, 'CookieStorage')\n        .mockReturnValueOnce({\n          ...testCookieStorage,\n          options: {},\n          config: {},\n        } as unknown as BrowserUtils.CookieStorage<unknown>)\n        .mockReturnValue({\n          ...actualCookieStorage,\n          options: {},\n          config: {},\n        } as unknown as BrowserUtils.CookieStorage<unknown>);\n\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      const isDomainWritableBefore = BrowserUtils.CookieStorage.isDomainWritable;\n      try {\n        BrowserUtils.CookieStorage.isDomainWritable = jest.fn().mockImplementation((domain: string) => {\n          if (domain === 'gov.uk') return Promise.resolve(false);\n          if (domain === 'ac.be') return Promise.resolve(false);\n          if (domain === 'legislation.gov.uk') return Promise.resolve(true);\n          if (domain === 'website.com') return Promise.resolve(true);\n          if (domain === 'hello.ac.be') return Promise.resolve(true);\n          return Promise.resolve(false);\n        });\n        expect(await Config.getTopLevelDomain('www.legislation.gov.uk')).toBe('.legislation.gov.uk');\n        expect(await Config.getTopLevelDomain('www.website.com')).toBe('.website.com');\n        expect(await Config.getTopLevelDomain('www.hello.ac.be')).toBe('.hello.ac.be');\n      } finally {\n        BrowserUtils.CookieStorage.isDomainWritable = isDomainWritableBefore;\n      }\n    });\n\n    test('should not throw an error when location is an empty object', async () => {\n      const originalLocation = window.location;\n\n      Object.defineProperty(window, 'location', {\n        value: {} as Location,\n        configurable: true,\n      });\n\n      expect(await Config.getTopLevelDomain()).toBe('');\n\n      Object.defineProperty(window, 'location', {\n        value: originalLocation,\n        configurable: true,\n      });\n    });\n\n    test('should return empty string when location is undefined', async () => {\n      const originalLocation = window.location;\n\n      Object.defineProperty(window, 'location', {\n        value: undefined,\n        configurable: true,\n      });\n\n      expect(await Config.getTopLevelDomain()).toBe('');\n\n      Object.defineProperty(window, 'location', {\n        value: originalLocation,\n        configurable: true,\n      });\n    });\n\n    test('should record a diagnostics event when no access to cookies', async () => {\n      const mockDiagnosticsClient = {\n        recordEvent: jest.fn(),\n        setTag: jest.fn(),\n        increment: jest.fn(),\n        recordHistogram: jest.fn(),\n        _flush: jest.fn(),\n        _setSampleRate: jest.fn(),\n      };\n      await Config.getTopLevelDomain('www.amplitude.com', mockDiagnosticsClient);\n      expect(mockDiagnosticsClient.recordEvent).toHaveBeenCalledWith('cookies.tld.failure', {\n        reason: 'Could not determine TLD for host www.amplitude.com',\n      });\n    });\n\n    test('should record cookies.tld.failure when isDomainWritable throws', async () => {\n      const tldError = new Error('cookie access denied');\n      const mockDiagnosticsClient = {\n        recordEvent: jest.fn(),\n        setTag: jest.fn(),\n        increment: jest.fn(),\n        recordHistogram: jest.fn(),\n        _flush: jest.fn(),\n        _setSampleRate: jest.fn(),\n      };\n\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      const isDomainWritableBefore = BrowserUtils.CookieStorage.isDomainWritable;\n      try {\n        BrowserUtils.CookieStorage.isDomainWritable = jest.fn().mockRejectedValue(tldError);\n        expect(await Config.getTopLevelDomain('www.example.com', mockDiagnosticsClient)).toBe('');\n        expect(mockDiagnosticsClient.recordEvent).toHaveBeenCalledWith('cookies.tld.failure', {\n          reason: 'Unexpected exception checking domain is writable: example.com',\n          error: 'cookie access denied',\n        });\n      } finally {\n        BrowserUtils.CookieStorage.isDomainWritable = isDomainWritableBefore;\n      }\n    });\n  });\n\n  describe('fetchRemoteConfig', () => {\n    test('should set remoteConfig.fetchRemoteConfig to true when remoteConfig.fetchRemoteConfig true', async () => {\n      const instance = new AmplitudeBrowser();\n      const config = await useBrowserConfig(\n        apiKey,\n        {\n          fetchRemoteConfig: false,\n          remoteConfig: {\n            fetchRemoteConfig: true,\n          },\n        },\n        instance,\n      );\n      expect(config.remoteConfig?.fetchRemoteConfig).toBe(true);\n    });\n\n    test('should set remoteConfig.fetchRemoteConfig to true when remoteConfig.fetchRemoteConfig is false', async () => {\n      const instance = new AmplitudeBrowser();\n      const config = await useBrowserConfig(\n        apiKey,\n        {\n          remoteConfig: {\n            fetchRemoteConfig: false,\n          },\n        },\n        instance,\n      );\n      expect(config.remoteConfig?.fetchRemoteConfig).toBe(false);\n    });\n  });\n\n  describe('duplicateResolverFn', () => {\n    const encodeJson = (session: UserSession) => btoa(encodeURIComponent(JSON.stringify(session)));\n\n    let config: BrowserConfig;\n    let cookieStorage: BrowserUtils.CookieStorage<UserSession>;\n    let duplicateResolverFn: ((value: string) => boolean) | undefined;\n\n    beforeEach(async () => {\n      config = await Config.useBrowserConfig(\n        apiKey,\n        { cookieOptions: { domain: '.amplitude.com' } },\n        new AmplitudeBrowser(),\n      );\n      cookieStorage = config.cookieStorage as BrowserUtils.CookieStorage<UserSession>;\n      duplicateResolverFn = cookieStorage.config.duplicateResolverFn;\n    });\n\n    test('should return true when cookieDomain matches config domain', async () => {\n      expect(duplicateResolverFn?.(encodeJson({ optOut: false, cookieDomain: '.amplitude.com' }))).toBe(true);\n    });\n\n    test('should return false when cookieDomain does not match config domain', async () => {\n      expect(duplicateResolverFn?.(encodeJson({ optOut: false, cookieDomain: '.other.com' }))).toBe(false);\n    });\n\n    test('should return false when cookieDomain is not set', async () => {\n      expect(duplicateResolverFn?.(encodeJson({ optOut: false }))).toBe(false);\n    });\n\n    test('should return false when cookie value cannot be decoded', async () => {\n      expect(duplicateResolverFn?.('not-valid-base64!')).toBe(false);\n    });\n  });\n\n  describe('shouldFetchRemoteConfig', () => {\n    test('should return true when remoteConfig.fetchRemoteConfig is explicitly true', () => {\n      expect(shouldFetchRemoteConfig({ remoteConfig: { fetchRemoteConfig: true } })).toBe(true);\n    });\n\n    test('should return false when remoteConfig.fetchRemoteConfig is explicitly false', () => {\n      expect(shouldFetchRemoteConfig({ remoteConfig: { fetchRemoteConfig: false } })).toBe(false);\n    });\n\n    test('should return false when fetchRemoteConfig is explicitly false', () => {\n      expect(shouldFetchRemoteConfig({ fetchRemoteConfig: false })).toBe(false);\n    });\n\n    test('should return true when both are undefined (default behavior)', () => {\n      expect(shouldFetchRemoteConfig({})).toBe(true);\n    });\n\n    test('should return true when options is undefined', () => {\n      expect(shouldFetchRemoteConfig()).toBe(true);\n    });\n  });\n\n  describe('useBrowserConfig with earlyConfig', () => {\n    test('should use earlyConfig values when provided', async () => {\n      const customLogger = new core.Logger();\n      customLogger.enable(LogLevel.Debug);\n\n      const earlyConfig: Config.EarlyConfig = {\n        loggerProvider: customLogger,\n        serverZone: 'EU',\n        enableDiagnostics: false,\n        diagnosticsSampleRate: 0.5,\n      };\n\n      const config = await Config.useBrowserConfig(\n        apiKey,\n        {}, // Empty options to ensure earlyConfig values are used\n        new AmplitudeBrowser(),\n        undefined, // diagnosticsClient\n        earlyConfig,\n      );\n\n      // Verify earlyConfig values are used instead of defaults\n      expect(config.loggerProvider).toBe(customLogger);\n      expect(config.serverZone).toBe('EU');\n      expect(config.enableDiagnostics).toBe(false);\n      expect(config.diagnosticsSampleRate).toBe(0.5);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-browser/test/cookie-migration/index.test.ts",
    "content": "import { Storage, UserSession, MemoryStorage, CookieStorage, getOldCookieName } from '@amplitude/analytics-core';\nimport { decode, parseLegacyCookies, parseTime } from '../../src/cookie-migration';\nimport * as LocalStorageModule from '../../src/storage/local-storage';\n\ndescribe('cookie-migration', () => {\n  const API_KEY = 'asdfasdf';\n  afterEach(() => {\n    // clean up cookies\n    document.cookie = `${getOldCookieName(API_KEY)}=null; expires=-1`;\n  });\n\n  describe('parseLegacyCookies', () => {\n    test('should return default values', async () => {\n      const cookies = await parseLegacyCookies(API_KEY, new MemoryStorage());\n      expect(cookies).toEqual({\n        optOut: false,\n      });\n    });\n\n    test('should handle non-persistent storage', async () => {\n      jest.spyOn(LocalStorageModule, 'LocalStorage').mockReturnValueOnce({\n        isEnabled: async () => false,\n        get: async () => ({}),\n        getRaw: async () => '',\n        set: async () => undefined,\n        remove: async () => undefined,\n        reset: async () => undefined,\n      });\n      const cookies = await parseLegacyCookies(API_KEY, new MemoryStorage());\n      expect(cookies).toEqual({\n        optOut: false,\n      });\n    });\n\n    test('should remove old cookies by default', async () => {\n      const timestamp = 1650949309508;\n      const time = timestamp.toString(32);\n      const userId = 'userId';\n      const encodedUserId = btoa(unescape(encodeURIComponent(userId)));\n      const oldCookieName = getOldCookieName(API_KEY);\n      const lastEventId = (0).toString(32);\n      document.cookie = `${oldCookieName}=deviceId.${encodedUserId}..${time}.${time}.${lastEventId}`;\n      const cookieStorage: Storage<UserSession> = new CookieStorage<UserSession>();\n      const cookies = await parseLegacyCookies(API_KEY, cookieStorage);\n      expect(cookies).toEqual({\n        deviceId: 'deviceId',\n        userId: 'userId',\n        sessionId: timestamp,\n        lastEventId: 0,\n        lastEventTime: timestamp,\n        optOut: false,\n      });\n      const cookies2 = await cookieStorage.getRaw(oldCookieName);\n      expect(cookies2).toBeUndefined();\n    });\n\n    test('should remove old cookies', async () => {\n      const timestamp = 1650949309508;\n      const time = timestamp.toString(32);\n      const userId = 'userId';\n      const encodedUserId = btoa(unescape(encodeURIComponent(userId)));\n      const oldCookieName = getOldCookieName(API_KEY);\n      const lastEventId = (0).toString(32);\n      document.cookie = `${oldCookieName}=deviceId.${encodedUserId}..${time}.${time}.${lastEventId}`;\n      const cookieStorage: Storage<UserSession> = new CookieStorage<UserSession>();\n      const cookies = await parseLegacyCookies(API_KEY, cookieStorage, true);\n      expect(cookies).toEqual({\n        deviceId: 'deviceId',\n        userId: 'userId',\n        sessionId: timestamp,\n        lastEventTime: timestamp,\n        lastEventId: 0,\n        optOut: false,\n      });\n\n      const storage: Storage<string> = new CookieStorage<string>();\n      const cookies2 = await storage.getRaw(oldCookieName);\n      expect(cookies2).toBeUndefined();\n    });\n\n    test('should keep old cookies', async () => {\n      const timestamp = 1650949309508;\n      const time = timestamp.toString(32);\n      const userId = 'userId';\n      const encodedUserId = btoa(unescape(encodeURIComponent(userId)));\n      const oldCookieName = getOldCookieName(API_KEY);\n      const lastEventId = (0).toString(32);\n      document.cookie = `${oldCookieName}=deviceId.${encodedUserId}..${time}.${time}.${lastEventId}`;\n      const cookieStorage: Storage<UserSession> = new CookieStorage<UserSession>();\n      const cookies = await parseLegacyCookies(API_KEY, cookieStorage, false);\n      expect(cookies).toEqual({\n        deviceId: 'deviceId',\n        userId: 'userId',\n        sessionId: timestamp,\n        lastEventTime: timestamp,\n        lastEventId: 0,\n        optOut: false,\n      });\n\n      const storage: Storage<string> = new CookieStorage<string>();\n      const cookies2 = await storage.getRaw(oldCookieName);\n      expect(cookies2).toBe(`deviceId.${encodedUserId}..${time}.${time}.${lastEventId}`);\n    });\n  });\n\n  describe('parseTime', () => {\n    test('should parse time', () => {\n      const timestamp = Date.now();\n      const base32 = timestamp.toString(32);\n      expect(parseTime(base32)).toBe(timestamp);\n    });\n\n    test('should handle invalid values', () => {\n      expect(parseTime('')).toBe(undefined);\n    });\n  });\n\n  describe('decode', () => {\n    test('should decode value', () => {\n      expect(decode('YXNkZg==')).toBe('asdf');\n    });\n\n    test('should handle incorrecty encoded value', () => {\n      expect(decode('asdf')).toBe(undefined);\n    });\n\n    test('should handle undefined input', () => {\n      expect(decode(undefined)).toBe(undefined);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-browser/test/default-tracking.test.ts",
    "content": "import * as analyticsCoreModule from '@amplitude/analytics-core';\nimport {\n  getAttributionTrackingConfig,\n  getElementInteractionsConfig,\n  getFormInteractionsConfig,\n  getFrustrationInteractionsConfig,\n  getNetworkTrackingConfig,\n  getPageViewTrackingConfig,\n  getPerformanceTrackingConfig,\n  isAttributionTrackingEnabled,\n  isCustomEnrichmentEnabled,\n  isElementInteractionsEnabled,\n  isFileDownloadTrackingEnabled,\n  isFormInteractionTrackingEnabled,\n  isFrustrationInteractionsEnabled,\n  isNetworkTrackingEnabled,\n  isPageUrlEnrichmentEnabled,\n  isPageViewTrackingEnabled,\n  isPerformanceTrackingEnabled,\n  isSessionTrackingEnabled,\n  isWebVitalsEnabled,\n} from '../src/default-tracking';\n\ndescribe('isCustomEnrichmentEnabled', () => {\n  test('should return false when customEnrichment is undefined', () => {\n    expect(isCustomEnrichmentEnabled(undefined)).toBe(false);\n  });\n\n  test('should return true when customEnrichment is an object with enabled=true', () => {\n    expect(isCustomEnrichmentEnabled({ enabled: true, body: 'test' })).toBe(true);\n  });\n\n  test('should return false when customEnrichment is an object with enabled=false', () => {\n    expect(isCustomEnrichmentEnabled({ enabled: false, body: 'test' })).toBe(false);\n  });\n\n  test('should return true when customEnrichment is true (from translated remote config)', () => {\n    expect(isCustomEnrichmentEnabled(true)).toBe(true);\n  });\n\n  test('should return false when customEnrichment is false (from translated remote config)', () => {\n    expect(isCustomEnrichmentEnabled(false)).toBe(false);\n  });\n\n  test('should return true when customEnrichment is an object without enabled (from translated remote config)', () => {\n    expect(isCustomEnrichmentEnabled({ body: 'test' })).toBe(true);\n  });\n\n  test('should return false when customEnrichment is null', () => {\n    expect(isCustomEnrichmentEnabled(null as unknown as undefined)).toBe(false);\n  });\n});\n\ndescribe('isWebVitalsEnabled', () => {\n  describe('is true when', () => {\n    test('autocapture=true', () => {\n      expect(isWebVitalsEnabled(true)).toBe(true);\n    });\n\n    test('autocapture.webVitals=true', () => {\n      expect(isWebVitalsEnabled({ webVitals: true })).toBe(true);\n    });\n  });\n\n  describe('is false when', () => {\n    test('autocapture=false', () => {\n      expect(isWebVitalsEnabled(false)).toBe(false);\n    });\n\n    test('autocapture.webVitals=false', () => {\n      expect(isWebVitalsEnabled({ webVitals: false })).toBe(false);\n    });\n\n    test('autocapture.webVitals is undefined', () => {\n      expect(isWebVitalsEnabled({ networkTracking: true })).toBe(false);\n    });\n  });\n});\n\ndescribe('isFrustrationInteractionsEnabled', () => {\n  test('should return true when autocapture=true', () => {\n    expect(isFrustrationInteractionsEnabled(true)).toBe(true);\n  });\n\n  test('should return false with undefined parameter', () => {\n    expect(isFrustrationInteractionsEnabled(undefined)).toBe(false);\n  });\n\n  test('should return false with false parameter', () => {\n    expect(isFrustrationInteractionsEnabled(false)).toBe(false);\n  });\n\n  test('should return true with object parameter', () => {\n    expect(isFrustrationInteractionsEnabled({ frustrationInteractions: true })).toBe(true);\n  });\n\n  test('should return false with object parameter', () => {\n    expect(isFrustrationInteractionsEnabled({ frustrationInteractions: false })).toBe(false);\n  });\n\n  test('should get frustration interactions config', () => {\n    const config = getFrustrationInteractionsConfig({\n      autocapture: {\n        frustrationInteractions: {\n          deadClicks: {\n            cssSelectorAllowlist: ['button'],\n          },\n          rageClicks: {\n            cssSelectorAllowlist: ['button'],\n          },\n        },\n      },\n    });\n    expect(config).toEqual({\n      deadClicks: {\n        cssSelectorAllowlist: ['button'],\n      },\n      rageClicks: {\n        cssSelectorAllowlist: ['button'],\n      },\n    });\n  });\n\n  test('should get undefined frustration interactions config when autocapture is true', () => {\n    const config = getFrustrationInteractionsConfig({\n      autocapture: true,\n    });\n    expect(config).toBeUndefined();\n  });\n});\n\ndescribe('isPerformanceTrackingEnabled', () => {\n  test('should return false with undefined parameter', () => {\n    expect(isPerformanceTrackingEnabled(undefined)).toBe(false);\n  });\n\n  test('should return false when autocapture=true', () => {\n    expect(isPerformanceTrackingEnabled(true)).toBe(false);\n  });\n\n  test('should return false when autocapture=false', () => {\n    expect(isPerformanceTrackingEnabled(false)).toBe(false);\n  });\n\n  test('should return true with performanceTracking=true', () => {\n    expect(isPerformanceTrackingEnabled({ performanceTracking: true })).toBe(true);\n  });\n\n  test('should return true with performanceTracking as object', () => {\n    expect(isPerformanceTrackingEnabled({ performanceTracking: { mainThreadBlock: true } })).toBe(true);\n  });\n\n  test('should return false with performanceTracking=false', () => {\n    expect(isPerformanceTrackingEnabled({ performanceTracking: false })).toBe(false);\n  });\n\n  test('should return false when performanceTracking is undefined', () => {\n    expect(isPerformanceTrackingEnabled({ webVitals: true })).toBe(false);\n  });\n});\n\ndescribe('getPerformanceTrackingConfig', () => {\n  test('should return config when performanceTracking is an object', () => {\n    const config = getPerformanceTrackingConfig({\n      autocapture: {\n        performanceTracking: {\n          mainThreadBlock: { durationThreshold: 200 },\n        },\n      },\n    });\n    expect(config).toEqual({ mainThreadBlock: { durationThreshold: 200 } });\n  });\n\n  test('should return undefined when autocapture is true', () => {\n    expect(getPerformanceTrackingConfig({ autocapture: true })).toBeUndefined();\n  });\n\n  test('should return mainThreadBlock true when performanceTracking=true (explicit autocapture opt-in)', () => {\n    expect(getPerformanceTrackingConfig({ autocapture: { performanceTracking: true } })).toEqual({\n      mainThreadBlock: true,\n    });\n  });\n\n  test('should return undefined when performanceTracking is disabled', () => {\n    expect(getPerformanceTrackingConfig({ autocapture: { performanceTracking: false } })).toBeUndefined();\n  });\n});\n\ndescribe('isFileDownloadTrackingEnabled', () => {\n  test('should return true with true parameter', () => {\n    expect(isFileDownloadTrackingEnabled(true)).toBe(true);\n  });\n\n  test('should return true with undefined parameter', () => {\n    expect(isFileDownloadTrackingEnabled(undefined)).toBe(true);\n  });\n\n  test('should return false with false parameter', () => {\n    expect(isFileDownloadTrackingEnabled(false)).toBe(false);\n  });\n\n  test('should return true with object parameter', () => {\n    expect(\n      isFileDownloadTrackingEnabled({\n        fileDownloads: true,\n      }),\n    ).toBe(true);\n  });\n\n  test('should return false with object parameter', () => {\n    expect(\n      isFileDownloadTrackingEnabled({\n        fileDownloads: false,\n      }),\n    ).toBe(false);\n  });\n});\n\ndescribe('isFormInteractionTrackingEnabled', () => {\n  test('should return true with true parameter', () => {\n    expect(isFormInteractionTrackingEnabled(true)).toBe(true);\n  });\n\n  test('should return true with undefined parameter', () => {\n    expect(isFormInteractionTrackingEnabled(undefined)).toBe(true);\n  });\n\n  test('should return false with false parameter', () => {\n    expect(isFormInteractionTrackingEnabled(false)).toBe(false);\n  });\n\n  test('should return true with object parameter', () => {\n    expect(\n      isFormInteractionTrackingEnabled({\n        formInteractions: true,\n      }),\n    ).toBe(true);\n  });\n\n  test('should return false with object parameter', () => {\n    expect(\n      isFormInteractionTrackingEnabled({\n        formInteractions: false,\n      }),\n    ).toBe(false);\n  });\n});\n\ndescribe('getFormInteractionsConfig', () => {\n  test('should return undefined when defaultTracking is undefined', () => {\n    const config = getFormInteractionsConfig({});\n    expect(config).toBeUndefined();\n  });\n\n  test('should return undefined when defaultTracking is true', () => {\n    const config = getFormInteractionsConfig({\n      defaultTracking: true,\n    });\n    expect(config).toBeUndefined();\n  });\n\n  test('should return undefined when defaultTracking is false', () => {\n    const config = getFormInteractionsConfig({\n      defaultTracking: false,\n    });\n    expect(config).toBeUndefined();\n  });\n\n  test('should return undefined when formInteractions is true', () => {\n    const config = getFormInteractionsConfig({\n      defaultTracking: {\n        formInteractions: true,\n      },\n    });\n    expect(config).toBeUndefined();\n  });\n\n  test('should return undefined when formInteractions is false', () => {\n    const config = getFormInteractionsConfig({\n      defaultTracking: {\n        formInteractions: false,\n      },\n    });\n    expect(config).toBeUndefined();\n  });\n\n  test('should return config with shouldTrackSubmit callback', () => {\n    const shouldTrackSubmit = jest.fn(() => true);\n    const config = getFormInteractionsConfig({\n      defaultTracking: {\n        formInteractions: {\n          shouldTrackSubmit,\n        },\n      },\n    });\n\n    expect(config).toBeDefined();\n    expect(config?.shouldTrackSubmit).toBe(shouldTrackSubmit);\n  });\n\n  test('should return empty config object when formInteractions is empty object', () => {\n    const config = getFormInteractionsConfig({\n      defaultTracking: {\n        formInteractions: {},\n      },\n    });\n\n    expect(config).toEqual({});\n  });\n});\n\ndescribe('isPageViewTrackingEnabled', () => {\n  test('should return true with true parameter', () => {\n    expect(isPageViewTrackingEnabled(true)).toBe(true);\n  });\n\n  test('should return true with undefined parameter', () => {\n    expect(isPageViewTrackingEnabled(undefined)).toBe(true);\n  });\n\n  test('should return true with false parameter', () => {\n    expect(isPageViewTrackingEnabled(false)).toBe(false);\n  });\n\n  test('should return true with object parameter', () => {\n    expect(\n      isPageViewTrackingEnabled({\n        pageViews: true,\n      }),\n    ).toBe(true);\n  });\n\n  test('should return false with object parameter', () => {\n    expect(\n      isPageViewTrackingEnabled({\n        pageViews: false,\n      }),\n    ).toBe(false);\n  });\n\n  test('should return true with nested object parameter', () => {\n    expect(\n      isPageViewTrackingEnabled({\n        pageViews: {},\n      }),\n    ).toBe(true);\n  });\n});\n\ndescribe('isSessionTrackingEnabled', () => {\n  test('should return true with true parameter', () => {\n    expect(isSessionTrackingEnabled(true)).toBe(true);\n  });\n\n  test('should return true with undefined parameter', () => {\n    expect(isSessionTrackingEnabled(undefined)).toBe(true);\n  });\n\n  test('should return false with false parameter', () => {\n    expect(isSessionTrackingEnabled(false)).toBe(false);\n  });\n\n  test('should return true with object parameter', () => {\n    expect(\n      isSessionTrackingEnabled({\n        sessions: true,\n      }),\n    ).toBe(true);\n  });\n\n  test('should return false with object parameter', () => {\n    expect(\n      isSessionTrackingEnabled({\n        sessions: false,\n      }),\n    ).toBe(false);\n  });\n\n  describe('when environment is a Chrome extension', () => {\n    beforeEach(() => {\n      jest.spyOn(analyticsCoreModule, 'isChromeExtension').mockReturnValue(true);\n    });\n\n    test('should return false if not set', () => {\n      expect(isSessionTrackingEnabled(undefined)).toBe(false);\n    });\n\n    test('should return true if set to true', () => {\n      expect(isSessionTrackingEnabled({ sessions: true })).toBe(true);\n    });\n  });\n});\n\ndescribe('isAttributionTrackingEnabled', () => {\n  test('should return true with true parameter', () => {\n    expect(isAttributionTrackingEnabled(true)).toBe(true);\n  });\n\n  test('should return true with undefined parameter', () => {\n    expect(isAttributionTrackingEnabled(undefined)).toBe(true);\n  });\n\n  test('should return false with false parameter', () => {\n    expect(isAttributionTrackingEnabled(false)).toBe(false);\n  });\n\n  test('should return true with object parameter', () => {\n    expect(\n      isAttributionTrackingEnabled({\n        attribution: true,\n      }),\n    ).toBe(true);\n  });\n\n  test('should return false with object parameter', () => {\n    expect(\n      isAttributionTrackingEnabled({\n        attribution: false,\n      }),\n    ).toBe(false);\n  });\n});\n\ndescribe('isNetworkTrackingEnabled', () => {\n  test('should return false when autocapture is false', () => {\n    expect(isNetworkTrackingEnabled(false)).toBe(false);\n  });\n\n  test('should return false when autocapture is undefined', () => {\n    expect(isNetworkTrackingEnabled(undefined)).toBe(false);\n  });\n\n  test('should return true when autocapture is true', () => {\n    expect(isNetworkTrackingEnabled(true)).toBe(true);\n  });\n\n  test('should return true when autocapture.networkTracking is true', () => {\n    expect(\n      isNetworkTrackingEnabled({\n        networkTracking: true,\n      }),\n    ).toBe(true);\n  });\n\n  test('should return true when autocapture.networkTracking is an object', () => {\n    expect(\n      isNetworkTrackingEnabled({\n        networkTracking: {},\n      }),\n    ).toBe(true);\n  });\n\n  test('should return false when autocapture.networkTracking is false', () => {\n    expect(\n      isNetworkTrackingEnabled({\n        networkTracking: false,\n      }),\n    ).toBe(false);\n  });\n\n  test('should return false when autocapture.networkTracking is undefined', () => {\n    expect(\n      isNetworkTrackingEnabled({\n        sessions: true,\n        pageViews: true,\n        networkTracking: undefined,\n      }),\n    ).toBe(false);\n  });\n});\n\ndescribe('isElementInteractionsEnabled', () => {\n  test('should return true with true parameter', () => {\n    expect(isElementInteractionsEnabled(true)).toBe(true);\n  });\n\n  test('should return false with undefined parameter', () => {\n    expect(isElementInteractionsEnabled(undefined)).toBe(false);\n  });\n\n  test('should return false with false parameter', () => {\n    expect(isElementInteractionsEnabled(false)).toBe(false);\n  });\n\n  test('should return true with object parameter', () => {\n    expect(\n      isElementInteractionsEnabled({\n        elementInteractions: true,\n      }),\n    ).toBe(true);\n  });\n\n  test('should return false with object parameter', () => {\n    expect(\n      isElementInteractionsEnabled({\n        elementInteractions: false,\n      }),\n    ).toBe(false);\n  });\n\n  test('should return false with object parameter undefined', () => {\n    expect(\n      isElementInteractionsEnabled({\n        elementInteractions: undefined,\n      }),\n    ).toBe(false);\n  });\n});\n\ndescribe('getPageViewTrackingConfig', () => {\n  test('should return undefined trackOn config', () => {\n    const config = getPageViewTrackingConfig({\n      defaultTracking: {\n        pageViews: true,\n      },\n    });\n\n    expect(config.trackOn).toBe(undefined);\n  });\n\n  test('should return trackOn config returning false', () => {\n    const config = getPageViewTrackingConfig({\n      defaultTracking: {\n        pageViews: false,\n      },\n    });\n\n    expect(typeof config.trackOn).toBe('function');\n    // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n    // @ts-ignore asserts that track on is a function that returns a boolean\n    expect(config.trackOn()).toBe(false);\n  });\n\n  test('should return advanced options', () => {\n    const config = getPageViewTrackingConfig({\n      defaultTracking: {\n        pageViews: {\n          trackOn: 'attribution',\n          trackHistoryChanges: 'all',\n          eventType: 'Page View',\n        },\n      },\n    });\n\n    expect(typeof config.trackOn).toBe('string');\n    expect(config.trackOn).toBe('attribution');\n    expect(config.trackHistoryChanges).toBe('all');\n    expect(config.eventType).toBe('Page View');\n  });\n});\n\ndescribe('getAttributionTrackingConfig', () => {\n  test('should return disabled config', () => {\n    const config = getAttributionTrackingConfig({\n      defaultTracking: {\n        attribution: false,\n      },\n    });\n    expect(config).toEqual({\n      excludeReferrers: undefined,\n      initialEmptyValue: undefined,\n      resetSessionOnNewCampaign: undefined,\n    });\n  });\n\n  test('should return default config', () => {\n    const config = getAttributionTrackingConfig({\n      defaultTracking: {\n        attribution: {},\n      },\n    });\n    expect(config).toEqual({\n      excludeReferrers: undefined,\n      initialEmptyValue: undefined,\n      resetSessionOnNewCampaign: undefined,\n    });\n  });\n\n  test('should return custom config', () => {\n    const config = getAttributionTrackingConfig({\n      defaultTracking: {\n        attribution: {\n          excludeReferrers: [],\n          initialEmptyValue: 'EMPTY',\n          resetSessionOnNewCampaign: true,\n        },\n      },\n    });\n    expect(config).toEqual({\n      excludeReferrers: [],\n      initialEmptyValue: 'EMPTY',\n      resetSessionOnNewCampaign: true,\n    });\n  });\n});\n\ndescribe('getNetworkTrackingConfig', () => {\n  test('should return autocapture.networkTracking if it is an object', () => {\n    const autocapture = {\n      networkTracking: {\n        ignoreAmplitudeRequests: true,\n        ignoreHosts: ['example.com'],\n        captureRules: [\n          {\n            hosts: ['example.com'],\n            statusCodeRange: '500-599',\n          },\n        ],\n      },\n    };\n    const config = getNetworkTrackingConfig({\n      autocapture,\n    });\n    expect(typeof config).toBe('object');\n    expect(config).toEqual(autocapture.networkTracking);\n  });\n\n  test('should return \"networkTrackingOptions\" if is defined and autocapture.networkTracking=true (deprecated)', () => {\n    const autocapture = {\n      networkTracking: true,\n    };\n    const networkTrackingOptions = {\n      ignoreAmplitudeRequests: true,\n      ignoreHosts: ['example.com'],\n      captureRules: [\n        {\n          hosts: ['example.com'],\n          statusCodeRange: '500-599',\n        },\n      ],\n    };\n    const config = getNetworkTrackingConfig({\n      autocapture,\n      networkTrackingOptions,\n    });\n    expect(typeof config).toBe('object');\n    expect(config).toEqual(networkTrackingOptions);\n  });\n\n  test('should return undefined when autocapture is not defined', () => {\n    const autocapture = undefined;\n    const networkTrackingOptions = {};\n    const config = getNetworkTrackingConfig({\n      autocapture,\n      networkTrackingOptions,\n    });\n    expect(config).toBeUndefined();\n  });\n\n  test('should return undefined when autocapture.networkTracking is undefined', () => {\n    const config = getNetworkTrackingConfig({\n      autocapture: {\n        elementInteractions: true,\n        sessions: true,\n      },\n      networkTrackingOptions: {\n        ignoreAmplitudeRequests: true,\n        ignoreHosts: ['example.com'],\n        captureRules: [\n          {\n            hosts: ['example.com'],\n            statusCodeRange: '500-599',\n          },\n        ],\n      },\n    });\n    expect(config).toBeUndefined();\n  });\n\n  describe('captureRules.urls and .hosts combinations', () => {\n    const networkTracking = {\n      captureRules: [\n        { urls: ['https://example.com/path', /path\\/to/], hosts: ['example.com'] },\n        { hosts: ['example.com', 'helloworld.com'] },\n        { urls: ['https://example.com'] },\n      ],\n    };\n\n    test('should ignore hosts if urls are set', () => {\n      const captureRules =\n        getNetworkTrackingConfig({\n          autocapture: { networkTracking },\n        })?.captureRules || [];\n      const ruleWithBothSet = captureRules[0];\n      expect(ruleWithBothSet.hosts).toBeUndefined();\n      expect(ruleWithBothSet.urls).toEqual(['https://example.com/path', /path\\/to/]);\n    });\n\n    test('should keep hosts if urls are not set', () => {\n      const captureRules =\n        getNetworkTrackingConfig({\n          autocapture: { networkTracking },\n        })?.captureRules || [];\n      const ruleWithOnlyHosts = captureRules[1];\n      expect(ruleWithOnlyHosts.hosts).toEqual(['example.com', 'helloworld.com']);\n      expect(ruleWithOnlyHosts.urls).toBeUndefined();\n    });\n\n    test('should ignore hosts if urls are set and hosts is undefined', () => {\n      const captureRules =\n        getNetworkTrackingConfig({\n          autocapture: { networkTracking },\n        })?.captureRules || [];\n      const ruleWithBothSet = captureRules[2];\n      expect(ruleWithBothSet.hosts).toBeUndefined();\n      expect(ruleWithBothSet.urls).toEqual(['https://example.com']);\n    });\n\n    test('should not do anything if captureRules is not set', () => {\n      const config = getNetworkTrackingConfig({\n        autocapture: { networkTracking: {} },\n      });\n      expect(config?.captureRules).toBeUndefined();\n    });\n\n    test('should apply captureRules to networkTrackingOptions', () => {\n      const networkTrackingOptions = {\n        captureRules: [{ urls: ['https://example.com/path', /path\\/to/], hosts: ['example.com'] }],\n      };\n      const config = getNetworkTrackingConfig({\n        autocapture: { networkTracking: true },\n        networkTrackingOptions,\n      });\n      const ruleWithBothSet = config?.captureRules?.[0];\n      expect(ruleWithBothSet?.urls).toEqual(['https://example.com/path', /path\\/to/]);\n      expect(ruleWithBothSet?.hosts).toBeUndefined();\n    });\n  });\n});\n\ndescribe('getElementInteractionsConfig', () => {\n  test('should return an empty object when autocapture is true', () => {\n    const config = getElementInteractionsConfig({\n      autocapture: true,\n    });\n\n    expect(config).toBeUndefined();\n  });\n\n  test('should return an empty object when userInteraction is true', () => {\n    const config = getElementInteractionsConfig({\n      autocapture: {\n        elementInteractions: true,\n      },\n    });\n\n    expect(config).toBeUndefined();\n  });\n\n  test('should return advanced options', () => {\n    const testCssSelectorAllowlist = ['button'];\n    const testPageUrlAllowlist = ['example.com'];\n    const mockedShouldTrackEventResolver = jest.fn(() => true);\n    const testDataAttributePrefix = 'data-amp-track';\n    const config = getElementInteractionsConfig({\n      autocapture: {\n        elementInteractions: {\n          cssSelectorAllowlist: testCssSelectorAllowlist,\n          pageUrlAllowlist: testPageUrlAllowlist,\n          shouldTrackEventResolver: mockedShouldTrackEventResolver,\n          dataAttributePrefix: testDataAttributePrefix,\n        },\n      },\n    });\n\n    expect(config?.cssSelectorAllowlist).toBe(testCssSelectorAllowlist);\n    expect(config?.pageUrlAllowlist).toBe(testPageUrlAllowlist);\n    expect(config?.shouldTrackEventResolver).toBe(mockedShouldTrackEventResolver);\n    expect(config?.dataAttributePrefix).toBe(testDataAttributePrefix);\n  });\n});\n\ndescribe('isPageUrlEnrichmentEnabled', () => {\n  test('should return true with true parameter', () => {\n    expect(isPageUrlEnrichmentEnabled(true)).toBe(true);\n  });\n\n  test('should return true with undefined parameter', () => {\n    expect(isPageUrlEnrichmentEnabled(undefined)).toBe(true);\n  });\n\n  test('should return false with false parameter', () => {\n    expect(isPageUrlEnrichmentEnabled(false)).toBe(false);\n  });\n\n  test('should return true with object parameter set to true', () => {\n    expect(\n      isPageUrlEnrichmentEnabled({\n        pageUrlEnrichment: true,\n      }),\n    ).toBe(true);\n  });\n\n  test('should return false with object parameter set to false', () => {\n    expect(\n      isPageUrlEnrichmentEnabled({\n        pageUrlEnrichment: false,\n      }),\n    ).toBe(false);\n  });\n\n  test('should return true with object parameter undefined', () => {\n    expect(\n      isPageUrlEnrichmentEnabled({\n        pageUrlEnrichment: undefined,\n      }),\n    ).toBe(true);\n  });\n});\n"
  },
  {
    "path": "packages/analytics-browser/test/det-notification.test.ts",
    "content": "jest.unmock('../src/det-notification');\n\nimport { detNotify, resetNotify } from '../src/det-notification';\nimport { BrowserConfig } from '../src/config';\nimport { UUID } from '@amplitude/analytics-core';\n\ndescribe('detNotify', () => {\n  let apiKey = '';\n\n  afterAll(() => {\n    jest.mock('../src/det-notification');\n  });\n\n  beforeEach(() => {\n    apiKey = UUID();\n    resetNotify();\n  });\n\n  test('should handle undefined config', () => {\n    const config = new BrowserConfig(apiKey);\n    const warn = jest.spyOn(config.loggerProvider, 'warn').mockImplementationOnce(() => undefined);\n    detNotify(config);\n    expect(warn).toHaveBeenCalledTimes(1);\n    expect(warn).toHaveBeenCalledWith(\n      `\\`options.defaultTracking\\` is set to undefined. This implicitly configures your Amplitude instance to track Page Views, Sessions, File Downloads, and Form Interactions. You can suppress this warning by explicitly setting a value to \\`options.defaultTracking\\`. The value must either be a boolean, to enable and disable all default events, or an object, for advanced configuration. For example:\n\namplitude.init(<YOUR_API_KEY>, {\n  defaultTracking: true,\n});\n\nVisit https://www.docs.developers.amplitude.com/data/sdks/browser-2/#tracking-default-events for more details.`,\n    );\n  });\n\n  test('should handle duplicate calls', () => {\n    const config = new BrowserConfig(apiKey);\n    const warn = jest.spyOn(config.loggerProvider, 'warn').mockImplementationOnce(() => undefined);\n    detNotify(config);\n    expect(warn).toHaveBeenCalledTimes(1);\n    expect(warn).toHaveBeenCalledWith(\n      `\\`options.defaultTracking\\` is set to undefined. This implicitly configures your Amplitude instance to track Page Views, Sessions, File Downloads, and Form Interactions. You can suppress this warning by explicitly setting a value to \\`options.defaultTracking\\`. The value must either be a boolean, to enable and disable all default events, or an object, for advanced configuration. For example:\n\namplitude.init(<YOUR_API_KEY>, {\n  defaultTracking: true,\n});\n\nVisit https://www.docs.developers.amplitude.com/data/sdks/browser-2/#tracking-default-events for more details.`,\n    );\n\n    detNotify(config);\n    // call count still at 1\n    expect(warn).toHaveBeenCalledTimes(1);\n  });\n\n  test('should handle defined config', () => {\n    const config = new BrowserConfig(apiKey, undefined, undefined, undefined, true);\n    const warn = jest.spyOn(config.loggerProvider, 'warn').mockImplementationOnce(() => undefined);\n    detNotify(config);\n    expect(warn).toHaveBeenCalledTimes(0);\n  });\n});\n"
  },
  {
    "path": "packages/analytics-browser/test/helpers/constants.ts",
    "content": "export const uuidPattern = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/;\n"
  },
  {
    "path": "packages/analytics-browser/test/helpers/mock.ts",
    "content": "import {\n  Logger,\n  MemoryStorage,\n  UUID,\n  LogLevel,\n  UserSession,\n  BrowserClient,\n  BrowserConfig,\n} from '@amplitude/analytics-core';\n\nexport const createAmplitudeMock = (): jest.MockedObject<BrowserClient> => ({\n  init: jest.fn(),\n  add: jest.fn(),\n  remove: jest.fn(),\n  track: jest.fn(),\n  logEvent: jest.fn(),\n  identify: jest.fn(),\n  groupIdentify: jest.fn(),\n  setGroup: jest.fn(),\n  revenue: jest.fn(),\n  setOptOut: jest.fn(),\n  getOptOut: jest.fn(),\n  getIdentity: jest.fn(),\n  setIdentity: jest.fn(),\n  flush: jest.fn(),\n  getUserId: jest.fn(),\n  setUserId: jest.fn(),\n  getDeviceId: jest.fn(),\n  setDeviceId: jest.fn(),\n  getSessionId: jest.fn(),\n  setSessionId: jest.fn(),\n  extendSession: jest.fn(),\n  reset: jest.fn(),\n  setTransport: jest.fn(),\n  _setDiagnosticsSampleRate: jest.fn(),\n});\n\nexport const createConfigurationMock = (options?: Partial<BrowserConfig>) => {\n  const apiKey = options?.apiKey ?? UUID();\n  const cookieStorage = new MemoryStorage<UserSession>();\n\n  return {\n    // core config\n    apiKey: apiKey,\n    flushIntervalMillis: 1000,\n    flushMaxRetries: 5,\n    flushQueueSize: 10,\n    logLevel: LogLevel.Warn,\n    loggerProvider: new Logger(),\n    minIdLength: undefined,\n    offline: false,\n    optOut: false,\n    plan: undefined,\n    ingestionMetadata: undefined,\n    serverUrl: undefined,\n    serverZone: undefined,\n    storageProvider: {\n      isEnabled: async () => true,\n      get: jest.fn(),\n      set: jest.fn(),\n      remove: jest.fn(),\n      reset: jest.fn(),\n      getRaw: jest.fn(),\n    },\n    transportProvider: {\n      send: jest.fn(),\n    },\n    useBatch: false,\n\n    // browser config\n    appVersion: undefined,\n    attribution: undefined,\n    deviceId: undefined,\n    cookieExpiration: 365,\n    cookieSameSite: 'Lax',\n    cookieSecure: false,\n    cookieStorage: cookieStorage,\n    cookieUpgrade: undefined,\n    disableCookies: false,\n    domain: '',\n    lastEventTime: undefined,\n    partnerId: undefined,\n    sessionId: undefined,\n    sessionManager: sessionStorage,\n    sessionTimeout: 30 * 60 * 1000,\n    trackingOptions: {\n      ipAddress: true,\n      language: true,\n      platform: true,\n    },\n    trackingSessionEvents: false,\n    userId: undefined,\n    ...options,\n  };\n};\n"
  },
  {
    "path": "packages/analytics-browser/test/index.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unsafe-member-access */\nimport * as amplitude from '../src/index';\nimport { FakeBrowserClient } from './utils/fake-browser-client';\n\nconst {\n  add,\n  createInstance,\n  extendSession,\n  flush,\n  getDeviceId,\n  getSessionId,\n  getUserId,\n  groupIdentify,\n  Identify,\n  identify,\n  init,\n  logEvent,\n  remove,\n  reset,\n  Revenue,\n  revenue,\n  runQueuedFunctions,\n  setDeviceId,\n  setGroup,\n  setOptOut,\n  setSessionId,\n  setTransport,\n  setUserId,\n  track,\n  AmplitudeBrowser,\n  trackVideo,\n} = amplitude;\n\ndescribe('index', () => {\n  test(`structural typing test, 'default export' should be  BrowserClient`, () => {\n    for (const key of Object.keys(FakeBrowserClient.prototype)) {\n      // add message for if it fails\n      if (!(amplitude as any)[key]) {\n        throw new Error(\n          `'${key}' is a required method in BrowserClient but is not defined in analytics-browser export`,\n        );\n      }\n    }\n    // sanity test a few known methods\n    expect(typeof amplitude.add).toBe('function');\n    expect(typeof amplitude.getIdentity).toBe('function');\n    expect(typeof amplitude.track).toBe('function');\n    expect(typeof (amplitude as any).foo).toBe('undefined');\n  });\n\n  test('should expose apis', () => {\n    expect(typeof add).toBe('function');\n    expect(typeof createInstance).toBe('function');\n    expect(typeof extendSession).toBe('function');\n    expect(typeof flush).toBe('function');\n    expect(typeof groupIdentify).toBe('function');\n    expect(typeof getDeviceId).toBe('function');\n    expect(typeof getSessionId).toBe('function');\n    expect(typeof getUserId).toBe('function');\n    expect(typeof Identify).toBe('function');\n    expect(typeof identify).toBe('function');\n    expect(typeof init).toBe('function');\n    expect(typeof logEvent).toBe('function');\n    expect(typeof remove).toBe('function');\n    expect(typeof Revenue).toBe('function');\n    expect(typeof revenue).toBe('function');\n    expect(typeof reset).toBe('function');\n    expect(typeof runQueuedFunctions).toBe('function');\n    expect(typeof setDeviceId).toBe('function');\n    expect(typeof setGroup).toBe('function');\n    expect(typeof setOptOut).toBe('function');\n    expect(typeof setSessionId).toBe('function');\n    expect(typeof setTransport).toBe('function');\n    expect(typeof setUserId).toBe('function');\n    expect(typeof track).toBe('function');\n    expect(typeof AmplitudeBrowser).toBe('function');\n    expect(typeof trackVideo).toBe('function');\n  });\n});\n"
  },
  {
    "path": "packages/analytics-browser/test/plugins/context.test.ts",
    "content": "import { BrowserConfig } from '../../src/config';\nimport { Context } from '../../src/plugins/context';\nimport { UUID } from '@amplitude/analytics-core';\n\ndescribe('context', () => {\n  let apiKey = '';\n\n  beforeEach(() => {\n    apiKey = UUID();\n  });\n\n  describe('setup', () => {\n    test('should setup plugin', async () => {\n      const context = new Context();\n      const config = new BrowserConfig(apiKey);\n      config.appVersion = '1.0.0';\n      config.lastEventId = 1;\n      await context.setup(config);\n      expect(context.config.appVersion).toEqual('1.0.0');\n    });\n\n    test('should setup plugin without app version', async () => {\n      const context = new Context();\n      const config = new BrowserConfig(apiKey);\n      await context.setup(config);\n      expect(context.config.appVersion).toBeUndefined();\n    });\n  });\n\n  describe('execute', () => {\n    test('should execute plugin', async () => {\n      const context = new Context();\n      const config = new BrowserConfig(apiKey);\n      config.appVersion = '1.0.0';\n      config.deviceId = 'deviceId';\n      config.sessionId = 1;\n      config.userId = 'user@amplitude.com';\n      await context.setup(config);\n\n      const event = {\n        event_type: 'event_type',\n      };\n      const firstContextEvent = await context.execute(event);\n      expect(firstContextEvent.app_version).toEqual('1.0.0');\n      expect(firstContextEvent.event_id).toEqual(0);\n      expect(firstContextEvent.event_type).toEqual('event_type');\n      expect(firstContextEvent.insert_id).toBeDefined();\n      expect(firstContextEvent.platform).toEqual('Web');\n      expect(firstContextEvent.language).toBeDefined();\n      expect(firstContextEvent.ip).toEqual('$remote');\n      expect(firstContextEvent.device_id).toEqual('deviceId');\n      expect(firstContextEvent.session_id).toEqual(1);\n      expect(firstContextEvent.user_id).toEqual('user@amplitude.com');\n\n      const secondContextEvent = await context.execute(event);\n      expect(secondContextEvent.event_id).toEqual(1);\n    });\n\n    test('should not return the properties when the tracking options are false', async () => {\n      const context = new Context();\n      const config = new BrowserConfig(apiKey);\n      config.appVersion = '1.0.0';\n      config.deviceId = 'deviceId';\n      config.sessionId = 1;\n      config.trackingOptions = {\n        ipAddress: false,\n        language: false,\n        platform: false,\n      };\n      config.userId = 'user@amplitude.com';\n      await context.setup(config);\n\n      const event = {\n        event_type: 'event_type',\n      };\n      const firstContextEvent = await context.execute(event);\n      expect(firstContextEvent.app_version).toEqual('1.0.0');\n      expect(firstContextEvent.event_id).toEqual(0);\n      expect(firstContextEvent.event_type).toEqual('event_type');\n      expect(firstContextEvent.insert_id).toBeDefined();\n\n      // tracking options should not be included\n      expect(firstContextEvent.platform).toBeUndefined();\n      expect(firstContextEvent.language).toBeUndefined();\n      expect(firstContextEvent.ip).toBeUndefined();\n      expect(firstContextEvent.device_id).toEqual('deviceId');\n      expect(firstContextEvent.session_id).toEqual(1);\n      expect(firstContextEvent.user_id).toEqual('user@amplitude.com');\n\n      const secondContextEvent = await context.execute(event);\n      expect(secondContextEvent.event_id).toEqual(1);\n    });\n\n    test('should be overwritten by the context', async () => {\n      const context = new Context();\n      const config = new BrowserConfig(apiKey);\n      config.appVersion = '1.0.0';\n      config.deviceId = 'deviceId';\n      config.sessionId = 1;\n      config.userId = 'user@amplitude.com';\n      await context.setup(config);\n\n      const event = {\n        event_type: 'event_type',\n        device_id: 'new deviceId',\n      };\n      const firstContextEvent = await context.execute({\n        ...event,\n        event_id: 100,\n      });\n      expect(firstContextEvent.app_version).toEqual('1.0.0');\n      expect(firstContextEvent.event_id).toEqual(100);\n      expect(firstContextEvent.event_type).toEqual('event_type');\n      expect(firstContextEvent.insert_id).toBeDefined();\n      expect(firstContextEvent.device_id).toEqual('new deviceId');\n\n      const secondContextEvent = await context.execute(event);\n      expect(secondContextEvent.event_id).toEqual(101);\n    });\n\n    describe('ingestionMetadata config', () => {\n      test('should include ingestion metadata', async () => {\n        const sourceName = 'ampli';\n        const sourceVersion = '2.0.0';\n        const context = new Context();\n        const config = new BrowserConfig(apiKey);\n        config.ingestionMetadata = {\n          sourceName,\n          sourceVersion,\n        };\n        config.userId = 'user@amplitude.com';\n        await context.setup(config);\n\n        const event = {\n          event_type: 'event_type',\n        };\n        const firstContextEvent = await context.execute(event);\n        expect(firstContextEvent.event_id).toEqual(0);\n        expect(firstContextEvent.event_type).toEqual('event_type');\n        expect(firstContextEvent.ingestion_metadata?.source_name).toEqual(sourceName);\n        expect(firstContextEvent.ingestion_metadata?.source_version).toEqual(sourceVersion);\n      });\n\n      test('sourceName should be optional', async () => {\n        const sourceVersion = '2.0.0';\n        const context = new Context();\n        const config = new BrowserConfig(apiKey);\n        config.ingestionMetadata = {\n          sourceVersion,\n        };\n        config.userId = 'user@amplitude.com';\n        await context.setup(config);\n\n        const event = {\n          event_type: 'event_type',\n        };\n        const firstContextEvent = await context.execute(event);\n        expect(firstContextEvent.event_id).toEqual(0);\n        expect(firstContextEvent.ingestion_metadata?.source_name).toBeUndefined();\n        expect(firstContextEvent.ingestion_metadata?.source_version).toEqual(sourceVersion);\n      });\n\n      test('sourceVersion should be optional', async () => {\n        const sourceName = 'ampli';\n        const context = new Context();\n        const config = new BrowserConfig(apiKey);\n        config.ingestionMetadata = {\n          sourceName,\n        };\n        config.userId = 'user@amplitude.com';\n        await context.setup(config);\n\n        const event = {\n          event_type: 'event_type',\n        };\n        const firstContextEvent = await context.execute(event);\n        expect(firstContextEvent.event_id).toEqual(0);\n        expect(firstContextEvent.ingestion_metadata?.source_name).toEqual(sourceName);\n        expect(firstContextEvent.ingestion_metadata?.source_version).toBeUndefined();\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-browser/test/plugins/file-download-tracking.test.ts",
    "content": "/* eslint-disable @typescript-eslint/unbound-method */\n\nimport { createAmplitudeMock, createConfigurationMock } from '../helpers/mock';\nimport { fileDownloadTracking } from '../../src/plugins/file-download-tracking';\nimport { FILE_EXTENSION, FILE_NAME, LINK_ID, LINK_TEXT, LINK_URL } from '../../src/constants';\n\ndescribe('fileDownloadTracking', () => {\n  let amplitude = createAmplitudeMock();\n\n  beforeEach(() => {\n    amplitude = createAmplitudeMock();\n\n    const link = document.createElement('a');\n    link.setAttribute('id', 'my-link-id');\n    link.setAttribute('class', 'my-link-class');\n    link.text = 'my-link-text';\n\n    document.body.appendChild(link);\n  });\n\n  afterEach(() => {\n    document.querySelector('a#my-link-id')?.remove();\n  });\n\n  test.each([\n    'https://analytics.amplitude.com/files/my-file.pdf',\n    'https://analytics.amplitude.com/files/my-file.pdf?foo=bar',\n  ])('should track file_download event', async (value) => {\n    // setup\n    document.getElementById('my-link-id')?.setAttribute('href', value);\n    const config = createConfigurationMock();\n    const plugin = fileDownloadTracking();\n    await plugin.setup?.(config, amplitude);\n    window.dispatchEvent(new Event('load'));\n\n    // trigger click event\n    document.getElementById('my-link-id')?.dispatchEvent(new Event('click'));\n\n    // assert file download event was tracked\n    expect(amplitude.track).toHaveBeenCalledTimes(1);\n    expect(amplitude.track).toHaveBeenNthCalledWith(1, '[Amplitude] File Downloaded', {\n      [FILE_EXTENSION]: 'pdf',\n      [FILE_NAME]: '/files/my-file.pdf',\n      [LINK_ID]: 'my-link-id',\n      [LINK_TEXT]: 'my-link-text',\n      [LINK_URL]: value,\n    });\n\n    // stop observer and listeners\n    await plugin.teardown?.();\n\n    // trigger click event\n    document.getElementById('my-link-id')?.dispatchEvent(new Event('click'));\n\n    // assert no additional event was tracked\n    expect(amplitude.track).toHaveBeenCalledTimes(1);\n  });\n\n  test('should track file_download event for a dynamically added achor tag', async () => {\n    // setup\n    const config = createConfigurationMock();\n    const plugin = fileDownloadTracking();\n    await plugin.setup?.(config, amplitude);\n    window.dispatchEvent(new Event('load'));\n\n    // add anchor element dynamically\n    const link = document.createElement('a');\n    link.setAttribute('id', 'my-link-2-id');\n    link.setAttribute('class', 'my-link-2-class');\n    link.setAttribute('href', 'https://analytics.amplitude.com/files/my-file-2.pdf');\n    link.text = 'my-link-2-text';\n    document.body.appendChild(link);\n\n    // allow mutation observer to execute and event listener to be attached\n    await new Promise((r) => r(undefined)); // basically, await next clock tick\n    // trigger change event\n    link.dispatchEvent(new Event('click'));\n\n    // assert file download event was tracked\n    expect(amplitude.track).toHaveBeenCalledTimes(1);\n    expect(amplitude.track).toHaveBeenNthCalledWith(1, '[Amplitude] File Downloaded', {\n      [FILE_EXTENSION]: 'pdf',\n      [FILE_NAME]: '/files/my-file-2.pdf',\n      [LINK_ID]: 'my-link-2-id',\n      [LINK_TEXT]: 'my-link-2-text',\n      [LINK_URL]: 'https://analytics.amplitude.com/files/my-file-2.pdf',\n    });\n\n    // stop observer and listeners\n    await plugin.teardown?.();\n\n    // add anchor element dynamically\n    const link3 = document.createElement('a');\n    link3.setAttribute('id', 'my-link-3-id');\n    link3.setAttribute('class', 'my-link-3-class');\n    link3.setAttribute('href', 'https://analytics.amplitude.com/files/my-file-3.pdf');\n    link3.text = 'my-link-3-text';\n    document.body.appendChild(link3);\n\n    // allow mutation observer to execute and event listener to be attached\n    await new Promise((r) => r(undefined)); // basically, await next clock tick\n    // trigger change event\n    link.dispatchEvent(new Event('click'));\n\n    // assert no additional file download event was tracked\n    expect(amplitude.track).toHaveBeenCalledTimes(1);\n  });\n\n  test('should track file_download event for a dynamically added nested achor tag', async () => {\n    // setup\n    const config = createConfigurationMock();\n    const plugin = fileDownloadTracking();\n    await plugin.setup?.(config, amplitude);\n    window.dispatchEvent(new Event('load'));\n\n    // add anchor element dynamically\n    const link = document.createElement('a');\n    link.setAttribute('id', 'my-link-2-id');\n    link.setAttribute('class', 'my-link-2-class');\n    link.setAttribute('href', 'https://analytics.amplitude.com/files/my-file-2.pdf');\n    link.text = 'my-link-2-text';\n\n    // add parent element\n    const div = document.createElement('div');\n\n    div.appendChild(link);\n    document.body.appendChild(div);\n\n    // allow mutation observer to execute and event listener to be attached\n    await new Promise((r) => r(undefined)); // basically, await next clock tick\n    // trigger change event\n    link.dispatchEvent(new Event('click'));\n\n    // assert file download event was tracked\n    expect(amplitude.track).toHaveBeenCalledTimes(1);\n    expect(amplitude.track).toHaveBeenNthCalledWith(1, '[Amplitude] File Downloaded', {\n      [FILE_EXTENSION]: 'pdf',\n      [FILE_NAME]: '/files/my-file-2.pdf',\n      [LINK_ID]: 'my-link-2-id',\n      [LINK_TEXT]: 'my-link-2-text',\n      [LINK_URL]: 'https://analytics.amplitude.com/files/my-file-2.pdf',\n    });\n  });\n\n  test('should track file download event when the plugin is added after window load', async () => {\n    // setup\n    document.getElementById('my-link-id')?.setAttribute('href', 'https://analytics.amplitude.com/files/my-file.pdf');\n    const config = createConfigurationMock();\n    const plugin = fileDownloadTracking();\n    await plugin.setup?.(config, amplitude);\n\n    // trigger change event\n    document.getElementById('my-link-id')?.dispatchEvent(new Event('click'));\n\n    // assert first event was tracked\n    expect(amplitude.track).toHaveBeenCalledTimes(1);\n  });\n\n  test('should track form_start event when the plugin is added before window load', async () => {\n    const originalReadyState = document.readyState;\n    Object.defineProperty(document, 'readyState', {\n      value: 'loading',\n      writable: true,\n      configurable: true,\n    });\n\n    // setup\n    document.getElementById('my-link-id')?.setAttribute('href', 'https://analytics.amplitude.com/files/my-file.pdf');\n    const config = createConfigurationMock();\n    const plugin = fileDownloadTracking();\n    await plugin.setup?.(config, amplitude);\n\n    // trigger change event\n    window.dispatchEvent(new Event('load'));\n    document.getElementById('my-link-id')?.dispatchEvent(new Event('click'));\n\n    // assert first event was tracked\n    expect(amplitude.track).toHaveBeenCalledTimes(1);\n\n    // Restore the original value after each test\n    Object.defineProperty(document, 'readyState', {\n      value: originalReadyState,\n      writable: true,\n    });\n  });\n\n  test('should not enrich events', async () => {\n    const input = {\n      event_type: 'page_view',\n    };\n    const plugin = fileDownloadTracking();\n    const result = await plugin.execute?.(input);\n    expect(result).toEqual(input);\n  });\n\n  // eslint-disable-next-line jest/expect-expect\n  test('should teardown plugin', async () => {\n    const plugin = fileDownloadTracking();\n    await plugin.teardown?.();\n    // no explicit assertion\n    // test asserts that no error is thrown\n  });\n});\n"
  },
  {
    "path": "packages/analytics-browser/test/plugins/form-interaction-tracking.test.ts",
    "content": "/* eslint-disable @typescript-eslint/unbound-method */\n\nimport { createAmplitudeMock, createConfigurationMock } from '../helpers/mock';\nimport { formInteractionTracking } from '../../src/plugins/form-interaction-tracking';\nimport { FORM_DESTINATION, FORM_ID, FORM_NAME } from '../../src/constants';\n\n// SubmitEvent is not available in JSDOM, so we need to polyfill it\nif (typeof SubmitEvent === 'undefined') {\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  (global as any).SubmitEvent = function SubmitEvent(\n    this: Event & { submitter: HTMLElement | null },\n    type: string,\n    eventInitDict?: SubmitEventInit,\n  ) {\n    const event = new Event(type, eventInitDict);\n    Object.setPrototypeOf(event, SubmitEvent.prototype);\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    (event as any).submitter = eventInitDict?.submitter ?? null;\n    return event;\n  };\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  (global as any).SubmitEvent.prototype = Object.create(Event.prototype);\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  (global as any).SubmitEvent.prototype.constructor = (global as any).SubmitEvent;\n}\n\ndescribe('formInteractionTracking', () => {\n  let amplitude = createAmplitudeMock();\n\n  beforeEach(() => {\n    amplitude = createAmplitudeMock();\n\n    const form = document.createElement('form');\n    form.setAttribute('id', 'my-form-id');\n    form.setAttribute('name', 'my-form-name');\n    form.setAttribute('action', '/submit');\n\n    const text = document.createElement('input');\n    text.setAttribute('type', 'text');\n    text.setAttribute('id', 'my-text-id');\n\n    const submit = document.createElement('input');\n    submit.setAttribute('type', 'submit');\n    submit.setAttribute('id', 'my-submit-id');\n\n    form.appendChild(text);\n    form.appendChild(submit);\n    document.body.appendChild(form);\n  });\n\n  afterEach(() => {\n    document.querySelector('form#my-form-id')?.remove();\n  });\n\n  test('should track form_start event when the plugin is added after window load', async () => {\n    // setup\n    const config = createConfigurationMock();\n    const plugin = formInteractionTracking();\n    await plugin.setup?.(config, amplitude);\n\n    // trigger change event\n    document.getElementById('my-form-id')?.dispatchEvent(new Event('change'));\n\n    // assert first event was tracked\n    expect(amplitude.track).toHaveBeenCalledTimes(1);\n  });\n\n  test('should track form_start event when the plugin is added before window load', async () => {\n    const originalReadyState = document.readyState;\n    Object.defineProperty(document, 'readyState', {\n      value: 'loading',\n      writable: true,\n      configurable: true,\n    });\n\n    // setup\n    const config = createConfigurationMock();\n    const plugin = formInteractionTracking();\n    await plugin.setup?.(config, amplitude);\n\n    // trigger change event\n    window.dispatchEvent(new Event('load'));\n    document.getElementById('my-form-id')?.dispatchEvent(new Event('change'));\n\n    // assert first event was tracked\n    expect(amplitude.track).toHaveBeenCalledTimes(1);\n\n    // Restore the original value after each test\n    Object.defineProperty(document, 'readyState', {\n      value: originalReadyState,\n      writable: true,\n    });\n  });\n\n  test('should track form_start event', async () => {\n    // setup\n    const config = createConfigurationMock();\n    const plugin = formInteractionTracking();\n    await plugin.setup?.(config, amplitude);\n    window.dispatchEvent(new Event('load'));\n\n    // trigger change event\n    document.getElementById('my-form-id')?.dispatchEvent(new Event('change'));\n\n    // assert first event was tracked\n    expect(amplitude.track).toHaveBeenCalledTimes(1);\n    expect(amplitude.track).toHaveBeenNthCalledWith(1, '[Amplitude] Form Started', {\n      [FORM_ID]: 'my-form-id',\n      [FORM_NAME]: 'my-form-name',\n      [FORM_DESTINATION]: 'http://localhost/submit',\n    });\n\n    // trigger change event again\n    document.getElementById('my-form-id')?.dispatchEvent(new Event('change'));\n\n    // assert second event was not tracked\n    expect(amplitude.track).toHaveBeenCalledTimes(1);\n  });\n\n  test('should return current location if form action attribute is missing', async () => {\n    // setup\n    const config = createConfigurationMock();\n    const plugin = formInteractionTracking();\n    await plugin.setup?.(config, amplitude);\n    window.dispatchEvent(new Event('load'));\n\n    // Remove form action\n    document.getElementById('my-form-id')?.removeAttribute('action');\n    // trigger change event\n    document.getElementById('my-form-id')?.dispatchEvent(new Event('change'));\n    // assert first event was tracked\n    expect(amplitude.track).toHaveBeenCalledTimes(1);\n    expect(amplitude.track).toHaveBeenNthCalledWith(1, '[Amplitude] Form Started', {\n      [FORM_ID]: 'my-form-id',\n      [FORM_NAME]: 'my-form-name',\n      [FORM_DESTINATION]: 'http://localhost/',\n    });\n    // trigger change event again\n    document.getElementById('my-form-id')?.dispatchEvent(new Event('change'));\n    // assert second event was not tracked\n    expect(amplitude.track).toHaveBeenCalledTimes(1);\n  });\n\n  test('should track form_start event for a dynamically added form tag', async () => {\n    // setup\n    const config = createConfigurationMock();\n    const plugin = formInteractionTracking();\n    await plugin.setup?.(config, amplitude);\n    window.dispatchEvent(new Event('load'));\n\n    // add form element dynamically\n    const form = document.createElement('form');\n    form.setAttribute('id', 'my-form-2-id');\n    form.setAttribute('name', 'my-form-2-name');\n    form.setAttribute('action', '/submit');\n\n    const text = document.createElement('input');\n    text.setAttribute('type', 'text');\n    text.setAttribute('id', 'my-text-2-id');\n\n    const submit = document.createElement('input');\n    submit.setAttribute('type', 'submit');\n    submit.setAttribute('id', 'my-submit-2-id');\n\n    form.appendChild(text);\n    form.appendChild(submit);\n    document.body.appendChild(form);\n\n    // allow mutation observer to execute and event listener to be attached\n    await new Promise((r) => r(undefined)); // basically, await next clock tick\n    // trigger change event\n    form.dispatchEvent(new Event('change'));\n\n    // assert first event was tracked\n    expect(amplitude.track).toHaveBeenCalledTimes(1);\n    expect(amplitude.track).toHaveBeenNthCalledWith(1, '[Amplitude] Form Started', {\n      [FORM_ID]: 'my-form-2-id',\n      [FORM_NAME]: 'my-form-2-name',\n      [FORM_DESTINATION]: 'http://localhost/submit',\n    });\n\n    // trigger change event again\n    form.dispatchEvent(new Event('change'));\n\n    // assert second event was not tracked\n    expect(amplitude.track).toHaveBeenCalledTimes(1);\n\n    // stop observer and listeners\n    await plugin.teardown?.();\n\n    // add form element dynamically\n    const form3 = document.createElement('form');\n    form3.setAttribute('id', 'my-form-3-id');\n    form3.setAttribute('name', 'my-form-3-name');\n    form3.setAttribute('action', '/submit');\n\n    const text3 = document.createElement('input');\n    text3.setAttribute('type', 'text');\n    text3.setAttribute('id', 'my-text-3-id');\n\n    const submit3 = document.createElement('input');\n    submit3.setAttribute('type', 'submit');\n    submit3.setAttribute('id', 'my-submit-3-id');\n\n    form3.appendChild(text3);\n    form3.appendChild(submit3);\n    document.body.appendChild(form3);\n\n    // allow mutation observer to execute and event listener to be attached\n    await new Promise((r) => r(undefined)); // basically, await next clock tick\n    // trigger change event\n    form3.dispatchEvent(new Event('change'));\n\n    // assert no additional event was tracked\n    expect(amplitude.track).toHaveBeenCalledTimes(1);\n  });\n\n  test('should track form_start event for a dynamically added nested form tag', async () => {\n    // setup\n    const config = createConfigurationMock();\n    const plugin = formInteractionTracking();\n    await plugin.setup?.(config, amplitude);\n    window.dispatchEvent(new Event('load'));\n\n    // add form element dynamically\n    const form = document.createElement('form');\n    form.setAttribute('id', 'my-form-2-id');\n    form.setAttribute('name', 'my-form-2-name');\n    form.setAttribute('action', '/submit');\n\n    const text = document.createElement('input');\n    text.setAttribute('type', 'text');\n    text.setAttribute('id', 'my-text-2-id');\n\n    const submit = document.createElement('input');\n    submit.setAttribute('type', 'submit');\n    submit.setAttribute('id', 'my-submit-2-id');\n\n    form.appendChild(text);\n    form.appendChild(submit);\n\n    const div = document.createElement('div');\n    div.appendChild(form);\n\n    document.body.appendChild(div);\n\n    // allow mutation observer to execute and event listener to be attached\n    await new Promise((r) => r(undefined)); // basically, await next clock tick\n    // trigger change event\n    form.dispatchEvent(new Event('change'));\n\n    // assert first event was tracked\n    expect(amplitude.track).toHaveBeenCalledTimes(1);\n    expect(amplitude.track).toHaveBeenNthCalledWith(1, '[Amplitude] Form Started', {\n      [FORM_ID]: 'my-form-2-id',\n      [FORM_NAME]: 'my-form-2-name',\n      [FORM_DESTINATION]: 'http://localhost/submit',\n    });\n\n    // trigger change event again\n    form.dispatchEvent(new Event('change'));\n\n    // assert second event was not tracked\n    expect(amplitude.track).toHaveBeenCalledTimes(1);\n  });\n\n  test('should track form_start and form_submit events on change and submit', async () => {\n    // setup\n    const config = createConfigurationMock();\n    const plugin = formInteractionTracking();\n    await plugin.setup?.(config, amplitude);\n    window.dispatchEvent(new Event('load'));\n\n    // trigger change event again\n    document.getElementById('my-form-id')?.dispatchEvent(new Event('change'));\n\n    // assert first event was tracked\n    expect(amplitude.track).toHaveBeenCalledTimes(1);\n    expect(amplitude.track).toHaveBeenNthCalledWith(1, '[Amplitude] Form Started', {\n      [FORM_ID]: 'my-form-id',\n      [FORM_NAME]: 'my-form-name',\n      [FORM_DESTINATION]: 'http://localhost/submit',\n    });\n\n    // trigger submit event\n    document.getElementById('my-form-id')?.dispatchEvent(new Event('submit'));\n\n    // assert second event was tracked\n    expect(amplitude.track).toHaveBeenCalledTimes(2);\n    expect(amplitude.track).toHaveBeenNthCalledWith(2, '[Amplitude] Form Submitted', {\n      [FORM_ID]: 'my-form-id',\n      [FORM_NAME]: 'my-form-name',\n      [FORM_DESTINATION]: 'http://localhost/submit',\n    });\n  });\n\n  test('should track form_start and form_submit events on submit only', async () => {\n    // setup\n    const config = createConfigurationMock();\n    const plugin = formInteractionTracking();\n    await plugin.setup?.(config, amplitude);\n    window.dispatchEvent(new Event('load'));\n\n    // trigger change event\n    document.getElementById('my-form-id')?.dispatchEvent(new Event('submit'));\n\n    // assert both events were tracked\n    expect(amplitude.track).toHaveBeenCalledTimes(2);\n    expect(amplitude.track).toHaveBeenNthCalledWith(1, '[Amplitude] Form Started', {\n      [FORM_ID]: 'my-form-id',\n      [FORM_NAME]: 'my-form-name',\n      [FORM_DESTINATION]: 'http://localhost/submit',\n    });\n    expect(amplitude.track).toHaveBeenNthCalledWith(2, '[Amplitude] Form Submitted', {\n      [FORM_ID]: 'my-form-id',\n      [FORM_NAME]: 'my-form-name',\n      [FORM_DESTINATION]: 'http://localhost/submit',\n    });\n\n    // stop observer and listeners\n    await plugin.teardown?.();\n\n    // trigger change event\n    document.getElementById('my-form-id')?.dispatchEvent(new Event('submit'));\n\n    // assert no additional event was tracked\n    expect(amplitude.track).toHaveBeenCalledTimes(2);\n  });\n\n  test('should not enrich events', async () => {\n    const input = {\n      event_type: 'page_view',\n    };\n    const plugin = formInteractionTracking();\n    const result = await plugin.execute?.(input);\n    expect(result).toEqual(input);\n  });\n\n  // eslint-disable-next-line jest/expect-expect\n  test('should teardown plugin', async () => {\n    const plugin = formInteractionTracking();\n    await plugin.teardown?.();\n    // no explicit assertion\n    // test asserts that no error is thrown\n  });\n\n  describe('shouldTrackSubmit', () => {\n    test('should not track form_submit when shouldTrackSubmit returns false', async () => {\n      const shouldTrackSubmit = jest.fn(() => false);\n      const config = createConfigurationMock({\n        defaultTracking: {\n          formInteractions: {\n            shouldTrackSubmit,\n          },\n        },\n      });\n      const plugin = formInteractionTracking();\n      await plugin.setup?.(config, amplitude);\n      window.dispatchEvent(new Event('load'));\n\n      // trigger submit event with SubmitEvent\n      document.getElementById('my-form-id')?.dispatchEvent(new SubmitEvent('submit'));\n\n      // assert shouldTrackSubmit was called\n      expect(shouldTrackSubmit).toHaveBeenCalledTimes(1);\n\n      // assert form_start was tracked but form_submit was NOT\n      expect(amplitude.track).toHaveBeenCalledTimes(1);\n      expect(amplitude.track).toHaveBeenNthCalledWith(1, '[Amplitude] Form Started', {\n        [FORM_ID]: 'my-form-id',\n        [FORM_NAME]: 'my-form-name',\n        [FORM_DESTINATION]: 'http://localhost/submit',\n      });\n    });\n\n    test('should not re-track form_start on subsequent submit when shouldTrackSubmit returns false', async () => {\n      const shouldTrackSubmit = jest.fn(() => false);\n      const config = createConfigurationMock({\n        defaultTracking: {\n          formInteractions: {\n            shouldTrackSubmit,\n          },\n        },\n      });\n      const plugin = formInteractionTracking();\n      await plugin.setup?.(config, amplitude);\n      window.dispatchEvent(new Event('load'));\n\n      // trigger first submit event (tracks form_start)\n      document.getElementById('my-form-id')?.dispatchEvent(new SubmitEvent('submit'));\n      expect(amplitude.track).toHaveBeenCalledTimes(1);\n\n      // trigger second submit event (should NOT track form_start again)\n      document.getElementById('my-form-id')?.dispatchEvent(new SubmitEvent('submit'));\n\n      // assert shouldTrackSubmit was called twice\n      expect(shouldTrackSubmit).toHaveBeenCalledTimes(2);\n\n      // assert form_start was only tracked once (no duplicate)\n      expect(amplitude.track).toHaveBeenCalledTimes(1);\n    });\n\n    test('should track form_submit when shouldTrackSubmit returns true', async () => {\n      const shouldTrackSubmit = jest.fn(() => true);\n      const config = createConfigurationMock({\n        defaultTracking: {\n          formInteractions: {\n            shouldTrackSubmit,\n          },\n        },\n      });\n      const plugin = formInteractionTracking();\n      await plugin.setup?.(config, amplitude);\n      window.dispatchEvent(new Event('load'));\n\n      // trigger submit event with SubmitEvent\n      document.getElementById('my-form-id')?.dispatchEvent(new SubmitEvent('submit'));\n\n      // assert shouldTrackSubmit was called\n      expect(shouldTrackSubmit).toHaveBeenCalledTimes(1);\n\n      // assert both form_start and form_submit were tracked\n      expect(amplitude.track).toHaveBeenCalledTimes(2);\n      expect(amplitude.track).toHaveBeenNthCalledWith(2, '[Amplitude] Form Submitted', {\n        [FORM_ID]: 'my-form-id',\n        [FORM_NAME]: 'my-form-name',\n        [FORM_DESTINATION]: 'http://localhost/submit',\n      });\n    });\n\n    test('should track form_submit normally when shouldTrackSubmit is not provided', async () => {\n      const config = createConfigurationMock({\n        defaultTracking: {\n          formInteractions: {},\n        },\n      });\n      const plugin = formInteractionTracking();\n      await plugin.setup?.(config, amplitude);\n      window.dispatchEvent(new Event('load'));\n\n      // trigger submit event\n      document.getElementById('my-form-id')?.dispatchEvent(new Event('submit'));\n\n      // assert both form_start and form_submit were tracked\n      expect(amplitude.track).toHaveBeenCalledTimes(2);\n      expect(amplitude.track).toHaveBeenNthCalledWith(2, '[Amplitude] Form Submitted', {\n        [FORM_ID]: 'my-form-id',\n        [FORM_NAME]: 'my-form-name',\n        [FORM_DESTINATION]: 'http://localhost/submit',\n      });\n    });\n\n    test('should log warning and proceed with tracking when shouldTrackSubmit throws an error', async () => {\n      const shouldTrackSubmit = jest.fn(() => {\n        throw new Error('Test error');\n      });\n      const config = createConfigurationMock({\n        defaultTracking: {\n          formInteractions: {\n            shouldTrackSubmit,\n          },\n        },\n      });\n      const warnSpy = jest.spyOn(config.loggerProvider, 'warn');\n      const plugin = formInteractionTracking();\n      await plugin.setup?.(config, amplitude);\n      window.dispatchEvent(new Event('load'));\n\n      // trigger submit event with SubmitEvent\n      document.getElementById('my-form-id')?.dispatchEvent(new SubmitEvent('submit'));\n\n      // assert shouldTrackSubmit was called\n      expect(shouldTrackSubmit).toHaveBeenCalledTimes(1);\n\n      // assert warning was logged\n      expect(warnSpy).toHaveBeenCalledWith('shouldTrackSubmit callback threw an error, proceeding with tracking.');\n\n      // assert both form_start and form_submit were still tracked despite the error\n      expect(amplitude.track).toHaveBeenCalledTimes(2);\n      expect(amplitude.track).toHaveBeenNthCalledWith(2, '[Amplitude] Form Submitted', {\n        [FORM_ID]: 'my-form-id',\n        [FORM_NAME]: 'my-form-name',\n        [FORM_DESTINATION]: 'http://localhost/submit',\n      });\n    });\n\n    describe('duplicate form tracking', () => {\n      let plugin: ReturnType<typeof formInteractionTracking>;\n      beforeEach(async () => {\n        const config = createConfigurationMock({\n          defaultTracking: {\n            formInteractions: {\n              shouldTrackSubmit: () => true,\n            },\n          },\n        });\n        plugin = formInteractionTracking();\n        await plugin?.setup?.(config, amplitude);\n        window.dispatchEvent(new Event('load'));\n\n        // create a new form element and add it to the body\n        const form = document.createElement('form');\n        form.setAttribute('id', 'duplicate-form-id');\n        form.setAttribute('name', 'duplicate-form-name');\n        form.setAttribute('action', '/submit');\n        document.body.appendChild(form);\n\n        // move form element to div container\n        // this will cause Form element to show up twice in mutation observer\n        const div = document.createElement('div');\n        div.setAttribute('id', 'duplicate-div-id');\n        div.appendChild(form);\n        document.body.appendChild(div);\n\n        // allow mutation observer to execute and event listener to be attached\n        await new Promise((r) => r(undefined));\n      });\n\n      afterEach(async () => {\n        await plugin?.teardown?.();\n        document.getElementById('duplicate-div-id')?.remove();\n        document.getElementById('duplicate-form-id')?.remove();\n      });\n\n      test('should not track form events more than once', async () => {\n        // trigger submit event with SubmitEvent\n        document.getElementById('duplicate-form-id')?.dispatchEvent(new SubmitEvent('submit'));\n\n        // assert both form_start and form_submit were tracked only once each\n        expect(amplitude.track).toHaveBeenCalledTimes(2);\n        expect(amplitude.track).toHaveBeenNthCalledWith(1, '[Amplitude] Form Started', {\n          [FORM_ID]: 'duplicate-form-id',\n          [FORM_NAME]: 'duplicate-form-name',\n          [FORM_DESTINATION]: 'http://localhost/submit',\n        });\n        expect(amplitude.track).toHaveBeenNthCalledWith(2, '[Amplitude] Form Submitted', {\n          [FORM_ID]: 'duplicate-form-id',\n          [FORM_NAME]: 'duplicate-form-name',\n          [FORM_DESTINATION]: 'http://localhost/submit',\n        });\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-browser/test/plugins/network-connectivity-checker.test.ts",
    "content": "/* eslint-disable @typescript-eslint/unbound-method */\n\nimport { createAmplitudeMock, createConfigurationMock } from '../helpers/mock';\nimport { networkConnectivityCheckerPlugin } from '../../src/plugins/network-connectivity-checker';\nimport * as AnalyticsCore from '@amplitude/analytics-core';\n\ndescribe('networkConnectivityCheckerPlugin', () => {\n  const amplitude = createAmplitudeMock();\n  const config = createConfigurationMock();\n\n  test('should set up correctly when online', async () => {\n    const plugin = networkConnectivityCheckerPlugin();\n    jest.spyOn(navigator, 'onLine', 'get').mockReturnValue(true);\n    const addEventListenerSpy = jest.spyOn(window, 'addEventListener');\n\n    await plugin.setup?.(config, amplitude);\n\n    expect(config.offline).toEqual(false);\n    expect(addEventListenerSpy).toHaveBeenCalledWith('online', expect.any(Function));\n    expect(addEventListenerSpy).toHaveBeenCalledWith('offline', expect.any(Function));\n    addEventListenerSpy.mockRestore();\n  });\n\n  test('should set up correctly when offline', async () => {\n    const plugin = networkConnectivityCheckerPlugin();\n    jest.spyOn(navigator, 'onLine', 'get').mockReturnValue(false);\n    const addEventListenerSpy = jest.spyOn(window, 'addEventListener');\n\n    await plugin.setup?.(config, amplitude);\n\n    expect(config.offline).toEqual(true);\n    expect(addEventListenerSpy).toHaveBeenCalledWith('online', expect.any(Function));\n    expect(addEventListenerSpy).toHaveBeenCalledWith('offline', expect.any(Function));\n    addEventListenerSpy.mockRestore();\n  });\n\n  test('should teardown plugin', async () => {\n    const plugin = networkConnectivityCheckerPlugin();\n    const removeEventListenerSpy = jest.spyOn(window, 'removeEventListener');\n\n    await plugin.setup?.(createConfigurationMock(), amplitude);\n    await plugin.teardown?.();\n\n    expect(removeEventListenerSpy).toHaveBeenCalledWith('online', expect.any(Function));\n    expect(removeEventListenerSpy).toHaveBeenCalledWith('offline', expect.any(Function));\n  });\n\n  test('should do nothing when not on a browser', async () => {\n    const plugin = networkConnectivityCheckerPlugin();\n    // @ts-expect-error we are mocking a node.js environment\n    jest.spyOn(window, 'navigator', 'get').mockReturnValue(undefined);\n    const addEventListenerSpy = jest.spyOn(window, 'addEventListener');\n\n    await plugin.setup?.(config, amplitude);\n\n    expect(config.offline).toEqual(false);\n    expect(addEventListenerSpy).not.toHaveBeenCalled();\n    addEventListenerSpy.mockRestore();\n  });\n\n  test('should not throw if addEventListener is not a function', async () => {\n    const getGlobalScopeMock = jest\n      .spyOn(AnalyticsCore, 'getGlobalScope')\n      .mockReturnValue({} as unknown as typeof globalThis);\n    const plugin = networkConnectivityCheckerPlugin();\n\n    await expect(plugin.setup?.(config, amplitude)).resolves.not.toThrow();\n    await expect(plugin.teardown?.()).resolves.not.toThrow();\n\n    getGlobalScopeMock.mockRestore();\n  });\n\n  test('should not throw if globalScope.addEventListener is not available', async () => {\n    jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({} as unknown as typeof globalThis);\n    const plugin = networkConnectivityCheckerPlugin();\n\n    await expect(plugin.setup?.(config, amplitude)).resolves.not.toThrow();\n  });\n});\n"
  },
  {
    "path": "packages/analytics-browser/test/plugins/page-view-tracking-enrichment.test.ts",
    "content": "import { pageViewTrackingEnrichment } from './page-view-tracking-enrichment';\n\ndescribe('page-view-tracking-enrichment', () => {\n  describe('execute', () => {\n    test('should enrich page view event', async () => {\n      const mockEvent = {\n        event_type: '[Amplitude] Page Viewed',\n      };\n      const plugin = pageViewTrackingEnrichment();\n      const result = await plugin.execute?.(mockEvent);\n      expect(result).toEqual({\n        event_type: '[Amplitude] Page Viewed',\n        event_properties: {\n          new_property: 'new_value',\n        },\n      });\n    });\n\n    test('should not enrich other events', async () => {\n      const mockEvent = {\n        event_type: 'Not Page View',\n      };\n      const plugin = pageViewTrackingEnrichment();\n      const result = await plugin.execute?.(mockEvent);\n      expect(result).toEqual({\n        event_type: 'Not Page View',\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-browser/test/plugins/page-view-tracking-enrichment.ts",
    "content": "import { EnrichmentPlugin, Event } from '@amplitude/analytics-core';\n\n/**\n * This plugin enriches events with event_type \"Page View\" by adding\n * more event_properties on top of what @amplitude/analytics-browser provides out of the box\n *\n * @returns EnrichmentPlugin\n */\nexport const pageViewTrackingEnrichment = (): EnrichmentPlugin => {\n  return {\n    name: 'page-view-tracking-enrichment',\n    type: 'enrichment',\n    setup: async () => undefined,\n    execute: async (event: Event) => {\n      if (event.event_type !== '[Amplitude] Page Viewed') {\n        // event name format if using Autocapture Pageviews\n        return event;\n      }\n      event.event_properties = {\n        ...event.event_properties,\n        // TODO: Add new event properties here\n        new_property: 'new_value',\n      };\n      return event;\n    },\n  };\n};\n"
  },
  {
    "path": "packages/analytics-browser/test/plugins/remove-event-key-enrichment.test.ts",
    "content": "import { removeEventKeyEnrichment } from './remove-event-key-enrichment';\n\ndescribe('remove-event-key-enrichment', () => {\n  describe('execute', () => {\n    test('should remove keys from event payload', async () => {\n      const plugin = removeEventKeyEnrichment(['time']);\n      const mockEvent = {\n        event_type: 'Custom Event',\n        time: Date.now(),\n      };\n      const result = await plugin.execute?.(mockEvent);\n      expect(result?.time).toBeUndefined();\n    });\n\n    test('should not remove keys from event payload', async () => {\n      const plugin = removeEventKeyEnrichment();\n      const mockEvent = {\n        event_type: 'Custom Event',\n        time: Date.now(),\n      };\n      const result = await plugin.execute?.(mockEvent);\n      expect(result?.time).toBeDefined();\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-browser/test/plugins/remove-event-key-enrichment.ts",
    "content": "import { BaseEvent, Event, EnrichmentPlugin } from '@amplitude/analytics-core';\n\ntype KeyOfEvent = keyof BaseEvent;\n\n/**\n * This plugin enriches all events by removing a list of keys from the\n * event payload. This plugin is helpful in cases where users prefer not to use default\n * values set by the @amplitude/analytics-browser library, for example:\n * - `event.time`\n * - `event.idfa`\n * - `event.idva`\n * - `event.ip`\n *\n * @param keysToRemove\n * @returns EnrichmentPlugin\n */\nexport const removeEventKeyEnrichment = (keysToRemove: KeyOfEvent[] = []): EnrichmentPlugin => {\n  return {\n    name: 'remove-event-key-enrichment',\n    type: 'enrichment',\n    setup: async () => undefined,\n    execute: async (event: Event) => {\n      for (const key of keysToRemove) {\n        delete event[key];\n      }\n      return event;\n    },\n  };\n};\n\n/**\n * This plugin enriches all events by removing `event.time` from all events.\n * `event.time` uses `Date.now()` which is controlled by the device where the browser runs on.\n * The device clock can be easily manipulated yielding events having unreasonable time values.\n * With `event.time` being `undefined`, the time of the event is determined when the event was sent\n * successfully by the browser (\"Client Upload Time\"), determined by the server clock, rather than\n * when the event actually occurred. On majority of the cases, \"Client Upload Time\" can be\n * off by up to the configured `config.flushIntervalMillis`. By default `config.flushIntervalMillis`\n * is set to 1000 milliseconds. In rare cases where initial request to Amplitude fails due to\n * bad payload, throttled request, server error, etc, the time difference can be extended.\n */\nexport const removeTimeEnrichment = removeEventKeyEnrichment(['time']);\n"
  },
  {
    "path": "packages/analytics-browser/test/setup.js",
    "content": "jest.mock('../src/det-notification');\n"
  },
  {
    "path": "packages/analytics-browser/test/storage/local-storage.test.ts",
    "content": "import { Logger } from '@amplitude/analytics-core';\nimport { LocalStorage } from '../../src/storage/local-storage';\nimport * as AnalyticsCore from '@amplitude/analytics-core';\n\ndescribe('local-storage', () => {\n  test('should return true if storage is available', async () => {\n    const localStorage = new LocalStorage();\n    expect(await localStorage.isEnabled()).toBe(true);\n  });\n\n  test('should return false if storage is unavailable', async () => {\n    jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue(undefined);\n    const localStorage = new LocalStorage();\n    expect(await localStorage.isEnabled()).toBe(false);\n  });\n\n  test('should drop events when set more than 1000 events without logging', async () => {\n    const localStorage = new LocalStorage<number[]>();\n\n    await localStorage.set('storage-key', new Array<number>(1001).fill(1));\n    const value = await localStorage.get('storage-key');\n\n    expect(value?.length).toBe(1000);\n  });\n\n  test('should drop events when set more than 1000 events and use custom logger', async () => {\n    const loggerProvider = new Logger();\n    const localStorage = new LocalStorage<number[]>({ loggerProvider });\n    const errorMock = jest.spyOn(loggerProvider, 'error');\n\n    await localStorage.set('storage-key', new Array<number>(1001).fill(1));\n    const value = await localStorage.get('storage-key');\n\n    expect(value?.length).toBe(1000);\n    expect(errorMock).toHaveBeenCalledTimes(1);\n    expect(errorMock).toHaveBeenCalledWith('Failed to save 1 events because the queue length exceeded 1000.');\n  });\n\n  test('should not be enabled if \"window.localStorage\" getter throws an error', async () => {\n    let backupLocalStorage: Storage | null = null;\n    try {\n      backupLocalStorage = window.localStorage;\n      Object.defineProperty(window, 'localStorage', {\n        get: () => {\n          // simulates security error: https://www.chromium.org/for-testers/bug-reporting-guidelines/uncaught-securityerror-failed-to-read-the-localstorage-property-from-window-access-is-denied-for-this-document/\n          const err = `SecurityError: Failed to read the 'localStorage' property from 'Window': Access is denied for this document`;\n          throw new Error(err);\n        },\n        configurable: true,\n      });\n      const configs = [undefined, { loggerProvider: undefined }, { loggerProvider: new Logger() }];\n      await Promise.all(\n        configs.map(async (config) => {\n          const localStorage = new LocalStorage(config);\n          expect(await localStorage.isEnabled()).toBe(false);\n        }),\n      );\n    } finally {\n      Object.defineProperty(window, 'localStorage', {\n        get: () => backupLocalStorage,\n        configurable: true,\n      });\n    }\n  });\n});\n"
  },
  {
    "path": "packages/analytics-browser/test/storage/session-storage.test.ts",
    "content": "import { SessionStorage } from '../../src/storage/session-storage';\nimport * as AnalyticsCore from '@amplitude/analytics-core';\n\ndescribe('session-storage', () => {\n  test('should return true if storage is available', async () => {\n    const sessionStorage = new SessionStorage();\n    expect(await sessionStorage.isEnabled()).toBe(true);\n  });\n\n  test('should return false if storage is unavailable', async () => {\n    jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue(undefined);\n    const sessionStorage = new SessionStorage();\n    expect(await sessionStorage.isEnabled()).toBe(false);\n  });\n});\n"
  },
  {
    "path": "packages/analytics-browser/test/transport/fetch.test.ts",
    "content": "import { ReadableStream, WritableStream } from 'stream/web';\nimport { TextEncoder } from 'util';\nimport { MIN_GZIP_UPLOAD_BODY_SIZE_BYTES, Status } from '@amplitude/analytics-core';\nimport { FetchTransport } from '../../src/transports/fetch';\nimport 'isomorphic-fetch';\n\nif (typeof global.TextEncoder === 'undefined') {\n  (global as typeof globalThis & { TextEncoder?: typeof TextEncoder }).TextEncoder = TextEncoder;\n}\n\ndescribe('fetch transport', () => {\n  describe('send', () => {\n    test.each([['{}'], [''], ['<']])('should resolve with response', async (body) => {\n      const transport = new FetchTransport();\n      const url = 'http://localhost:3000';\n      const payload = { api_key: '', events: [] };\n      const result = {\n        statusCode: 200,\n        status: Status.Success as const,\n        body: {\n          eventsIngested: 0,\n          payloadSizeBytes: 0,\n          serverUploadTime: 0,\n        },\n      };\n\n      jest.spyOn(window, 'fetch').mockReturnValueOnce(Promise.resolve(new Response(body)));\n      jest.spyOn(transport, 'buildResponse').mockReturnValueOnce(result);\n\n      const response = await transport.send(url, payload);\n      expect(response).toEqual(result);\n    });\n\n    test('should include custom headers', async () => {\n      const transport = new FetchTransport({ Authorization: 'Bearer token123' });\n      const url = 'http://localhost:3000';\n      const payload = { api_key: '', events: [] };\n\n      const fetchSpy = jest.spyOn(window, 'fetch').mockReturnValueOnce(Promise.resolve(new Response('{}')));\n      await transport.send(url, payload, false);\n\n      expect(fetchSpy).toHaveBeenCalledWith(url, {\n        headers: {\n          'Content-Type': 'application/json',\n          Accept: '*/*',\n          Authorization: 'Bearer token123',\n        },\n        body: JSON.stringify(payload),\n        method: 'POST',\n      });\n    });\n\n    test('should keep body uncompressed when compression flag is false', async () => {\n      const transport = new FetchTransport();\n      const url = 'http://localhost:3000';\n      const payload = { api_key: '', events: [{ event_type: 'test', device_id: 'test_device_id' }] };\n      const mockCompressionStream = jest.fn();\n      (global as typeof globalThis & { CompressionStream?: unknown }).CompressionStream = mockCompressionStream;\n\n      const fetchSpy = jest.spyOn(window, 'fetch').mockReturnValueOnce(Promise.resolve(new Response('{}')));\n      await transport.send(url, payload, false);\n\n      expect(fetchSpy).toHaveBeenCalledWith(url, {\n        headers: {\n          'Content-Type': 'application/json',\n          Accept: '*/*',\n        },\n        body: JSON.stringify(payload),\n        method: 'POST',\n      });\n      expect(mockCompressionStream).not.toHaveBeenCalled();\n\n      delete (global as { CompressionStream?: unknown }).CompressionStream;\n    });\n\n    test('should send gzip-compressed body when compression flag is true', async () => {\n      const mockCompressedBytes = new Uint8Array([0x1f, 0x8b]);\n      const mockArrayBuffer = new ArrayBuffer(2);\n      new Uint8Array(mockArrayBuffer).set(mockCompressedBytes);\n      const OriginalResponse = (global as { Response?: typeof Response }).Response;\n      (global as { Response?: unknown }).Response = jest.fn().mockImplementation(() => ({\n        arrayBuffer: () => Promise.resolve(mockArrayBuffer),\n      }));\n\n      const mockReadable = new ReadableStream<Uint8Array>({\n        start(controller) {\n          controller.enqueue(mockCompressedBytes);\n          controller.close();\n        },\n      });\n      (global as { CompressionStream?: unknown }).CompressionStream = jest.fn().mockImplementation(() => ({\n        readable: mockReadable,\n        writable: new WritableStream(),\n      }));\n\n      const blobStreamSource = new ReadableStream<Uint8Array>();\n      Object.defineProperty(Blob.prototype, 'stream', {\n        value: () => blobStreamSource,\n        configurable: true,\n        writable: true,\n      });\n\n      const transport = new FetchTransport();\n      const url = 'http://localhost:3000';\n      const payload = {\n        api_key: '',\n        events: [\n          {\n            event_type: 'large-payload',\n            event_properties: { value: 'a'.repeat(MIN_GZIP_UPLOAD_BODY_SIZE_BYTES) },\n          },\n        ],\n      };\n\n      const fetchSpy = jest\n        .spyOn(window, 'fetch')\n        .mockReturnValueOnce(Promise.resolve({ text: () => Promise.resolve('{}') } as Response));\n      await transport.send(url, payload, true);\n\n      const [, options] = fetchSpy.mock.calls[0];\n      expect(options?.headers).toMatchObject({\n        'Content-Type': 'application/json',\n        Accept: '*/*',\n        'Content-Encoding': 'gzip',\n      });\n      expect(options?.body).toBeInstanceOf(ArrayBuffer);\n      expect(new Uint8Array(options?.body as ArrayBuffer)).toEqual(mockCompressedBytes);\n\n      (global as { Response?: unknown }).Response = OriginalResponse;\n      delete (Blob.prototype as unknown as { stream?: () => ReadableStream }).stream;\n      delete (global as { CompressionStream?: unknown }).CompressionStream;\n    });\n\n    test('should respect Content-Encoding header when compression is enabled', async () => {\n      const mockCompressedBytes = new Uint8Array([0x1f, 0x8b]);\n      const mockArrayBuffer = new ArrayBuffer(2);\n      new Uint8Array(mockArrayBuffer).set(mockCompressedBytes);\n      const OriginalResponse = (global as { Response?: typeof Response }).Response;\n      (global as { Response?: unknown }).Response = jest.fn().mockImplementation(() => ({\n        arrayBuffer: () => Promise.resolve(mockArrayBuffer),\n      }));\n\n      const mockReadable = new ReadableStream<Uint8Array>({\n        start(controller) {\n          controller.enqueue(mockCompressedBytes);\n          controller.close();\n        },\n      });\n      (global as { CompressionStream?: unknown }).CompressionStream = jest.fn().mockImplementation(() => ({\n        readable: mockReadable,\n        writable: new WritableStream(),\n      }));\n\n      const blobStreamSource = new ReadableStream<Uint8Array>();\n      Object.defineProperty(Blob.prototype, 'stream', {\n        value: () => blobStreamSource,\n        configurable: true,\n        writable: true,\n      });\n\n      const transport = new FetchTransport({ 'Content-Encoding': 'br' });\n      const url = 'http://localhost:3000';\n      const payload = {\n        api_key: '',\n        events: [\n          {\n            event_type: 'large-payload',\n            event_properties: { value: 'a'.repeat(MIN_GZIP_UPLOAD_BODY_SIZE_BYTES) },\n          },\n        ],\n      };\n\n      const fetchSpy = jest\n        .spyOn(window, 'fetch')\n        .mockReturnValueOnce(Promise.resolve({ text: () => Promise.resolve('{}') } as Response));\n      await transport.send(url, payload, true);\n\n      const [, options] = fetchSpy.mock.calls[0];\n      expect(options?.headers).toMatchObject({\n        'Content-Type': 'application/json',\n        Accept: '*/*',\n        'Content-Encoding': 'gzip',\n      });\n\n      (global as { Response?: unknown }).Response = OriginalResponse;\n      delete (Blob.prototype as unknown as { stream?: () => ReadableStream }).stream;\n      delete (global as { CompressionStream?: unknown }).CompressionStream;\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-browser/test/transport/send-beacon.test.ts",
    "content": "import { SendBeaconTransport } from '../../src/transports/send-beacon';\nimport { Status } from '@amplitude/analytics-core';\nimport * as AnalyticsCore from '@amplitude/analytics-core';\n\ndescribe('beacon', () => {\n  // eslint-disable-next-line @typescript-eslint/unbound-method\n  const beacon = window.navigator.sendBeacon;\n\n  beforeEach(() => {\n    window.navigator.sendBeacon = jest.fn();\n  });\n\n  afterEach(() => {\n    window.navigator.sendBeacon = beacon;\n  });\n\n  describe('send', () => {\n    test('should resolve with response', async () => {\n      const transport = new SendBeaconTransport();\n      const url = 'http://localhost:3000';\n      const payload = {\n        api_key: '',\n        events: [],\n      };\n      jest.spyOn(window.navigator, 'sendBeacon').mockReturnValueOnce(true);\n      const response = await transport.send(url, payload);\n      expect(response).toEqual({\n        statusCode: 200,\n        status: Status.Success,\n        body: {\n          eventsIngested: 0,\n          payloadSizeBytes: 26,\n          // serverUploadTime is equal to Date.now() which is different each test execution\n          // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n          serverUploadTime: expect.any(Number),\n        },\n      });\n    });\n\n    test('should handle failed send beacon attempt', async () => {\n      const transport = new SendBeaconTransport();\n      const url = 'http://localhost:3000';\n      const payload = {\n        api_key: '',\n        events: [],\n      };\n      jest.spyOn(window.navigator, 'sendBeacon').mockReturnValueOnce(false);\n      const response = await transport.send(url, payload);\n      expect(response).toEqual({\n        statusCode: 500,\n        status: Status.Failed,\n      });\n    });\n\n    test('should handle unexpected error', async () => {\n      const transport = new SendBeaconTransport();\n      const url = 'http://localhost:3000';\n      const payload = {\n        api_key: '',\n        events: [],\n      };\n      jest.spyOn(window.navigator, 'sendBeacon').mockImplementationOnce(() => {\n        throw new Error('sendBeacon error');\n      });\n      await expect(transport.send(url, payload)).rejects.toThrow('sendBeacon error');\n    });\n\n    test('should handle GlobalScope is not defined', async () => {\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValueOnce(undefined);\n      const transport = new SendBeaconTransport();\n      const url = 'http://localhost:3000';\n      const payload = {\n        api_key: '',\n        events: [],\n      };\n      await expect(transport.send(url, payload)).rejects.toThrow('SendBeaconTransport is not supported');\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-browser/test/transport/xhr.test.ts",
    "content": "import { ReadableStream, WritableStream } from 'stream/web';\nimport { TextEncoder } from 'util';\nimport { compressToGzipArrayBuffer, MIN_GZIP_UPLOAD_BODY_SIZE_BYTES, Status } from '@amplitude/analytics-core';\nimport { XHRTransport } from '../../src/transports/xhr';\n\nif (typeof global.TextEncoder === 'undefined') {\n  (global as typeof globalThis & { TextEncoder?: typeof TextEncoder }).TextEncoder = TextEncoder;\n}\n\ndescribe('xhr', () => {\n  describe('send', () => {\n    test.each([\n      ['{}'], // ideally response body should be json format to an application/json request\n      [''], // test the edge case where response body is non-json format\n      ['<'],\n    ])('should resolve with response', async (body) => {\n      const transport = new XHRTransport();\n      const url = 'http://localhost:3000';\n      const payload = {\n        api_key: '',\n        events: [],\n      };\n      const result = {\n        statusCode: 200,\n        status: Status.Success as const,\n        body: {\n          eventsIngested: 0,\n          payloadSizeBytes: 0,\n          serverUploadTime: 0,\n        },\n      };\n      const xhr = new XMLHttpRequest();\n      const open = jest.fn();\n      const setRequestHeader = jest.fn();\n      const send = jest.fn();\n      const mock = {\n        ...xhr,\n        open,\n        setRequestHeader,\n        send,\n        readyState: 4,\n        responseText: body,\n      };\n      jest.spyOn(window, 'XMLHttpRequest').mockReturnValueOnce(mock);\n      jest.spyOn(transport, 'buildResponse').mockReturnValueOnce(result);\n\n      const unresolvedResponse = transport.send(url, payload);\n      expect(mock.onreadystatechange).toBeDefined();\n      mock.onreadystatechange && mock.onreadystatechange(new Event(''));\n      const response = await unresolvedResponse;\n      expect(response).toBe(result);\n      expect(open).toHaveBeenCalledWith('POST', url, true);\n      expect(setRequestHeader).toHaveBeenCalledTimes(2);\n      expect(send).toHaveBeenCalledTimes(1);\n      expect(send).toHaveBeenCalledWith(JSON.stringify(payload));\n    });\n\n    test('should include custom headers in request', async () => {\n      const customHeaders = {\n        Authorization: 'Bearer token123',\n        'X-Custom-Header': 'custom-value',\n      };\n      const transport = new XHRTransport(customHeaders);\n      const url = 'http://localhost:3000';\n      const payload = {\n        api_key: '',\n        events: [],\n      };\n      const result = {\n        statusCode: 200,\n        status: Status.Success as const,\n        body: {\n          eventsIngested: 0,\n          payloadSizeBytes: 0,\n          serverUploadTime: 0,\n        },\n      };\n      const xhr = new XMLHttpRequest();\n      const open = jest.fn();\n      const setRequestHeader = jest.fn();\n      const send = jest.fn();\n      const mock = {\n        ...xhr,\n        open,\n        setRequestHeader,\n        send,\n        readyState: 4,\n        responseText: '{}',\n      };\n      jest.spyOn(window, 'XMLHttpRequest').mockReturnValueOnce(mock);\n      jest.spyOn(transport, 'buildResponse').mockReturnValueOnce(result);\n\n      const unresolvedResponse = transport.send(url, payload);\n      mock.onreadystatechange && mock.onreadystatechange(new Event(''));\n      await unresolvedResponse;\n\n      expect(setRequestHeader).toHaveBeenCalledTimes(4); // Content-Type, Accept, + 2 custom headers\n      expect(setRequestHeader).toHaveBeenCalledWith('Content-Type', 'application/json');\n      expect(setRequestHeader).toHaveBeenCalledWith('Accept', '*/*');\n      expect(setRequestHeader).toHaveBeenCalledWith('Authorization', 'Bearer token123');\n      expect(setRequestHeader).toHaveBeenCalledWith('X-Custom-Header', 'custom-value');\n    });\n\n    test('should not allow custom headers to override defaults', async () => {\n      const customHeaders = {\n        'Content-Type': 'text/plain',\n        Accept: 'application/json',\n      };\n      const transport = new XHRTransport(customHeaders);\n      const url = 'http://localhost:3000';\n      const payload = {\n        api_key: '',\n        events: [],\n      };\n      const result = {\n        statusCode: 200,\n        status: Status.Success as const,\n        body: {\n          eventsIngested: 0,\n          payloadSizeBytes: 0,\n          serverUploadTime: 0,\n        },\n      };\n      const xhr = new XMLHttpRequest();\n      const open = jest.fn();\n      const setRequestHeader = jest.fn();\n      const send = jest.fn();\n      const mock = {\n        ...xhr,\n        open,\n        setRequestHeader,\n        send,\n        readyState: 4,\n        responseText: '{}',\n      };\n      jest.spyOn(window, 'XMLHttpRequest').mockReturnValueOnce(mock);\n      jest.spyOn(transport, 'buildResponse').mockReturnValueOnce(result);\n\n      const unresolvedResponse = transport.send(url, payload);\n      mock.onreadystatechange && mock.onreadystatechange(new Event(''));\n      await unresolvedResponse;\n\n      // Custom headers should override defaults, so only 2 calls total\n      expect(setRequestHeader).toHaveBeenCalledTimes(2);\n      expect(setRequestHeader).toHaveBeenCalledWith('Content-Type', 'application/json');\n      expect(setRequestHeader).toHaveBeenCalledWith('Accept', '*/*');\n    });\n\n    test('should work without custom headers (backward compatibility)', async () => {\n      const transport = new XHRTransport();\n      const url = 'http://localhost:3000';\n      const payload = {\n        api_key: '',\n        events: [],\n      };\n      const result = {\n        statusCode: 200,\n        status: Status.Success as const,\n        body: {\n          eventsIngested: 0,\n          payloadSizeBytes: 0,\n          serverUploadTime: 0,\n        },\n      };\n      const xhr = new XMLHttpRequest();\n      const open = jest.fn();\n      const setRequestHeader = jest.fn();\n      const send = jest.fn();\n      const mock = {\n        ...xhr,\n        open,\n        setRequestHeader,\n        send,\n        readyState: 4,\n        responseText: '{}',\n      };\n      jest.spyOn(window, 'XMLHttpRequest').mockReturnValueOnce(mock);\n      jest.spyOn(transport, 'buildResponse').mockReturnValueOnce(result);\n\n      const unresolvedResponse = transport.send(url, payload);\n      mock.onreadystatechange && mock.onreadystatechange(new Event(''));\n      await unresolvedResponse;\n\n      expect(setRequestHeader).toHaveBeenCalledTimes(2); // Only Content-Type and Accept\n      expect(setRequestHeader).toHaveBeenCalledWith('Content-Type', 'application/json');\n      expect(setRequestHeader).toHaveBeenCalledWith('Accept', '*/*');\n    });\n\n    test('compressToGzipArrayBuffer returns undefined when CompressionStream is not available', async () => {\n      const g = global as { CompressionStream?: unknown };\n      const originalCompressionStream = g.CompressionStream;\n      // Set to undefined (don't delete) so the code hits our return instead of ReferenceError\n      g.CompressionStream = undefined;\n\n      const result = await compressToGzipArrayBuffer('data');\n      expect(result).toBeUndefined();\n\n      g.CompressionStream = originalCompressionStream;\n    });\n\n    test('when shouldCompressUploadBody is true but CompressionStream is not available, should send uncompressed body', async () => {\n      const g = global as { CompressionStream?: unknown };\n      const originalCompressionStream = g.CompressionStream;\n      delete g.CompressionStream;\n\n      const transport = new XHRTransport();\n      const url = 'http://localhost:3000';\n      const payload = { api_key: '', events: [] };\n\n      const setRequestHeader = jest.fn();\n      const send = jest.fn();\n      const mockXhr = {\n        open: jest.fn(),\n        setRequestHeader,\n        send,\n        readyState: 4,\n        responseText: '{}',\n        onreadystatechange: null as (() => void) | null,\n      };\n      jest.spyOn(global, 'XMLHttpRequest').mockImplementation(() => mockXhr as unknown as XMLHttpRequest);\n\n      const sendPromise = transport.send(url, payload, true);\n      mockXhr.onreadystatechange?.();\n      await sendPromise;\n\n      expect(setRequestHeader).not.toHaveBeenCalledWith('Content-Encoding', 'gzip');\n      expect(send).toHaveBeenCalledWith(JSON.stringify(payload));\n\n      g.CompressionStream = originalCompressionStream;\n    });\n\n    test('when shouldCompressUploadBody is true but compression returns undefined, should send uncompressed body', async () => {\n      const g = global as { CompressionStream?: unknown; Response?: unknown };\n      const originalCompressionStream = g.CompressionStream;\n      const originalResponse = g.Response;\n\n      const mockCompressedStream = {};\n      const pipeThrough = jest.fn().mockReturnValue(mockCompressedStream);\n      Object.defineProperty(Blob.prototype, 'stream', {\n        value: () => ({ pipeThrough }),\n        configurable: true,\n        writable: true,\n      });\n\n      g.CompressionStream = jest.fn();\n      g.Response = jest.fn().mockImplementation(() => ({\n        arrayBuffer: () => Promise.reject(new Error('compression failed')),\n      }));\n\n      const transport = new XHRTransport();\n      const url = 'http://localhost:3000';\n      const payload = {\n        api_key: '',\n        events: [\n          {\n            event_type: 'large-payload',\n            event_properties: { value: 'a'.repeat(MIN_GZIP_UPLOAD_BODY_SIZE_BYTES) },\n          },\n        ],\n      };\n\n      const setRequestHeader = jest.fn();\n      const send = jest.fn();\n      const mockXhr = {\n        open: jest.fn(),\n        setRequestHeader,\n        send,\n        readyState: 4,\n        responseText: '{}',\n        onreadystatechange: null as (() => void) | null,\n      };\n      jest.spyOn(global, 'XMLHttpRequest').mockImplementation(() => mockXhr as unknown as XMLHttpRequest);\n\n      const sendPromise = transport.send(url, payload, true);\n      await new Promise((r) => setTimeout(r, 0));\n      mockXhr.onreadystatechange?.();\n      await sendPromise;\n\n      expect(setRequestHeader).not.toHaveBeenCalledWith('Content-Encoding', 'gzip');\n      expect(send).toHaveBeenCalledWith(JSON.stringify(payload));\n\n      g.CompressionStream = originalCompressionStream;\n      g.Response = originalResponse;\n      delete (Blob.prototype as unknown as { stream?: () => unknown }).stream;\n    });\n\n    test('when payload is below compression threshold, should send uncompressed body', async () => {\n      const g = global as { CompressionStream?: unknown };\n      const originalCompressionStream = g.CompressionStream;\n      const MockCompressionStream = jest.fn();\n      g.CompressionStream = MockCompressionStream;\n\n      const transport = new XHRTransport();\n      const url = 'http://localhost:3000';\n      const payload = { api_key: '', events: [] };\n\n      const setRequestHeader = jest.fn();\n      const send = jest.fn();\n      const mockXhr = {\n        open: jest.fn(),\n        setRequestHeader,\n        send,\n        readyState: 4,\n        responseText: '{}',\n        onreadystatechange: null as (() => void) | null,\n      };\n      jest.spyOn(global, 'XMLHttpRequest').mockImplementation(() => mockXhr as unknown as XMLHttpRequest);\n\n      const sendPromise = transport.send(url, payload, true);\n      mockXhr.onreadystatechange?.();\n      await sendPromise;\n\n      expect(setRequestHeader).not.toHaveBeenCalledWith('Content-Encoding', 'gzip');\n      expect(send).toHaveBeenCalledWith(JSON.stringify(payload));\n      expect(MockCompressionStream).not.toHaveBeenCalled();\n\n      g.CompressionStream = originalCompressionStream;\n    });\n\n    test('should send gzip-compressed body with Content-Encoding when shouldCompressUploadBody is true', async () => {\n      const mockCompressedBytes = new Uint8Array([0x1f, 0x8b]); // gzip magic number\n      const mockArrayBuffer = new ArrayBuffer(2);\n      new Uint8Array(mockArrayBuffer).set(mockCompressedBytes);\n      const OriginalResponse = (global as { Response?: typeof Response }).Response;\n      (global as { Response?: unknown }).Response = jest.fn().mockImplementation(() => ({\n        arrayBuffer: () => Promise.resolve(mockArrayBuffer),\n      }));\n\n      const mockReadable = new ReadableStream<Uint8Array>({\n        start(controller) {\n          controller.enqueue(mockCompressedBytes);\n          controller.close();\n        },\n      });\n      const MockCompressionStream = jest.fn().mockImplementation(() => ({\n        readable: mockReadable,\n        writable: new WritableStream(),\n      }));\n      (global as { CompressionStream?: unknown }).CompressionStream = MockCompressionStream;\n\n      // jsdom Blob doesn't implement .stream(); provide one (same as fetch.test.ts)\n      const blobStreamSource = new ReadableStream<Uint8Array>();\n      Object.defineProperty(Blob.prototype, 'stream', {\n        value: () => blobStreamSource,\n        configurable: true,\n        writable: true,\n      });\n\n      const transport = new XHRTransport();\n      const url = 'http://localhost:3000';\n      const payload = {\n        api_key: '',\n        events: [\n          {\n            event_type: 'large-payload',\n            event_properties: { value: 'a'.repeat(MIN_GZIP_UPLOAD_BODY_SIZE_BYTES) },\n          },\n        ],\n      };\n\n      const open = jest.fn();\n      const setRequestHeader = jest.fn();\n      const send = jest.fn();\n      const mockXhr = {\n        open,\n        setRequestHeader,\n        send,\n        readyState: 4,\n        responseText: '{}',\n        onreadystatechange: null as (() => void) | null,\n      };\n      jest.spyOn(global, 'XMLHttpRequest').mockImplementation(() => mockXhr as unknown as XMLHttpRequest);\n\n      const sendPromise = transport.send(url, payload, true);\n      // Allow compressToGzipArrayBuffer (Response(stream).arrayBuffer()) to resolve before resolving send promise\n      await new Promise((r) => setTimeout(r, 0));\n      mockXhr.onreadystatechange?.();\n      await sendPromise;\n\n      expect(setRequestHeader).toHaveBeenCalledWith('Content-Encoding', 'gzip');\n      expect(send).toHaveBeenCalledTimes(1);\n      const sentBody = send.mock.calls[0][0];\n      expect(sentBody).toBeInstanceOf(ArrayBuffer);\n      expect(new Uint8Array(sentBody as ArrayBuffer)).toEqual(mockCompressedBytes);\n\n      (global as { Response?: unknown }).Response = OriginalResponse;\n      delete (Blob.prototype as unknown as { stream?: () => ReadableStream }).stream;\n      const g = global as { CompressionStream?: unknown };\n      delete g.CompressionStream;\n    });\n\n    test('should keep body uncompressed when compression flag is false', async () => {\n      const transport = new XHRTransport();\n      const url = 'https://api2.amplitude.com/2/httpapi';\n      const payload = { api_key: '', events: [{ event_type: 'test', device_id: 'test_device_id' }] };\n      const MockCompressionStream = jest.fn();\n      (global as { CompressionStream?: unknown }).CompressionStream = MockCompressionStream;\n\n      const setRequestHeader = jest.fn();\n      const send = jest.fn();\n      const mockXhr = {\n        open: jest.fn(),\n        setRequestHeader,\n        send,\n        readyState: 4,\n        responseText: '{}',\n        onreadystatechange: null as (() => void) | null,\n      };\n      jest.spyOn(global, 'XMLHttpRequest').mockImplementation(() => mockXhr as unknown as XMLHttpRequest);\n\n      const sendPromise = transport.send(url, payload, false);\n      mockXhr.onreadystatechange?.();\n      await sendPromise;\n\n      expect(setRequestHeader).not.toHaveBeenCalledWith('Content-Encoding', 'gzip');\n      expect(send).toHaveBeenCalledWith(JSON.stringify(payload));\n      expect(MockCompressionStream).not.toHaveBeenCalled();\n\n      delete (global as { CompressionStream?: unknown }).CompressionStream;\n    });\n\n    test('should reject when sendBody throws (e.g. xhr.send throws)', async () => {\n      const sendError = new Error('xhr.send failed');\n      const transport = new XHRTransport();\n      const url = 'http://localhost:3000';\n      const payload = { api_key: '', events: [] };\n\n      const setRequestHeader = jest.fn();\n      const send = jest.fn().mockImplementation(() => {\n        throw sendError;\n      });\n      const mockXhr = {\n        open: jest.fn(),\n        setRequestHeader,\n        send,\n        readyState: 4,\n        responseText: '{}',\n        onreadystatechange: null as (() => void) | null,\n      };\n      jest.spyOn(global, 'XMLHttpRequest').mockImplementation(() => mockXhr as unknown as XMLHttpRequest);\n\n      await expect(transport.send(url, payload, false)).rejects.toThrow(sendError);\n    });\n\n    test('should reject when setRequestHeader throws', async () => {\n      const headerError = new Error('setRequestHeader failed');\n      const transport = new XHRTransport();\n      const url = 'http://localhost:3000';\n      const payload = { api_key: '', events: [] };\n\n      const setRequestHeader = jest.fn().mockImplementation(() => {\n        throw headerError;\n      });\n      const send = jest.fn();\n      const mockXhr = {\n        open: jest.fn(),\n        setRequestHeader,\n        send,\n        readyState: 4,\n        responseText: '{}',\n        onreadystatechange: null as (() => void) | null,\n      };\n      jest.spyOn(global, 'XMLHttpRequest').mockImplementation(() => mockXhr as unknown as XMLHttpRequest);\n\n      await expect(transport.send(url, payload, false)).rejects.toThrow(headerError);\n    });\n\n    test('should respect custom Content-Encoding header when compressing', async () => {\n      const mockCompressedBytes = new Uint8Array([0x1f, 0x8b]);\n      const mockArrayBuffer = new ArrayBuffer(2);\n      new Uint8Array(mockArrayBuffer).set(mockCompressedBytes);\n      const OriginalResponse = (global as { Response?: typeof Response }).Response;\n      (global as { Response?: unknown }).Response = jest.fn().mockImplementation(() => ({\n        arrayBuffer: () => Promise.resolve(mockArrayBuffer),\n      }));\n\n      const mockReadable = new ReadableStream<Uint8Array>({\n        start(controller) {\n          controller.enqueue(mockCompressedBytes);\n          controller.close();\n        },\n      });\n      const MockCompressionStream = jest.fn().mockImplementation(() => ({\n        readable: mockReadable,\n        writable: new WritableStream(),\n      }));\n      (global as { CompressionStream?: unknown }).CompressionStream = MockCompressionStream;\n\n      const blobStreamSource = new ReadableStream<Uint8Array>();\n      Object.defineProperty(Blob.prototype, 'stream', {\n        value: () => blobStreamSource,\n        configurable: true,\n        writable: true,\n      });\n\n      const transport = new XHRTransport({ 'Content-Encoding': 'br' });\n      const url = 'http://localhost:3000';\n      const payload = {\n        api_key: '',\n        events: [\n          {\n            event_type: 'large-payload',\n            event_properties: { value: 'a'.repeat(MIN_GZIP_UPLOAD_BODY_SIZE_BYTES) },\n          },\n        ],\n      };\n\n      const setRequestHeader = jest.fn();\n      const send = jest.fn();\n      const mockXhr = {\n        open: jest.fn(),\n        setRequestHeader,\n        send,\n        readyState: 4,\n        responseText: '{}',\n        onreadystatechange: null as (() => void) | null,\n      };\n      jest.spyOn(global, 'XMLHttpRequest').mockImplementation(() => mockXhr as unknown as XMLHttpRequest);\n\n      const sendPromise = transport.send(url, payload, true);\n      await new Promise((r) => setTimeout(r, 0));\n      mockXhr.onreadystatechange?.();\n      await sendPromise;\n\n      expect(setRequestHeader).toHaveBeenCalledWith('Content-Encoding', 'gzip');\n\n      (global as { Response?: unknown }).Response = OriginalResponse;\n      delete (Blob.prototype as unknown as { stream?: () => ReadableStream }).stream;\n      const g = global as { CompressionStream?: unknown };\n      delete g.CompressionStream;\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-browser/test/types.test.ts",
    "content": "import * as amplitude from '../src/index';\n\ndescribe('Type Exports', () => {\n  test('IdentifyOperation should be an enum', () => {\n    expect(amplitude.Types.IdentifyOperation.ADD).toBe('$add');\n  });\n\n  test('SpecialEventType should be an enum', () => {\n    expect(amplitude.Types.SpecialEventType.IDENTIFY).toBe('$identify');\n  });\n\n  test('exported enums are proper enums', () => {\n    const enumTypes = ['RevenueProperty', 'LogLevel', 'ServerZone'];\n    enumTypes.forEach((enumType) => {\n      expect((amplitude.Types as any)[enumType]).toBeDefined();\n      expect(typeof (amplitude.Types as any)[enumType]).toBe('object');\n      expect(Object.keys((amplitude.Types as any)[enumType]).length).toBeGreaterThan(0);\n    });\n  });\n\n  test('exported null to be null', () => {\n    expect(amplitude.Types.OfflineDisabled).toBe(null);\n  });\n\n  test('exported arrays are proper arrays', () => {\n    const arrTypes = ['DEFAULT_CSS_SELECTOR_ALLOWLIST', 'DEFAULT_ACTION_CLICK_ALLOWLIST'];\n    arrTypes.forEach((arrType) => {\n      expect((amplitude.Types as any)[arrType]).toBeDefined();\n      expect(Array.isArray((amplitude.Types as any)[arrType])).toBe(true);\n      expect((amplitude.Types as any)[arrType].length).toBeGreaterThan(0);\n    });\n  });\n\n  test('exported string is string', () => {\n    expect(typeof amplitude.Types.DEFAULT_DATA_ATTRIBUTE_PREFIX).toBe('string');\n  });\n});\n"
  },
  {
    "path": "packages/analytics-browser/test/utils/fake-browser-client.ts",
    "content": "import {\n  BrowserClient,\n  returnWrapper,\n  Plugin,\n  BrowserOptions,\n  AmplitudeReturn,\n  Result,\n  EventOptions,\n  IIdentify,\n  IRevenue,\n  BaseEvent,\n  TransportType,\n  AnalyticsIdentity,\n} from '@amplitude/analytics-core';\n\nexport class FakeBrowserClient implements BrowserClient {\n  // BrowserClient specific methods\n  init(apiKey: string, options?: BrowserOptions): AmplitudeReturn<void>;\n  init(apiKey: string, userId?: string, options?: BrowserOptions): AmplitudeReturn<void>;\n  init(\n    apiKey: string,\n    userIdOrOptions?: string | BrowserOptions,\n    maybeOptions?: BrowserOptions,\n  ): AmplitudeReturn<void> {\n    console.log('FakeBrowserClient.init called with:', { apiKey, userIdOrOptions, maybeOptions });\n    return returnWrapper(Promise.resolve());\n  }\n\n  setTransport(transport: TransportType): void {\n    console.log('FakeBrowserClient.setTransport called with:', { transport });\n  }\n\n  add(plugin: Plugin): AmplitudeReturn<void> {\n    console.log('FakeBrowserClient.add called with:', { plugin });\n    return returnWrapper(Promise.resolve());\n  }\n\n  getIdentity(): AnalyticsIdentity {\n    console.log('FakeBrowserClient.getIdentity called');\n    return {\n      userId: undefined,\n      deviceId: undefined,\n      userProperties: undefined,\n    };\n  }\n\n  setIdentity(identity: Partial<AnalyticsIdentity>): void {\n    console.log('FakeBrowserClient.setIdentity called with:', { identity });\n  }\n\n  getOptOut(): boolean | undefined {\n    console.log('FakeBrowserClient.getOptOut called');\n    return false;\n  }\n\n  // CoreClient methods\n  remove(pluginName: string): AmplitudeReturn<void> {\n    console.log('FakeBrowserClient.remove called with:', { pluginName });\n    return returnWrapper(Promise.resolve());\n  }\n\n  track(\n    eventInput: BaseEvent | string,\n    eventProperties?: Record<string, any>,\n    eventOptions?: EventOptions,\n  ): AmplitudeReturn<Result> {\n    console.log('FakeBrowserClient.track called with:', { eventInput, eventProperties, eventOptions });\n    return returnWrapper(\n      Promise.resolve({\n        code: 200,\n        message: 'Event tracked successfully',\n        event: {\n          event_type: typeof eventInput === 'string' ? eventInput : eventInput.event_type,\n        },\n      }),\n    );\n  }\n\n  logEvent(\n    eventInput: BaseEvent | string,\n    eventProperties?: Record<string, any>,\n    eventOptions?: EventOptions,\n  ): AmplitudeReturn<Result> {\n    console.log('FakeBrowserClient.logEvent called with:', { eventInput, eventProperties, eventOptions });\n    return this.track(eventInput, eventProperties, eventOptions);\n  }\n\n  identify(identify: IIdentify, eventOptions?: EventOptions): AmplitudeReturn<Result> {\n    console.log('FakeBrowserClient.identify called with:', { identify, eventOptions });\n    return returnWrapper(\n      Promise.resolve({\n        code: 200,\n        message: 'Identify event tracked successfully',\n        event: {\n          event_type: '$identify',\n        },\n      }),\n    );\n  }\n\n  groupIdentify(\n    groupType: string,\n    groupName: string | string[],\n    identify: IIdentify,\n    eventOptions?: EventOptions,\n  ): AmplitudeReturn<Result> {\n    console.log('FakeBrowserClient.groupIdentify called with:', { groupType, groupName, identify, eventOptions });\n    return returnWrapper(\n      Promise.resolve({\n        code: 200,\n        message: 'Group identify event tracked successfully',\n        event: {\n          event_type: '$groupidentify',\n        },\n      }),\n    );\n  }\n\n  setGroup(groupType: string, groupName: string | string[], eventOptions?: EventOptions): AmplitudeReturn<Result> {\n    console.log('FakeBrowserClient.setGroup called with:', { groupType, groupName, eventOptions });\n    return returnWrapper(\n      Promise.resolve({\n        code: 200,\n        message: 'Set group event tracked successfully',\n        event: {\n          event_type: '$setgroup',\n        },\n      }),\n    );\n  }\n\n  revenue(revenue: IRevenue, eventOptions?: EventOptions): AmplitudeReturn<Result> {\n    console.log('FakeBrowserClient.revenue called with:', { revenue, eventOptions });\n    return returnWrapper(\n      Promise.resolve({\n        code: 200,\n        message: 'Revenue event tracked successfully',\n        event: {\n          event_type: '$revenue',\n        },\n      }),\n    );\n  }\n\n  setOptOut(optOut: boolean): void {\n    console.log('FakeBrowserClient.setOptOut called with:', { optOut });\n  }\n\n  flush(): AmplitudeReturn<void> {\n    console.log('FakeBrowserClient.flush called');\n    return returnWrapper(Promise.resolve());\n  }\n\n  // Client methods (from Client interface)\n  getUserId(): string | undefined {\n    console.log('FakeBrowserClient.getUserId called');\n    return undefined;\n  }\n\n  setUserId(userId: string | undefined): void {\n    console.log('FakeBrowserClient.setUserId called with:', { userId });\n  }\n\n  getDeviceId(): string | undefined {\n    console.log('FakeBrowserClient.getDeviceId called');\n    return undefined;\n  }\n\n  setDeviceId(deviceId: string): void {\n    console.log('FakeBrowserClient.setDeviceId called with:', { deviceId });\n  }\n\n  getSessionId(): number | undefined {\n    console.log('FakeBrowserClient.getSessionId called');\n    return undefined;\n  }\n\n  setSessionId(sessionId: number): void {\n    console.log('FakeBrowserClient.setSessionId called with:', { sessionId });\n  }\n\n  extendSession(): void {\n    console.log('FakeBrowserClient.extendSession called');\n  }\n\n  reset(): void {\n    console.log('FakeBrowserClient.reset called');\n  }\n\n  _setDiagnosticsSampleRate(sampleRate: number): void {\n    console.log('FakeBrowserClient.setDiagnosticsSampleRate called with:', { sampleRate });\n  }\n}\n"
  },
  {
    "path": "packages/analytics-browser/test/utils/snippet-helper.test.ts",
    "content": "import * as SnippetHelper from '../../src/utils/snippet-helper';\n\ndescribe('snippet-helper', () => {\n  const API_KEY = 'apiKey';\n\n  describe('runQueuedFunctions', () => {\n    test('should convert to real object', () => {\n      const obj = {};\n      const convertProxyObjectToRealObject = jest\n        .spyOn(SnippetHelper, 'convertProxyObjectToRealObject')\n        .mockReturnValueOnce(obj);\n      SnippetHelper.runQueuedFunctions(obj, []);\n      expect(convertProxyObjectToRealObject).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('convertProxyObjectToRealObject', () => {\n    test('should convert to real object', () => {\n      const init = (apiKey: string) => {\n        expect(apiKey).toBe(API_KEY);\n        return { promise: Promise.resolve() };\n      };\n      const resolve = jest.fn();\n      const proxyObj = {\n        name: 'init',\n        args: [API_KEY],\n        resolve,\n      };\n      const queue = [proxyObj];\n      const instance = { init };\n      SnippetHelper.convertProxyObjectToRealObject(instance, queue);\n      expect(resolve).toHaveBeenCalledTimes(1);\n    });\n\n    test('should handle no result', () => {\n      const init = () => {\n        return undefined;\n      };\n      const resolve = jest.fn();\n      const proxyObj = {\n        name: 'init',\n        args: [],\n        resolve,\n      };\n      const queue = [proxyObj];\n      const instance = { init };\n      expect(SnippetHelper.convertProxyObjectToRealObject(instance, queue)).toBe(instance);\n      expect(resolve).toHaveBeenCalledTimes(1);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-browser/test/video-capture/mock-video-observer.ts",
    "content": "/* eslint-disable @typescript-eslint/no-this-alias -- singleton test double */\nimport type { VideoObserverParams, VideoState } from '@amplitude/analytics-core';\n\n/** Last instance constructed (cleared by {@link resetMockVideoObserver}). */\nexport let currentVideoObserver: MockVideoObserver | undefined;\n\nexport function resetMockVideoObserver(): void {\n  currentVideoObserver = undefined;\n}\n\n/**\n * Lightweight stand-in for {@link VideoObserver} in unit tests (no DOM / trackHtmlVideo).\n */\nexport class MockVideoObserver {\n  readonly videoEl: VideoObserverParams['videoEl'];\n\n  private isDestroyed = false;\n\n  readonly vendor: VideoObserverParams['vendor'];\n\n  readonly isEmbedded: VideoObserverParams['isEmbedded'];\n\n  private readonly onStateChange: VideoObserverParams['onStateChange'];\n\n  constructor({ videoEl, onStateChange, vendor, isEmbedded }: VideoObserverParams) {\n    this.videoEl = videoEl;\n    this.onStateChange = onStateChange;\n    this.vendor = vendor;\n    this.isEmbedded = isEmbedded;\n    currentVideoObserver = this;\n  }\n\n  emitStateChange(previousState: VideoState, nextState: VideoState): void {\n    if (this.isDestroyed) {\n      return;\n    }\n    this.onStateChange(previousState, nextState);\n  }\n\n  destroy(): void {\n    this.isDestroyed = true;\n  }\n}\n"
  },
  {
    "path": "packages/analytics-browser/test/video-capture/video-capture.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-non-null-assertion, @typescript-eslint/unbound-method -- jest expectations */\nimport { AmplitudeBrowser } from '@amplitude/analytics-browser';\nimport { EmbeddedVideoPlayer, VideoState } from '@amplitude/analytics-core';\nimport { VideoCapture, trackVideo } from '../../src/video-capture/video-capture';\nimport { currentVideoObserver, resetMockVideoObserver } from './mock-video-observer';\n\njest.mock('@amplitude/analytics-core', () => {\n  const actual = jest.requireActual<typeof import('@amplitude/analytics-core')>('@amplitude/analytics-core');\n  const { MockVideoObserver } = jest.requireActual<typeof import('./mock-video-observer')>('./mock-video-observer');\n  return {\n    ...actual,\n    VideoObserver: MockVideoObserver,\n  };\n});\n\ndescribe('VideoCapture', () => {\n  let mockAmplitude: AmplitudeBrowser;\n\n  beforeEach(() => {\n    resetMockVideoObserver();\n    mockAmplitude = {\n      track: jest.fn(),\n    } as unknown as AmplitudeBrowser;\n  });\n\n  describe('kitchen sink', () => {\n    it('should track start and stop events', () => {\n      const capture = new VideoCapture(mockAmplitude)\n        .withVideoElement(document.createElement('video'))\n        .captureVideoStarted()\n        .captureVideoStopped()\n        .withExtraEventProperties({\n          hello: 'world',\n          number: 123,\n        })\n        .start();\n\n      // mock a play event\n      let previousState: VideoState = { playbackState: 'paused', lastEvent: undefined };\n      let nextState: VideoState = { playbackState: 'playing', lastEvent: { duration: 10, last_position: undefined } };\n      currentVideoObserver!.emitStateChange(previousState, nextState);\n      expect(mockAmplitude.track).toHaveBeenCalledWith('Video Content Started', {\n        duration: 10,\n        hello: 'world',\n        number: 123,\n      });\n\n      // mock a pause event\n      previousState = nextState;\n      nextState = { playbackState: 'paused', lastEvent: { duration: 10, last_position: 5 } };\n      currentVideoObserver!.emitStateChange(previousState, nextState);\n      expect(mockAmplitude.track).toHaveBeenCalledWith('Video Content Stopped', {\n        duration: 10,\n        last_position: 5,\n        hello: 'world',\n        number: 123,\n      });\n      expect(mockAmplitude.track).toHaveBeenCalledTimes(2);\n\n      // stop the capture\n      capture.stop();\n\n      // mock another play event\n      previousState = nextState;\n      nextState = { playbackState: 'playing', lastEvent: { duration: 10, last_position: undefined } };\n      currentVideoObserver!.emitStateChange(previousState, nextState);\n\n      // assert that the track method was not called again\n      expect(mockAmplitude.track).toHaveBeenCalledTimes(2);\n    });\n  });\n\n  describe('withEmbeddedPlayer()', () => {\n    it('should capture start and stop events', () => {\n      const dummyPlayer = {};\n      new VideoCapture(mockAmplitude)\n        .withEmbeddedPlayer(dummyPlayer as unknown as EmbeddedVideoPlayer)\n        .withVendor('mux')\n        .start();\n      expect(currentVideoObserver!.isEmbedded).toBe(true);\n      expect(currentVideoObserver!.vendor).toBe('mux');\n    });\n  });\n\n  describe('withVendor()', () => {\n    it('should capture start and stop events', () => {\n      const videoCapture = new VideoCapture(mockAmplitude).withVendor('mux');\n      expect((videoCapture as unknown as { vendor: string }).vendor).toBe('mux');\n    });\n  });\n\n  describe('start()', () => {\n    it('should throw an error if neither withVideoElement nor withEmbeddedPlayer was called', () => {\n      const capture = new VideoCapture(mockAmplitude);\n      expect(() => capture.start()).toThrow(/withVideoElement/g);\n    });\n\n    it('should throw an error if both video element and embedded video player are specified', () => {\n      const capture = new VideoCapture(mockAmplitude)\n        .withVideoElement(document.createElement('video'))\n        .withEmbeddedPlayer({} as unknown as EmbeddedVideoPlayer);\n      expect(() => capture.start()).toThrow(/withVideoElement/g);\n    });\n  });\n\n  describe('trackVideo()', () => {\n    beforeEach(() => {\n      resetMockVideoObserver();\n    });\n    it('should capture start and stop events', () => {\n      const stopVideoCapture = trackVideo(mockAmplitude, document.createElement('video'), {\n        vendor: 'mux',\n        extraEventProperties: { hello: 'world', number: 123 },\n      });\n      expect(currentVideoObserver!.vendor).toBe('mux');\n      currentVideoObserver!.emitStateChange(\n        { playbackState: 'paused', lastEvent: undefined },\n        { playbackState: 'playing', lastEvent: { duration: 10, last_position: undefined } },\n      );\n      expect(mockAmplitude.track).toHaveBeenCalledWith('Video Content Started', {\n        duration: 10,\n        hello: 'world',\n        number: 123,\n      });\n      currentVideoObserver!.emitStateChange(\n        { playbackState: 'playing', lastEvent: { duration: 10, last_position: undefined } },\n        { playbackState: 'paused', lastEvent: { duration: 10, last_position: 5 } },\n      );\n      expect(mockAmplitude.track).toHaveBeenCalledWith('Video Content Stopped', {\n        duration: 10,\n        last_position: 5,\n        hello: 'world',\n        number: 123,\n      });\n      stopVideoCapture();\n      currentVideoObserver!.emitStateChange(\n        { playbackState: 'paused', lastEvent: { duration: 10, last_position: 5 } },\n        { playbackState: 'playing', lastEvent: { duration: 10, last_position: undefined } },\n      );\n      expect(mockAmplitude.track).toHaveBeenCalledTimes(2);\n    });\n\n    it('should capture start and stop events with embedded video player', () => {\n      const stopVideoCapture = trackVideo(mockAmplitude, {\n        onPlay: jest.fn(),\n        onPause: jest.fn(),\n        onEnded: jest.fn(),\n        onError: jest.fn(),\n      } as unknown as EmbeddedVideoPlayer);\n      currentVideoObserver!.emitStateChange(\n        { playbackState: 'paused', lastEvent: undefined },\n        { playbackState: 'playing', lastEvent: { duration: 10, last_position: undefined } },\n      );\n      expect(mockAmplitude.track).toHaveBeenCalledWith('Video Content Started', {\n        duration: 10,\n      });\n      currentVideoObserver!.emitStateChange(\n        { playbackState: 'playing', lastEvent: { duration: 10, last_position: undefined } },\n        { playbackState: 'paused', lastEvent: { duration: 10, last_position: 5 } },\n      );\n      expect(mockAmplitude.track).toHaveBeenCalledWith('Video Content Stopped', {\n        duration: 10,\n        last_position: 5,\n      });\n      stopVideoCapture();\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-browser/tsconfig.es5.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/cjs\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/analytics-browser/tsconfig.esm.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"es6\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/esm\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/analytics-browser/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src/**/*\", \"test/**/*\", \"e2e/**/*\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"esModuleInterop\": true,\n    \"lib\": [\"dom\"],\n    \"noEmit\": true,\n    \"rootDir\": \".\"\n  }\n}\n"
  },
  {
    "path": "packages/analytics-browser-test/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.7.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.6.2...@amplitude/analytics-browser-test@2.7.0) (2023-05-04)\n\n### Features\n\n- add attribution tracking for linkedin click id li_fat_id\n  ([ca81f3d](https://github.com/amplitude/Amplitude-TypeScript/commit/ca81f3d75ece7e0e23a1bc1b6889107d53a60a86))\n- add rtd_cid for Reddit campaign tracking/attribution\n  ([784e080](https://github.com/amplitude/Amplitude-TypeScript/commit/784e080aa129c37e850d7f34115beb9770044e4e))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.6.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.6.1...@amplitude/analytics-browser-test@2.6.2) (2023-04-27)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.6.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.6.0...@amplitude/analytics-browser-test@2.6.1) (2023-04-27)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.6.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.5.4...@amplitude/analytics-browser-test@2.6.0) (2023-04-25)\n\n### Features\n\n- send user_agent with events ([#375](https://github.com/amplitude/Amplitude-TypeScript/issues/375))\n  ([26086b5](https://github.com/amplitude/Amplitude-TypeScript/commit/26086b543d7f0ee2d35e09b43199b5c26ed24e36))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.5.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.5.3...@amplitude/analytics-browser-test@2.5.4) (2023-04-06)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.5.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.5.2...@amplitude/analytics-browser-test@2.5.3) (2023-03-31)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.5.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.5.2-beta.0...@amplitude/analytics-browser-test@2.5.2) (2023-03-31)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.5.2-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.5.1...@amplitude/analytics-browser-test@2.5.2-beta.0) (2023-03-31)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.5.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.5.1-beta.1...@amplitude/analytics-browser-test@2.5.1) (2023-03-03)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.5.1-beta.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.5.1-beta.0...@amplitude/analytics-browser-test@2.5.1-beta.1) (2023-03-03)\n\n### Bug Fixes\n\n- event types and properties for default events ([#341](https://github.com/amplitude/Amplitude-TypeScript/issues/341))\n  ([707522d](https://github.com/amplitude/Amplitude-TypeScript/commit/707522d440d5aa3be48809afcb44a4147f103903))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.5.1-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.5.0...@amplitude/analytics-browser-test@2.5.1-beta.0) (2023-03-03)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.5.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.5.0-beta.4...@amplitude/analytics-browser-test@2.5.0) (2023-02-27)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.5.0-beta.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.5.0-beta.3...@amplitude/analytics-browser-test@2.5.0-beta.4) (2023-02-27)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.5.0-beta.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.5.0-beta.2...@amplitude/analytics-browser-test@2.5.0-beta.3) (2023-02-26)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.5.0-beta.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.5.0-beta.1...@amplitude/analytics-browser-test@2.5.0-beta.2) (2023-02-25)\n\n### Bug Fixes\n\n- inconsistent user and device id on session events\n  ([#337](https://github.com/amplitude/Amplitude-TypeScript/issues/337))\n  ([0dfbc6c](https://github.com/amplitude/Amplitude-TypeScript/commit/0dfbc6c78335a7578fc0207d91c1ef9845950f16))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.5.0-beta.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.5.0-beta.0...@amplitude/analytics-browser-test@2.5.0-beta.1) (2023-02-24)\n\n### Bug Fixes\n\n- improper cookie usage ([#330](https://github.com/amplitude/Amplitude-TypeScript/issues/330))\n  ([e670091](https://github.com/amplitude/Amplitude-TypeScript/commit/e670091e59014bb35bd9b3ec2a7192f259393575))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.5.0-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.4.2...@amplitude/analytics-browser-test@2.5.0-beta.0) (2023-02-24)\n\n### Features\n\n- add session start/end event tracker ([#332](https://github.com/amplitude/Amplitude-TypeScript/issues/332))\n  ([e26cf15](https://github.com/amplitude/Amplitude-TypeScript/commit/e26cf15503c59d3b25bd54391bb330a8c634eca3))\n- retrofit web attribution and page view plugins to browser SDK\n  ([#331](https://github.com/amplitude/Amplitude-TypeScript/issues/331))\n  ([ba845d3](https://github.com/amplitude/Amplitude-TypeScript/commit/ba845d3329bd6bebe3b89f24f4f316088c2d62b9))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.4.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.4.1...@amplitude/analytics-browser-test@2.4.2) (2023-02-09)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.4.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.4.0...@amplitude/analytics-browser-test@2.4.1) (2023-02-02)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.4.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.4.0-beta.0...@amplitude/analytics-browser-test@2.4.0) (2023-01-31)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.4.0-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.3.5...@amplitude/analytics-browser-test@2.4.0-beta.0) (2023-01-26)\n\n### Features\n\n- allow opt out of deleting legacy sdk cookies\n  ([c6a82fb](https://github.com/amplitude/Amplitude-TypeScript/commit/c6a82fb52e1301e427116891d1f31208bcfc6548))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.3.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.3.4...@amplitude/analytics-browser-test@2.3.5) (2023-01-11)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.3.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.3.3...@amplitude/analytics-browser-test@2.3.4) (2022-12-21)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n## [2.3.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.3.2...@amplitude/analytics-browser-test@2.3.3) (2022-12-10)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n## [2.3.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.3.1...@amplitude/analytics-browser-test@2.3.2) (2022-12-06)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n## [2.3.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.3.0...@amplitude/analytics-browser-test@2.3.1) (2022-12-05)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n# [2.3.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.2.3...@amplitude/analytics-browser-test@2.3.0) (2022-11-28)\n\n### Features\n\n- add utm_id tracking ([#284](https://github.com/amplitude/Amplitude-TypeScript/issues/284))\n  ([f72dcf1](https://github.com/amplitude/Amplitude-TypeScript/commit/f72dcf1788ebc84544aaee1dc41b1d1ba6e4c06e))\n\n## [2.2.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.2.2...@amplitude/analytics-browser-test@2.2.3) (2022-11-22)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n## [2.2.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.2.1...@amplitude/analytics-browser-test@2.2.2) (2022-11-15)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n## [2.2.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.2.0...@amplitude/analytics-browser-test@2.2.1) (2022-11-01)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n# [2.2.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.1.11...@amplitude/analytics-browser-test@2.2.0) (2022-11-01)\n\n### Features\n\n- enhance logger with debug information ([#254](https://github.com/amplitude/Amplitude-TypeScript/issues/254))\n  ([5c6175e](https://github.com/amplitude/Amplitude-TypeScript/commit/5c6175e9372cbeea264ddb34c6cc68148063d4f7))\n\n## [2.1.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.1.10...@amplitude/analytics-browser-test@2.1.11) (2022-10-26)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n## [2.1.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.1.10-beta.1...@amplitude/analytics-browser-test@2.1.10) (2022-10-25)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n## [2.1.10-beta.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.1.10-beta.0...@amplitude/analytics-browser-test@2.1.10-beta.1) (2022-10-25)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n## [2.1.10-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.1.9...@amplitude/analytics-browser-test@2.1.10-beta.0) (2022-10-25)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n## [2.1.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.1.8...@amplitude/analytics-browser-test@2.1.9) (2022-10-25)\n\n### Bug Fixes\n\n- invoke pre-init track fns after attribution ([#253](https://github.com/amplitude/Amplitude-TypeScript/issues/253))\n  ([b8996d7](https://github.com/amplitude/Amplitude-TypeScript/commit/b8996d793f74d388c1a96e0cde5c0ac060c1e565))\n\n## [2.1.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.1.7...@amplitude/analytics-browser-test@2.1.8) (2022-10-14)\n\n### Bug Fixes\n\n- run queued functions after attribution in browser-client.ts\n  ([#249](https://github.com/amplitude/Amplitude-TypeScript/issues/249))\n  ([751b7ca](https://github.com/amplitude/Amplitude-TypeScript/commit/751b7ca6b0f05131dc932b89dd89e8979e334b4b))\n\n## [2.1.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.1.6...@amplitude/analytics-browser-test@2.1.7) (2022-10-04)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n## [2.1.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.1.5...@amplitude/analytics-browser-test@2.1.6) (2022-09-30)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n## [2.1.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.1.4...@amplitude/analytics-browser-test@2.1.5) (2022-09-30)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n## [2.1.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.1.4-beta.1...@amplitude/analytics-browser-test@2.1.4) (2022-09-28)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n## [2.1.4-beta.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.1.4-beta.0...@amplitude/analytics-browser-test@2.1.4-beta.1) (2022-09-27)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n## [2.1.4-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.1.3...@amplitude/analytics-browser-test@2.1.4-beta.0) (2022-09-26)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n## [2.1.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.1.2...@amplitude/analytics-browser-test@2.1.3) (2022-09-26)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n## [2.1.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.1.1...@amplitude/analytics-browser-test@2.1.2) (2022-09-22)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n## [2.1.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.1.0...@amplitude/analytics-browser-test@2.1.1) (2022-09-16)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n# [2.1.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.0.13...@amplitude/analytics-browser-test@2.1.0) (2022-09-08)\n\n### Features\n\n- add ingestion_metadata field ([#212](https://github.com/amplitude/Amplitude-TypeScript/issues/212))\n  ([ebe8448](https://github.com/amplitude/Amplitude-TypeScript/commit/ebe8448b23609134f846e18da2e769158ca30bf1))\n\n## [2.0.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.0.12...@amplitude/analytics-browser-test@2.0.13) (2022-08-31)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n## [2.0.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.0.11...@amplitude/analytics-browser-test@2.0.12) (2022-08-29)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n## [2.0.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.0.10...@amplitude/analytics-browser-test@2.0.11) (2022-08-23)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n## [2.0.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.0.9...@amplitude/analytics-browser-test@2.0.10) (2022-08-18)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n## [2.0.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.0.8...@amplitude/analytics-browser-test@2.0.9) (2022-08-16)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n## [2.0.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.0.7...@amplitude/analytics-browser-test@2.0.8) (2022-08-13)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n## [2.0.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.0.6...@amplitude/analytics-browser-test@2.0.7) (2022-08-12)\n\n### Bug Fixes\n\n- add callable queue when init is pending ([#181](https://github.com/amplitude/Amplitude-TypeScript/issues/181))\n  ([d8fc361](https://github.com/amplitude/Amplitude-TypeScript/commit/d8fc36195b96e2c10ccc5106027beaa7e970e0c0))\n\n## [2.0.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.0.5...@amplitude/analytics-browser-test@2.0.6) (2022-08-02)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n## [2.0.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.0.4...@amplitude/analytics-browser-test@2.0.5) (2022-07-30)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n## [2.0.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.0.3...@amplitude/analytics-browser-test@2.0.4) (2022-07-29)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n## [2.0.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.0.2...@amplitude/analytics-browser-test@2.0.3) (2022-07-22)\n\n### Bug Fixes\n\n- adds error handling for invalid api ([#153](https://github.com/amplitude/Amplitude-TypeScript/issues/153))\n  ([c03f9d7](https://github.com/amplitude/Amplitude-TypeScript/commit/c03f9d7dad51e3026673dca31418a74591d79bbc))\n\n## [2.0.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.0.1...@amplitude/analytics-browser-test@2.0.2) (2022-07-15)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n## [2.0.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@2.0.0...@amplitude/analytics-browser-test@2.0.1) (2022-07-13)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n# [2.0.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@1.3.1...@amplitude/analytics-browser-test@2.0.0) (2022-06-29)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n## [1.3.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@1.3.0...@amplitude/analytics-browser-test@1.3.1) (2022-06-29)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n# [1.3.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@1.2.1...@amplitude/analytics-browser-test@1.3.0) (2022-06-29)\n\n### Features\n\n- make storage interface async to enable react-native\n  ([#122](https://github.com/amplitude/Amplitude-TypeScript/issues/122))\n  ([42bb39c](https://github.com/amplitude/Amplitude-TypeScript/commit/42bb39c967db015d5899487618d066f3540c9f18))\n\n## [1.2.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@1.2.0...@amplitude/analytics-browser-test@1.2.1) (2022-06-24)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n# [1.2.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@1.1.3...@amplitude/analytics-browser-test@1.2.0) (2022-06-24)\n\n### Features\n\n- add marketing campaign tracking ([#112](https://github.com/amplitude/Amplitude-TypeScript/issues/112))\n  ([bca73ed](https://github.com/amplitude/Amplitude-TypeScript/commit/bca73ede308ecb1663986a99600657732969d60c))\n\n## [1.1.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@1.1.2...@amplitude/analytics-browser-test@1.1.3) (2022-06-21)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n## [1.1.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@1.1.1...@amplitude/analytics-browser-test@1.1.2) (2022-06-17)\n\n**Note:** Version bump only for package @amplitude/analytics-browser-test\n\n## [1.1.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-browser-test@1.1.0...@amplitude/analytics-browser-test@1.1.1) (2022-05-17)\n\n### Bug Fixes\n\n- allow option.serverUrl to be used in destination plugin\n  ([#104](https://github.com/amplitude/Amplitude-TypeScript/issues/104))\n  ([f353367](https://github.com/amplitude/Amplitude-TypeScript/commit/f353367b8b264f86b6ea15b15f30385f8d5b8ad5))\n\n# 1.1.0 (2022-05-12)\n\n### Bug Fixes\n\n- allow event level groups tracking ([#90](https://github.com/amplitude/Amplitude-TypeScript/issues/90))\n  ([3240660](https://github.com/amplitude/Amplitude-TypeScript/commit/3240660e94db9e5c5a1ce4280d07faced2b5fd4d))\n- e2e tests hardcoded library version\n  ([c6caac6](https://github.com/amplitude/Amplitude-TypeScript/commit/c6caac64e0716d779c073d872e3745d5377868fe))\n\n### Features\n\n- parse old cookies and convert to new format ([#85](https://github.com/amplitude/Amplitude-TypeScript/issues/85))\n  ([bda78be](https://github.com/amplitude/Amplitude-TypeScript/commit/bda78be5d2de335e7b1ff6da413b20d3dc751aca))\n"
  },
  {
    "path": "packages/analytics-browser-test/README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://amplitude.com\" target=\"_blank\" align=\"center\">\n    <img src=\"https://static.amplitude.com/lightning/46c85bfd91905de8047f1ee65c7c93d6fa9ee6ea/static/media/amplitude-logo-with-text.4fb9e463.svg\" width=\"280\">\n  </a>\n  <br />\n</p>\n\n# `@amplitude/analytics-browser-test`\n\n> Internal Node package for Amplitude\n"
  },
  {
    "path": "packages/analytics-browser-test/jest.config.js",
    "content": "const baseConfig = require('../../jest.config.js');\nconst package = require('./package');\n\nmodule.exports = {\n  ...baseConfig,\n  collectCoverage: false,\n  displayName: package.name,\n  rootDir: '.',\n  setupFiles: ['./test/setup.ts'],\n  testEnvironment: 'jsdom',\n};\n"
  },
  {
    "path": "packages/analytics-browser-test/package.json",
    "content": "{\n  \"name\": \"@amplitude/analytics-browser-test\",\n  \"version\": \"2.8.0-beta.0\",\n  \"private\": true,\n  \"description\": \"\",\n  \"author\": \"Amplitude Inc\",\n  \"homepage\": \"https://github.com/amplitude/Amplitude-TypeScript\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/amplitude/Amplitude-TypeScript.git\"\n  },\n  \"scripts\": {\n    \"test\": \"jest\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/amplitude/Amplitude-TypeScript/issues\"\n  },\n  \"dependencies\": {\n  },\n  \"devDependencies\": {\n    \"@amplitude/analytics-browser\": \"workspace:*\",\n    \"@amplitude/analytics-core\": \"workspace:*\",\n    \"nock\": \"^13.2.4\"\n  }\n}\n"
  },
  {
    "path": "packages/analytics-browser-test/test/constants.ts",
    "content": "export const uuidPattern = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/;\nexport const url = 'https://api2.amplitude.com';\nexport const path = '/2/httpapi';\nexport const SUCCESS_MESSAGE = 'Event tracked successfully';\n"
  },
  {
    "path": "packages/analytics-browser-test/test/helpers.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unsafe-call */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\nimport { BaseEvent, Campaign, BASE_CAMPAIGN } from '@amplitude/analytics-core';\nimport { uuidPattern } from './constants';\n\nconst uuid: string = expect.stringMatching(uuidPattern) as string;\nconst userAgent = expect.any(String) as string;\nconst library = expect.stringMatching(/^amplitude-ts\\/.+/) as string;\nconst number = expect.any(Number) as number;\n\nconst parseQueryString = (url: string) => {\n  const params: { [key: string]: string } = {};\n  // Extract the query string part from the URL\n  const queryString = url.split('?')[1];\n  if (queryString) {\n    // Split the query string into key-value pairs\n    queryString.split('&').forEach((part) => {\n      const [key, value] = part.split('=');\n      // Decode URI components and add to the params object\n      params[decodeURIComponent(key)] = decodeURIComponent(value);\n    });\n  }\n  return params;\n};\n\nconst getReferrerObject = (referrerString?: string) => {\n  if (!referrerString) return {};\n  const referrerURL = new URL(referrerString);\n  const referrer = referrerURL.href.split('?')[0];\n  const referring_domain = referrerURL.hostname;\n  return { referrer, referring_domain };\n};\n\nconst generateAttributionUserProps = (campaignURL: string, referrerString?: string) => {\n  const referrer = getReferrerObject(referrerString);\n  const campaign = parseQueryString(campaignURL);\n  const campaignObject: Campaign = {\n    ...BASE_CAMPAIGN,\n    ...campaign,\n    ...referrer,\n  };\n  const hasNoCampaign = Object.entries(campaign).length === 0;\n  const hasAllCampaign = Object.entries(campaign).length === Object.entries(BASE_CAMPAIGN).length;\n  const operationObject: { [key: string]: { [key: string]: string } } = {\n    $setOnce: {},\n    ...(!hasAllCampaign ? { $unset: {} } : {}),\n    ...(!hasNoCampaign ? { $set: {} } : {}),\n  };\n\n  const user_properties = Object.keys(campaignObject).reduce((operationObject, key) => {\n    if (campaignObject[key] !== undefined) {\n      operationObject.$setOnce['initial_' + key] = campaignObject[key] as string;\n      operationObject.$set[key] = campaignObject[key] as string; // Assert that the value is a string\n    } else {\n      operationObject.$setOnce['initial_' + key] = 'EMPTY';\n      operationObject.$unset[key] = '-';\n    }\n\n    return operationObject;\n  }, operationObject);\n\n  return user_properties;\n};\n\nexport const generateEvent = (\n  event_id: number,\n  event_type: string,\n  options?: {\n    withPageURLEnrichmentProperties?: {\n      url?: string;\n      previousPageUrl?: string;\n    };\n  },\n): BaseEvent => {\n  const event = {\n    device_id: uuid,\n    event_id: event_id,\n    event_type: event_type,\n    insert_id: uuid,\n    ip: '$remote',\n    language: 'en-US',\n    library,\n    partner_id: undefined,\n    plan: undefined,\n    platform: 'Web',\n    session_id: number,\n    time: number,\n    user_agent: userAgent,\n    user_id: 'user1@amplitude.com',\n  };\n\n  if (options?.withPageURLEnrichmentProperties) {\n    return addPageUrlEnrichmentProperties(\n      event,\n      options.withPageURLEnrichmentProperties.url || '',\n      options.withPageURLEnrichmentProperties.previousPageUrl || '',\n    );\n  }\n  return event;\n};\n\nexport const generateAttributionEvent = (event_id: number, campaignURL: string, referrer?: string) => {\n  const attributionEvent = generateEvent(event_id, '$identify');\n  attributionEvent.user_properties = generateAttributionUserProps(campaignURL, referrer);\n  return attributionEvent;\n};\n\nexport const generateSessionStartEvent = (\n  event_id: number,\n  options: {\n    withPageURLEnrichmentProperties: {\n      url?: string;\n      previousPageUrl?: string;\n    };\n  },\n) => {\n  const sessionStartEvent = generateEvent(event_id, 'session_start');\n\n  if (options.withPageURLEnrichmentProperties) {\n    return addPageUrlEnrichmentProperties(\n      sessionStartEvent,\n      options.withPageURLEnrichmentProperties.url || '',\n      options.withPageURLEnrichmentProperties.previousPageUrl || '',\n    );\n  }\n  return sessionStartEvent;\n};\n\nexport const generateSessionEndEvent = (\n  event_id: number,\n  options?: {\n    withPageURLEnrichmentProperties: {\n      url?: string;\n      previousPageUrl?: string;\n    };\n  },\n) => {\n  const sessionEndEvent = generateEvent(event_id, 'session_end');\n\n  if (options?.withPageURLEnrichmentProperties) {\n    return addPageUrlEnrichmentProperties(\n      sessionEndEvent,\n      options?.withPageURLEnrichmentProperties.url || '',\n      options?.withPageURLEnrichmentProperties.previousPageUrl || '',\n    );\n  }\n  return sessionEndEvent;\n};\n\nconst generatePageViewEventProps = (\n  pageCounter: number,\n  urlString: string,\n  referrerString?: string,\n  options?: {\n    withPageURLEnrichmentProperties?: {\n      previousPageUrl?: string;\n    };\n  },\n) => {\n  const referrer = getReferrerObject(referrerString);\n  const previousUrl = options?.withPageURLEnrichmentProperties?.previousPageUrl\n    ? new URL(options?.withPageURLEnrichmentProperties.previousPageUrl)\n    : { href: '' };\n\n  const url = new URL(urlString);\n  const campaign = parseQueryString(urlString);\n\n  return {\n    '[Amplitude] Page Counter': pageCounter,\n    '[Amplitude] Page Domain': url.hostname,\n    '[Amplitude] Page Location': url.href,\n    '[Amplitude] Page Path': url.pathname,\n    '[Amplitude] Page Title': '',\n    '[Amplitude] Page URL': url.href.split('?')[0],\n    '[Amplitude] Page View ID': uuid,\n    ...(options?.withPageURLEnrichmentProperties\n      ? addPageUrlEnrichmentPreviousPageProperties(url.href, previousUrl.href || '')\n      : {}),\n    ...campaign,\n    ...referrer,\n  };\n};\n\nexport const generatePageViewEvent = (\n  event_id: number,\n  pageCounter: number,\n  url: string,\n  referrer?: string,\n  options?: {\n    withPageURLEnrichmentProperties?: {\n      previousPageUrl?: string;\n    };\n  },\n) => {\n  const generatePageViewEvent = generateEvent(event_id, '[Amplitude] Page Viewed');\n  generatePageViewEvent.event_properties = generatePageViewEventProps(pageCounter, url, referrer, {\n    withPageURLEnrichmentProperties: options?.withPageURLEnrichmentProperties,\n  });\n  return generatePageViewEvent;\n};\n\nexport const navigateTo = (urlString: string, referrer?: string) => {\n  if (referrer) {\n    Object.defineProperty(document, 'referrer', { value: referrer, configurable: true });\n  }\n\n  const url = new URL(urlString);\n  // eslint-disable-next-line no-restricted-globals\n  Object.defineProperty(window, 'location', {\n    value: {\n      hostname: url.hostname,\n      href: url.href,\n      pathname: url.pathname,\n      search: url.search,\n    },\n    writable: true,\n  });\n};\n\nexport const addPageUrlEnrichmentProperties = (event: BaseEvent, urlString: string, previousPageUrl?: string) => {\n  const url = new URL(urlString);\n  const previousUrl = previousPageUrl ? new URL(previousPageUrl) : { href: '' };\n\n  event.event_properties = {\n    ...event.event_properties,\n    '[Amplitude] Page Domain': url.hostname,\n    '[Amplitude] Page Location': url.href,\n    '[Amplitude] Page Path': url.pathname,\n    '[Amplitude] Page Title': '',\n    '[Amplitude] Page URL': url.href.split('?')[0],\n    ...addPageUrlEnrichmentPreviousPageProperties(url.href, previousUrl.href),\n  };\n  return event;\n};\n\nexport const addPageUrlEnrichmentPreviousPageProperties = (current: string, previous: string) => {\n  // note that the five duplicate properties with the page viewed are skipped here\n  return {\n    '[Amplitude] Previous Page Location': previous,\n    '[Amplitude] Previous Page Type': getPreviousPageType(current, previous),\n  };\n};\n\nexport const getPreviousPageType = (current: string, previous: string) => {\n  if (!previous) {\n    return 'direct';\n  }\n\n  const currentUrl = new URL(current);\n  const previousUrl = new URL(previous);\n\n  return previousUrl.hostname === currentUrl.hostname ? 'internal' : 'external';\n};\n"
  },
  {
    "path": "packages/analytics-browser-test/test/in-memory-storage.test.ts",
    "content": "import { createInstance } from '@amplitude/analytics-browser';\nimport { MemoryStorage, UUID } from '@amplitude/analytics-core';\nimport { default as nock } from 'nock';\nimport { path, url } from './constants';\nimport { success } from './responses';\nimport 'isomorphic-fetch';\n\ndescribe('Storage options', () => {\n  let apiKey = '';\n  let shortenedApiKey = '';\n  const defaultTracking = {\n    attribution: false,\n  };\n\n  beforeEach(() => {\n    apiKey = UUID();\n    shortenedApiKey = `${apiKey.substring(0, 10)}`;\n  });\n\n  afterEach(() => {\n    // clean up storage\n    document.cookie = `AMP_${shortenedApiKey}=null; expires=1 Jan 1970 00:00:00 GMT`;\n    window.localStorage.clear();\n  });\n\n  test('should use default storage', async () => {\n    const scope = nock(url).post(path).reply(200, success);\n\n    const amplitude = createInstance();\n    await amplitude.init(apiKey, {\n      defaultTracking,\n      fetchRemoteConfig: false,\n    }).promise;\n\n    await amplitude.track('Event').promise;\n\n    /**\n     * cookies are the default storage option for user session\n     * asserts that cookie storage was used\n     */\n    expect(document.cookie).toContain(`AMP_${shortenedApiKey}=`);\n    /**\n     * local storage is the default storage option for unsent events\n     * asserts that local storage was used\n     */\n    expect(window.localStorage.key(0)).toBe(`AMP_unsent_${shortenedApiKey}`);\n\n    scope.done();\n  });\n\n  test('should use local storage', async () => {\n    const scope = nock(url).post(path).reply(200, success);\n\n    const amplitude = createInstance();\n    await amplitude.init(apiKey, {\n      defaultTracking,\n      identityStorage: 'localStorage',\n      fetchRemoteConfig: false,\n    }).promise;\n\n    await amplitude.track('Event').promise;\n\n    /**\n     * cookies are disabled\n     * asserts that cookie storage was not used\n     */\n    expect(document.cookie).toBe('');\n    /**\n     * with `disableCookies: true`, user session is stored in local storage\n     * asserts that local storage is used for use session and unsent events\n     */\n    expect(window.localStorage.key(0)).toContain(`AMP_${shortenedApiKey}`);\n    expect(window.localStorage.key(1)).toBe(`AMP_unsent_${shortenedApiKey}`);\n    expect(window.localStorage.length).toBe(2);\n\n    scope.done();\n  });\n\n  test('should use memory storage', async () => {\n    const scope = nock(url).post(path).reply(200, success);\n\n    const amplitude = createInstance();\n    await amplitude.init(apiKey, {\n      defaultTracking,\n      identityStorage: 'none',\n      storageProvider: new MemoryStorage(),\n      fetchRemoteConfig: false,\n    }).promise;\n\n    await amplitude.track('Event').promise;\n\n    /**\n     * cookieStorage is set to new MemoryStorage()\n     * asserts that cookie storage is not used\n     */\n    expect(document.cookie).toBe('');\n    /**\n     * storageProvider is set to new MemoryStorage()\n     * asserts that local storage is not used\n     */\n    expect(window.localStorage.length).toBe(0);\n\n    scope.done();\n  });\n});\n"
  },
  {
    "path": "packages/analytics-browser-test/test/index.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unsafe-call */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\nimport * as amplitude from '@amplitude/analytics-browser';\nimport { default as nock } from 'nock';\nimport { success } from './responses';\nimport 'isomorphic-fetch';\nimport { path, url, SUCCESS_MESSAGE, uuidPattern } from './constants';\nimport { LogLevel, UUID } from '@amplitude/analytics-core';\n\ndescribe('integration', () => {\n  const uuid: string = expect.stringMatching(uuidPattern) as string;\n  const library = expect.stringMatching(/^amplitude-ts\\/.+/) as string;\n  const number = expect.any(Number) as number;\n  const userAgent = expect.any(String) as string;\n  const defaultTracking = {\n    attribution: false,\n    fileDownloads: false,\n    formInteractions: false,\n    pageViews: false,\n    sessions: false,\n  };\n\n  let apiKey = '';\n  let client = amplitude.createInstance();\n\n  const event_upload_time = '2023-01-01T12:00:00:000Z';\n  Date.prototype.toISOString = jest.fn(() => event_upload_time);\n\n  beforeAll(() => {\n    Object.defineProperty(window, 'location', {\n      value: {\n        hostname: '',\n        href: '',\n        pathname: '',\n        search: '',\n      },\n      writable: true,\n    });\n  });\n\n  beforeEach(() => {\n    client = amplitude.createInstance();\n    apiKey = UUID();\n    (window.location as any) = {\n      hostname: '',\n      href: '',\n      pathname: '',\n      search: '',\n    };\n  });\n\n  afterEach(() => {\n    // clean up cookies\n    document.cookie = `amp_${apiKey.substring(0, 6)}=null; expires=1 Jan 1970 00:00:00 GMT`;\n    document.cookie = `AMP_${apiKey.substring(0, 10)}=null; expires=1 Jan 1970 00:00:00 GMT`;\n    document.cookie = `AMP_MKTG_${apiKey.substring(0, 10)}=null; expires=1 Jan 1970 00:00:00 GMT`;\n\n    // clear url info in session storage\n    window.sessionStorage.setItem('AMP_URL_INFO', '{}');\n  });\n\n  describe('defer initialization', () => {\n    beforeAll(() => {\n      Object.defineProperty(window, 'location', {\n        value: {\n          hostname: '',\n          href: '',\n          pathname: '',\n          search: '',\n        },\n        writable: true,\n      });\n    });\n\n    beforeEach(() => {\n      (window.location as any) = {\n        hostname: '',\n        href: '',\n        pathname: '',\n        search: '',\n      };\n    });\n\n    test('should allow init to be called after other APIs', () => {\n      return new Promise((resolve) => {\n        const scope = nock(url).post(path).reply(200, success);\n\n        // NOTE: Values to assert on\n        const sessionId = Date.now() - 1000;\n        const userId = 'user@amplitude.com';\n        const deviceId = 'device-12345';\n        const platform = 'Jest';\n\n        client.setUserId(userId);\n        client.setDeviceId(deviceId);\n        client.setSessionId(sessionId);\n        client.add({\n          type: 'enrichment',\n          name: 'custom',\n          setup: async () => {\n            return undefined;\n          },\n          execute: async (event) => {\n            event.platform = platform;\n            return event;\n          },\n        });\n        void client.track('Event Before Init').promise.then((response) => {\n          expect(response.event).toEqual({\n            device_id: deviceId, // NOTE: Device ID was set before init\n            event_id: 0,\n            event_type: 'Event Before Init',\n            event_properties: {\n              '[Amplitude] Page Domain': '',\n              '[Amplitude] Page Location': '',\n              '[Amplitude] Page Path': '',\n              '[Amplitude] Page Title': '',\n              '[Amplitude] Page URL': '',\n              '[Amplitude] Previous Page Location': '',\n              '[Amplitude] Previous Page Type': 'direct',\n            },\n            insert_id: uuid,\n            ip: '$remote',\n            language: 'en-US',\n            library: library,\n            partner_id: undefined,\n            plan: undefined,\n            ingestion_metadata: undefined,\n            platform: platform, // NOTE: Session ID was set using a plugin added before init\n            session_id: sessionId, // NOTE: Session ID was set before init\n            time: number,\n            user_id: userId, // NOTE: User ID was set before init\n            user_agent: userAgent,\n          });\n          expect(response.code).toBe(200);\n          expect(response.message).toBe(SUCCESS_MESSAGE);\n          scope.done();\n          resolve(undefined);\n        });\n        client.init(apiKey, {\n          defaultTracking,\n          serverUrl: url + path,\n          fetchRemoteConfig: false,\n        });\n      });\n    });\n\n    test('should set attribution on init prior to running queued methods', async () => {\n      let requestBody1: Record<string, any> = {};\n      const scope1 = nock(url)\n        .post(path, (body: Record<string, any>) => {\n          requestBody1 = body;\n          return true;\n        })\n        .reply(200, success);\n\n      // NOTE: Values to assert on\n      const sessionId = Date.now() - 1000;\n      const userId = 'user@amplitude.com';\n      const deviceId = 'device-12345';\n\n      client.setUserId(userId);\n      client.setDeviceId(deviceId);\n      client.setSessionId(sessionId);\n\n      const trackPromise = client.track('Event Before Init').promise;\n      await client.init(apiKey, {\n        defaultTracking: {\n          ...defaultTracking,\n          attribution: true,\n          pageViews: {\n            trackOn: 'attribution',\n          },\n        },\n        fetchRemoteConfig: false,\n      }).promise;\n      await trackPromise;\n\n      expect(requestBody1).toEqual({\n        api_key: apiKey,\n        client_upload_time: event_upload_time,\n        events: [\n          {\n            device_id: deviceId,\n            session_id: sessionId,\n            user_id: userId,\n            time: number,\n            platform: 'Web',\n            language: 'en-US',\n            ip: '$remote',\n            insert_id: uuid,\n            event_type: '[Amplitude] Page Viewed',\n            event_properties: {\n              '[Amplitude] Page Domain': '',\n              '[Amplitude] Page Location': '',\n              '[Amplitude] Page Path': '',\n              '[Amplitude] Page Title': '',\n              '[Amplitude] Page URL': '',\n              '[Amplitude] Page Counter': 1,\n              '[Amplitude] Previous Page Location': '',\n              '[Amplitude] Previous Page Type': 'direct',\n            },\n            user_agent: userAgent,\n            user_properties: {\n              $setOnce: {\n                initial_dclid: 'EMPTY',\n                initial_fbclid: 'EMPTY',\n                initial_gbraid: 'EMPTY',\n                initial_gclid: 'EMPTY',\n                initial_ko_click_id: 'EMPTY',\n                initial_li_fat_id: 'EMPTY',\n                initial_msclkid: 'EMPTY',\n                initial_referrer: 'EMPTY',\n                initial_referring_domain: 'EMPTY',\n                initial_rdt_cid: 'EMPTY',\n                initial_ttclid: 'EMPTY',\n                initial_twclid: 'EMPTY',\n                initial_utm_campaign: 'EMPTY',\n                initial_utm_content: 'EMPTY',\n                initial_utm_medium: 'EMPTY',\n                initial_utm_source: 'EMPTY',\n                initial_utm_term: 'EMPTY',\n                initial_utm_id: 'EMPTY',\n                initial_wbraid: 'EMPTY',\n              },\n              $unset: {\n                dclid: '-',\n                fbclid: '-',\n                gbraid: '-',\n                gclid: '-',\n                ko_click_id: '-',\n                li_fat_id: '-',\n                msclkid: '-',\n                referrer: '-',\n                referring_domain: '-',\n                rdt_cid: '-',\n                ttclid: '-',\n                twclid: '-',\n                utm_campaign: '-',\n                utm_content: '-',\n                utm_id: '-',\n                utm_medium: '-',\n                utm_source: '-',\n                utm_term: '-',\n                wbraid: '-',\n              },\n            },\n            event_id: 0,\n            library: library,\n          },\n          {\n            device_id: deviceId,\n            session_id: sessionId,\n            user_id: userId,\n            time: number,\n            platform: 'Web',\n            language: 'en-US',\n            ip: '$remote',\n            insert_id: uuid,\n            event_type: 'Event Before Init',\n            event_id: 1,\n            event_properties: {\n              '[Amplitude] Page Domain': '',\n              '[Amplitude] Page Location': '',\n              '[Amplitude] Page Path': '',\n              '[Amplitude] Page Title': '',\n              '[Amplitude] Page URL': '',\n              '[Amplitude] Previous Page Location': '',\n              '[Amplitude] Previous Page Type': 'direct',\n            },\n            library: library,\n            user_agent: userAgent,\n          },\n        ],\n        options: {},\n      });\n      scope1.done();\n    });\n  });\n\n  describe('track', () => {\n    test('should track event', async () => {\n      const scope = nock(url).post(path).reply(200, success);\n\n      await client.init(apiKey, {\n        defaultTracking,\n        fetchRemoteConfig: false,\n      }).promise;\n      const response = await client.track('test event', {\n        mode: 'test',\n      }).promise;\n      expect(response.event).toEqual({\n        user_id: undefined,\n        device_id: uuid,\n        session_id: number,\n        time: number,\n        platform: 'Web',\n        language: 'en-US',\n        ip: '$remote',\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event',\n        event_id: 0,\n        event_properties: {\n          mode: 'test',\n          '[Amplitude] Page Domain': '',\n          '[Amplitude] Page Location': '',\n          '[Amplitude] Page Path': '',\n          '[Amplitude] Page Title': '',\n          '[Amplitude] Page URL': '',\n          '[Amplitude] Previous Page Location': '',\n          '[Amplitude] Previous Page Type': 'direct',\n        },\n        library: library,\n        user_agent: userAgent,\n      });\n      expect(response.code).toBe(200);\n      expect(response.message).toBe(SUCCESS_MESSAGE);\n      scope.done();\n    });\n\n    test('should track event with custom config', async () => {\n      const scope = nock(url).post(path).reply(200, success);\n\n      await client.init(apiKey, 'sdk.dev@amplitude.com', {\n        deviceId: 'deviceId',\n        sessionId: 1,\n        defaultTracking,\n        fetchRemoteConfig: false,\n      }).promise;\n      const response = await client.track('test event').promise;\n      expect(response.event).toEqual({\n        user_id: 'sdk.dev@amplitude.com',\n        device_id: 'deviceId',\n        session_id: 1,\n        time: number,\n        platform: 'Web',\n        language: 'en-US',\n        ip: '$remote',\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event',\n        event_properties: {\n          '[Amplitude] Page Domain': '',\n          '[Amplitude] Page Location': '',\n          '[Amplitude] Page Path': '',\n          '[Amplitude] Page Title': '',\n          '[Amplitude] Page URL': '',\n          '[Amplitude] Previous Page Location': '',\n          '[Amplitude] Previous Page Type': 'direct',\n        },\n        event_id: 0,\n        library: library,\n        user_agent: userAgent,\n      });\n      expect(response.code).toBe(200);\n      expect(response.message).toBe(SUCCESS_MESSAGE);\n      scope.done();\n    });\n\n    test('should track event with event options', async () => {\n      const scope = nock(url).post(path).reply(200, success);\n\n      await client.init(apiKey, {\n        defaultTracking,\n        fetchRemoteConfig: false,\n      }).promise;\n      const response = await client.track('test event', undefined, {\n        user_id: 'sdk.dev@amplitude.com',\n        device_id: 'deviceId',\n        session_id: 1,\n      }).promise;\n      expect(response.event).toEqual({\n        user_id: 'sdk.dev@amplitude.com',\n        device_id: 'deviceId',\n        session_id: 1,\n        time: number,\n        platform: 'Web',\n        language: 'en-US',\n        ip: '$remote',\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event',\n        event_properties: {\n          '[Amplitude] Page Domain': '',\n          '[Amplitude] Page Location': '',\n          '[Amplitude] Page Path': '',\n          '[Amplitude] Page Title': '',\n          '[Amplitude] Page URL': '',\n          '[Amplitude] Previous Page Location': '',\n          '[Amplitude] Previous Page Type': 'direct',\n        },\n        event_id: 0,\n        library: library,\n        user_agent: userAgent,\n      });\n      expect(response.code).toBe(200);\n      expect(response.message).toBe(SUCCESS_MESSAGE);\n      scope.done();\n    });\n\n    test('should track event with optional ingestionMetadata option', async () => {\n      const scope = nock(url).post(path).reply(200, success);\n\n      const sourceName = 'ampli';\n      const sourceVersion = '2.0.0';\n      await client.init(apiKey, {\n        defaultTracking,\n        ingestionMetadata: {\n          sourceName,\n          sourceVersion,\n        },\n        fetchRemoteConfig: false,\n      }).promise;\n      const response = await client.track('test event', undefined, {\n        user_id: 'sdk.dev@amplitude.com',\n        device_id: 'deviceId',\n        session_id: 1,\n      }).promise;\n      expect(response.event).toEqual({\n        user_id: 'sdk.dev@amplitude.com',\n        device_id: 'deviceId',\n        session_id: 1,\n        time: number,\n        platform: 'Web',\n        language: 'en-US',\n        ip: '$remote',\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event',\n        event_properties: {\n          '[Amplitude] Page Domain': '',\n          '[Amplitude] Page Location': '',\n          '[Amplitude] Page Path': '',\n          '[Amplitude] Page Title': '',\n          '[Amplitude] Page URL': '',\n          '[Amplitude] Previous Page Location': '',\n          '[Amplitude] Previous Page Type': 'direct',\n        },\n        event_id: 0,\n        library: library,\n        ingestion_metadata: {\n          source_name: sourceName,\n          source_version: sourceVersion,\n        },\n        user_agent: userAgent,\n      });\n      expect(response.code).toBe(200);\n      expect(response.message).toBe(SUCCESS_MESSAGE);\n      scope.done();\n    });\n\n    test('should track event with base event', async () => {\n      const scope = nock(url).post(path).reply(200, success);\n\n      await client.init(apiKey, {\n        defaultTracking,\n        fetchRemoteConfig: false,\n      }).promise;\n      const response = await client.track(\n        {\n          event_type: 'test event',\n          groups: {\n            org: '15',\n          },\n        },\n        undefined,\n        {\n          user_id: 'sdk.dev@amplitude.com',\n          device_id: 'deviceId',\n          session_id: 1,\n        },\n      ).promise;\n      expect(response.event).toEqual({\n        user_id: 'sdk.dev@amplitude.com',\n        device_id: 'deviceId',\n        session_id: 1,\n        time: number,\n        platform: 'Web',\n        language: 'en-US',\n        ip: '$remote',\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event',\n        event_properties: {\n          '[Amplitude] Page Domain': '',\n          '[Amplitude] Page Location': '',\n          '[Amplitude] Page Path': '',\n          '[Amplitude] Page Title': '',\n          '[Amplitude] Page URL': '',\n          '[Amplitude] Previous Page Location': '',\n          '[Amplitude] Previous Page Type': 'direct',\n        },\n        event_id: 0,\n        library: library,\n        groups: {\n          org: '15',\n        },\n        user_agent: userAgent,\n      });\n      expect(response.code).toBe(200);\n      expect(response.message).toBe(SUCCESS_MESSAGE);\n      scope.done();\n    });\n\n    test('should handle 400 error', async () => {\n      const first = nock(url)\n        .post(path)\n        .reply(400, {\n          code: 400,\n          error: 'Invalid field values on some events',\n          events_with_invalid_fields: {\n            device_id: [1],\n          },\n        });\n      const second = nock(url).post(path).reply(200, success);\n\n      await client.init(apiKey, {\n        logLevel: 0,\n        defaultTracking,\n        fetchRemoteConfig: false,\n      }).promise;\n      const response = await Promise.all([\n        client.track('test event 1').promise,\n        client.track('test event 2', undefined, {\n          device_id: undefined,\n        }).promise,\n      ]);\n      expect(response[0].event).toEqual({\n        user_id: undefined,\n        device_id: uuid,\n        session_id: number,\n        time: number,\n        platform: 'Web',\n        language: 'en-US',\n        ip: '$remote',\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event 1',\n        event_properties: {\n          '[Amplitude] Page Domain': '',\n          '[Amplitude] Page Location': '',\n          '[Amplitude] Page Path': '',\n          '[Amplitude] Page Title': '',\n          '[Amplitude] Page URL': '',\n          '[Amplitude] Previous Page Location': '',\n          '[Amplitude] Previous Page Type': 'direct',\n        },\n        event_id: 0,\n        library: library,\n        user_agent: userAgent,\n      });\n      expect(response[0].code).toBe(200);\n      expect(response[0].message).toBe(SUCCESS_MESSAGE);\n      expect(response[1].event).toEqual({\n        user_id: undefined,\n        device_id: undefined,\n        session_id: number,\n        time: number,\n        platform: 'Web',\n        language: 'en-US',\n        ip: '$remote',\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event 2',\n        event_properties: {\n          '[Amplitude] Page Domain': '',\n          '[Amplitude] Page Location': '',\n          '[Amplitude] Page Path': '',\n          '[Amplitude] Page Title': '',\n          '[Amplitude] Page URL': '',\n          '[Amplitude] Previous Page Location': '',\n          '[Amplitude] Previous Page Type': 'direct',\n        },\n        event_id: 1,\n        library: library,\n        user_agent: userAgent,\n      });\n      expect(response[1].code).toBe(400);\n      expect(response[1].message).toBe('Invalid field values on some events');\n      first.done();\n      second.done();\n    });\n\n    test('should handle 413 error', async () => {\n      const first = nock(url).post(path).reply(413, {\n        code: 413,\n        error: 'Payload too large',\n      });\n      const second = nock(url).post(path).times(2).reply(200, success);\n\n      await client.init(apiKey, {\n        logLevel: 0,\n        flushQueueSize: 2,\n        defaultTracking,\n        fetchRemoteConfig: false,\n      }).promise;\n      const response = await Promise.all([client.track('test event 1').promise, client.track('test event 2').promise]);\n      expect(response[0].event).toEqual({\n        user_id: undefined,\n        device_id: uuid,\n        session_id: number,\n        time: number,\n        platform: 'Web',\n        language: 'en-US',\n        ip: '$remote',\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event 1',\n        event_properties: {\n          '[Amplitude] Page Domain': '',\n          '[Amplitude] Page Location': '',\n          '[Amplitude] Page Path': '',\n          '[Amplitude] Page Title': '',\n          '[Amplitude] Page URL': '',\n          '[Amplitude] Previous Page Location': '',\n          '[Amplitude] Previous Page Type': 'direct',\n        },\n        event_id: 0,\n        library: library,\n        user_agent: userAgent,\n      });\n      expect(response[0].code).toBe(200);\n      expect(response[0].message).toBe(SUCCESS_MESSAGE);\n      expect(response[1].event).toEqual({\n        user_id: undefined,\n        device_id: uuid,\n        session_id: number,\n        time: number,\n        platform: 'Web',\n        language: 'en-US',\n        ip: '$remote',\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event 2',\n        event_properties: {\n          '[Amplitude] Page Domain': '',\n          '[Amplitude] Page Location': '',\n          '[Amplitude] Page Path': '',\n          '[Amplitude] Page Title': '',\n          '[Amplitude] Page URL': '',\n          '[Amplitude] Previous Page Location': '',\n          '[Amplitude] Previous Page Type': 'direct',\n        },\n        event_id: 1,\n        library: library,\n        user_agent: userAgent,\n      });\n      expect(response[1].code).toBe(200);\n      expect(response[1].message).toBe(SUCCESS_MESSAGE);\n      first.done();\n      second.done();\n    });\n\n    test('should handle 429 error', async () => {\n      const first = nock(url)\n        .post(path)\n        .reply(429, {\n          code: 429,\n          error: 'Too many requests for some devices and users',\n          exceeded_daily_quota_devices: {\n            throttled_device_id: 1,\n          },\n        });\n      const second = nock(url).post(path).reply(200, success);\n\n      await client.init(apiKey, {\n        logLevel: 0,\n        defaultTracking,\n        fetchRemoteConfig: false,\n      }).promise;\n      const response = await Promise.all([\n        client.track('test event 1').promise,\n        client.track('test event 2', undefined, {\n          device_id: 'throttled_device_id',\n        }).promise,\n      ]);\n      expect(response[0].event).toEqual({\n        user_id: undefined,\n        device_id: uuid,\n        session_id: number,\n        time: number,\n        platform: 'Web',\n        language: 'en-US',\n        ip: '$remote',\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event 1',\n        event_properties: {\n          '[Amplitude] Page Domain': '',\n          '[Amplitude] Page Location': '',\n          '[Amplitude] Page Path': '',\n          '[Amplitude] Page Title': '',\n          '[Amplitude] Page URL': '',\n          '[Amplitude] Previous Page Location': '',\n          '[Amplitude] Previous Page Type': 'direct',\n        },\n        event_id: 0,\n        library: library,\n        user_agent: userAgent,\n      });\n      expect(response[0].code).toBe(200);\n      expect(response[0].message).toBe(SUCCESS_MESSAGE);\n      expect(response[1].event).toEqual({\n        user_id: undefined,\n        device_id: 'throttled_device_id',\n        session_id: number,\n        time: number,\n        platform: 'Web',\n        language: 'en-US',\n        ip: '$remote',\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event 2',\n        event_properties: {\n          '[Amplitude] Page Domain': '',\n          '[Amplitude] Page Location': '',\n          '[Amplitude] Page Path': '',\n          '[Amplitude] Page Title': '',\n          '[Amplitude] Page URL': '',\n          '[Amplitude] Previous Page Location': '',\n          '[Amplitude] Previous Page Type': 'direct',\n        },\n        event_id: 1,\n        library: library,\n        user_agent: userAgent,\n      });\n      expect(response[1].code).toBe(429);\n      expect(response[1].message).toBe('Too many requests for some devices and users');\n      first.done();\n      second.done();\n    });\n\n    test('should handle 500 error', async () => {\n      const first = nock(url).post(path).reply(500, {\n        code: 500,\n      });\n      const second = nock(url).post(path).reply(200, success);\n\n      await client.init(apiKey, {\n        logLevel: 0,\n        defaultTracking,\n        fetchRemoteConfig: false,\n      }).promise;\n      const response = await Promise.all([client.track('test event 1').promise, client.track('test event 2').promise]);\n      expect(response[0].event).toEqual({\n        user_id: undefined,\n        device_id: uuid,\n        session_id: number,\n        time: number,\n        platform: 'Web',\n        language: 'en-US',\n        ip: '$remote',\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event 1',\n        event_properties: {\n          '[Amplitude] Page Domain': '',\n          '[Amplitude] Page Location': '',\n          '[Amplitude] Page Path': '',\n          '[Amplitude] Page Title': '',\n          '[Amplitude] Page URL': '',\n          '[Amplitude] Previous Page Location': '',\n          '[Amplitude] Previous Page Type': 'direct',\n        },\n        event_id: 0,\n        library: library,\n        user_agent: userAgent,\n      });\n      expect(response[0].code).toBe(200);\n      expect(response[0].message).toBe(SUCCESS_MESSAGE);\n      expect(response[1].event).toEqual({\n        user_id: undefined,\n        device_id: uuid,\n        session_id: number,\n        time: number,\n        platform: 'Web',\n        language: 'en-US',\n        ip: '$remote',\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event 2',\n        event_properties: {\n          '[Amplitude] Page Domain': '',\n          '[Amplitude] Page Location': '',\n          '[Amplitude] Page Path': '',\n          '[Amplitude] Page Title': '',\n          '[Amplitude] Page URL': '',\n          '[Amplitude] Previous Page Location': '',\n          '[Amplitude] Previous Page Type': 'direct',\n        },\n        event_id: 1,\n        library: library,\n        user_agent: userAgent,\n      });\n      expect(response[0].code).toBe(200);\n      expect(response[0].message).toBe(SUCCESS_MESSAGE);\n      first.done();\n      second.done();\n    });\n\n    test('should exhaust max retries', async () => {\n      const scope = nock(url).post(path).times(3).reply(500, {\n        code: 500,\n      });\n\n      await client.init(apiKey, {\n        logLevel: 0,\n        flushMaxRetries: 3,\n        defaultTracking,\n        fetchRemoteConfig: false,\n      }).promise;\n      const response = await client.track('test event').promise;\n      expect(response.event).toEqual({\n        user_id: undefined,\n        device_id: uuid,\n        session_id: number,\n        time: number,\n        platform: 'Web',\n        language: 'en-US',\n        ip: '$remote',\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event',\n        event_properties: {\n          '[Amplitude] Page Domain': '',\n          '[Amplitude] Page Location': '',\n          '[Amplitude] Page Path': '',\n          '[Amplitude] Page Title': '',\n          '[Amplitude] Page URL': '',\n          '[Amplitude] Previous Page Location': '',\n          '[Amplitude] Previous Page Type': 'direct',\n        },\n        event_id: 0,\n        library: library,\n        user_agent: userAgent,\n      });\n      expect(response.code).toBe(500);\n      expect(response.message).toBe('Event rejected due to exceeded retry count');\n      scope.done();\n    }, 10000);\n\n    test('should handle missing api key', async () => {\n      await client.init('', undefined, {\n        logLevel: 0,\n        defaultTracking,\n        fetchRemoteConfig: false,\n      }).promise;\n      const response = await client.track('test event').promise;\n      expect(response.code).toBe(400);\n      expect(response.message).toBe('Event rejected due to missing API key');\n      document.cookie = `AMP=null; expires=1 Jan 1970 00:00:00 GMT`;\n    });\n\n    test('should handle client opt out', async () => {\n      await client.init(apiKey, {\n        logLevel: 0,\n        defaultTracking,\n        fetchRemoteConfig: false,\n      }).promise;\n      client.setOptOut(true);\n      const response = await client.track('test event').promise;\n      expect(response.code).toBe(0);\n      expect(response.message).toBe('Event skipped due to optOut config');\n    });\n  });\n\n  describe('identify', () => {\n    test('should track event', async () => {\n      const scope = nock(url).post(path).reply(200, success);\n\n      await client.init(apiKey, {\n        defaultTracking,\n        fetchRemoteConfig: false,\n      }).promise;\n      const id = new amplitude.Identify();\n      id.set('org', 'amp');\n      id.setOnce('initial_org', 'amp');\n      id.append('locations_1', 'ca');\n      id.prepend('locations_2', 'ny');\n      id.postInsert('tasks_1', 'a');\n      id.preInsert('tasks_2', 'b');\n      id.remove('company', 'x');\n      id.add('employees', 1);\n      const response = await client.identify(id).promise;\n      expect(response.event).toEqual({\n        user_id: undefined,\n        device_id: uuid,\n        session_id: number,\n        time: number,\n        platform: 'Web',\n        language: 'en-US',\n        ip: '$remote',\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: '$identify',\n        event_id: 0,\n        library: library,\n        user_agent: userAgent,\n        user_properties: {\n          $add: {\n            employees: 1,\n          },\n          $append: {\n            locations_1: 'ca',\n          },\n          $postInsert: {\n            tasks_1: 'a',\n          },\n          $preInsert: {\n            tasks_2: 'b',\n          },\n          $prepend: {\n            locations_2: 'ny',\n          },\n          $remove: {\n            company: 'x',\n          },\n          $set: {\n            org: 'amp',\n          },\n          $setOnce: {\n            initial_org: 'amp',\n          },\n        },\n      });\n      expect(response.code).toBe(200);\n      expect(response.message).toBe(SUCCESS_MESSAGE);\n      scope.done();\n    });\n  });\n\n  describe('revenue', () => {\n    test('should track event', async () => {\n      const scope = nock(url).post(path).reply(200, success);\n\n      await client.init(apiKey, {\n        defaultTracking,\n        fetchRemoteConfig: false,\n      }).promise;\n      const rev = new amplitude.Revenue();\n      rev.setProductId('1');\n      rev.setQuantity(1);\n      rev.setPrice(100);\n      rev.setRevenueType('t');\n      rev.setCurrency('USD');\n      rev.setRevenue(200);\n      rev.setReceipt('receipt');\n      rev.setReceiptSig('receipt sig');\n      const response = await client.revenue(rev).promise;\n      expect(response.event).toEqual({\n        device_id: uuid,\n        event_id: 0,\n        event_properties: {\n          $price: 100,\n          $productId: '1',\n          $quantity: 1,\n          $revenue: 200,\n          $revenueType: 't',\n          $currency: 'USD',\n          $receipt: 'receipt',\n          $receiptSig: 'receipt sig',\n        },\n        event_type: 'revenue_amount',\n        insert_id: uuid,\n        ip: '$remote',\n        language: 'en-US',\n        library: library,\n        partner_id: undefined,\n        platform: 'Web',\n        session_id: number,\n        time: number,\n        user_agent: userAgent,\n        user_id: undefined,\n      });\n      expect(response.code).toBe(200);\n      expect(response.message).toBe(SUCCESS_MESSAGE);\n      scope.done();\n    });\n  });\n\n  describe('setGroup', () => {\n    test('should track event', async () => {\n      const scope = nock(url).post(path).reply(200, success);\n\n      await client.init(apiKey, {\n        defaultTracking,\n        fetchRemoteConfig: false,\n      }).promise;\n      const response = await client.setGroup('org', 'engineering').promise;\n      expect(response.event).toEqual({\n        device_id: uuid,\n        event_id: 0,\n        event_type: '$identify',\n        groups: {\n          org: 'engineering',\n        },\n        insert_id: uuid,\n        ip: '$remote',\n        language: 'en-US',\n        library: library,\n        partner_id: undefined,\n        platform: 'Web',\n        session_id: number,\n        time: number,\n        user_agent: userAgent,\n        user_id: undefined,\n        user_properties: {\n          $set: {\n            org: 'engineering',\n          },\n        },\n      });\n      expect(response.code).toBe(200);\n      expect(response.message).toBe(SUCCESS_MESSAGE);\n      scope.done();\n    });\n  });\n\n  describe('session handler', () => {\n    const previousSessionId = Date.now() - 31 * 60 * 1000; // now minus 31 minutes\n    const previousSessionLastEventTime = Date.now() - 31 * 60 * 1000; // now minus 31 minutes\n    const previousSessionLastEventId = 99;\n    const previousSessionDeviceId = 'a7a96s8d';\n    const previousSessionUserId = 'a7a96s8d';\n    beforeEach(() => {\n      // setup expired previous session\n      setLegacyCookie(\n        apiKey,\n        previousSessionDeviceId,\n        previousSessionUserId,\n        undefined,\n        previousSessionId,\n        previousSessionLastEventTime,\n        previousSessionLastEventId,\n      );\n    });\n\n    test('should send session events and replace with known user', () => {\n      let payload: any = undefined;\n      const scope = nock(url)\n        .post(path, (body: Record<string, any>) => {\n          payload = body;\n          return true;\n        })\n        .reply(200, success);\n      client.init(apiKey, 'user1@amplitude.com', {\n        deviceId: UUID(),\n        defaultTracking: {\n          ...defaultTracking,\n          attribution: true,\n          sessions: true,\n        },\n        sessionTimeout: 500,\n        flushIntervalMillis: 3000,\n        fetchRemoteConfig: false,\n      });\n      // Sends `session_start` event\n      client.track('Event in first session');\n\n      setTimeout(() => {\n        client.track('Event in next session');\n        // Sends `session_end` event for previous session\n        // Sends `session_start` event for next session\n      }, 1000);\n\n      setTimeout(() => {\n        client.setUserId('user2@amplitude.com');\n      }, 2000);\n\n      return new Promise<void>((resolve) => {\n        setTimeout(() => {\n          expect(payload).toEqual({\n            api_key: apiKey,\n            client_upload_time: event_upload_time,\n            events: [\n              {\n                // This is a `session_end` event for the previous session\n                device_id: previousSessionDeviceId,\n                event_id: 100,\n                event_type: 'session_end',\n                event_properties: {\n                  '[Amplitude] Page Domain': '',\n                  '[Amplitude] Page Location': '',\n                  '[Amplitude] Page Path': '',\n                  '[Amplitude] Page Title': '',\n                  '[Amplitude] Page URL': '',\n                  '[Amplitude] Previous Page Location': '',\n                  '[Amplitude] Previous Page Type': 'direct',\n                },\n                insert_id: uuid,\n                ip: '$remote',\n                language: 'en-US',\n                library,\n                partner_id: undefined,\n                plan: undefined,\n                platform: 'Web',\n                session_id: previousSessionId,\n                time: previousSessionId + 1,\n                user_agent: userAgent,\n                user_id: previousSessionUserId,\n              },\n              {\n                device_id: uuid,\n                event_id: 101,\n                event_type: '$identify',\n                insert_id: uuid,\n                ip: '$remote',\n                language: 'en-US',\n                library,\n                partner_id: undefined,\n                plan: undefined,\n                platform: 'Web',\n                session_id: number,\n                time: number,\n                user_agent: userAgent,\n                user_id: 'user1@amplitude.com',\n                user_properties: {\n                  $setOnce: {\n                    initial_dclid: 'EMPTY',\n                    initial_fbclid: 'EMPTY',\n                    initial_gbraid: 'EMPTY',\n                    initial_gclid: 'EMPTY',\n                    initial_ko_click_id: 'EMPTY',\n                    initial_li_fat_id: 'EMPTY',\n                    initial_msclkid: 'EMPTY',\n                    initial_referrer: 'EMPTY',\n                    initial_referring_domain: 'EMPTY',\n                    initial_rdt_cid: 'EMPTY',\n                    initial_ttclid: 'EMPTY',\n                    initial_twclid: 'EMPTY',\n                    initial_utm_campaign: 'EMPTY',\n                    initial_utm_content: 'EMPTY',\n                    initial_utm_id: 'EMPTY',\n                    initial_utm_medium: 'EMPTY',\n                    initial_utm_source: 'EMPTY',\n                    initial_utm_term: 'EMPTY',\n                    initial_wbraid: 'EMPTY',\n                  },\n                  $unset: {\n                    dclid: '-',\n                    fbclid: '-',\n                    gbraid: '-',\n                    gclid: '-',\n                    ko_click_id: '-',\n                    li_fat_id: '-',\n                    msclkid: '-',\n                    referrer: '-',\n                    referring_domain: '-',\n                    rdt_cid: '-',\n                    ttclid: '-',\n                    twclid: '-',\n                    utm_campaign: '-',\n                    utm_content: '-',\n                    utm_id: '-',\n                    utm_medium: '-',\n                    utm_source: '-',\n                    utm_term: '-',\n                    wbraid: '-',\n                  },\n                },\n              },\n              {\n                device_id: uuid,\n                event_id: 102,\n                event_type: 'session_start',\n                event_properties: {\n                  '[Amplitude] Page Domain': '',\n                  '[Amplitude] Page Location': '',\n                  '[Amplitude] Page Path': '',\n                  '[Amplitude] Page Title': '',\n                  '[Amplitude] Page URL': '',\n                  '[Amplitude] Previous Page Location': '',\n                  '[Amplitude] Previous Page Type': 'direct',\n                },\n                insert_id: uuid,\n                ip: '$remote',\n                language: 'en-US',\n                library,\n                partner_id: undefined,\n                plan: undefined,\n                platform: 'Web',\n                session_id: number,\n                time: number,\n                user_agent: userAgent,\n                user_id: 'user1@amplitude.com',\n              },\n              {\n                device_id: uuid,\n                event_id: 103,\n                event_properties: {\n                  '[Amplitude] Page Domain': '',\n                  '[Amplitude] Page Location': '',\n                  '[Amplitude] Page Path': '',\n                  '[Amplitude] Page Title': '',\n                  '[Amplitude] Page URL': '',\n                  '[Amplitude] Previous Page Location': '',\n                  '[Amplitude] Previous Page Type': 'direct',\n                },\n                event_type: 'Event in first session',\n                insert_id: uuid,\n                ip: '$remote',\n                language: 'en-US',\n                library,\n                partner_id: undefined,\n                plan: undefined,\n                platform: 'Web',\n                session_id: number,\n                time: number,\n                user_agent: userAgent,\n                user_id: 'user1@amplitude.com',\n              },\n              {\n                device_id: uuid,\n                event_id: 104,\n                event_type: 'session_end',\n                event_properties: {\n                  '[Amplitude] Page Domain': '',\n                  '[Amplitude] Page Location': '',\n                  '[Amplitude] Page Path': '',\n                  '[Amplitude] Page Title': '',\n                  '[Amplitude] Page URL': '',\n                  '[Amplitude] Previous Page Location': '',\n                  '[Amplitude] Previous Page Type': 'direct',\n                },\n                insert_id: uuid,\n                ip: '$remote',\n                language: 'en-US',\n                library,\n                partner_id: undefined,\n                plan: undefined,\n                platform: 'Web',\n                session_id: number,\n                time: number,\n                user_agent: userAgent,\n                user_id: 'user1@amplitude.com',\n              },\n              {\n                device_id: uuid,\n                event_id: 105,\n                event_type: 'session_start',\n                event_properties: {\n                  '[Amplitude] Page Domain': '',\n                  '[Amplitude] Page Location': '',\n                  '[Amplitude] Page Path': '',\n                  '[Amplitude] Page Title': '',\n                  '[Amplitude] Page URL': '',\n                  '[Amplitude] Previous Page Location': '',\n                  '[Amplitude] Previous Page Type': 'direct',\n                },\n                insert_id: uuid,\n                ip: '$remote',\n                language: 'en-US',\n                library,\n                partner_id: undefined,\n                plan: undefined,\n                platform: 'Web',\n                session_id: number,\n                time: number,\n                user_agent: userAgent,\n                user_id: 'user1@amplitude.com',\n              },\n              {\n                device_id: uuid,\n                event_id: 106,\n                event_properties: {\n                  '[Amplitude] Page Domain': '',\n                  '[Amplitude] Page Location': '',\n                  '[Amplitude] Page Path': '',\n                  '[Amplitude] Page Title': '',\n                  '[Amplitude] Page URL': '',\n                  '[Amplitude] Previous Page Location': '',\n                  '[Amplitude] Previous Page Type': 'direct',\n                },\n                event_type: 'Event in next session',\n                insert_id: uuid,\n                ip: '$remote',\n                language: 'en-US',\n                library,\n                partner_id: undefined,\n                plan: undefined,\n                platform: 'Web',\n                session_id: number,\n                time: number,\n                user_agent: userAgent,\n                user_id: 'user1@amplitude.com',\n              },\n            ],\n            options: {\n              min_id_length: undefined,\n            },\n          });\n          scope.done();\n          resolve();\n        }, 4000);\n      });\n    });\n\n    test('should send session events and replace with unknown user', () => {\n      // Reset previous session cookies\n      document.cookie = `amp_${apiKey.substring(0, 6)}=null; expires=1 Jan 1970 00:00:00 GMT`;\n\n      let payload: any = undefined;\n      const scope = nock(url)\n        .post(path, (body: Record<string, any>) => {\n          payload = body;\n          return true;\n        })\n        .reply(200, success);\n      client.init(apiKey, 'user1@amplitude.com', {\n        defaultTracking: {\n          ...defaultTracking,\n          attribution: true,\n          sessions: true,\n        },\n        sessionTimeout: 500,\n        flushIntervalMillis: 3000,\n        fetchRemoteConfig: false,\n      });\n      // Sends `session_start` event\n      client.track('Event in first session');\n\n      setTimeout(() => {\n        client.track('Event in next session');\n        // Sends `session_end` event for previous session\n        // Sends `session_start` event for next session\n      }, 1000);\n\n      setTimeout(() => {\n        client.reset();\n      }, 2000);\n\n      return new Promise<void>((resolve) => {\n        setTimeout(() => {\n          const deviceId0 = payload.events[0].device_id;\n          [\n            payload.events[1].device_id,\n            payload.events[2].device_id,\n            payload.events[3].device_id,\n            payload.events[4].device_id,\n            payload.events[5].device_id,\n          ].forEach((deviceId) => {\n            expect(deviceId).toEqual(deviceId0);\n          });\n          const sessionId0 = payload.events[0].session_id;\n          [payload.events[1].session_id, payload.events[2].session_id, payload.events[3].session_id].forEach(\n            (sessionId) => {\n              expect(sessionId).toEqual(sessionId0);\n            },\n          );\n          expect(sessionId0).not.toEqual(payload.events[4].session_id);\n          expect(payload.events[4].session_id).toEqual(payload.events[5].session_id);\n          expect(payload).toEqual({\n            api_key: apiKey,\n            client_upload_time: event_upload_time,\n            events: [\n              {\n                device_id: uuid,\n                event_id: 0,\n                event_type: '$identify',\n                insert_id: uuid,\n                ip: '$remote',\n                language: 'en-US',\n                library,\n                partner_id: undefined,\n                plan: undefined,\n                platform: 'Web',\n                session_id: number,\n                time: number,\n                user_agent: userAgent,\n                user_id: 'user1@amplitude.com',\n                user_properties: {\n                  $setOnce: {\n                    initial_dclid: 'EMPTY',\n                    initial_fbclid: 'EMPTY',\n                    initial_gbraid: 'EMPTY',\n                    initial_gclid: 'EMPTY',\n                    initial_ko_click_id: 'EMPTY',\n                    initial_li_fat_id: 'EMPTY',\n                    initial_msclkid: 'EMPTY',\n                    initial_referrer: 'EMPTY',\n                    initial_referring_domain: 'EMPTY',\n                    initial_rdt_cid: 'EMPTY',\n                    initial_ttclid: 'EMPTY',\n                    initial_twclid: 'EMPTY',\n                    initial_utm_campaign: 'EMPTY',\n                    initial_utm_content: 'EMPTY',\n                    initial_utm_id: 'EMPTY',\n                    initial_utm_medium: 'EMPTY',\n                    initial_utm_source: 'EMPTY',\n                    initial_utm_term: 'EMPTY',\n                    initial_wbraid: 'EMPTY',\n                  },\n                  $unset: {\n                    dclid: '-',\n                    fbclid: '-',\n                    gbraid: '-',\n                    gclid: '-',\n                    ko_click_id: '-',\n                    li_fat_id: '-',\n                    msclkid: '-',\n                    referrer: '-',\n                    referring_domain: '-',\n                    rdt_cid: '-',\n                    ttclid: '-',\n                    twclid: '-',\n                    utm_campaign: '-',\n                    utm_content: '-',\n                    utm_id: '-',\n                    utm_medium: '-',\n                    utm_source: '-',\n                    utm_term: '-',\n                    wbraid: '-',\n                  },\n                },\n              },\n              {\n                device_id: uuid,\n                event_id: 1,\n                event_type: 'session_start',\n                event_properties: {\n                  '[Amplitude] Page Domain': '',\n                  '[Amplitude] Page Location': '',\n                  '[Amplitude] Page Path': '',\n                  '[Amplitude] Page Title': '',\n                  '[Amplitude] Page URL': '',\n                  '[Amplitude] Previous Page Location': '',\n                  '[Amplitude] Previous Page Type': 'direct',\n                },\n                insert_id: uuid,\n                ip: '$remote',\n                language: 'en-US',\n                library,\n                partner_id: undefined,\n                plan: undefined,\n                platform: 'Web',\n                session_id: number,\n                time: number,\n                user_agent: userAgent,\n                user_id: 'user1@amplitude.com',\n              },\n              {\n                device_id: uuid,\n                event_id: 2,\n                event_properties: {\n                  '[Amplitude] Page Domain': '',\n                  '[Amplitude] Page Location': '',\n                  '[Amplitude] Page Path': '',\n                  '[Amplitude] Page Title': '',\n                  '[Amplitude] Page URL': '',\n                  '[Amplitude] Previous Page Location': '',\n                  '[Amplitude] Previous Page Type': 'direct',\n                },\n                event_type: 'Event in first session',\n                insert_id: uuid,\n                ip: '$remote',\n                language: 'en-US',\n                library,\n                partner_id: undefined,\n                plan: undefined,\n                platform: 'Web',\n                session_id: number,\n                time: number,\n                user_agent: userAgent,\n                user_id: 'user1@amplitude.com',\n              },\n              {\n                device_id: uuid,\n                event_id: 3,\n                event_type: 'session_end',\n                event_properties: {\n                  '[Amplitude] Page Domain': '',\n                  '[Amplitude] Page Location': '',\n                  '[Amplitude] Page Path': '',\n                  '[Amplitude] Page Title': '',\n                  '[Amplitude] Page URL': '',\n                  '[Amplitude] Previous Page Location': '',\n                  '[Amplitude] Previous Page Type': 'direct',\n                },\n                insert_id: uuid,\n                ip: '$remote',\n                language: 'en-US',\n                library,\n                partner_id: undefined,\n                plan: undefined,\n                platform: 'Web',\n                session_id: number,\n                time: number,\n                user_agent: userAgent,\n                user_id: 'user1@amplitude.com',\n              },\n              {\n                device_id: uuid,\n                event_id: 4,\n                event_type: 'session_start',\n                event_properties: {\n                  '[Amplitude] Page Domain': '',\n                  '[Amplitude] Page Location': '',\n                  '[Amplitude] Page Path': '',\n                  '[Amplitude] Page Title': '',\n                  '[Amplitude] Page URL': '',\n                  '[Amplitude] Previous Page Location': '',\n                  '[Amplitude] Previous Page Type': 'direct',\n                },\n                insert_id: uuid,\n                ip: '$remote',\n                language: 'en-US',\n                library,\n                partner_id: undefined,\n                plan: undefined,\n                platform: 'Web',\n                session_id: number,\n                time: number,\n                user_agent: userAgent,\n                user_id: 'user1@amplitude.com',\n              },\n              {\n                device_id: uuid,\n                event_id: 5,\n                event_properties: {\n                  '[Amplitude] Page Domain': '',\n                  '[Amplitude] Page Location': '',\n                  '[Amplitude] Page Path': '',\n                  '[Amplitude] Page Title': '',\n                  '[Amplitude] Page URL': '',\n                  '[Amplitude] Previous Page Location': '',\n                  '[Amplitude] Previous Page Type': 'direct',\n                },\n                event_type: 'Event in next session',\n                insert_id: uuid,\n                ip: '$remote',\n                language: 'en-US',\n                library,\n                partner_id: undefined,\n                plan: undefined,\n                platform: 'Web',\n                session_id: number,\n                time: number,\n                user_agent: userAgent,\n                user_id: 'user1@amplitude.com',\n              },\n            ],\n            options: {\n              min_id_length: undefined,\n            },\n          });\n          scope.done();\n          resolve();\n        }, 4000);\n      });\n    });\n\n    test('should extend session with new event', () => {\n      let payload: any = undefined;\n      const scope = nock(url)\n        .post(path, (body: Record<string, any>) => {\n          payload = body;\n          return true;\n        })\n        .reply(200, success);\n      client.init(apiKey, 'user1@amplitude.com', {\n        deviceId: UUID(),\n        defaultTracking: {\n          ...defaultTracking,\n        },\n        sessionId: 1,\n        sessionTimeout: 1000,\n        flushIntervalMillis: 3000,\n        fetchRemoteConfig: false,\n      });\n      client.track('First event in first session');\n\n      setTimeout(() => {\n        // Track event before first session expires\n        client.track('Second event in first session');\n      }, 800);\n\n      setTimeout(() => {\n        // Track event before extended session expires\n        // Without second event, session should have expired\n        client.track('Third event in first session');\n      }, 1600);\n\n      return new Promise<void>((resolve) => {\n        setTimeout(() => {\n          expect(payload).toEqual({\n            api_key: apiKey,\n            client_upload_time: event_upload_time,\n            events: [\n              {\n                device_id: uuid,\n                event_id: 100,\n                event_properties: {\n                  '[Amplitude] Page Domain': '',\n                  '[Amplitude] Page Location': '',\n                  '[Amplitude] Page Path': '',\n                  '[Amplitude] Page Title': '',\n                  '[Amplitude] Page URL': '',\n                  '[Amplitude] Previous Page Location': '',\n                  '[Amplitude] Previous Page Type': 'direct',\n                },\n                event_type: 'First event in first session',\n                insert_id: uuid,\n                ip: '$remote',\n                language: 'en-US',\n                library,\n                partner_id: undefined,\n                plan: undefined,\n                platform: 'Web',\n                session_id: 1,\n                time: number,\n                user_agent: userAgent,\n                user_id: 'user1@amplitude.com',\n              },\n              {\n                device_id: uuid,\n                event_id: 101,\n                event_properties: {\n                  '[Amplitude] Page Domain': '',\n                  '[Amplitude] Page Location': '',\n                  '[Amplitude] Page Path': '',\n                  '[Amplitude] Page Title': '',\n                  '[Amplitude] Page URL': '',\n                  '[Amplitude] Previous Page Location': '',\n                  '[Amplitude] Previous Page Type': 'direct',\n                },\n                event_type: 'Second event in first session',\n                insert_id: uuid,\n                ip: '$remote',\n                language: 'en-US',\n                library,\n                partner_id: undefined,\n                plan: undefined,\n                platform: 'Web',\n                session_id: 1,\n                time: number,\n                user_agent: userAgent,\n                user_id: 'user1@amplitude.com',\n              },\n              {\n                device_id: uuid,\n                event_id: 102,\n                event_properties: {\n                  '[Amplitude] Page Domain': '',\n                  '[Amplitude] Page Location': '',\n                  '[Amplitude] Page Path': '',\n                  '[Amplitude] Page Title': '',\n                  '[Amplitude] Page URL': '',\n                  '[Amplitude] Previous Page Location': '',\n                  '[Amplitude] Previous Page Type': 'direct',\n                },\n                event_type: 'Third event in first session',\n                insert_id: uuid,\n                ip: '$remote',\n                language: 'en-US',\n                library,\n                partner_id: undefined,\n                plan: undefined,\n                platform: 'Web',\n                session_id: 1,\n                time: number,\n                user_agent: userAgent,\n                user_id: 'user1@amplitude.com',\n              },\n            ],\n            options: {\n              min_id_length: undefined,\n            },\n          });\n          scope.done();\n          resolve();\n        }, 4000);\n      });\n    });\n\n    test('should handle expired session', async () => {\n      const scope = nock(url).post(path).reply(200, success);\n      await client.init(apiKey, {\n        defaultTracking,\n        fetchRemoteConfig: false,\n      }).promise;\n      const response = await client.track('test event', {\n        mode: 'test',\n      }).promise;\n      expect(response.event.session_id).not.toBe(previousSessionId);\n      expect(response.event).toEqual({\n        user_id: previousSessionUserId,\n        device_id: previousSessionDeviceId,\n        session_id: number,\n        time: number,\n        platform: 'Web',\n        language: 'en-US',\n        ip: '$remote',\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event',\n        event_id: 100,\n        event_properties: {\n          mode: 'test',\n          '[Amplitude] Page Domain': '',\n          '[Amplitude] Page Location': '',\n          '[Amplitude] Page Path': '',\n          '[Amplitude] Page Title': '',\n          '[Amplitude] Page URL': '',\n          '[Amplitude] Previous Page Location': '',\n          '[Amplitude] Previous Page Type': 'direct',\n        },\n        library: library,\n        user_agent: userAgent,\n      });\n      expect(response.code).toBe(200);\n      expect(response.message).toBe(SUCCESS_MESSAGE);\n      expect(document.cookie.includes('amp_')).toBe(false);\n      scope.done();\n    });\n\n    test('should handle expired session and set with options.sessionId', async () => {\n      const scope = nock(url).post(path).reply(200, success);\n      await client.init(apiKey, {\n        defaultTracking,\n        sessionId: 1,\n        fetchRemoteConfig: false,\n      }).promise;\n      const response = await client.track('test event', {\n        mode: 'test',\n      }).promise;\n      expect(response.event.session_id).toBe(1);\n      expect(response.event).toEqual({\n        user_id: previousSessionUserId,\n        device_id: previousSessionDeviceId,\n        session_id: number,\n        time: number,\n        platform: 'Web',\n        language: 'en-US',\n        ip: '$remote',\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event',\n        event_id: 100,\n        event_properties: {\n          mode: 'test',\n          '[Amplitude] Page Domain': '',\n          '[Amplitude] Page Location': '',\n          '[Amplitude] Page Path': '',\n          '[Amplitude] Page Title': '',\n          '[Amplitude] Page URL': '',\n          '[Amplitude] Previous Page Location': '',\n          '[Amplitude] Previous Page Type': 'direct',\n        },\n        library: library,\n        user_agent: userAgent,\n      });\n      expect(response.code).toBe(200);\n      expect(response.message).toBe(SUCCESS_MESSAGE);\n      expect(document.cookie.includes('amp_')).toBe(false);\n      scope.done();\n    });\n\n    test('should handle expired session and set with setSessionId', async () => {\n      const scope = nock(url).post(path).reply(200, success);\n      await client.init(apiKey, {\n        defaultTracking,\n        fetchRemoteConfig: false,\n      }).promise;\n      client.setSessionId(1);\n      const response = await client.track('test event', {\n        mode: 'test',\n      }).promise;\n      expect(response.event).toEqual({\n        user_id: previousSessionUserId,\n        device_id: previousSessionDeviceId,\n        session_id: 1,\n        time: number,\n        platform: 'Web',\n        language: 'en-US',\n        ip: '$remote',\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event',\n        event_id: 100,\n        event_properties: {\n          mode: 'test',\n          '[Amplitude] Page Domain': '',\n          '[Amplitude] Page Location': '',\n          '[Amplitude] Page Path': '',\n          '[Amplitude] Page Title': '',\n          '[Amplitude] Page URL': '',\n          '[Amplitude] Previous Page Location': '',\n          '[Amplitude] Previous Page Type': 'direct',\n        },\n        library: library,\n        user_agent: userAgent,\n      });\n      expect(response.code).toBe(200);\n      expect(response.message).toBe(SUCCESS_MESSAGE);\n      expect(document.cookie.includes('amp_')).toBe(false);\n      scope.done();\n    });\n  });\n\n  describe('default page view tracking', () => {\n    test('should send page view on attribution', () => {\n      let payload: any = undefined;\n      const scope = nock(url)\n        .post(path, (body: Record<string, any>) => {\n          payload = body;\n          return true;\n        })\n        .reply(200, success);\n      client.init(apiKey, 'user1@amplitude.com', {\n        defaultTracking: {\n          ...defaultTracking,\n          attribution: true,\n          pageViews: {\n            trackOn: 'attribution',\n          },\n        },\n        fetchRemoteConfig: false,\n      });\n\n      return new Promise<void>((resolve) => {\n        setTimeout(() => {\n          expect(payload).toEqual({\n            api_key: apiKey,\n            client_upload_time: event_upload_time,\n            events: [\n              {\n                device_id: uuid,\n                event_id: 0,\n                event_properties: {\n                  '[Amplitude] Page Domain': '',\n                  '[Amplitude] Page Location': '',\n                  '[Amplitude] Page Path': '',\n                  '[Amplitude] Page Title': '',\n                  '[Amplitude] Page URL': '',\n                  '[Amplitude] Page Counter': 1,\n                  '[Amplitude] Previous Page Location': '',\n                  '[Amplitude] Previous Page Type': 'direct',\n                },\n                event_type: '[Amplitude] Page Viewed',\n                insert_id: uuid,\n                ip: '$remote',\n                language: 'en-US',\n                library,\n                partner_id: undefined,\n                plan: undefined,\n                platform: 'Web',\n                session_id: number,\n                time: number,\n                user_agent: userAgent,\n                user_id: 'user1@amplitude.com',\n                user_properties: {\n                  $setOnce: {\n                    initial_dclid: 'EMPTY',\n                    initial_fbclid: 'EMPTY',\n                    initial_gbraid: 'EMPTY',\n                    initial_gclid: 'EMPTY',\n                    initial_ko_click_id: 'EMPTY',\n                    initial_li_fat_id: 'EMPTY',\n                    initial_msclkid: 'EMPTY',\n                    initial_referrer: 'EMPTY',\n                    initial_referring_domain: 'EMPTY',\n                    initial_rdt_cid: 'EMPTY',\n                    initial_ttclid: 'EMPTY',\n                    initial_twclid: 'EMPTY',\n                    initial_utm_campaign: 'EMPTY',\n                    initial_utm_content: 'EMPTY',\n                    initial_utm_id: 'EMPTY',\n                    initial_utm_medium: 'EMPTY',\n                    initial_utm_source: 'EMPTY',\n                    initial_utm_term: 'EMPTY',\n                    initial_wbraid: 'EMPTY',\n                  },\n                  $unset: {\n                    dclid: '-',\n                    fbclid: '-',\n                    gbraid: '-',\n                    gclid: '-',\n                    ko_click_id: '-',\n                    li_fat_id: '-',\n                    msclkid: '-',\n                    referrer: '-',\n                    referring_domain: '-',\n                    rdt_cid: '-',\n                    ttclid: '-',\n                    twclid: '-',\n                    utm_campaign: '-',\n                    utm_content: '-',\n                    utm_id: '-',\n                    utm_medium: '-',\n                    utm_source: '-',\n                    utm_term: '-',\n                    wbraid: '-',\n                  },\n                },\n              },\n            ],\n            options: {\n              min_id_length: undefined,\n            },\n          });\n          scope.done();\n          resolve();\n        }, 2000);\n      });\n    });\n\n    test('should send page view with and clear pageCounter in new session', () => {\n      let payload: any = undefined;\n      const scope = nock(url)\n        .post(path, (body: Record<string, any>) => {\n          payload = body;\n          return true;\n        })\n        .reply(200, success);\n\n      const client = amplitude.createInstance();\n      client.init(apiKey, 'user1@amplitude.com', {\n        defaultTracking: {\n          ...defaultTracking,\n          pageViews: true,\n        },\n        sessionTimeout: 500,\n        flushIntervalMillis: 3000,\n        fetchRemoteConfig: false,\n      });\n\n      client.track('Event in first session');\n\n      const oldURL = new URL('https://www.example.com');\n      mockWindowLocationFromURL(oldURL);\n      window.history.pushState(undefined, oldURL.href);\n\n      const newURL = new URL('https://www.example.com/about');\n      mockWindowLocationFromURL(newURL);\n      window.history.pushState(undefined, newURL.href);\n\n      // Fire page view event in current session\n      setTimeout(() => {\n        const latestURL = new URL('https://www.example.com/contact');\n        mockWindowLocationFromURL(latestURL);\n        window.history.pushState(undefined, latestURL.href);\n      }, 500);\n\n      // Fire page view event in new session\n      setTimeout(() => {\n        const anotherURL = new URL('https://www.example.com/more');\n        mockWindowLocationFromURL(anotherURL);\n        window.history.pushState(undefined, anotherURL.href);\n      }, 2000);\n\n      return new Promise<void>((resolve) => {\n        setTimeout(() => {\n          try {\n            expect(payload).toEqual({\n              api_key: apiKey,\n              client_upload_time: event_upload_time,\n              events: [\n                {\n                  device_id: uuid,\n                  event_id: 0,\n                  event_properties: {\n                    '[Amplitude] Page Domain': 'www.example.com',\n                    '[Amplitude] Page Location': 'https://www.example.com/about',\n                    '[Amplitude] Page Path': '/about',\n                    '[Amplitude] Page Title': '',\n                    '[Amplitude] Page URL': 'https://www.example.com/about',\n                    '[Amplitude] Page View ID': uuid,\n                    '[Amplitude] Page Counter': 1,\n                    '[Amplitude] Previous Page Location': '',\n                    '[Amplitude] Previous Page Type': 'direct',\n                  },\n                  event_type: '[Amplitude] Page Viewed',\n                  insert_id: uuid,\n                  ip: '$remote',\n                  language: 'en-US',\n                  library,\n                  partner_id: undefined,\n                  plan: undefined,\n                  platform: 'Web',\n                  session_id: number,\n                  time: number,\n                  user_agent: userAgent,\n                  user_id: 'user1@amplitude.com',\n                },\n                {\n                  device_id: uuid,\n                  event_id: 1,\n                  event_type: 'Event in first session',\n                  event_properties: {\n                    '[Amplitude] Page Domain': 'www.example.com',\n                    '[Amplitude] Page Location': 'https://www.example.com/about',\n                    '[Amplitude] Page Path': '/about',\n                    '[Amplitude] Page Title': '',\n                    '[Amplitude] Page URL': 'https://www.example.com/about',\n                    '[Amplitude] Previous Page Location': '',\n                    '[Amplitude] Previous Page Type': 'direct',\n                  },\n                  insert_id: uuid,\n                  ip: '$remote',\n                  language: 'en-US',\n                  library,\n                  partner_id: undefined,\n                  plan: undefined,\n                  platform: 'Web',\n                  session_id: number,\n                  time: number,\n                  user_agent: userAgent,\n                  user_id: 'user1@amplitude.com',\n                },\n                {\n                  device_id: uuid,\n                  event_id: 2,\n                  event_properties: {\n                    '[Amplitude] Page Domain': 'www.example.com',\n                    '[Amplitude] Page Location': 'https://www.example.com/contact',\n                    '[Amplitude] Page Path': '/contact',\n                    '[Amplitude] Page Title': '',\n                    '[Amplitude] Page URL': 'https://www.example.com/contact',\n                    '[Amplitude] Page View ID': uuid,\n                    '[Amplitude] Previous Page Location': 'https://www.example.com/about',\n                    '[Amplitude] Previous Page Type': 'internal',\n                    '[Amplitude] Page Counter': 2,\n                  },\n                  event_type: '[Amplitude] Page Viewed',\n                  insert_id: uuid,\n                  ip: '$remote',\n                  language: 'en-US',\n                  library,\n                  partner_id: undefined,\n                  plan: undefined,\n                  platform: 'Web',\n                  session_id: number,\n                  time: number,\n                  user_agent: userAgent,\n                  user_id: 'user1@amplitude.com',\n                },\n                {\n                  device_id: uuid,\n                  event_id: 3,\n                  event_properties: {\n                    '[Amplitude] Page Domain': 'www.example.com',\n                    '[Amplitude] Page Location': 'https://www.example.com/more',\n                    '[Amplitude] Page Path': '/more',\n                    '[Amplitude] Page Title': '',\n                    '[Amplitude] Page URL': 'https://www.example.com/more',\n                    '[Amplitude] Page Counter': 1,\n                    '[Amplitude] Page View ID': uuid,\n                    '[Amplitude] Previous Page Location': 'https://www.example.com/contact',\n                    '[Amplitude] Previous Page Type': 'internal',\n                  },\n                  event_type: '[Amplitude] Page Viewed',\n                  insert_id: uuid,\n                  ip: '$remote',\n                  language: 'en-US',\n                  library,\n                  partner_id: undefined,\n                  plan: undefined,\n                  platform: 'Web',\n                  session_id: number,\n                  time: number,\n                  user_agent: userAgent,\n                  user_id: 'user1@amplitude.com',\n                },\n              ],\n              options: {\n                min_id_length: undefined,\n              },\n            });\n          } finally {\n            scope.done();\n          }\n          resolve();\n        }, 4000);\n      });\n    });\n\n    test('should send page view', () => {\n      let payload: any = undefined;\n      const scope = nock(url)\n        .post(path, (body: Record<string, any>) => {\n          payload = body;\n          return true;\n        })\n        .reply(200, success);\n      client.init(apiKey, 'user1@amplitude.com', {\n        defaultTracking: {\n          ...defaultTracking,\n          pageViews: true,\n        },\n        fetchRemoteConfig: false,\n      });\n\n      return new Promise<void>((resolve) => {\n        setTimeout(() => {\n          expect(payload).toEqual({\n            api_key: apiKey,\n            client_upload_time: event_upload_time,\n            events: [\n              {\n                device_id: uuid,\n                event_id: 0,\n                event_properties: {\n                  '[Amplitude] Page Domain': '',\n                  '[Amplitude] Page Location': '',\n                  '[Amplitude] Page Path': '',\n                  '[Amplitude] Page Title': '',\n                  '[Amplitude] Page URL': '',\n                  '[Amplitude] Page View ID': uuid,\n                  '[Amplitude] Page Counter': 1,\n                  '[Amplitude] Previous Page Location': '',\n                  '[Amplitude] Previous Page Type': 'direct',\n                },\n                event_type: '[Amplitude] Page Viewed',\n                insert_id: uuid,\n                ip: '$remote',\n                language: 'en-US',\n                library,\n                partner_id: undefined,\n                plan: undefined,\n                platform: 'Web',\n                session_id: number,\n                time: number,\n                user_agent: userAgent,\n                user_id: 'user1@amplitude.com',\n              },\n            ],\n            options: {\n              min_id_length: undefined,\n            },\n          });\n          scope.done();\n          resolve();\n        }, 2000);\n      });\n    });\n  });\n\n  describe('cookie migration', () => {\n    const previousSessionId = Date.now(); // now minus 31 minutes\n    const previousSessionLastEventTime = Date.now(); // now minus 31 minutes\n    const previousSessionLastEventId = 99;\n    const previousSessionDeviceId = 'deviceId';\n    const previousSessionUserId = 'userId';\n\n    beforeEach(() => {\n      // setup expired previous session\n      setLegacyCookie(\n        apiKey,\n        previousSessionDeviceId,\n        previousSessionUserId,\n        undefined,\n        previousSessionId,\n        previousSessionLastEventTime,\n        previousSessionLastEventId,\n      );\n    });\n\n    test('should use old cookies', async () => {\n      const scope = nock(url).post(path).reply(200, success);\n      await client.init(apiKey, {\n        defaultTracking,\n        fetchRemoteConfig: false,\n      }).promise;\n      const response = await client.track('test event', {\n        mode: 'test',\n      }).promise;\n      expect(response.event).toEqual({\n        user_id: previousSessionUserId,\n        device_id: previousSessionDeviceId,\n        session_id: previousSessionId,\n        time: number,\n        platform: 'Web',\n        language: 'en-US',\n        ip: '$remote',\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event',\n        event_id: 100,\n        event_properties: {\n          mode: 'test',\n          '[Amplitude] Page Domain': '',\n          '[Amplitude] Page Location': '',\n          '[Amplitude] Page Path': '',\n          '[Amplitude] Page Title': '',\n          '[Amplitude] Page URL': '',\n          '[Amplitude] Previous Page Location': '',\n          '[Amplitude] Previous Page Type': 'direct',\n        },\n        library: library,\n        user_agent: userAgent,\n      });\n      expect(response.code).toBe(200);\n      expect(response.message).toBe(SUCCESS_MESSAGE);\n      expect(document.cookie.includes('amp_')).toBe(false);\n      scope.done();\n    });\n\n    test('should retain old cookies', async () => {\n      const scope = nock(url).post(path).reply(200, success);\n      await client.init(apiKey, {\n        defaultTracking,\n        cookieOptions: {\n          upgrade: false,\n        },\n        fetchRemoteConfig: false,\n      }).promise;\n      const response = await client.track('test event', {\n        mode: 'test',\n      }).promise;\n      expect(response.event).toEqual({\n        user_id: previousSessionUserId,\n        device_id: previousSessionDeviceId,\n        session_id: previousSessionId,\n        time: number,\n        platform: 'Web',\n        language: 'en-US',\n        ip: '$remote',\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event',\n        event_id: 100,\n        event_properties: {\n          mode: 'test',\n          '[Amplitude] Page Domain': '',\n          '[Amplitude] Page Location': '',\n          '[Amplitude] Page Path': '',\n          '[Amplitude] Page Title': '',\n          '[Amplitude] Page URL': '',\n          '[Amplitude] Previous Page Location': '',\n          '[Amplitude] Previous Page Type': 'direct',\n        },\n        library: library,\n        user_agent: userAgent,\n      });\n      expect(response.code).toBe(200);\n      expect(response.message).toBe(SUCCESS_MESSAGE);\n      expect(document.cookie.includes('amp_')).toBe(true);\n      scope.done();\n    });\n  });\n\n  describe('custom config', () => {\n    describe('serverUrl', () => {\n      test('should track event to custom serverUrl', async () => {\n        const serverUrl = 'https://domain.com';\n        const scope = nock(serverUrl).post(path).reply(200, success);\n\n        await client.init(apiKey, {\n          defaultTracking,\n          serverUrl: serverUrl + path,\n          fetchRemoteConfig: false,\n        }).promise;\n        const response = await client.track('test event').promise;\n        expect(response.event).toEqual({\n          user_id: undefined,\n          device_id: uuid,\n          session_id: number,\n          time: number,\n          platform: 'Web',\n          language: 'en-US',\n          ip: '$remote',\n          insert_id: uuid,\n          partner_id: undefined,\n          event_type: 'test event',\n          event_id: 0,\n          event_properties: {\n            '[Amplitude] Page Domain': '',\n            '[Amplitude] Page Location': '',\n            '[Amplitude] Page Path': '',\n            '[Amplitude] Page Title': '',\n            '[Amplitude] Page URL': '',\n            '[Amplitude] Previous Page Location': '',\n            '[Amplitude] Previous Page Type': 'direct',\n          },\n          library: library,\n          user_agent: userAgent,\n        });\n        expect(response.code).toBe(200);\n        expect(response.message).toBe(SUCCESS_MESSAGE);\n        scope.done();\n      });\n    });\n\n    describe('debug mode', () => {\n      test('should enable debug mode for track', async () => {\n        const scope = nock(url).post(path).reply(200, success);\n\n        const logger = {\n          disable: jest.fn(),\n          enable: jest.fn(),\n          debug: jest.fn(),\n          log: jest.fn(),\n          warn: jest.fn(),\n          error: jest.fn(),\n        };\n        await client.init(apiKey, {\n          defaultTracking,\n          loggerProvider: logger,\n          logLevel: LogLevel.Debug,\n          fetchRemoteConfig: false,\n        }).promise;\n\n        const response = await client.track('test event').promise;\n        expect(response.event).toEqual({\n          user_id: undefined,\n          device_id: uuid,\n          session_id: number,\n          time: number,\n          platform: 'Web',\n          language: 'en-US',\n          ip: '$remote',\n          insert_id: uuid,\n          partner_id: undefined,\n          event_type: 'test event',\n          event_id: 0,\n          event_properties: {\n            '[Amplitude] Page Domain': '',\n            '[Amplitude] Page Location': '',\n            '[Amplitude] Page Path': '',\n            '[Amplitude] Page Title': '',\n            '[Amplitude] Page URL': '',\n            '[Amplitude] Previous Page Location': '',\n            '[Amplitude] Previous Page Type': 'direct',\n          },\n          library: library,\n          user_agent: userAgent,\n        });\n        expect(response.code).toBe(200);\n        expect(response.message).toBe(SUCCESS_MESSAGE);\n        scope.done();\n\n        expect(logger.debug).toHaveBeenCalledTimes(6);\n        /* eslint-disable */\n        const debugContext = JSON.parse(logger.debug.mock.calls[5]);\n        expect(debugContext.type).toBeDefined();\n        expect(debugContext.name).toEqual('track');\n        expect(debugContext.args).toBeDefined();\n        expect(debugContext.stacktrace).toBeDefined();\n        expect(debugContext.time).toBeDefined();\n        expect(debugContext.states).toBeDefined();\n        /* eslint-enable */\n      });\n\n      test('should enable debug mode for setOptOut', async () => {\n        const logger = {\n          disable: jest.fn(),\n          enable: jest.fn(),\n          debug: jest.fn(),\n          log: jest.fn(),\n          warn: jest.fn(),\n          error: jest.fn(),\n        };\n        await client.init(apiKey, {\n          defaultTracking,\n          loggerProvider: logger,\n          logLevel: LogLevel.Debug,\n          fetchRemoteConfig: false,\n        }).promise;\n        client.setOptOut(true);\n\n        expect(logger.debug).toHaveBeenCalledTimes(6);\n        /* eslint-disable */\n        const debugContext = JSON.parse(logger.debug.mock.calls[5]);\n        expect(debugContext.type).toBeDefined();\n        expect(debugContext.name).toEqual('setOptOut');\n        expect(debugContext.args).toBeDefined();\n        expect(debugContext.stacktrace).toBeDefined();\n        expect(debugContext.time).toBeDefined();\n        expect(debugContext.states).toBeDefined();\n        /* eslint-enable */\n      });\n    });\n  });\n\n  describe('browser cookie existence', () => {\n    test('should create cookies', async () => {\n      // intercept for attribution event and identify event\n      const scope1 = nock(url).post(path).reply(200, success);\n      // intercept for test event\n      const scope2 = nock(url).post(path).reply(200, success);\n      await client.init(apiKey, {\n        identityStorage: 'cookie',\n        fetchRemoteConfig: false,\n      }).promise;\n      await client.identify(new amplitude.Identify().set('a', 'b')).promise;\n      await client.track('Test Event').promise;\n      expect(document.cookie).toContain(`AMP_${apiKey.substring(0, 10)}`);\n      expect(document.cookie).toContain(`AMP_MKTG_${apiKey.substring(0, 10)}`);\n      scope1.done();\n      scope2.done();\n    });\n\n    test('should not create cookies', async () => {\n      // intercept for attribution event and identify event\n      const scope1 = nock(url).post(path).reply(200, success);\n      // intercept for test event\n      const scope2 = nock(url).post(path).reply(200, success);\n      await client.init(apiKey, {\n        identityStorage: 'localStorage',\n        fetchRemoteConfig: false,\n      }).promise;\n      await client.identify(new amplitude.Identify().set('a', 'b')).promise;\n      await client.track('Test Event').promise;\n      expect(document.cookie).not.toContain(`AMP_${apiKey.substring(0, 10)}`);\n      expect(document.cookie).not.toContain(`AMP_MKTG_${apiKey.substring(0, 10)}`);\n      scope1.done();\n      scope2.done();\n    });\n  });\n});\n\nconst setLegacyCookie = (\n  apiKey: string,\n  deviceId?: string,\n  userId?: string,\n  optOut?: '1',\n  sessionId?: number,\n  lastEventTime?: number,\n  eventId?: number,\n) => {\n  document.cookie = `amp_${apiKey.substring(0, 6)}=${[\n    deviceId,\n    btoa(userId || ''),\n    optOut,\n    sessionId ? sessionId.toString(32) : '',\n    lastEventTime ? lastEventTime.toString(32) : '',\n    eventId ? eventId.toString(32) : '',\n  ].join('.')}`;\n};\n\nconst mockWindowLocationFromURL = (url: URL) => {\n  window.location.href = url.toString();\n  window.location.search = url.search;\n  window.location.hostname = url.hostname;\n  window.location.pathname = url.pathname;\n};\n"
  },
  {
    "path": "packages/analytics-browser-test/test/responses.ts",
    "content": "export const success = {\n  code: 200,\n  events_ingested: 1,\n  payload_size_bytes: 50,\n  server_upload_time: 1396381378123,\n};\n"
  },
  {
    "path": "packages/analytics-browser-test/test/setup.ts",
    "content": "import { TextEncoder } from 'util';\n\nif (typeof global.TextEncoder === 'undefined') {\n  (global as typeof global & { TextEncoder?: typeof TextEncoder }).TextEncoder = TextEncoder;\n}\n"
  },
  {
    "path": "packages/analytics-browser-test/test/web-attribution.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unsafe-call */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\nimport * as amplitude from '@amplitude/analytics-browser';\nimport { UUID } from '@amplitude/analytics-core';\nimport { default as nock } from 'nock';\nimport { path, url as httpEndPoint } from './constants';\nimport { success } from './responses';\nimport 'isomorphic-fetch';\nimport {\n  generateEvent,\n  generateAttributionEvent,\n  generateSessionStartEvent,\n  generateSessionEndEvent,\n  generatePageViewEvent,\n  navigateTo,\n} from './helpers';\n\ndescribe('Web attribution', () => {\n  const defaultTracking = {\n    attribution: true,\n    fileDownloads: false,\n    formInteractions: false,\n    pageViews: true,\n    sessions: true,\n  };\n\n  let apiKey = '';\n  let client = amplitude.createInstance();\n\n  const event_upload_time = '2023-01-01T12:00:00:000Z';\n  Date.prototype.toISOString = jest.fn(() => event_upload_time);\n\n  beforeEach(() => {\n    client = amplitude.createInstance();\n    apiKey = UUID();\n  });\n\n  describe('Page load', () => {\n    describe('in a new session', () => {\n      let eventId = -1;\n      beforeEach(() => {\n        eventId = -1;\n      });\n\n      afterEach(() => {\n        cleanup();\n      });\n\n      test('should track all UTMs and referrers', async () => {\n        const referrer = 'https://www.google.com/';\n        const url = 'https://www.example.com?utm_source=test_utm_source';\n        navigateTo(url, referrer);\n\n        let payload: any = undefined;\n        const scope = nock(httpEndPoint)\n          .post(path, (body: Record<string, any>) => {\n            payload = body;\n            return true;\n          })\n          .reply(200, success);\n\n        await client.init(apiKey, 'user1@amplitude.com', {\n          deviceId: UUID(),\n          defaultTracking,\n          sessionTimeout: 500,\n          flushIntervalMillis: 3000,\n          fetchRemoteConfig: false,\n        }).promise;\n\n        return new Promise<void>((resolve) => {\n          setTimeout(() => {\n            expect(payload).toEqual({\n              api_key: apiKey,\n              client_upload_time: event_upload_time,\n              events: [\n                generateAttributionEvent(++eventId, url, referrer),\n                generateSessionStartEvent(++eventId, {\n                  withPageURLEnrichmentProperties: { url, previousPageUrl: referrer },\n                }),\n                generatePageViewEvent(++eventId, 1, url, referrer, {\n                  withPageURLEnrichmentProperties: { previousPageUrl: referrer },\n                }),\n              ],\n              options: {\n                min_id_length: undefined,\n              },\n            });\n            scope.done();\n            resolve();\n          }, 4000);\n        });\n      });\n\n      test('should track EMPTY campaign if no UTMs and no referrer', async () => {\n        const url = 'https://www.example.com';\n        navigateTo(url);\n\n        let payload: any = undefined;\n        const scope = nock(httpEndPoint)\n          .post(path, (body: Record<string, any>) => {\n            payload = body;\n            return true;\n          })\n          .reply(200, success);\n\n        await client.init(apiKey, 'user1@amplitude.com', {\n          deviceId: UUID(),\n          defaultTracking,\n          sessionTimeout: 500,\n          flushIntervalMillis: 3000,\n          fetchRemoteConfig: false,\n        }).promise;\n\n        return new Promise<void>((resolve) => {\n          setTimeout(() => {\n            expect(payload).toEqual({\n              api_key: apiKey,\n              client_upload_time: event_upload_time,\n              events: [\n                generateAttributionEvent(++eventId, url),\n                generateSessionStartEvent(++eventId, { withPageURLEnrichmentProperties: { url } }),\n                generatePageViewEvent(++eventId, 1, url, undefined, {\n                  withPageURLEnrichmentProperties: {},\n                }),\n              ],\n              options: {\n                min_id_length: undefined,\n              },\n            });\n            scope.done();\n            resolve();\n          }, 4000);\n        });\n      });\n\n      test('should not track all UTMs and referrers if the referrer is excluded referrer', async () => {\n        const referrer = 'https://www.google.com/';\n        const referrerDomain = 'www.google.com';\n        const url = 'https://www.example.com?utm_source=test_utm_source';\n        navigateTo(url, referrer);\n\n        let payload: any = undefined;\n        const scope = nock(httpEndPoint)\n          .post(path, (body: Record<string, any>) => {\n            payload = body;\n            return true;\n          })\n          .reply(200, success);\n\n        await client.init(apiKey, 'user1@amplitude.com', {\n          deviceId: UUID(),\n          defaultTracking: {\n            ...defaultTracking,\n            attribution: {\n              excludeReferrers: [referrerDomain],\n            },\n          },\n          sessionTimeout: 500,\n          flushIntervalMillis: 3000,\n          fetchRemoteConfig: false,\n        }).promise;\n\n        return new Promise<void>((resolve) => {\n          setTimeout(() => {\n            expect(payload).toEqual({\n              api_key: apiKey,\n              client_upload_time: event_upload_time,\n              events: [\n                generateSessionStartEvent(++eventId, {\n                  withPageURLEnrichmentProperties: { url, previousPageUrl: referrer },\n                }),\n                generatePageViewEvent(++eventId, 1, url, referrer, {\n                  withPageURLEnrichmentProperties: { previousPageUrl: referrer },\n                }),\n              ],\n              options: {\n                min_id_length: undefined,\n              },\n            });\n            scope.done();\n            resolve();\n          }, 4000);\n        });\n      });\n    });\n\n    describe('during a session', () => {\n      let eventId = -1;\n      beforeEach(() => {\n        eventId = -1;\n      });\n\n      afterEach(() => {\n        cleanup();\n      });\n\n      test('should not fire campaign identify event for direct traffic', async () => {\n        const url = 'https://www.example.com?utm_source=test_utm_source';\n        navigateTo(url);\n\n        let payload: any = undefined;\n        const scope = nock(httpEndPoint)\n          .post(path, (body: Record<string, any>) => {\n            payload = body;\n            return true;\n          })\n          .reply(200, success);\n\n        nock(httpEndPoint)\n          .post(path, (body: Record<string, any>) => {\n            payload = body;\n            return true;\n          })\n          .reply(200, success);\n\n        await client.init(apiKey, 'user1@amplitude.com', {\n          deviceId: UUID(),\n          defaultTracking,\n          sessionTimeout: 500,\n          flushIntervalMillis: 3000,\n          fetchRemoteConfig: false,\n        }).promise;\n\n        await new Promise((resolve) => setTimeout(resolve, 200));\n\n        // refresh during the session.\n        const directUrl = 'https://www.example.com/home';\n        navigateTo(directUrl);\n\n        await new Promise((resolve) => setTimeout(resolve, 100));\n\n        await client.init(apiKey, 'user1@amplitude.com', {\n          deviceId: UUID(),\n          defaultTracking,\n          sessionTimeout: 500,\n          flushIntervalMillis: 3000,\n          fetchRemoteConfig: false,\n        }).promise;\n\n        return new Promise<void>((resolve) => {\n          setTimeout(() => {\n            expect(payload).toEqual({\n              api_key: apiKey,\n              client_upload_time: event_upload_time,\n              events: [\n                generateAttributionEvent(++eventId, url),\n                generateSessionStartEvent(++eventId, { withPageURLEnrichmentProperties: { url } }),\n                generatePageViewEvent(++eventId, 1, url, undefined, {\n                  withPageURLEnrichmentProperties: {},\n                }),\n                generatePageViewEvent(++eventId, 2, directUrl, undefined, {\n                  withPageURLEnrichmentProperties: {}, // no referrer because the previous page prop relies on document.referrer for non-SPA sites\n                }),\n              ],\n              options: {\n                min_id_length: undefined,\n              },\n            });\n            scope.done();\n            resolve();\n          }, 4000);\n        });\n      });\n\n      test('should track all UTMs and referrers if any campaign changed and not direct traffic', async () => {\n        const url = 'https://www.example.com?utm_source=test_utm_source';\n        navigateTo(url);\n\n        let payload: any = undefined;\n        const scope = nock(httpEndPoint)\n          .post(path, (body: Record<string, any>) => {\n            payload = body;\n            return true;\n          })\n          .reply(200, success);\n\n        nock(httpEndPoint)\n          .post(path, (body: Record<string, any>) => {\n            payload = body;\n            return true;\n          })\n          .reply(200, success);\n\n        await client.init(apiKey, 'user1@amplitude.com', {\n          deviceId: UUID(),\n          defaultTracking,\n          sessionTimeout: 500,\n          flushIntervalMillis: 3000,\n          fetchRemoteConfig: false,\n        }).promise;\n\n        await new Promise((resolve) => setTimeout(resolve, 200));\n\n        // mock refresh during the session with updated campaign change.\n        const newCampaignURL = 'https://www.example.com/?utm_source=second_utm_source&utm_content=test_utm_content';\n        navigateTo(newCampaignURL);\n\n        await new Promise((resolve) => setTimeout(resolve, 100));\n\n        await client.init(apiKey, 'user1@amplitude.com', {\n          deviceId: UUID(),\n          defaultTracking,\n          sessionTimeout: 500,\n          flushIntervalMillis: 3000,\n          fetchRemoteConfig: false,\n        }).promise;\n\n        return new Promise<void>((resolve) => {\n          setTimeout(() => {\n            expect(payload).toEqual({\n              api_key: apiKey,\n              client_upload_time: event_upload_time,\n              events: [\n                generateAttributionEvent(++eventId, url),\n                generateSessionStartEvent(++eventId, { withPageURLEnrichmentProperties: { url } }),\n                generatePageViewEvent(++eventId, 1, url, undefined, {\n                  withPageURLEnrichmentProperties: {},\n                }),\n                generateAttributionEvent(++eventId, newCampaignURL),\n                generatePageViewEvent(++eventId, 2, newCampaignURL, undefined, {\n                  withPageURLEnrichmentProperties: {}, // no referrer because the previous page prop relies on document.referrer for non-SPA sites\n                }),\n              ],\n              options: {\n                min_id_length: undefined,\n              },\n            });\n            scope.done();\n            resolve();\n          }, 4000);\n        });\n      });\n\n      test('should start a new session with resetSessionCampaign enable and track campaign updates', async () => {\n        const url = 'https://www.example.com?utm_source=test_utm_source';\n        navigateTo(url);\n\n        let payload: any = undefined;\n        const scope = nock(httpEndPoint)\n          .post(path, (body: Record<string, any>) => {\n            payload = body;\n            return true;\n          })\n          .reply(200, success);\n\n        nock(httpEndPoint)\n          .post(path, (body: Record<string, any>) => {\n            payload = body;\n            return true;\n          })\n          .reply(200, success);\n\n        await client.init(apiKey, 'user1@amplitude.com', {\n          deviceId: UUID(),\n          defaultTracking: {\n            ...defaultTracking,\n            attribution: {\n              resetSessionOnNewCampaign: true,\n            },\n          },\n          sessionTimeout: 500,\n          flushIntervalMillis: 3000,\n          fetchRemoteConfig: false,\n        }).promise;\n\n        await new Promise((resolve) => setTimeout(resolve, 100));\n\n        // refresh during the session.\n        const directUrl = 'https://www.example.com/?utm_content=test_utm_content';\n        navigateTo(directUrl);\n\n        // eslint-disable-next-line @typescript-eslint/no-misused-promises\n        setTimeout(async () => {\n          await client.init(apiKey, 'user1@amplitude.com', {\n            deviceId: UUID(),\n            defaultTracking: {\n              ...defaultTracking,\n              attribution: {\n                resetSessionOnNewCampaign: true,\n              },\n            },\n            sessionTimeout: 500,\n            flushIntervalMillis: 3000,\n            fetchRemoteConfig: false,\n          }).promise;\n        }, 100);\n\n        return new Promise<void>((resolve) => {\n          setTimeout(() => {\n            expect(payload).toEqual({\n              api_key: apiKey,\n              client_upload_time: event_upload_time,\n              events: [\n                generateAttributionEvent(++eventId, url),\n                generateSessionStartEvent(++eventId, { withPageURLEnrichmentProperties: { url } }),\n                generatePageViewEvent(++eventId, 1, url, undefined, {\n                  withPageURLEnrichmentProperties: {},\n                }),\n                generateSessionEndEvent(++eventId, { withPageURLEnrichmentProperties: { url: directUrl } }), // no referrer because the previous page prop relies on document.referrer for non-SPA sites\n                generateAttributionEvent(++eventId, directUrl),\n                generateSessionStartEvent(++eventId, { withPageURLEnrichmentProperties: { url: directUrl } }), // no referrer because the previous page prop relies on document.referrer for non-SPA sites\n                generatePageViewEvent(++eventId, 1, directUrl, undefined, {\n                  withPageURLEnrichmentProperties: {},\n                }), // no referrer because the previous page prop relies on document.referrer for non-SPA sites\n              ],\n              options: {\n                min_id_length: undefined,\n              },\n            });\n            scope.done();\n            resolve();\n          }, 4000);\n        });\n      });\n    });\n  });\n\n  describe('process event', () => {\n    describe('in a new session', () => {\n      let eventId = -1;\n      beforeEach(() => {\n        eventId = -1;\n      });\n\n      afterEach(() => {\n        cleanup();\n      });\n\n      //The SPA won't reload the page when redirected. We don't track campaign updates without reinitializing the SDK (reloading the page) for now.\n      test('Not track campaign change while processing any event', async () => {\n        const url = 'https://www.example.com?utm_source=test_utm_source';\n        navigateTo(url);\n\n        let payload: any = undefined;\n        const scope = nock(httpEndPoint)\n          .post(path, (body: Record<string, any>) => {\n            payload = body;\n            return true;\n          })\n          .reply(200, success);\n\n        await client.init(apiKey, 'user1@amplitude.com', {\n          deviceId: UUID(),\n          defaultTracking,\n          sessionTimeout: 500,\n          flushIntervalMillis: 3000,\n          fetchRemoteConfig: false,\n        }).promise;\n\n        // update the url and fire the first event after session timeout\n        const newCampaignURL = 'https://www.example.com?utm_source=second_utm_source&utm_content=test_utm_content';\n        setTimeout(() => {\n          navigateTo(newCampaignURL);\n\n          client.track('test event after session timeout');\n        }, 600);\n\n        return new Promise<void>((resolve) => {\n          setTimeout(() => {\n            expect(payload).toEqual({\n              api_key: apiKey,\n              client_upload_time: event_upload_time,\n              events: [\n                generateAttributionEvent(++eventId, url),\n                generateSessionStartEvent(++eventId, { withPageURLEnrichmentProperties: { url } }),\n                generatePageViewEvent(++eventId, 1, url, undefined, {\n                  withPageURLEnrichmentProperties: {},\n                }),\n                generateSessionEndEvent(++eventId, { withPageURLEnrichmentProperties: { url: newCampaignURL } }), // no previous page url prop since there is no pushstate event or referrer\n                generateSessionStartEvent(++eventId, { withPageURLEnrichmentProperties: { url: newCampaignURL } }), // no previous page url prop since there is no pushstate event or referrer\n                generateEvent(++eventId, 'test event after session timeout', {\n                  withPageURLEnrichmentProperties: { url: newCampaignURL }, // no previous page url prop since there is no pushstate event or referrer\n                }),\n              ],\n              options: {\n                min_id_length: undefined,\n              },\n            });\n            scope.done();\n            resolve();\n          }, 4000);\n        });\n      });\n\n      test('should not track UTMs and referrers if the referrer is excluded referrer', async () => {\n        const referrer = 'https://www.google.com/';\n        const referring_domain = 'www.google.com';\n        const url = 'https://www.example.com?utm_source=test_utm_source';\n        navigateTo(url, referrer);\n\n        let payload: any = undefined;\n        const scope = nock(httpEndPoint)\n          .post(path, (body: Record<string, any>) => {\n            payload = body;\n            return true;\n          })\n          .reply(200, success);\n\n        await client.init(apiKey, 'user1@amplitude.com', {\n          deviceId: UUID(),\n          defaultTracking: {\n            ...defaultTracking,\n            attribution: {\n              excludeReferrers: [referring_domain],\n            },\n            sessions: true,\n          },\n          sessionTimeout: 500,\n          flushIntervalMillis: 3000,\n          fetchRemoteConfig: false,\n        }).promise;\n\n        // update the url and fire the first event after session timeout\n        const newCampaignURL = 'https://www.example.com?utm_source=second_utm_source&utm_content=test_utm_content';\n        setTimeout(() => {\n          navigateTo(newCampaignURL);\n\n          client.track('test event after session timeout');\n        }, 600);\n\n        return new Promise<void>((resolve) => {\n          setTimeout(() => {\n            expect(payload).toEqual({\n              api_key: apiKey,\n              client_upload_time: event_upload_time,\n              events: [\n                generateSessionStartEvent(++eventId, {\n                  withPageURLEnrichmentProperties: { url, previousPageUrl: referrer },\n                }),\n                generatePageViewEvent(++eventId, 1, url, referrer, {\n                  withPageURLEnrichmentProperties: { previousPageUrl: referrer },\n                }),\n                generateSessionEndEvent(++eventId, {\n                  withPageURLEnrichmentProperties: { url: newCampaignURL, previousPageUrl: referrer }, // referrer stays the same as it has not been changed or removed\n                }),\n                generateSessionStartEvent(++eventId, {\n                  withPageURLEnrichmentProperties: { url: newCampaignURL, previousPageUrl: referrer }, // referrer stays the same as it has not been changed or removed\n                }),\n\n                generateEvent(++eventId, 'test event after session timeout', {\n                  withPageURLEnrichmentProperties: { url: newCampaignURL, previousPageUrl: referrer }, // referrer stays the same as it has not been changed or removed\n                }),\n              ],\n              options: {\n                min_id_length: undefined,\n              },\n            });\n            scope.done();\n            resolve();\n          }, 4000);\n        });\n      });\n    });\n\n    // Specific tests for an SPA. The SPA won't reload the page when redirected. We don't track campaign updates without reinitializing the SDK (reloading the page).\n    describe('during a session', () => {\n      let eventId = -1;\n      beforeEach(() => {\n        eventId = -1;\n      });\n\n      afterEach(() => {\n        cleanup();\n      });\n\n      test('should not track updated campaign', async () => {\n        const url = 'https://www.example.com?utm_source=test_utm_source';\n        navigateTo(url);\n\n        let payload: any = undefined;\n        const scope = nock(httpEndPoint)\n          .post(path, (body: Record<string, any>) => {\n            payload = body;\n            return true;\n          })\n          .reply(200, success);\n\n        await client.init(apiKey, 'user1@amplitude.com', {\n          deviceId: UUID(),\n          defaultTracking,\n          sessionTimeout: 500,\n          flushIntervalMillis: 3000,\n          fetchRemoteConfig: false,\n        }).promise;\n\n        await new Promise((resolve) => setTimeout(resolve, 100));\n\n        // update the url and fire the first event during the same session without refreshing the page\n        const newCampaignURL = 'https://www.example.com?utm_source=second_utm_source&utm_content=test_utm_content';\n        navigateTo(newCampaignURL);\n\n        client.track('test event in the same session');\n\n        return new Promise<void>((resolve) => {\n          setTimeout(() => {\n            expect(payload).toEqual({\n              api_key: apiKey,\n              client_upload_time: event_upload_time,\n              events: [\n                generateAttributionEvent(++eventId, url),\n                generateSessionStartEvent(++eventId, { withPageURLEnrichmentProperties: { url } }),\n                generatePageViewEvent(++eventId, 1, url, undefined, {\n                  withPageURLEnrichmentProperties: { previousPageUrl: '' }, // no previous page url prop since there is no pushstate event or referrer\n                }),\n                generateEvent(++eventId, 'test event in the same session', {\n                  withPageURLEnrichmentProperties: { url: newCampaignURL, previousPageUrl: '' }, // no previous page url prop since there is no pushstate event or referrer\n                }),\n              ],\n              options: {\n                min_id_length: undefined,\n              },\n            });\n            scope.done();\n            resolve();\n          }, 4000);\n        });\n      });\n\n      test('should not track campaign with resetSessionCampaign enable', async () => {\n        const url = 'https://www.example.com?utm_source=test_utm_source';\n        navigateTo(url);\n\n        let payload: any = undefined;\n        const scope = nock(httpEndPoint)\n          .post(path, (body: Record<string, any>) => {\n            payload = body;\n            return true;\n          })\n          .reply(200, success);\n\n        await client.init(apiKey, 'user1@amplitude.com', {\n          deviceId: UUID(),\n          defaultTracking: {\n            ...defaultTracking,\n            attribution: {\n              resetSessionOnNewCampaign: true,\n            },\n            sessions: true,\n          },\n          sessionTimeout: 500,\n          flushIntervalMillis: 3000,\n          fetchRemoteConfig: false,\n        }).promise;\n\n        await new Promise((resolve) => setTimeout(resolve, 100));\n\n        // refresh during the session.\n        const directUrl = 'https://www.example.com/?utm_content=test_utm_content';\n        navigateTo(directUrl);\n\n        client.track('test event in same session');\n\n        return new Promise<void>((resolve) => {\n          setTimeout(() => {\n            expect(payload).toEqual({\n              api_key: apiKey,\n              client_upload_time: event_upload_time,\n              events: [\n                generateAttributionEvent(++eventId, url),\n                generateSessionStartEvent(++eventId, { withPageURLEnrichmentProperties: { url } }),\n                generatePageViewEvent(++eventId, 1, url, undefined, {\n                  withPageURLEnrichmentProperties: {},\n                }),\n                generateEvent(++eventId, 'test event in same session', {\n                  withPageURLEnrichmentProperties: { url: directUrl, previousPageUrl: '' }, // no previous page url prop since there is no pushstate event or referrer\n                }),\n              ],\n              options: {\n                min_id_length: undefined,\n              },\n            });\n            scope.done();\n            resolve();\n          }, 4000);\n        });\n      });\n\n      test('should not drop campaign without reinitializing the SDK after unsetting the referrer', async () => {\n        const url = 'https://www.example.com?utm_source=test_utm_source';\n        const initReferrer = 'https://www.test.com/';\n\n        navigateTo(url, initReferrer);\n        expect(document.referrer).toEqual(initReferrer);\n\n        let payload: any = undefined;\n        const scope = nock(httpEndPoint)\n          .post(path, (body: Record<string, any>) => {\n            payload = body;\n            return true;\n          })\n          .reply(200, success);\n\n        await client.init(apiKey, 'user1@amplitude.com', {\n          deviceId: UUID(),\n          defaultTracking,\n          sessionTimeout: 500,\n          flushIntervalMillis: 3000,\n          fetchRemoteConfig: false,\n        }).promise;\n\n        await new Promise((resolve) => setTimeout(resolve, 100));\n\n        // Unset the referrer after first hit\n        Object.defineProperty(document, 'referrer', { value: '', configurable: true });\n        expect(document.referrer).toEqual('');\n\n        // Update the url to drop all UTM to mock SPA redirect during the same session without refreshing the page\n        // Fire page view event in current session\n        const newURL = 'https://www.example.com';\n        navigateTo(newURL);\n        window.history.pushState(undefined, newURL);\n\n        return new Promise<void>((resolve) => {\n          setTimeout(() => {\n            expect(payload).toEqual({\n              api_key: apiKey,\n              client_upload_time: event_upload_time,\n              events: [\n                generateAttributionEvent(++eventId, url, initReferrer),\n                generateSessionStartEvent(++eventId, {\n                  withPageURLEnrichmentProperties: { url, previousPageUrl: initReferrer },\n                }),\n                generatePageViewEvent(++eventId, 1, url, initReferrer, {\n                  withPageURLEnrichmentProperties: { previousPageUrl: initReferrer },\n                }),\n                generatePageViewEvent(++eventId, 2, newURL, undefined, {\n                  withPageURLEnrichmentProperties: { previousPageUrl: url },\n                }),\n              ],\n              options: {\n                min_id_length: undefined,\n              },\n            });\n            scope.done();\n            resolve();\n          }, 4000);\n        });\n      });\n    });\n  });\n\n  const cleanup = () => {\n    // clean up cookies\n    document.cookie = `amp_${apiKey.substring(0, 6)}=null; expires=1 Jan 1970 00:00:00 GMT`;\n    document.cookie = `AMP_${apiKey.substring(0, 10)}=null; expires=1 Jan 1970 00:00:00 GMT`;\n    document.cookie = `AMP_MKTG_${apiKey.substring(0, 10)}=null; expires=1 Jan 1970 00:00:00 GMT`;\n    (window.location as any) = {\n      hostname: '',\n      href: '',\n      pathname: '',\n      search: '',\n    };\n    Object.defineProperty(document, 'referrer', { value: '', configurable: true });\n\n    // clear url info in session storage from page url enrichment plugin\n    window.sessionStorage.setItem('AMP_URL_INFO', '{}');\n  };\n});\n"
  },
  {
    "path": "packages/analytics-browser-test/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"test/**/*\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"esModuleInterop\": true,\n    \"lib\": [\"dom\"],\n    \"noEmit\": true,\n    \"rootDir\": \".\",\n  }\n}\n"
  },
  {
    "path": "packages/analytics-client-common/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.4.47](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.46...@amplitude/analytics-client-common@2.4.47) (2026-04-28)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.46](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.45...@amplitude/analytics-client-common@2.4.46) (2026-04-22)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.45](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.44...@amplitude/analytics-client-common@2.4.45) (2026-04-21)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.44](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.43...@amplitude/analytics-client-common@2.4.44) (2026-04-14)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.43](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.42...@amplitude/analytics-client-common@2.4.43) (2026-04-09)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.42](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.41...@amplitude/analytics-client-common@2.4.42) (2026-04-01)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.41](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.40...@amplitude/analytics-client-common@2.4.41) (2026-03-26)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.40](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.39...@amplitude/analytics-client-common@2.4.40) (2026-03-23)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.39](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.38...@amplitude/analytics-client-common@2.4.39) (2026-03-20)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.38](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.37...@amplitude/analytics-client-common@2.4.38) (2026-03-19)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.37](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.36...@amplitude/analytics-client-common@2.4.37) (2026-03-17)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.36](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.35...@amplitude/analytics-client-common@2.4.36) (2026-03-16)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.35](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.34...@amplitude/analytics-client-common@2.4.35) (2026-03-13)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.34](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.33...@amplitude/analytics-client-common@2.4.34) (2026-03-12)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.33](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.32...@amplitude/analytics-client-common@2.4.33) (2026-03-09)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.32](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.31...@amplitude/analytics-client-common@2.4.32) (2026-03-05)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.31](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.30...@amplitude/analytics-client-common@2.4.31) (2026-03-03)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.30](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.29...@amplitude/analytics-client-common@2.4.30) (2026-03-03)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.29](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.28...@amplitude/analytics-client-common@2.4.29) (2026-02-26)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.28](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.27...@amplitude/analytics-client-common@2.4.28) (2026-02-24)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.27](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.26...@amplitude/analytics-client-common@2.4.27) (2026-02-19)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.26](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.25...@amplitude/analytics-client-common@2.4.26) (2026-02-17)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.25](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.24...@amplitude/analytics-client-common@2.4.25) (2026-02-10)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.24](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.23...@amplitude/analytics-client-common@2.4.24) (2026-01-26)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.23](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.22...@amplitude/analytics-client-common@2.4.23) (2026-01-21)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.22](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.21...@amplitude/analytics-client-common@2.4.22) (2026-01-15)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.21](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.20...@amplitude/analytics-client-common@2.4.21) (2026-01-14)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.20](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.19...@amplitude/analytics-client-common@2.4.20) (2026-01-14)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.19](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.18...@amplitude/analytics-client-common@2.4.19) (2025-12-24)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.18](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.17...@amplitude/analytics-client-common@2.4.18) (2025-12-16)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.17](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.16...@amplitude/analytics-client-common@2.4.17) (2025-12-09)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.16](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.15...@amplitude/analytics-client-common@2.4.16) (2025-11-21)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.15](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.14...@amplitude/analytics-client-common@2.4.15) (2025-11-20)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.14](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.13...@amplitude/analytics-client-common@2.4.14) (2025-11-17)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.12...@amplitude/analytics-client-common@2.4.13) (2025-11-17)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.11...@amplitude/analytics-client-common@2.4.12) (2025-11-05)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.10...@amplitude/analytics-client-common@2.4.11) (2025-10-29)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.9...@amplitude/analytics-client-common@2.4.10) (2025-10-23)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.8...@amplitude/analytics-client-common@2.4.9) (2025-10-23)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.7...@amplitude/analytics-client-common@2.4.8) (2025-10-17)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.6...@amplitude/analytics-client-common@2.4.7) (2025-10-15)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.5...@amplitude/analytics-client-common@2.4.6) (2025-10-14)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.4...@amplitude/analytics-client-common@2.4.5) (2025-10-14)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.3...@amplitude/analytics-client-common@2.4.4) (2025-10-07)\n\n\n### Bug Fixes\n\n* Revert \"feat(analytics-client-common): refactor getPageTitle from aut… ([#1328](https://github.com/amplitude/Amplitude-TypeScript/issues/1328)) ([3976910](https://github.com/amplitude/Amplitude-TypeScript/commit/3976910d2e17a61f9f8e588a006cd44012f2f250))\n\n\n\n\n\n## [2.4.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.2...@amplitude/analytics-client-common@2.4.3) (2025-10-03)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.1...@amplitude/analytics-client-common@2.4.2) (2025-10-01)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.4.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.4.0...@amplitude/analytics-client-common@2.4.1) (2025-09-25)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n# [2.4.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.42...@amplitude/analytics-client-common@2.4.0) (2025-09-23)\n\n\n### Features\n\n* **analytics-client-common:** refactor getPageTitle from autocapture to make it reusable ([#1298](https://github.com/amplitude/Amplitude-TypeScript/issues/1298)) ([3c931ee](https://github.com/amplitude/Amplitude-TypeScript/commit/3c931eeb7bb4d2482523c48cf796113187d9b078))\n\n\n\n\n\n## [2.3.42](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.41...@amplitude/analytics-client-common@2.3.42) (2025-09-18)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.41](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.40...@amplitude/analytics-client-common@2.3.41) (2025-09-12)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.40](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.39...@amplitude/analytics-client-common@2.3.40) (2025-09-05)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.39](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.38...@amplitude/analytics-client-common@2.3.39) (2025-08-28)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.38](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.37...@amplitude/analytics-client-common@2.3.38) (2025-08-26)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.37](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.36...@amplitude/analytics-client-common@2.3.37) (2025-08-25)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.36](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.35...@amplitude/analytics-client-common@2.3.36) (2025-08-22)\n\n\n### Bug Fixes\n\n* **analytics-core:** fix typo in Reddit click-id ([#1267](https://github.com/amplitude/Amplitude-TypeScript/issues/1267)) ([43e581d](https://github.com/amplitude/Amplitude-TypeScript/commit/43e581d6465546a38373f758f179eee103172755))\n\n\n\n\n\n## [2.3.35](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.34...@amplitude/analytics-client-common@2.3.35) (2025-08-21)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.34](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.33...@amplitude/analytics-client-common@2.3.34) (2025-08-13)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.33](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.32...@amplitude/analytics-client-common@2.3.33) (2025-08-08)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.32](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.31...@amplitude/analytics-client-common@2.3.32) (2025-08-05)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.31](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.30...@amplitude/analytics-client-common@2.3.31) (2025-07-29)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.30](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.29...@amplitude/analytics-client-common@2.3.30) (2025-07-17)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.29](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.28...@amplitude/analytics-client-common@2.3.29) (2025-07-15)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.28](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.27...@amplitude/analytics-client-common@2.3.28) (2025-07-08)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.27](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.26...@amplitude/analytics-client-common@2.3.27) (2025-06-30)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.26](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.25...@amplitude/analytics-client-common@2.3.26) (2025-06-26)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.25](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.24...@amplitude/analytics-client-common@2.3.25) (2025-06-25)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.24](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.23...@amplitude/analytics-client-common@2.3.24) (2025-06-11)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.23](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.22...@amplitude/analytics-client-common@2.3.23) (2025-06-03)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.22](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.21...@amplitude/analytics-client-common@2.3.22) (2025-05-27)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.21](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.20...@amplitude/analytics-client-common@2.3.21) (2025-05-13)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.20](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.19...@amplitude/analytics-client-common@2.3.20) (2025-05-05)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.19](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.18...@amplitude/analytics-client-common@2.3.19) (2025-05-02)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.18](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.17...@amplitude/analytics-client-common@2.3.18) (2025-05-02)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.17](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.16...@amplitude/analytics-client-common@2.3.17) (2025-04-22)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.16](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.15...@amplitude/analytics-client-common@2.3.16) (2025-04-17)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.15](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.14...@amplitude/analytics-client-common@2.3.15) (2025-04-15)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.14](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.13...@amplitude/analytics-client-common@2.3.14) (2025-04-10)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.12...@amplitude/analytics-client-common@2.3.13) (2025-04-07)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.11...@amplitude/analytics-client-common@2.3.12) (2025-04-02)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.10...@amplitude/analytics-client-common@2.3.11) (2025-03-24)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.9...@amplitude/analytics-client-common@2.3.10) (2025-03-21)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.8...@amplitude/analytics-client-common@2.3.9) (2025-03-14)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.7...@amplitude/analytics-client-common@2.3.8) (2025-02-28)\n\n\n### Reverts\n\n* Revert \"chore(release): publish\" ([d392f62](https://github.com/amplitude/Amplitude-TypeScript/commit/d392f6290b8bb4dd955d6e6f20b00191679489c4))\n\n\n\n\n\n## [2.3.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.6...@amplitude/analytics-client-common@2.3.7) (2024-12-31)\n\n\n### Bug Fixes\n\n* add comments in isNewCampaign() ([#941](https://github.com/amplitude/Amplitude-TypeScript/issues/941)) ([a14a68c](https://github.com/amplitude/Amplitude-TypeScript/commit/a14a68c65cea7a4bf8a842761ff7a81830e5d3ba))\n\n\n\n\n\n## [2.3.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.5...@amplitude/analytics-client-common@2.3.6) (2024-12-17)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.4...@amplitude/analytics-client-common@2.3.5) (2024-11-05)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.3...@amplitude/analytics-client-common@2.3.4) (2024-10-21)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.2...@amplitude/analytics-client-common@2.3.3) (2024-09-17)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.1...@amplitude/analytics-client-common@2.3.2) (2024-09-10)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n## [2.3.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.3.0...@amplitude/analytics-client-common@2.3.1) (2024-08-13)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n\n\n\n\n# [2.3.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.2.4...@amplitude/analytics-client-common@2.3.0) (2024-08-02)\n\n\n### Features\n\n* remote config ([#832](https://github.com/amplitude/Amplitude-TypeScript/issues/832)) ([c415f79](https://github.com/amplitude/Amplitude-TypeScript/commit/c415f792a98253ac60885eb1dc7e53b78ca47dcb)), closes [#769](https://github.com/amplitude/Amplitude-TypeScript/issues/769) [#772](https://github.com/amplitude/Amplitude-TypeScript/issues/772) [#780](https://github.com/amplitude/Amplitude-TypeScript/issues/780) [#782](https://github.com/amplitude/Amplitude-TypeScript/issues/782) [#811](https://github.com/amplitude/Amplitude-TypeScript/issues/811) [#828](https://github.com/amplitude/Amplitude-TypeScript/issues/828)\n\n\n\n\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.2.3...@amplitude/analytics-client-common@2.2.4) (2024-06-24)\n\n### Bug Fixes\n\n- **analytics-browser:** handle double URL encoded cookie values\n  ([#790](https://github.com/amplitude/Amplitude-TypeScript/issues/790))\n  ([577c1a9](https://github.com/amplitude/Amplitude-TypeScript/commit/577c1a940cfe2d3b64590b09bf2cdb03cb961c3f))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.2.2...@amplitude/analytics-client-common@2.2.3) (2024-06-24)\n\n### Bug Fixes\n\n- adding ampIntegrationsContext to getGlobalScope\n  ([bd6f08c](https://github.com/amplitude/Amplitude-TypeScript/commit/bd6f08c10c9814e4f098c37810332c6881b4f424))\n- checking for undefined and added tests\n  ([4176f5f](https://github.com/amplitude/Amplitude-TypeScript/commit/4176f5f0571dbd535761f92c997fb825253807a5))\n- fix reference error\n  ([1af86fa](https://github.com/amplitude/Amplitude-TypeScript/commit/1af86fa8900d8755848d0dece9658cb1f136ed48))\n- fixed minifing the global variable name\n  ([09b733b](https://github.com/amplitude/Amplitude-TypeScript/commit/09b733bcb0dfcb4da2969c5332fdb9b24b060633))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.2.1...@amplitude/analytics-client-common@2.2.2) (2024-06-17)\n\n### Bug Fixes\n\n- add cookie storage logs ([#778](https://github.com/amplitude/Amplitude-TypeScript/issues/778))\n  ([743b9c0](https://github.com/amplitude/Amplitude-TypeScript/commit/743b9c053ec4db4fc754da812534c329de4d1fff))\n- response with non-json format ([#758](https://github.com/amplitude/Amplitude-TypeScript/issues/758))\n  ([3d234ca](https://github.com/amplitude/Amplitude-TypeScript/commit/3d234ca5a71bacf9ab7f82a115cb2010e94a3a33))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.2.0...@amplitude/analytics-client-common@2.2.1) (2024-05-24)\n\n### Bug Fixes\n\n- success response with no body ([#755](https://github.com/amplitude/Amplitude-TypeScript/issues/755))\n  ([5d1eb72](https://github.com/amplitude/Amplitude-TypeScript/commit/5d1eb72bf9114acd884e709660eeedb0511ef4af))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.2.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.1.6...@amplitude/analytics-client-common@2.2.0) (2024-05-21)\n\n### Features\n\n- support sessionId from url for cross domain tracking\n  ([#753](https://github.com/amplitude/Amplitude-TypeScript/issues/753))\n  ([691d725](https://github.com/amplitude/Amplitude-TypeScript/commit/691d725131b5dfba497084fcf101a4e6e22bbd59))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.1.5...@amplitude/analytics-client-common@2.1.6) (2024-05-15)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.1.4...@amplitude/analytics-client-common@2.1.5) (2024-05-03)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.1.4-beta.0...@amplitude/analytics-client-common@2.1.4) (2024-04-29)\n\n### Bug Fixes\n\n- add logic to escape campaign tracking for direct traffic in session\n  ([#726](https://github.com/amplitude/Amplitude-TypeScript/issues/726))\n  ([c0c9a9d](https://github.com/amplitude/Amplitude-TypeScript/commit/c0c9a9d3fcd2a9d6dfe9e12d4a187cf2dba6424c))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.4-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.1.3...@amplitude/analytics-client-common@2.1.4-beta.0) (2024-04-19)\n\n### Bug Fixes\n\n- fix web attribution identify and session start order\n  ([#696](https://github.com/amplitude/Amplitude-TypeScript/issues/696))\n  ([2f077da](https://github.com/amplitude/Amplitude-TypeScript/commit/2f077da7b528ed6f23f7459b7c961c099dbcb1bb))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.1.3-beta.0...@amplitude/analytics-client-common@2.1.3) (2024-04-09)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.3-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.1.2...@amplitude/analytics-client-common@2.1.3-beta.0) (2024-03-28)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.1.1...@amplitude/analytics-client-common@2.1.2) (2024-03-23)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.1.0...@amplitude/analytics-client-common@2.1.1) (2024-03-12)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.1.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.0.11...@amplitude/analytics-client-common@2.1.0) (2024-02-23)\n\n### Features\n\n- landing page improvement ([#667](https://github.com/amplitude/Amplitude-TypeScript/issues/667))\n  ([5f365f0](https://github.com/amplitude/Amplitude-TypeScript/commit/5f365f0b933ee890aee1d9ac083576f09b0defc3))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.0.10...@amplitude/analytics-client-common@2.0.11) (2024-01-24)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.0.9...@amplitude/analytics-client-common@2.0.10) (2023-12-20)\n\n### Reverts\n\n- update attribution plugin to apply utm params to the `session_start` event\n  ([#638](https://github.com/amplitude/Amplitude-TypeScript/issues/638))\n  ([c820279](https://github.com/amplitude/Amplitude-TypeScript/commit/c820279cbef2123d890beb7861d7edbbc3926f6e))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.0.9-beta.0...@amplitude/analytics-client-common@2.0.9) (2023-12-01)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.9-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.0.8...@amplitude/analytics-client-common@2.0.9-beta.0) (2023-11-22)\n\n### Bug Fixes\n\n- update attribution plugin to apply utm params to the `session_start` event\n  ([#619](https://github.com/amplitude/Amplitude-TypeScript/issues/619))\n  ([bf45ca6](https://github.com/amplitude/Amplitude-TypeScript/commit/bf45ca6c17ac8d656cb6c5bb4f4fa19ff344ac85))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.0.7...@amplitude/analytics-client-common@2.0.8) (2023-11-16)\n\n### Bug Fixes\n\n- npm latest tags ([#624](https://github.com/amplitude/Amplitude-TypeScript/issues/624))\n  ([76bf7a4](https://github.com/amplitude/Amplitude-TypeScript/commit/76bf7a4c871375649fac45d549b711ac52c16b0d))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.0.6...@amplitude/analytics-client-common@2.0.7) (2023-10-18)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.0.5...@amplitude/analytics-client-common@2.0.6) (2023-09-18)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.0.4...@amplitude/analytics-client-common@2.0.5) (2023-08-24)\n\n### Bug Fixes\n\n- fix web attribution behavior for no referrer in the same session\n  ([#554](https://github.com/amplitude/Amplitude-TypeScript/issues/554))\n  ([ed54eb2](https://github.com/amplitude/Amplitude-TypeScript/commit/ed54eb28810a3edb3326f82bdd7aed901ec9452f))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.0.3...@amplitude/analytics-client-common@2.0.4) (2023-07-03)\n\n### Bug Fixes\n\n- handle concurrent cookie testing ([#465](https://github.com/amplitude/Amplitude-TypeScript/issues/465))\n  ([92bb7de](https://github.com/amplitude/Amplitude-TypeScript/commit/92bb7de48861438e987778390a66831191b15907))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.0.2...@amplitude/analytics-client-common@2.0.3) (2023-06-30)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.0.1...@amplitude/analytics-client-common@2.0.2) (2023-06-22)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.0.0...@amplitude/analytics-client-common@2.0.1) (2023-06-21)\n\n### Bug Fixes\n\n- cookie-storage SSR incompatibility ([#445](https://github.com/amplitude/Amplitude-TypeScript/issues/445))\n  ([0086808](https://github.com/amplitude/Amplitude-TypeScript/commit/008680806d3cd34c3d6a1fd2b8cdb77806e37bff))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.0.0-beta.8...@amplitude/analytics-client-common@2.0.0) (2023-06-14)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.0.0-beta.7...@amplitude/analytics-client-common@2.0.0-beta.8) (2023-06-14)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.0.0-beta.6...@amplitude/analytics-client-common@2.0.0-beta.7) (2023-06-14)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.0.0-beta.5...@amplitude/analytics-client-common@2.0.0-beta.6) (2023-06-13)\n\n### Features\n\n- add option for instance name ([#428](https://github.com/amplitude/Amplitude-TypeScript/issues/428))\n  ([1a8ff7d](https://github.com/amplitude/Amplitude-TypeScript/commit/1a8ff7d665d2a936db7cb42f4cde5350379b7cae))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.0.0-beta.4...@amplitude/analytics-client-common@2.0.0-beta.5) (2023-06-13)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.0.0-beta.3...@amplitude/analytics-client-common@2.0.0-beta.4) (2023-06-08)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.0.0-beta.2...@amplitude/analytics-client-common@2.0.0-beta.3) (2023-06-07)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@2.0.0-beta.1...@amplitude/analytics-client-common@2.0.0-beta.2) (2023-06-06)\n\n### Bug Fixes\n\n- simplify plugins and eliminate enums ([#407](https://github.com/amplitude/Amplitude-TypeScript/issues/407))\n  ([890ec66](https://github.com/amplitude/Amplitude-TypeScript/commit/890ec6695a8b25cd6988e9f7ae584d4ba2835f67))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.7.0...@amplitude/analytics-client-common@2.0.0-beta.1) (2023-06-06)\n\n### Features\n\n- allow cross subdomain excluded referrer ([#391](https://github.com/amplitude/Amplitude-TypeScript/issues/391))\n  ([f34f64b](https://github.com/amplitude/Amplitude-TypeScript/commit/f34f64b68bbd328da354afae61ca416d7055a734))\n- make default event tracking enabled by default ([#386](https://github.com/amplitude/Amplitude-TypeScript/issues/386))\n  ([242f42d](https://github.com/amplitude/Amplitude-TypeScript/commit/242f42dd2e46eaec95c827795e04f74fba39c35f))\n- simplify browser SDK options and plugin options interface\n  ([#384](https://github.com/amplitude/Amplitude-TypeScript/issues/384))\n  ([b464cfb](https://github.com/amplitude/Amplitude-TypeScript/commit/b464cfb8e09d722bf06ed3c11955f77465a23daf))\n- use server side user agent parser ([#382](https://github.com/amplitude/Amplitude-TypeScript/issues/382))\n  ([69bd255](https://github.com/amplitude/Amplitude-TypeScript/commit/69bd2558cb37d027064b6459cc2887c219196973))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.7.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.6.5...@amplitude/analytics-client-common@0.7.0) (2023-05-04)\n\n### Features\n\n- add attribution tracking for linkedin click id li_fat_id\n  ([ca81f3d](https://github.com/amplitude/Amplitude-TypeScript/commit/ca81f3d75ece7e0e23a1bc1b6889107d53a60a86))\n- add rtd_cid for Reddit campaign tracking/attribution\n  ([784e080](https://github.com/amplitude/Amplitude-TypeScript/commit/784e080aa129c37e850d7f34115beb9770044e4e))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.6.4...@amplitude/analytics-client-common@0.6.5) (2023-04-27)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.6.3...@amplitude/analytics-client-common@0.6.4) (2023-04-25)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.6.2...@amplitude/analytics-client-common@0.6.3) (2023-04-06)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.6.1...@amplitude/analytics-client-common@0.6.2) (2023-03-31)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.6.1-beta.0...@amplitude/analytics-client-common@0.6.1) (2023-03-03)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.1-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.6.0...@amplitude/analytics-client-common@0.6.1-beta.0) (2023-03-03)\n\n### Bug Fixes\n\n- push user id and device id changes to analytics connector\n  ([#342](https://github.com/amplitude/Amplitude-TypeScript/issues/342))\n  ([3214b08](https://github.com/amplitude/Amplitude-TypeScript/commit/3214b0836eb03e39b5753b1e6be30e1c2f5770ca))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.6.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.6.0-beta.0...@amplitude/analytics-client-common@0.6.0) (2023-02-27)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.6.0-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.5.4...@amplitude/analytics-client-common@0.6.0-beta.0) (2023-02-24)\n\n### Bug Fixes\n\n- consolidate web attribution and page view tracking plugins for marketing analytics use case\n  ([c268997](https://github.com/amplitude/Amplitude-TypeScript/commit/c26899787611daeda7fca288e260bbc42a831130))\n\n### Features\n\n- allow custom page view event type ([#335](https://github.com/amplitude/Amplitude-TypeScript/issues/335))\n  ([0a4f8ed](https://github.com/amplitude/Amplitude-TypeScript/commit/0a4f8ede6e30ec3450ac0a468cf22b9266b0b23c))\n- pass amplitude instance to plugin.setup for enhanced plugin capabilities\n  ([#328](https://github.com/amplitude/Amplitude-TypeScript/issues/328))\n  ([91eeaa0](https://github.com/amplitude/Amplitude-TypeScript/commit/91eeaa0d6bff6bde39538bb54548a938df784462))\n- retrofit web attribution and page view plugins to browser SDK\n  ([#331](https://github.com/amplitude/Amplitude-TypeScript/issues/331))\n  ([ba845d3](https://github.com/amplitude/Amplitude-TypeScript/commit/ba845d3329bd6bebe3b89f24f4f316088c2d62b9))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.5.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.5.3...@amplitude/analytics-client-common@0.5.4) (2023-02-09)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.5.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.5.3-beta.0...@amplitude/analytics-client-common@0.5.3) (2023-01-31)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.5.3-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.5.2...@amplitude/analytics-client-common@0.5.3-beta.0) (2023-01-26)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.5.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.5.1...@amplitude/analytics-client-common@0.5.2) (2023-01-11)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.5.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.5.0...@amplitude/analytics-client-common@0.5.1) (2022-12-21)\n\n### Bug Fixes\n\n- upgrade dependencies to resolve dependabot vulnerability alerts\n  ([#299](https://github.com/amplitude/Amplitude-TypeScript/issues/299))\n  ([7dd1cd1](https://github.com/amplitude/Amplitude-TypeScript/commit/7dd1cd1b23a71981a4ad90b4b30cc9b7d28c4412))\n\n### Reverts\n\n- Revert \"Updated dependencies\"\n  ([7ca9964](https://github.com/amplitude/Amplitude-TypeScript/commit/7ca9964781e4b900c6c027bdddf2ae1e7428ba18))\n\n# [0.5.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.4.1...@amplitude/analytics-client-common@0.5.0) (2022-11-28)\n\n### Features\n\n- add utm_id tracking ([#284](https://github.com/amplitude/Amplitude-TypeScript/issues/284))\n  ([f72dcf1](https://github.com/amplitude/Amplitude-TypeScript/commit/f72dcf1788ebc84544aaee1dc41b1d1ba6e4c06e))\n- persisted event identifiers (React Native) ([#280](https://github.com/amplitude/Amplitude-TypeScript/issues/280))\n  ([bd35e73](https://github.com/amplitude/Amplitude-TypeScript/commit/bd35e73a0a08db6609938d27f00f54cbf77ff6c1))\n\n## [0.4.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.4.0...@amplitude/analytics-client-common@0.4.1) (2022-11-15)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n# [0.4.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.3.5...@amplitude/analytics-client-common@0.4.0) (2022-11-01)\n\n### Features\n\n- ignore subdomains when comparing newness of campaigns\n  ([#260](https://github.com/amplitude/Amplitude-TypeScript/issues/260))\n  ([8bb2b76](https://github.com/amplitude/Amplitude-TypeScript/commit/8bb2b76faf37783a58e953391468bd31c089e3a3))\n\n## [0.3.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.3.4...@amplitude/analytics-client-common@0.3.5) (2022-11-01)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n## [0.3.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.3.3...@amplitude/analytics-client-common@0.3.4) (2022-10-26)\n\n### Bug Fixes\n\n- adds optional chaining to window.location ([#258](https://github.com/amplitude/Amplitude-TypeScript/issues/258))\n  ([c30a1e0](https://github.com/amplitude/Amplitude-TypeScript/commit/c30a1e06feb632942a1697bda4948259ea0721a5))\n\n## [0.3.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.3.3-beta.1...@amplitude/analytics-client-common@0.3.3) (2022-10-25)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n## [0.3.3-beta.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.3.3-beta.0...@amplitude/analytics-client-common@0.3.3-beta.1) (2022-10-25)\n\n### Reverts\n\n- add logging around cookie storage ([#256](https://github.com/amplitude/Amplitude-TypeScript/issues/256))\n  ([12016e7](https://github.com/amplitude/Amplitude-TypeScript/commit/12016e7eddb7bec885883c0ebf1619fc447beb87))\n\n## [0.3.3-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.3.2...@amplitude/analytics-client-common@0.3.3-beta.0) (2022-10-25)\n\n### Bug Fixes\n\n- add logging around cookie storage ([#255](https://github.com/amplitude/Amplitude-TypeScript/issues/255))\n  ([dee9d32](https://github.com/amplitude/Amplitude-TypeScript/commit/dee9d3299b90b71576a8c435c26a03c1dcabdae4))\n\n## [0.3.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.3.1...@amplitude/analytics-client-common@0.3.2) (2022-10-25)\n\n### Bug Fixes\n\n- add safe check for global scope before loading SDK\n  ([#252](https://github.com/amplitude/Amplitude-TypeScript/issues/252))\n  ([a3f4f6f](https://github.com/amplitude/Amplitude-TypeScript/commit/a3f4f6f7b11abd9cdbdf064e31e32d5fc3e92031))\n- invoke pre-init track fns after attribution ([#253](https://github.com/amplitude/Amplitude-TypeScript/issues/253))\n  ([b8996d7](https://github.com/amplitude/Amplitude-TypeScript/commit/b8996d793f74d388c1a96e0cde5c0ac060c1e565))\n\n## [0.3.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.3.0...@amplitude/analytics-client-common@0.3.1) (2022-10-14)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n# [0.3.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.2.4...@amplitude/analytics-client-common@0.3.0) (2022-10-04)\n\n### Features\n\n- add gbraid and wbraid as campaign parameters ([#242](https://github.com/amplitude/Amplitude-TypeScript/issues/242))\n  ([514b7cd](https://github.com/amplitude/Amplitude-TypeScript/commit/514b7cdea9fee0c4e61479b087f7acdfea889350))\n\n## [0.2.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.2.3...@amplitude/analytics-client-common@0.2.4) (2022-09-30)\n\n### Bug Fixes\n\n- resolve web attribution is not tracking the first direct/organic traffic\n  ([#239](https://github.com/amplitude/Amplitude-TypeScript/issues/239))\n  ([98a3363](https://github.com/amplitude/Amplitude-TypeScript/commit/98a33633a7a6de7ee147c8cbf690e5546ce53163))\n\n## [0.2.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.2.2...@amplitude/analytics-client-common@0.2.3) (2022-09-30)\n\n### Bug Fixes\n\n- cover the case when apiKey is missing in the runtime\n  ([#240](https://github.com/amplitude/Amplitude-TypeScript/issues/240))\n  ([308bbe8](https://github.com/amplitude/Amplitude-TypeScript/commit/308bbe8337cbab366a0ca255f2d665101f4781a0))\n\n## [0.2.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.2.2-beta.1...@amplitude/analytics-client-common@0.2.2) (2022-09-28)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n## [0.2.2-beta.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.2.2-beta.0...@amplitude/analytics-client-common@0.2.2-beta.1) (2022-09-27)\n\n### Bug Fixes\n\n- define correct dependencies for @amplitude/analytics-connector\n  ([#234](https://github.com/amplitude/Amplitude-TypeScript/issues/234))\n  ([41c1351](https://github.com/amplitude/Amplitude-TypeScript/commit/41c1351e441b890b016ba123c4ed5747a4c33adb))\n\n## [0.2.2-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.2.1...@amplitude/analytics-client-common@0.2.2-beta.0) (2022-09-26)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n\n## [0.2.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.2.0...@amplitude/analytics-client-common@0.2.1) (2022-09-26)\n\n### Bug Fixes\n\n- update base config to include additional click ids\n  ([#229](https://github.com/amplitude/Amplitude-TypeScript/issues/229))\n  ([5596931](https://github.com/amplitude/Amplitude-TypeScript/commit/55969310714c43f138e1702ba285fd4dadcdcb44))\n\n# [0.2.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.1.0...@amplitude/analytics-client-common@0.2.0) (2022-09-22)\n\n### Features\n\n- add campaign params to page view events ([#216](https://github.com/amplitude/Amplitude-TypeScript/issues/216))\n  ([c0f99b9](https://github.com/amplitude/Amplitude-TypeScript/commit/c0f99b98d0d2c24f6f9486312b568194c690a202))\n\n# [0.1.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-client-common@0.0.1...@amplitude/analytics-client-common@0.1.0) (2022-09-16)\n\n### Features\n\n- attl click id campaign params ([#220](https://github.com/amplitude/Amplitude-TypeScript/issues/220))\n  ([7598895](https://github.com/amplitude/Amplitude-TypeScript/commit/75988950d7d3a97d00e038ae368b311f0b314604))\n\n## 0.0.1 (2022-09-08)\n\n**Note:** Version bump only for package @amplitude/analytics-client-common\n"
  },
  {
    "path": "packages/analytics-client-common/jest.config.js",
    "content": "const baseConfig = require('../../jest.config.js');\nconst package = require('./package');\n\nmodule.exports = {\n  ...baseConfig,\n  displayName: package.name,\n  rootDir: '.',\n  testEnvironment: 'jsdom',\n  coveragePathIgnorePatterns: ['index.ts', 'global-scope.ts'],\n};\n"
  },
  {
    "path": "packages/analytics-client-common/package.json",
    "content": "{\n  \"name\": \"@amplitude/analytics-client-common\",\n  \"version\": \"2.4.47\",\n  \"description\": \"\",\n  \"author\": \"Amplitude Inc\",\n  \"homepage\": \"https://github.com/amplitude/Amplitude-TypeScript\",\n  \"license\": \"MIT\",\n  \"main\": \"lib/cjs/index.js\",\n  \"module\": \"lib/esm/index.js\",\n  \"types\": \"lib/esm/index.d.ts\",\n  \"sideEffects\": false,\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"tag\": \"latest\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/amplitude/Amplitude-TypeScript.git\"\n  },\n  \"scripts\": {\n    \"build\": \"pnpm build:es5 && pnpm build:esm\",\n    \"build:es5\": \"tsc -p ./tsconfig.es5.json\",\n    \"build:esm\": \"tsc -p ./tsconfig.esm.json\",\n    \"watch\": \"tsc -p ./tsconfig.esm.json --watch\",\n    \"clean\": \"rimraf node_modules lib coverage\",\n    \"fix\": \"pnpm fix:eslint & pnpm fix:prettier\",\n    \"fix:eslint\": \"eslint '{src,test}/**/*.ts' --fix\",\n    \"fix:prettier\": \"prettier --write \\\"{src,test}/**/*.ts\\\"\",\n    \"lint\": \"pnpm lint:eslint & pnpm lint:prettier\",\n    \"lint:eslint\": \"eslint '{src,test}/**/*.ts'\",\n    \"lint:prettier\": \"prettier --check \\\"{src,test}/**/*.ts\\\"\",\n    \"test\": \"jest\",\n    \"typecheck\": \"tsc -p ./tsconfig.json\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/amplitude/Amplitude-TypeScript/issues\"\n  },\n  \"dependencies\": {\n    \"@amplitude/analytics-connector\": \"^1.4.8\",\n    \"@amplitude/analytics-core\": \"workspace:*\",\n    \"@amplitude/analytics-types\": \"workspace:*\",\n    \"tslib\": \"^2.4.1\"\n  },\n  \"files\": [\n    \"lib\"\n  ]\n}\n"
  },
  {
    "path": "packages/analytics-client-common/src/analytics-connector.ts",
    "content": "import { AnalyticsConnector } from '@amplitude/analytics-connector';\n\nexport const getAnalyticsConnector = (instanceName = '$default_instance'): AnalyticsConnector => {\n  return AnalyticsConnector.getInstance(instanceName);\n};\n\nexport const setConnectorUserId = (userId: string | undefined, instanceName?: string): void => {\n  // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n  // @ts-ignore\n  getAnalyticsConnector(instanceName).identityStore.editIdentity().setUserId(userId).commit();\n};\n\nexport const setConnectorDeviceId = (deviceId: string, instanceName?: string): void => {\n  getAnalyticsConnector(instanceName).identityStore.editIdentity().setDeviceId(deviceId).commit();\n};\n"
  },
  {
    "path": "packages/analytics-client-common/src/attribution/campaign-parser.ts",
    "content": "import { getQueryParams } from '../query-params';\nimport {\n  UTM_CAMPAIGN,\n  UTM_CONTENT,\n  UTM_MEDIUM,\n  UTM_SOURCE,\n  UTM_TERM,\n  GCLID,\n  FBCLID,\n  BASE_CAMPAIGN,\n  DCLID,\n  MSCLKID,\n  RDT_CID,\n  TWCLID,\n  TTCLID,\n  KO_CLICK_ID,\n  LI_FAT_ID,\n  GBRAID,\n  WBRAID,\n  UTM_ID,\n} from './constants';\nimport {\n  Campaign,\n  CampaignParser as ICampaignParser,\n  ClickIdParameters,\n  ReferrerParameters,\n  UTMParameters,\n} from '@amplitude/analytics-types';\n\nexport class CampaignParser implements ICampaignParser {\n  async parse(): Promise<Campaign> {\n    return {\n      ...BASE_CAMPAIGN,\n      ...this.getUtmParam(),\n      ...this.getReferrer(),\n      ...this.getClickIds(),\n    } as Campaign;\n  }\n\n  getUtmParam(): UTMParameters {\n    const params = getQueryParams();\n\n    const utmCampaign = params[UTM_CAMPAIGN];\n    const utmContent = params[UTM_CONTENT];\n    const utmId = params[UTM_ID];\n    const utmMedium = params[UTM_MEDIUM];\n    const utmSource = params[UTM_SOURCE];\n    const utmTerm = params[UTM_TERM];\n\n    return {\n      utm_campaign: utmCampaign,\n      utm_content: utmContent,\n      utm_id: utmId,\n      utm_medium: utmMedium,\n      utm_source: utmSource,\n      utm_term: utmTerm,\n    };\n  }\n\n  getReferrer(): ReferrerParameters {\n    const data: ReferrerParameters = {\n      referrer: undefined,\n      referring_domain: undefined,\n    };\n    try {\n      data.referrer = document.referrer || undefined;\n      data.referring_domain = data.referrer?.split('/')[2] ?? undefined;\n    } catch {\n      // nothing to track\n    }\n    return data;\n  }\n\n  getClickIds(): ClickIdParameters {\n    const params = getQueryParams();\n    return {\n      [DCLID]: params[DCLID],\n      [FBCLID]: params[FBCLID],\n      [GBRAID]: params[GBRAID],\n      [GCLID]: params[GCLID],\n      [KO_CLICK_ID]: params[KO_CLICK_ID],\n      [LI_FAT_ID]: params[LI_FAT_ID],\n      [MSCLKID]: params[MSCLKID],\n      [RDT_CID]: params[RDT_CID],\n      [TTCLID]: params[TTCLID],\n      [TWCLID]: params[TWCLID],\n      [WBRAID]: params[WBRAID],\n    };\n  }\n}\n"
  },
  {
    "path": "packages/analytics-client-common/src/attribution/campaign-tracker.ts",
    "content": "import { createIdentifyEvent, Identify } from '@amplitude/analytics-core';\nimport {\n  Storage,\n  Campaign,\n  CampaignParser as ICampaignParser,\n  CampaignTracker as ICampaignTracker,\n  CampaignTrackFunction,\n  CampaignTrackerOptions,\n  BaseEvent,\n} from '@amplitude/analytics-types';\nimport { getCookieName as getStorageKey } from '../cookie-name';\nimport { CampaignParser } from './campaign-parser';\nimport { BASE_CAMPAIGN, EMPTY_VALUE, MKTG } from './constants';\n\n/**\n * @deprecated\n * Campaign tracker has mixed logic from built-in and plugin web attribution\n * features. Do not add more features here. The plan moving foward is to consolidate\n * logic in @amplitude/plugin-web-attribution-browser with backward compatibility.\n */\nexport class CampaignTracker implements ICampaignTracker {\n  storage: Storage<Campaign>;\n  storageKey: string;\n  parser: ICampaignParser;\n  track: CampaignTrackFunction;\n  onNewCampaign: (campaign: Campaign) => unknown;\n\n  disabled: boolean;\n  trackNewCampaigns: boolean;\n  trackPageViews: boolean;\n  excludeReferrers: string[];\n  initialEmptyValue: string;\n\n  constructor(apiKey: string, options: CampaignTrackerOptions) {\n    this.storage = options.storage;\n    this.storageKey = getStorageKey(apiKey, MKTG);\n    this.parser = new CampaignParser();\n    this.track = options.track;\n    this.onNewCampaign = options.onNewCampaign;\n\n    this.disabled = Boolean(options.disabled);\n    this.trackNewCampaigns = Boolean(options.trackNewCampaigns);\n    this.trackPageViews = Boolean(options.trackPageViews);\n    this.excludeReferrers = options.excludeReferrers ?? [];\n    if (typeof location !== 'undefined') {\n      this.excludeReferrers.unshift(location.hostname);\n    }\n    this.initialEmptyValue = options.initialEmptyValue ?? EMPTY_VALUE;\n  }\n\n  isNewCampaign(current: Campaign, previous: Campaign | undefined, ignoreSubdomainInReferrer = false) {\n    const { referrer, referring_domain, ...currentCampaign } = current;\n    const { referrer: _previous_referrer, referring_domain: prevReferringDomain, ...previousCampaign } = previous || {};\n\n    if (current.referring_domain && this.excludeReferrers.includes(current.referring_domain)) {\n      return false;\n    }\n\n    const hasNewCampaign = JSON.stringify(currentCampaign) !== JSON.stringify(previousCampaign);\n    const hasNewDomain = ignoreSubdomainInReferrer\n      ? domainWithoutSubdomain(referring_domain || '') !== domainWithoutSubdomain(prevReferringDomain || '')\n      : referring_domain !== prevReferringDomain;\n\n    return !previous || hasNewCampaign || hasNewDomain;\n  }\n\n  async saveCampaignToStorage(campaign: Campaign): Promise<void> {\n    await this.storage.set(this.storageKey, campaign);\n  }\n\n  async getCampaignFromStorage(): Promise<Campaign | undefined> {\n    return await this.storage.get(this.storageKey);\n  }\n\n  createCampaignEvent(campaign: Campaign) {\n    const campaignParameters: Campaign = {\n      // This object definition allows undefined keys to be iterated on\n      // in .reduce() to build indentify object\n      ...BASE_CAMPAIGN,\n      ...campaign,\n    };\n    const identifyEvent = Object.entries(campaignParameters).reduce((identify, [key, value]) => {\n      identify.setOnce(`initial_${key}`, value || this.initialEmptyValue);\n      if (value) {\n        return identify.set(key, value);\n      }\n      return identify.unset(key);\n    }, new Identify());\n\n    const pageViewEvent: BaseEvent = {\n      event_type: 'Page View',\n      event_properties: {\n        page_title: /* istanbul ignore next */ (typeof document !== 'undefined' && document.title) || '',\n        page_location: /* istanbul ignore next */ (typeof location !== 'undefined' && location.href) || '',\n        page_path: /* istanbul ignore next */ (typeof location !== 'undefined' && location.pathname) || '',\n      },\n    };\n    return {\n      ...createIdentifyEvent(identifyEvent),\n      ...(this.trackPageViews && pageViewEvent),\n    };\n  }\n\n  async send(isNewSession: boolean) {\n    if (this.disabled) {\n      return;\n    }\n    const currentCampaign = await this.parser.parse();\n    const previousCampaign = await this.getCampaignFromStorage();\n    if (!isNewSession) {\n      if (!this.trackNewCampaigns || !this.isNewCampaign(currentCampaign, previousCampaign)) {\n        return;\n      }\n      this.onNewCampaign(currentCampaign);\n    }\n    await this.track(this.createCampaignEvent(currentCampaign));\n    await this.saveCampaignToStorage(currentCampaign);\n  }\n}\n\nconst domainWithoutSubdomain = (domain: string) => {\n  const parts = domain.split('.');\n\n  if (parts.length <= 2) {\n    return domain;\n  }\n\n  return parts.slice(parts.length - 2, parts.length).join('.');\n};\n"
  },
  {
    "path": "packages/analytics-client-common/src/attribution/constants.ts",
    "content": "import { Campaign } from '@amplitude/analytics-types';\n\nexport const UTM_CAMPAIGN = 'utm_campaign';\nexport const UTM_CONTENT = 'utm_content';\nexport const UTM_ID = 'utm_id';\nexport const UTM_MEDIUM = 'utm_medium';\nexport const UTM_SOURCE = 'utm_source';\nexport const UTM_TERM = 'utm_term';\n\nexport const DCLID = 'dclid';\nexport const FBCLID = 'fbclid';\nexport const GBRAID = 'gbraid';\nexport const GCLID = 'gclid';\nexport const KO_CLICK_ID = 'ko_click_id';\nexport const LI_FAT_ID = 'li_fat_id';\nexport const MSCLKID = 'msclkid';\nexport const RDT_CID = 'rdt_cid';\nexport const TTCLID = 'ttclid';\nexport const TWCLID = 'twclid';\nexport const WBRAID = 'wbraid';\n\nexport const EMPTY_VALUE = 'EMPTY';\n\nexport const BASE_CAMPAIGN: Campaign = {\n  utm_campaign: undefined,\n  utm_content: undefined,\n  utm_id: undefined,\n  utm_medium: undefined,\n  utm_source: undefined,\n  utm_term: undefined,\n  referrer: undefined,\n  referring_domain: undefined,\n  dclid: undefined,\n  gbraid: undefined,\n  gclid: undefined,\n  fbclid: undefined,\n  ko_click_id: undefined,\n  li_fat_id: undefined,\n  msclkid: undefined,\n  rdt_cid: undefined,\n  ttclid: undefined,\n  twclid: undefined,\n  wbraid: undefined,\n};\n\nexport const MKTG = 'MKTG';\n"
  },
  {
    "path": "packages/analytics-client-common/src/attribution/helpers.ts",
    "content": "import { createIdentifyEvent, Identify } from '@amplitude/analytics-core';\nimport { Campaign, Logger } from '@amplitude/analytics-types';\nimport { BASE_CAMPAIGN } from './constants';\n\nexport interface Options {\n  excludeReferrers?: (string | RegExp)[];\n  initialEmptyValue?: string;\n  resetSessionOnNewCampaign?: boolean;\n}\n\nconst domainWithoutSubdomain = (domain: string) => {\n  const parts = domain.split('.');\n\n  if (parts.length <= 2) {\n    return domain;\n  }\n\n  return parts.slice(parts.length - 2, parts.length).join('.');\n};\n\n//Direct traffic mean no external referral, no UTMs, no click-ids, and no other customer identified marketing campaign url params.\nconst isDirectTraffic = (current: Campaign) => {\n  return Object.values(current).every((value) => !value);\n};\n\nexport const isNewCampaign = (\n  current: Campaign,\n  previous: Campaign | undefined,\n  options: Options,\n  logger: Logger,\n  isNewSession = true,\n) => {\n  const { referrer, referring_domain, ...currentCampaign } = current;\n  const { referrer: _previous_referrer, referring_domain: prevReferringDomain, ...previousCampaign } = previous || {};\n\n  if (isExcludedReferrer(options.excludeReferrers, current.referring_domain)) {\n    // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n    logger.debug(`This is not a new campaign because ${current.referring_domain} is in the exclude referrer list.`);\n    return false;\n  }\n\n  //In the same session, direct traffic should not override or unset any persisting query params\n  if (!isNewSession && isDirectTraffic(current) && previous) {\n    logger.debug('This is not a new campaign because this is a direct traffic in the same session.');\n    return false;\n  }\n\n  const hasNewCampaign = JSON.stringify(currentCampaign) !== JSON.stringify(previousCampaign);\n  const hasNewDomain =\n    domainWithoutSubdomain(referring_domain || '') !== domainWithoutSubdomain(prevReferringDomain || '');\n\n  const result = !previous || hasNewCampaign || hasNewDomain;\n\n  if (!result) {\n    logger.debug(\"This is not a new campaign because it's the same as the previous one.\");\n  } else {\n    logger.debug(`This is a new campaign. An $identify event will be sent.`);\n  }\n\n  return result;\n};\n\nexport const isExcludedReferrer = (excludeReferrers: (string | RegExp)[] = [], referringDomain = '') => {\n  return excludeReferrers.some((value) =>\n    value instanceof RegExp ? value.test(referringDomain) : value === referringDomain,\n  );\n};\n\nexport const createCampaignEvent = (campaign: Campaign, options: Options) => {\n  const campaignParameters: Campaign = {\n    // This object definition allows undefined keys to be iterated on\n    // in .reduce() to build indentify object\n    ...BASE_CAMPAIGN,\n    ...campaign,\n  };\n  const identifyEvent = Object.entries(campaignParameters).reduce((identify, [key, value]) => {\n    identify.setOnce(`initial_${key}`, value ?? options.initialEmptyValue ?? 'EMPTY');\n    if (value) {\n      return identify.set(key, value);\n    }\n    return identify.unset(key);\n  }, new Identify());\n\n  return createIdentifyEvent(identifyEvent);\n};\n\nexport const getDefaultExcludedReferrers = (cookieDomain: string | undefined) => {\n  let domain = cookieDomain;\n  if (domain) {\n    if (domain.startsWith('.')) {\n      domain = domain.substring(1);\n    }\n    return [new RegExp(`${domain.replace('.', '\\\\.')}$`)];\n  }\n  return [];\n};\n"
  },
  {
    "path": "packages/analytics-client-common/src/attribution/web-attribution.ts",
    "content": "import { BrowserConfig, Logger } from '@amplitude/analytics-types';\nimport { Campaign, Storage } from '@amplitude/analytics-types';\nimport { Options, getDefaultExcludedReferrers, createCampaignEvent, isNewCampaign } from './helpers';\nimport { getStorageKey } from '../storage/helpers';\nimport { CampaignParser } from './campaign-parser';\nimport { BASE_CAMPAIGN } from './constants';\nimport { isNewSession } from '../session';\n\nexport class WebAttribution {\n  options: Options;\n  storage: Storage<Campaign>;\n  storageKey: string;\n  previousCampaign?: Campaign;\n  currentCampaign: Campaign;\n  shouldTrackNewCampaign = false;\n  sessionTimeout: number;\n  lastEventTime?: number;\n  logger: Logger;\n\n  constructor(options: Options, config: BrowserConfig) {\n    this.options = {\n      initialEmptyValue: 'EMPTY',\n      resetSessionOnNewCampaign: false,\n      excludeReferrers: getDefaultExcludedReferrers(config.cookieOptions?.domain),\n      ...options,\n    };\n    this.storage = config.cookieStorage as unknown as Storage<Campaign>;\n    this.storageKey = getStorageKey(config.apiKey, 'MKTG');\n    this.currentCampaign = BASE_CAMPAIGN;\n    this.sessionTimeout = config.sessionTimeout;\n    this.lastEventTime = config.lastEventTime;\n    this.logger = config.loggerProvider;\n    config.loggerProvider.log('Installing web attribution tracking.');\n  }\n\n  async init() {\n    [this.currentCampaign, this.previousCampaign] = await this.fetchCampaign();\n    const isEventInNewSession = !this.lastEventTime ? true : isNewSession(this.sessionTimeout, this.lastEventTime);\n\n    if (isNewCampaign(this.currentCampaign, this.previousCampaign, this.options, this.logger, isEventInNewSession)) {\n      this.shouldTrackNewCampaign = true;\n      await this.storage.set(this.storageKey, this.currentCampaign);\n    }\n  }\n\n  async fetchCampaign() {\n    return await Promise.all([new CampaignParser().parse(), this.storage.get(this.storageKey)]);\n  }\n\n  /**\n   * This can be called when enable web attribution and either\n   * 1. set a new session\n   * 2. has new campaign and enable resetSessionOnNewCampaign\n   */\n  generateCampaignEvent(event_id?: number) {\n    // Mark this campaign has been tracked\n    this.shouldTrackNewCampaign = false;\n    const campaignEvent = createCampaignEvent(this.currentCampaign, this.options);\n    if (event_id) {\n      campaignEvent.event_id = event_id;\n    }\n    return campaignEvent;\n  }\n\n  shouldSetSessionIdOnNewCampaign() {\n    return this.shouldTrackNewCampaign && !!this.options.resetSessionOnNewCampaign;\n  }\n}\n"
  },
  {
    "path": "packages/analytics-client-common/src/cookie-name.ts",
    "content": "import { AMPLITUDE_PREFIX } from '@amplitude/analytics-core';\n\nexport const getCookieName = (apiKey: string, postKey = '', limit = 10) => {\n  return [AMPLITUDE_PREFIX, postKey, apiKey.substring(0, limit)].filter(Boolean).join('_');\n};\n\nexport const getOldCookieName = (apiKey: string) => {\n  return `${AMPLITUDE_PREFIX.toLowerCase()}_${apiKey.substring(0, 6)}`;\n};\n"
  },
  {
    "path": "packages/analytics-client-common/src/default-tracking.ts",
    "content": "import {\n  AttributionOptions,\n  AutocaptureOptions,\n  BrowserOptions,\n  PageTrackingHistoryChanges,\n  PageTrackingOptions,\n  PageTrackingTrackOn,\n  ElementInteractionsOptions,\n} from '@amplitude/analytics-types';\n\n/**\n * Returns false if autocapture === false or if autocapture[event],\n * otherwise returns true\n */\nconst isTrackingEnabled = (autocapture: AutocaptureOptions | boolean | undefined, event: keyof AutocaptureOptions) => {\n  if (typeof autocapture === 'boolean') {\n    return autocapture;\n  }\n\n  if (autocapture?.[event] === false) {\n    return false;\n  }\n\n  return true;\n};\n\nexport const isAttributionTrackingEnabled = (autocapture: AutocaptureOptions | boolean | undefined) =>\n  isTrackingEnabled(autocapture, 'attribution');\n\nexport const isFileDownloadTrackingEnabled = (autocapture: AutocaptureOptions | boolean | undefined) =>\n  isTrackingEnabled(autocapture, 'fileDownloads');\n\nexport const isFormInteractionTrackingEnabled = (autocapture: AutocaptureOptions | boolean | undefined) =>\n  isTrackingEnabled(autocapture, 'formInteractions');\n\nexport const isPageViewTrackingEnabled = (autocapture: AutocaptureOptions | boolean | undefined) =>\n  isTrackingEnabled(autocapture, 'pageViews');\n\nexport const isSessionTrackingEnabled = (autocapture: AutocaptureOptions | boolean | undefined) =>\n  isTrackingEnabled(autocapture, 'sessions');\n\n/**\n * Returns true if\n * 1. autocapture === true\n * 2. if autocapture.elementInteractions === true\n * 3. if autocapture.elementInteractions === object\n * otherwise returns false\n */\nexport const isElementInteractionsEnabled = (autocapture: AutocaptureOptions | boolean | undefined): boolean => {\n  if (typeof autocapture === 'boolean') {\n    return autocapture;\n  }\n\n  if (\n    typeof autocapture === 'object' &&\n    (autocapture.elementInteractions === true || typeof autocapture.elementInteractions === 'object')\n  ) {\n    return true;\n  }\n\n  return false;\n};\n\nexport const getElementInteractionsConfig = (config: BrowserOptions): ElementInteractionsOptions | undefined => {\n  if (\n    isElementInteractionsEnabled(config.autocapture) &&\n    typeof config.autocapture === 'object' &&\n    typeof config.autocapture.elementInteractions === 'object'\n  ) {\n    return config.autocapture.elementInteractions;\n  }\n  return undefined;\n};\n\nexport const getPageViewTrackingConfig = (config: BrowserOptions): PageTrackingOptions => {\n  let trackOn: PageTrackingTrackOn | undefined = () => false;\n  let trackHistoryChanges: PageTrackingHistoryChanges | undefined = undefined;\n  let eventType: string | undefined;\n  const pageCounter = config.pageCounter;\n\n  const isDefaultPageViewTrackingEnabled = isPageViewTrackingEnabled(config.defaultTracking);\n  if (isDefaultPageViewTrackingEnabled) {\n    trackOn = undefined;\n    eventType = undefined;\n\n    if (\n      config.defaultTracking &&\n      typeof config.defaultTracking === 'object' &&\n      config.defaultTracking.pageViews &&\n      typeof config.defaultTracking.pageViews === 'object'\n    ) {\n      if ('trackOn' in config.defaultTracking.pageViews) {\n        trackOn = config.defaultTracking.pageViews.trackOn;\n      }\n\n      if ('trackHistoryChanges' in config.defaultTracking.pageViews) {\n        trackHistoryChanges = config.defaultTracking.pageViews.trackHistoryChanges;\n      }\n\n      if ('eventType' in config.defaultTracking.pageViews && config.defaultTracking.pageViews.eventType) {\n        eventType = config.defaultTracking.pageViews.eventType;\n      }\n    }\n  }\n\n  return {\n    trackOn,\n    trackHistoryChanges,\n    eventType,\n    pageCounter,\n  };\n};\n\nexport const getAttributionTrackingConfig = (config: BrowserOptions): AttributionOptions => {\n  if (\n    isAttributionTrackingEnabled(config.defaultTracking) &&\n    config.defaultTracking &&\n    typeof config.defaultTracking === 'object' &&\n    config.defaultTracking.attribution &&\n    typeof config.defaultTracking.attribution === 'object'\n  ) {\n    return {\n      ...config.defaultTracking.attribution,\n    };\n  }\n\n  return {};\n};\n"
  },
  {
    "path": "packages/analytics-client-common/src/global-scope.ts",
    "content": "/* eslint-disable no-restricted-globals */\n/* Only file allowed to access to globalThis, window, self */\n\nexport const getGlobalScope = (): typeof globalThis | undefined => {\n  // This should only be used for integrations with Amplitude that are not running in a browser environment\n  //   We need to specify the name of the global variable as a string to prevent it from being minified\n  const ampIntegrationContextName = 'ampIntegrationContext' as keyof typeof globalThis;\n  if (typeof globalThis !== 'undefined' && typeof globalThis[ampIntegrationContextName] !== 'undefined') {\n    return globalThis[ampIntegrationContextName] as typeof globalThis;\n  }\n  if (typeof globalThis !== 'undefined') {\n    return globalThis;\n  }\n  if (typeof window !== 'undefined') {\n    return window;\n  }\n  if (typeof self !== 'undefined') {\n    return self;\n  }\n  if (typeof global !== 'undefined') {\n    return global;\n  }\n  return undefined;\n};\n"
  },
  {
    "path": "packages/analytics-client-common/src/index.ts",
    "content": "export { CampaignParser } from './attribution/campaign-parser';\nexport { CampaignTracker } from './attribution/campaign-tracker';\nexport {\n  Options,\n  isNewCampaign,\n  isExcludedReferrer,\n  createCampaignEvent,\n  getDefaultExcludedReferrers,\n} from './attribution/helpers';\nexport { WebAttribution } from './attribution/web-attribution';\nexport { BASE_CAMPAIGN } from './attribution/constants';\nexport { getQueryParams } from './query-params';\nexport { isNewSession } from './session';\nexport { getCookieName, getOldCookieName } from './cookie-name';\nexport { getStorageKey } from './storage/helpers';\nexport { CookieStorage } from './storage/cookie';\nexport { FetchTransport } from './transports/fetch';\nexport { getAnalyticsConnector, setConnectorDeviceId, setConnectorUserId } from './analytics-connector';\nexport { IdentityEventSender } from './plugins/identity';\nexport { getLanguage } from './language';\nexport { getGlobalScope } from './global-scope';\nexport {\n  getPageViewTrackingConfig,\n  getAttributionTrackingConfig,\n  getElementInteractionsConfig,\n  isAttributionTrackingEnabled,\n  isFileDownloadTrackingEnabled,\n  isFormInteractionTrackingEnabled,\n  isPageViewTrackingEnabled,\n  isSessionTrackingEnabled,\n  isElementInteractionsEnabled,\n} from './default-tracking';\n"
  },
  {
    "path": "packages/analytics-client-common/src/language.ts",
    "content": "export const getLanguage = (): string => {\n  if (typeof navigator === 'undefined') return '';\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n  const userLanguage = (navigator as any).userLanguage as string | undefined;\n\n  return navigator.languages?.[0] ?? navigator.language ?? userLanguage ?? '';\n};\n"
  },
  {
    "path": "packages/analytics-client-common/src/plugins/identity.ts",
    "content": "import { BeforePlugin, Config, Event } from '@amplitude/analytics-types';\nimport { getAnalyticsConnector } from '../analytics-connector';\n\nexport class IdentityEventSender implements BeforePlugin {\n  name = 'identity';\n  type = 'before' as const;\n\n  identityStore = getAnalyticsConnector().identityStore;\n\n  async execute(context: Event): Promise<Event> {\n    const userProperties = context.user_properties as Record<string, any>;\n    if (userProperties) {\n      this.identityStore.editIdentity().updateUserProperties(userProperties).commit();\n    }\n    return context;\n  }\n\n  async setup(config: Config) {\n    if (config.instanceName) {\n      this.identityStore = getAnalyticsConnector(config.instanceName).identityStore;\n    }\n  }\n}\n"
  },
  {
    "path": "packages/analytics-client-common/src/query-params.ts",
    "content": "import { getGlobalScope } from './global-scope';\n\nexport const getQueryParams = (): Record<string, string | undefined> => {\n  const globalScope = getGlobalScope();\n  /* istanbul ignore if */\n  if (!globalScope?.location?.search) {\n    return {};\n  }\n  const pairs = globalScope.location.search.substring(1).split('&').filter(Boolean);\n  const params = pairs.reduce<Record<string, string | undefined>>((acc, curr) => {\n    const query = curr.split('=', 2);\n    const key = tryDecodeURIComponent(query[0]);\n    const value = tryDecodeURIComponent(query[1]);\n    if (!value) {\n      return acc;\n    }\n    acc[key] = value;\n    return acc;\n  }, {});\n  return params;\n};\n\nexport const tryDecodeURIComponent = (value = '') => {\n  try {\n    return decodeURIComponent(value);\n  } catch {\n    return '';\n  }\n};\n"
  },
  {
    "path": "packages/analytics-client-common/src/session.ts",
    "content": "export const isNewSession = (sessionTimeout: number, lastEventTime: number = Date.now()): boolean => {\n  const currentTime = Date.now();\n  const timeSinceLastEvent = currentTime - lastEventTime;\n\n  return timeSinceLastEvent > sessionTimeout;\n};\n"
  },
  {
    "path": "packages/analytics-client-common/src/storage/cookie.ts",
    "content": "import { Storage, CookieStorageOptions } from '@amplitude/analytics-types';\nimport { getGlobalScope } from '../global-scope';\n\nexport class CookieStorage<T> implements Storage<T> {\n  options: CookieStorageOptions;\n  private static testValue: undefined | string;\n\n  constructor(options?: CookieStorageOptions) {\n    this.options = { ...options };\n  }\n\n  async isEnabled(): Promise<boolean> {\n    /* istanbul ignore if */\n    if (!getGlobalScope()) {\n      return false;\n    }\n\n    CookieStorage.testValue = String(Date.now());\n    const testStrorage = new CookieStorage<string>(this.options);\n    const testKey = 'AMP_TEST';\n    try {\n      await testStrorage.set(testKey, CookieStorage.testValue);\n      const value = await testStrorage.get(testKey);\n      return value === CookieStorage.testValue;\n    } catch {\n      /* istanbul ignore next */\n      return false;\n    } finally {\n      await testStrorage.remove(testKey);\n    }\n  }\n\n  async get(key: string): Promise<T | undefined> {\n    const value = await this.getRaw(key);\n    if (!value) {\n      return undefined;\n    }\n    try {\n      const decodedValue = decodeCookiesAsDefault(value) ?? decodeCookiesWithDoubleUrlEncoding(value);\n      if (decodedValue === undefined) {\n        console.error(`Amplitude Logger [Error]: Failed to decode cookie value for key: ${key}, value: ${value}`);\n        return undefined;\n      }\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n      return JSON.parse(decodedValue);\n    } catch {\n      console.error(`Amplitude Logger [Error]: Failed to parse cookie value for key: ${key}, value: ${value}`);\n      return undefined;\n    }\n  }\n\n  async getRaw(key: string): Promise<string | undefined> {\n    const globalScope = getGlobalScope();\n    const cookie = globalScope?.document?.cookie.split('; ') ?? [];\n    const match = cookie.find((c) => c.indexOf(key + '=') === 0);\n    if (!match) {\n      return undefined;\n    }\n    return match.substring(key.length + 1);\n  }\n\n  async set(key: string, value: T | null): Promise<void> {\n    try {\n      const expirationDays = this.options.expirationDays ?? 0;\n      const expires = value !== null ? expirationDays : -1;\n      let expireDate: Date | undefined = undefined;\n      if (expires) {\n        const date = new Date();\n        date.setTime(date.getTime() + expires * 24 * 60 * 60 * 1000);\n        expireDate = date;\n      }\n      let str = `${key}=${btoa(encodeURIComponent(JSON.stringify(value)))}`;\n      if (expireDate) {\n        str += `; expires=${expireDate.toUTCString()}`;\n      }\n      str += '; path=/';\n      if (this.options.domain) {\n        str += `; domain=${this.options.domain}`;\n      }\n      if (this.options.secure) {\n        str += '; Secure';\n      }\n      if (this.options.sameSite) {\n        str += `; SameSite=${this.options.sameSite}`;\n      }\n      const globalScope = getGlobalScope();\n      if (globalScope) {\n        globalScope.document.cookie = str;\n      }\n    } catch (error) {\n      const errorMessage = error instanceof Error ? error.message : String(error);\n      console.error(`Amplitude Logger [Error]: Failed to set cookie for key: ${key}. Error: ${errorMessage}`);\n    }\n  }\n\n  async remove(key: string): Promise<void> {\n    await this.set(key, null);\n  }\n\n  async reset(): Promise<void> {\n    return;\n  }\n}\n\nconst decodeCookiesAsDefault = (value: string): string | undefined => {\n  try {\n    return decodeURIComponent(atob(value));\n  } catch {\n    return undefined;\n  }\n};\n\nconst decodeCookiesWithDoubleUrlEncoding = (value: string): string | undefined => {\n  // Modern Ruby (v7+) automatically encodes cookies with URL encoding by\n  // https://api.rubyonrails.org/classes/ActionDispatch/Cookies.html\n  try {\n    return decodeURIComponent(atob(decodeURIComponent(value)));\n  } catch {\n    return undefined;\n  }\n};\n"
  },
  {
    "path": "packages/analytics-client-common/src/storage/helpers.ts",
    "content": "import { AMPLITUDE_PREFIX } from '@amplitude/analytics-core';\n\nexport const getStorageKey = (apiKey: string, postKey = '', limit = 10) => {\n  return [AMPLITUDE_PREFIX, postKey, apiKey.substring(0, limit)].filter(Boolean).join('_');\n};\n"
  },
  {
    "path": "packages/analytics-client-common/src/transports/fetch.ts",
    "content": "import { BaseTransport } from '@amplitude/analytics-core';\nimport { Payload, Response, Transport } from '@amplitude/analytics-types';\n\nexport class FetchTransport extends BaseTransport implements Transport {\n  async send(serverUrl: string, payload: Payload): Promise<Response | null> {\n    /* istanbul ignore if */\n    if (typeof fetch === 'undefined') {\n      throw new Error('FetchTransport is not supported');\n    }\n    const options: RequestInit = {\n      headers: {\n        'Content-Type': 'application/json',\n        Accept: '*/*',\n      },\n      body: JSON.stringify(payload),\n      method: 'POST',\n    };\n    const response = await fetch(serverUrl, options);\n    const responseText = await response.text();\n    try {\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n      return this.buildResponse(JSON.parse(responseText));\n    } catch {\n      return this.buildResponse({ code: response.status });\n    }\n  }\n}\n"
  },
  {
    "path": "packages/analytics-client-common/src/types/global.ts",
    "content": "/* eslint-disable no-restricted-globals */\n// eslint-disable-next-line no-var\nexport var ampIntegrationContext: typeof globalThis;\n"
  },
  {
    "path": "packages/analytics-client-common/test/analytics-connector.test.ts",
    "content": "import { AnalyticsConnector } from '@amplitude/analytics-connector';\nimport { getAnalyticsConnector, setConnectorDeviceId, setConnectorUserId } from '../src/analytics-connector';\n\ndescribe('analytics-connector', () => {\n  describe('getAnalyticsConnector', () => {\n    test('should return connector instance', () => {\n      const instance = new AnalyticsConnector();\n      const getInstance = jest.spyOn(AnalyticsConnector, 'getInstance').mockReturnValueOnce(instance);\n      expect(getAnalyticsConnector()).toBe(instance);\n      expect(getInstance).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('setConnectorUserId', () => {\n    test('should return connector instance', () => {\n      const commit = jest.fn();\n      const identityEditor = {\n        setUserId: function () {\n          return this;\n        },\n        setDeviceId: function () {\n          return this;\n        },\n        setUserProperties: function () {\n          return this;\n        },\n        updateUserProperties: function () {\n          return this;\n        },\n        setOptOut: function () {\n          return this;\n        },\n        commit,\n      };\n      const instance = new AnalyticsConnector();\n      jest.spyOn(instance.identityStore, 'editIdentity').mockReturnValueOnce(identityEditor);\n      const getInstance = jest.spyOn(AnalyticsConnector, 'getInstance').mockReturnValueOnce(instance);\n      expect(setConnectorUserId('123')).toBe(undefined);\n      expect(getInstance).toHaveBeenCalledTimes(1);\n      expect(commit).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('setConnectorDeviceId', () => {\n    test('should return connector instance', () => {\n      const commit = jest.fn();\n      const identityEditor = {\n        setUserId: function () {\n          return this;\n        },\n        setDeviceId: function () {\n          return this;\n        },\n        setUserProperties: function () {\n          return this;\n        },\n        updateUserProperties: function () {\n          return this;\n        },\n        setOptOut: function () {\n          return this;\n        },\n        commit,\n      };\n      const instance = new AnalyticsConnector();\n      jest.spyOn(instance.identityStore, 'editIdentity').mockReturnValueOnce(identityEditor);\n      const getInstance = jest.spyOn(AnalyticsConnector, 'getInstance').mockReturnValueOnce(instance);\n      expect(setConnectorDeviceId('123')).toBe(undefined);\n      expect(getInstance).toHaveBeenCalledTimes(1);\n      expect(commit).toHaveBeenCalledTimes(1);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-client-common/test/attribution/campaign-parser.test.ts",
    "content": "import { BASE_CAMPAIGN } from '../../src/attribution/constants';\nimport { CampaignParser } from '../../src/attribution/campaign-parser';\nimport * as queryParams from '../../src/query-params';\n\nbeforeAll(() => {\n  Object.defineProperty(window, 'location', {\n    value: {\n      hostname: '',\n      href: '',\n      pathname: '',\n      search: '',\n    },\n    writable: true,\n  });\n  Object.defineProperty(document, 'referrer', {\n    value: '',\n    writable: true,\n  });\n});\n\ndescribe('campaign-parser', () => {\n  describe('parse', () => {\n    test('should return parameters', async () => {\n      const parser = new CampaignParser();\n      const referringDomain = 'https://google.com';\n      const search = '?utm_campaign=utm_campaign&gclid=123';\n      (document.referrer as any) = referringDomain;\n      window.location.search = search;\n\n      const campaign = await parser.parse();\n      expect(campaign).toEqual({\n        ...BASE_CAMPAIGN,\n        utm_campaign: 'utm_campaign',\n        referrer: 'https://google.com',\n        referring_domain: 'google.com',\n        gclid: '123',\n      });\n    });\n  });\n\n  describe('getUtmParam', () => {\n    test('should return utm param from query params', async () => {\n      const parser = new CampaignParser();\n      const getQueryParams = jest.spyOn(queryParams, 'getQueryParams');\n      window.location.search =\n        '?utm_source=utm_source&utm_medium=utm_medium&utm_campaign=utm_campaign&utm_term=utm_term&utm_content=utm_content';\n      const utmParam = parser.getUtmParam();\n      expect(utmParam).toEqual({\n        utm_source: 'utm_source',\n        utm_medium: 'utm_medium',\n        utm_campaign: 'utm_campaign',\n        utm_term: 'utm_term',\n        utm_content: 'utm_content',\n      });\n      expect(getQueryParams).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('getReferrer', () => {\n    afterEach(() => {\n      Object.defineProperty(document, 'referrer', {\n        value: '',\n        writable: true,\n      });\n    });\n\n    test('should return referrer info', () => {\n      Object.defineProperty(document, 'referrer', {\n        value: 'https://amplitude.com',\n        writable: true,\n      });\n      const parser = new CampaignParser();\n      const referrer = parser.getReferrer();\n      expect(referrer).toEqual({\n        referrer: 'https://amplitude.com',\n        referring_domain: 'amplitude.com',\n      });\n    });\n\n    test('should return not referrer info', () => {\n      Object.defineProperty(document, 'referrer', {\n        value: undefined,\n        writable: true,\n      });\n      const parser = new CampaignParser();\n      const referrer = parser.getReferrer();\n      expect(referrer).toEqual({});\n    });\n  });\n\n  describe('getGclid', () => {\n    test('should return gclid data', () => {\n      const parser = new CampaignParser();\n      jest.spyOn(queryParams, 'getQueryParams').mockReturnValueOnce({\n        gclid: 'hello google',\n        fbclid: 'hello fb',\n      });\n      const data = parser.getClickIds();\n      expect(data).toEqual({\n        gclid: 'hello google',\n        fbclid: 'hello fb',\n      });\n    });\n\n    test('should return empty data', () => {\n      const parser = new CampaignParser();\n      jest.spyOn(queryParams, 'getQueryParams').mockReturnValueOnce({});\n      const data = parser.getClickIds();\n      expect(data).toEqual({});\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-client-common/test/attribution/campaign-tracker.test.ts",
    "content": "import { API_KEY } from '../helpers/constants';\nimport { CampaignTracker } from '../../src/attribution/campaign-tracker';\nimport { BASE_CAMPAIGN } from '../../src/attribution/constants';\nimport { MemoryStorage } from '@amplitude/analytics-core';\nimport { Campaign } from '@amplitude/analytics-types';\n\ndescribe('CampaignTracker', () => {\n  describe('isNewCampaign', () => {\n    test('should return true for new campaign', () => {\n      const config = {\n        storage: new MemoryStorage<Campaign>(),\n        track: jest.fn(),\n        onNewCampaign: jest.fn(),\n      };\n      const campaignTracker = new CampaignTracker(API_KEY, config);\n      const previousCampaign = {\n        ...BASE_CAMPAIGN,\n      };\n      const currentCampaign = {\n        ...BASE_CAMPAIGN,\n        utm_campaign: 'utm_campaign',\n      };\n      expect(campaignTracker.isNewCampaign(currentCampaign, previousCampaign)).toBe(true);\n    });\n\n    test('should return true for new referrer', () => {\n      const config = {\n        storage: new MemoryStorage<Campaign>(),\n        track: jest.fn(),\n        onNewCampaign: jest.fn(),\n      };\n      const campaignTracker = new CampaignTracker(API_KEY, config);\n      const previousCampaign = {\n        ...BASE_CAMPAIGN,\n        utm_campaign: 'utm_campaign',\n        referring_domain: 'a',\n      };\n      const currentCampaign = {\n        ...BASE_CAMPAIGN,\n        utm_campaign: 'utm_campaign',\n        referring_domain: 'b',\n      };\n      expect(campaignTracker.isNewCampaign(currentCampaign, previousCampaign)).toBe(true);\n    });\n\n    test('should return false for excluded referrer', () => {\n      const config = {\n        storage: new MemoryStorage<Campaign>(),\n        track: jest.fn(),\n        onNewCampaign: jest.fn(),\n        excludeReferrers: ['a'],\n      };\n      const campaignTracker = new CampaignTracker(API_KEY, config);\n      const previousCampaign = {\n        ...BASE_CAMPAIGN,\n      };\n      const currentCampaign = {\n        ...BASE_CAMPAIGN,\n        referring_domain: 'a',\n      };\n      expect(campaignTracker.isNewCampaign(currentCampaign, previousCampaign)).toBe(false);\n    });\n\n    test('should return true for undefined previous campaign', () => {\n      const config = {\n        storage: new MemoryStorage<Campaign>(),\n        track: jest.fn(),\n        onNewCampaign: jest.fn(),\n        excludeReferrers: ['a'],\n      };\n      const campaignTracker = new CampaignTracker(API_KEY, config);\n      const previousCampaign = undefined;\n      const currentCampaign = {\n        ...BASE_CAMPAIGN,\n      };\n      expect(campaignTracker.isNewCampaign(currentCampaign, previousCampaign)).toBe(true);\n    });\n\n    test('should return false for undefined previous campaign and excluded referrer', () => {\n      const config = {\n        storage: new MemoryStorage<Campaign>(),\n        track: jest.fn(),\n        onNewCampaign: jest.fn(),\n        excludeReferrers: ['a'],\n      };\n      const campaignTracker = new CampaignTracker(API_KEY, config);\n      const previousCampaign = undefined;\n      const currentCampaign = {\n        ...BASE_CAMPAIGN,\n        referring_domain: 'a',\n      };\n      expect(campaignTracker.isNewCampaign(currentCampaign, previousCampaign)).toBe(false);\n    });\n  });\n\n  describe('saveCampaignToStorage', () => {\n    test('should save campaign', async () => {\n      const config = {\n        storage: new MemoryStorage<Campaign>(),\n        track: jest.fn(),\n        onNewCampaign: jest.fn(),\n      };\n      const campaignTracker = new CampaignTracker(API_KEY, config);\n      const set = jest.spyOn(campaignTracker.storage, 'set');\n      await campaignTracker.saveCampaignToStorage({\n        ...BASE_CAMPAIGN,\n        utm_campaign: 'utm_campaign',\n      });\n      expect(set).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('getCampaignFromStorage', () => {\n    test('should get campaign', async () => {\n      const config = {\n        storage: new MemoryStorage<Campaign>(),\n        track: jest.fn(),\n        onNewCampaign: jest.fn(),\n      };\n      const campaignTracker = new CampaignTracker(API_KEY, config);\n      const get = jest.spyOn(campaignTracker.storage, 'get');\n      expect(await campaignTracker.getCampaignFromStorage()).toEqual(undefined);\n      expect(get).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('createCampaignEvent', () => {\n    test('should return event', () => {\n      const config = {\n        storage: new MemoryStorage<Campaign>(),\n        track: jest.fn(),\n        onNewCampaign: jest.fn(),\n        trackPageViews: true,\n      };\n      const campaignTracker = new CampaignTracker(API_KEY, config);\n      const campaignEvent = campaignTracker.createCampaignEvent({\n        ...BASE_CAMPAIGN,\n        utm_campaign: 'utm_campaign',\n      });\n      expect(campaignEvent).toEqual({\n        event_type: 'Page View',\n        event_properties: {\n          page_location: 'http://localhost/',\n          page_path: '/',\n          page_title: '',\n        },\n        user_id: undefined,\n        user_properties: {\n          $set: {\n            utm_campaign: 'utm_campaign',\n          },\n          $setOnce: {\n            initial_dclid: 'EMPTY',\n            initial_fbclid: 'EMPTY',\n            initial_gbraid: 'EMPTY',\n            initial_gclid: 'EMPTY',\n            initial_ko_click_id: 'EMPTY',\n            initial_li_fat_id: 'EMPTY',\n            initial_msclkid: 'EMPTY',\n            initial_wbraid: 'EMPTY',\n            initial_referrer: 'EMPTY',\n            initial_referring_domain: 'EMPTY',\n            initial_rdt_cid: 'EMPTY',\n            initial_ttclid: 'EMPTY',\n            initial_twclid: 'EMPTY',\n            initial_utm_campaign: 'utm_campaign',\n            initial_utm_content: 'EMPTY',\n            initial_utm_id: 'EMPTY',\n            initial_utm_medium: 'EMPTY',\n            initial_utm_source: 'EMPTY',\n            initial_utm_term: 'EMPTY',\n          },\n          $unset: {\n            dclid: '-',\n            fbclid: '-',\n            gbraid: '-',\n            gclid: '-',\n            ko_click_id: '-',\n            li_fat_id: '-',\n            msclkid: '-',\n            wbraid: '-',\n            referrer: '-',\n            referring_domain: '-',\n            rdt_cid: '-',\n            ttclid: '-',\n            twclid: '-',\n            utm_content: '-',\n            utm_id: '-',\n            utm_medium: '-',\n            utm_source: '-',\n            utm_term: '-',\n          },\n        },\n      });\n    });\n\n    test('should return event with custom empty value', () => {\n      const config = {\n        storage: new MemoryStorage<Campaign>(),\n        track: jest.fn(),\n        onNewCampaign: jest.fn(),\n        initialEmptyValue: '(none)',\n      };\n      const campaignTracker = new CampaignTracker(API_KEY, config);\n      const campaignEvent = campaignTracker.createCampaignEvent({\n        ...BASE_CAMPAIGN,\n        utm_campaign: 'utm_campaign',\n      });\n      expect(campaignEvent).toEqual({\n        event_type: '$identify',\n        user_id: undefined,\n        user_properties: {\n          $set: {\n            utm_campaign: 'utm_campaign',\n          },\n          $setOnce: {\n            initial_dclid: '(none)',\n            initial_fbclid: '(none)',\n            initial_gbraid: '(none)',\n            initial_gclid: '(none)',\n            initial_ko_click_id: '(none)',\n            initial_li_fat_id: '(none)',\n            initial_msclkid: '(none)',\n            initial_wbraid: '(none)',\n            initial_referrer: '(none)',\n            initial_referring_domain: '(none)',\n            initial_rdt_cid: '(none)',\n            initial_ttclid: '(none)',\n            initial_twclid: '(none)',\n            initial_utm_campaign: 'utm_campaign',\n            initial_utm_content: '(none)',\n            initial_utm_id: '(none)',\n            initial_utm_medium: '(none)',\n            initial_utm_source: '(none)',\n            initial_utm_term: '(none)',\n          },\n          $unset: {\n            dclid: '-',\n            fbclid: '-',\n            gbraid: '-',\n            gclid: '-',\n            ko_click_id: '-',\n            li_fat_id: '-',\n            msclkid: '-',\n            wbraid: '-',\n            referrer: '-',\n            referring_domain: '-',\n            rdt_cid: '-',\n            ttclid: '-',\n            twclid: '-',\n            utm_content: '-',\n            utm_id: '-',\n            utm_medium: '-',\n            utm_source: '-',\n            utm_term: '-',\n          },\n        },\n      });\n    });\n  });\n\n  describe('send', () => {\n    test('should force track', async () => {\n      const config = {\n        storage: new MemoryStorage<Campaign>(),\n        track: jest.fn(),\n        onNewCampaign: jest.fn(),\n      };\n      const campaignTracker = new CampaignTracker(API_KEY, config);\n      const track = jest.spyOn(campaignTracker, 'track').mockReturnValueOnce(Promise.resolve());\n      const saveCampaignToStorage = jest\n        .spyOn(campaignTracker, 'saveCampaignToStorage')\n        .mockResolvedValueOnce(undefined);\n      await campaignTracker.send(true);\n      expect(track).toHaveBeenCalledTimes(1);\n      expect(saveCampaignToStorage).toHaveBeenCalledTimes(1);\n    });\n\n    test('should disbale tracking', async () => {\n      const config = {\n        disabled: true,\n        storage: new MemoryStorage<Campaign>(),\n        track: jest.fn(),\n        onNewCampaign: jest.fn(),\n      };\n      const campaignTracker = new CampaignTracker(API_KEY, config);\n      const track = jest.spyOn(campaignTracker, 'track').mockReturnValueOnce(Promise.resolve());\n      const saveCampaignToStorage = jest\n        .spyOn(campaignTracker, 'saveCampaignToStorage')\n        .mockResolvedValueOnce(undefined);\n      await campaignTracker.send(true);\n      expect(track).toHaveBeenCalledTimes(0);\n      expect(saveCampaignToStorage).toHaveBeenCalledTimes(0);\n    });\n\n    test('should track new campaigns', async () => {\n      const onNewCampaign = jest.fn();\n      const config = {\n        storage: new MemoryStorage<Campaign>(),\n        track: jest.fn(),\n        onNewCampaign,\n        trackNewCampaigns: true,\n      };\n      const campaignTracker = new CampaignTracker(API_KEY, config);\n      const isNewCampaign = jest.spyOn(campaignTracker, 'isNewCampaign').mockReturnValueOnce(true);\n      const track = jest.spyOn(campaignTracker, 'track').mockReturnValueOnce(Promise.resolve());\n      const saveCampaignToStorage = jest\n        .spyOn(campaignTracker, 'saveCampaignToStorage')\n        .mockResolvedValueOnce(undefined);\n      await campaignTracker.send(false);\n      expect(onNewCampaign).toHaveBeenCalledTimes(1);\n      expect(isNewCampaign).toHaveBeenCalledTimes(1);\n      expect(track).toHaveBeenCalledTimes(1);\n      expect(saveCampaignToStorage).toHaveBeenCalledTimes(1);\n    });\n\n    test('should not track same campaigns', async () => {\n      const onNewCampaign = jest.fn();\n      const config = {\n        storage: new MemoryStorage<Campaign>(),\n        track: jest.fn(),\n        onNewCampaign,\n        trackNewCampaigns: true,\n      };\n      const campaignTracker = new CampaignTracker(API_KEY, config);\n      const isNewCampaign = jest.spyOn(campaignTracker, 'isNewCampaign').mockReturnValueOnce(false);\n      const track = jest.spyOn(campaignTracker, 'track').mockReturnValueOnce(Promise.resolve());\n      const saveCampaignToStorage = jest\n        .spyOn(campaignTracker, 'saveCampaignToStorage')\n        .mockResolvedValueOnce(undefined);\n      await campaignTracker.send(false);\n      expect(onNewCampaign).toHaveBeenCalledTimes(0);\n      expect(isNewCampaign).toHaveBeenCalledTimes(1);\n      expect(track).toHaveBeenCalledTimes(0);\n      expect(saveCampaignToStorage).toHaveBeenCalledTimes(0);\n    });\n\n    test('should not track new campaigns', async () => {\n      const onNewCampaign = jest.fn();\n      const config = {\n        storage: new MemoryStorage<Campaign>(),\n        track: jest.fn(),\n        onNewCampaign,\n        trackNewCampaigns: false,\n      };\n      const campaignTracker = new CampaignTracker(API_KEY, config);\n      const track = jest.spyOn(campaignTracker, 'track').mockReturnValueOnce(Promise.resolve());\n      const saveCampaignToStorage = jest\n        .spyOn(campaignTracker, 'saveCampaignToStorage')\n        .mockResolvedValueOnce(undefined);\n      await campaignTracker.send(false);\n      expect(onNewCampaign).toHaveBeenCalledTimes(0);\n      expect(track).toHaveBeenCalledTimes(0);\n      expect(saveCampaignToStorage).toHaveBeenCalledTimes(0);\n    });\n  });\n\n  describe('domain comparison without subdomains', () => {\n    const cases = [\n      ['amplitude.com', 'www.amplitude.com', false] as const,\n      ['google.com', 'amplitude.com', true] as const,\n      ['', '', false] as const,\n      ['www.amplitude.com', 'www.amplitude.com', false] as const,\n      ['', 'www.amplitude.com', true] as const,\n    ];\n    for (const [domain1, domain2, isNewCampaign] of cases) {\n      test(`for \"${domain1}\" and \"${domain2}\", should track new campaign: ${isNewCampaign.toString()} `, () => {\n        const config = {\n          storage: new MemoryStorage<Campaign>(),\n          track: jest.fn(),\n          onNewCampaign: () => false,\n        };\n        const campaignTracker = new CampaignTracker(API_KEY, config);\n        const result = campaignTracker.isNewCampaign(\n          { referring_domain: domain1 } as Campaign,\n          { referring_domain: domain2 } as Campaign,\n          true,\n        );\n        expect(result).toBe(isNewCampaign);\n      });\n    }\n  });\n});\n"
  },
  {
    "path": "packages/analytics-client-common/test/attribution/helpers.test.ts",
    "content": "import { BASE_CAMPAIGN } from '../../src/attribution/constants';\nimport {\n  isNewCampaign,\n  createCampaignEvent,\n  getDefaultExcludedReferrers,\n  isExcludedReferrer,\n} from '../../src/attribution/helpers';\n\nimport { getStorageKey } from '../../src/storage/helpers';\n\nconst loggerProvider = {\n  log: jest.fn(),\n  debug: jest.fn(),\n  warn: jest.fn(),\n  error: jest.fn(),\n  enable: jest.fn(),\n  disable: jest.fn(),\n};\n\ndescribe('getStorageKey', () => {\n  test('should return storage key without explicit suffix and limit', () => {\n    expect(getStorageKey('API_KEY')).toBe('AMP_API_KEY');\n  });\n\n  test('should return storage key', () => {\n    expect(getStorageKey('API_KEY', 'MKTG', 3)).toBe('AMP_MKTG_API');\n  });\n});\n\ndescribe('isNewCampaign', () => {\n  test('should return true for new campaign', () => {\n    const previousCampaign = {\n      ...BASE_CAMPAIGN,\n    };\n    const currentCampaign = {\n      ...BASE_CAMPAIGN,\n      utm_campaign: 'utm_campaign',\n    };\n    expect(isNewCampaign(currentCampaign, previousCampaign, {}, loggerProvider)).toBe(true);\n  });\n\n  test('should return true for new referrer', () => {\n    const previousCampaign = {\n      ...BASE_CAMPAIGN,\n      utm_campaign: 'utm_campaign',\n      referring_domain: 'a.b.c.d',\n    };\n    const currentCampaign = {\n      ...BASE_CAMPAIGN,\n      utm_campaign: 'utm_campaign',\n      referring_domain: 'b.c.d.e',\n    };\n    expect(isNewCampaign(currentCampaign, previousCampaign, {}, loggerProvider)).toBe(true);\n  });\n\n  test('should return false for string excluded referrer', () => {\n    const previousCampaign = {\n      ...BASE_CAMPAIGN,\n    };\n    const currentCampaign = {\n      ...BASE_CAMPAIGN,\n      referring_domain: 'amplitude.com',\n    };\n    expect(\n      isNewCampaign(\n        currentCampaign,\n        previousCampaign,\n        {\n          excludeReferrers: ['amplitude.com'],\n        },\n        loggerProvider,\n      ),\n    ).toBe(false);\n  });\n\n  test('should return false for regexp excluded referrer', () => {\n    const previousCampaign = {\n      ...BASE_CAMPAIGN,\n    };\n    const currentCampaign = {\n      ...BASE_CAMPAIGN,\n      referring_domain: 'amplitude.com',\n    };\n    expect(\n      isNewCampaign(\n        currentCampaign,\n        previousCampaign,\n        {\n          excludeReferrers: getDefaultExcludedReferrers('.amplitude.com'),\n        },\n        loggerProvider,\n      ),\n    ).toBe(false);\n  });\n\n  test('should return false for cross subdomain regexp excluded referrer', () => {\n    const previousCampaign = {\n      ...BASE_CAMPAIGN,\n    };\n    const currentCampaign = {\n      ...BASE_CAMPAIGN,\n      referring_domain: 'analytics.amplitude.com',\n    };\n    expect(\n      isNewCampaign(\n        currentCampaign,\n        previousCampaign,\n        {\n          excludeReferrers: getDefaultExcludedReferrers('.amplitude.com'),\n        },\n        loggerProvider,\n      ),\n    ).toBe(false);\n  });\n\n  test('should return true for undefined previous campaign', () => {\n    const previousCampaign = undefined;\n    const currentCampaign = {\n      ...BASE_CAMPAIGN,\n    };\n    expect(\n      isNewCampaign(\n        currentCampaign,\n        previousCampaign,\n        {\n          excludeReferrers: ['a'],\n        },\n        loggerProvider,\n      ),\n    ).toBe(true);\n  });\n\n  test('should return false for undefined previous campaign and excluded referrer', () => {\n    const previousCampaign = undefined;\n    const currentCampaign = {\n      ...BASE_CAMPAIGN,\n      referring_domain: 'a',\n    };\n    expect(\n      isNewCampaign(\n        currentCampaign,\n        previousCampaign,\n        {\n          excludeReferrers: ['a'],\n        },\n        loggerProvider,\n      ),\n    ).toBe(false);\n  });\n\n  test('should return false for no extra referrer with direct traffic in the same session', () => {\n    const previousCampaign = {\n      ...BASE_CAMPAIGN,\n      utm_campaign: 'utm_campaign',\n      referring_domain: 'a.b.c.d',\n    };\n    const currentCampaign = {\n      ...BASE_CAMPAIGN,\n    };\n\n    expect(isNewCampaign(currentCampaign, previousCampaign, {}, loggerProvider, false)).toBe(false);\n  });\n\n  test('should return true for no referrer with any new campaign in the same session', () => {\n    const previousCampaign = {\n      ...BASE_CAMPAIGN,\n      utm_campaign: 'utm_campaign',\n      referring_domain: 'a.b.c.d',\n    };\n    const currentCampaign = {\n      ...BASE_CAMPAIGN,\n      utm_source: 'utm_source',\n    };\n\n    expect(isNewCampaign(currentCampaign, previousCampaign, {}, loggerProvider, false)).toBe(true);\n  });\n});\n\ndescribe('isExcludedReferrer', () => {\n  test('should return true with string excluded referrer', () => {\n    expect(isExcludedReferrer(['data.amplitude.com'], 'data.amplitude.com')).toEqual(true);\n  });\n\n  test('should return true with regexp excluded referrer', () => {\n    expect(isExcludedReferrer(getDefaultExcludedReferrers('.amplitude.com'), 'data.amplitude.com')).toEqual(true);\n  });\n});\n\ndescribe('createCampaignEvent', () => {\n  test('should return event', () => {\n    const campaignEvent = createCampaignEvent(\n      {\n        ...BASE_CAMPAIGN,\n        utm_campaign: 'utm_campaign',\n      },\n      {},\n    );\n    expect(campaignEvent).toEqual({\n      event_type: '$identify',\n      user_id: undefined,\n      user_properties: {\n        $set: {\n          utm_campaign: 'utm_campaign',\n        },\n        $setOnce: {\n          initial_dclid: 'EMPTY',\n          initial_fbclid: 'EMPTY',\n          initial_gbraid: 'EMPTY',\n          initial_gclid: 'EMPTY',\n          initial_ko_click_id: 'EMPTY',\n          initial_li_fat_id: 'EMPTY',\n          initial_msclkid: 'EMPTY',\n          initial_wbraid: 'EMPTY',\n          initial_referrer: 'EMPTY',\n          initial_referring_domain: 'EMPTY',\n          initial_rdt_cid: 'EMPTY',\n          initial_ttclid: 'EMPTY',\n          initial_twclid: 'EMPTY',\n          initial_utm_campaign: 'utm_campaign',\n          initial_utm_content: 'EMPTY',\n          initial_utm_id: 'EMPTY',\n          initial_utm_medium: 'EMPTY',\n          initial_utm_source: 'EMPTY',\n          initial_utm_term: 'EMPTY',\n        },\n        $unset: {\n          dclid: '-',\n          fbclid: '-',\n          gbraid: '-',\n          gclid: '-',\n          ko_click_id: '-',\n          li_fat_id: '-',\n          msclkid: '-',\n          wbraid: '-',\n          referrer: '-',\n          referring_domain: '-',\n          rdt_cid: '-',\n          ttclid: '-',\n          twclid: '-',\n          utm_content: '-',\n          utm_id: '-',\n          utm_medium: '-',\n          utm_source: '-',\n          utm_term: '-',\n        },\n      },\n    });\n  });\n\n  test('should return event with custom empty value', () => {\n    const campaignEvent = createCampaignEvent(\n      {\n        ...BASE_CAMPAIGN,\n        utm_campaign: 'utm_campaign',\n      },\n      {\n        initialEmptyValue: '(none)',\n      },\n    );\n    expect(campaignEvent).toEqual({\n      event_type: '$identify',\n      user_id: undefined,\n      user_properties: {\n        $set: {\n          utm_campaign: 'utm_campaign',\n        },\n        $setOnce: {\n          initial_dclid: '(none)',\n          initial_fbclid: '(none)',\n          initial_gbraid: '(none)',\n          initial_gclid: '(none)',\n          initial_ko_click_id: '(none)',\n          initial_li_fat_id: '(none)',\n          initial_msclkid: '(none)',\n          initial_wbraid: '(none)',\n          initial_referrer: '(none)',\n          initial_referring_domain: '(none)',\n          initial_rdt_cid: '(none)',\n          initial_ttclid: '(none)',\n          initial_twclid: '(none)',\n          initial_utm_campaign: 'utm_campaign',\n          initial_utm_content: '(none)',\n          initial_utm_id: '(none)',\n          initial_utm_medium: '(none)',\n          initial_utm_source: '(none)',\n          initial_utm_term: '(none)',\n        },\n        $unset: {\n          dclid: '-',\n          fbclid: '-',\n          gbraid: '-',\n          gclid: '-',\n          ko_click_id: '-',\n          li_fat_id: '-',\n          msclkid: '-',\n          wbraid: '-',\n          referrer: '-',\n          referring_domain: '-',\n          rdt_cid: '-',\n          ttclid: '-',\n          twclid: '-',\n          utm_content: '-',\n          utm_id: '-',\n          utm_medium: '-',\n          utm_source: '-',\n          utm_term: '-',\n        },\n      },\n    });\n  });\n});\n\ndescribe('getDefaultExcludedReferrers', () => {\n  test('should return empty array', () => {\n    const excludedReferrers = getDefaultExcludedReferrers(undefined);\n    expect(excludedReferrers).toEqual([]);\n  });\n\n  test('should return array with regex 1', () => {\n    const excludedReferrers = getDefaultExcludedReferrers('amplitude.com');\n    expect(excludedReferrers).toEqual([new RegExp('amplitude\\\\.com$')]);\n  });\n\n  test('should return array with regex 2', () => {\n    const excludedReferrers = getDefaultExcludedReferrers('.amplitude.com');\n    expect(excludedReferrers).toEqual([new RegExp('amplitude\\\\.com$')]);\n  });\n});\n"
  },
  {
    "path": "packages/analytics-client-common/test/attribution/web-attribution.test.ts",
    "content": "import { Logger, UUID } from '@amplitude/analytics-core';\nimport { AttributionOptions, BrowserConfig, LogLevel } from '@amplitude/analytics-types';\nimport { BASE_CAMPAIGN } from '../../src/attribution/constants';\nimport { CampaignParser } from '../../src/attribution/campaign-parser';\nimport { WebAttribution } from '../../src/attribution/web-attribution';\nimport { FetchTransport } from '../../src/transports/fetch';\nimport { CookieStorage } from '../../src/storage/cookie';\n\ndescribe('shouldTrackNewCampaign', () => {\n  const mockConfig: BrowserConfig = {\n    apiKey: UUID(),\n    flushIntervalMillis: 0,\n    flushMaxRetries: 0,\n    flushQueueSize: 0,\n    logLevel: LogLevel.None,\n    loggerProvider: new Logger(),\n    offline: false,\n    optOut: false,\n    serverUrl: undefined,\n    transportProvider: new FetchTransport(),\n    useBatch: false,\n    cookieOptions: {\n      domain: '.amplitude.com',\n      expiration: 365,\n      sameSite: 'Lax',\n      secure: false,\n      upgrade: true,\n    },\n    cookieStorage: new CookieStorage(),\n    sessionTimeout: 30 * 60 * 1000,\n    trackingOptions: {\n      ipAddress: true,\n      language: true,\n      platform: true,\n    },\n  };\n  const option: AttributionOptions = {};\n\n  test('should track campaign with new campaign', async () => {\n    const overrideMockConfig = {\n      ...mockConfig,\n      cookieOptions: undefined,\n    };\n    const webAttribution = new WebAttribution(option, overrideMockConfig);\n\n    jest.spyOn(CampaignParser.prototype, 'parse').mockResolvedValueOnce({\n      ...BASE_CAMPAIGN,\n      utm_source: 'amp-test',\n    });\n    jest.spyOn(webAttribution.storage, 'get').mockResolvedValueOnce({\n      ...BASE_CAMPAIGN,\n    });\n\n    await webAttribution.init();\n    expect(webAttribution.shouldTrackNewCampaign).toBe(true);\n  });\n\n  test('should not track campaign without new campaign', async () => {\n    const overrideMockConfig = {\n      ...mockConfig,\n      cookieOptions: undefined,\n    };\n    const emptyCampaign = { ...BASE_CAMPAIGN };\n    const webAttribution = new WebAttribution(option, overrideMockConfig);\n\n    jest.spyOn(CampaignParser.prototype, 'parse').mockResolvedValue(emptyCampaign);\n    jest.spyOn(webAttribution.storage, 'get').mockResolvedValue(emptyCampaign);\n\n    await webAttribution.init();\n    expect(webAttribution.shouldTrackNewCampaign).toBe(false);\n  });\n\n  test('should generate campaign event with given eventId', async () => {\n    const webAttribution = new WebAttribution(option, mockConfig);\n    const event_id = 1;\n    const campaignEvent = webAttribution.generateCampaignEvent(event_id);\n    expect(campaignEvent.event_id).toBe(event_id);\n  });\n\n  test('should set session id on a new Campaign', async () => {\n    const option = {\n      resetSessionOnNewCampaign: true,\n    };\n    const webAttribution = new WebAttribution(option, mockConfig);\n    await webAttribution.init();\n\n    expect(webAttribution.shouldSetSessionIdOnNewCampaign()).toBe(true);\n  });\n\n  test('should not set session id on a new Campaign', async () => {\n    const option = {\n      resetSessionOnNewCampaign: true,\n    };\n    const webAttribution = new WebAttribution(option, mockConfig);\n    await webAttribution.init();\n\n    webAttribution.generateCampaignEvent();\n    expect(webAttribution.shouldSetSessionIdOnNewCampaign()).toBe(false);\n  });\n\n  test('should ignore the campaign for direct traffic in session', async () => {\n    const lastEventTime = Date.now();\n\n    const overrideMockConfig = {\n      ...mockConfig,\n      // In session event\n      lastEventTime,\n    };\n    const webAttribution = new WebAttribution({}, overrideMockConfig);\n    const previousCampaign = {\n      ...BASE_CAMPAIGN,\n      referrer: 'https://www.google.com',\n      referring_domain: 'www.google.com',\n    };\n\n    jest.spyOn(CampaignParser.prototype, 'parse').mockResolvedValue(BASE_CAMPAIGN); // Direct Traffic\n    jest.spyOn(webAttribution.storage, 'get').mockResolvedValue(previousCampaign);\n\n    await webAttribution.init();\n    expect(webAttribution.shouldTrackNewCampaign).toBe(false);\n  });\n\n  test('should not ignore the campaign for direct traffic in new session', async () => {\n    const lastEventTime = Date.now() - 2 * 30 * 60 * 1000;\n\n    const overrideMockConfig = {\n      ...mockConfig,\n      // Out of session event\n      lastEventTime,\n    };\n\n    const webAttribution = new WebAttribution({}, overrideMockConfig);\n    const previousCampaign = {\n      ...BASE_CAMPAIGN,\n      referrer: 'https://www.google.com',\n      referring_domain: 'www.google.com',\n    };\n\n    jest.spyOn(CampaignParser.prototype, 'parse').mockResolvedValue(BASE_CAMPAIGN); // Direct Traffic\n    jest.spyOn(webAttribution.storage, 'get').mockResolvedValue(previousCampaign);\n\n    await webAttribution.init();\n    expect(webAttribution.shouldTrackNewCampaign).toBe(true);\n  });\n});\n"
  },
  {
    "path": "packages/analytics-client-common/test/cookie-name.test.ts",
    "content": "import { getCookieName, getOldCookieName } from '../src/cookie-name';\nimport { API_KEY } from './helpers/constants';\n\ndescribe('cookie-name', () => {\n  describe('getCookieName', () => {\n    test('should return cookie name', () => {\n      expect(getCookieName(API_KEY)).toBe('AMP_apiKey');\n    });\n\n    test('should handle apiKey is empty string', () => {\n      expect(getCookieName('')).toBe('AMP');\n    });\n  });\n\n  describe('getOldCookieName', () => {\n    test('should return cookie name', () => {\n      expect(getOldCookieName(API_KEY)).toBe('amp_apiKey');\n    });\n\n    test('should handle apiKey is empty string', () => {\n      expect(getOldCookieName('')).toBe('amp_');\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-client-common/test/default-tracking.test.ts",
    "content": "import {\n  getAttributionTrackingConfig,\n  getPageViewTrackingConfig,\n  getElementInteractionsConfig,\n  isAttributionTrackingEnabled,\n  isFileDownloadTrackingEnabled,\n  isFormInteractionTrackingEnabled,\n  isPageViewTrackingEnabled,\n  isSessionTrackingEnabled,\n  isElementInteractionsEnabled,\n} from '../src/default-tracking';\n\ndescribe('isFileDownloadTrackingEnabled', () => {\n  test('should return true with true parameter', () => {\n    expect(isFileDownloadTrackingEnabled(true)).toBe(true);\n  });\n\n  test('should return true with undefined parameter', () => {\n    expect(isFileDownloadTrackingEnabled(undefined)).toBe(true);\n  });\n\n  test('should return false with false parameter', () => {\n    expect(isFileDownloadTrackingEnabled(false)).toBe(false);\n  });\n\n  test('should return true with object parameter', () => {\n    expect(\n      isFileDownloadTrackingEnabled({\n        fileDownloads: true,\n      }),\n    ).toBe(true);\n  });\n\n  test('should return false with object parameter', () => {\n    expect(\n      isFileDownloadTrackingEnabled({\n        fileDownloads: false,\n      }),\n    ).toBe(false);\n  });\n});\n\ndescribe('isFormInteractionTrackingEnabled', () => {\n  test('should return true with true parameter', () => {\n    expect(isFormInteractionTrackingEnabled(true)).toBe(true);\n  });\n\n  test('should return true with undefined parameter', () => {\n    expect(isFormInteractionTrackingEnabled(undefined)).toBe(true);\n  });\n\n  test('should return false with false parameter', () => {\n    expect(isFormInteractionTrackingEnabled(false)).toBe(false);\n  });\n\n  test('should return true with object parameter', () => {\n    expect(\n      isFormInteractionTrackingEnabled({\n        formInteractions: true,\n      }),\n    ).toBe(true);\n  });\n\n  test('should return false with object parameter', () => {\n    expect(\n      isFormInteractionTrackingEnabled({\n        formInteractions: false,\n      }),\n    ).toBe(false);\n  });\n});\n\ndescribe('isPageViewTrackingEnabled', () => {\n  test('should return true with true parameter', () => {\n    expect(isPageViewTrackingEnabled(true)).toBe(true);\n  });\n\n  test('should return true with undefined parameter', () => {\n    expect(isPageViewTrackingEnabled(undefined)).toBe(true);\n  });\n\n  test('should return true with false parameter', () => {\n    expect(isPageViewTrackingEnabled(false)).toBe(false);\n  });\n\n  test('should return true with object parameter', () => {\n    expect(\n      isPageViewTrackingEnabled({\n        pageViews: true,\n      }),\n    ).toBe(true);\n  });\n\n  test('should return false with object parameter', () => {\n    expect(\n      isPageViewTrackingEnabled({\n        pageViews: false,\n      }),\n    ).toBe(false);\n  });\n\n  test('should return true with nested object parameter', () => {\n    expect(\n      isPageViewTrackingEnabled({\n        pageViews: {},\n      }),\n    ).toBe(true);\n  });\n});\n\ndescribe('isSessionTrackingEnabled', () => {\n  test('should return true with true parameter', () => {\n    expect(isSessionTrackingEnabled(true)).toBe(true);\n  });\n\n  test('should return true with undefined parameter', () => {\n    expect(isSessionTrackingEnabled(undefined)).toBe(true);\n  });\n\n  test('should return false with false parameter', () => {\n    expect(isSessionTrackingEnabled(false)).toBe(false);\n  });\n\n  test('should return true with object parameter', () => {\n    expect(\n      isSessionTrackingEnabled({\n        sessions: true,\n      }),\n    ).toBe(true);\n  });\n\n  test('should return false with object parameter', () => {\n    expect(\n      isSessionTrackingEnabled({\n        sessions: false,\n      }),\n    ).toBe(false);\n  });\n});\n\ndescribe('isAttributionTrackingEnabled', () => {\n  test('should return true with true parameter', () => {\n    expect(isAttributionTrackingEnabled(true)).toBe(true);\n  });\n\n  test('should return true with undefined parameter', () => {\n    expect(isAttributionTrackingEnabled(undefined)).toBe(true);\n  });\n\n  test('should return false with false parameter', () => {\n    expect(isAttributionTrackingEnabled(false)).toBe(false);\n  });\n\n  test('should return true with object parameter', () => {\n    expect(\n      isAttributionTrackingEnabled({\n        attribution: true,\n      }),\n    ).toBe(true);\n  });\n\n  test('should return false with object parameter', () => {\n    expect(\n      isAttributionTrackingEnabled({\n        attribution: false,\n      }),\n    ).toBe(false);\n  });\n});\n\ndescribe('isElementInteractionsEnabled', () => {\n  test('should return true with true parameter', () => {\n    expect(isElementInteractionsEnabled(true)).toBe(true);\n  });\n\n  test('should return false with undefined parameter', () => {\n    expect(isElementInteractionsEnabled(undefined)).toBe(false);\n  });\n\n  test('should return false with false parameter', () => {\n    expect(isElementInteractionsEnabled(false)).toBe(false);\n  });\n\n  test('should return true with object parameter', () => {\n    expect(\n      isElementInteractionsEnabled({\n        elementInteractions: true,\n      }),\n    ).toBe(true);\n  });\n\n  test('should return false with object parameter', () => {\n    expect(\n      isElementInteractionsEnabled({\n        elementInteractions: false,\n      }),\n    ).toBe(false);\n  });\n\n  test('should return false with object parameter undefined', () => {\n    expect(\n      isElementInteractionsEnabled({\n        elementInteractions: undefined,\n      }),\n    ).toBe(false);\n  });\n});\n\ndescribe('getPageViewTrackingConfig', () => {\n  test('should return undefined trackOn config', () => {\n    const config = getPageViewTrackingConfig({\n      defaultTracking: {\n        pageViews: true,\n      },\n    });\n\n    expect(config.trackOn).toBe(undefined);\n  });\n\n  test('should return trackOn config returning false', () => {\n    const config = getPageViewTrackingConfig({\n      defaultTracking: {\n        pageViews: false,\n      },\n    });\n\n    expect(typeof config.trackOn).toBe('function');\n    // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n    // @ts-ignore asserts that track on is a function that returns a boolean\n    expect(config.trackOn()).toBe(false);\n  });\n\n  test('should return advanced options', () => {\n    const config = getPageViewTrackingConfig({\n      defaultTracking: {\n        pageViews: {\n          trackOn: 'attribution',\n          trackHistoryChanges: 'all',\n          eventType: 'Page View',\n        },\n      },\n    });\n\n    expect(typeof config.trackOn).toBe('string');\n    expect(config.trackOn).toBe('attribution');\n    expect(config.trackHistoryChanges).toBe('all');\n    expect(config.eventType).toBe('Page View');\n  });\n});\n\ndescribe('getAttributionTrackingConfig', () => {\n  test('should return disabled config', () => {\n    const config = getAttributionTrackingConfig({\n      defaultTracking: {\n        attribution: false,\n      },\n    });\n    expect(config).toEqual({\n      excludeReferrers: undefined,\n      initialEmptyValue: undefined,\n      resetSessionOnNewCampaign: undefined,\n    });\n  });\n\n  test('should return default config', () => {\n    const config = getAttributionTrackingConfig({\n      defaultTracking: {\n        attribution: {},\n      },\n    });\n    expect(config).toEqual({\n      excludeReferrers: undefined,\n      initialEmptyValue: undefined,\n      resetSessionOnNewCampaign: undefined,\n    });\n  });\n\n  test('should return custom config', () => {\n    const config = getAttributionTrackingConfig({\n      defaultTracking: {\n        attribution: {\n          excludeReferrers: [],\n          initialEmptyValue: 'EMPTY',\n          resetSessionOnNewCampaign: true,\n        },\n      },\n    });\n    expect(config).toEqual({\n      excludeReferrers: [],\n      initialEmptyValue: 'EMPTY',\n      resetSessionOnNewCampaign: true,\n    });\n  });\n});\n\ndescribe('getElementInteractionsConfig', () => {\n  test('should return an empty object when autocapture is true', () => {\n    const config = getElementInteractionsConfig({\n      autocapture: true,\n    });\n\n    expect(config).toBeUndefined();\n  });\n\n  test('should return an empty object when userInteraction is true', () => {\n    const config = getElementInteractionsConfig({\n      autocapture: {\n        elementInteractions: true,\n      },\n    });\n\n    expect(config).toBeUndefined();\n  });\n\n  test('should return advanced options', () => {\n    const testCssSelectorAllowlist = ['button'];\n    const testPageUrlAllowlist = ['example.com'];\n    const mockedShouldTrackEventResolver = jest.fn(() => true);\n    const testDataAttributePrefix = 'data-amp-track';\n    const config = getElementInteractionsConfig({\n      autocapture: {\n        elementInteractions: {\n          cssSelectorAllowlist: testCssSelectorAllowlist,\n          pageUrlAllowlist: testPageUrlAllowlist,\n          shouldTrackEventResolver: mockedShouldTrackEventResolver,\n          dataAttributePrefix: testDataAttributePrefix,\n        },\n      },\n    });\n\n    expect(config?.cssSelectorAllowlist).toBe(testCssSelectorAllowlist);\n    expect(config?.pageUrlAllowlist).toBe(testPageUrlAllowlist);\n    expect(config?.shouldTrackEventResolver).toBe(mockedShouldTrackEventResolver);\n    expect(config?.dataAttributePrefix).toBe(testDataAttributePrefix);\n  });\n});\n"
  },
  {
    "path": "packages/analytics-client-common/test/global-scope.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unsafe-member-access */\nimport { getGlobalScope } from '../src/global-scope';\n\ndescribe('getGlobalScope', () => {\n  let originalGlobalThis: any;\n\n  beforeEach(() => {\n    originalGlobalThis = globalThis;\n  });\n\n  afterEach(() => {\n    // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n    // @ts-ignore\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n    globalThis = originalGlobalThis;\n    delete (globalThis as any).ampIntegrationContext;\n  });\n\n  test('returns ampIntegrationContext if it exists', () => {\n    (globalThis as any).ampIntegrationContext = { someKey: 'someValue' };\n    expect(getGlobalScope()).toBe((globalThis as any).ampIntegrationContext);\n  });\n\n  test('returns globalThis if ampIntegrationContext does not exist', () => {\n    const scope = getGlobalScope();\n    // Need to use Object.is because expect(scope).toBe(globalThis) will throw an error\n    expect(Object.is(scope, globalThis)).toBeTruthy();\n  });\n\n  test('should return window if globalThis is undefined and window is defined', () => {\n    // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n    // @ts-ignore\n    globalThis = undefined;\n\n    const scope = getGlobalScope();\n\n    // Note: We NEED to reassign globalThis to its original state because the jest expect function requires it\n    // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n    // @ts-ignore\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n    globalThis = originalGlobalThis;\n    // Need to use Object.is because expect(scope).toBe(globalThis) will throw an error\n    expect(Object.is(scope, window)).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "packages/analytics-client-common/test/helpers/constants.ts",
    "content": "export const API_KEY = 'apiKey';\n"
  },
  {
    "path": "packages/analytics-client-common/test/language.test.ts",
    "content": "import { getLanguage } from '../src/language';\ninterface Navigator {\n  language: string | undefined;\n  languages: string[] | undefined;\n  userLanguage: string | undefined;\n}\n\ndescribe('language', () => {\n  // Simulates other browser version\n  // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n  // @ts-ignore\n  const nav: Navigator = navigator;\n\n  beforeAll(() => {\n    Object.defineProperty(nav, 'userLanguage', {\n      get: () => '',\n      configurable: true,\n      enumerable: true,\n    });\n  });\n\n  afterAll(() => {\n    if (nav.userLanguage) {\n      delete nav.userLanguage;\n    }\n  });\n\n  test('should return a language', () => {\n    enableNavigatorLanguageProperties(['languages', 'language', 'userLanguage']);\n    expect(getLanguage()).not.toBeNull();\n  });\n\n  test('should prioritize the first language of navigator.languages', () => {\n    enableNavigatorLanguageProperties(['languages', 'language', 'userLanguage']);\n    expect(getLanguage()).toBe('some-locale');\n  });\n\n  test('should secondly use the language of navigator.language', () => {\n    enableNavigatorLanguageProperties(['language', 'userLanguage']);\n    expect(getLanguage()).toBe('some-second-locale');\n  });\n\n  test('should thirdly use the language of navigator.userLanguage', () => {\n    enableNavigatorLanguageProperties(['userLanguage']);\n    expect(getLanguage()).toBe('some-third-locale');\n  });\n\n  test('should return empty string if navigator language is not set', () => {\n    enableNavigatorLanguageProperties([]);\n    expect(getLanguage()).toBe('');\n  });\n\n  test('should return empty string if navigator is not set', () => {\n    jest.spyOn(window as any, 'navigator', 'get').mockReturnValue(undefined);\n    expect(getLanguage()).toBe('');\n  });\n\n  function enableNavigatorLanguageProperties(properties: Array<'languages' | 'language' | 'userLanguage'>) {\n    jest\n      .spyOn(nav, 'languages', 'get')\n      .mockReturnValue(properties.includes('languages') ? ['some-locale', 'some-other-locale'] : undefined);\n    jest\n      .spyOn(nav, 'language', 'get')\n      .mockReturnValue(properties.includes('language') ? 'some-second-locale' : undefined);\n    jest\n      .spyOn(nav, 'userLanguage', 'get')\n      .mockReturnValue(properties.includes('userLanguage') ? 'some-third-locale' : undefined);\n  }\n});\n"
  },
  {
    "path": "packages/analytics-client-common/test/plugins/identity.test.ts",
    "content": "import { IdentityEventSender } from '../../src/plugins/identity';\nimport { Config } from '@amplitude/analytics-types';\nimport { getAnalyticsConnector } from '../../src/analytics-connector';\n\ndescribe('identity', () => {\n  describe('execute', () => {\n    beforeEach(() => {\n      getAnalyticsConnector().identityStore.setIdentity({ userProperties: {} });\n    });\n\n    test('should set identity in analytics connector on identify with default instance', async () => {\n      const plugin = new IdentityEventSender();\n      await plugin.setup({} as Config);\n      const event = {\n        event_type: '$identify',\n        user_properties: {\n          $set: { k: 'v' },\n        },\n      };\n      const result = await plugin.execute(event);\n      const identity = getAnalyticsConnector().identityStore.getIdentity();\n      expect(result).toEqual(event);\n      expect(identity.userProperties).toEqual({ k: 'v' });\n    });\n\n    test('should set identity in analytics connector on identify with instance name', async () => {\n      const plugin = new IdentityEventSender();\n      await plugin.setup({\n        instanceName: 'env',\n      } as Config);\n      const event = {\n        event_type: '$identify',\n        user_properties: {\n          $set: { k: 'v' },\n        },\n      };\n      const result = await plugin.execute(event);\n      const identity = getAnalyticsConnector('env').identityStore.getIdentity();\n      expect(result).toEqual(event);\n      expect(identity.userProperties).toEqual({ k: 'v' });\n    });\n\n    test('should do nothing on track event', async () => {\n      const plugin = new IdentityEventSender();\n      await plugin.setup({} as Config);\n      const event = {\n        event_type: 'test_track',\n      };\n      const result = await plugin.execute(event);\n      expect(result).toEqual(event);\n      const emptyIdentity = { userProperties: {} };\n      const identity = getAnalyticsConnector().identityStore.getIdentity();\n      expect(identity).toEqual(emptyIdentity);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-client-common/test/query-params.test.ts",
    "content": "import { getQueryParams } from '../src/query-params';\nimport * as GlobalScopeModule from '../src/global-scope';\n\ndescribe('query-params', () => {\n  describe('getQueryParams', () => {\n    beforeAll(() => {\n      Object.defineProperty(window, 'location', {\n        value: {\n          search: '',\n          writable: true,\n        },\n      });\n    });\n\n    afterAll(() => {\n      Object.defineProperty(window, 'location', {\n        value: {\n          search: '',\n          writable: false,\n        },\n      });\n    });\n\n    test('should parse query params', () => {\n      window.location.search = '?a=1&b=2%20test&&c%24=hello&d';\n      const params = getQueryParams();\n      expect(params).toEqual({\n        a: '1',\n        b: '2 test',\n        c$: 'hello',\n      });\n    });\n\n    test('should parse malformed uri', () => {\n      window.location.search = '?fb=X+%EF%BF%BD%93+C';\n      const params = getQueryParams();\n      expect(params).toEqual({});\n    });\n\n    test('should handle undefined global scope', () => {\n      jest.spyOn(GlobalScopeModule, 'getGlobalScope').mockReturnValueOnce(undefined);\n      const params = getQueryParams();\n      expect(params).toEqual({});\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-client-common/test/session.test.ts",
    "content": "import { isNewSession } from '../src/session';\n\ndescribe('session', () => {\n  const sessionTimeout: number = 30 * 60 * 1000;\n\n  test('should be in a same session for undefined lastEventTime', () => {\n    const isEventInNewSession = isNewSession(sessionTimeout, undefined);\n\n    expect(isEventInNewSession).toBe(false);\n  });\n\n  test('should be a new session', () => {\n    const lastEventTime = Date.now() - sessionTimeout * 2;\n    const isEventInNewSession = isNewSession(sessionTimeout, lastEventTime);\n\n    expect(isEventInNewSession).toBe(true);\n  });\n\n  test('should be in a same session', () => {\n    const lastEventTime = Date.now();\n    const isEventInNewSession = isNewSession(sessionTimeout, lastEventTime);\n\n    expect(isEventInNewSession).toBe(false);\n  });\n});\n"
  },
  {
    "path": "packages/analytics-client-common/test/storage/cookies.test.ts",
    "content": "import { CookieStorage } from '../../src/storage/cookie';\nimport * as GlobalScopeModule from '../../src/global-scope';\n\ndescribe('cookies', () => {\n  describe('isEnabled', () => {\n    test('should return true', async () => {\n      const cookies = new CookieStorage();\n      expect(await cookies.isEnabled()).toBe(true);\n    });\n  });\n\n  describe('get', () => {\n    test('should return undefined for no cookie value', async () => {\n      const cookies = new CookieStorage();\n      expect(await cookies.get('hello')).toBe(undefined);\n    });\n\n    test('should return non-encoded value', async () => {\n      const cookies = new CookieStorage();\n      document.cookie = 'hello=world';\n      expect(await cookies.get('hello')).toBe(undefined);\n      await cookies.remove('world');\n    });\n\n    test('should handle double url encoded value for Ruby Rails', async () => {\n      const cookies = new CookieStorage();\n      const value = { a: 1 };\n      const cookieValue = encodeURIComponent(btoa(encodeURIComponent(JSON.stringify(value))));\n      document.cookie = `hello=${cookieValue}`;\n      expect(await cookies.get('hello')).toEqual(value);\n      await cookies.remove('world');\n    });\n\n    test('should return cookie object value', async () => {\n      const cookies = new CookieStorage<Record<string, number>>();\n      await cookies.set('hello', { a: 1 });\n      expect(await cookies.get('hello')).toEqual({ a: 1 });\n      await cookies.remove('hello');\n    });\n\n    test('should catch non-json format value', async () => {\n      const cookies = new CookieStorage();\n      const value = '{\"a\":1';\n      const encodedValue = btoa(encodeURIComponent(value));\n      document.cookie = `hello=${encodedValue}`;\n      expect(await cookies.get('hello')).toBe(undefined);\n    });\n\n    test('should return cookie array value', async () => {\n      const cookies = new CookieStorage<number[]>();\n      await cookies.set('hello', [1]);\n      expect(await cookies.get('hello')).toEqual([1]);\n      await cookies.remove('hello');\n    });\n\n    test('should return undefined when global scope is not defined', async () => {\n      const cookies = new CookieStorage<number[]>();\n      await cookies.set('hello', [1]);\n      jest.spyOn(GlobalScopeModule, 'getGlobalScope').mockReturnValueOnce(undefined);\n      expect(await cookies.get('hello')).toEqual(undefined);\n      await cookies.remove('hello');\n    });\n\n    test('should return undefined when global scope is defined but document is not', async () => {\n      const cookies = new CookieStorage<number[]>();\n      await cookies.set('hello', [1]);\n      jest.spyOn(GlobalScopeModule, 'getGlobalScope').mockReturnValueOnce({} as typeof globalThis);\n      expect(await cookies.get('hello')).toEqual(undefined);\n      await cookies.remove('hello');\n    });\n  });\n\n  describe('set', () => {\n    test('should set cookie value', async () => {\n      const cookies = new CookieStorage();\n      await cookies.set('hello', 'world');\n      expect(await cookies.get('hello')).toBe('world');\n      await cookies.remove('hello');\n    });\n\n    test('should set cookie value with options', async () => {\n      const cookies = new CookieStorage({\n        expirationDays: 365,\n        domain: '',\n        secure: false,\n        sameSite: 'Lax',\n      });\n      await cookies.set('hello', 'world');\n      expect(await cookies.get('hello')).toBe('world');\n      await cookies.remove('hello');\n    });\n\n    test('should set restricted cookie value with options', async () => {\n      const cookies = new CookieStorage({\n        expirationDays: 365,\n        domain: '.amplitude.com',\n        secure: true,\n        sameSite: 'Lax',\n      });\n      await cookies.set('hello', 'world');\n      expect(await cookies.get('hello')).toBe(undefined);\n      await cookies.remove('hello');\n    });\n\n    test.each([new Error('Simulated error'), 'Simulated error'])(\n      'logs an error message when setting a cookie fails',\n      async (error) => {\n        console.error = jest.fn();\n        jest.spyOn(global, 'btoa').mockImplementation(() => {\n          throw error;\n        });\n\n        const cookies = new CookieStorage();\n        await cookies.set('hello', 'world');\n\n        expect(console.error).toHaveBeenCalledWith(\n          expect.stringContaining(\n            `Amplitude Logger [Error]: Failed to set cookie for key: hello. Error: Simulated error`,\n          ),\n        );\n\n        jest.restoreAllMocks();\n      },\n    );\n  });\n\n  describe('remove', () => {\n    test('should call set', async () => {\n      const cookies = new CookieStorage();\n      const set = jest.spyOn(cookies, 'set');\n      await cookies.remove('key');\n      expect(set).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('reset', () => {\n    test('should return undefined', async () => {\n      const cookies = new CookieStorage();\n      expect(await cookies.reset()).toBe(undefined);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-client-common/test/transports/fetch.test.ts",
    "content": "import { FetchTransport } from '../../src/transports/fetch';\nimport { Status } from '@amplitude/analytics-types';\nimport 'isomorphic-fetch';\n\ndescribe('fetch', () => {\n  describe('send', () => {\n    test.each([\n      ['{}'], // ideally response body should be json format to an application/json request\n      [''], // test the edge case where response body is non-json format\n      ['<'],\n    ])('should resolve with response', async (body) => {\n      const transport = new FetchTransport();\n      const url = 'http://localhost:3000';\n      const payload = {\n        api_key: '',\n        events: [],\n      };\n      const result = {\n        statusCode: 200,\n        status: Status.Success as const,\n        body: {\n          eventsIngested: 0,\n          payloadSizeBytes: 0,\n          serverUploadTime: 0,\n        },\n      };\n      jest.spyOn(window, 'fetch').mockReturnValueOnce(Promise.resolve(new Response(body)));\n      jest.spyOn(transport, 'buildResponse').mockReturnValueOnce(result);\n      const response = await transport.send(url, payload);\n      expect(response).toEqual(result);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-client-common/tsconfig.es5.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/cjs\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/analytics-client-common/tsconfig.esm.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"es6\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/esm\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/analytics-client-common/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src/**/*\", \"test/**/*\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"esModuleInterop\": true,\n    \"lib\": [\"dom\"],\n    \"noEmit\": true,\n    \"rootDir\": \".\",\n  }\n}\n"
  },
  {
    "path": "packages/analytics-core/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.48.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.48.0...@amplitude/analytics-core@2.48.1) (2026-05-05)\n\n\n### Bug Fixes\n\n* **analytics-browser:** make autocapture opt-in within Chrome Extension ([#1710](https://github.com/amplitude/Amplitude-TypeScript/issues/1710)) ([de5ff6e](https://github.com/amplitude/Amplitude-TypeScript/commit/de5ff6e4fc9bfcf5d880fb291c796614ef86cc59))\n* **analytics-core:** close TOCTOU race in Timeline.register() ([#1702](https://github.com/amplitude/Amplitude-TypeScript/issues/1702)) ([3c399a5](https://github.com/amplitude/Amplitude-TypeScript/commit/3c399a5770097e657dafb7394023b4518076eca5))\n\n\n\n\n\n# [2.48.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.47.1...@amplitude/analytics-core@2.48.0) (2026-04-28)\n\n\n### Features\n\n* remove experimental request body compression backdoor ([#1699](https://github.com/amplitude/Amplitude-TypeScript/issues/1699)) ([98ecb9d](https://github.com/amplitude/Amplitude-TypeScript/commit/98ecb9dc1f3658cf6d0dfae1e9784335c9d33b5e))\n\n\n\n\n\n## [2.47.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.47.0...@amplitude/analytics-core@2.47.1) (2026-04-22)\n\n\n### Bug Fixes\n\n* **analytics-browser:** replace \"blocklist\" with \"excludelist\" in networkTracking ([#1692](https://github.com/amplitude/Amplitude-TypeScript/issues/1692)) ([f84374e](https://github.com/amplitude/Amplitude-TypeScript/commit/f84374eb0a4754e9fedfec0fbb9694531ba021e9))\n\n\n\n\n\n# [2.47.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.46.0...@amplitude/analytics-core@2.47.0) (2026-04-21)\n\n\n### Features\n\n* add long task tracking ([#1622](https://github.com/amplitude/Amplitude-TypeScript/issues/1622)) ([d995e1f](https://github.com/amplitude/Amplitude-TypeScript/commit/d995e1f2c098441808d65f6c171e171587e37ac2))\n\n\n\n\n\n# [2.46.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.45.0...@amplitude/analytics-core@2.46.0) (2026-04-14)\n\n\n### Features\n\n* **analytics-browser:** event property attribution ([#1628](https://github.com/amplitude/Amplitude-TypeScript/issues/1628)) ([6d37e79](https://github.com/amplitude/Amplitude-TypeScript/commit/6d37e797976e0e77dc11046b9259eb4b80259996))\n* **analytics-browser:** make \"attribution.excludeInternalReferrers\" GA ([#1660](https://github.com/amplitude/Amplitude-TypeScript/issues/1660)) ([72bcc33](https://github.com/amplitude/Amplitude-TypeScript/commit/72bcc335ad78c54512d26c0e359ae0c47611fd30))\n* **analytics-browser:** make errorClicks and thrashedCursor GA ([#1658](https://github.com/amplitude/Amplitude-TypeScript/issues/1658)) ([bfd0b9f](https://github.com/amplitude/Amplitude-TypeScript/commit/bfd0b9fbe9f0b7f954b20012ecc448afd3535be5))\n\n\n\n\n\n# [2.45.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.44.1...@amplitude/analytics-core@2.45.0) (2026-04-09)\n\n\n### Features\n\n* **analytics-browser:** [experimental] add video tracking function ([#1652](https://github.com/amplitude/Amplitude-TypeScript/issues/1652)) ([3af90e2](https://github.com/amplitude/Amplitude-TypeScript/commit/3af90e2f662d9ed82c56a506c8d2ef6d5da85bd8))\n\n\n\n\n\n## [2.44.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.44.0...@amplitude/analytics-core@2.44.1) (2026-04-01)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n\n\n\n\n# [2.44.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.43.1...@amplitude/analytics-core@2.44.0) (2026-03-26)\n\n\n### Features\n\n* **autocapture:** add viewportContentUpdated support to remote config ([#1621](https://github.com/amplitude/Amplitude-TypeScript/issues/1621)) ([f40b150](https://github.com/amplitude/Amplitude-TypeScript/commit/f40b150ddb44da9c69bc97da69f9ba003d1eb7d6))\n\n\n\n\n\n## [2.43.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.43.0...@amplitude/analytics-core@2.43.1) (2026-03-23)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n\n\n\n\n# [2.43.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.42.0...@amplitude/analytics-core@2.43.0) (2026-03-20)\n\n\n### Bug Fixes\n\n* **analytics-browser:** double thrashed cursor threshold ([#1604](https://github.com/amplitude/Amplitude-TypeScript/issues/1604)) ([32cb4b6](https://github.com/amplitude/Amplitude-TypeScript/commit/32cb4b63ddce39dc6b68d3ae3b3798b0ae73ccd4))\n* **analytics-core:** network request event circular dependency ([#1606](https://github.com/amplitude/Amplitude-TypeScript/issues/1606)) ([12ef222](https://github.com/amplitude/Amplitude-TypeScript/commit/12ef222ee990188f5700a8dd27d31cabd36f0ffc))\n\n\n### Features\n\n* **plugin-custom-enrichment:** add custom enrichment plugin ([#1339](https://github.com/amplitude/Amplitude-TypeScript/issues/1339)) ([b236190](https://github.com/amplitude/Amplitude-TypeScript/commit/b236190fa30d0e4325c37b8896824e11f980e20c))\n* **plugin-custom-enrichment:** add plugin based on remote config settings ([#1586](https://github.com/amplitude/Amplitude-TypeScript/issues/1586)) ([617ebfe](https://github.com/amplitude/Amplitude-TypeScript/commit/617ebfe7aaee04b0aef3db09b48ed11bad9a6ca3))\n\n\n\n\n\n# [2.42.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.41.7...@amplitude/analytics-core@2.42.0) (2026-03-19)\n\n\n### Bug Fixes\n\n* **analytics-core:** filter invalid event properties instead of rejecting whole object ([#1598](https://github.com/amplitude/Amplitude-TypeScript/issues/1598)) ([882db5c](https://github.com/amplitude/Amplitude-TypeScript/commit/882db5c6361c6279fd4b487b5ce681263e18d35f))\n* **analytics-core:** treat 403 as invalid API key in remote config client ([#1603](https://github.com/amplitude/Amplitude-TypeScript/issues/1603)) ([1c70064](https://github.com/amplitude/Amplitude-TypeScript/commit/1c70064e347219b5c8f6283d05c6e609580140e5))\n\n\n### Features\n\n* **autocapture:** zoning beta  ([#1589](https://github.com/amplitude/Amplitude-TypeScript/issues/1589)) ([2bb3608](https://github.com/amplitude/Amplitude-TypeScript/commit/2bb36088dc1342512ba0289fb1108ed8a61361f6))\n\n\n\n\n\n## [2.41.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.41.6...@amplitude/analytics-core@2.41.7) (2026-03-17)\n\n\n### Bug Fixes\n\n* **analytics-browser:** catch navigator.locks exceptions and fallback to no-locking ([#1600](https://github.com/amplitude/Amplitude-TypeScript/issues/1600)) ([8f58ef7](https://github.com/amplitude/Amplitude-TypeScript/commit/8f58ef753ceeae958eb0f22fa1430b7e30133308))\n\n\n\n\n\n## [2.41.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.41.5...@amplitude/analytics-core@2.41.6) (2026-03-16)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n\n\n\n\n## [2.41.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.41.4...@amplitude/analytics-core@2.41.5) (2026-03-13)\n\n\n### Bug Fixes\n\n* **analytics-core:** check document before writing cookie ([#1594](https://github.com/amplitude/Amplitude-TypeScript/issues/1594)) ([d88bd4e](https://github.com/amplitude/Amplitude-TypeScript/commit/d88bd4eca1f4b1dd19733c194f45f2317e7cb545))\n\n\n\n\n\n## [2.41.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.41.3...@amplitude/analytics-core@2.41.4) (2026-03-12)\n\n\n### Bug Fixes\n\n* **analytics-core:** remote config should not retry client side error except 429 ([#1590](https://github.com/amplitude/Amplitude-TypeScript/issues/1590)) ([b1445cb](https://github.com/amplitude/Amplitude-TypeScript/commit/b1445cb43272281ceb60da5055283fb42c494068))\n\n\n\n\n\n## [2.41.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.41.2...@amplitude/analytics-core@2.41.3) (2026-03-09)\n\n\n### Bug Fixes\n\n* **analytics-browser:** remove zen observable version with bad polyfill ([#1580](https://github.com/amplitude/Amplitude-TypeScript/issues/1580)) ([e07cbe4](https://github.com/amplitude/Amplitude-TypeScript/commit/e07cbe4eaccb261ce8db05d3fd6bd561e7e6da1b))\n* **analytics-browser:** Safari cookie writing race condition + extra exception catching ([#1578](https://github.com/amplitude/Amplitude-TypeScript/issues/1578)) ([bbcc6d7](https://github.com/amplitude/Amplitude-TypeScript/commit/bbcc6d77342a78388fce3fdf8b01d208e6403acf))\n\n\n\n\n\n## [2.41.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.41.1...@amplitude/analytics-core@2.41.2) (2026-03-05)\n\n\n### Bug Fixes\n\n* make getTopLevelDomain and isEnabled synchronous to avoid re-entrancy ([#1564](https://github.com/amplitude/Amplitude-TypeScript/issues/1564)) ([ab9b09f](https://github.com/amplitude/Amplitude-TypeScript/commit/ab9b09f9ec9b9583f92c7cdffb7194cc30e0ea9f))\n\n\n\n\n\n## [2.41.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.41.0...@amplitude/analytics-core@2.41.1) (2026-03-03)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n\n\n\n\n# [2.41.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.40.2...@amplitude/analytics-core@2.41.0) (2026-03-03)\n\n\n### Bug Fixes\n\n* **analytics-browser:** duplicate cookie resolution bugfix ([#1566](https://github.com/amplitude/Amplitude-TypeScript/issues/1566)) ([3fe77c6](https://github.com/amplitude/Amplitude-TypeScript/commit/3fe77c6034799afad8668373d296b367b2fd478c))\n\n\n### Features\n\n* **analytics-browser:** add config attribution.excludeInternalReferrers ([#1548](https://github.com/amplitude/Amplitude-TypeScript/issues/1548)) ([df16648](https://github.com/amplitude/Amplitude-TypeScript/commit/df1664856bea96afde1dbac8dc523b4d69925c2a))\n* **analytics-browser:** support gzip request body compression ([#1542](https://github.com/amplitude/Amplitude-TypeScript/issues/1542)) ([0d2a7d2](https://github.com/amplitude/Amplitude-TypeScript/commit/0d2a7d2d873c86d8854dad16109af461ad392166))\n* manual opt in gzip ([#1568](https://github.com/amplitude/Amplitude-TypeScript/issues/1568)) ([303c130](https://github.com/amplitude/Amplitude-TypeScript/commit/303c130429c51b0913f3903db4ace5263e1c78e7))\n\n\n\n\n\n## [2.40.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.40.1...@amplitude/analytics-core@2.40.2) (2026-02-26)\n\n\n### Bug Fixes\n\n* early return isEnabled false when document not present ([#1555](https://github.com/amplitude/Amplitude-TypeScript/issues/1555)) ([50c9a38](https://github.com/amplitude/Amplitude-TypeScript/commit/50c9a38580997b952e7cec6835139239d5de63a8))\n\n\n\n\n\n## [2.40.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.40.0...@amplitude/analytics-core@2.40.1) (2026-02-24)\n\n\n### Bug Fixes\n\n* import globalScope from named versus root ([#1554](https://github.com/amplitude/Amplitude-TypeScript/issues/1554)) ([b565551](https://github.com/amplitude/Amplitude-TypeScript/commit/b56555199782f070b0a8e5163add3ff36d5350ea))\n\n\n\n\n\n# [2.40.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.39.0...@amplitude/analytics-core@2.40.0) (2026-02-19)\n\n\n### Bug Fixes\n\n* **analytics-browser:** handle XHR open vs send race condition ([#1541](https://github.com/amplitude/Amplitude-TypeScript/issues/1541)) ([b952b81](https://github.com/amplitude/Amplitude-TypeScript/commit/b952b8145f8be436ccf1fe62d1275162c8a92f70))\n* **analytics-browser:** prevent circular reference in logBrowserOptions ([#1537](https://github.com/amplitude/Amplitude-TypeScript/issues/1537)) ([23b4fdb](https://github.com/amplitude/Amplitude-TypeScript/commit/23b4fdb106a242e4f64b81842f4227bcf771432b))\n* **analytics-core:** diagnostics supports multiple script urls ([#1538](https://github.com/amplitude/Amplitude-TypeScript/issues/1538)) ([8ae3b27](https://github.com/amplitude/Amplitude-TypeScript/commit/8ae3b27e9011a7fddcb63b6dd421d943f26873d8))\n\n\n### Features\n\n* screenshot capture messenger ([#1535](https://github.com/amplitude/Amplitude-TypeScript/issues/1535)) ([93ef551](https://github.com/amplitude/Amplitude-TypeScript/commit/93ef551ff0ab7dc48014aa5fa25841437d641993))\n\n\n\n\n\n# [2.39.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.38.0...@amplitude/analytics-core@2.39.0) (2026-02-17)\n\n\n### Bug Fixes\n\n* **analytics-browser:** cookie re-entrancy problem in isEnabled ([#1539](https://github.com/amplitude/Amplitude-TypeScript/issues/1539)) ([bb4b25e](https://github.com/amplitude/Amplitude-TypeScript/commit/bb4b25e03d05ca2b86e2bfb530b371c155ba70d1))\n\n\n### Features\n\n* **analytics-browser:** add setIdentity() ([#1517](https://github.com/amplitude/Amplitude-TypeScript/issues/1517)) ([314b3c1](https://github.com/amplitude/Amplitude-TypeScript/commit/314b3c1b7ee5b0ef135848a66156eb2874daec5f))\n\n\n\n\n\n# [2.38.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.37.0...@amplitude/analytics-core@2.38.0) (2026-02-10)\n\n\n### Bug Fixes\n\n* **analytics-browser:** defer session_start and attribution when optOut is \"true\" ([#1509](https://github.com/amplitude/Amplitude-TypeScript/issues/1509)) ([3a3818d](https://github.com/amplitude/Amplitude-TypeScript/commit/3a3818d19bd84e4aa8405e10f8538886dd647f38))\n* **analytics-core:** add ValidPropertyType type ([#1525](https://github.com/amplitude/Amplitude-TypeScript/issues/1525)) ([f63c657](https://github.com/amplitude/Amplitude-TypeScript/commit/f63c6570f95acab087ad47d9ce9442fe42765a2c))\n\n\n### Features\n\n* **analytics-browser:** [@experimental](https://github.com/experimental) add Thrashed Cursor frustration signal ([#1523](https://github.com/amplitude/Amplitude-TypeScript/issues/1523)) ([376b034](https://github.com/amplitude/Amplitude-TypeScript/commit/376b0342716057c82430ab72c0fc5bab55bc0dba))\n\n\n\n\n\n# [2.37.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.36.1...@amplitude/analytics-core@2.37.0) (2026-01-26)\n\n\n### Features\n\n* **analytics-browser:** add shouldTrackSubmit for custom form validation ([#1500](https://github.com/amplitude/Amplitude-TypeScript/issues/1500)) ([1d76745](https://github.com/amplitude/Amplitude-TypeScript/commit/1d76745dc202e27d188bfe47ae76d69806bbb566))\n\n\n\n\n\n## [2.36.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.36.0...@amplitude/analytics-core@2.36.1) (2026-01-21)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n\n\n\n\n# [2.36.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.35.2...@amplitude/analytics-core@2.36.0) (2026-01-15)\n\n\n### Features\n\n* **analytics-core:** add console observer helper ([#1478](https://github.com/amplitude/Amplitude-TypeScript/issues/1478)) ([f81ad91](https://github.com/amplitude/Amplitude-TypeScript/commit/f81ad91459cb0b69d1fdb2c4bcc463ac887dd44f))\n\n\n\n\n\n## [2.35.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.35.1...@amplitude/analytics-core@2.35.2) (2026-01-14)\n\n\n### Bug Fixes\n\n* **analytics-browser:** re-entrant error in cookies.isEnabled ([#1493](https://github.com/amplitude/Amplitude-TypeScript/issues/1493)) ([ed4f62c](https://github.com/amplitude/Amplitude-TypeScript/commit/ed4f62cb57a389deb1b67f3fdb310e30caf7e3e2))\n* **plugin-autocapture-browser:** allow selective configuration of frustration interactions ([#1489](https://github.com/amplitude/Amplitude-TypeScript/issues/1489)) ([5350f5b](https://github.com/amplitude/Amplitude-TypeScript/commit/5350f5b53d134b516f1e0e0cd202090015751ce0))\n\n\n\n\n\n## [2.35.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.35.0...@amplitude/analytics-core@2.35.1) (2026-01-14)\n\n\n### Bug Fixes\n\n* **analytics-browser:** two cookie problem resolution ([#1490](https://github.com/amplitude/Amplitude-TypeScript/issues/1490)) ([506638a](https://github.com/amplitude/Amplitude-TypeScript/commit/506638a2a412dc3843b0da9450325f70ff465422))\n\n\n\n\n\n# [2.35.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.34.1...@amplitude/analytics-core@2.35.0) (2025-12-24)\n\n\n### Features\n\n* **analytics-browser:** add support to set headers for transport pro… ([#1444](https://github.com/amplitude/Amplitude-TypeScript/issues/1444)) ([c277239](https://github.com/amplitude/Amplitude-TypeScript/commit/c277239d317106496f7a08fc2933e72e391be9de))\n\n\n\n\n\n## [2.34.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.34.0...@amplitude/analytics-core@2.34.1) (2025-12-16)\n\n\n### Bug Fixes\n\n* **plugin-page-url-enrichment-browser:** add internalDomains config for subdomain matching ([#1433](https://github.com/amplitude/Amplitude-TypeScript/issues/1433)) ([cf97ca3](https://github.com/amplitude/Amplitude-TypeScript/commit/cf97ca344e81666d4227aba67b0368d2213c9b34))\n\n\n\n\n\n# [2.34.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.33.0...@amplitude/analytics-core@2.34.0) (2025-12-09)\n\n\n### Features\n\n* diagnostics uncaught sdk errors installed by script  ([#1419](https://github.com/amplitude/Amplitude-TypeScript/issues/1419)) ([dc0b3cc](https://github.com/amplitude/Amplitude-TypeScript/commit/dc0b3cc9df5915d1bfb773b64099c70fc9408fda))\n\n\n\n\n\n# [2.33.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.32.2...@amplitude/analytics-core@2.33.0) (2025-11-21)\n\n\n### Features\n\n* **analytics-browser:** reduce bundle size via refactoring out rxjs ([#1391](https://github.com/amplitude/Amplitude-TypeScript/issues/1391)) ([09ade0b](https://github.com/amplitude/Amplitude-TypeScript/commit/09ade0b37cfdbaacb0e328cb812168d60dc25124))\n\n\n\n\n\n## [2.32.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.32.1...@amplitude/analytics-core@2.32.2) (2025-11-20)\n\n\n### Bug Fixes\n\n* **analytics-core:** record unsuccessful response from catch error ([#1411](https://github.com/amplitude/Amplitude-TypeScript/issues/1411)) ([c298d58](https://github.com/amplitude/Amplitude-TypeScript/commit/c298d58e3d32eb3bafe61d7d6efbcb9c775c363b))\n\n\n\n\n\n## [2.32.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.32.0...@amplitude/analytics-core@2.32.1) (2025-11-17)\n\n\n### Bug Fixes\n\n* **analytics-core:** record unsuccessful response ([#1405](https://github.com/amplitude/Amplitude-TypeScript/issues/1405)) ([7e842fe](https://github.com/amplitude/Amplitude-TypeScript/commit/7e842feb0aa36ec4274b97a205b19613f3b5c642))\n\n\n\n\n\n# [2.32.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.31.1...@amplitude/analytics-core@2.32.0) (2025-11-17)\n\n\n### Bug Fixes\n\n* **analytics-core:** batch remote config requests ([#1398](https://github.com/amplitude/Amplitude-TypeScript/issues/1398)) ([29da299](https://github.com/amplitude/Amplitude-TypeScript/commit/29da299e7c378a2c4221826f1b87e94aa6df3cb7))\n* **analytics-core:** remote config should not return null from cache for first time users ([#1401](https://github.com/amplitude/Amplitude-TypeScript/issues/1401)) ([568554a](https://github.com/amplitude/Amplitude-TypeScript/commit/568554a4849ff9069ae6948783458bc3c2997523))\n\n\n### Features\n\n* **analytics-browser:** add reset listener API ([#1393](https://github.com/amplitude/Amplitude-TypeScript/issues/1393)) ([7bd85e5](https://github.com/amplitude/Amplitude-TypeScript/commit/7bd85e51b01cefdb43b8474d930e8c219b739323))\n\n\n### Reverts\n\n* \"fix: make setDiagnosticsRate an optional function ([#1382](https://github.com/amplitude/Amplitude-TypeScript/issues/1382))\" ([#1394](https://github.com/amplitude/Amplitude-TypeScript/issues/1394)) ([f8ddc88](https://github.com/amplitude/Amplitude-TypeScript/commit/f8ddc88961e14a3ae7ad7e79ac7a182e84b158a0))\n\n\n\n\n\n## [2.31.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.31.0...@amplitude/analytics-core@2.31.1) (2025-11-05)\n\n\n### Bug Fixes\n\n* make setDiagnosticsRate an optional function ([#1382](https://github.com/amplitude/Amplitude-TypeScript/issues/1382)) ([8898186](https://github.com/amplitude/Amplitude-TypeScript/commit/889818637c41c6469a89b70553e8dcfc9725ab87))\n\n\n\n\n\n# [2.31.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.30.0...@amplitude/analytics-core@2.31.0) (2025-10-29)\n\n\n### Features\n\n* more diagnostics metrics ([#1371](https://github.com/amplitude/Amplitude-TypeScript/issues/1371)) ([40e255c](https://github.com/amplitude/Amplitude-TypeScript/commit/40e255c89c98f4ffffd883296d3d8a9947326aaa))\n\n\n\n\n\n# [2.30.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.29.0...@amplitude/analytics-core@2.30.0) (2025-10-23)\n\n\n### Features\n\n* **autocapture:** set page url enrichment plugin to default on and add/fix tests ([#1287](https://github.com/amplitude/Amplitude-TypeScript/issues/1287)) ([d96d7dd](https://github.com/amplitude/Amplitude-TypeScript/commit/d96d7dd7db156eae51a342b4956db2530ca64d29))\n\n\n\n\n\n# [2.29.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.28.0...@amplitude/analytics-core@2.29.0) (2025-10-23)\n\n\n### Features\n\n* **analytics-browser:** add remote config server url to proxy remote config requests ([#1348](https://github.com/amplitude/Amplitude-TypeScript/issues/1348)) ([461b598](https://github.com/amplitude/Amplitude-TypeScript/commit/461b59876a75af0d97fd639c35ce08f6b0f4c24b))\n\n\n\n\n\n# [2.28.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.27.2...@amplitude/analytics-core@2.28.0) (2025-10-17)\n\n\n### Features\n\n* make web-vitals autocapture GA ([#1347](https://github.com/amplitude/Amplitude-TypeScript/issues/1347)) ([178862f](https://github.com/amplitude/Amplitude-TypeScript/commit/178862f87e6ea8a882c1d612f48692ab1ab65e14))\n\n\n\n\n\n## [2.27.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.27.1...@amplitude/analytics-core@2.27.2) (2025-10-15)\n\n\n### Bug Fixes\n\n* **plugin-page-view-tracking-browser:** migrate to analytics-core ([#1341](https://github.com/amplitude/Amplitude-TypeScript/issues/1341)) ([676d347](https://github.com/amplitude/Amplitude-TypeScript/commit/676d347a04a6bd1ab5264ac8f58a358fd983ea54))\n\n\n\n\n\n## [2.27.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.27.0...@amplitude/analytics-core@2.27.1) (2025-10-14)\n\n\n### Bug Fixes\n\n* **analytics-core:** diagnostics client use temp sampling algo ([#1340](https://github.com/amplitude/Amplitude-TypeScript/issues/1340)) ([3e89dd7](https://github.com/amplitude/Amplitude-TypeScript/commit/3e89dd7a678cf7043d843949b0c7934e74f59d29))\n\n\n\n\n\n# [2.27.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.26.2...@amplitude/analytics-core@2.27.0) (2025-10-14)\n\n\n### Features\n\n* **autocapture:** refactor getPageTitle from autocapture to make it reusable ([#1331](https://github.com/amplitude/Amplitude-TypeScript/issues/1331)) ([44eabd1](https://github.com/amplitude/Amplitude-TypeScript/commit/44eabd1139252ed71845d29a86ceccd2ef119d15))\n* **plugin-network-capture-browser:** make networkTracking headers + body capturing GA ([#1334](https://github.com/amplitude/Amplitude-TypeScript/issues/1334)) ([8b57656](https://github.com/amplitude/Amplitude-TypeScript/commit/8b576569d28f323b21f6c82d708867d91c641063))\n\n\n\n\n\n## [2.26.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.26.1...@amplitude/analytics-core@2.26.2) (2025-10-03)\n\n\n### Bug Fixes\n\n* add diagnostics to client and track autocapture getHierachy block time ([#1312](https://github.com/amplitude/Amplitude-TypeScript/issues/1312)) ([a919e22](https://github.com/amplitude/Amplitude-TypeScript/commit/a919e223428083a87954cffa50bc765baa5360b0))\n\n\n\n\n\n## [2.26.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.26.0...@amplitude/analytics-core@2.26.1) (2025-10-01)\n\n\n### Bug Fixes\n\n* suppress relative url errors ([#1311](https://github.com/amplitude/Amplitude-TypeScript/issues/1311)) ([9f3b3b0](https://github.com/amplitude/Amplitude-TypeScript/commit/9f3b3b0ded160ef56e046a35d7f0eb747a2a4ef3))\n\n\n\n\n\n# [2.26.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.25.0...@amplitude/analytics-core@2.26.0) (2025-09-25)\n\n\n### Features\n\n* **analytics-browser:** add \"identify\" to config ([#1303](https://github.com/amplitude/Amplitude-TypeScript/issues/1303)) ([693720c](https://github.com/amplitude/Amplitude-TypeScript/commit/693720c348eaac0ffef8b88454deae06ceca0bb4))\n\n\n\n\n\n# [2.25.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.24.1...@amplitude/analytics-core@2.25.0) (2025-09-23)\n\n\n### Bug Fixes\n\n* **analytics-core:** add events support for diagnostics client ([#1301](https://github.com/amplitude/Amplitude-TypeScript/issues/1301)) ([9671929](https://github.com/amplitude/Amplitude-TypeScript/commit/9671929b6cfa63621e6e8ca6f2575d057990775e))\n\n\n### Features\n\n* **analytics-core:** add diagnostics client ([#1281](https://github.com/amplitude/Amplitude-TypeScript/issues/1281)) ([c511002](https://github.com/amplitude/Amplitude-TypeScript/commit/c5110024832f09d3f69d25077c4c5b825e538e6c))\n\n\n\n\n\n## [2.24.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.24.0...@amplitude/analytics-core@2.24.1) (2025-09-18)\n\n\n### Bug Fixes\n\n* **analytics-browser:** add URI decoding to Element Clicked event attribute ([#1297](https://github.com/amplitude/Amplitude-TypeScript/issues/1297)) ([ebb2120](https://github.com/amplitude/Amplitude-TypeScript/commit/ebb212080948e8acbaeadbdc410580e04202f818))\n\n\n\n\n\n# [2.24.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.23.0...@amplitude/analytics-core@2.24.0) (2025-09-12)\n\n\n### Features\n\n* **analytics-browser:** make frustrationInteractions GA ([#1286](https://github.com/amplitude/Amplitude-TypeScript/issues/1286)) ([40d62be](https://github.com/amplitude/Amplitude-TypeScript/commit/40d62be5e1713a3756464f83bd15d25fe1294956))\n\n\n\n\n\n# [2.23.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.22.1...@amplitude/analytics-core@2.23.0) (2025-09-05)\n\n\n### Bug Fixes\n\n* **analytics-core:** strip out basic auth from url ([#1279](https://github.com/amplitude/Amplitude-TypeScript/issues/1279)) ([d9ee8af](https://github.com/amplitude/Amplitude-TypeScript/commit/d9ee8afc34537cf96c05e98bebfad94b3bc426ad))\n\n\n### Features\n\n* **autocapture:** include pageUrlExcludelist ([#1264](https://github.com/amplitude/Amplitude-TypeScript/issues/1264)) ([dd2aa7f](https://github.com/amplitude/Amplitude-TypeScript/commit/dd2aa7fbb476ead45831f2dc39a94db224131699))\n\n\n\n\n\n## [2.22.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.22.0...@amplitude/analytics-core@2.22.1) (2025-08-28)\n\n\n### Bug Fixes\n\n* **analytics-core:** handle XHR responseType JSON ([#1276](https://github.com/amplitude/Amplitude-TypeScript/issues/1276)) ([cd35193](https://github.com/amplitude/Amplitude-TypeScript/commit/cd35193ba51cdb986b3a4b8a50989067e3f8bf5b))\n\n\n\n\n\n# [2.22.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.21.2...@amplitude/analytics-core@2.22.0) (2025-08-26)\n\n\n### Bug Fixes\n\n* **plugin-network-autocapture:** replace consumption check with cache ([#1274](https://github.com/amplitude/Amplitude-TypeScript/issues/1274)) ([9c41081](https://github.com/amplitude/Amplitude-TypeScript/commit/9c41081ce23aea51ff9c9a82f0b8b9e5e3c53061))\n\n\n### Features\n\n* **autocapture:** add maskTextRegex option to autocapture ([#1259](https://github.com/amplitude/Amplitude-TypeScript/issues/1259)) ([2f1cf07](https://github.com/amplitude/Amplitude-TypeScript/commit/2f1cf075b3e0728f4124bb5c30c8a7e7c21d5a12))\n\n\n\n\n\n## [2.21.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.21.1...@amplitude/analytics-core@2.21.2) (2025-08-25)\n\n\n### Bug Fixes\n\n* **plugin-autocapture-browser:** make rage click less noisy ([#1265](https://github.com/amplitude/Amplitude-TypeScript/issues/1265)) ([a31acd3](https://github.com/amplitude/Amplitude-TypeScript/commit/a31acd34f2389d12427daba776ce22a262db7874))\n\n\n\n\n\n## [2.21.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.21.0...@amplitude/analytics-core@2.21.1) (2025-08-22)\n\n\n### Bug Fixes\n\n* **analytics-core:** fix typo in Reddit click-id ([#1267](https://github.com/amplitude/Amplitude-TypeScript/issues/1267)) ([43e581d](https://github.com/amplitude/Amplitude-TypeScript/commit/43e581d6465546a38373f758f179eee103172755))\n\n\n\n\n\n# [2.21.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.20.2...@amplitude/analytics-core@2.21.0) (2025-08-21)\n\n\n### Features\n\n* **analytics-browser:** add urls matching attribute to network capture rules (experimental) ([#1252](https://github.com/amplitude/Amplitude-TypeScript/issues/1252)) ([c28a98c](https://github.com/amplitude/Amplitude-TypeScript/commit/c28a98c13536d3eb2472edcce6ec225539db00aa))\n* **plugin-network-capture-browser:** add ability to capture headers (experimental) ([#1253](https://github.com/amplitude/Amplitude-TypeScript/issues/1253)) ([52cfc0c](https://github.com/amplitude/Amplitude-TypeScript/commit/52cfc0c6dab309f30cfce56c091065ff95d95fc2))\n* **plugin-network-capture-browser:** add request + response body capture (experimental) ([#1256](https://github.com/amplitude/Amplitude-TypeScript/issues/1256)) ([1850c58](https://github.com/amplitude/Amplitude-TypeScript/commit/1850c58d145973b3bd104ab70368eb4e2fdbafbc))\n\n\n\n\n\n## [2.20.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.20.1...@amplitude/analytics-core@2.20.2) (2025-08-13)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n\n\n\n\n## [2.20.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.20.0...@amplitude/analytics-core@2.20.1) (2025-08-08)\n\n\n### Bug Fixes\n\n* **analytics-core:** should abort remote config request ([#1234](https://github.com/amplitude/Amplitude-TypeScript/issues/1234)) ([394f18b](https://github.com/amplitude/Amplitude-TypeScript/commit/394f18b52c383f30fbed85cb0dcf4fa80df527b5))\n\n\n\n\n\n# [2.20.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.19.0...@amplitude/analytics-core@2.20.0) (2025-08-05)\n\n\n### Bug Fixes\n\n* **analtyics-browser): Revert \"feat(analytics-browser:** add page-url-previous-page plugin\" ([#1237](https://github.com/amplitude/Amplitude-TypeScript/issues/1237)) ([dfd7340](https://github.com/amplitude/Amplitude-TypeScript/commit/dfd7340f6519e647a814b3c66913b0c96b0567cf))\n* **analytics-browser:** use the new remote config client ([#1191](https://github.com/amplitude/Amplitude-TypeScript/issues/1191)) ([9af61ea](https://github.com/amplitude/Amplitude-TypeScript/commit/9af61ea1f29fa97644910f37440562e5a6d5eeba))\n* **plugin-autocapture-browser:** remove unused configurations from FrustrationInteractions ([#1229](https://github.com/amplitude/Amplitude-TypeScript/issues/1229)) ([d7af23b](https://github.com/amplitude/Amplitude-TypeScript/commit/d7af23b4b02d475475c3249d67ee6e24c49136af))\n\n\n### Features\n\n* **analytics-browser:** add page-url-previous-page plugin ([#1110](https://github.com/amplitude/Amplitude-TypeScript/issues/1110)) ([dc053ed](https://github.com/amplitude/Amplitude-TypeScript/commit/dc053ed9f0b6378fce6a49f6a6e4196f3622bd25))\n* **plugin-page-url-enrichment-browser:** AMP-130401 create Page URL Enrichment plugin for additional Page URL related properties ([#1238](https://github.com/amplitude/Amplitude-TypeScript/issues/1238)) ([4673be8](https://github.com/amplitude/Amplitude-TypeScript/commit/4673be86ab5535fdca66d1743ef4ee071d5fdef7))\n\n\n\n\n\n# [2.19.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.18.0...@amplitude/analytics-core@2.19.0) (2025-07-29)\n\n\n### Bug Fixes\n\n* **analytics-react-native:** migrate to analytics-core v2 ([#1216](https://github.com/amplitude/Amplitude-TypeScript/issues/1216)) ([76e85a1](https://github.com/amplitude/Amplitude-TypeScript/commit/76e85a1daa704a1c4c44d0176a56c8dd8d4ad3f1))\n\n\n### Features\n\n* **analytics-core:** expose unified AmplitudeContext and AnalyticsClient ([#1222](https://github.com/amplitude/Amplitude-TypeScript/issues/1222)) ([7e32712](https://github.com/amplitude/Amplitude-TypeScript/commit/7e327128b4032592897dc6bb50dedda053ad8eda))\n* **autocapture:** fetch page actions from remote config ([#1168](https://github.com/amplitude/Amplitude-TypeScript/issues/1168)) ([da213cc](https://github.com/amplitude/Amplitude-TypeScript/commit/da213cc33c4986bcebff2b4264b2c17314f5f310))\n\n\n\n\n\n# [2.18.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.17.0...@amplitude/analytics-core@2.18.0) (2025-07-17)\n\n\n### Features\n\n* **analytics-browser:** support autocapture.webVitals ([#1195](https://github.com/amplitude/Amplitude-TypeScript/issues/1195)) ([a186f52](https://github.com/amplitude/Amplitude-TypeScript/commit/a186f523a28d8a322842566b892f50bcf2643142))\n\n\n\n\n\n# [2.17.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.16.0...@amplitude/analytics-core@2.17.0) (2025-07-15)\n\n\n### Bug Fixes\n\n* **analytics-browser:** prevent infinite Amplitude network requests ([#1100](https://github.com/amplitude/Amplitude-TypeScript/issues/1100)) ([fde763c](https://github.com/amplitude/Amplitude-TypeScript/commit/fde763cd4889bda41edc55789ee18186711d825e))\n\n\n### Features\n\n* **analytics-browser:** add experimental frustrationInteractions ([#1209](https://github.com/amplitude/Amplitude-TypeScript/issues/1209)) ([e321744](https://github.com/amplitude/Amplitude-TypeScript/commit/e3217444c58be15e779ff1fd54a55027c93f5db0))\n* **analytics-node:** migrate to v2.x core  ([#1207](https://github.com/amplitude/Amplitude-TypeScript/issues/1207)) ([e1c1b28](https://github.com/amplitude/Amplitude-TypeScript/commit/e1c1b28ed2036f7ebb68173f8da2e6cbb82cb287))\n\n\n\n\n\n# [2.16.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.15.0...@amplitude/analytics-core@2.16.0) (2025-07-08)\n\n\n### Bug Fixes\n\n* **analytics-core:** more logs in timeline ([#1180](https://github.com/amplitude/Amplitude-TypeScript/issues/1180)) ([dcb6cee](https://github.com/amplitude/Amplitude-TypeScript/commit/dcb6ceee00e3587b8eaf601074940696c94a4466))\n* **analytics-core:** remote config use new schema & config group ([#1185](https://github.com/amplitude/Amplitude-TypeScript/issues/1185)) ([db54ae5](https://github.com/amplitude/Amplitude-TypeScript/commit/db54ae5ce87d5d7a4ae49c80aab5037dee3dd03c))\n\n\n### Features\n\n* **analytics-browser:** change definition of rage click ([#1183](https://github.com/amplitude/Amplitude-TypeScript/issues/1183)) ([108f930](https://github.com/amplitude/Amplitude-TypeScript/commit/108f930114629fdb3d600532a2c6b8b4f6cafd01))\n\n\n\n\n\n# [2.15.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.14.0...@amplitude/analytics-core@2.15.0) (2025-06-30)\n\n\n### Features\n\n* add getOptOut() and getIdentity() ([#1174](https://github.com/amplitude/Amplitude-TypeScript/issues/1174)) ([72017c8](https://github.com/amplitude/Amplitude-TypeScript/commit/72017c8a1a54d929542e883e61d61168f214a780))\n\n\n\n\n\n# [2.14.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.13.0...@amplitude/analytics-core@2.14.0) (2025-06-26)\n\n\n### Features\n\n* **plugin-autocapture-browser:** add rage+dead clicks to autocapture plugin ([#1146](https://github.com/amplitude/Amplitude-TypeScript/issues/1146)) ([c850f02](https://github.com/amplitude/Amplitude-TypeScript/commit/c850f020a6b56bbd8d64e0f946acaf0eac15ccf7))\n\n\n\n\n\n# [2.13.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.12.3...@amplitude/analytics-core@2.13.0) (2025-06-25)\n\n\n### Features\n\n* **autocapture:** Added config to capture event properties ([#1111](https://github.com/amplitude/Amplitude-TypeScript/issues/1111)) ([109c3e2](https://github.com/amplitude/Amplitude-TypeScript/commit/109c3e220293fff92f870f8efe1a6cb4a20bebf4))\n\n\n\n\n\n## [2.12.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.12.2...@amplitude/analytics-core@2.12.3) (2025-06-11)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n\n\n\n\n## [2.12.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.12.1...@amplitude/analytics-core@2.12.2) (2025-06-03)\n\n\n### Bug Fixes\n\n* **analytics-core:** bump version ([#1123](https://github.com/amplitude/Amplitude-TypeScript/issues/1123)) ([65ab775](https://github.com/amplitude/Amplitude-TypeScript/commit/65ab77559dc0a61895043eb10c08922ad4f19690))\n\n\n\n\n\n## [2.12.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.12.0...@amplitude/analytics-core@2.12.1) (2025-05-27)\n\n\n### Bug Fixes\n\n* **analytics-browser:** support autocapture.networkTracking as object ([#1095](https://github.com/amplitude/Amplitude-TypeScript/issues/1095)) ([121abc7](https://github.com/amplitude/Amplitude-TypeScript/commit/121abc7e69a354cc704de7cbe493b8c79fa6eacd))\n* **analytics-browser:** support XHR in network capture ([#1089](https://github.com/amplitude/Amplitude-TypeScript/issues/1089)) ([339d49c](https://github.com/amplitude/Amplitude-TypeScript/commit/339d49cfa7b07ffc20fe085b8548f6489a3029f3))\n\n\n\n\n\n# [2.12.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.11.2...@amplitude/analytics-core@2.12.0) (2025-05-13)\n\n\n### Bug Fixes\n\n* **analytics-core:** make network observer event callbacks handle exceptions ([#1071](https://github.com/amplitude/Amplitude-TypeScript/issues/1071)) ([baf46e2](https://github.com/amplitude/Amplitude-TypeScript/commit/baf46e22585f58924b801e301db78c7aecda1b4a))\n\n\n### Features\n\n* **analytics-core:** add plugins to look up plugin by class type ([#1079](https://github.com/amplitude/Amplitude-TypeScript/issues/1079)) ([14c73b9](https://github.com/amplitude/Amplitude-TypeScript/commit/14c73b9bffcf621b44f66febc2801582e26b7cae))\n\n\n\n\n\n## [2.11.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.11.1...@amplitude/analytics-core@2.11.2) (2025-05-05)\n\n\n### Bug Fixes\n\n* **analytics-browser:** use performance.now in network capture ([#1060](https://github.com/amplitude/Amplitude-TypeScript/issues/1060)) ([70917e2](https://github.com/amplitude/Amplitude-TypeScript/commit/70917e26369d27adf62e6b9a44a39599a312b3ef))\n\n\n\n\n\n## [2.11.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.11.0...@amplitude/analytics-core@2.11.1) (2025-05-02)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n\n\n\n\n# [2.11.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.10.1...@amplitude/analytics-core@2.11.0) (2025-05-02)\n\n\n### Features\n\n* **analytics-browser:** autocapture network errors ([#1050](https://github.com/amplitude/Amplitude-TypeScript/issues/1050)) ([104350f](https://github.com/amplitude/Amplitude-TypeScript/commit/104350ffe8b1bd1a7090482ac3bf24d85672bd43))\n\n\n\n\n\n## [2.10.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.10.0...@amplitude/analytics-core@2.10.1) (2025-04-22)\n\n\n### Bug Fixes\n\n* **analytics-core:** add missing analytics-connector dependency ([#1031](https://github.com/amplitude/Amplitude-TypeScript/issues/1031)) ([820a761](https://github.com/amplitude/Amplitude-TypeScript/commit/820a7614cba3ce58c5e42cdf0f61880619196750))\n\n\n\n\n\n# [2.10.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.9.0...@amplitude/analytics-core@2.10.0) (2025-04-17)\n\n\n### Bug Fixes\n\n* **analytics-core:** add support for experiment plugin ([#1033](https://github.com/amplitude/Amplitude-TypeScript/issues/1033)) ([69a20c7](https://github.com/amplitude/Amplitude-TypeScript/commit/69a20c7a895eb4bb4668583ea3371d0ca2df18d2))\n\n\n### Features\n\n* **analytics-core:** new plugin interfaces onXXXchanged() ([#1025](https://github.com/amplitude/Amplitude-TypeScript/issues/1025)) ([e6fd23b](https://github.com/amplitude/Amplitude-TypeScript/commit/e6fd23b17809d0c7d94e7627636b200166d41a0f))\n\n\n\n\n\n# [2.9.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.8.1...@amplitude/analytics-core@2.9.0) (2025-04-15)\n\n\n### Features\n\n* **session-replay-browser:** migrate to core v2.x ([#1022](https://github.com/amplitude/Amplitude-TypeScript/issues/1022)) ([7a665d5](https://github.com/amplitude/Amplitude-TypeScript/commit/7a665d55fff89092ed5f2bb94caa1eb2c7efe5b1))\n\n\n\n\n\n## [2.8.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.8.0...@amplitude/analytics-core@2.8.1) (2025-04-10)\n\n\n### Bug Fixes\n\n* **uuid:** set UUID's using crypto libraries instead of Math.random ([#852](https://github.com/amplitude/Amplitude-TypeScript/issues/852)) ([54b86bb](https://github.com/amplitude/Amplitude-TypeScript/commit/54b86bba518261e365a0b3ff49cb44521531491c))\n\n\n\n\n\n# [2.8.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.7.0...@amplitude/analytics-core@2.8.0) (2025-04-07)\n\n\n### Features\n\n* **analytics-core:** remote config client ([#997](https://github.com/amplitude/Amplitude-TypeScript/issues/997)) ([9a25350](https://github.com/amplitude/Amplitude-TypeScript/commit/9a25350802fc6326501bd31a201534d2f906985b))\n\n\n\n\n\n# [2.7.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.6.1...@amplitude/analytics-core@2.7.0) (2025-04-02)\n\n\n### Bug Fixes\n\n* **analytics-browser:** export more types ([#1011](https://github.com/amplitude/Amplitude-TypeScript/issues/1011)) ([561afc2](https://github.com/amplitude/Amplitude-TypeScript/commit/561afc2538da25867db02646829b2eb81693abcd))\n\n\n### Features\n\n* **analytics-browser:** set default for fetchRemoteConfig option to true ([#1008](https://github.com/amplitude/Amplitude-TypeScript/issues/1008)) ([5138cd1](https://github.com/amplitude/Amplitude-TypeScript/commit/5138cd16be1ff3bb57c38ec0eae5098a1b7933fc))\n\n\n\n\n\n## [2.6.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.6.0...@amplitude/analytics-core@2.6.1) (2025-03-21)\n\n\n### Bug Fixes\n\n* **analytics-browser:** replace analytics-types with analytics-core ([#993](https://github.com/amplitude/Amplitude-TypeScript/issues/993)) ([f180f05](https://github.com/amplitude/Amplitude-TypeScript/commit/f180f05854393bf18d94f1753d284778ba3b5377))\n\n\n\n\n\n# [2.6.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.5.6...@amplitude/analytics-core@2.6.0) (2025-03-14)\n\n\n### Features\n\n* **analytics-core:** add support for revenue receipt and receipt sig ([#991](https://github.com/amplitude/Amplitude-TypeScript/issues/991)) ([e736a65](https://github.com/amplitude/Amplitude-TypeScript/commit/e736a65e35f0462a6b6080e66a27ffaec9a512b5))\n* **analytics-core:** merge analytics-client-common  ([#977](https://github.com/amplitude/Amplitude-TypeScript/issues/977)) ([1746ae5](https://github.com/amplitude/Amplitude-TypeScript/commit/1746ae5efb1ecd0e7586bc22ff8a704a6928c26a))\n* **analytics-core:** merge analytics-types ([#989](https://github.com/amplitude/Amplitude-TypeScript/issues/989)) ([9f7ed68](https://github.com/amplitude/Amplitude-TypeScript/commit/9f7ed68e8ec468f5c597ce427c70ffd855dde629))\n\n\n\n\n\n## [2.5.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.5.5...@amplitude/analytics-core@2.5.6) (2025-02-28)\n\n\n### Bug Fixes\n\n* ability to send revenue currency to amplitude ([d4f52e7](https://github.com/amplitude/Amplitude-TypeScript/commit/d4f52e74e9840a3361784dfc37ef21125375d02e))\n* adding tests ([ba9688a](https://github.com/amplitude/Amplitude-TypeScript/commit/ba9688a31377a3e7903e9689970a99878e635569))\n* **analytics-core:** should not flush until previous request resolves ([#964](https://github.com/amplitude/Amplitude-TypeScript/issues/964)) ([771ce55](https://github.com/amplitude/Amplitude-TypeScript/commit/771ce556cb131b71ddb28461268a6feb5f3a1b1d))\n\n\n### Reverts\n\n* Revert \"chore(release): publish\" ([d392f62](https://github.com/amplitude/Amplitude-TypeScript/commit/d392f6290b8bb4dd955d6e6f20b00191679489c4))\n\n\n\n\n\n## [2.5.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.5.4...@amplitude/analytics-core@2.5.5) (2024-12-17)\n\n\n### Bug Fixes\n\n* amplitude.remove should only remove if plugin was already registered ([ad84bf6](https://github.com/amplitude/Amplitude-TypeScript/commit/ad84bf62a8b113a3d59de1b16a052b72ffe14c22))\n* **analytics-browser:** should send batches sequentially ([#935](https://github.com/amplitude/Amplitude-TypeScript/issues/935)) ([ad319d6](https://github.com/amplitude/Amplitude-TypeScript/commit/ad319d602d167b1db7ee3c8d07beb4c00be8c080))\n\n\n\n\n\n## [2.5.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.5.3...@amplitude/analytics-core@2.5.4) (2024-11-05)\n\n\n### Bug Fixes\n\n* **analytics-types:** allow an array of objects as identity value type ([#914](https://github.com/amplitude/Amplitude-TypeScript/issues/914)) ([a6ddf9f](https://github.com/amplitude/Amplitude-TypeScript/commit/a6ddf9f369fb0240f7fe9ca7040ef36a48a65d41))\n\n\n\n\n\n## [2.5.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.5.2...@amplitude/analytics-core@2.5.3) (2024-10-21)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n\n\n\n\n## [2.5.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.5.1...@amplitude/analytics-core@2.5.2) (2024-09-17)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n\n\n\n\n## [2.5.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.5.0...@amplitude/analytics-core@2.5.1) (2024-09-10)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n\n\n\n\n# [2.5.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.4.0...@amplitude/analytics-core@2.5.0) (2024-08-13)\n\n\n### Features\n\n* support remote config for each autocapture field ([#848](https://github.com/amplitude/Amplitude-TypeScript/issues/848)) ([939d49f](https://github.com/amplitude/Amplitude-TypeScript/commit/939d49f488bda8bbe4fa57cd2a2ab23f75540fc5))\n\n\n\n\n\n# [2.4.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.3.0...@amplitude/analytics-core@2.4.0) (2024-08-02)\n\n\n### Features\n\n* remote config ([#832](https://github.com/amplitude/Amplitude-TypeScript/issues/832)) ([c415f79](https://github.com/amplitude/Amplitude-TypeScript/commit/c415f792a98253ac60885eb1dc7e53b78ca47dcb)), closes [#769](https://github.com/amplitude/Amplitude-TypeScript/issues/769) [#772](https://github.com/amplitude/Amplitude-TypeScript/issues/772) [#780](https://github.com/amplitude/Amplitude-TypeScript/issues/780) [#782](https://github.com/amplitude/Amplitude-TypeScript/issues/782) [#811](https://github.com/amplitude/Amplitude-TypeScript/issues/811) [#828](https://github.com/amplitude/Amplitude-TypeScript/issues/828)\n\n\n\n\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.3.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.2.8...@amplitude/analytics-core@2.3.0) (2024-06-17)\n\n### Features\n\n- **analytics-browser:** consume remote config ([#769](https://github.com/amplitude/Amplitude-TypeScript/issues/769))\n  ([9c4e03c](https://github.com/amplitude/Amplitude-TypeScript/commit/9c4e03c3b3989213ac04410c8b9bf5e78ed393cf))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.2.7...@amplitude/analytics-core@2.2.8) (2024-05-21)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.2.6...@amplitude/analytics-core@2.2.7) (2024-05-15)\n\n### Bug Fixes\n\n- **core:** api calls should queue while awaiting queued promises\n  ([60fe272](https://github.com/amplitude/Amplitude-TypeScript/commit/60fe272d7bc4ea20944dbf444f73fa14e4785030))\n- **core:** flush queue if more functions are added while awaiting promises in queue\n  ([1b7ce6d](https://github.com/amplitude/Amplitude-TypeScript/commit/1b7ce6dd36c98ac4a0d49241284d763cf56960cb))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.2.5...@amplitude/analytics-core@2.2.6) (2024-05-03)\n\n### Bug Fixes\n\n- **core:** correctly await promises called before init\n  ([b329e05](https://github.com/amplitude/Amplitude-TypeScript/commit/b329e057023d266abb6b1145ea45e3c3471335fc))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.2.4...@amplitude/analytics-core@2.2.5) (2024-04-29)\n\n### Bug Fixes\n\n- error when sending data to Amplitude should get retried\n  ([fb29785](https://github.com/amplitude/Amplitude-TypeScript/commit/fb297852288a9cd158b6171e79697e990f375a49))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.2.4-beta.0...@amplitude/analytics-core@2.2.4) (2024-04-09)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.4-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.2.3...@amplitude/analytics-core@2.2.4-beta.0) (2024-03-28)\n\n### Bug Fixes\n\n- fix event drop issue ([#689](https://github.com/amplitude/Amplitude-TypeScript/issues/689))\n  ([43a0ca3](https://github.com/amplitude/Amplitude-TypeScript/commit/43a0ca3e1797bdb8a74938c6a0f65d6dec1e5b89))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.2.2...@amplitude/analytics-core@2.2.3) (2024-03-23)\n\n### Bug Fixes\n\n- stop accumulating bad events\n  ([9fc9550](https://github.com/amplitude/Amplitude-TypeScript/commit/9fc9550c20c5693bc0322bf376cd7958d1a2154e))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.2.1...@amplitude/analytics-core@2.2.2) (2024-03-12)\n\n### Bug Fixes\n\n- fix event flush process ([#673](https://github.com/amplitude/Amplitude-TypeScript/issues/673))\n  ([043987f](https://github.com/amplitude/Amplitude-TypeScript/commit/043987f1382172fa5b700220b0b39f0e655514e4))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.2.0...@amplitude/analytics-core@2.2.1) (2024-02-23)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.2.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.1.3...@amplitude/analytics-core@2.2.0) (2024-01-24)\n\n### Features\n\n- add offline mode ([#644](https://github.com/amplitude/Amplitude-TypeScript/issues/644))\n  ([f2cd717](https://github.com/amplitude/Amplitude-TypeScript/commit/f2cd717316eef66b101153cb8eedf37fadc6de0c))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.1.2...@amplitude/analytics-core@2.1.3) (2023-12-20)\n\n### Reverts\n\n- update attribution plugin to apply utm params to the `session_start` event\n  ([#638](https://github.com/amplitude/Amplitude-TypeScript/issues/638))\n  ([c820279](https://github.com/amplitude/Amplitude-TypeScript/commit/c820279cbef2123d890beb7861d7edbbc3926f6e))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.1.2-beta.0...@amplitude/analytics-core@2.1.2) (2023-12-01)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.2-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.1.1...@amplitude/analytics-core@2.1.2-beta.0) (2023-11-22)\n\n### Bug Fixes\n\n- update attribution plugin to apply utm params to the `session_start` event\n  ([#619](https://github.com/amplitude/Amplitude-TypeScript/issues/619))\n  ([bf45ca6](https://github.com/amplitude/Amplitude-TypeScript/commit/bf45ca6c17ac8d656cb6c5bb4f4fa19ff344ac85))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.1.0...@amplitude/analytics-core@2.1.1) (2023-11-16)\n\n### Bug Fixes\n\n- npm latest tags ([#624](https://github.com/amplitude/Amplitude-TypeScript/issues/624))\n  ([76bf7a4](https://github.com/amplitude/Amplitude-TypeScript/commit/76bf7a4c871375649fac45d549b711ac52c16b0d))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.1.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.0.5...@amplitude/analytics-core@2.1.0) (2023-10-18)\n\n### Features\n\n- add client upload time ([#601](https://github.com/amplitude/Amplitude-TypeScript/issues/601))\n  ([b80d090](https://github.com/amplitude/Amplitude-TypeScript/commit/b80d090c5a70f75b4d3cb653efa1af48ff2fcd34))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.0.4...@amplitude/analytics-core@2.0.5) (2023-09-18)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.0.3...@amplitude/analytics-core@2.0.4) (2023-08-24)\n\n### Bug Fixes\n\n- apply 'core' changes fom 1.x/migrate-legacy-data\n  ([#531](https://github.com/amplitude/Amplitude-TypeScript/issues/531))\n  ([502a080](https://github.com/amplitude/Amplitude-TypeScript/commit/502a080b6eca2bc390b5d8076f24b9137d213f89))\n- **core:** allow no destination plugins on instance\n  ([2c72800](https://github.com/amplitude/Amplitude-TypeScript/commit/2c728009c79116aa4fc038cd266fba830a6ca0b6))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.0.2...@amplitude/analytics-core@2.0.3) (2023-06-30)\n\n### Bug Fixes\n\n- allow plugins to teardown to remove listeners ([#460](https://github.com/amplitude/Amplitude-TypeScript/issues/460))\n  ([c337363](https://github.com/amplitude/Amplitude-TypeScript/commit/c337363c25b0a1285e8df455511516fc0a9bec7e))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.0.1...@amplitude/analytics-core@2.0.2) (2023-06-22)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.0.0...@amplitude/analytics-core@2.0.1) (2023-06-21)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.0.0-beta.8...@amplitude/analytics-core@2.0.0) (2023-06-14)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.0.0-beta.7...@amplitude/analytics-core@2.0.0-beta.8) (2023-06-14)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.0.0-beta.6...@amplitude/analytics-core@2.0.0-beta.7) (2023-06-14)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.0.0-beta.5...@amplitude/analytics-core@2.0.0-beta.6) (2023-06-13)\n\n### Features\n\n- add option for instance name ([#428](https://github.com/amplitude/Amplitude-TypeScript/issues/428))\n  ([1a8ff7d](https://github.com/amplitude/Amplitude-TypeScript/commit/1a8ff7d665d2a936db7cb42f4cde5350379b7cae))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.0.0-beta.4...@amplitude/analytics-core@2.0.0-beta.5) (2023-06-13)\n\n### Features\n\n- log response body from API to logger ([#415](https://github.com/amplitude/Amplitude-TypeScript/issues/415))\n  ([#422](https://github.com/amplitude/Amplitude-TypeScript/issues/422))\n  ([d14b5c0](https://github.com/amplitude/Amplitude-TypeScript/commit/d14b5c00a88f1a61149a61128bb4c4d07ed35836))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.0.0-beta.3...@amplitude/analytics-core@2.0.0-beta.4) (2023-06-08)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.0.0-beta.2...@amplitude/analytics-core@2.0.0-beta.3) (2023-06-07)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@2.0.0-beta.1...@amplitude/analytics-core@2.0.0-beta.2) (2023-06-06)\n\n### Bug Fixes\n\n- simplify plugins and eliminate enums ([#407](https://github.com/amplitude/Amplitude-TypeScript/issues/407))\n  ([890ec66](https://github.com/amplitude/Amplitude-TypeScript/commit/890ec6695a8b25cd6988e9f7ae584d4ba2835f67))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.13.3...@amplitude/analytics-core@2.0.0-beta.1) (2023-06-06)\n\n### Features\n\n- simplify browser SDK options and plugin options interface\n  ([#384](https://github.com/amplitude/Amplitude-TypeScript/issues/384))\n  ([b464cfb](https://github.com/amplitude/Amplitude-TypeScript/commit/b464cfb8e09d722bf06ed3c11955f77465a23daf))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.13.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.13.2...@amplitude/analytics-core@0.13.3) (2023-05-04)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.13.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.13.1...@amplitude/analytics-core@0.13.2) (2023-04-27)\n\n### Bug Fixes\n\n- do not overwrite flushIntervalMillis=0 with default value (10 seconds)\n  ([#377](https://github.com/amplitude/Amplitude-TypeScript/issues/377))\n  ([02dc428](https://github.com/amplitude/Amplitude-TypeScript/commit/02dc428a5b5b453a245d893a4baaf7ef8757d7ca))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.13.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.13.0...@amplitude/analytics-core@0.13.1) (2023-04-25)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.13.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.12.1...@amplitude/analytics-core@0.13.0) (2023-04-06)\n\n### Features\n\n- update Plugin implementation to allow for dropping events\n  ([#361](https://github.com/amplitude/Amplitude-TypeScript/issues/361))\n  ([3db4d13](https://github.com/amplitude/Amplitude-TypeScript/commit/3db4d1327e87ebcf7a2a8c1d50a62e5c8bc2b418))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.12.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.12.0...@amplitude/analytics-core@0.12.1) (2023-03-31)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.12.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.12.0-beta.0...@amplitude/analytics-core@0.12.0) (2023-02-27)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.12.0-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.11.4...@amplitude/analytics-core@0.12.0-beta.0) (2023-02-24)\n\n### Features\n\n- pass amplitude instance to plugin.setup for enhanced plugin capabilities\n  ([#328](https://github.com/amplitude/Amplitude-TypeScript/issues/328))\n  ([91eeaa0](https://github.com/amplitude/Amplitude-TypeScript/commit/91eeaa0d6bff6bde39538bb54548a938df784462))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.11.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.11.3...@amplitude/analytics-core@0.11.4) (2023-02-09)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.11.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.11.3-beta.0...@amplitude/analytics-core@0.11.3) (2023-01-31)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.11.3-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.11.2...@amplitude/analytics-core@0.11.3-beta.0) (2023-01-26)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.11.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.11.1...@amplitude/analytics-core@0.11.2) (2023-01-11)\n\n### Bug Fixes\n\n- avoid loading types node ([#301](https://github.com/amplitude/Amplitude-TypeScript/issues/301))\n  ([1141807](https://github.com/amplitude/Amplitude-TypeScript/commit/1141807e77ea86423b092943dbbe357813967bd0))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.11.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.11.0...@amplitude/analytics-core@0.11.1) (2022-12-21)\n\n### Bug Fixes\n\n- upgrade dependencies to resolve dependabot vulnerability alerts\n  ([#299](https://github.com/amplitude/Amplitude-TypeScript/issues/299))\n  ([7dd1cd1](https://github.com/amplitude/Amplitude-TypeScript/commit/7dd1cd1b23a71981a4ad90b4b30cc9b7d28c4412))\n\n### Reverts\n\n- Revert \"Updated dependencies\"\n  ([7ca9964](https://github.com/amplitude/Amplitude-TypeScript/commit/7ca9964781e4b900c6c027bdddf2ae1e7428ba18))\n\n# [0.11.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.10.1...@amplitude/analytics-core@0.11.0) (2022-11-28)\n\n### Features\n\n- add nest.js example app and improve response message with body content\n  ([#275](https://github.com/amplitude/Amplitude-TypeScript/issues/275))\n  ([1379195](https://github.com/amplitude/Amplitude-TypeScript/commit/1379195677af0120a09cdf632c3bae36baa4fd1c))\n\n## [0.10.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.10.0...@amplitude/analytics-core@0.10.1) (2022-11-15)\n\n### Bug Fixes\n\n- clear open timeouts when flush is called\n  ([0cebcb7](https://github.com/amplitude/Amplitude-TypeScript/commit/0cebcb72d10de9c4af8c6665a098434b511a6de1))\n- clear open timeouts when flush is called\n  ([f404100](https://github.com/amplitude/Amplitude-TypeScript/commit/f4041003a6024875b9fe03806d487382d7f044d4))\n\n# [0.10.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.9.7...@amplitude/analytics-core@0.10.0) (2022-11-01)\n\n### Features\n\n- enhance logger with debug information ([#254](https://github.com/amplitude/Amplitude-TypeScript/issues/254))\n  ([5c6175e](https://github.com/amplitude/Amplitude-TypeScript/commit/5c6175e9372cbeea264ddb34c6cc68148063d4f7))\n\n## [0.9.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.9.6...@amplitude/analytics-core@0.9.7) (2022-10-25)\n\n### Bug Fixes\n\n- invoke pre-init track fns after attribution ([#253](https://github.com/amplitude/Amplitude-TypeScript/issues/253))\n  ([b8996d7](https://github.com/amplitude/Amplitude-TypeScript/commit/b8996d793f74d388c1a96e0cde5c0ac060c1e565))\n\n## [0.9.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.9.5...@amplitude/analytics-core@0.9.6) (2022-10-14)\n\n### Bug Fixes\n\n- run queued functions after attribution in browser-client.ts\n  ([#249](https://github.com/amplitude/Amplitude-TypeScript/issues/249))\n  ([751b7ca](https://github.com/amplitude/Amplitude-TypeScript/commit/751b7ca6b0f05131dc932b89dd89e8979e334b4b))\n\n## [0.9.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.9.4...@amplitude/analytics-core@0.9.5) (2022-10-04)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n## [0.9.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.9.4-beta.0...@amplitude/analytics-core@0.9.4) (2022-09-28)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n## [0.9.4-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.9.3...@amplitude/analytics-core@0.9.4-beta.0) (2022-09-26)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n## [0.9.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.9.2...@amplitude/analytics-core@0.9.3) (2022-09-26)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n## [0.9.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.9.1...@amplitude/analytics-core@0.9.2) (2022-09-22)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n## [0.9.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.9.0...@amplitude/analytics-core@0.9.1) (2022-09-16)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n# [0.9.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.8.1...@amplitude/analytics-core@0.9.0) (2022-09-08)\n\n### Features\n\n- add ingestion_metadata field ([#212](https://github.com/amplitude/Amplitude-TypeScript/issues/212))\n  ([ebe8448](https://github.com/amplitude/Amplitude-TypeScript/commit/ebe8448b23609134f846e18da2e769158ca30bf1))\n\n## [0.8.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.8.0...@amplitude/analytics-core@0.8.1) (2022-08-31)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n# [0.8.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.7.0...@amplitude/analytics-core@0.8.0) (2022-08-18)\n\n### Bug Fixes\n\n- prevent concurrent init calls ([#191](https://github.com/amplitude/Amplitude-TypeScript/issues/191))\n  ([efda076](https://github.com/amplitude/Amplitude-TypeScript/commit/efda0760f4f1e92e47a3150985e18efcc3b108d9))\n\n### Features\n\n- adds create instance api ([#188](https://github.com/amplitude/Amplitude-TypeScript/issues/188))\n  ([050c1d9](https://github.com/amplitude/Amplitude-TypeScript/commit/050c1d96cedbc9e68aedf6fd55e85d2d3dc2fee4))\n\n# [0.7.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.6.6...@amplitude/analytics-core@0.7.0) (2022-08-16)\n\n### Bug Fixes\n\n- add event options to setGroup\n  ([6ee19e2](https://github.com/amplitude/Amplitude-TypeScript/commit/6ee19e2abb326a687e6e43ecb95fe84adf35a8ce))\n\n### Features\n\n- add 'extra' to eventOptions ([#186](https://github.com/amplitude/Amplitude-TypeScript/issues/186))\n  ([32266f4](https://github.com/amplitude/Amplitude-TypeScript/commit/32266f459c180b75236d036bac66c3e7ecd33920))\n\n## [0.6.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.6.5...@amplitude/analytics-core@0.6.6) (2022-08-13)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n## [0.6.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.6.4...@amplitude/analytics-core@0.6.5) (2022-08-12)\n\n### Bug Fixes\n\n- add callable queue when init is pending ([#181](https://github.com/amplitude/Amplitude-TypeScript/issues/181))\n  ([d8fc361](https://github.com/amplitude/Amplitude-TypeScript/commit/d8fc36195b96e2c10ccc5106027beaa7e970e0c0))\n\n## [0.6.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.6.3...@amplitude/analytics-core@0.6.4) (2022-07-22)\n\n### Bug Fixes\n\n- adds error handling for invalid api ([#153](https://github.com/amplitude/Amplitude-TypeScript/issues/153))\n  ([c03f9d7](https://github.com/amplitude/Amplitude-TypeScript/commit/c03f9d7dad51e3026673dca31418a74591d79bbc))\n- allow undefined storage provider ([#146](https://github.com/amplitude/Amplitude-TypeScript/issues/146))\n  ([e704342](https://github.com/amplitude/Amplitude-TypeScript/commit/e704342761c8ad7de3921ba21901ef8d3a768188))\n- missing tracked events before init issue ([#144](https://github.com/amplitude/Amplitude-TypeScript/issues/144))\n  ([60d0f68](https://github.com/amplitude/Amplitude-TypeScript/commit/60d0f6848087f7b8fc3c870d55489a238e841b26))\n- removes saveEvents config ([#147](https://github.com/amplitude/Amplitude-TypeScript/issues/147))\n  ([6fde736](https://github.com/amplitude/Amplitude-TypeScript/commit/6fde736ca8a865462522082a8085673756dbcc7d))\n- update default flush config for node ([#152](https://github.com/amplitude/Amplitude-TypeScript/issues/152))\n  ([2445dff](https://github.com/amplitude/Amplitude-TypeScript/commit/2445dff0842e7e0a2b7ee767ab926b5a93348214))\n\n## [0.6.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.6.2...@amplitude/analytics-core@0.6.3) (2022-07-15)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n## [0.6.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.6.1...@amplitude/analytics-core@0.6.2) (2022-07-13)\n\n### Bug Fixes\n\n- handle error gracefully when identify is set with null\n  ([#138](https://github.com/amplitude/Amplitude-TypeScript/issues/138))\n  ([e0458d1](https://github.com/amplitude/Amplitude-TypeScript/commit/e0458d1256d2a96195bc8029c3df0d6ac257a588))\n\n## [0.6.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.6.0...@amplitude/analytics-core@0.6.1) (2022-06-29)\n\n### Bug Fixes\n\n- remove Awaited type to support older versions of typescript\n  ([#121](https://github.com/amplitude/Amplitude-TypeScript/issues/121))\n  ([23d36f8](https://github.com/amplitude/Amplitude-TypeScript/commit/23d36f8aade258b995132dafd725ada00e400916))\n\n# [0.6.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.5.0...@amplitude/analytics-core@0.6.0) (2022-06-29)\n\n### Features\n\n- add flush() api to send all events immediately ([#125](https://github.com/amplitude/Amplitude-TypeScript/issues/125))\n  ([b5dbcbb](https://github.com/amplitude/Amplitude-TypeScript/commit/b5dbcbb803c76ee5ade7ea85f76fbea50d8bab49))\n- make storage interface async to enable react-native\n  ([#122](https://github.com/amplitude/Amplitude-TypeScript/issues/122))\n  ([42bb39c](https://github.com/amplitude/Amplitude-TypeScript/commit/42bb39c967db015d5899487618d066f3540c9f18))\n\n# [0.5.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.4.1...@amplitude/analytics-core@0.5.0) (2022-06-24)\n\n### Features\n\n- add marketing campaign tracking ([#112](https://github.com/amplitude/Amplitude-TypeScript/issues/112))\n  ([bca73ed](https://github.com/amplitude/Amplitude-TypeScript/commit/bca73ede308ecb1663986a99600657732969d60c))\n\n## [0.4.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.4.0...@amplitude/analytics-core@0.4.1) (2022-06-21)\n\n### Bug Fixes\n\n- remove userId and deviceId from createIdentifyEvent and createGroupIdentifyEvent\n  ([#119](https://github.com/amplitude/Amplitude-TypeScript/issues/119))\n  ([e7726bb](https://github.com/amplitude/Amplitude-TypeScript/commit/e7726bb9ba16c390638b51042169ede9e083e331))\n\n# [0.4.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.3.1...@amplitude/analytics-core@0.4.0) (2022-06-17)\n\n### Features\n\n- add event bridge components ([#93](https://github.com/amplitude/Amplitude-TypeScript/issues/93))\n  ([64452fc](https://github.com/amplitude/Amplitude-TypeScript/commit/64452fcfeee66e10367220da023137232b2ea112))\n- add Plan option to config ([#117](https://github.com/amplitude/Amplitude-TypeScript/issues/117))\n  ([194d7e6](https://github.com/amplitude/Amplitude-TypeScript/commit/194d7e66af0209cb8155cf6aa0b05a5dcb170f9d))\n- introduce NodeJS package ([#92](https://github.com/amplitude/Amplitude-TypeScript/issues/92))\n  ([476fb44](https://github.com/amplitude/Amplitude-TypeScript/commit/476fb44efcf2dfcd84af6f0ef45e141ad87dac43))\n\n## [0.3.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.3.0...@amplitude/analytics-core@0.3.1) (2022-05-17)\n\n### Bug Fixes\n\n- allow min_id_length option in http payload ([#99](https://github.com/amplitude/Amplitude-TypeScript/issues/99))\n  ([85ec965](https://github.com/amplitude/Amplitude-TypeScript/commit/85ec965d1202f8ee68ca15fbc46015fba76ba3c9))\n- allow option.serverUrl to be used in destination plugin\n  ([#104](https://github.com/amplitude/Amplitude-TypeScript/issues/104))\n  ([f353367](https://github.com/amplitude/Amplitude-TypeScript/commit/f353367b8b264f86b6ea15b15f30385f8d5b8ad5))\n\n# [0.3.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.2.4...@amplitude/analytics-core@0.3.0) (2022-05-12)\n\n### Bug Fixes\n\n- allow event level groups tracking ([#90](https://github.com/amplitude/Amplitude-TypeScript/issues/90))\n  ([3240660](https://github.com/amplitude/Amplitude-TypeScript/commit/3240660e94db9e5c5a1ce4280d07faced2b5fd4d))\n- fix early return if array element is a valid object\n  ([#95](https://github.com/amplitude/Amplitude-TypeScript/issues/95))\n  ([2a82b37](https://github.com/amplitude/Amplitude-TypeScript/commit/2a82b37ec06573318703f3f89d72b44a10b7a392))\n- handle 400 error with invalid id lengths ([#81](https://github.com/amplitude/Amplitude-TypeScript/issues/81))\n  ([fd1686f](https://github.com/amplitude/Amplitude-TypeScript/commit/fd1686fa427588d1dcb6d2125cb4d53647c699e8))\n\n### Features\n\n- parse old cookies and convert to new format ([#85](https://github.com/amplitude/Amplitude-TypeScript/issues/85))\n  ([bda78be](https://github.com/amplitude/Amplitude-TypeScript/commit/bda78be5d2de335e7b1ff6da413b20d3dc751aca))\n\n## [0.2.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.2.3...@amplitude/analytics-core@0.2.4) (2022-04-09)\n\n### Bug Fixes\n\n- fix error handling in fetch client ([#79](https://github.com/amplitude/Amplitude-TypeScript/issues/79))\n  ([749925f](https://github.com/amplitude/Amplitude-TypeScript/commit/749925f907ba72f0e67f3828da99151d00278e6b))\n\n## [0.2.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.2.2...@amplitude/analytics-core@0.2.3) (2022-04-02)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n## [0.2.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.2.1...@amplitude/analytics-core@0.2.2) (2022-04-01)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n## [0.2.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.2.0...@amplitude/analytics-core@0.2.1) (2022-04-01)\n\n**Note:** Version bump only for package @amplitude/analytics-core\n\n# [0.2.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.1.1...@amplitude/analytics-core@0.2.0) (2022-04-01)\n\n### Bug Fixes\n\n- context plugin library version\n  ([8d29c6f](https://github.com/amplitude/Amplitude-TypeScript/commit/8d29c6f4a612510188d920ac243c0bdb116fe02c))\n\n### Features\n\n- add snippet promise support ([#64](https://github.com/amplitude/Amplitude-TypeScript/issues/64))\n  ([4d23c98](https://github.com/amplitude/Amplitude-TypeScript/commit/4d23c98c25c7caa4cd5e63b2a37398f711991288))\n\n## [0.1.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-core@0.1.0...@amplitude/analytics-core@0.1.1) (2022-03-31)\n\n### Bug Fixes\n\n- add missing dependency\n  ([6283f64](https://github.com/amplitude/Amplitude-TypeScript/commit/6283f64dc40b070d68a0243a93ab58d95d436664))\n\n# 0.1.0 (2022-03-31)\n\n### Bug Fixes\n\n- add log message ([#44](https://github.com/amplitude/Amplitude-TypeScript/issues/44))\n  ([92325bc](https://github.com/amplitude/Amplitude-TypeScript/commit/92325bc34cf0143f5f33ec4b0afd3e2d148c3d38))\n- couple plugins with config instance ([#43](https://github.com/amplitude/Amplitude-TypeScript/issues/43))\n  ([abf687a](https://github.com/amplitude/Amplitude-TypeScript/commit/abf687a5d7a395638d8154f65ececc9b5464c366))\n- max retry limit ([#53](https://github.com/amplitude/Amplitude-TypeScript/issues/53))\n  ([fdc0391](https://github.com/amplitude/Amplitude-TypeScript/commit/fdc0391885ac9822f42324d2fd66a8aace001afe))\n- update event results callback parameter ([#29](https://github.com/amplitude/Amplitude-TypeScript/issues/29))\n  ([1acd3c0](https://github.com/amplitude/Amplitude-TypeScript/commit/1acd3c02310e5e9a2b7ab19140f7d6249e9a8452))\n- update logger config to logger provider ([#19](https://github.com/amplitude/Amplitude-TypeScript/issues/19))\n  ([ef89d9f](https://github.com/amplitude/Amplitude-TypeScript/commit/ef89d9f5ffdc9dd88c3652ac36705c79741f53d1))\n- use config reference as plugin instance property ([#21](https://github.com/amplitude/Amplitude-TypeScript/issues/21))\n  ([38c2e33](https://github.com/amplitude/Amplitude-TypeScript/commit/38c2e3334b27063e23275c020207f647acbbaf6f))\n\n### Features\n\n- add amplitude built-in plugins ([#22](https://github.com/amplitude/Amplitude-TypeScript/issues/22))\n  ([443a424](https://github.com/amplitude/Amplitude-TypeScript/commit/443a424d6dfd3a2c867f528f953429151de96ed0))\n- add context plugin ([#13](https://github.com/amplitude/Amplitude-TypeScript/issues/13))\n  ([3d63991](https://github.com/amplitude/Amplitude-TypeScript/commit/3d639917905b25cab0bb012286b8ba487d0f63fb))\n- add EU and batch endpoint support ([#50](https://github.com/amplitude/Amplitude-TypeScript/issues/50))\n  ([af6be60](https://github.com/amplitude/Amplitude-TypeScript/commit/af6be606a0e049657129ddbcbbf83c3dff844443))\n- add getter and setter for config and group ([#45](https://github.com/amplitude/Amplitude-TypeScript/issues/45))\n  ([60e0073](https://github.com/amplitude/Amplitude-TypeScript/commit/60e00734a73002dffc98ddf6171ee74c5ac53aa4))\n- add identify class and handle identify logging ([#10](https://github.com/amplitude/Amplitude-TypeScript/issues/10))\n  ([9075b1f](https://github.com/amplitude/Amplitude-TypeScript/commit/9075b1f0cf4270dacc05b1b7f4bad36c50e2500b))\n- add partner_id in event options ([#38](https://github.com/amplitude/Amplitude-TypeScript/issues/38))\n  ([880fe57](https://github.com/amplitude/Amplitude-TypeScript/commit/880fe57e5813d8bbe05c2a2a9428bd8a0a1e7d08))\n- add serverZone check while calling getApiHost ([#51](https://github.com/amplitude/Amplitude-TypeScript/issues/51))\n  ([fa3014d](https://github.com/amplitude/Amplitude-TypeScript/commit/fa3014dd730e624b6320769edbdf35350d0edc3d))\n- adds default logger provider ([#14](https://github.com/amplitude/Amplitude-TypeScript/issues/14))\n  ([c5c3d62](https://github.com/amplitude/Amplitude-TypeScript/commit/c5c3d62cf505e3df949a4225e3fa3ae2b56d5a0a))\n- adds group identify api ([#18](https://github.com/amplitude/Amplitude-TypeScript/issues/18))\n  ([8871527](https://github.com/amplitude/Amplitude-TypeScript/commit/8871527fb74d0f5745c57a053492a00d19a68c5a))\n- adds session management ([#15](https://github.com/amplitude/Amplitude-TypeScript/issues/15))\n  ([e23a563](https://github.com/amplitude/Amplitude-TypeScript/commit/e23a563c27befa5a3dc31ee55c559359e0159de3))\n- analytics core initialization ([#2](https://github.com/amplitude/Amplitude-TypeScript/issues/2))\n  ([7ba8a7b](https://github.com/amplitude/Amplitude-TypeScript/commit/7ba8a7b1e9b7dfc0af304dd44718a3deb5912fe9))\n- browser init config ([#6](https://github.com/amplitude/Amplitude-TypeScript/issues/6))\n  ([c5a0992](https://github.com/amplitude/Amplitude-TypeScript/commit/c5a09925e64f8a613eeab612ee6efb43419f39b4))\n- core timeline implementation ([#3](https://github.com/amplitude/Amplitude-TypeScript/issues/3))\n  ([ac8bc3a](https://github.com/amplitude/Amplitude-TypeScript/commit/ac8bc3a7212c4e13240fca0da1fbca2cdf7d68c2))\n- create browser folder structure ([#5](https://github.com/amplitude/Amplitude-TypeScript/issues/5))\n  ([b1b279d](https://github.com/amplitude/Amplitude-TypeScript/commit/b1b279da067af7a5ca0c797b4f45fc154e3c2ae4))\n- create cookie/events storage providers ([#7](https://github.com/amplitude/Amplitude-TypeScript/issues/7))\n  ([b3d6fab](https://github.com/amplitude/Amplitude-TypeScript/commit/b3d6fab5239d0d14854af9aa8a0c31826447ac48))\n- create transport providers (fetch/xhr/sendBeacon) ([#8](https://github.com/amplitude/Amplitude-TypeScript/issues/8))\n  ([5ad3477](https://github.com/amplitude/Amplitude-TypeScript/commit/5ad3477974c779d696088922f56cae38a89f911c))\n- implement revenue ([#12](https://github.com/amplitude/Amplitude-TypeScript/issues/12))\n  ([dafd10e](https://github.com/amplitude/Amplitude-TypeScript/commit/dafd10e9feb84513bdcd415a965e3216b044206a))\n- implement save events to storage on destination plugin\n  ([#26](https://github.com/amplitude/Amplitude-TypeScript/issues/26))\n  ([5f47677](https://github.com/amplitude/Amplitude-TypeScript/commit/5f476773f0a546db15de45fc40725a138a037c97))\n- implemented destination plugin with retry ([#4](https://github.com/amplitude/Amplitude-TypeScript/issues/4))\n  ([f4f085e](https://github.com/amplitude/Amplitude-TypeScript/commit/f4f085ed343ea3a0571c778f2d40d637573817d7))\n- implements optOut config ([#30](https://github.com/amplitude/Amplitude-TypeScript/issues/30))\n  ([bdf1eb0](https://github.com/amplitude/Amplitude-TypeScript/commit/bdf1eb0c46f535947f66162639dd0b23f154ce28))\n- improve browser config logic ([#56](https://github.com/amplitude/Amplitude-TypeScript/issues/56))\n  ([3054c68](https://github.com/amplitude/Amplitude-TypeScript/commit/3054c6856dd8f8ed49c9326f25c14b672890915b))\n- update track event ([#25](https://github.com/amplitude/Amplitude-TypeScript/issues/25))\n  ([bcccd65](https://github.com/amplitude/Amplitude-TypeScript/commit/bcccd659f83bd235ce7cb59848e259e14e1df392))\n"
  },
  {
    "path": "packages/analytics-core/README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://amplitude.com\" target=\"_blank\" align=\"center\">\n    <img src=\"https://static.amplitude.com/lightning/46c85bfd91905de8047f1ee65c7c93d6fa9ee6ea/static/media/amplitude-logo-with-text.4fb9e463.svg\" width=\"280\">\n  </a>\n  <br />\n</p>\n\n# @amplitude/analytics-core\n\nInternal Node package for Amplitude \n"
  },
  {
    "path": "packages/analytics-core/jest.config.js",
    "content": "const baseConfig = require('../../jest.config.js');\nconst package = require('./package');\n\nmodule.exports = {\n  ...baseConfig,\n  displayName: package.name,\n  setupFiles: ['./test/setup.js'],\n  rootDir: '.',\n  testEnvironment: 'node',\n  coveragePathIgnorePatterns: ['global-scope.ts', 'types/'],\n};\n"
  },
  {
    "path": "packages/analytics-core/package.json",
    "content": "{\n  \"name\": \"@amplitude/analytics-core\",\n  \"version\": \"2.48.1\",\n  \"description\": \"\",\n  \"author\": \"Amplitude Inc\",\n  \"homepage\": \"https://github.com/amplitude/Amplitude-TypeScript\",\n  \"license\": \"MIT\",\n  \"main\": \"lib/cjs/index.js\",\n  \"module\": \"lib/esm/index.js\",\n  \"types\": \"lib/esm/index.d.ts\",\n  \"sideEffects\": false,\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"tag\": \"latest\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/amplitude/Amplitude-TypeScript.git\"\n  },\n  \"scripts\": {\n    \"build\": \"pnpm build:es5 & pnpm build:esm\",\n    \"build:es5\": \"tsc -p ./tsconfig.es5.json\",\n    \"build:esm\": \"tsc -p ./tsconfig.esm.json\",\n    \"watch\": \"tsc -p ./tsconfig.esm.json --watch\",\n    \"clean\": \"rimraf node_modules lib coverage\",\n    \"fix\": \"pnpm fix:eslint & pnpm fix:prettier\",\n    \"fix:eslint\": \"eslint '{src,test}/**/*.ts' --fix\",\n    \"fix:prettier\": \"prettier --write \\\"{src,test}/**/*.ts\\\"\",\n    \"lint\": \"pnpm lint:eslint & pnpm lint:prettier\",\n    \"lint:eslint\": \"eslint '{src,test}/**/*.ts'\",\n    \"lint:prettier\": \"prettier --check \\\"{src,test}/**/*.ts\\\"\",\n    \"test\": \"jest\",\n    \"typecheck\": \"tsc -p ./tsconfig.json\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/amplitude/Amplitude-TypeScript/issues\"\n  },\n  \"dependencies\": {\n    \"@amplitude/analytics-connector\": \"^1.6.4\",\n    \"@types/zen-observable\": \"0.8.3\",\n    \"safe-json-stringify\": \"1.2.0\",\n    \"tslib\": \"^2.4.1\",\n    \"zen-observable\": \"0.10.0\"\n  },\n  \"files\": [\n    \"lib\"\n  ],\n  \"devDependencies\": {\n    \"@types/safe-json-stringify\": \"1.1.5\"\n  }\n}\n"
  },
  {
    "path": "packages/analytics-core/src/__mocks__/logger.ts",
    "content": "export class Logger {\n  disable(): void {\n    return undefined;\n  }\n\n  enable(): void {\n    return undefined;\n  }\n\n  log(): void {\n    return undefined;\n  }\n\n  warn(): void {\n    return undefined;\n  }\n\n  error(): void {\n    return undefined;\n  }\n}\n"
  },
  {
    "path": "packages/analytics-core/src/analytics-connector.ts",
    "content": "import { AnalyticsConnector } from '@amplitude/analytics-connector';\nimport { DEFAULT_INSTANCE_NAME } from './types/constants';\n\nexport const getAnalyticsConnector = (instanceName = DEFAULT_INSTANCE_NAME): AnalyticsConnector => {\n  return AnalyticsConnector.getInstance(instanceName);\n};\n\nexport const setConnectorUserId = (userId: string | undefined, instanceName?: string): void => {\n  // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n  // @ts-ignore\n  getAnalyticsConnector(instanceName).identityStore.editIdentity().setUserId(userId).commit();\n};\n\nexport const setConnectorDeviceId = (deviceId: string, instanceName?: string): void => {\n  getAnalyticsConnector(instanceName).identityStore.editIdentity().setDeviceId(deviceId).commit();\n};\n"
  },
  {
    "path": "packages/analytics-core/src/campaign/campaign-parser.ts",
    "content": "import { getQueryParams } from '../query-params';\nimport {\n  UTM_CAMPAIGN,\n  UTM_CONTENT,\n  UTM_MEDIUM,\n  UTM_SOURCE,\n  UTM_TERM,\n  GCLID,\n  FBCLID,\n  BASE_CAMPAIGN,\n  DCLID,\n  MSCLKID,\n  RDT_CID,\n  TWCLID,\n  TTCLID,\n  KO_CLICK_ID,\n  LI_FAT_ID,\n  GBRAID,\n  WBRAID,\n  UTM_ID,\n} from '../types/constants';\nimport { Campaign, ICampaignParser, ClickIdParameters, ReferrerParameters, UTMParameters } from '../types/campaign';\n\nexport class CampaignParser implements ICampaignParser {\n  async parse(): Promise<Campaign> {\n    return {\n      ...BASE_CAMPAIGN,\n      ...this.getUtmParam(),\n      ...this.getReferrer(),\n      ...this.getClickIds(),\n    } as Campaign;\n  }\n\n  getUtmParam(): UTMParameters {\n    const params = getQueryParams();\n\n    const utmCampaign = params[UTM_CAMPAIGN];\n    const utmContent = params[UTM_CONTENT];\n    const utmId = params[UTM_ID];\n    const utmMedium = params[UTM_MEDIUM];\n    const utmSource = params[UTM_SOURCE];\n    const utmTerm = params[UTM_TERM];\n\n    return {\n      utm_campaign: utmCampaign,\n      utm_content: utmContent,\n      utm_id: utmId,\n      utm_medium: utmMedium,\n      utm_source: utmSource,\n      utm_term: utmTerm,\n    };\n  }\n\n  getReferrer(): ReferrerParameters {\n    const data: ReferrerParameters = {\n      referrer: undefined,\n      referring_domain: undefined,\n    };\n    try {\n      data.referrer = document.referrer || undefined;\n      data.referring_domain = data.referrer?.split('/')[2] ?? undefined;\n    } catch {\n      // nothing to track\n    }\n    return data;\n  }\n\n  getClickIds(): ClickIdParameters {\n    const params = getQueryParams();\n    return {\n      [DCLID]: params[DCLID],\n      [FBCLID]: params[FBCLID],\n      [GBRAID]: params[GBRAID],\n      [GCLID]: params[GCLID],\n      [KO_CLICK_ID]: params[KO_CLICK_ID],\n      [LI_FAT_ID]: params[LI_FAT_ID],\n      [MSCLKID]: params[MSCLKID],\n      [RDT_CID]: params[RDT_CID],\n      [TTCLID]: params[TTCLID],\n      [TWCLID]: params[TWCLID],\n      [WBRAID]: params[WBRAID],\n    };\n  }\n}\n"
  },
  {
    "path": "packages/analytics-core/src/config.ts",
    "content": "import { OfflineDisabled } from './types/offline';\nimport { ServerZoneType } from './types/server-zone';\nimport { Transport } from './types/transport';\nimport { Event } from './types/event/event';\nimport { Plan } from './types/event/plan';\nimport { IngestionMetadata } from './types/event/ingestion-metadata';\nimport { Storage } from './types/storage';\nimport {\n  AMPLITUDE_SERVER_URL,\n  AMPLITUDE_BATCH_SERVER_URL,\n  EU_AMPLITUDE_SERVER_URL,\n  EU_AMPLITUDE_BATCH_SERVER_URL,\n  DEFAULT_INSTANCE_NAME,\n} from './types/constants';\n\nimport { Logger, ILogger } from './logger';\nimport { LogLevel } from './types/loglevel';\nimport { ConfigOptions, IRequestMetadata, IHistogramOptions, HistogramKey, IConfig } from './types/config/core-config';\n\nexport const getDefaultConfig = () => ({\n  flushMaxRetries: 12,\n  flushQueueSize: 200,\n  flushIntervalMillis: 10000,\n  instanceName: DEFAULT_INSTANCE_NAME,\n  logLevel: LogLevel.Warn,\n  loggerProvider: new Logger(),\n  offline: false,\n  optOut: false,\n  serverUrl: AMPLITUDE_SERVER_URL,\n  serverZone: 'US' as ServerZoneType,\n  useBatch: false,\n});\nexport class Config implements IConfig {\n  apiKey: string;\n  flushIntervalMillis: number;\n  flushMaxRetries: number;\n  flushQueueSize: number;\n  instanceName?: string;\n  loggerProvider: ILogger;\n  logLevel: LogLevel;\n  minIdLength?: number;\n  offline?: boolean | typeof OfflineDisabled;\n  plan?: Plan;\n  ingestionMetadata?: IngestionMetadata;\n  serverUrl: string | undefined;\n  serverZone?: ServerZoneType;\n  transportProvider: Transport;\n  storageProvider?: Storage<Event[]>;\n  useBatch: boolean;\n  requestMetadata?: RequestMetadata;\n\n  protected _optOut = false;\n  get optOut() {\n    return this._optOut;\n  }\n  set optOut(optOut: boolean) {\n    this._optOut = optOut;\n  }\n\n  constructor(options: ConfigOptions) {\n    const defaultConfig = getDefaultConfig();\n    this.apiKey = options.apiKey;\n    this.flushIntervalMillis = options.flushIntervalMillis ?? defaultConfig.flushIntervalMillis;\n    this.flushMaxRetries = options.flushMaxRetries || defaultConfig.flushMaxRetries;\n    this.flushQueueSize = options.flushQueueSize || defaultConfig.flushQueueSize;\n    this.instanceName = options.instanceName || defaultConfig.instanceName;\n    this.loggerProvider = options.loggerProvider || defaultConfig.loggerProvider;\n    this.logLevel = options.logLevel ?? defaultConfig.logLevel;\n    this.minIdLength = options.minIdLength;\n    this.plan = options.plan;\n    this.ingestionMetadata = options.ingestionMetadata;\n    this.offline = options.offline !== undefined ? options.offline : defaultConfig.offline;\n    this.optOut = options.optOut ?? defaultConfig.optOut;\n    this.serverUrl = options.serverUrl;\n    this.serverZone = options.serverZone || defaultConfig.serverZone;\n    this.storageProvider = options.storageProvider;\n    this.transportProvider = options.transportProvider;\n    this.useBatch = options.useBatch ?? defaultConfig.useBatch;\n    this.loggerProvider.enable(this.logLevel);\n\n    const serverConfig = createServerConfig(options.serverUrl, options.serverZone, options.useBatch);\n    this.serverZone = serverConfig.serverZone;\n    this.serverUrl = serverConfig.serverUrl;\n  }\n}\n\nexport const getServerUrl = (serverZone: ServerZoneType, useBatch: boolean) => {\n  if (serverZone === 'EU') {\n    return useBatch ? EU_AMPLITUDE_BATCH_SERVER_URL : EU_AMPLITUDE_SERVER_URL;\n  }\n  return useBatch ? AMPLITUDE_BATCH_SERVER_URL : AMPLITUDE_SERVER_URL;\n};\n\nexport const createServerConfig = (\n  serverUrl = '',\n  serverZone: ServerZoneType = getDefaultConfig().serverZone,\n  useBatch: boolean = getDefaultConfig().useBatch,\n) => {\n  if (serverUrl) {\n    return { serverUrl, serverZone: undefined };\n  }\n  const _serverZone = ['US', 'EU'].includes(serverZone) ? serverZone : getDefaultConfig().serverZone;\n  return {\n    serverZone: _serverZone,\n    serverUrl: getServerUrl(_serverZone, useBatch),\n  };\n};\n\nexport class RequestMetadata implements IRequestMetadata {\n  sdk: {\n    metrics: {\n      histogram: HistogramOptions;\n    };\n  };\n\n  constructor() {\n    this.sdk = {\n      metrics: {\n        histogram: {},\n      },\n    };\n  }\n\n  recordHistogram<T extends HistogramKey>(key: T, value: HistogramOptions[T]) {\n    this.sdk.metrics.histogram[key] = value;\n  }\n}\n\nclass HistogramOptions implements IHistogramOptions {\n  remote_config_fetch_time_IDB?: number;\n  remote_config_fetch_time_API_success?: number;\n  remote_config_fetch_time_API_fail?: number;\n}\n"
  },
  {
    "path": "packages/analytics-core/src/cookie-name.ts",
    "content": "import { AMPLITUDE_PREFIX } from './types/constants';\n\nexport const getCookieName = (apiKey: string, postKey = '', limit = 10) => {\n  return [AMPLITUDE_PREFIX, postKey, apiKey.substring(0, limit)].filter(Boolean).join('_');\n};\n\nexport const getOldCookieName = (apiKey: string) => {\n  return `${AMPLITUDE_PREFIX.toLowerCase()}_${apiKey.substring(0, 6)}`;\n};\n"
  },
  {
    "path": "packages/analytics-core/src/core-client.ts",
    "content": "import { Plugin } from './types/plugin';\nimport { IConfig } from './types/config/core-config';\nimport { BaseEvent, EventOptions } from './types/event/base-event';\nimport { Result } from './types/result';\nimport {\n  Event,\n  IdentifyOperation,\n  IdentifyUserProperties,\n  SpecialEventType,\n  UserProperties,\n} from './types/event/event';\nimport { IIdentify, OrderedIdentifyOperations } from './identify';\nimport { IRevenue } from './revenue';\nimport { CLIENT_NOT_INITIALIZED, OPT_OUT_MESSAGE } from './types/messages';\nimport { Timeline } from './timeline';\nimport {\n  createGroupEvent,\n  createGroupIdentifyEvent,\n  createIdentifyEvent,\n  createRevenueEvent,\n  createTrackEvent,\n} from './utils/event-builder';\nimport { buildResult } from './utils/result-builder';\nimport { returnWrapper } from './utils/return-wrapper';\nimport { CoreClient, PluginHost } from './types/client/core-client';\nexport class AmplitudeCore implements CoreClient, PluginHost {\n  protected initializing = false;\n  protected name: string;\n  // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n  // @ts-ignore\n  config: IConfig;\n  // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n  // @ts-ignore\n  timeline: Timeline;\n  isReady = false;\n  protected q: Array<CallableFunction | typeof returnWrapper> = [];\n  protected dispatchQ: Array<CallableFunction> = [];\n\n  /**\n   * Current user properties (operation-applied, flat key-value).\n   * Only used by client-side SDKs; server SDKs may leave this undefined.\n   */\n  userProperties: { [key: string]: any } | undefined;\n\n  constructor(name = '$default') {\n    this.timeline = new Timeline(this);\n    this.name = name;\n  }\n\n  protected async _init(config: IConfig) {\n    this.config = config;\n    this.timeline.reset(this);\n    this.timeline.loggerProvider = this.config.loggerProvider;\n    await this.runQueuedFunctions('q');\n    this.isReady = true;\n  }\n\n  async runQueuedFunctions(queueName: 'q' | 'dispatchQ') {\n    const queuedFunctions = this[queueName];\n    this[queueName] = [];\n    for (const queuedFunction of queuedFunctions) {\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n      const val: ReturnType<typeof returnWrapper> | Promise<any> = queuedFunction();\n      if (val && 'promise' in val) {\n        await val.promise;\n      } else {\n        await val;\n      }\n    }\n    // Rerun queued functions if the queue has accrued more while awaiting promises\n    if (this[queueName].length) {\n      await this.runQueuedFunctions(queueName);\n    }\n  }\n\n  track(eventInput: BaseEvent | string, eventProperties?: Record<string, any>, eventOptions?: EventOptions) {\n    const event = createTrackEvent(eventInput, eventProperties, eventOptions);\n    // Update client user properties immediately and synchronously\n    this.userProperties = this.getOperationAppliedUserProperties(event.user_properties);\n    return returnWrapper(this.dispatch(event));\n  }\n\n  logEvent = this.track.bind(this);\n\n  identify(identify: IIdentify, eventOptions?: EventOptions) {\n    const event = createIdentifyEvent(identify, eventOptions);\n    // Update client user properties immediately and synchronously\n    this.userProperties = this.getOperationAppliedUserProperties(event.user_properties);\n    return returnWrapper(this.dispatch(event));\n  }\n\n  groupIdentify(groupType: string, groupName: string | string[], identify: IIdentify, eventOptions?: EventOptions) {\n    const event = createGroupIdentifyEvent(groupType, groupName, identify, eventOptions);\n    return returnWrapper(this.dispatch(event));\n  }\n\n  setGroup(groupType: string, groupName: string | string[], eventOptions?: EventOptions) {\n    const event = createGroupEvent(groupType, groupName, eventOptions);\n    // Update client user properties immediately and synchronously\n    this.userProperties = this.getOperationAppliedUserProperties(event.user_properties);\n    return returnWrapper(this.dispatch(event));\n  }\n\n  revenue(revenue: IRevenue, eventOptions?: EventOptions) {\n    const event = createRevenueEvent(revenue, eventOptions);\n    return returnWrapper(this.dispatch(event));\n  }\n\n  add(plugin: Plugin) {\n    if (!this.isReady) {\n      this.q.push(this._addPlugin.bind(this, plugin));\n      return returnWrapper();\n    }\n    return this._addPlugin(plugin);\n  }\n\n  _addPlugin(plugin: Plugin) {\n    return returnWrapper(this.timeline.register(plugin, this.config));\n  }\n\n  remove(pluginName: string) {\n    if (!this.isReady) {\n      this.q.push(this._removePlugin.bind(this, pluginName));\n      return returnWrapper();\n    }\n    return this._removePlugin(pluginName);\n  }\n\n  _removePlugin(pluginName: string) {\n    return returnWrapper(this.timeline.deregister(pluginName, this.config));\n  }\n\n  dispatchWithCallback(event: Event, callback: (result: Result) => void): void {\n    if (!this.isReady) {\n      return callback(buildResult(event, 0, CLIENT_NOT_INITIALIZED));\n    }\n    void this.process(event).then(callback);\n  }\n\n  async dispatch(event: Event): Promise<Result> {\n    if (!this.isReady) {\n      return new Promise<Result>((resolve) => {\n        this.dispatchQ.push(this.dispatchWithCallback.bind(this, event, resolve));\n      });\n    }\n\n    return this.process(event);\n  }\n\n  /**\n   *\n   * This method applies identify operations to user properties and\n   * returns a single object representing the final user property state.\n   *\n   * This is a best-effort api that only supports $set, $clearAll, and $unset.\n   * Other operations are not supported and are ignored.\n   *\n   * Operations are applied on top of current client state (this.userProperties).\n   *\n   * @param userProperties The new user properties object from identify() or setIdentity().\n   * @returns A key-value object user properties without operations.\n   *\n   * @example\n   * Input:\n   * {\n   *   $set: { plan: 'premium' },\n   *   custom_flag: true\n   * }\n   *\n   * Output:\n   * {\n   *   plan: 'premium',\n   *   custom_flag: true\n   * }\n   */\n  getOperationAppliedUserProperties(userProperties: UserProperties | undefined): { [key: string]: any } {\n    const base = this.userProperties ?? {};\n    const updatedProperties: { [key: string]: any } = { ...base };\n\n    if (userProperties === undefined) {\n      return updatedProperties;\n    }\n\n    // Keep non-operation keys for later merge\n    const nonOpProperties: {\n      [key in Exclude<string, IdentifyOperation>]: any;\n    } = {};\n    Object.keys(userProperties).forEach((key) => {\n      if (!Object.values(IdentifyOperation).includes(key as IdentifyOperation)) {\n        // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n        // @ts-ignore\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n        nonOpProperties[key] = userProperties[key];\n      }\n    });\n\n    OrderedIdentifyOperations.forEach((operation) => {\n      // Skip when key is an operation.\n      if (!Object.keys(userProperties).includes(operation)) return;\n\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n      const opProperties: IdentifyUserProperties = userProperties[operation];\n\n      switch (operation) {\n        case IdentifyOperation.CLEAR_ALL:\n          // Due to operation order, the following line will never execute.\n          /* istanbul ignore next */\n          Object.keys(updatedProperties).forEach((prop) => {\n            delete updatedProperties[prop];\n          });\n          break;\n        case IdentifyOperation.UNSET:\n          Object.keys(opProperties).forEach((prop) => {\n            delete updatedProperties[prop];\n          });\n          break;\n        case IdentifyOperation.SET:\n          Object.assign(updatedProperties, opProperties);\n          break;\n      }\n    });\n\n    // Merge non-operation properties.\n    // Custom properties should not be affected by operations.\n    // https://github.com/amplitude/nova/blob/343f678ded83c032e83b189796b3c2be161b48f5/src/main/java/com/amplitude/userproperty/model/ModifyUserPropertiesIdent.java#L79-L83\n    Object.assign(updatedProperties, nonOpProperties);\n\n    return updatedProperties;\n  }\n\n  async process(event: Event): Promise<Result> {\n    try {\n      // skip event processing if opt out\n      if (this.config.optOut) {\n        return buildResult(event, 0, OPT_OUT_MESSAGE);\n      }\n\n      if (event.event_type === SpecialEventType.IDENTIFY) {\n        // Do not update this.userProperties here.\n        // It is only set synchronously in identify() or setIdentity()\n        this.timeline.onIdentityChanged({ userProperties: this.userProperties });\n      }\n\n      const result = await this.timeline.push(event);\n\n      result.code === 200\n        ? this.config.loggerProvider.log(result.message)\n        : result.code === 100\n        ? this.config.loggerProvider.warn(result.message)\n        : this.config.loggerProvider.error(result.message);\n\n      return result;\n    } catch (e) {\n      const message = String(e);\n      this.config.loggerProvider.error(message);\n      const result = buildResult(event, 0, message);\n\n      return result;\n    }\n  }\n\n  setOptOut(optOut: boolean) {\n    if (!this.isReady) {\n      this.q.push(this._setOptOut.bind(this, Boolean(optOut)));\n      return;\n    }\n    this._setOptOut(optOut);\n  }\n\n  _setOptOut(optOut: boolean) {\n    if (this.config.optOut !== optOut) {\n      this.config.optOut = Boolean(optOut);\n      this.timeline.onOptOutChanged(optOut);\n    }\n  }\n\n  flush() {\n    return returnWrapper(this.timeline.flush());\n  }\n\n  plugin(name: string): Plugin | undefined {\n    const plugin = this.timeline.plugins.find((plugin) => plugin.name === name);\n    if (plugin === undefined) {\n      this.config.loggerProvider.debug(`Cannot find plugin with name ${name}`);\n      return undefined;\n    }\n\n    return plugin;\n  }\n\n  plugins<T extends Plugin>(pluginClass: { new (...args: any[]): T }): T[] {\n    return this.timeline.plugins.filter((plugin) => plugin instanceof pluginClass) as T[];\n  }\n}\n"
  },
  {
    "path": "packages/analytics-core/src/diagnostics/diagnostics-client.ts",
    "content": "import { ILogger } from '../logger';\nimport { DiagnosticsStorage, IDiagnosticsStorage } from './diagnostics-storage';\nimport { ServerZoneType } from '../types/server-zone';\nimport { getGlobalScope } from '../global-scope';\nimport { isTimestampInSampleTemp } from '../utils/sampling';\nimport { enableSdkErrorListeners } from './uncaught-sdk-errors';\n\nexport const SAVE_INTERVAL_MS = 1000; // 1 second\nexport const FLUSH_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes\nexport const DIAGNOSTICS_US_SERVER_URL = 'https://diagnostics.prod.us-west-2.amplitude.com/v1/capture';\nexport const DIAGNOSTICS_EU_SERVER_URL = 'https://diagnostics.prod.eu-central-1.amplitude.com/v1/capture';\n\n// In-memory storage limits\nexport const MAX_MEMORY_STORAGE_COUNT = 10000; // for tags, counters, histograms separately\nexport const MAX_MEMORY_STORAGE_EVENTS_COUNT = 10;\n\n// === Core Data Types ===\n\n/**\n * Key-value pairs for environment/context information\n */\ntype DiagnosticsTags = Record<string, string>;\n\n/**\n * Numeric counters that can be incremented\n */\ntype DiagnosticsCounters = Record<string, number>;\n\n/**\n * Properties for diagnostic events\n */\ntype EventProperties = Record<string, any>;\n\n/**\n * Individual diagnostic event\n */\ninterface DiagnosticsEvent {\n  readonly event_name: string;\n  readonly time: number;\n  readonly event_properties: EventProperties;\n}\n\n/**\n * Computed histogram statistics for final payload\n */\ninterface HistogramResult {\n  readonly count: number;\n  readonly min: number;\n  readonly max: number;\n  readonly avg: number;\n}\n\n/**\n * Internal histogram statistics with sum for efficient incremental updates\n */\nexport interface HistogramStats {\n  count: number;\n  min: number;\n  max: number;\n  sum: number; // Used for avg calculation\n}\n\n/**\n * Collection of histogram results keyed by histogram name\n */\ntype DiagnosticsHistograms = Record<string, HistogramResult>;\n\n/**\n * Collection of histogram stats keyed by histogram name (internal use for memory + persistence storage)\n */\ntype DiagnosticsHistogramStats = Record<string, HistogramStats>;\n\n// === Payload Types ===\n\n/**\n * Complete diagnostics payload sent to backend\n */\ninterface FlushPayload {\n  readonly tags: DiagnosticsTags;\n  readonly histogram: DiagnosticsHistograms;\n  readonly counters: DiagnosticsCounters;\n  readonly events: readonly DiagnosticsEvent[];\n}\n\n/**\n * Amplitude Diagnostics Client\n *\n * A client for collecting and managing diagnostics data including tags, counters,\n * histograms, and events. Data is stored persistently using IndexedDB to survive browser restarts and offline scenarios.\n *\n * Key Features:\n * - IndexedDB storage\n * - Time-based persistent storage flush interval (5 minutes since last flush)\n * - 1 second time-based memory storage flush to persistent storage\n * - Histogram statistics calculation (min, max, avg)\n */\nexport interface IDiagnosticsClient {\n  /**\n   * Set or update a tag\n   *\n   * @example\n   * ```typescript\n   * // Set environment tags\n   * diagnostics.setTag('library', 'amplitude-typescript/2.0.0');\n   * diagnostics.setTag('user_agent', navigator.userAgent);\n   * ```\n   */\n  setTag(name: string, value: string): void;\n\n  /**\n   * Increment a counter. If doesn't exist, create a counter and set value to 1\n   *\n   * @example\n   * ```typescript\n   * // Track counters\n   * diagnostics.increment('analytics.fileNotFound');\n   * diagnostics.increment('network.retry', 3);\n   * ```\n   */\n  increment(name: string, size?: number): void;\n\n  /**\n   * Record a histogram value\n   *\n   * @example\n   * ```typescript\n   * // Record performance metrics\n   * diagnostics.recordHistogram('sr.time', 5.2);\n   * diagnostics.recordHistogram('network.latency', 150);\n   * ```\n   */\n  recordHistogram(name: string, value: number): void;\n\n  /**\n   * Record an event\n   *\n   * @example\n   * ```typescript\n   * // Record diagnostic events\n   * diagnostics.recordEvent('error', {\n   *   stack_trace: '...',\n   * });\n   * ```\n   */\n  recordEvent(name: string, properties: EventProperties): void;\n\n  // Flush storage\n  _flush(): void;\n\n  /**\n   * Sets the sample rate for diagnostics.\n   *\n   * @example\n   * ```typescript\n   * diagnostics.setSampleRate(0.5);\n   * ```\n   */\n  _setSampleRate(sampleRate: number): void;\n}\n\nexport class DiagnosticsClient implements IDiagnosticsClient {\n  storage?: IDiagnosticsStorage;\n  logger: ILogger;\n  serverUrl: string;\n  apiKey: string;\n  // Whether to track diagnostics data based on sample rate and enabled flag\n  shouldTrack: boolean;\n  config: {\n    enabled: boolean;\n    sampleRate: number;\n  };\n  /**\n   * The timestamp when the diagnostics client was initialized.\n   * Save in memory to keep lifecycle sample rate calculation consistency.\n   */\n  startTimestamp: number;\n\n  // In-memory storages\n  inMemoryTags: DiagnosticsTags = {};\n  inMemoryCounters: DiagnosticsCounters = {};\n  inMemoryHistograms: DiagnosticsHistogramStats = {};\n  inMemoryEvents: DiagnosticsEvent[] = [];\n\n  // Timer for 1-second persistence\n  saveTimer: ReturnType<typeof setTimeout> | null = null;\n  // Timer for flush interval\n  flushTimer: ReturnType<typeof setTimeout> | null = null;\n\n  constructor(\n    apiKey: string,\n    logger: ILogger,\n    serverZone: ServerZoneType = 'US',\n    options?: {\n      enabled?: boolean;\n      sampleRate?: number;\n    },\n  ) {\n    this.apiKey = apiKey;\n    this.logger = logger;\n    this.serverUrl = serverZone === 'US' ? DIAGNOSTICS_US_SERVER_URL : DIAGNOSTICS_EU_SERVER_URL;\n\n    this.logger.debug('DiagnosticsClient: Initializing with options', JSON.stringify(options, null, 2));\n    // Diagnostics is enabled by default with sample rate of 0 (no sampling)\n    this.config = { enabled: true, sampleRate: 0, ...options };\n    this.startTimestamp = Date.now();\n    this.shouldTrack = isTimestampInSampleTemp(this.startTimestamp, this.config.sampleRate) && this.config.enabled;\n\n    if (DiagnosticsStorage.isSupported()) {\n      this.storage = new DiagnosticsStorage(apiKey, logger);\n    } else {\n      this.logger.debug('DiagnosticsClient: IndexedDB is not supported');\n    }\n\n    void this.initializeFlushInterval();\n\n    // Track internal diagnostics metrics for sampling\n    if (this.shouldTrack) {\n      this.increment('sdk.diagnostics.sampled.in.and.enabled');\n      enableSdkErrorListeners(this);\n    }\n  }\n\n  /**\n   * Check if storage is available and tracking is enabled\n   */\n  isStorageAndTrackEnabled(): boolean {\n    return Boolean(this.storage) && Boolean(this.shouldTrack);\n  }\n\n  setTag(name: string, value: string) {\n    if (!this.isStorageAndTrackEnabled()) {\n      return;\n    }\n\n    if (Object.keys(this.inMemoryTags).length >= MAX_MEMORY_STORAGE_COUNT) {\n      this.logger.debug('DiagnosticsClient: Early return setTags as reaching memory limit');\n      return;\n    }\n\n    this.inMemoryTags[name] = value;\n    this.startTimersIfNeeded();\n  }\n\n  increment(name: string, size = 1) {\n    if (!this.isStorageAndTrackEnabled()) {\n      return;\n    }\n\n    if (Object.keys(this.inMemoryCounters).length >= MAX_MEMORY_STORAGE_COUNT) {\n      this.logger.debug('DiagnosticsClient: Early return increment as reaching memory limit');\n      return;\n    }\n\n    this.inMemoryCounters[name] = (this.inMemoryCounters[name] || 0) + size;\n    this.startTimersIfNeeded();\n  }\n\n  recordHistogram(name: string, value: number) {\n    if (!this.isStorageAndTrackEnabled()) {\n      return;\n    }\n\n    if (Object.keys(this.inMemoryHistograms).length >= MAX_MEMORY_STORAGE_COUNT) {\n      this.logger.debug('DiagnosticsClient: Early return recordHistogram as reaching memory limit');\n      return;\n    }\n\n    const existing = this.inMemoryHistograms[name];\n    if (existing) {\n      // Update existing stats incrementally\n      existing.count += 1;\n      existing.min = Math.min(existing.min, value);\n      existing.max = Math.max(existing.max, value);\n      existing.sum += value;\n    } else {\n      // Create new stats\n      this.inMemoryHistograms[name] = {\n        count: 1,\n        min: value,\n        max: value,\n        sum: value,\n      };\n    }\n    this.startTimersIfNeeded();\n  }\n\n  recordEvent(name: string, properties: EventProperties) {\n    if (!this.isStorageAndTrackEnabled()) {\n      return;\n    }\n\n    if (this.inMemoryEvents.length >= MAX_MEMORY_STORAGE_EVENTS_COUNT) {\n      this.logger.debug('DiagnosticsClient: Early return recordEvent as reaching memory limit');\n      return;\n    }\n\n    this.inMemoryEvents.push({\n      event_name: name,\n      time: Date.now(),\n      event_properties: properties,\n    });\n    this.startTimersIfNeeded();\n  }\n\n  startTimersIfNeeded() {\n    if (!this.saveTimer) {\n      this.saveTimer = setTimeout(() => {\n        this.saveAllDataToStorage()\n          .catch((error) => {\n            this.logger.debug('DiagnosticsClient: Failed to save all data to storage', error);\n          })\n          .finally(() => {\n            this.saveTimer = null;\n          });\n      }, SAVE_INTERVAL_MS);\n    }\n\n    if (!this.flushTimer) {\n      this.flushTimer = setTimeout(() => {\n        this._flush()\n          .catch((error) => {\n            this.logger.debug('DiagnosticsClient: Failed to flush', error);\n          })\n          .finally(() => {\n            this.flushTimer = null;\n          });\n      }, FLUSH_INTERVAL_MS);\n    }\n  }\n\n  async saveAllDataToStorage() {\n    if (!this.storage) {\n      return;\n    }\n    const tagsToSave = { ...this.inMemoryTags };\n    const countersToSave = { ...this.inMemoryCounters };\n    const histogramsToSave = { ...this.inMemoryHistograms };\n    const eventsToSave = [...this.inMemoryEvents];\n\n    this.inMemoryEvents = [];\n    this.inMemoryTags = {};\n    this.inMemoryCounters = {};\n    this.inMemoryHistograms = {};\n\n    await Promise.all([\n      this.storage.setTags(tagsToSave),\n      this.storage.incrementCounters(countersToSave),\n      this.storage.setHistogramStats(histogramsToSave),\n      this.storage.addEventRecords(eventsToSave),\n    ]);\n  }\n\n  async _flush() {\n    if (!this.storage) {\n      return;\n    }\n\n    await this.saveAllDataToStorage();\n    this.saveTimer = null;\n    this.flushTimer = null;\n\n    // Get all data from storage and clear it\n    const {\n      tags: tagRecords,\n      counters: counterRecords,\n      histogramStats: histogramStatsRecords,\n      events: eventRecords,\n    } = await this.storage.getAllAndClear();\n\n    // Update the last flush timestamp\n    void this.storage.setLastFlushTimestamp(Date.now());\n\n    // Convert metrics to the expected format\n    const tags: DiagnosticsTags = {};\n    tagRecords.forEach((record) => {\n      tags[record.key] = record.value;\n    });\n\n    const counters: DiagnosticsCounters = {};\n    counterRecords.forEach((record) => {\n      counters[record.key] = record.value;\n    });\n\n    const histogram: DiagnosticsHistograms = {};\n    histogramStatsRecords.forEach((stats) => {\n      histogram[stats.key] = {\n        count: stats.count,\n        min: stats.min,\n        max: stats.max,\n        avg: Math.round((stats.sum / stats.count) * 100) / 100, // round the average to 2 decimal places.\n      };\n    });\n\n    const events: DiagnosticsEvent[] = eventRecords.map((record) => ({\n      event_name: record.event_name,\n      time: record.time,\n      event_properties: record.event_properties,\n    }));\n\n    // Early return if all data collections are empty\n    if (Object.keys(counters).length === 0 && Object.keys(histogram).length === 0 && events.length === 0) {\n      return;\n    }\n\n    // Create flush payload\n    const payload: FlushPayload = {\n      tags,\n      histogram,\n      counters,\n      events,\n    };\n\n    // Send payload to diagnostics server\n    void this.fetch(payload);\n  }\n\n  /**\n   * Send diagnostics data to the server\n   */\n  async fetch(payload: FlushPayload) {\n    try {\n      if (!getGlobalScope()) {\n        throw new Error('DiagnosticsClient: Fetch is not supported');\n      }\n\n      const response = await fetch(this.serverUrl, {\n        method: 'POST',\n        headers: {\n          'X-ApiKey': this.apiKey,\n          'Content-Type': 'application/json',\n        },\n        body: JSON.stringify(payload),\n      });\n\n      if (!response.ok) {\n        this.logger.debug('DiagnosticsClient: Failed to send diagnostics data.');\n        return;\n      }\n\n      this.logger.debug('DiagnosticsClient: Successfully sent diagnostics data');\n    } catch (error) {\n      this.logger.debug('DiagnosticsClient: Failed to send diagnostics data. ', error);\n    }\n  }\n\n  /**\n   * Initialize flush interval logic.\n   * Check if 5 minutes has passed since last flush, if so flush immediately.\n   * Otherwise set a timer to flush when the interval is reached.\n   */\n  async initializeFlushInterval() {\n    if (!this.storage) {\n      return;\n    }\n    const now = Date.now();\n    const lastFlushTimestamp = (await this.storage.getLastFlushTimestamp()) || -1;\n\n    // If last flush timestamp is -1, it means this is a new client\n    // Save current timestamp as the initial \"last flush timestamp\"\n    // and schedule the flush timer\n    if (lastFlushTimestamp === -1) {\n      void this.storage.setLastFlushTimestamp(now);\n      this._setFlushTimer(FLUSH_INTERVAL_MS);\n      return;\n    }\n\n    const timeSinceLastFlush = now - lastFlushTimestamp;\n    if (timeSinceLastFlush >= FLUSH_INTERVAL_MS) {\n      // More than 5 minutes has passed, flush immediately\n      void this._flush();\n      return;\n    } else {\n      // Set timer for remaining time\n      this._setFlushTimer(FLUSH_INTERVAL_MS - timeSinceLastFlush);\n    }\n  }\n\n  /**\n   * Helper method to set flush timer with consistent error handling\n   */\n  private _setFlushTimer(delay: number) {\n    this.flushTimer = setTimeout(() => {\n      this._flush()\n        .catch((error) => {\n          this.logger.debug('DiagnosticsClient: Failed to flush', error);\n        })\n        .finally(() => {\n          this.flushTimer = null;\n        });\n    }, delay);\n  }\n\n  _setSampleRate(sampleRate: number): void {\n    this.logger.debug('DiagnosticsClient: Setting sample rate to', sampleRate);\n    this.config.sampleRate = sampleRate;\n    this.shouldTrack = isTimestampInSampleTemp(this.startTimestamp, this.config.sampleRate) && this.config.enabled;\n    this.logger.debug('DiagnosticsClient: Should track is', this.shouldTrack);\n  }\n}\n"
  },
  {
    "path": "packages/analytics-core/src/diagnostics/diagnostics-storage.ts",
    "content": "import { getGlobalScope } from '../global-scope';\nimport { ILogger } from '../logger';\nimport { HistogramStats } from './diagnostics-client';\n\nconst MAX_PERSISTENT_STORAGE_EVENTS_COUNT = 10;\n\n// Database configuration\nconst DB_VERSION = 1;\n\n// Table names for different diagnostics types\nexport const TABLE_NAMES = {\n  TAGS: 'tags',\n  COUNTERS: 'counters',\n  HISTOGRAMS: 'histograms',\n  EVENTS: 'events',\n  INTERNAL: 'internal', // New table for internal storage like flush timestamps\n} as const;\n\n// Keys for internal storage table\nexport const INTERNAL_KEYS = {\n  LAST_FLUSH_TIMESTAMP: 'last_flush_timestamp',\n} as const;\n\n// Record interfaces for each table\nexport interface TagRecord {\n  key: string;\n  value: string;\n}\n\nexport interface CounterRecord {\n  key: string;\n  value: number;\n}\n\nexport interface HistogramRecord {\n  key: string;\n  count: number;\n  min: number;\n  max: number;\n  sum: number;\n}\n\nexport interface EventRecord {\n  id?: number; // Auto-increment primary key\n  event_name: string;\n  time: number;\n  event_properties: Record<string, any>;\n}\n\nexport interface InternalRecord {\n  key: string;\n  value: string;\n}\n\nexport interface IDiagnosticsStorage {\n  /**\n   * Set multiple tags in a single transaction (batch operation)\n   * Promise never rejects - errors are logged and operation continues gracefully\n   */\n  setTags(tags: Record<string, string>): Promise<void>;\n  /**\n   * Increment multiple counters in a single transaction (batch operation)\n   * Uses read-modify-write pattern to accumulate with existing values\n   * Promise never rejects - errors are logged and operation continues gracefully\n   */\n  incrementCounters(counters: Record<string, number>): Promise<void>;\n  /**\n   * Set multiple histogram stats in a single transaction (batch operation)\n   * Uses read-modify-write pattern to accumulate count/sum and update min/max with existing values\n   * Promise never rejects - errors are logged and operation continues gracefully\n   */\n  setHistogramStats(\n    histogramStats: Record<string, { count: number; min: number; max: number; sum: number }>,\n  ): Promise<void>;\n  /**\n   * Add multiple event records in a single transaction (batch operation)\n   * Promise never rejects - errors are logged and operation continues gracefully\n   */\n  addEventRecords(\n    events: Array<{ event_name: string; time: number; event_properties: Record<string, any> }>,\n  ): Promise<void>;\n\n  setLastFlushTimestamp(timestamp: number): Promise<void>;\n\n  getLastFlushTimestamp(): Promise<number | undefined>;\n\n  /**\n   * Get all data except internal data from storage and clear it\n   */\n  getAllAndClear(): Promise<{\n    tags: TagRecord[];\n    counters: CounterRecord[];\n    histogramStats: HistogramRecord[];\n    events: EventRecord[];\n  }>;\n}\n\n/**\n * Purpose-specific IndexedDB storage for diagnostics data\n * Provides optimized methods for each type of diagnostics data\n */\nexport class DiagnosticsStorage implements IDiagnosticsStorage {\n  dbPromise: Promise<IDBDatabase> | null = null;\n  dbName: string;\n  logger: ILogger;\n\n  constructor(apiKey: string, logger: ILogger) {\n    this.logger = logger;\n    this.dbName = `AMP_diagnostics_${apiKey.substring(0, 10)}`;\n  }\n\n  /**\n   * Check if IndexedDB is supported in the current environment\n   * @returns true if IndexedDB is available, false otherwise\n   */\n  static isSupported(): boolean {\n    return getGlobalScope()?.indexedDB !== undefined;\n  }\n\n  async getDB(): Promise<IDBDatabase> {\n    if (!this.dbPromise) {\n      this.dbPromise = this.openDB();\n    }\n    return this.dbPromise;\n  }\n\n  openDB(): Promise<IDBDatabase> {\n    return new Promise((resolve, reject) => {\n      const request = indexedDB.open(this.dbName, DB_VERSION);\n\n      request.onerror = () => {\n        // Clear dbPromise when it rejects for the first time\n        this.dbPromise = null;\n        reject(new Error('Failed to open IndexedDB'));\n      };\n\n      request.onsuccess = () => {\n        const db = request.result;\n        // Clear dbPromise when connection was on but went off later\n        db.onclose = () => {\n          this.dbPromise = null;\n          this.logger.debug('DiagnosticsStorage: DB connection closed.');\n        };\n\n        db.onerror = (event) => {\n          this.logger.debug('DiagnosticsStorage: A global database error occurred.', event);\n          db.close();\n        };\n        resolve(db);\n      };\n\n      request.onupgradeneeded = (event) => {\n        const db = (event.target as IDBOpenDBRequest).result;\n        this.createTables(db);\n      };\n    });\n  }\n\n  createTables(db: IDBDatabase): void {\n    // Create tags table\n    if (!db.objectStoreNames.contains(TABLE_NAMES.TAGS)) {\n      db.createObjectStore(TABLE_NAMES.TAGS, { keyPath: 'key' });\n    }\n\n    // Create counters table\n    if (!db.objectStoreNames.contains(TABLE_NAMES.COUNTERS)) {\n      db.createObjectStore(TABLE_NAMES.COUNTERS, { keyPath: 'key' });\n    }\n\n    // Create histograms table for storing histogram stats (count, min, max, sum)\n    if (!db.objectStoreNames.contains(TABLE_NAMES.HISTOGRAMS)) {\n      db.createObjectStore(TABLE_NAMES.HISTOGRAMS, {\n        keyPath: 'key',\n      });\n    }\n\n    // Create events table\n    if (!db.objectStoreNames.contains(TABLE_NAMES.EVENTS)) {\n      const eventsStore = db.createObjectStore(TABLE_NAMES.EVENTS, {\n        keyPath: 'id',\n        autoIncrement: true,\n      });\n\n      // Create index on time for chronological queries\n      eventsStore.createIndex('time_idx', 'time', { unique: false });\n    }\n\n    // Create internal table for storing internal data like flush timestamps\n    if (!db.objectStoreNames.contains(TABLE_NAMES.INTERNAL)) {\n      db.createObjectStore(TABLE_NAMES.INTERNAL, { keyPath: 'key' });\n    }\n  }\n\n  async setTags(tags: Record<string, string>): Promise<void> {\n    try {\n      if (Object.entries(tags).length === 0) {\n        return;\n      }\n\n      const db = await this.getDB();\n      const transaction = db.transaction([TABLE_NAMES.TAGS], 'readwrite');\n      const store = transaction.objectStore(TABLE_NAMES.TAGS);\n\n      return new Promise((resolve) => {\n        const entries = Object.entries(tags);\n\n        transaction.oncomplete = () => {\n          resolve();\n        };\n\n        transaction.onabort = (event) => {\n          this.logger.debug('DiagnosticsStorage: Failed to set tags', event);\n          resolve();\n        };\n\n        entries.forEach(([key, value]) => {\n          const putRequest = store.put({ key, value });\n\n          putRequest.onerror = (event) => {\n            this.logger.debug('DiagnosticsStorage: Failed to set tag', key, value, event);\n          };\n        });\n      });\n    } catch (error) {\n      this.logger.debug('DiagnosticsStorage: Failed to set tags', error);\n    }\n  }\n\n  async incrementCounters(counters: Record<string, number>): Promise<void> {\n    try {\n      if (Object.entries(counters).length === 0) {\n        return;\n      }\n\n      const db = await this.getDB();\n      const transaction = db.transaction([TABLE_NAMES.COUNTERS], 'readwrite');\n      const store = transaction.objectStore(TABLE_NAMES.COUNTERS);\n\n      return new Promise((resolve) => {\n        const entries = Object.entries(counters);\n\n        transaction.oncomplete = () => {\n          resolve();\n        };\n\n        transaction.onabort = (event) => {\n          this.logger.debug('DiagnosticsStorage: Failed to increment counters', event);\n          resolve();\n        };\n\n        // Read existing values and update them\n        entries.forEach(([key, incrementValue]) => {\n          const getRequest = store.get(key);\n\n          getRequest.onsuccess = () => {\n            const existingRecord = getRequest.result as CounterRecord | undefined;\n            /* istanbul ignore next */\n            const existingValue = existingRecord ? existingRecord.value : 0;\n            const putRequest = store.put({ key, value: existingValue + incrementValue });\n\n            putRequest.onerror = (event) => {\n              this.logger.debug('DiagnosticsStorage: Failed to update counter', key, event);\n            };\n          };\n\n          getRequest.onerror = (event) => {\n            this.logger.debug('DiagnosticsStorage: Failed to read existing counter', key, event);\n          };\n        });\n      });\n    } catch (error) {\n      this.logger.debug('DiagnosticsStorage: Failed to increment counters', error);\n    }\n  }\n\n  async setHistogramStats(histogramStats: Record<string, HistogramStats>): Promise<void> {\n    try {\n      if (Object.entries(histogramStats).length === 0) {\n        return;\n      }\n\n      const db = await this.getDB();\n      const transaction = db.transaction([TABLE_NAMES.HISTOGRAMS], 'readwrite');\n      const store = transaction.objectStore(TABLE_NAMES.HISTOGRAMS);\n\n      return new Promise((resolve) => {\n        const entries = Object.entries(histogramStats);\n\n        transaction.oncomplete = () => {\n          resolve();\n        };\n\n        transaction.onabort = (event) => {\n          this.logger.debug('DiagnosticsStorage: Failed to set histogram stats', event);\n          resolve();\n        };\n\n        // Read existing values and update them\n        entries.forEach(([key, newStats]) => {\n          const getRequest = store.get(key);\n\n          getRequest.onsuccess = () => {\n            const existingRecord = getRequest.result as HistogramRecord | undefined;\n            let updatedStats: HistogramRecord;\n\n            /* istanbul ignore next */\n            if (existingRecord) {\n              // Accumulate with existing stats\n              updatedStats = {\n                key,\n                count: existingRecord.count + newStats.count,\n                min: Math.min(existingRecord.min, newStats.min),\n                max: Math.max(existingRecord.max, newStats.max),\n                sum: existingRecord.sum + newStats.sum,\n              };\n            } else {\n              // Create new stats\n              updatedStats = {\n                key,\n                count: newStats.count,\n                min: newStats.min,\n                max: newStats.max,\n                sum: newStats.sum,\n              };\n            }\n\n            const putRequest = store.put(updatedStats);\n\n            putRequest.onerror = (event) => {\n              this.logger.debug('DiagnosticsStorage: Failed to set histogram stats', key, event);\n            };\n          };\n\n          getRequest.onerror = (event) => {\n            this.logger.debug('DiagnosticsStorage: Failed to read existing histogram stats', key, event);\n          };\n        });\n      });\n    } catch (error) {\n      this.logger.debug('DiagnosticsStorage: Failed to set histogram stats', error);\n    }\n  }\n\n  async addEventRecords(\n    events: Array<{ event_name: string; time: number; event_properties: Record<string, any> }>,\n  ): Promise<void> {\n    try {\n      if (events.length === 0) {\n        return;\n      }\n\n      const db = await this.getDB();\n      const transaction = db.transaction([TABLE_NAMES.EVENTS], 'readwrite');\n      const store = transaction.objectStore(TABLE_NAMES.EVENTS);\n\n      return new Promise((resolve) => {\n        transaction.oncomplete = () => {\n          resolve();\n        };\n\n        /* istanbul ignore next */\n        transaction.onabort = (event) => {\n          this.logger.debug('DiagnosticsStorage: Failed to add event records', event);\n          resolve();\n        };\n\n        // First, check how many events are currently stored\n        const countRequest = store.count();\n\n        countRequest.onsuccess = () => {\n          const currentCount = countRequest.result;\n\n          // Calculate how many events we can add\n          const availableSlots = Math.max(0, MAX_PERSISTENT_STORAGE_EVENTS_COUNT - currentCount);\n\n          if (availableSlots < events.length) {\n            this.logger.debug(\n              `DiagnosticsStorage: Only added ${availableSlots} of ${events.length} events due to storage limit`,\n            );\n          }\n\n          // Only add events up to the available slots (take the least recent ones)\n          events.slice(0, availableSlots).forEach((event) => {\n            const request = store.add(event);\n\n            request.onerror = (event) => {\n              this.logger.debug('DiagnosticsStorage: Failed to add event record', event);\n            };\n          });\n        };\n\n        countRequest.onerror = (event) => {\n          this.logger.debug('DiagnosticsStorage: Failed to count existing events', event);\n        };\n      });\n    } catch (error) {\n      this.logger.debug('DiagnosticsStorage: Failed to add event records', error);\n    }\n  }\n\n  async setInternal(key: string, value: string): Promise<void> {\n    try {\n      const db = await this.getDB();\n      const transaction = db.transaction([TABLE_NAMES.INTERNAL], 'readwrite');\n      const store = transaction.objectStore(TABLE_NAMES.INTERNAL);\n\n      return new Promise((resolve, reject) => {\n        /* istanbul ignore next */\n        transaction.onabort = () => reject(new Error('Failed to set internal value'));\n\n        const request = store.put({ key, value });\n\n        request.onsuccess = () => resolve();\n\n        /* istanbul ignore next */\n        request.onerror = () => reject(new Error('Failed to set internal value'));\n      });\n    } catch (error) {\n      /* istanbul ignore next */\n      this.logger.debug('DiagnosticsStorage: Failed to set internal value', error);\n    }\n  }\n\n  async getInternal(key: string): Promise<InternalRecord | undefined> {\n    try {\n      const db = await this.getDB();\n      const transaction = db.transaction([TABLE_NAMES.INTERNAL], 'readonly');\n      const store = transaction.objectStore(TABLE_NAMES.INTERNAL);\n\n      return new Promise((resolve, reject) => {\n        /* istanbul ignore next */\n        transaction.onabort = () => reject(new Error('Failed to get internal value'));\n\n        const request = store.get(key);\n\n        request.onsuccess = () => resolve(request.result as InternalRecord | undefined);\n\n        /* istanbul ignore next */\n        request.onerror = () => reject(new Error('Failed to get internal value'));\n      });\n    } catch (error) {\n      this.logger.debug('DiagnosticsStorage: Failed to get internal value', error);\n      return undefined;\n    }\n  }\n\n  async getLastFlushTimestamp(): Promise<number | undefined> {\n    try {\n      const record = await this.getInternal(INTERNAL_KEYS.LAST_FLUSH_TIMESTAMP);\n      return record ? parseInt(record.value, 10) : undefined;\n    } catch (error) {\n      /* istanbul ignore next */\n      this.logger.debug('DiagnosticsStorage: Failed to get last flush timestamp', error);\n      /* istanbul ignore next */\n      return undefined;\n    }\n  }\n\n  async setLastFlushTimestamp(timestamp: number): Promise<void> {\n    try {\n      await this.setInternal(INTERNAL_KEYS.LAST_FLUSH_TIMESTAMP, timestamp.toString());\n    } catch (error) {\n      /* istanbul ignore next */\n      this.logger.debug('DiagnosticsStorage: Failed to set last flush timestamp', error);\n    }\n  }\n\n  /* istanbul ignore next */\n  clearTable(transaction: IDBTransaction, tableName: string): Promise<void> {\n    return new Promise((resolve, reject) => {\n      const store = transaction.objectStore(tableName);\n      const request = store.clear();\n\n      request.onsuccess = () => resolve();\n      request.onerror = () => reject(new Error(`Failed to clear table ${tableName}`));\n    });\n  }\n\n  /* istanbul ignore next */\n  async getAllAndClear(): Promise<{\n    tags: TagRecord[];\n    counters: CounterRecord[];\n    histogramStats: HistogramRecord[];\n    events: EventRecord[];\n  }> {\n    try {\n      const db = await this.getDB();\n      const transaction = db.transaction(\n        [TABLE_NAMES.TAGS, TABLE_NAMES.COUNTERS, TABLE_NAMES.HISTOGRAMS, TABLE_NAMES.EVENTS],\n        'readwrite',\n      );\n\n      // Get all data first\n      const [tags, counters, histogramStats, events] = await Promise.all([\n        this.getAllFromStore<TagRecord>(transaction, TABLE_NAMES.TAGS),\n        this.getAllFromStore<CounterRecord>(transaction, TABLE_NAMES.COUNTERS),\n        this.getAllFromStore<HistogramRecord>(transaction, TABLE_NAMES.HISTOGRAMS),\n        this.getAllFromStore<EventRecord>(transaction, TABLE_NAMES.EVENTS),\n      ]);\n\n      // Clear all data in the same transaction\n      await Promise.all([\n        this.clearTable(transaction, TABLE_NAMES.COUNTERS),\n        this.clearTable(transaction, TABLE_NAMES.HISTOGRAMS),\n        this.clearTable(transaction, TABLE_NAMES.EVENTS),\n      ]);\n\n      return { tags, counters, histogramStats, events };\n    } catch (error) {\n      this.logger.debug('DiagnosticsStorage: Failed to get all and clear data', error);\n      return { tags: [], counters: [], histogramStats: [], events: [] };\n    }\n  }\n\n  /**\n   * Helper method to get all records from a store within a transaction\n   */\n  /* istanbul ignore next */\n  private getAllFromStore<T>(transaction: IDBTransaction, tableName: string): Promise<T[]> {\n    return new Promise((resolve, reject) => {\n      const store = transaction.objectStore(tableName);\n      const request = store.getAll();\n\n      request.onsuccess = () => resolve(request.result as T[]);\n      request.onerror = () => reject(new Error(`Failed to get all from ${tableName}`));\n    });\n  }\n}\n"
  },
  {
    "path": "packages/analytics-core/src/diagnostics/uncaught-sdk-errors.ts",
    "content": "import { getGlobalScope } from '../global-scope';\nimport { IDiagnosticsClient } from './diagnostics-client';\n\ntype ErrorEventType = 'error' | 'unhandledrejection';\n\ninterface CapturedErrorContext {\n  readonly type: ErrorEventType;\n  readonly message: string;\n  readonly stack?: string;\n  readonly filename?: string;\n  readonly errorName?: string;\n  readonly metadata?: Record<string, unknown>;\n}\n\nexport const GLOBAL_KEY = '__AMPLITUDE_SCRIPT_URL__';\nexport const EVENT_NAME_ERROR_UNCAUGHT = 'sdk.error.uncaught';\n\nconst getNormalizedScriptUrls = (): string[] => {\n  const scope = getGlobalScope() as Record<string, unknown> | null;\n  /* istanbul ignore next */\n  if (!scope) {\n    return [];\n  }\n  const value = scope[GLOBAL_KEY];\n  if (Array.isArray(value)) {\n    return value as string[];\n  }\n  /* istanbul ignore next - legacy single URL stored as string */\n  if (typeof value === 'string') {\n    return [value];\n  }\n  return [];\n};\n\nconst addNormalizedScriptUrl = (url: string) => {\n  const scope = getGlobalScope() as Record<string, unknown> | null;\n  /* istanbul ignore next */\n  if (!scope) {\n    return;\n  }\n  const urls = getNormalizedScriptUrls();\n  if (!urls.includes(url)) {\n    urls.push(url);\n    scope[GLOBAL_KEY] = urls;\n  }\n};\n\nexport const registerSdkLoaderMetadata = (metadata: { scriptUrl?: string }) => {\n  if (metadata.scriptUrl) {\n    const normalized = normalizeUrl(metadata.scriptUrl);\n    if (normalized) {\n      addNormalizedScriptUrl(normalized);\n    }\n  }\n};\n\nexport const enableSdkErrorListeners = (client: IDiagnosticsClient) => {\n  const scope = getGlobalScope();\n\n  if (!scope || typeof scope.addEventListener !== 'function') {\n    return;\n  }\n\n  const handleError = (event: ErrorEvent) => {\n    const error = event.error instanceof Error ? event.error : undefined;\n    const stack = error?.stack;\n    const match = detectSdkOrigin({ filename: event.filename, stack });\n    if (!match) {\n      return;\n    }\n\n    capture({\n      type: 'error',\n      message: event.message,\n      stack,\n      filename: event.filename,\n      errorName: error?.name,\n      metadata: {\n        colno: event.colno,\n        lineno: event.lineno,\n        isTrusted: event.isTrusted,\n        matchReason: match,\n      },\n    });\n  };\n\n  const handleRejection = (event: PromiseRejectionEvent) => {\n    const error = event.reason instanceof Error ? event.reason : undefined;\n    const stack = error?.stack;\n    const filename = extractFilenameFromStack(stack);\n    const match = detectSdkOrigin({ filename, stack });\n\n    if (!match) {\n      return;\n    }\n\n    /* istanbul ignore next */\n    capture({\n      type: 'unhandledrejection',\n      message: error?.message ?? stringifyReason(event.reason),\n      stack,\n      filename,\n      errorName: error?.name,\n      metadata: {\n        isTrusted: event.isTrusted,\n        matchReason: match,\n      },\n    });\n  };\n\n  const capture = (context: CapturedErrorContext) => {\n    client.recordEvent(EVENT_NAME_ERROR_UNCAUGHT, {\n      type: context.type,\n      message: context.message,\n      filename: context.filename,\n      error_name: context.errorName,\n      stack: context.stack,\n      ...context.metadata,\n    });\n  };\n\n  scope.addEventListener('error', handleError, true);\n  scope.addEventListener('unhandledrejection', handleRejection, true);\n};\n\nconst detectSdkOrigin = (payload: { filename?: string; stack?: string }): 'filename' | 'stack' | undefined => {\n  const normalizedScriptUrls = getNormalizedScriptUrls();\n  if (normalizedScriptUrls.length === 0) {\n    return undefined;\n  }\n\n  for (const normalizedScriptUrl of normalizedScriptUrls) {\n    if (payload.filename && payload.filename.includes(normalizedScriptUrl)) {\n      return 'filename';\n    }\n    if (payload.stack && payload.stack.includes(normalizedScriptUrl)) {\n      return 'stack';\n    }\n  }\n\n  return undefined;\n};\n\nconst normalizeUrl = (value: string) => {\n  try {\n    /* istanbul ignore next */\n    const url = new URL(value, getGlobalScope()?.location?.origin);\n    return url.origin + url.pathname;\n  } catch {\n    return undefined;\n  }\n};\n\nconst extractFilenameFromStack = (stack?: string) => {\n  if (!stack) {\n    return undefined;\n  }\n\n  const match = stack.match(/(https?:\\/\\/\\S+?)(?=[)\\s]|$)/);\n  /* istanbul ignore next */\n  return match ? match[1] : undefined;\n};\n\n/* istanbul ignore next */\nconst stringifyReason = (reason: unknown) => {\n  if (typeof reason === 'string') {\n    return reason;\n  }\n\n  try {\n    return JSON.stringify(reason);\n  } catch {\n    return '[object Object]';\n  }\n};\n"
  },
  {
    "path": "packages/analytics-core/src/event-bridge/event-bridge-channel.ts",
    "content": "import { IEventBridgeReceiver } from './event-bridge';\nimport { Event } from '../types/event/event';\n\nconst QUEUE_CAPACITY = 512;\n\nexport class EventBridgeChannel {\n  channel: string;\n  queue: Event[] = [];\n  receiver: IEventBridgeReceiver | undefined;\n\n  constructor(channel: string) {\n    this.channel = channel;\n  }\n\n  sendEvent(event: Event) {\n    if (!this.receiver) {\n      this.queue = [...this.queue.slice(0, QUEUE_CAPACITY), event];\n      return;\n    }\n    this.receiver.receive(this.channel, event);\n  }\n\n  setReceiver(receiver: IEventBridgeReceiver) {\n    if (this.receiver) {\n      return;\n    }\n    this.receiver = receiver;\n    const events = this.queue;\n    this.queue = [];\n    events.forEach((event) => {\n      (this.receiver as IEventBridgeReceiver).receive(this.channel, event);\n    });\n  }\n}\n"
  },
  {
    "path": "packages/analytics-core/src/event-bridge/event-bridge-container.ts",
    "content": "import { EventBridge, IEventBridge } from './event-bridge';\n\nexport class EventBridgeContainer {\n  static instances: Record<string, IEventBridge> = {};\n  static getInstance(instanceName: string): IEventBridge {\n    if (!this.instances[instanceName]) {\n      this.instances[instanceName] = new EventBridge();\n    }\n    return this.instances[instanceName];\n  }\n}\n"
  },
  {
    "path": "packages/analytics-core/src/event-bridge/event-bridge.ts",
    "content": "import { Event } from '../types/event/event';\nimport { EventBridgeChannel } from './event-bridge-channel';\n\nexport interface IEventBridge {\n  sendEvent(channel: string, event: Event): void;\n  setReceiver(channel: string, receiver: IEventBridgeReceiver): void;\n}\n\nexport interface IEventBridgeReceiver {\n  receive(channel: string, event: Event): void;\n}\n\nexport class EventBridge implements IEventBridge {\n  eventBridgeChannels: Record<string, EventBridgeChannel | undefined> = {};\n\n  sendEvent(channel: string, event: Event) {\n    if (!this.eventBridgeChannels[channel]) {\n      this.eventBridgeChannels[channel] = new EventBridgeChannel(channel);\n    }\n    (this.eventBridgeChannels[channel] as EventBridgeChannel).sendEvent(event);\n  }\n\n  setReceiver(channel: string, receiver: IEventBridgeReceiver) {\n    if (!this.eventBridgeChannels[channel]) {\n      this.eventBridgeChannels[channel] = new EventBridgeChannel(channel);\n    }\n    (this.eventBridgeChannels[channel] as EventBridgeChannel).setReceiver(receiver);\n  }\n}\n"
  },
  {
    "path": "packages/analytics-core/src/global-scope.ts",
    "content": "/* eslint-disable no-restricted-globals */\n/* Only file allowed to access to globalThis, window, self */\n\nexport const getGlobalScope = (): typeof globalThis | undefined => {\n  // This should only be used for integrations with Amplitude that are not running in a browser environment\n  //   We need to specify the name of the global variable as a string to prevent it from being minified\n  const ampIntegrationContextName = 'ampIntegrationContext' as keyof typeof globalThis;\n  if (typeof globalThis !== 'undefined' && typeof globalThis[ampIntegrationContextName] !== 'undefined') {\n    return globalThis[ampIntegrationContextName] as typeof globalThis;\n  }\n  if (typeof globalThis !== 'undefined') {\n    return globalThis;\n  }\n  if (typeof window !== 'undefined') {\n    return window;\n  }\n  if (typeof self !== 'undefined') {\n    return self;\n  }\n  if (typeof global !== 'undefined') {\n    return global;\n  }\n  return undefined;\n};\n"
  },
  {
    "path": "packages/analytics-core/src/identify.ts",
    "content": "import { UNSET_VALUE } from './types/constants';\nimport { isValidProperties } from './utils/valid-properties';\n\nexport interface IIdentify {\n  getUserProperties(): IdentifyUserProperties;\n  set(property: string, value: ValidPropertyType): IIdentify;\n  setOnce(property: string, value: ValidPropertyType): IIdentify;\n  append(property: string, value: ValidPropertyType): IIdentify;\n  prepend(property: string, value: ValidPropertyType): IIdentify;\n  postInsert(property: string, value: ValidPropertyType): IIdentify;\n  preInsert(property: string, value: ValidPropertyType): IIdentify;\n  remove(property: string, value: ValidPropertyType): IIdentify;\n  add(property: string, value: number): IIdentify;\n  unset(property: string): IIdentify;\n  clearAll(): IIdentify;\n}\n\nexport class Identify implements IIdentify {\n  protected readonly _propertySet: Set<string> = new Set<string>();\n  protected _properties: IdentifyUserProperties = {};\n\n  public getUserProperties(): IdentifyUserProperties {\n    return { ...this._properties };\n  }\n\n  public set(property: string, value: ValidPropertyType): Identify {\n    this._safeSet(IdentifyOperation.SET, property, value);\n    return this;\n  }\n\n  public setOnce(property: string, value: ValidPropertyType): Identify {\n    this._safeSet(IdentifyOperation.SET_ONCE, property, value);\n    return this;\n  }\n\n  public append(property: string, value: ValidPropertyType): Identify {\n    this._safeSet(IdentifyOperation.APPEND, property, value);\n    return this;\n  }\n\n  public prepend(property: string, value: ValidPropertyType): Identify {\n    this._safeSet(IdentifyOperation.PREPEND, property, value);\n    return this;\n  }\n\n  public postInsert(property: string, value: ValidPropertyType): Identify {\n    this._safeSet(IdentifyOperation.POSTINSERT, property, value);\n    return this;\n  }\n\n  public preInsert(property: string, value: ValidPropertyType): Identify {\n    this._safeSet(IdentifyOperation.PREINSERT, property, value);\n    return this;\n  }\n\n  public remove(property: string, value: ValidPropertyType): Identify {\n    this._safeSet(IdentifyOperation.REMOVE, property, value);\n    return this;\n  }\n\n  public add(property: string, value: number): Identify {\n    this._safeSet(IdentifyOperation.ADD, property, value);\n    return this;\n  }\n\n  public unset(property: string): Identify {\n    this._safeSet(IdentifyOperation.UNSET, property, UNSET_VALUE);\n    return this;\n  }\n\n  public clearAll(): Identify {\n    // When clear all happens, all properties are unset. Reset the entire object.\n    this._properties = {};\n    this._properties[IdentifyOperation.CLEAR_ALL] = UNSET_VALUE;\n\n    return this;\n  }\n\n  // Returns whether or not this set actually worked.\n  private _safeSet(operation: IdentifyOperation, property: string, value: ValidPropertyType): boolean {\n    if (this._validate(operation, property, value)) {\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n      let userPropertyMap: any = this._properties[operation];\n      if (userPropertyMap === undefined) {\n        userPropertyMap = {};\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n        this._properties[operation] = userPropertyMap;\n      }\n\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n      userPropertyMap[property] = value;\n      this._propertySet.add(property);\n      return true;\n    }\n\n    return false;\n  }\n\n  private _validate(operation: IdentifyOperation, property: string, value: ValidPropertyType): boolean {\n    if (this._properties[IdentifyOperation.CLEAR_ALL] !== undefined) {\n      // clear all already set. Skipping operation;\n      return false;\n    }\n\n    if (this._propertySet.has(property)) {\n      // Property already used. Skipping operation\n      return false;\n    }\n\n    if (operation === IdentifyOperation.ADD) {\n      return typeof value === 'number';\n    }\n\n    if (operation !== IdentifyOperation.UNSET && operation !== IdentifyOperation.REMOVE) {\n      return isValidProperties(property, value);\n    }\n    return true;\n  }\n}\n\nexport type ValidPropertyType =\n  | number\n  | string\n  | boolean\n  | Array<string | number>\n  | { [key: string]: ValidPropertyType }\n  | Array<{ [key: string]: ValidPropertyType }>;\n\ninterface BaseOperationConfig {\n  [key: string]: ValidPropertyType;\n}\n\nexport interface IdentifyUserProperties {\n  // Add operations can only take numbers\n  [IdentifyOperation.ADD]?: { [key: string]: number };\n\n  // This reads the keys of the passed object, but the values are not used\n  [IdentifyOperation.UNSET]?: BaseOperationConfig;\n  // This option does not read the key as it unsets all user properties\n  [IdentifyOperation.CLEAR_ALL]?: any;\n\n  // These operations can take numbers, strings, or arrays of both.\n  [IdentifyOperation.SET]?: BaseOperationConfig;\n  [IdentifyOperation.SET_ONCE]?: BaseOperationConfig;\n  [IdentifyOperation.APPEND]?: BaseOperationConfig;\n  [IdentifyOperation.PREPEND]?: BaseOperationConfig;\n  [IdentifyOperation.POSTINSERT]?: BaseOperationConfig;\n  [IdentifyOperation.PREINSERT]?: BaseOperationConfig;\n  [IdentifyOperation.REMOVE]?: BaseOperationConfig;\n}\n\nexport enum IdentifyOperation {\n  // Base Operations to set values\n  SET = '$set',\n  SET_ONCE = '$setOnce',\n\n  // Operations around modifying existing values\n  ADD = '$add',\n  APPEND = '$append',\n  PREPEND = '$prepend',\n  REMOVE = '$remove',\n\n  // Operations around appending values *if* they aren't present\n  PREINSERT = '$preInsert',\n  POSTINSERT = '$postInsert',\n\n  // Operations around removing properties/values\n  UNSET = '$unset',\n  CLEAR_ALL = '$clearAll',\n}\n\n/**\n * Note that the order of operations should align with https://github.com/amplitude/nova/blob/7701b5986b565d4b2fb53b99a9f2175df055dea8/src/main/java/com/amplitude/ingestion/core/UserPropertyUtils.java#L210\n */\nexport const OrderedIdentifyOperations = [\n  IdentifyOperation.CLEAR_ALL,\n  IdentifyOperation.UNSET,\n  IdentifyOperation.SET,\n  IdentifyOperation.SET_ONCE,\n  IdentifyOperation.ADD,\n  IdentifyOperation.APPEND,\n  IdentifyOperation.PREPEND,\n  IdentifyOperation.PREINSERT,\n  IdentifyOperation.POSTINSERT,\n  IdentifyOperation.REMOVE,\n];\n"
  },
  {
    "path": "packages/analytics-core/src/index.ts",
    "content": "export { AmplitudeCore } from './core-client';\nexport { CoreClient, PluginHost } from './types/client/core-client';\nexport { AnalyticsClient } from './types/client/analytics-client';\nexport { AmplitudeContext } from './types/amplitude-context';\nexport { Identify, IIdentify, ValidPropertyType } from './identify';\nexport { Revenue, IRevenue, RevenueProperty } from './revenue';\nexport { Destination } from './plugins/destination';\nexport { IdentityEventSender } from './plugins/identity';\nexport { Config, RequestMetadata } from './config';\nexport { IConfig } from './types/config/core-config';\nexport { Logger, ILogger, LogConfig } from './logger';\nexport { getGlobalScope } from './global-scope';\nexport { getAnalyticsConnector, setConnectorDeviceId, setConnectorUserId } from './analytics-connector';\nexport { isNewSession } from './session';\nexport { getCookieName, getOldCookieName } from './cookie-name';\nexport { getLanguage } from './language';\nexport { getQueryParams } from './query-params';\n\nexport { returnWrapper, AmplitudeReturn } from './utils/return-wrapper';\nexport { debugWrapper, getClientLogConfig, getClientStates } from './utils/debug';\nexport { UUID } from './utils/uuid';\nexport { createIdentifyEvent } from './utils/event-builder';\nexport { isUrlMatchAllowlist, getDecodeURI } from './utils/url-utils';\nexport { generateHashCode, isTimestampInSample } from './utils/sampling';\nexport { omitUndefined } from './utils/omit-undefined';\n\nexport { MemoryStorage } from './storage/memory';\nexport { CookieStorage, isDomainEqual, decodeCookieValue } from './storage/cookie';\nexport { getStorageKey } from './storage/helpers';\n\nexport { BrowserStorage } from './storage/browser-storage';\n\nexport { DiagnosticsClient, IDiagnosticsClient } from './diagnostics/diagnostics-client';\nexport { registerSdkLoaderMetadata } from './diagnostics/uncaught-sdk-errors';\n\nexport { BaseTransport } from './transports/base';\nexport { FetchTransport } from './transports/fetch';\nexport {\n  compressToGzipArrayBuffer,\n  isCompressionStreamAvailable,\n  MIN_GZIP_UPLOAD_BODY_SIZE_BYTES,\n} from './transports/gzip';\n\nexport { RemoteConfigClient, IRemoteConfigClient, RemoteConfig, Source } from './remote-config/remote-config';\n\nexport { LogLevel } from './types/loglevel';\nexport { AMPLITUDE_PREFIX, STORAGE_PREFIX } from './types/constants';\nexport { Storage, IdentityStorageType, CookieStorageConfig } from './types/storage';\nexport { consoleObserver } from './observers/console';\nexport {\n  Event,\n  IdentifyOperation,\n  SpecialEventType,\n  IdentifyEvent,\n  GroupIdentifyEvent,\n  IdentifyUserProperties,\n} from './types/event/event';\nexport { EventOptions, BaseEvent } from './types/event/base-event';\nexport { IngestionMetadata } from './types/event/ingestion-metadata';\nexport { ServerZoneType, ServerZone } from './types/server-zone';\nexport { OfflineDisabled } from './types/offline';\nexport { Plan } from './types/event/plan';\nexport { TransportType, Transport, TransportOptions, TransportTypeOrOptions } from './types/transport';\nexport { Payload } from './types/payload';\nexport { Response } from './types/response';\nexport { UserSession } from './types/user-session';\nexport {\n  Plugin,\n  BeforePlugin,\n  DestinationPlugin,\n  EnrichmentPlugin,\n  PluginType,\n  AnalyticsIdentity,\n} from './types/plugin';\nexport { Result } from './types/result';\nexport {\n  ElementInteractionsOptions,\n  Messenger,\n  ActionType,\n  DEFAULT_CSS_SELECTOR_ALLOWLIST,\n  DEFAULT_DATA_ATTRIBUTE_PREFIX,\n  DEFAULT_ACTION_CLICK_ALLOWLIST,\n  DEFAULT_EXPOSURE_DURATION,\n  LabeledEvent,\n  Trigger,\n  DataSource,\n} from './types/element-interactions';\n\nexport {\n  FrustrationInteractionsOptions,\n  DEFAULT_DEAD_CLICK_ALLOWLIST,\n  DEFAULT_RAGE_CLICK_ALLOWLIST,\n  DEFAULT_ERROR_CLICK_ALLOWLIST,\n  DEFAULT_RAGE_CLICK_THRESHOLD,\n  DEFAULT_RAGE_CLICK_WINDOW_MS,\n  DEFAULT_RAGE_CLICK_OUT_OF_BOUNDS_THRESHOLD,\n  DEFAULT_DEAD_CLICK_WINDOW_MS,\n} from './types/frustration-interactions';\nexport { PageTrackingOptions, PageTrackingTrackOn, PageTrackingHistoryChanges } from './types/page-view-tracking';\nexport { FormInteractionsOptions } from './types/form-interactions';\nexport { Status } from './types/status';\n\nexport { NetworkEventCallback, networkObserver } from './observers/network';\nexport { NetworkRequestEvent, IRequestWrapper, JsonObject, JsonValue, JsonArray } from './network-request-event';\nexport { NetworkTrackingOptions, NetworkCaptureRule } from './types/network-tracking';\nexport { SAFE_HEADERS, FORBIDDEN_HEADERS } from './types/constants';\n\nexport { PageUrlEnrichmentOptions } from './types/page-url-enrichment';\nexport { CustomEnrichmentOptions } from './types/custom-enrichment';\nexport { PerformanceTrackingOptions, MainThreadBlockOptions } from './types/performance-tracking';\n\n// Campaign\nexport { Campaign, UTMParameters, ReferrerParameters, ClickIdParameters, ICampaignParser } from './types/campaign';\nexport { EMPTY_VALUE, BASE_CAMPAIGN, MKTG } from './types/constants';\nexport { CampaignParser } from './campaign/campaign-parser';\nexport {\n  getPageTitle,\n  TEXT_MASK_ATTRIBUTE,\n  MASKED_TEXT_VALUE,\n  replaceSensitiveString,\n  CC_REGEX,\n  SSN_REGEX,\n  EMAIL_REGEX,\n} from './plugins/helpers';\n\n// Browser\nexport {\n  BrowserConfig,\n  BrowserOptions,\n  DefaultTrackingOptions,\n  TrackingOptions,\n  TrackingMethod,\n  AutocaptureOptions,\n  CookieOptions,\n  AttributionOptions,\n  RemoteConfigOptions,\n} from './types/config/browser-config';\nexport { BrowserClient } from './types/client/browser-client';\n\n// Node\nexport { NodeClient } from './types/client/node-client';\nexport { NodeConfig, NodeOptions } from './types/config/node-config';\n\n// React Native\nexport {\n  ReactNativeConfig,\n  ReactNativeTrackingOptions,\n  ReactNativeOptions,\n  ReactNativeAttributionOptions,\n} from './types/config/react-native-config';\nexport { ReactNativeClient } from './types/client/react-native-client';\n\nexport { Observable, asyncMap, merge, multicast, Unsubscribable } from './utils/observable';\n\nexport { InstanceProxy } from './types/proxy';\nexport { safeJsonStringify } from './utils/safe-stringify';\n\n// Messenger (cross-window communication)\nexport type { BaseWindowMessenger, ActionHandler } from './messenger/base-window-messenger';\nexport { getOrCreateWindowMessenger } from './messenger/base-window-messenger';\nexport { enableBackgroundCapture } from './messenger/background-capture';\nexport {\n  AMPLITUDE_ORIGIN,\n  AMPLITUDE_ORIGIN_EU,\n  AMPLITUDE_ORIGIN_STAGING,\n  AMPLITUDE_ORIGINS_MAP,\n  AMPLITUDE_BACKGROUND_CAPTURE_SCRIPT_URL,\n} from './messenger/constants';\n\nexport { ExcludeInternalReferrersOptions, EXCLUDE_INTERNAL_REFERRERS_CONDITIONS } from './types/config/browser-config';\n\nexport { VideoObserver, State as VideoState, type VideoObserverParams } from './observers/video';\nexport { EmbeddedVideoPlayer, type Vendor as VideoVendor } from './video-analytics/types';\nexport { isChromeExtension } from './utils/environment';\n"
  },
  {
    "path": "packages/analytics-core/src/language.ts",
    "content": "export const getLanguage = (): string => {\n  if (typeof navigator === 'undefined') return '';\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n  const userLanguage = (navigator as any).userLanguage as string | undefined;\n\n  return navigator.languages?.[0] ?? navigator.language ?? userLanguage ?? '';\n};\n"
  },
  {
    "path": "packages/analytics-core/src/logger.ts",
    "content": "import { LogLevel } from './types/loglevel';\n\nconst PREFIX = 'Amplitude Logger ';\n\nexport interface ILogger {\n  disable(): void;\n  enable(logLevel: LogLevel): void;\n  log(...args: any[]): void;\n  warn(...args: any[]): void;\n  error(...args: any[]): void;\n  debug(...args: any[]): void;\n}\n\nexport interface LogConfig {\n  logger: ILogger;\n  logLevel: LogLevel;\n}\n\ntype TimeKey = 'start' | 'end';\n\nexport interface DebugContext {\n  type: string;\n  name: string;\n  args: string[] | string;\n  stacktrace?: string[] | string;\n  time?: { [key in TimeKey]?: string };\n  states?: { [key: string]: any };\n}\n\nexport class Logger implements ILogger {\n  logLevel: LogLevel;\n\n  constructor() {\n    this.logLevel = LogLevel.None;\n  }\n\n  disable(): void {\n    this.logLevel = LogLevel.None;\n  }\n\n  enable(logLevel: LogLevel = LogLevel.Warn): void {\n    this.logLevel = logLevel;\n  }\n\n  log(...args: any[]): void {\n    if (this.logLevel < LogLevel.Verbose) {\n      return;\n    }\n    console.log(`${PREFIX}[Log]: ${args.join(' ')}`);\n  }\n\n  warn(...args: any[]): void {\n    if (this.logLevel < LogLevel.Warn) {\n      return;\n    }\n    console.warn(`${PREFIX}[Warn]: ${args.join(' ')}`);\n  }\n\n  error(...args: any[]): void {\n    if (this.logLevel < LogLevel.Error) {\n      return;\n    }\n    console.error(`${PREFIX}[Error]: ${args.join(' ')}`);\n  }\n\n  debug(...args: any[]): void {\n    if (this.logLevel < LogLevel.Debug) {\n      return;\n    }\n    // console.debug output is hidden by default in chrome\n    console.log(`${PREFIX}[Debug]: ${args.join(' ')}`);\n  }\n}\n"
  },
  {
    "path": "packages/analytics-core/src/messenger/background-capture.ts",
    "content": "/* eslint-disable no-restricted-globals */\nimport type { BaseWindowMessenger } from './base-window-messenger';\nimport { AMPLITUDE_BACKGROUND_CAPTURE_SCRIPT_URL } from './constants';\n\n/**\n * Brand key set on the messenger instance to track whether background capture\n * has been enabled.\n */\nconst BG_CAPTURE_BRAND = '__AMPLITUDE_BACKGROUND_CAPTURE__' as const;\n\n/**\n * Enable background capture on a messenger instance.\n * Plugins can call this on a shared messenger instance.\n * The first call registers the handlers; subsequent calls are no-ops.\n *\n * @param messenger - The messenger to enable background capture on\n * @param options.scriptUrl - Override the background capture script URL (optional)\n */\nexport function enableBackgroundCapture(messenger: BaseWindowMessenger, options?: { scriptUrl?: string }): void {\n  // Check the brand on the messenger object itself — works across bundle boundaries\n  const branded = messenger as unknown as Record<string, unknown>;\n  if (branded[BG_CAPTURE_BRAND] === true) {\n    return;\n  }\n  branded[BG_CAPTURE_BRAND] = true;\n\n  const scriptUrl = options?.scriptUrl ?? AMPLITUDE_BACKGROUND_CAPTURE_SCRIPT_URL;\n  let backgroundCaptureInstance: any = null;\n\n  const onBackgroundCapture = (type: string, backgroundCaptureData: { [key: string]: string | number | null }) => {\n    if (type === 'background-capture-complete') {\n      messenger.logger?.debug?.('Background capture complete');\n      messenger.notify({ action: 'background-capture-complete', data: backgroundCaptureData });\n    }\n  };\n\n  messenger.registerActionHandler('initialize-background-capture', () => {\n    messenger.logger?.debug?.('Initializing background capture (external script)');\n    const resolvedUrl = new URL(scriptUrl, messenger.endpoint).toString();\n\n    messenger\n      .loadScriptOnce(resolvedUrl)\n      .then(() => {\n        messenger.logger?.debug?.('Background capture script loaded (external)');\n        // eslint-disable-next-line\n        backgroundCaptureInstance = /* istanbul ignore next -- window is always defined in browser */ (\n          window as any\n        )?.amplitudeBackgroundCapture?.({\n          messenger,\n          onBackgroundCapture,\n        });\n        messenger.notify({ action: 'background-capture-loaded' });\n      })\n      .catch(() => {\n        messenger.logger?.warn('Failed to initialize background capture');\n      });\n  });\n\n  messenger.registerActionHandler('close-background-capture', () => {\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call\n    backgroundCaptureInstance?.close?.();\n    backgroundCaptureInstance = null;\n  });\n}\n"
  },
  {
    "path": "packages/analytics-core/src/messenger/base-window-messenger.ts",
    "content": "/* eslint-disable no-restricted-globals */\nimport { ILogger } from '../logger';\nimport { Messenger } from '../types/element-interactions';\nimport { getGlobalScope } from '../global-scope';\nimport { AMPLITUDE_ORIGIN } from './constants';\nimport { asyncLoadScript, generateUniqueId } from './utils';\n\ntype MessageRequest = {\n  id: string;\n  action: string;\n  args: Record<string, any>;\n};\n\ntype MessageResponse = {\n  id: string;\n  action: string;\n  responseData: any;\n};\n\nexport type ActionHandler = (data: any) => void;\n\n/**\n * Brand key used to identify BaseWindowMessenger instances across bundle boundaries.\n */\nconst MESSENGER_BRAND = '__AMPLITUDE_MESSENGER_INSTANCE__' as const;\n\n/** Global scope key where the singleton messenger is stored. */\nconst MESSENGER_GLOBAL_KEY = '__AMPLITUDE_MESSENGER__';\n\n/**\n * BaseWindowMessenger provides generic cross-window communication via postMessage.\n * Singleton access via getOrCreateWindowMessenger() to prevent duplicate instances\n */\nclass BaseWindowMessenger implements Messenger {\n  /** Brand property for cross-bundle instanceof checks. */\n  readonly [MESSENGER_BRAND] = true;\n\n  endpoint: string;\n  logger?: ILogger;\n  private isSetup = false;\n  private messageHandler: ((event: MessageEvent) => void) | null = null;\n  requestCallbacks: {\n    [id: string]: {\n      resolve: (data: any) => void;\n      reject: (data: any) => void;\n    };\n  } = {};\n  private actionHandlers = new Map<string, ActionHandler>();\n\n  /**\n   * Messages received for actions that had no registered handler yet.\n   * Drained automatically when the corresponding handler is registered via\n   * registerActionHandler(), solving startup race conditions between\n   * independently-initialized plugins.\n   */\n  private pendingMessages = new Map<string, any[]>();\n\n  /**\n   * Tracks in-flight and completed script loads by URL.\n   * Using a map, this prevents duplicate loads before the first resolves.\n   */\n  private scriptLoadPromises = new Map<string, Promise<void>>();\n\n  constructor({ origin = AMPLITUDE_ORIGIN }: { origin?: string } = {}) {\n    this.endpoint = origin;\n  }\n\n  /**\n   * Send a message to the parent window (window.opener).\n   */\n  notify(message: { action: string; data?: any } | MessageRequest) {\n    this.logger?.debug?.('Message sent: ', JSON.stringify(message));\n    (window.opener as WindowProxy)?.postMessage?.(message, this.endpoint);\n  }\n\n  /**\n   * Send an async request to the parent window with a unique ID.\n   * Returns a Promise that resolves when the parent responds.\n   */\n  public sendRequest(action: string, args: Record<string, any>, options = { timeout: 15_000 }): Promise<any> {\n    const id = generateUniqueId();\n    const request: MessageRequest = { id, action, args };\n\n    const promise = new Promise((resolve, reject) => {\n      this.requestCallbacks[id] = { resolve, reject };\n\n      this.notify(request);\n\n      if (options.timeout > 0) {\n        setTimeout(() => {\n          reject(new Error(`${action} timed out (id: ${id})`));\n          delete this.requestCallbacks[id];\n        }, options.timeout);\n      }\n    });\n\n    return promise;\n  }\n\n  /**\n   * Handle a response to a previous request by resolving its Promise.\n   */\n  private handleResponse(response: MessageResponse) {\n    if (!this.requestCallbacks[response.id]) {\n      this.logger?.warn(`No callback found for request id: ${response.id}`);\n      return;\n    }\n\n    this.requestCallbacks[response.id].resolve(response.responseData);\n    delete this.requestCallbacks[response.id];\n  }\n\n  /**\n   * Register a handler for a specific action type.\n   * Logs a warning if overwriting an existing handler.\n   */\n  registerActionHandler(action: string, handler: ActionHandler) {\n    if (this.actionHandlers.has(action)) {\n      this.logger?.warn?.(`Overwriting existing action handler for: ${action}`);\n    }\n    this.actionHandlers.set(action, handler);\n\n    // Replay any messages that arrived before this handler was registered\n    const queued = this.pendingMessages.get(action);\n    if (queued) {\n      this.pendingMessages.delete(action);\n      for (const data of queued) {\n        handler(data);\n      }\n    }\n  }\n\n  /**\n   * Load a script once, deduplicating by URL.\n   * Safe against concurrent calls — the second call awaits the first's in-flight Promise\n   * rather than triggering a duplicate load.\n   */\n  async loadScriptOnce(url: string): Promise<void> {\n    const existing = this.scriptLoadPromises.get(url);\n    if (existing) {\n      return existing;\n    }\n\n    const loadPromise = asyncLoadScript(url).then(() => {\n      // Resolve to void\n    });\n    this.scriptLoadPromises.set(url, loadPromise);\n\n    try {\n      await loadPromise;\n    } catch (error) {\n      // Remove failed loads so they can be retried\n      this.scriptLoadPromises.delete(url);\n      throw error;\n    }\n  }\n\n  /**\n   * Set up the message listener. Idempotent — safe to call multiple times.\n   * Subclasses should call super.setup() and then register their own action handlers.\n   */\n  setup({ logger, endpoint }: { logger?: ILogger; endpoint?: string } = {}) {\n    if (logger) {\n      this.logger = logger;\n    }\n\n    // If endpoint is customized, don't override a previously customized endpoint.\n    if (endpoint && this.endpoint === AMPLITUDE_ORIGIN) {\n      this.endpoint = endpoint;\n    }\n\n    // Only attach the message listener once\n    if (this.isSetup) {\n      return;\n    }\n    this.isSetup = true;\n\n    this.logger?.debug?.('Setting up messenger');\n\n    // Attach Event Listener to listen for messages from the parent window\n    this.messageHandler = (event: MessageEvent) => {\n      this.logger?.debug?.('Message received: ', JSON.stringify(event));\n\n      // Only accept messages from the specified origin\n      if (this.endpoint !== event.origin) {\n        return;\n      }\n\n      const eventData = event.data as { action?: string; id?: string; data?: any; responseData?: any };\n      const action = eventData?.action;\n\n      // Ignore messages without action\n      if (!action) {\n        return;\n      }\n\n      // If id exists, handle responses to previous requests\n      if ('id' in eventData && eventData.id) {\n        this.logger?.debug?.('Received Response to previous request: ', JSON.stringify(event));\n        this.handleResponse(eventData as MessageResponse);\n      } else {\n        if (action === 'ping') {\n          this.notify({ action: 'pong' });\n          return;\n        }\n\n        // Dispatch to registered action handlers, or buffer for late registration\n        const handler = this.actionHandlers.get(action);\n        if (handler) {\n          handler(eventData.data);\n        } else {\n          const queue = this.pendingMessages.get(action) ?? [];\n          queue.push(eventData.data);\n          this.pendingMessages.set(action, queue);\n        }\n      }\n    };\n    window.addEventListener('message', this.messageHandler);\n\n    this.notify({ action: 'page-loaded' });\n  }\n\n  /**\n   * Tear down the messenger: remove the message listener, clear all state.\n   */\n  destroy() {\n    if (this.messageHandler) {\n      window.removeEventListener('message', this.messageHandler);\n      this.messageHandler = null;\n    }\n    this.isSetup = false;\n    this.actionHandlers.clear();\n    this.pendingMessages.clear();\n    this.requestCallbacks = {};\n    this.scriptLoadPromises.clear();\n\n    // Remove from global scope if this is the singleton\n    const globalScope = getGlobalScope() as Record<string, unknown> | undefined;\n    if (globalScope?.[MESSENGER_GLOBAL_KEY] === this) {\n      delete globalScope[MESSENGER_GLOBAL_KEY];\n    }\n  }\n}\n\n/**\n * Type guard: checks whether a value is a BaseWindowMessenger instance.\n */\nfunction isWindowMessenger(value: unknown): value is BaseWindowMessenger {\n  return (\n    typeof value === 'object' &&\n    value !== null &&\n    MESSENGER_BRAND in value &&\n    (value as Record<string, unknown>)[MESSENGER_BRAND] === true\n  );\n}\n\n/**\n * Get or create a singleton BaseWindowMessenger instance.\n * Ensures only one messenger (and one message listener) exists per page,\n * preventing duplicate script loads and double notifications.\n *\n * The singleton is stored on globalScope under the same MESSENGER_KEY.\n * The branded property check verifies the stored value is actually a messenger.\n */\nexport function getOrCreateWindowMessenger(options?: { origin?: string }): BaseWindowMessenger {\n  const globalScope = getGlobalScope() as Record<string, unknown> | undefined;\n\n  const existing = globalScope?.[MESSENGER_GLOBAL_KEY];\n  if (isWindowMessenger(existing)) {\n    return existing;\n  }\n\n  const messenger = new BaseWindowMessenger(options);\n  if (globalScope) {\n    globalScope[MESSENGER_GLOBAL_KEY] = messenger;\n  }\n  return messenger;\n}\n\nexport type { BaseWindowMessenger };\n"
  },
  {
    "path": "packages/analytics-core/src/messenger/constants.ts",
    "content": "// Shared origin constants for Amplitude cross-window communication\nexport const AMPLITUDE_ORIGIN = 'https://app.amplitude.com';\nexport const AMPLITUDE_ORIGIN_EU = 'https://app.eu.amplitude.com';\nexport const AMPLITUDE_ORIGIN_STAGING = 'https://apps.stag2.amplitude.com';\nexport const AMPLITUDE_ORIGINS_MAP: Record<string, string> = {\n  US: AMPLITUDE_ORIGIN,\n  EU: AMPLITUDE_ORIGIN_EU,\n  STAGING: AMPLITUDE_ORIGIN_STAGING,\n};\n\n// Background capture script URL (shared between autocapture and session-replay)\nexport const AMPLITUDE_BACKGROUND_CAPTURE_SCRIPT_URL = 'https://cdn.amplitude.com/libs/background-capture-1.0.1.js.gz';\n"
  },
  {
    "path": "packages/analytics-core/src/messenger/utils.ts",
    "content": "/* eslint-disable no-restricted-globals */\n\n/**\n * Dynamically loads an external script by appending a <script> tag to the document head.\n * Deduplicates by checking if a script with the same src already exists.\n */\nexport const asyncLoadScript = (url: string): Promise<{ status: boolean }> => {\n  // Dedup: if a script with this src already exists, resolve immediately\n  const existing = document.querySelector(`script[src=\"${CSS.escape(url)}\"]`);\n  if (existing) {\n    return Promise.resolve({ status: true });\n  }\n\n  return new Promise((resolve, reject) => {\n    try {\n      const scriptElement = document.createElement('script');\n      scriptElement.type = 'text/javascript';\n      scriptElement.async = true;\n      scriptElement.src = url;\n      scriptElement.addEventListener(\n        'load',\n        () => {\n          resolve({ status: true });\n        },\n        { once: true },\n      );\n      scriptElement.addEventListener('error', () => {\n        reject({\n          status: false,\n          message: `Failed to load the script ${url}`,\n        });\n      });\n      /* istanbul ignore next */\n      document.head?.appendChild(scriptElement);\n    } catch (error) {\n      /* istanbul ignore next */\n      reject(error);\n    }\n  });\n};\n\n/**\n * Generates a simple unique ID for message request/response correlation.\n */\nexport function generateUniqueId(): string {\n  return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n}\n"
  },
  {
    "path": "packages/analytics-core/src/network-request-event.ts",
    "content": "import { getGlobalScope } from './global-scope';\nimport { pruneJson } from './utils/json-query';\nimport { SAFE_HEADERS, FORBIDDEN_HEADERS } from './types/constants';\n\n/* SAFE TYPE DEFINITIONS\n  These type definitions expose limited properties of the original types\n  to prevent the consumer from mutating them or consuming them.\n*/\ntype BlobSafe = {\n  size: number;\n};\n\ntype ArrayBufferSafe = {\n  byteLength: number;\n};\n\ntype ArrayBufferViewSafe = {\n  byteLength: number;\n};\n\ntype URLSearchParamsSafe = {\n  toString(): string;\n};\n\n// no method on readablestream is safe to call\ntype ReadableStreamSafe = Record<string, never>;\n\ntype FormDataEntryValueSafe = string | BlobSafe | null;\n\ntype BodyInitSafe =\n  | string\n  | Blob\n  | ArrayBufferSafe\n  | FormDataSafe\n  | URLSearchParamsSafe\n  | ArrayBufferViewSafe\n  | null\n  | undefined;\n\ntype HeadersRequestSafe = {\n  entries(): IterableIterator<[string, string]>;\n  forEach(callbackfn: (value: string, key: string) => void): void;\n};\n\ntype HeadersResponseSafe = {\n  get(name: string): string | null;\n  forEach(callbackfn: (value: string, key: string) => void): void;\n};\n\ntype HeadersInitSafe = HeadersRequestSafe | Record<string, string> | string[][];\n\ntype ResponseSafe = {\n  status: number;\n  headers: HeadersResponseSafe | undefined;\n  clone(): ResponseCloneSafe;\n};\n\ntype ResponseCloneSafe = {\n  text(): Promise<string>;\n};\n\nconst TEXT_READ_TIMEOUT = 500;\n\nexport type RequestInitSafe = {\n  method?: string;\n  headers?: HeadersInitSafe;\n  body?: BodyInitSafe;\n};\nexport interface FormDataSafe {\n  entries(): IterableIterator<[string, FormDataEntryValueSafe]>;\n}\nexport type XMLHttpRequestBodyInitSafe = BlobSafe | FormDataSafe | URLSearchParamsSafe | string;\n\nexport type FetchRequestBody =\n  | string\n  | BlobSafe\n  | ArrayBufferSafe\n  | FormDataSafe\n  | URLSearchParamsSafe\n  | ArrayBufferViewSafe\n  | null\n  | undefined;\n\nexport interface IRequestWrapper {\n  /**\n   * Get the headers of the request.\n   * @param allow - The headers to allow.\n   * @returns The pruned headers\n   */\n  headers(allow?: string[]): Record<string, string> | undefined;\n  bodySize?: number;\n  method?: string;\n  body?: FetchRequestBody | XMLHttpRequestBodyInitSafe | null;\n  json: (allow?: string[], exclude?: string[]) => Promise<JsonObject | null>;\n}\n\nexport const MAXIMUM_ENTRIES = 100;\n\n/**\n * This class encapsulates the RequestInit (https://developer.mozilla.org/en-US/docs/Web/API/RequestInit)\n * object so that the consumer can only get access to the headers, method and body size.\n *\n * This is to prevent consumers from directly accessing the Request object\n * and mutating it or running costly operations on it.\n *\n * IMPORTANT:\n *    * Do not make changes to this class without careful consideration\n *      of performance implications, memory usage and potential to mutate the customer's\n *      request.\n *   * NEVER .clone() the RequestInit object. This will 2x's the memory overhead of the request\n *   * NEVER: call .arrayBuffer(), text(), json() or any other method on the body that\n *     consumes the body's stream. This will cause the response to be consumed\n *     meaning the body will be empty when the customer tries to access it.\n *     (ie: if the body is an instanceof https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream\n *      never call any of the methods on it)\n */\nexport class RequestWrapperFetch implements IRequestWrapper {\n  private _bodySize: number | undefined;\n  constructor(private request: RequestInitSafe) {}\n\n  headers(allow: string[] = []): Record<string, string> | undefined {\n    const headersUnsafe = this.request.headers;\n\n    // copy the headers into a new object\n    const headersSafeCopy: Record<string, string> = {};\n    if (Array.isArray(headersUnsafe)) {\n      headersUnsafe.forEach(([headerName, headerValue]) => {\n        headersSafeCopy[headerName] = headerValue;\n      });\n    } else if (headersUnsafe instanceof Headers) {\n      headersUnsafe.forEach((value: string, key: string) => {\n        headersSafeCopy[key] = value;\n      });\n    } else if (typeof headersUnsafe === 'object' && headersUnsafe !== null) {\n      for (const [key, value] of Object.entries(headersUnsafe as Record<string, string>)) {\n        headersSafeCopy[key] = value;\n      }\n    }\n\n    return pruneHeaders(headersSafeCopy, { allow });\n  }\n\n  get bodySize(): number | undefined {\n    if (typeof this._bodySize === 'number') return this._bodySize;\n    const global = getGlobalScope();\n\n    /* istanbul ignore if */\n    if (!global?.TextEncoder) {\n      return;\n    }\n    const body = this.request.body as FetchRequestBody;\n    this._bodySize = getBodySize(body, MAXIMUM_ENTRIES);\n    return this._bodySize;\n  }\n\n  get method(): string | undefined {\n    return this.request.method;\n  }\n\n  get body(): string | null {\n    if (typeof this.request.body === 'string') {\n      return this.request.body;\n    }\n    return null;\n  }\n\n  async json(allow: string[] = [], exclude: string[] = []): Promise<JsonObject | null> {\n    if (allow.length === 0) {\n      return null;\n    }\n    const text = this.body;\n    return safeParseAndPruneBody(text, allow, exclude);\n  }\n}\n\nexport class RequestWrapperXhr implements IRequestWrapper {\n  constructor(readonly bodyRaw: XMLHttpRequestBodyInitSafe | null, readonly requestHeaders: Record<string, string>) {}\n\n  headers(allow: string[] = []): Record<string, string> | undefined {\n    return pruneHeaders(this.requestHeaders, { allow });\n  }\n\n  get bodySize(): number | undefined {\n    return getBodySize(this.bodyRaw as FetchRequestBody, MAXIMUM_ENTRIES);\n  }\n\n  get body(): string | null {\n    if (typeof this.bodyRaw === 'string') {\n      return this.bodyRaw;\n    }\n    return null;\n  }\n\n  async json(allow: string[] = [], exclude: string[] = []): Promise<JsonObject | null> {\n    if (allow.length === 0) {\n      return null;\n    }\n    const text = this.body;\n    return safeParseAndPruneBody(text, allow, exclude);\n  }\n}\n\nfunction getBodySize(bodyUnsafe: FetchRequestBody, maxEntries: number): number | undefined {\n  let bodySize: number | undefined;\n  const global = getGlobalScope();\n  /* istanbul ignore next */\n  const TextEncoder = global?.TextEncoder;\n  /* istanbul ignore next */\n  if (!TextEncoder) {\n    return;\n  }\n  let bodySafe;\n  if (typeof bodyUnsafe === 'string') {\n    bodySafe = bodyUnsafe;\n    bodySize = new TextEncoder().encode(bodySafe).length;\n  } else if (bodyUnsafe instanceof Blob) {\n    bodySafe = bodyUnsafe as BlobSafe;\n    bodySize = bodySafe.size;\n  } else if (bodyUnsafe instanceof URLSearchParams) {\n    bodySafe = bodyUnsafe as URLSearchParamsSafe;\n    bodySize = new TextEncoder().encode(bodySafe.toString()).length;\n  } else if (ArrayBuffer.isView(bodyUnsafe)) {\n    bodySafe = bodyUnsafe as ArrayBufferViewSafe;\n    bodySize = bodySafe.byteLength;\n  } else if (bodyUnsafe instanceof ArrayBuffer) {\n    bodySafe = bodyUnsafe as ArrayBufferSafe;\n    bodySize = bodySafe.byteLength;\n  } else if (bodyUnsafe instanceof FormData) {\n    // Estimating only for text parts; not accurate for files\n    const formData = bodyUnsafe as unknown as FormDataSafe;\n\n    let total = 0;\n    let count = 0;\n    for (const [key, value] of formData.entries()) {\n      total += key.length;\n      if (typeof value === 'string') {\n        total += new TextEncoder().encode(value).length;\n      } else if (value instanceof Blob) {\n        total += value.size;\n      } else {\n        // encountered an unknown type\n        // we can't estimate the size of this entry\n        return;\n      }\n      // terminate if we reach the maximum number of entries\n      // to avoid performance issues in case of very large FormData\n      if (++count >= maxEntries) {\n        return;\n      }\n    }\n    bodySize = total;\n  } else if (bodyUnsafe instanceof ReadableStream) {\n    // If bodyUnsafe is an instanceof ReadableStream, we can't determine the size,\n    // without consuming it, so we return undefined.\n    // Never ever consume ReadableStream! DO NOT DO IT!!!\n    // eslint-disable-next-line @typescript-eslint/no-unused-vars\n    bodySafe = bodyUnsafe as unknown as ReadableStreamSafe;\n    return;\n  }\n  return bodySize;\n}\n\nexport type JsonObject = {\n  [key: string]: JsonValue;\n};\n\nexport type JsonValue = string | number | boolean | null | JsonObject | JsonArray;\n\nexport type JsonArray = Array<JsonValue>;\n\nexport interface IResponseWrapper {\n  /**\n   * Get the headers of the response.\n   * @param allow - The headers to allow.\n   * @returns The pruned headers\n   */\n  headers(allow?: string[]): Record<string, string> | undefined;\n  bodySize?: number;\n  status?: number;\n  body?: string | Blob | ReadableStream | ArrayBuffer | FormDataSafe | URLSearchParams | ArrayBufferView | null;\n  json: (allow?: string[], exclude?: string[]) => Promise<JsonObject | null>;\n}\n\n/**\n * This class encapsulates the Fetch API Response object\n * (https://developer.mozilla.org/en-US/docs/Web/API/Response) so that the consumer can\n * only get access to the headers and body size.\n *\n * This is to prevent consumers from directly accessing the Response object\n * and mutating it or running costly operations on it.\n *\n * IMPORTANT:\n *   * Do not make changes to this class without careful consideration\n *     of performance implications, memory usage and potential to mutate the customer's\n *     response.\n *   * Do not .clone() the Response object unless you need to access the body.\n *     Cloning will 2x the memory overhead of the response.\n *   * NEVER consume the body's stream. This will cause the response to be consumed\n *     meaning the body will be empty when the customer tries to access it.\n *     (ie: if the body is an instanceof https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream\n *      never call any of the methods on it)\n */\nexport class ResponseWrapperFetch implements IResponseWrapper {\n  private _bodySize: number | undefined;\n  private clonedResponse?: ResponseCloneSafe;\n  constructor(private response: ResponseSafe) {}\n\n  headers(allow: string[] = []): Record<string, string> | undefined {\n    if (this.response.headers instanceof Headers) {\n      const headersSafe = this.response.headers as HeadersResponseSafe;\n      const headersOut: Record<string, string> = {};\n      /* istanbul ignore next */\n      headersSafe?.forEach?.((value, key) => {\n        headersOut[key] = value;\n      });\n      return pruneHeaders(headersOut, { allow });\n    }\n\n    return;\n  }\n\n  get bodySize(): number | undefined {\n    if (this._bodySize !== undefined) return this._bodySize;\n    /* istanbul ignore next */\n    const contentLength = this.response.headers?.get?.('content-length');\n    const bodySize = contentLength ? parseInt(contentLength, 10) : undefined;\n    this._bodySize = bodySize;\n    return bodySize;\n  }\n\n  get status(): number {\n    return this.response.status;\n  }\n\n  async text(): Promise<string | null> {\n    // !!!IMPORTANT: we clone the response to avoid mutating the original response\n    // never call .text(), .json(), etc.. on the original response always clone it first\n    if (!this.clonedResponse) {\n      this.clonedResponse = this.response.clone();\n    }\n    try {\n      const textPromise = this.clonedResponse.text();\n      const timer = new Promise<null>((resolve) =>\n        setTimeout(\n          /* istanbul ignore next */\n          () => resolve(null),\n          TEXT_READ_TIMEOUT,\n        ),\n      );\n      const text = await Promise.race<string | null>([textPromise, timer]);\n      return text;\n    } catch (error) {\n      return null;\n    }\n  }\n\n  async json(allow: string[] = [], exclude: string[] = []): Promise<JsonObject | null> {\n    if (allow.length === 0) {\n      return null;\n    }\n    const text = await this.text();\n    return safeParseAndPruneBody(text, allow, exclude);\n  }\n}\n\nexport class ResponseWrapperXhr implements IResponseWrapper {\n  constructor(\n    readonly statusCode: number,\n    readonly headersString: string,\n    readonly size: number | undefined,\n    readonly getJson: () => any | null,\n  ) {}\n\n  get bodySize(): number | undefined {\n    return this.size;\n  }\n\n  get status(): number {\n    return this.statusCode;\n  }\n\n  headers(allow: string[] = []): Record<string, string> | undefined {\n    if (!this.headersString) {\n      return {};\n    }\n    const headers: Record<string, string> = {};\n    const headerLines = this.headersString.split('\\r\\n');\n    for (const line of headerLines) {\n      const [key, value] = line.split(': ');\n      if (key && value) {\n        headers[key] = value;\n      }\n    }\n    return pruneHeaders(headers, { allow });\n  }\n\n  async json(allow: string[] = [], exclude: string[] = []): Promise<JsonObject | null> {\n    if (allow.length === 0) {\n      return null;\n    }\n    const jsonBody = this.getJson() as JsonObject | null;\n    if (jsonBody) {\n      pruneJson(jsonBody, allow, exclude);\n      return jsonBody;\n    }\n    return null;\n  }\n}\n\nfunction safeParseAndPruneBody(text: string | null, allow: string[], exclude: string[]): JsonObject | null {\n  if (!text) return null;\n  try {\n    const json = JSON.parse(text) as JsonObject;\n    pruneJson(json, allow, exclude);\n    return json;\n  } catch (error) {\n    return null;\n  }\n}\n\nexport enum PRUNE_STRATEGY {\n  REDACT = 'redact',\n  REMOVE = 'remove',\n}\n\nconst REDACTED_VALUE = '[REDACTED]';\n\n/**\n * Prune headers from a headers record object.\n * @param headers - The headers to prune.\n * @param options - The options to prune the headers.\n * @param options.exclude - List of headers to delete from headers\n * @param options.include - List of headers to keep in headers, if not provided, all headers are kept by default\n * @returns The pruned headers.\n */\nexport const pruneHeaders = (\n  headers: Record<string, string>,\n  options: {\n    allow?: string[];\n    strategy?: PRUNE_STRATEGY;\n  },\n): Record<string, string> => {\n  const { allow = [], strategy = PRUNE_STRATEGY.REMOVE } = options;\n  const exclude = [...FORBIDDEN_HEADERS];\n  const headersPruned: Record<string, string> = {};\n\n  for (const key of Object.keys(headers)) {\n    const lowerKey = key.toLowerCase();\n\n    if (exclude.find((e) => e.toLowerCase() === lowerKey)) {\n      if (strategy === PRUNE_STRATEGY.REDACT) {\n        headersPruned[key] = REDACTED_VALUE;\n      }\n    } else if (!allow.find((i) => i.toLowerCase() === lowerKey)) {\n      if (strategy === PRUNE_STRATEGY.REDACT) {\n        headersPruned[key] = REDACTED_VALUE;\n      }\n    } else {\n      headersPruned[key] = headers[key];\n    }\n  }\n  return headersPruned;\n};\nexport class NetworkRequestEvent {\n  public requestHeaders?: Record<string, string>;\n  public responseHeaders?: Record<string, string>;\n  public requestBodyJson?: Promise<JsonObject | null>;\n  public responseBodyJson?: Promise<JsonObject | null>;\n  constructor(\n    public readonly type: 'xhr' | 'fetch',\n    public readonly method: string,\n    public readonly timestamp: number,\n    public readonly startTime: number,\n    public readonly url?: string,\n    public readonly requestWrapper?: IRequestWrapper,\n    public readonly status: number = 0,\n    public readonly duration?: number,\n    public readonly responseWrapper?: IResponseWrapper,\n    public readonly error?: {\n      name: string;\n      message: string;\n    },\n    public readonly endTime?: number,\n  ) {}\n\n  toSerializable(): Record<string, any> {\n    const serialized: Record<string, any> = {\n      type: this.type,\n      method: this.method,\n      url: this.url,\n      timestamp: this.timestamp,\n      status: this.status,\n      duration: this.duration,\n      error: this.error,\n      startTime: this.startTime,\n      endTime: this.endTime,\n      requestHeaders: this.requestWrapper?.headers([...SAFE_HEADERS]),\n      requestBodySize: this.requestWrapper?.bodySize,\n      responseHeaders: this.responseWrapper?.headers([...SAFE_HEADERS]),\n      responseBodySize: this.responseWrapper?.bodySize,\n    };\n\n    return Object.fromEntries(Object.entries(serialized).filter(([_, v]) => v !== undefined));\n  }\n}\n"
  },
  {
    "path": "packages/analytics-core/src/observers/console.ts",
    "content": "import { getGlobalScope } from '../global-scope';\n\ntype ConsoleLogLevel = keyof Console;\ntype Callback = (logLevel: ConsoleLogLevel, args: any[]) => void;\n\nconst globalScope = getGlobalScope();\n/* istanbul ignore next */\nconst originalConsole: any = globalScope?.console;\n\nlet handlers: { [key in ConsoleLogLevel]?: Array<Callback> } = {};\n\n// keeps reference to original console methods\nlet originalFn: { [key in ConsoleLogLevel]?: (...args: any[]) => void } = {};\n\nlet inConsoleOverride = false;\n\nfunction overrideConsole(logLevel: ConsoleLogLevel): boolean {\n  /* istanbul ignore if */\n  if (!originalConsole) {\n    return false;\n  }\n\n  // should not override if original console property is not a function\n  /* eslint-disable-next-line @typescript-eslint/no-unsafe-member-access */\n  if (typeof originalConsole[logLevel] !== 'function') {\n    return false;\n  }\n\n  // if console is already overridden, return true\n  if (originalFn[logLevel]) {\n    return true;\n  }\n\n  // override console method\n  const handler = function (...args: any[]) {\n    try {\n      if (handlers[logLevel] && !inConsoleOverride) {\n        // add a re-entrancy guard to prevent infinite recursion\n        inConsoleOverride = true;\n        const callbacks = handlers[logLevel];\n        if (callbacks) {\n          callbacks.forEach((callback) => {\n            try {\n              callback(logLevel, args);\n            } catch {\n              // do nothing\n            }\n          });\n        }\n      }\n    } catch {\n      // do nothing\n    }\n    inConsoleOverride = false;\n    return originalFn[logLevel]!.apply(originalConsole, args);\n  };\n  /* eslint-disable-next-line @typescript-eslint/no-unsafe-member-access */\n  originalFn[logLevel] = originalConsole[logLevel] as (...args: any[]) => void;\n  /* eslint-disable-next-line @typescript-eslint/no-unsafe-member-access */\n  originalConsole[logLevel] = handler;\n  return true;\n}\n\n/**\n * Observe a console log method (log, warn, error, etc.)\n * @param level - The console log level to observe\n * @param callback - The callback function to call when the console log level is observed\n */\nfunction addListener(level: ConsoleLogLevel, callback: Callback): Error | void {\n  const res = overrideConsole(level);\n\n  /* istanbul ignore if */\n  if (!res) {\n    return new Error('Console override failed');\n  }\n\n  if (handlers[level]) {\n    // using ! is safe because we know the key exists based on condition above\n    handlers[level]!.push(callback);\n  } else {\n    handlers[level] = [callback];\n  }\n}\n\n/**\n * Disconnect a callback function from a console log method\n * @param callback - The callback function to disconnect\n */\nfunction removeListener(callback: Callback) {\n  for (const callbacks of Object.values(handlers)) {\n    // iterate backwards to avoid index shifting\n    for (let i = callbacks.length - 1; i >= 0; i--) {\n      if (callbacks[i] === callback) {\n        callbacks.splice(i, 1);\n        break;\n      }\n    }\n  }\n}\n\n// this should only be used for testing\n// restoring console can break console overrides\nfunction _restoreConsole() {\n  for (const [key, originalHandler] of Object.entries(originalFn)) {\n    if (originalHandler) {\n      /* eslint-disable-next-line @typescript-eslint/no-unsafe-member-access */\n      originalConsole[key] = originalHandler;\n    }\n  }\n  originalFn = {};\n  handlers = {};\n}\n\nconst consoleObserver = {\n  addListener,\n  removeListener,\n  _restoreConsole,\n};\n\nexport { consoleObserver, ConsoleLogLevel };\n"
  },
  {
    "path": "packages/analytics-core/src/observers/network.ts",
    "content": "import { getGlobalScope } from '../global-scope';\nimport { UUID } from '../utils/uuid';\nimport { ILogger } from '../logger';\nimport {\n  IRequestWrapper,\n  NetworkRequestEvent,\n  RequestWrapperFetch,\n  ResponseWrapperFetch,\n  RequestWrapperXhr,\n  ResponseWrapperXhr,\n  IResponseWrapper,\n  RequestInitSafe,\n  XMLHttpRequestBodyInitSafe,\n} from '../network-request-event';\n\n// object that is added to each XHR instance so\n// that info can be set in xhr.open and retrieved in xhr.send\ntype AmplitudeAnalyticsEvent = {\n  method: string;\n  url: string | URL;\n  startTime: number;\n  durationStart: number;\n  status?: number;\n  headers: Record<string, string>;\n};\n\n/**\n * Typeguard function checks if an input is a Request object.\n */\nfunction isRequest(requestInfo: any): requestInfo is Request {\n  return typeof requestInfo === 'object' && requestInfo !== null && 'url' in requestInfo && 'method' in requestInfo;\n}\n\nexport type NetworkEventCallbackFn = (event: NetworkRequestEvent) => void;\n\nexport class NetworkEventCallback {\n  constructor(public readonly callback: (event: NetworkRequestEvent) => void, public readonly id: string = UUID()) {}\n}\n\ntype RequestUrlAndMethod = {\n  url: string | URL | undefined;\n  method: string | undefined;\n};\n\n// A narrowed down [XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) type\n// that only includes the properties we need to access and adds the $$AmplitudeAnalyticsEvent property\n// Use great care when modifying this type, make sure you only use read-only properties and only add\n// what you need to access, nothing more.\ntype AmplitudeXMLHttpRequestSafe = {\n  $$AmplitudeAnalyticsEvent: AmplitudeAnalyticsEvent;\n  status: number;\n  responseText: string;\n  responseType: XMLHttpRequestResponseType;\n  getAllResponseHeaders: typeof XMLHttpRequest.prototype.getAllResponseHeaders;\n  getResponseHeader: typeof XMLHttpRequest.prototype.getResponseHeader;\n  addEventListener: (type: 'loadend', listener: () => void) => void;\n};\n\nfunction safeInvoke(fn: () => void) {\n  try {\n    fn();\n  } catch (err) {\n    // swallow the error\n  }\n}\n\nexport class NetworkObserver {\n  private eventCallbacks: Map<string, NetworkEventCallback> = new Map();\n  // eslint-disable-next-line no-restricted-globals\n  private globalScope?: typeof globalThis;\n  private logger?: ILogger;\n  private isObserving = false;\n  constructor(logger?: ILogger) {\n    this.logger = logger;\n    const globalScope = getGlobalScope();\n    if (!NetworkObserver.isSupported()) {\n      /* istanbul ignore next */\n      return;\n    }\n    this.globalScope = globalScope;\n  }\n\n  static isSupported(): boolean {\n    const globalScope = getGlobalScope();\n    return !!globalScope && !!globalScope.fetch;\n  }\n\n  subscribe(eventCallback: NetworkEventCallback, logger?: ILogger) {\n    if (!this.logger) {\n      this.logger = logger;\n    }\n    this.eventCallbacks.set(eventCallback.id, eventCallback);\n    if (!this.isObserving) {\n      /* istanbul ignore next */\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      const originalXhrOpen = this.globalScope?.XMLHttpRequest?.prototype?.open;\n      /* istanbul ignore next */\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      const originalXhrSend = this.globalScope?.XMLHttpRequest?.prototype?.send;\n      /* istanbul ignore next */\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      const originalXhrSetRequestHeader = this.globalScope?.XMLHttpRequest?.prototype?.setRequestHeader;\n      if (originalXhrOpen && originalXhrSend && originalXhrSetRequestHeader) {\n        this.observeXhr(originalXhrOpen, originalXhrSend, originalXhrSetRequestHeader);\n      }\n\n      /* istanbul ignore next */\n      const originalFetch = this.globalScope?.fetch;\n      /* istanbul ignore next */\n      if (originalFetch) {\n        this.observeFetch(originalFetch);\n      }\n\n      /* istanbul ignore next */\n      this.isObserving = true;\n    }\n  }\n\n  unsubscribe(eventCallback: NetworkEventCallback) {\n    this.eventCallbacks.delete(eventCallback.id);\n  }\n\n  protected triggerEventCallbacks(event: NetworkRequestEvent) {\n    this.eventCallbacks.forEach((callback) => {\n      try {\n        callback.callback(event);\n      } catch (err) {\n        // if the callback throws an error, we should catch it\n        // to avoid breaking the fetch promise chain\n        safeInvoke(() => {\n          /* istanbul ignore next */\n          this.logger?.debug('an unexpected error occurred while triggering event callbacks', err);\n        });\n      }\n    });\n  }\n\n  handleNetworkRequestEvent(\n    requestType: 'fetch' | 'xhr',\n    requestInfo: RequestInfo | URL | RequestUrlAndMethod | undefined,\n    requestWrapper: IRequestWrapper | undefined,\n    responseWrapper: IResponseWrapper | undefined,\n    typedError: Error | undefined,\n    startTime?: number,\n    durationStart?: number,\n  ) {\n    /* istanbul ignore next */\n    if (startTime === undefined || durationStart === undefined) {\n      // if we reach this point, it means that the performance API is not supported\n      // so we can't construct a NetworkRequestEvent\n      return;\n    }\n\n    // parse the URL and Method\n    let url: string | undefined;\n    let method = 'GET';\n    if (isRequest(requestInfo)) {\n      url = requestInfo['url'];\n      method = requestInfo['method'];\n    } else {\n      url = requestInfo?.toString?.();\n    }\n\n    // strip basic auth from the URL\n    if (url) {\n      try {\n        const parsedUrl = new URL(url);\n        // reconstruct the URL without the basic auth\n        url = `${parsedUrl.protocol}//${parsedUrl.host}${parsedUrl.pathname}${parsedUrl.search}${parsedUrl.hash}`;\n        // eslint-disable-next-line no-empty\n      } catch (err) {}\n    }\n    method = requestWrapper?.method || method;\n\n    let status, error;\n    if (responseWrapper) {\n      status = responseWrapper.status;\n    }\n\n    if (typedError) {\n      error = {\n        name: typedError.name || 'UnknownError',\n        message: typedError.message || 'An unknown error occurred',\n      };\n      status = 0;\n    }\n\n    const duration = Math.floor(performance.now() - durationStart);\n    const endTime = Math.floor(startTime + duration);\n\n    const requestEvent = new NetworkRequestEvent(\n      requestType,\n      method,\n      startTime, // timestamp and startTime are aliases\n      startTime,\n      url,\n      requestWrapper,\n      status,\n      duration,\n      responseWrapper,\n      error,\n      endTime,\n    );\n\n    this.triggerEventCallbacks(requestEvent);\n  }\n\n  private getTimestamps() {\n    /* istanbul ignore next */\n    return {\n      startTime: Date.now?.(),\n      durationStart: performance?.now?.(),\n    };\n  }\n\n  private observeFetch(\n    originalFetch: (requestInfo: RequestInfo | URL, requestInit?: RequestInit) => Promise<Response>,\n  ) {\n    /* istanbul ignore next */\n    if (!this.globalScope || !originalFetch) {\n      return;\n    }\n    /**\n     * IMPORTANT: This overrides window.fetch in browsers.\n     * You probably never need to make changes to this function.\n     * If you do, please be careful to preserve the original functionality of fetch\n     * and make sure another developer who is an expert reviews this change throughly\n     */\n    this.globalScope.fetch = async (requestInfo?: RequestInfo | URL, requestInit?: RequestInit) => {\n      // 1: capture the start time and duration start time before the fetch call\n      let timestamps;\n      try {\n        timestamps = this.getTimestamps();\n      } catch (error) {\n        /* istanbul ignore next */\n        safeInvoke(() => this.logger?.debug('an unexpected error occurred while retrieving timestamps', error));\n      }\n\n      // 2. make the call to the original fetch and preserve the response or error\n      let originalResponse, originalError;\n      try {\n        originalResponse = await originalFetch(requestInfo as RequestInfo | URL, requestInit);\n      } catch (err) {\n        // Capture error information\n        originalError = err;\n      }\n\n      // 3. call the handler after the fetch call is done\n      try {\n        this.handleNetworkRequestEvent(\n          'fetch',\n          requestInfo,\n          requestInit ? new RequestWrapperFetch(requestInit as RequestInitSafe) : undefined,\n          originalResponse ? new ResponseWrapperFetch(originalResponse) : undefined,\n          originalError as Error,\n          /* istanbul ignore next */\n          timestamps?.startTime,\n          /* istanbul ignore next */\n          timestamps?.durationStart,\n        );\n      } catch (err) {\n        // this catch shouldn't be reachable, but keep it here for safety\n        // because we're overriding the fetch function and better to be safe than sorry\n        /* istanbul ignore next */\n        safeInvoke(() => this.logger?.debug('an unexpected error occurred while handling fetch', err));\n      }\n\n      // 4. return the original response or throw the original error\n      if (originalResponse) {\n        // if the response is not undefined, return it\n        return originalResponse;\n      } else {\n        throw originalError;\n      }\n    };\n  }\n\n  /**\n   * Creates a function that parses the response of an XMLHttpRequest as JSON.\n   *\n   * Returns function instead of JSON object to avoid unnecessary parsing if the\n   * body is not being captured.\n   *\n   * @param xhrSafe - The XMLHttpRequest object.\n   * @param context - The NetworkObserver instance.\n   * @returns A function that parses the response of an XMLHttpRequest as JSON.\n   */\n  static createXhrJsonParser(xhrUnsafe: XMLHttpRequest, context: NetworkObserver) {\n    return () => {\n      try {\n        if (xhrUnsafe.responseType === 'json') {\n          // if response is a JS object, clone it so that subscribers can't mutate it\n          if (context.globalScope?.structuredClone) {\n            /* eslint-disable-next-line @typescript-eslint/no-unsafe-return */\n            return context.globalScope.structuredClone(xhrUnsafe.response);\n          }\n        } else if (['text', ''].includes(xhrUnsafe.responseType)) {\n          // if response is a string, parse it as JSON\n          /* eslint-disable-next-line @typescript-eslint/no-unsafe-return */\n          return JSON.parse(xhrUnsafe.responseText);\n        }\n      } catch (err) {\n        /* istanbul ignore if */\n        if (err instanceof Error && err.name === 'InvalidStateError') {\n          // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseText#exceptions\n          // if we reach here, it means we don't handle responseType correctly\n          safeInvoke(() =>\n            context.logger?.debug(\n              `unexpected error when retrieving responseText. responseType='${xhrUnsafe.responseType}'`,\n            ),\n          );\n        }\n        // the other possible error is Json Parse error which we fail silently\n        return null;\n      }\n      return null;\n    };\n  }\n\n  private observeXhr(\n    originalXhrOpen:\n      | ((\n          method: string,\n          url: string | URL,\n          async?: boolean,\n          username?: string | null,\n          password?: string | null,\n        ) => void)\n      | undefined,\n    originalXhrSend: ((body?: Document | XMLHttpRequestBodyInit | null) => void) | undefined,\n    originalXhrSetRequestHeader: (headerName: string, headerValue: string) => void,\n  ) {\n    /* istanbul ignore next */\n    if (!this.globalScope || !originalXhrOpen || !originalXhrSend) {\n      return;\n    }\n\n    const xhrProto = this.globalScope.XMLHttpRequest.prototype;\n\n    const networkObserverContext = this as NetworkObserver;\n\n    /**\n     * IMPORTANT: This overrides window.XMLHttpRequest.prototype.open\n     * You probably never need to make changes to this function.\n     * If you do, please be careful to preserve the original functionality of xhr.open\n     * and make sure another developer who is an expert reviews this change throughly\n     */\n    xhrProto.open = function (...args: any[]) {\n      const xhrSafe = this as unknown as AmplitudeXMLHttpRequestSafe;\n      const [method, url] = args as [string, string | URL];\n      try {\n        /* istanbul ignore next */\n        xhrSafe.$$AmplitudeAnalyticsEvent = {\n          method,\n          url: url?.toString?.(),\n          headers: {},\n          ...networkObserverContext.getTimestamps(),\n        } as AmplitudeAnalyticsEvent;\n      } catch (err) {\n        /* istanbul ignore next */\n        safeInvoke(() =>\n          networkObserverContext.logger?.debug('an unexpected error occurred while calling xhr open', err),\n        );\n      }\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n      return originalXhrOpen.apply(xhrSafe, args as any);\n    };\n\n    /**\n     * IMPORTANT: This overrides window.XMLHttpRequest.prototype.send\n     * You probably never need to make changes to this function.\n     * If you do, please be careful to preserve the original functionality of xhr.send\n     * and make sure another developer who is an expert reviews this change throughly\n     */\n    // allow \"any\" type for args to reflect how it's used in the browser\n    /* eslint-disable-next-line @typescript-eslint/no-unsafe-argument */\n    xhrProto.send = function (...args: any[]) {\n      // eslint-disable-next-line @typescript-eslint/no-this-alias\n      const xhrUnsafe = this;\n      const xhrSafe = xhrUnsafe as unknown as AmplitudeXMLHttpRequestSafe;\n      const getJson = NetworkObserver.createXhrJsonParser(xhrUnsafe, networkObserverContext);\n      const body = args[0] as XMLHttpRequestBodyInitSafe;\n      const requestEvent = xhrSafe.$$AmplitudeAnalyticsEvent;\n\n      // if xhrSafe.$$AmplitudeAnalyticsEvent is not set, it means that\n      // the xhr.open method was called before we monkey-patched XHR and\n      // the event is missed\n      if (xhrSafe.$$AmplitudeAnalyticsEvent) {\n        xhrSafe.addEventListener('loadend', function () {\n          try {\n            const responseHeaders = xhrSafe.getAllResponseHeaders();\n            const responseBodySize = xhrSafe.getResponseHeader('content-length');\n\n            const responseWrapper = new ResponseWrapperXhr(\n              xhrSafe.status,\n              responseHeaders,\n              /* istanbul ignore next */\n              responseBodySize ? parseInt(responseBodySize, 10) : undefined,\n              getJson,\n            );\n            const requestHeaders = xhrSafe.$$AmplitudeAnalyticsEvent.headers;\n            const requestWrapper = new RequestWrapperXhr(body, requestHeaders);\n            requestEvent.status = xhrSafe.status;\n            networkObserverContext.handleNetworkRequestEvent(\n              'xhr',\n              { url: requestEvent.url, method: requestEvent.method },\n              requestWrapper,\n              responseWrapper,\n              undefined,\n              requestEvent.startTime,\n              requestEvent.durationStart,\n            );\n          } catch (err) {\n            /* istanbul ignore next */\n            safeInvoke(() =>\n              networkObserverContext.logger?.debug('an unexpected error occurred while handling xhr send', err),\n            );\n          }\n        });\n      }\n      /* eslint-disable-next-line @typescript-eslint/no-unsafe-argument */\n      return originalXhrSend.apply(xhrSafe, args as any);\n    };\n\n    /**\n     * IMPORTANT: This overrides window.XMLHttpRequest.prototype.setRequestHeader\n     * You probably never need to make changes to this function.\n     * If you do, please be careful to preserve the original functionality of xhr.setRequestHeader\n     * and make sure another developer who is an expert reviews this change throughly\n     */\n    // allow \"any\" type for args to reflect how it's used in the browser\n    /* eslint-disable-next-line @typescript-eslint/no-unsafe-argument */\n    xhrProto.setRequestHeader = function (headerName: any, headerValue: any) {\n      const xhrSafe = this as unknown as AmplitudeXMLHttpRequestSafe;\n      try {\n        const analyticsEvent = xhrSafe.$$AmplitudeAnalyticsEvent;\n        if (analyticsEvent) {\n          /* eslint-disable-next-line @typescript-eslint/no-unsafe-assignment */\n          analyticsEvent.headers[headerName as string] = headerValue as string;\n        }\n      } catch (err) {\n        /* istanbul ignore next */\n        safeInvoke(() =>\n          networkObserverContext.logger?.debug('an unexpected error occurred while calling xhr setRequestHeader', err),\n        );\n      }\n      /* eslint-disable-next-line @typescript-eslint/no-unsafe-argument */\n      originalXhrSetRequestHeader.apply(xhrSafe, [headerName, headerValue]);\n    };\n  }\n}\n\n// singleton instance of NetworkObserver\nexport const networkObserver = new NetworkObserver();\n"
  },
  {
    "path": "packages/analytics-core/src/observers/video.ts",
    "content": "import { trackHtmlVideo, trackEmbeddedVideo } from '../video-analytics/track-video';\nimport type {\n  VideoHandler,\n  VideoEvent,\n  EmbeddedVideoPlayer,\n  MuxElement,\n  Vendor,\n  TimeUpdateEvent,\n} from '../video-analytics/types';\n\nexport type { Vendor };\n\ntype PlaybackState = 'playing' | 'paused' | 'ended' | 'error' | 'seeking';\n\nexport type State = {\n  playbackState: PlaybackState;\n  errorMessage?: string;\n  lastEvent?: VideoEvent;\n  watchTime?: number;\n  position?: number | null;\n  isSeeking?: boolean;\n};\n\nexport type VideoObserverParams = {\n  videoEl: HTMLVideoElement | EmbeddedVideoPlayer | MuxElement;\n  onStateChange: (previousState: State, nextState: State) => void;\n  vendor?: Vendor;\n  isEmbedded?: boolean;\n};\n\nexport class VideoObserver {\n  private state: State = {\n    playbackState: 'paused',\n  };\n\n  private untrack: () => void;\n  private onStateChange: (previousState: State, nextState: State) => void;\n  private handler: VideoHandler = {\n    onPlay: (evt: VideoEvent) => {\n      this.updatePlaybackState('playing', evt);\n    },\n    onPause: (evt: VideoEvent) => {\n      this.updatePlaybackState('paused', evt);\n    },\n    onEnded: (evt: VideoEvent) => {\n      this.updatePlaybackState('ended', evt);\n    },\n    onSeeking: () => {\n      const nextState: State = {\n        ...this.state,\n        isSeeking: true,\n      };\n      this.updateState(nextState);\n    },\n    onSeeked: (event: VideoEvent) => {\n      const nextState: State = {\n        ...this.state,\n        isSeeking: false,\n        position: event.last_position,\n      };\n      this.updateState(nextState);\n    },\n    onError: (errorMessage: string) => {\n      this.updateStateWithError(errorMessage);\n    },\n    onTimeUpdate: (evt: TimeUpdateEvent) => {\n      this.updateTime(evt);\n    },\n  };\n\n  constructor({ videoEl, onStateChange, vendor, isEmbedded }: VideoObserverParams) {\n    this.onStateChange = onStateChange;\n    if (isEmbedded) {\n      this.untrack = trackEmbeddedVideo(videoEl as EmbeddedVideoPlayer, this.handler, vendor);\n    } else {\n      this.untrack = trackHtmlVideo(videoEl as HTMLVideoElement, this.handler, vendor);\n    }\n  }\n\n  private stateChangeHandler(previousState: State, nextState: State) {\n    try {\n      this.onStateChange(previousState, nextState);\n    } catch (_error) {\n      // Swallow callback errors to keep observer state consistent.\n    }\n  }\n\n  private updateStateWithError(error: string) {\n    const previousState = this.state;\n    const nextState: State = {\n      ...previousState,\n      playbackState: 'error',\n      errorMessage: error,\n    };\n    this.updateState(nextState);\n  }\n\n  private updatePlaybackState(playbackState: PlaybackState, event: VideoEvent) {\n    const nextState: State = {\n      ...this.state,\n      playbackState,\n      lastEvent: event,\n      position: event.last_position,\n    };\n    this.updateState(nextState);\n  }\n\n  private updateTime(event: TimeUpdateEvent) {\n    const lastVideoEvent = this.state.lastEvent;\n    if (!lastVideoEvent || this.state.playbackState !== 'playing') {\n      return;\n    }\n    const isSeeking = event.isSeeking || this.state.isSeeking;\n    const lastPosition = this.state.position ?? 0;\n    const nextPosition = event.position;\n    if (isSeeking) {\n      this.state = {\n        ...this.state,\n        position: nextPosition,\n      };\n      return;\n    }\n    const timeDelta = nextPosition - lastPosition;\n    const nextState: State = {\n      ...this.state,\n      position: nextPosition,\n      watchTime: (this.state.watchTime ?? 0) + timeDelta,\n    };\n    this.updateState(nextState);\n  }\n\n  private updateState(nextState: State) {\n    const previousState = this.state;\n    this.state = nextState;\n    this.stateChangeHandler(previousState, nextState);\n  }\n\n  destroy() {\n    this.untrack();\n  }\n}\n"
  },
  {
    "path": "packages/analytics-core/src/plugins/destination.ts",
    "content": "import { DestinationPlugin } from '../types/plugin';\nimport { Event } from '../types/event/event';\nimport { Result } from '../types/result';\nimport { Status } from '../types/status';\nimport {\n  Response,\n  InvalidResponse,\n  PayloadTooLargeResponse,\n  RateLimitResponse,\n  SuccessResponse,\n} from '../types/response';\nimport {\n  INVALID_API_KEY,\n  MAX_RETRIES_EXCEEDED_MESSAGE,\n  MISSING_API_KEY_MESSAGE,\n  SUCCESS_MESSAGE,\n  UNEXPECTED_ERROR_MESSAGE,\n} from '../types/messages';\nimport {\n  AMPLITUDE_BATCH_SERVER_URL,\n  AMPLITUDE_SERVER_URL,\n  EU_AMPLITUDE_BATCH_SERVER_URL,\n  EU_AMPLITUDE_SERVER_URL,\n  STORAGE_PREFIX,\n} from '../types/constants';\nimport { chunk } from '../utils/chunk';\nimport { buildResult } from '../utils/result-builder';\nimport { createServerConfig, RequestMetadata } from '../config';\nimport { UUID } from '../utils/uuid';\nimport { IConfig } from '../types/config/core-config';\nimport { EventCallback } from '../types/event-callback';\nimport { IDiagnosticsClient } from '../diagnostics/diagnostics-client';\nimport { isSuccessStatusCode } from '../utils/status-code';\nimport { getStacktrace } from '../utils/debug';\n\nexport interface Context {\n  event: Event;\n  attempts: number;\n  callback: EventCallback;\n  timeout: number;\n}\n\nconst DEFAULT_AMPLITUDE_SERVER_URLS = new Set([\n  AMPLITUDE_SERVER_URL,\n  EU_AMPLITUDE_SERVER_URL,\n  AMPLITUDE_BATCH_SERVER_URL,\n  EU_AMPLITUDE_BATCH_SERVER_URL,\n]);\n\nconst shouldCompressUploadBodyForRequest = (serverUrl: string, enableRequestBodyCompression = false) => {\n  if (DEFAULT_AMPLITUDE_SERVER_URLS.has(serverUrl)) {\n    return true;\n  }\n\n  return enableRequestBodyCompression;\n};\n\nfunction getErrorMessage(error: unknown) {\n  if (error instanceof Error) return error.message;\n  return String(error);\n}\n\nexport function getResponseBodyString(res: Response) {\n  let responseBodyString = '';\n  try {\n    if ('body' in res) {\n      responseBodyString = JSON.stringify(res.body, null, 2);\n    }\n  } catch {\n    // to avoid crash, but don't care about the error, add comment to avoid empty block lint error\n  }\n  return responseBodyString;\n}\n\nexport class Destination implements DestinationPlugin {\n  name = 'amplitude';\n  type = 'destination' as const;\n\n  retryTimeout = 1000;\n  throttleTimeout = 30000;\n  storageKey = '';\n  // this.config is defined in setup() which will always be called first\n  // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n  // @ts-ignore\n  config: IConfig;\n  // Indicator of whether events that are scheduled (but not flushed yet).\n  // When flush:\n  //   1. assign `scheduleId` to `flushId`\n  //   2. set `scheduleId` to null\n  scheduleId: ReturnType<typeof setTimeout> | null = null;\n  // Timeout in milliseconds of current schedule\n  scheduledTimeout = 0;\n  // Indicator of whether current flush resolves.\n  // When flush resolves, set `flushId` to null\n  flushId: ReturnType<typeof setTimeout> | null = null;\n  queue: Context[] = [];\n  diagnosticsClient: IDiagnosticsClient | undefined;\n\n  constructor(context?: { diagnosticsClient: IDiagnosticsClient }) {\n    this.diagnosticsClient = context?.diagnosticsClient;\n  }\n\n  async setup(config: IConfig): Promise<undefined> {\n    this.config = config;\n\n    this.storageKey = `${STORAGE_PREFIX}_${this.config.apiKey.substring(0, 10)}`;\n    const unsent = await this.config.storageProvider?.get(this.storageKey);\n    if (unsent && unsent.length > 0) {\n      void Promise.all(unsent.map((event: Event) => this.execute(event))).catch();\n    }\n\n    return Promise.resolve(undefined);\n  }\n\n  execute(event: Event): Promise<Result> {\n    // Assign insert_id for dropping invalid event later\n    if (!event.insert_id) {\n      event.insert_id = UUID();\n    }\n\n    return new Promise((resolve) => {\n      const context = {\n        event,\n        attempts: 0,\n        callback: (result: Result) => resolve(result),\n        timeout: 0,\n      };\n      this.queue.push(context);\n      this.schedule(this.config.flushIntervalMillis);\n      this.saveEvents();\n    });\n  }\n\n  removeEventsExceedFlushMaxRetries(list: Context[]) {\n    return list.filter((context) => {\n      context.attempts += 1;\n      if (context.attempts < this.config.flushMaxRetries) {\n        return true;\n      }\n      void this.fulfillRequest([context], 500, MAX_RETRIES_EXCEEDED_MESSAGE);\n      return false;\n    });\n  }\n\n  scheduleEvents(list: Context[]) {\n    list.forEach((context) => {\n      this.schedule(context.timeout === 0 ? this.config.flushIntervalMillis : context.timeout);\n    });\n  }\n\n  // Schedule a flush in timeout when\n  // 1. No schedule\n  // 2. Timeout greater than existing timeout.\n  // This makes sure that when throttled, no flush when throttle timeout expires.\n  schedule(timeout: number) {\n    if (this.config.offline) {\n      return;\n    }\n\n    if (this.scheduleId === null || (this.scheduleId && timeout > this.scheduledTimeout)) {\n      if (this.scheduleId) {\n        clearTimeout(this.scheduleId);\n      }\n      this.scheduledTimeout = timeout;\n      this.scheduleId = setTimeout(() => {\n        this.queue = this.queue.map((context) => {\n          context.timeout = 0;\n          return context;\n        });\n        void this.flush(true);\n      }, timeout);\n      return;\n    }\n  }\n\n  // Mark current schedule is flushed.\n  resetSchedule() {\n    this.scheduleId = null;\n    this.scheduledTimeout = 0;\n  }\n\n  // Flush all events regardless of their timeout\n  async flush(useRetry = false) {\n    // Skip flush if offline\n    if (this.config.offline) {\n      this.resetSchedule();\n      this.config.loggerProvider.debug('Skipping flush while offline.');\n      return;\n    }\n\n    if (this.flushId) {\n      this.resetSchedule();\n      this.config.loggerProvider.debug('Skipping flush because previous flush has not resolved.');\n      return;\n    }\n\n    this.flushId = this.scheduleId;\n    this.resetSchedule();\n\n    const list: Context[] = [];\n    const later: Context[] = [];\n    this.queue.forEach((context) => (context.timeout === 0 ? list.push(context) : later.push(context)));\n\n    const batches = chunk(list, this.config.flushQueueSize);\n\n    // Promise.all() doesn't guarantee resolve order.\n    // Sequentially resolve to make sure backend receives events in order\n    await batches.reduce(async (promise, batch) => {\n      await promise;\n      return await this.send(batch, useRetry);\n    }, Promise.resolve());\n\n    // Mark current flush is done\n    this.flushId = null;\n\n    this.scheduleEvents(this.queue);\n  }\n\n  async send(list: Context[], useRetry = true) {\n    if (!this.config.apiKey) {\n      return this.fulfillRequest(list, 400, MISSING_API_KEY_MESSAGE);\n    }\n\n    const payload = {\n      api_key: this.config.apiKey,\n      events: list.map((context) => {\n        // eslint-disable-next-line @typescript-eslint/no-unused-vars\n        const { extra, ...eventWithoutExtra } = context.event;\n        return eventWithoutExtra;\n      }),\n      options: {\n        min_id_length: this.config.minIdLength,\n      },\n      client_upload_time: new Date().toISOString(),\n      request_metadata: this.config.requestMetadata,\n    };\n    this.config.requestMetadata = new RequestMetadata();\n\n    try {\n      const { serverUrl } = createServerConfig(this.config.serverUrl, this.config.serverZone, this.config.useBatch);\n      const shouldCompressUploadBody = shouldCompressUploadBodyForRequest(\n        serverUrl,\n        this.config.enableRequestBodyCompression,\n      );\n      const res = await this.config.transportProvider.send(serverUrl, payload, shouldCompressUploadBody);\n      if (res === null) {\n        this.fulfillRequest(list, 0, UNEXPECTED_ERROR_MESSAGE);\n        return;\n      }\n      if (!useRetry) {\n        if ('body' in res) {\n          this.fulfillRequest(list, res.statusCode, `${res.status}: ${getResponseBodyString(res)}`);\n        } else {\n          this.fulfillRequest(list, res.statusCode, res.status);\n        }\n        return;\n      }\n      this.handleResponse(res, list);\n    } catch (e) {\n      const errorMessage = getErrorMessage(e);\n      this.config.loggerProvider.error(errorMessage);\n\n      this.diagnosticsClient?.recordEvent('analytics.events.unsuccessful.from.catch.error', {\n        events: list.map((context) => context.event.event_type),\n        message: errorMessage,\n        stack_trace: getStacktrace(),\n      });\n\n      this.handleResponse({ status: Status.Failed, statusCode: 0 }, list);\n    }\n  }\n\n  handleResponse(res: Response, list: Context[]) {\n    if (!isSuccessStatusCode(res.statusCode)) {\n      this.diagnosticsClient?.recordEvent('analytics.events.unsuccessful', {\n        events: list.map((context) => context.event.event_type),\n        code: res.statusCode,\n        status: res.status,\n        body: getResponseBodyString(res),\n        stack_trace: getStacktrace(),\n      });\n    }\n\n    const { status } = res;\n\n    switch (status) {\n      case Status.Success: {\n        this.handleSuccessResponse(res, list);\n        break;\n      }\n      case Status.Invalid: {\n        this.handleInvalidResponse(res, list);\n        break;\n      }\n      case Status.PayloadTooLarge: {\n        this.handlePayloadTooLargeResponse(res, list);\n        break;\n      }\n      case Status.RateLimit: {\n        this.handleRateLimitResponse(res, list);\n        break;\n      }\n      default: {\n        // log intermediate event status before retry\n        this.config.loggerProvider.warn(`{code: 0, error: \"Status '${status}' provided for ${list.length} events\"}`);\n        this.handleOtherResponse(list);\n        break;\n      }\n    }\n  }\n\n  handleSuccessResponse(res: SuccessResponse, list: Context[]) {\n    this.fulfillRequest(list, res.statusCode, SUCCESS_MESSAGE);\n  }\n\n  handleInvalidResponse(res: InvalidResponse, list: Context[]) {\n    if (res.body.missingField || res.body.error.startsWith(INVALID_API_KEY)) {\n      this.fulfillRequest(list, res.statusCode, res.body.error);\n      return;\n    }\n\n    const dropIndex = [\n      ...Object.values(res.body.eventsWithInvalidFields),\n      ...Object.values(res.body.eventsWithMissingFields),\n      ...Object.values(res.body.eventsWithInvalidIdLengths),\n      ...res.body.silencedEvents,\n    ].flat();\n    const dropIndexSet = new Set(dropIndex);\n\n    const retry = list.filter((context, index) => {\n      if (dropIndexSet.has(index)) {\n        this.fulfillRequest([context], res.statusCode, res.body.error);\n        return;\n      }\n      return true;\n    });\n\n    if (retry.length > 0) {\n      // log intermediate event status before retry\n      this.config.loggerProvider.warn(getResponseBodyString(res));\n    }\n\n    const tryable = this.removeEventsExceedFlushMaxRetries(retry);\n    this.scheduleEvents(tryable);\n  }\n\n  handlePayloadTooLargeResponse(res: PayloadTooLargeResponse, list: Context[]) {\n    if (list.length === 1) {\n      this.fulfillRequest(list, res.statusCode, res.body.error);\n      return;\n    }\n\n    // log intermediate event status before retry\n    this.config.loggerProvider.warn(getResponseBodyString(res));\n\n    this.config.flushQueueSize /= 2;\n\n    const tryable = this.removeEventsExceedFlushMaxRetries(list);\n    this.scheduleEvents(tryable);\n  }\n\n  handleRateLimitResponse(res: RateLimitResponse, list: Context[]) {\n    const dropUserIds = Object.keys(res.body.exceededDailyQuotaUsers);\n    const dropDeviceIds = Object.keys(res.body.exceededDailyQuotaDevices);\n    const throttledIndex = res.body.throttledEvents;\n    const dropUserIdsSet = new Set(dropUserIds);\n    const dropDeviceIdsSet = new Set(dropDeviceIds);\n    const throttledIndexSet = new Set(throttledIndex);\n\n    const retry = list.filter((context, index) => {\n      if (\n        (context.event.user_id && dropUserIdsSet.has(context.event.user_id)) ||\n        (context.event.device_id && dropDeviceIdsSet.has(context.event.device_id))\n      ) {\n        this.fulfillRequest([context], res.statusCode, res.body.error);\n        return;\n      }\n      if (throttledIndexSet.has(index)) {\n        context.timeout = this.throttleTimeout;\n      }\n      return true;\n    });\n\n    if (retry.length > 0) {\n      // log intermediate event status before retry\n      this.config.loggerProvider.warn(getResponseBodyString(res));\n    }\n\n    const tryable = this.removeEventsExceedFlushMaxRetries(retry);\n    this.scheduleEvents(tryable);\n  }\n\n  handleOtherResponse(list: Context[]) {\n    const later = list.map((context) => {\n      context.timeout = context.attempts * this.retryTimeout;\n      return context;\n    });\n\n    const tryable = this.removeEventsExceedFlushMaxRetries(later);\n    this.scheduleEvents(tryable);\n  }\n\n  fulfillRequest(list: Context[], code: number, message: string) {\n    // Record diagnostics for dropped events (non-success status codes)\n    if (!isSuccessStatusCode(code)) {\n      this.diagnosticsClient?.increment('analytics.events.dropped', list.length);\n      this.diagnosticsClient?.recordEvent('analytics.events.dropped', {\n        events: list.map((context) => context.event.event_type),\n        code: code,\n        message: message,\n        stack_trace: getStacktrace(),\n      });\n    } else {\n      this.diagnosticsClient?.increment('analytics.events.sent', list.length);\n    }\n    this.removeEvents(list);\n    list.forEach((context) => context.callback(buildResult(context.event, code, message)));\n  }\n\n  /**\n   * This is called on\n   * 1) new events are added to queue; or\n   * 2) response comes back for a request\n   *\n   * Update the event storage based on the queue\n   */\n  saveEvents() {\n    if (!this.config.storageProvider) {\n      return;\n    }\n\n    const updatedEvents = this.queue.map((context) => context.event);\n    void this.config.storageProvider.set(this.storageKey, updatedEvents);\n  }\n\n  /**\n   * This is called on response comes back for a request\n   */\n  removeEvents(eventsToRemove: Context[]) {\n    this.queue = this.queue.filter(\n      (queuedContext) => !eventsToRemove.some((context) => context.event.insert_id === queuedContext.event.insert_id),\n    );\n\n    this.saveEvents();\n  }\n}\n"
  },
  {
    "path": "packages/analytics-core/src/plugins/helpers.ts",
    "content": "export const TEXT_MASK_ATTRIBUTE = 'data-amp-mask';\nexport const MASKED_TEXT_VALUE = '*****';\n\n// Regex patterns for sensitive data\nexport const CC_REGEX = /\\b(?:\\d[ -]*?){13,16}\\b/;\nexport const SSN_REGEX = /(\\d{3}-?\\d{2}-?\\d{4})/g;\nexport const EMAIL_REGEX = /[^\\s@]+@[^\\s@.]+\\.[^\\s@]+/g;\n\n/**\n * Replaces sensitive strings (credit cards, SSNs, emails) and custom patterns with masked text\n * @param text - The text to search for sensitive data\n * @param additionalMaskTextPatterns - Optional array of additional regex patterns to mask\n * @returns The text with sensitive data replaced by masked text\n */\nexport const replaceSensitiveString = (text: string | null, additionalMaskTextPatterns: RegExp[] = []): string => {\n  if (typeof text !== 'string') {\n    return '';\n  }\n\n  let result = text;\n\n  // Check for credit card number (with or without spaces/dashes)\n  result = result.replace(CC_REGEX, MASKED_TEXT_VALUE);\n\n  // Check for social security number\n  result = result.replace(SSN_REGEX, MASKED_TEXT_VALUE);\n\n  // Check for email\n  result = result.replace(EMAIL_REGEX, MASKED_TEXT_VALUE);\n\n  // Check for additional mask text patterns\n  for (const pattern of additionalMaskTextPatterns) {\n    try {\n      result = result.replace(pattern, MASKED_TEXT_VALUE);\n    } catch {\n      // ignore invalid pattern\n    }\n  }\n\n  return result;\n};\n\n/**\n * Gets the page title, checking if the title element has data-amp-mask attribute\n * @returns The page title, masked if the title element has data-amp-mask attribute\n */\nexport const getPageTitle = (parseTitleFunction?: (title: string) => string): string => {\n  if (typeof document === 'undefined' || !document.title) {\n    return '';\n  }\n  const titleElement = document.querySelector('title');\n  if (titleElement && titleElement.hasAttribute(TEXT_MASK_ATTRIBUTE)) {\n    return MASKED_TEXT_VALUE;\n  }\n  return parseTitleFunction ? parseTitleFunction(document.title) : document.title; // document.title is always synced to the first title element\n};\n"
  },
  {
    "path": "packages/analytics-core/src/plugins/identity.ts",
    "content": "import { BeforePlugin } from '../types/plugin';\nimport { IConfig } from '../types/config/core-config';\nimport { Event } from '../types/event/event';\nimport { getAnalyticsConnector } from '../analytics-connector';\n\nexport class IdentityEventSender implements BeforePlugin {\n  name = 'identity';\n  type = 'before' as const;\n\n  identityStore = getAnalyticsConnector().identityStore;\n\n  async execute(context: Event): Promise<Event> {\n    const userProperties = context.user_properties as Record<string, any>;\n    if (userProperties) {\n      this.identityStore.editIdentity().updateUserProperties(userProperties).commit();\n    }\n    return context;\n  }\n\n  async setup(config: IConfig) {\n    if (config.instanceName) {\n      this.identityStore = getAnalyticsConnector(config.instanceName).identityStore;\n    }\n  }\n}\n"
  },
  {
    "path": "packages/analytics-core/src/query-params.ts",
    "content": "import { getGlobalScope } from './global-scope';\n\nexport const getQueryParams = (): Record<string, string | undefined> => {\n  const globalScope = getGlobalScope();\n  /* istanbul ignore if */\n  if (!globalScope?.location?.search) {\n    return {};\n  }\n  const pairs = globalScope.location.search.substring(1).split('&').filter(Boolean);\n  const params = pairs.reduce<Record<string, string | undefined>>((acc, curr) => {\n    const query = curr.split('=', 2);\n    const key = tryDecodeURIComponent(query[0]);\n    const value = tryDecodeURIComponent(query[1]);\n    if (!value) {\n      return acc;\n    }\n    acc[key] = value;\n    return acc;\n  }, {});\n  return params;\n};\n\nexport const tryDecodeURIComponent = (value = '') => {\n  try {\n    return decodeURIComponent(value);\n  } catch {\n    return '';\n  }\n};\n"
  },
  {
    "path": "packages/analytics-core/src/remote-config/remote-config-localstorage.ts",
    "content": "import { RemoteConfigStorage, RemoteConfigInfo } from './remote-config';\nimport { ILogger } from '../logger';\n\nexport class RemoteConfigLocalStorage implements RemoteConfigStorage {\n  private readonly key: string;\n  private readonly logger: ILogger;\n\n  constructor(apiKey: string, logger: ILogger) {\n    this.key = `AMP_remote_config_${apiKey.substring(0, 10)}`;\n    this.logger = logger;\n  }\n\n  fetchConfig(): Promise<RemoteConfigInfo> {\n    let result: string | null = null;\n    const failedRemoteConfigInfo = {\n      remoteConfig: null,\n      lastFetch: new Date(),\n    };\n\n    try {\n      result = localStorage.getItem(this.key);\n    } catch (error) {\n      this.logger.debug('Remote config localstorage failed to access: ', error);\n      return Promise.resolve(failedRemoteConfigInfo);\n    }\n\n    if (result === null) {\n      this.logger.debug('Remote config localstorage gets null because the key does not exist');\n      return Promise.resolve(failedRemoteConfigInfo);\n    }\n\n    try {\n      const remoteConfigInfo: RemoteConfigInfo = JSON.parse(result) as RemoteConfigInfo;\n      this.logger.debug(`Remote config localstorage parsed successfully: ${JSON.stringify(remoteConfigInfo)}`);\n      return Promise.resolve({\n        remoteConfig: remoteConfigInfo.remoteConfig,\n        lastFetch: new Date(remoteConfigInfo.lastFetch),\n      });\n    } catch (error) {\n      this.logger.debug('Remote config localstorage failed to parse: ', error);\n      localStorage.removeItem(this.key);\n      return Promise.resolve(failedRemoteConfigInfo);\n    }\n  }\n\n  setConfig(config: RemoteConfigInfo): Promise<boolean> {\n    try {\n      localStorage.setItem(this.key, JSON.stringify(config));\n      this.logger.debug('Remote config localstorage set successfully.');\n      return Promise.resolve(true);\n    } catch (error) {\n      this.logger.debug('Remote config localstorage failed to set: ', error);\n    }\n    return Promise.resolve(false);\n  }\n}\n"
  },
  {
    "path": "packages/analytics-core/src/remote-config/remote-config.ts",
    "content": "import { ServerZoneType } from '../types/server-zone';\nimport { ILogger } from '../logger';\nimport { RemoteConfigLocalStorage } from './remote-config-localstorage';\nimport { UUID } from '../utils/uuid';\n\n/**\n * Modes for receiving remote config updates:\n * - `'all'` – Optimized for both speed and freshness. Returns the fastest response first\n *   (cache or remote), then always waits for and returns the remote response to ensure\n *   the most up-to-date config. Callback may be called once (if remote wins) or twice\n *   (cache first, then remote).\n * - `{ timeout: number }` – Prefers remote data but with a fallback strategy. Waits for\n *   a remote response until the specified timeout (in milliseconds), then falls back to\n *   cached data if available. Callback is called exactly once.\n */\nexport type DeliveryMode = 'all' | { timeout: number };\n\n/**\n * Sources of returned remote config:\n * - `cache` - Fetched from local storage.\n * - `remote` - Fetched from remote.\n */\nexport type Source = 'cache' | 'remote';\n\nexport const US_SERVER_URL = 'https://sr-client-cfg.amplitude.com/config';\nexport const EU_SERVER_URL = 'https://sr-client-cfg.eu.amplitude.com/config';\nexport const DEFAULT_MAX_RETRIES = 3;\nconst CODE_STATUS = {\n  INVALID_API_KEY: 401,\n  FORBIDDEN: 403,\n  RATE_LIMIT: 429,\n} as const;\n\n/**\n * The default timeout for fetch in milliseconds.\n * Linear backoff policy: timeout / retry times is the interval between fetch retry.\n */\nconst DEFAULT_TIMEOUT = 1000;\n\n/**\n * The minimum time between fetches in milliseconds.\n * This prevents too many requests from being sent in a short period of time.\n */\nconst DEFAULT_MIN_TIME_BETWEEN_FETCHES = 5 * 60 * 1000; // 5 minutes\n\nexport interface RemoteConfig {\n  [key: string]: any;\n}\n\nexport interface RemoteConfigInfo {\n  remoteConfig: RemoteConfig | null;\n  // Timestamp of when the remote config was fetched.\n  lastFetch: Date;\n}\n\nexport interface RemoteConfigStorage {\n  /**\n   * Fetch remote config from storage asynchronously.\n   */\n  fetchConfig(): Promise<RemoteConfigInfo>;\n\n  /**\n   * Set remote config to storage asynchronously.\n   */\n  setConfig(config: RemoteConfigInfo): Promise<boolean>;\n}\n\n/**\n * Information about each callback registered by `RemoteConfigClient.subscribe()`,\n * managed internally by `RemoteConfigClient`.\n */\nexport interface CallbackInfo {\n  id: string;\n  key?: string;\n  deliveryMode: DeliveryMode;\n  callback: RemoteConfigCallback;\n  lastCallback?: Date;\n}\n\n/**\n * Callback used in `RemoteConfigClient.subscribe()`.\n * This function is called when the remote config is fetched.\n */\ntype RemoteConfigCallback = (remoteConfig: RemoteConfig | null, source: Source, lastFetch: Date) => void;\n\nexport interface IRemoteConfigClient {\n  /**\n   * Subscribe for updates to remote config.\n   * Callback is guaranteed to be called at least once,\n   * Whether we are able to fetch a config or not.\n   *\n   * @param key - a string containing a series of period delimited keys to filter the returned config.\n   * Ie, {a: {b: {c: ...}}} would return {b: {c: ...}} for \"a\" or {c: ...} for \"a.b\".\n   * Set to `undefined` to subscribe all keys.\n   * @param deliveryMode - how the initial callback is sent.\n   * @param callback - a block that will be called when remote config is fetched.\n   * @return id - identification of the subscribe and can be used to unsubscribe from updates.\n   */\n  subscribe(key: string | undefined, deliveryMode: DeliveryMode, callback: RemoteConfigCallback): string;\n\n  /**\n   * Unsubscribe a callback from receiving future updates.\n   *\n   * @param id - identification of the callback that you want to unsubscribe.\n   * It's the return value of subscribe().\n   * @return boolean - whether the callback is removed.\n   */\n  unsubscribe(id: string): boolean;\n\n  /**\n   * Request the remote config client to fetch from remote, update cache, and callback.\n   */\n  updateConfigs(): void;\n}\n\nexport class RemoteConfigClient implements IRemoteConfigClient {\n  static readonly CONFIG_GROUP = 'browser';\n\n  readonly apiKey: string;\n  readonly serverUrl: string;\n  readonly logger: ILogger;\n  readonly storage: RemoteConfigStorage;\n  // Registered callbackInfos by subscribe().\n  callbackInfos: CallbackInfo[] = [];\n  // Track the last successful fetch time for throttling (timestamp in milliseconds).\n  lastSuccessfulFetch: number | null = null;\n  // Store the in-flight fetch promise for deduplication.\n  fetchPromise: Promise<RemoteConfigInfo> | null = null;\n  // Used to skip periodic updateConfigs calls when API key is invalid.\n  isLastFetchInvalidApiKey = false;\n\n  constructor(apiKey: string, logger: ILogger, serverZone: ServerZoneType = 'US', serverUrl?: string) {\n    this.apiKey = apiKey;\n    this.serverUrl = serverUrl || (serverZone === 'US' ? US_SERVER_URL : EU_SERVER_URL);\n    this.logger = logger;\n    this.storage = new RemoteConfigLocalStorage(apiKey, logger);\n  }\n\n  subscribe(key: string | undefined, deliveryMode: DeliveryMode, callback: RemoteConfigCallback): string {\n    const id = UUID();\n    const callbackInfo = {\n      id: id,\n      key: key,\n      deliveryMode: deliveryMode,\n      callback: callback,\n    };\n    this.callbackInfos.push(callbackInfo);\n\n    if (deliveryMode === 'all') {\n      void this.subscribeAll(callbackInfo);\n    } else {\n      void this.subscribeWaitForRemote(callbackInfo, deliveryMode.timeout);\n    }\n\n    return id;\n  }\n\n  unsubscribe(id: string): boolean {\n    const index = this.callbackInfos.findIndex((callbackInfo) => callbackInfo.id === id);\n    if (index === -1) {\n      this.logger.debug(`Remote config client unsubscribe failed because callback with id ${id} doesn't exist.`);\n      return false;\n    }\n\n    this.callbackInfos.splice(index, 1);\n    this.logger.debug(`Remote config client unsubscribe succeeded removing callback with id ${id}.`);\n    return true;\n  }\n\n  async updateConfigs() {\n    // Check if we need to throttle based on last successful fetch time\n    if (this.lastSuccessfulFetch) {\n      const timeSinceLastFetch = Date.now() - this.lastSuccessfulFetch;\n      if (timeSinceLastFetch < DEFAULT_MIN_TIME_BETWEEN_FETCHES) {\n        this.logger.debug('Remote config client skipping updateConfigs: Too recent');\n        return;\n      }\n    }\n\n    const result = await this.getOrCreateFetchPromise();\n    void this.storage.setConfig(result);\n    this.callbackInfos.forEach((callbackInfo) => {\n      this.sendCallback(callbackInfo, result, 'remote');\n    });\n  }\n\n  /**\n   * Get the in-flight fetch promise or create a new one.\n   * This ensures multiple subscribe calls share the same network request.\n   */\n  getOrCreateFetchPromise(): Promise<RemoteConfigInfo> {\n    if (this.fetchPromise) {\n      return this.fetchPromise;\n    }\n\n    if (this.isLastFetchInvalidApiKey) {\n      this.logger.debug('Remote config client skipping fetch: Invalid API key');\n      this.fetchPromise = Promise.resolve({\n        remoteConfig: null,\n        lastFetch: new Date(),\n      }).finally(() => {\n        this.fetchPromise = null;\n      });\n      return this.fetchPromise;\n    }\n\n    this.fetchPromise = this.fetch()\n      .then((result) => {\n        // Update last successful fetch time if we got a valid config\n        if (result.remoteConfig !== null) {\n          this.lastSuccessfulFetch = Date.now();\n        }\n        return result;\n      })\n      .finally(() => {\n        // Clear the promise after it settles (success or failure)\n        this.fetchPromise = null;\n      });\n\n    return this.fetchPromise;\n  }\n\n  /**\n   * Send remote first. If it's already complete, we can skip the cached response.\n   * - if remote is fetched first, no cache fetch.\n   * - if cache is fetched first, still fetching remote.\n   */\n  async subscribeAll(callbackInfo: CallbackInfo) {\n    const remotePromise = this.getOrCreateFetchPromise().then((result) => {\n      this.logger.debug(`Remote config client subscription all mode fetched from remote: ${JSON.stringify(result)}`);\n      this.sendCallback(callbackInfo, result, 'remote');\n      void this.storage.setConfig(result);\n    });\n\n    const cachePromise = this.storage.fetchConfig().then((result) => {\n      return result;\n    });\n\n    // Wait for the first result to resolve\n    const result = await Promise.race([remotePromise, cachePromise]);\n\n    // If cache is fetched first, wait for remote.\n    if (result !== undefined) {\n      this.logger.debug(`Remote config client subscription all mode fetched from cache: ${JSON.stringify(result)}`);\n      // Skip sending callback if cache is empty (first time user).\n      if (result.remoteConfig !== null) {\n        this.sendCallback(callbackInfo, result, 'cache');\n      } else {\n        this.logger.debug('Remote config client skips sending callback because cache is empty (first time user).');\n      }\n    }\n    await remotePromise;\n  }\n\n  /**\n   * Waits for a remote response until the given timeout, then return a cached copy, if available.\n   */\n  async subscribeWaitForRemote(callbackInfo: CallbackInfo, timeout: number) {\n    const timeoutPromise = new Promise((_, reject) => {\n      setTimeout(() => {\n        reject('Timeout exceeded');\n      }, timeout);\n    });\n\n    try {\n      const result: RemoteConfigInfo = (await Promise.race([\n        this.getOrCreateFetchPromise(),\n        timeoutPromise,\n      ])) as RemoteConfigInfo;\n\n      this.logger.debug('Remote config client subscription wait for remote mode returns from remote.');\n      this.sendCallback(callbackInfo, result, 'remote');\n      void this.storage.setConfig(result);\n    } catch (error) {\n      this.logger.debug(\n        'Remote config client subscription wait for remote mode exceeded timeout. Try to fetch from cache.',\n      );\n      const result = await this.storage.fetchConfig();\n      if (result.remoteConfig !== null) {\n        this.logger.debug('Remote config client subscription wait for remote mode returns a cached copy.');\n        this.sendCallback(callbackInfo, result, 'cache');\n      } else {\n        this.logger.debug('Remote config client subscription wait for remote mode failed to fetch cache.');\n        this.sendCallback(callbackInfo, result, 'remote');\n      }\n    }\n  }\n\n  /**\n   * Call the callback with filtered remote config based on key.\n   * @param remoteConfigInfo - the whole remote config object without filtering by key.\n   */\n  sendCallback(callbackInfo: CallbackInfo, remoteConfigInfo: RemoteConfigInfo, source: Source) {\n    callbackInfo.lastCallback = new Date();\n\n    let filteredConfig: RemoteConfig | null;\n    if (callbackInfo.key) {\n      // Filter remote config by key.\n      // For example, if remote config is {a: {b: {c: 1}}},\n      // if key = 'a', filter result is {b: {c: 1}};\n      // if key = 'a.b', filter result is {c: 1}\n      filteredConfig = callbackInfo.key.split('.').reduce((config, key) => {\n        if (config === null) {\n          return config;\n        }\n\n        return key in config ? (config[key] as RemoteConfig) : null;\n      }, remoteConfigInfo.remoteConfig);\n    } else {\n      filteredConfig = remoteConfigInfo.remoteConfig;\n    }\n\n    callbackInfo.callback(filteredConfig, source, remoteConfigInfo.lastFetch);\n  }\n\n  /**\n   * Fetch remote config from remote.\n   * @param retries - the number of retries. default is 3.\n   * @param timeout - the timeout in milliseconds. Default is 1000.\n   * This timeout serves two purposes:\n   * 1. It determines how long to wait for each remote config fetch request before aborting it.\n   *    If the fetch does not complete within the specified timeout, the request is cancelled using AbortController,\n   *    and the attempt is considered failed (and may be retried if retries remain).\n   * 2. It is also used to calculate the interval between retries. The total timeout is divided by the number of retries,\n   *    so each retry waits for (timeout / retries) milliseconds before the next attempt (linear backoff).\n   * Retry behavior by status code:\n   * - 401: invalid API key (stop retries and disable future updateConfigs calls).\n   * - 429: retry up to max retries.\n   * - other 4xx: no retry.\n   * - 5xx and network failures: retry up to max retries.\n   * @returns the remote config info. null if failed to fetch or the response is not valid JSON.\n   */\n  async fetch(retries: number = DEFAULT_MAX_RETRIES, timeout: number = DEFAULT_TIMEOUT): Promise<RemoteConfigInfo> {\n    const interval = timeout / retries;\n    const failedRemoteConfigInfo: RemoteConfigInfo = {\n      remoteConfig: null,\n      lastFetch: new Date(),\n    };\n\n    for (let attempt = 0; attempt < retries; attempt++) {\n      let shouldRetry = true;\n      // Create AbortController for request timeout\n      const abortController = new AbortController();\n      const timeoutId = setTimeout(() => abortController.abort(), timeout);\n\n      try {\n        const res = await fetch(this.getUrlParams(), {\n          method: 'GET',\n          headers: {\n            Accept: '*/*',\n          },\n          signal: abortController.signal,\n        });\n\n        // Handle unsuccessful fetch\n        if (!res.ok) {\n          const body = await res.text();\n          this.logger.debug(`Remote config client fetch with retry time ${retries} failed with ${res.status}: ${body}`);\n\n          if (res.status === CODE_STATUS.INVALID_API_KEY || res.status === CODE_STATUS.FORBIDDEN) {\n            this.logger.error(\n              `Remote config client fetch failed with ${res.status}. Invalid API key; future fetches will be skipped.`,\n            );\n            this.isLastFetchInvalidApiKey = true;\n            shouldRetry = false;\n          } else if (res.status >= 400 && res.status < 500 && res.status !== CODE_STATUS.RATE_LIMIT) {\n            shouldRetry = false;\n          }\n        } else {\n          // Handle successful fetch\n          const remoteConfig: RemoteConfig = (await res.json()) as RemoteConfig;\n          return {\n            remoteConfig: remoteConfig,\n            lastFetch: new Date(),\n          };\n        }\n      } catch (error) {\n        // Handle rejects when the request fails, for example, a network error or timeout\n        if (error instanceof Error && error.name === 'AbortError') {\n          this.logger.debug(`Remote config client fetch with retry time ${retries} timed out after ${timeout}ms`);\n        } else {\n          this.logger.debug(`Remote config client fetch with retry time ${retries} is rejected because: `, error);\n        }\n      } finally {\n        // Clear the timeout since request completed or failed\n        clearTimeout(timeoutId);\n      }\n\n      if (!shouldRetry) {\n        break;\n      }\n\n      // Linear backoff:\n      // wait for the specified interval before the next attempt\n      // except after the last attempt.\n      if (attempt < retries - 1) {\n        await new Promise((resolve) => setTimeout(resolve, this.getJitterDelay(interval)));\n      }\n    }\n\n    return failedRemoteConfigInfo;\n  }\n\n  /**\n   * Return jitter in the bound of [0,baseDelay) and then floor round.\n   */\n  getJitterDelay(baseDelay: number): number {\n    return Math.floor(Math.random() * baseDelay);\n  }\n\n  getUrlParams(): string {\n    // URL encode the API key to handle special characters\n    const encodedApiKey = encodeURIComponent(this.apiKey);\n\n    const urlParams = new URLSearchParams();\n    urlParams.append('config_group', RemoteConfigClient.CONFIG_GROUP);\n\n    return `${this.serverUrl}/${encodedApiKey}?${urlParams.toString()}`;\n  }\n}\n"
  },
  {
    "path": "packages/analytics-core/src/revenue.ts",
    "content": "import { isValidObject } from './utils/valid-properties';\n\nexport interface IRevenue {\n  getEventProperties(): RevenueEventProperties;\n  setProductId(productId: string): IRevenue;\n  setQuantity(quantity: number): IRevenue;\n  setPrice(price: number): IRevenue;\n  setRevenueType(revenueType: string): IRevenue;\n  setCurrency(currency: string): IRevenue;\n  setEventProperties(properties: { [key: string]: any }): IRevenue;\n  setRevenue(revenue: number): IRevenue;\n  setReceipt(receipt: string): IRevenue;\n  setReceiptSig(receiptSig: string): IRevenue;\n}\n\nexport class Revenue implements IRevenue {\n  private productId: string;\n  private quantity: number;\n  private price: number;\n  private revenueType?: string;\n  private currency?: string;\n  private properties?: { [key: string]: any };\n  private revenue?: number;\n  private receipt?: string;\n  private receiptSig?: string;\n\n  constructor() {\n    this.productId = '';\n    this.quantity = 1;\n    this.price = 0.0;\n  }\n\n  setProductId(productId: string) {\n    this.productId = productId;\n    return this;\n  }\n\n  setQuantity(quantity: number) {\n    if (quantity > 0) {\n      this.quantity = quantity;\n    }\n    return this;\n  }\n\n  setPrice(price: number) {\n    this.price = price;\n    return this;\n  }\n\n  setRevenueType(revenueType: string) {\n    this.revenueType = revenueType;\n    return this;\n  }\n\n  setCurrency(currency: string) {\n    this.currency = currency;\n    return this;\n  }\n\n  setRevenue(revenue: number) {\n    this.revenue = revenue;\n    return this;\n  }\n\n  setReceipt(receipt: string) {\n    this.receipt = receipt;\n    return this;\n  }\n\n  setReceiptSig(receiptSig: string) {\n    this.receiptSig = receiptSig;\n    return this;\n  }\n\n  setEventProperties(properties: { [key: string]: ValidPropertyType }) {\n    try {\n      // JSON.stringify drops undefined/function/symbol values before validation,\n      // so a single undefined property no longer causes the whole object to be rejected.\n      const filtered = JSON.parse(JSON.stringify(properties)) as { [key: string]: ValidPropertyType };\n      if (isValidObject(filtered)) {\n        this.properties = filtered;\n      }\n    } catch {\n      // no-op: invalid properties are ignored\n    }\n    return this;\n  }\n\n  getEventProperties(): RevenueEventProperties {\n    const eventProperties: RevenueEventProperties = this.properties ? { ...this.properties } : {};\n    eventProperties[RevenueProperty.REVENUE_PRODUCT_ID] = this.productId;\n    eventProperties[RevenueProperty.REVENUE_QUANTITY] = this.quantity;\n    eventProperties[RevenueProperty.REVENUE_PRICE] = this.price;\n    eventProperties[RevenueProperty.REVENUE_TYPE] = this.revenueType;\n    eventProperties[RevenueProperty.REVENUE_CURRENCY] = this.currency;\n    eventProperties[RevenueProperty.REVENUE] = this.revenue;\n    eventProperties[RevenueProperty.RECEIPT] = this.receipt;\n    eventProperties[RevenueProperty.RECEIPT_SIG] = this.receiptSig;\n    return eventProperties;\n  }\n}\n\nexport interface RevenueEventProperties {\n  [RevenueProperty.REVENUE_PRODUCT_ID]?: string;\n  [RevenueProperty.REVENUE_QUANTITY]?: number;\n  [RevenueProperty.REVENUE_PRICE]?: number;\n  [RevenueProperty.REVENUE_TYPE]?: string;\n  [RevenueProperty.REVENUE_CURRENCY]?: string;\n  [RevenueProperty.REVENUE]?: number;\n  [RevenueProperty.RECEIPT]?: string;\n  [RevenueProperty.RECEIPT_SIG]?: string;\n}\n\nexport enum RevenueProperty {\n  REVENUE_PRODUCT_ID = '$productId',\n  REVENUE_QUANTITY = '$quantity',\n  REVENUE_PRICE = '$price',\n  REVENUE_TYPE = '$revenueType',\n  REVENUE_CURRENCY = '$currency',\n  REVENUE = '$revenue',\n  RECEIPT = '$receipt',\n  RECEIPT_SIG = '$receiptSig',\n}\n\nexport type ValidPropertyType =\n  | number\n  | string\n  | boolean\n  | Array<string | number>\n  | { [key: string]: ValidPropertyType }\n  | Array<{ [key: string]: ValidPropertyType }>;\n"
  },
  {
    "path": "packages/analytics-core/src/session.ts",
    "content": "export const isNewSession = (sessionTimeout: number, lastEventTime: number = Date.now()): boolean => {\n  const currentTime = Date.now();\n  const timeSinceLastEvent = currentTime - lastEventTime;\n\n  return timeSinceLastEvent > sessionTimeout;\n};\n"
  },
  {
    "path": "packages/analytics-core/src/storage/browser-storage.ts",
    "content": "import { Storage as AmplitudeStorage } from '../types/storage';\n\nexport class BrowserStorage<T> implements AmplitudeStorage<T> {\n  constructor(private storage?: Storage) {}\n\n  async isEnabled(): Promise<boolean> {\n    /* istanbul ignore if */\n    if (!this.storage) {\n      return false;\n    }\n\n    const random = String(Date.now());\n    const testStorage = new BrowserStorage<string>(this.storage);\n    const testKey = 'AMP_TEST';\n    try {\n      await testStorage.set(testKey, random);\n      const value = await testStorage.get(testKey);\n      return value === random;\n    } catch {\n      /* istanbul ignore next */\n      return false;\n    } finally {\n      await testStorage.remove(testKey);\n    }\n  }\n\n  async get(key: string): Promise<T | undefined> {\n    try {\n      const value = await this.getRaw(key);\n      if (!value) {\n        return undefined;\n      }\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n      return JSON.parse(value);\n    } catch {\n      console.error(`[Amplitude] Error: Could not get value from storage`);\n      return undefined;\n    }\n  }\n\n  async getRaw(key: string): Promise<string | undefined> {\n    return this.storage?.getItem(key) || undefined;\n  }\n\n  async set(key: string, value: T): Promise<void> {\n    try {\n      this.storage?.setItem(key, JSON.stringify(value));\n    } catch {\n      //\n    }\n  }\n\n  async remove(key: string): Promise<void> {\n    try {\n      this.storage?.removeItem(key);\n    } catch {\n      //\n    }\n  }\n\n  async reset(): Promise<void> {\n    try {\n      this.storage?.clear();\n    } catch {\n      //\n    }\n  }\n}\n"
  },
  {
    "path": "packages/analytics-core/src/storage/cookie.ts",
    "content": "import { Storage, StorageSync, CookieStorageOptions, CookieStorageConfig } from '../types/storage';\nimport { getGlobalScope } from '../global-scope';\n\n// CookieStore is a Web API not included in standard TypeScript lib types\n// https://developer.mozilla.org/en-US/docs/Web/API/CookieStore\ninterface CookieStoreSetOptions {\n  name: string;\n  value: string;\n  expires?: number;\n  domain?: string;\n  sameSite?: 'strict' | 'lax' | 'none';\n}\n\ninterface CookieStore {\n  getAll(key: string): Promise<CookieStoreSetOptions[] | undefined>;\n}\n\ntype GlobalScopeWithCookieStore = {\n  cookieStore?: CookieStore;\n} & typeof global;\n\n/* istanbul ignore next */\nconst getLocks = (): typeof global.navigator.locks | undefined => {\n  const globalScope = getGlobalScope();\n  return globalScope?.navigator?.locks;\n};\n\nexport class CookieStorage<T> implements Storage<T> {\n  options: CookieStorageOptions;\n  config: CookieStorageConfig;\n\n  private static cachedTlds: Record<string, boolean> = {};\n\n  constructor(options?: CookieStorageOptions, config: CookieStorageConfig = {}) {\n    this.options = { ...options };\n    this.config = config;\n  }\n\n  async isEnabled(): Promise<boolean> {\n    const testKey = 'AMP_TEST';\n    const testCookieOptions = { ...this.options };\n    const testStorage = new CookieStorage<string>(testCookieOptions);\n    const testValue = String(Date.now());\n    return await testStorage.transaction<boolean>(testKey, (storage: StorageSync<string>) => {\n      try {\n        storage.set(testValue);\n        const value = storage.get();\n        const result = value === testValue;\n        /* istanbul ignore next */\n        if (!result && this.config.diagnosticsClient) {\n          this.config.diagnosticsClient?.recordEvent('cookies.isEnabled.failure', {\n            reason: 'Test Value mismatch',\n            testKey,\n            testValue,\n            sync: true,\n          });\n        }\n        return result;\n      } catch (e) {\n        /* istanbul ignore next */\n        if (this.config.diagnosticsClient) {\n          const errMessage = e instanceof Error ? e.message : String(e);\n          this.config.diagnosticsClient?.recordEvent('cookies.isEnabled.failure', {\n            reason: 'Cookie getter/setter failed',\n            testKey,\n            testValue,\n            error: errMessage,\n            sync: true,\n          });\n        }\n        return false;\n      } finally {\n        // clean-up the AMP_TEST cookie behind us\n        storage.set(null);\n      }\n    });\n  }\n\n  async get(key: string): Promise<T | undefined> {\n    const value = await this.getRaw(key);\n    return this.decodeCookieValue(key, value);\n  }\n\n  private decodeCookieValue(key: string, value: string | undefined): T | undefined {\n    if (!value) {\n      return undefined;\n    }\n    try {\n      const decodedValue = decodeCookieValue(value);\n      if (decodedValue === undefined) {\n        console.error(`Amplitude Logger [Error]: Failed to decode cookie value for key: ${key}, value: ${value}`);\n        return undefined;\n      }\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n      return JSON.parse(decodedValue);\n    } catch {\n      console.error(`Amplitude Logger [Error]: Failed to parse cookie value for key: ${key}, value: ${value}`);\n      return undefined;\n    }\n  }\n\n  private getSync(key: string): T | undefined {\n    const value = this.getRawSync(key);\n    return this.decodeCookieValue(key, value);\n  }\n\n  async getRaw(key: string): Promise<string | undefined> {\n    const globalScope = getGlobalScope();\n\n    // use CookieStore if available and enabled\n    const globalScopeWithCookiesStore = globalScope as GlobalScopeWithCookieStore;\n    try {\n      const cookieStore = globalScopeWithCookiesStore?.cookieStore;\n      if (cookieStore) {\n        const cookies = await cookieStore.getAll(key);\n        if (cookies) {\n          /* istanbul ignore if */\n          if (cookies.length > 1) {\n            this.config.diagnosticsClient?.recordEvent('cookies.duplicate', {\n              cookies: cookies.map((cookie) => cookie.domain),\n            });\n            this.config.diagnosticsClient?.increment('cookies.duplicate.occurrence.cookieStore');\n          }\n\n          for (const cookie of cookies) {\n            if (isDomainEqual(cookie.domain, this.options.domain)) {\n              return cookie.value;\n            }\n          }\n        }\n      }\n    } catch (ignoreError) {\n      /* istanbul ignore next */\n      // if cookieStore had a surprise failure, fallback to document.cookie\n    }\n\n    return this.getRawSync(key);\n  }\n\n  private getRawSync(key: string): string | undefined {\n    const globalScope = getGlobalScope();\n    const cookies = (globalScope?.document?.cookie.split('; ') ?? []).filter((c) => c.indexOf(key + '=') === 0);\n    let match: string | undefined = undefined;\n\n    // if matcher function is provided, use it to de-duplicate when there's more than one cookie\n    /* istanbul ignore if */\n    const duplicateResolverFn = this.config.duplicateResolverFn;\n    if (typeof duplicateResolverFn === 'function' && cookies.length > 1) {\n      match = cookies.find((c) => {\n        try {\n          const res = duplicateResolverFn(c.substring(key.length + 1));\n          if (!res) {\n            this.config.diagnosticsClient?.increment('cookies.duplicate.occurrence.document.cookie');\n          }\n          return res;\n        } catch (ignoreError) {\n          /* istanbul ignore next */\n          return false;\n        }\n      });\n    }\n\n    // if match was not found, just get the first one that matches the key\n    if (!match) {\n      match = cookies[0];\n    }\n    if (!match) {\n      return undefined;\n    }\n    return match.substring(key.length + 1);\n  }\n\n  async set(key: string, value: T | null): Promise<void> {\n    this.setSync(key, value);\n  }\n\n  private setSync(key: string, value: T | null): void {\n    try {\n      const expirationDays = this.options.expirationDays ?? 0;\n      const expires = value !== null ? expirationDays : -1;\n      let expireDate: Date | undefined = undefined;\n      if (expires) {\n        const date = new Date();\n        date.setTime(date.getTime() + expires * 24 * 60 * 60 * 1000);\n        expireDate = date;\n      }\n      let str = `${key}=${btoa(encodeURIComponent(JSON.stringify(value)))}`;\n      if (expireDate) {\n        str += `; expires=${expireDate.toUTCString()}`;\n      }\n      str += '; path=/';\n      if (this.options.domain) {\n        str += `; domain=${this.options.domain}`;\n      }\n      if (this.options.secure) {\n        str += '; Secure';\n      }\n      if (this.options.sameSite) {\n        str += `; SameSite=${this.options.sameSite}`;\n      }\n      const globalScope = getGlobalScope();\n      if (globalScope?.document) {\n        globalScope.document.cookie = str;\n      }\n    } catch (error) {\n      const errorMessage = error instanceof Error ? error.message : String(error);\n      console.error(`Amplitude Logger [Error]: Failed to set cookie for key: ${key}. Error: ${errorMessage}`);\n    }\n  }\n\n  async remove(key: string): Promise<void> {\n    await this.set(key, null);\n  }\n\n  async reset(): Promise<void> {\n    return;\n  }\n\n  static async isDomainWritable(domain: string): Promise<boolean> {\n    if (CookieStorage.cachedTlds[domain]) {\n      return true;\n    }\n    const options = {\n      domain: '.' + domain,\n    };\n    const storageKey = 'AMP_TLDTEST';\n    const storage = new CookieStorage<number>(options);\n    try {\n      const res = await storage.transaction(storageKey, (storageSync) => {\n        if (CookieStorage.cachedTlds[domain]) {\n          return true;\n        }\n        try {\n          storageSync.set(1);\n          const result = !!storageSync.get();\n          if (result) {\n            CookieStorage.cachedTlds[domain] = true;\n          }\n          return result;\n        } finally {\n          storageSync.set(null);\n        }\n      });\n      return !!res;\n    } catch (error) {\n      return false;\n    }\n  }\n\n  private async transaction<ReturnType>(\n    key: string,\n    callback: (storageSync: StorageSync<T>) => ReturnType,\n  ): Promise<ReturnType> {\n    const locks = getLocks();\n    const callbackWrapper = () => {\n      // construct a sync storage object that is scoped to\n      // Cookie with name <key>\n      const storageSync: StorageSync<T> = {\n        get: () => this.getSync(key),\n        set: (value: T | null) => this.setSync(key, value),\n      };\n      return callback(storageSync);\n    };\n\n    // if 'locks' is missing, it is a legacy browser, just call the callback directly\n    // and settle for a transaction that isn't isolated across tabs\n    if (!locks) {\n      return callbackWrapper();\n    }\n    try {\n      return (await locks.request(`com.amplitude:cookie-lock:${key}`, callbackWrapper)) as ReturnType;\n    } catch (error) {\n      return callbackWrapper();\n    }\n  }\n}\n\nconst decodeCookiesAsDefault = (value: string): string | undefined => {\n  try {\n    return decodeURIComponent(atob(value));\n  } catch {\n    return undefined;\n  }\n};\n\nconst decodeCookiesWithDoubleUrlEncoding = (value: string): string | undefined => {\n  // Modern Ruby (v7+) automatically encodes cookies with URL encoding by\n  // https://api.rubyonrails.org/classes/ActionDispatch/Cookies.html\n  try {\n    return decodeURIComponent(atob(decodeURIComponent(value)));\n  } catch {\n    return undefined;\n  }\n};\n\n/**\n * Decodes a cookie value that was encoded with btoa(encodeURIComponent(...)).\n * Handles both standard encoding and double URL encoding (used by Ruby Rails v7+).\n */\nexport const decodeCookieValue = (value: string): string | undefined => {\n  return decodeCookiesAsDefault(value) ?? decodeCookiesWithDoubleUrlEncoding(value);\n};\n\n/**\n * Compares two domain strings for equality, ignoring leading dots.\n * This is useful for comparing cookie domains since \".example.com\" and \"example.com\"\n * are effectively equivalent for cookie scoping.\n */\nexport const isDomainEqual = (domain1: string | undefined, domain2: string | undefined): boolean => {\n  if (domain1 === '' && domain2 === '') {\n    return true;\n  }\n  if (!domain1 || !domain2) {\n    return false;\n  }\n  const normalized1 = domain1.startsWith('.') ? domain1.substring(1) : domain1;\n  const normalized2 = domain2.startsWith('.') ? domain2.substring(1) : domain2;\n  return normalized1.toLowerCase() === normalized2.toLowerCase();\n};\n"
  },
  {
    "path": "packages/analytics-core/src/storage/helpers.ts",
    "content": "import { AMPLITUDE_PREFIX } from '../types/constants';\n\nexport const getStorageKey = (apiKey: string, postKey = '', limit = 10) => {\n  return [AMPLITUDE_PREFIX, postKey, apiKey.substring(0, limit)].filter(Boolean).join('_');\n};\n"
  },
  {
    "path": "packages/analytics-core/src/storage/memory.ts",
    "content": "import { Storage } from '../types/storage';\n\nexport class MemoryStorage<T> implements Storage<T> {\n  memoryStorage: Map<string, T> = new Map();\n\n  async isEnabled(): Promise<boolean> {\n    return true;\n  }\n\n  async get(key: string): Promise<T | undefined> {\n    return this.memoryStorage.get(key);\n  }\n\n  async getRaw(key: string): Promise<string | undefined> {\n    const value = await this.get(key);\n    return value ? JSON.stringify(value) : undefined;\n  }\n\n  async set(key: string, value: T): Promise<void> {\n    this.memoryStorage.set(key, value);\n  }\n\n  async remove(key: string): Promise<void> {\n    this.memoryStorage.delete(key);\n  }\n\n  async reset(): Promise<void> {\n    this.memoryStorage.clear();\n  }\n}\n"
  },
  {
    "path": "packages/analytics-core/src/timeline.ts",
    "content": "import { AnalyticsIdentity, BeforePlugin, DestinationPlugin, EnrichmentPlugin, Plugin } from './types/plugin';\nimport { CoreClient } from './types/client/core-client';\nimport { IConfig } from './types/config/core-config';\nimport { ILogger } from './logger';\nimport { EventCallback } from './types/event-callback';\nimport { Event } from './types/event/event';\nimport { Result } from './types/result';\nimport { buildResult } from './utils/result-builder';\nimport { UUID } from './utils/uuid';\n\ntype PluginStatus = 'locked' | 'installed';\n\nexport class Timeline {\n  queue: [Event, EventCallback][] = [];\n  // Flag to guarantee one schedule apply is running\n  applying = false;\n  plugins: Plugin[] = [];\n  // Locks plugin names synchronously before `await plugin.setup?.()` so a concurrent\n  // register() with the same name bails. plugins[] only contains fully-installed plugins,\n  // so this map is the only source of truth for in-flight installs. Cleared per-name by\n  // deregister() and en masse by reset().\n  pluginStatus: Map<string, PluginStatus> = new Map();\n  // loggerProvider is set by the client at _init()\n  // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n  // @ts-ignore\n  loggerProvider: ILogger;\n  _optOutListeners: ((optOut: boolean) => Promise<void>)[] = [];\n\n  constructor(private client: CoreClient) {}\n\n  async register(plugin: Plugin, config: IConfig) {\n    if (plugin.name === undefined) {\n      plugin.name = UUID();\n      this.loggerProvider.warn(`Plugin name is undefined.\n      Generating a random UUID for plugin name: ${plugin.name}.\n      Set a name for the plugin to prevent it from being added multiple times.`);\n    }\n    const name = plugin.name;\n\n    if (this.pluginStatus.has(name)) {\n      this.loggerProvider.warn(`Plugin with name ${name} already exists, skipping registration`);\n      return;\n    }\n\n    plugin.type = plugin.type ?? 'enrichment';\n    // Lock the name synchronously to close the TOCTOU window across `await setup`.\n    // If setup throws, the entry stays as 'locked' and blocks future re-registration —\n    // a same-named plugin would just fail again, so retry isn't useful.\n    this.pluginStatus.set(name, 'locked');\n    await plugin.setup?.(config, this.client);\n    // reset() may have cleared the status map while setup was awaiting.\n    if (this.pluginStatus.get(name) !== 'locked') {\n      return;\n    }\n    this.plugins.push(plugin);\n    this.pluginStatus.set(name, 'installed');\n  }\n\n  async deregister(pluginName: string, config: IConfig) {\n    // Clear the status first so a name stuck in 'locked' (mid-install, or setup() threw)\n    // can be unlocked via deregister(). Map.delete is a no-op if the key is missing.\n    this.pluginStatus.delete(pluginName);\n    const index = this.plugins.findIndex((plugin) => plugin.name === pluginName);\n    if (index === -1) {\n      config.loggerProvider.warn(`Plugin with name ${pluginName} does not exist, skipping deregistration`);\n      return;\n    }\n    const plugin = this.plugins[index];\n    this.plugins.splice(index, 1);\n    await plugin.teardown?.();\n  }\n\n  reset(client: CoreClient) {\n    this._clearOptOutListeners();\n    this.applying = false;\n    const plugins = this.plugins;\n    plugins.map((plugin) => plugin.teardown?.());\n    this.plugins = [];\n    this.pluginStatus.clear();\n    this.client = client;\n  }\n\n  push(event: Event) {\n    return new Promise<Result>((resolve) => {\n      this.queue.push([event, resolve]);\n      this.scheduleApply(0);\n    });\n  }\n\n  scheduleApply(timeout: number) {\n    if (this.applying) return;\n    this.applying = true;\n    setTimeout(() => {\n      void this.apply(this.queue.shift()).then(() => {\n        this.applying = false;\n        if (this.queue.length > 0) {\n          this.scheduleApply(0);\n        }\n      });\n    }, timeout);\n  }\n\n  async apply(item: [Event, EventCallback] | undefined) {\n    if (!item) {\n      return;\n    }\n\n    let [event] = item;\n    const [, resolve] = item;\n\n    // Log initial event\n    this.loggerProvider.log('Timeline.apply: Initial event', event);\n\n    const before = this.plugins.filter<BeforePlugin>(\n      (plugin: Plugin): plugin is BeforePlugin => plugin.type === 'before',\n    );\n\n    for (const plugin of before) {\n      /* istanbul ignore if */\n      if (!plugin.execute) {\n        // do nothing\n        continue;\n      }\n      const e = await plugin.execute({ ...event });\n      if (e === null) {\n        this.loggerProvider.log(\n          `Timeline.apply: Event filtered out by before plugin '${String(plugin.name)}', event: ${JSON.stringify(\n            event,\n          )}`,\n        );\n        resolve({ event, code: 0, message: '' });\n        return;\n      } else {\n        event = e;\n        this.loggerProvider.log(\n          `Timeline.apply: Event after before plugin '${String(plugin.name)}', event: ${JSON.stringify(event)}`,\n        );\n      }\n    }\n\n    const enrichment = this.plugins.filter<EnrichmentPlugin>(\n      (plugin: Plugin): plugin is EnrichmentPlugin => plugin.type === 'enrichment' || plugin.type === undefined,\n    );\n\n    for (const plugin of enrichment) {\n      /* istanbul ignore if */\n      if (!plugin.execute) {\n        // do nothing\n        continue;\n      }\n      const e = await plugin.execute({ ...event });\n      if (e === null) {\n        this.loggerProvider.log(\n          `Timeline.apply: Event filtered out by enrichment plugin '${String(plugin.name)}', event: ${JSON.stringify(\n            event,\n          )}`,\n        );\n        resolve({ event, code: 0, message: '' });\n        return;\n      } else {\n        event = e;\n        this.loggerProvider.log(\n          `Timeline.apply: Event after enrichment plugin '${String(plugin.name)}', event: ${JSON.stringify(event)}`,\n        );\n      }\n    }\n\n    const destination = this.plugins.filter<DestinationPlugin>(\n      (plugin: Plugin): plugin is DestinationPlugin => plugin.type === 'destination',\n    );\n\n    // Log final event before sending to destinations\n    this.loggerProvider.log(`Timeline.apply: Final event before destinations, event: ${JSON.stringify(event)}`);\n\n    const executeDestinations = destination.map((plugin) => {\n      const eventClone = { ...event };\n      return plugin.execute(eventClone).catch((e) => buildResult(eventClone, 0, String(e)));\n    });\n\n    void Promise.all(executeDestinations).then(([result]) => {\n      const resolveResult =\n        result || buildResult(event, 100, 'Event not tracked, no destination plugins on the instance');\n      resolve(resolveResult);\n    });\n\n    return;\n  }\n\n  async flush() {\n    const queue = this.queue;\n    this.queue = [];\n\n    await Promise.all(queue.map((item) => this.apply(item)));\n\n    const destination = this.plugins.filter<DestinationPlugin>(\n      (plugin: Plugin): plugin is DestinationPlugin => plugin.type === 'destination',\n    );\n\n    const executeDestinations = destination.map((plugin) => {\n      return plugin.flush && plugin.flush();\n    });\n\n    await Promise.all(executeDestinations);\n  }\n\n  addOptOutListener(cb: (optOut: boolean) => Promise<void>) {\n    this._optOutListeners.push(cb);\n  }\n\n  _clearOptOutListeners() {\n    this._optOutListeners = [];\n  }\n\n  onIdentityChanged(identity: AnalyticsIdentity) {\n    this.plugins.forEach((plugin) => {\n      // Intentionally to not await plugin.onIdentityChanged() for non-blocking.\n      // Ignore optional channing next line for test coverage.\n      // If the plugin doesn't implement it, it won't be called.\n      /* istanbul ignore next */\n      void plugin.onIdentityChanged?.(identity);\n    });\n  }\n\n  onSessionIdChanged(sessionId: number) {\n    this.plugins.forEach((plugin) => {\n      // Intentionally to not await plugin.onSessionIdChanged() for non-blocking.\n      // Ignore optional channing next line for test coverage.\n      // If the plugin doesn't implement it, it won't be called.\n      /* istanbul ignore next */\n      void plugin.onSessionIdChanged?.(sessionId);\n    });\n  }\n\n  onOptOutChanged(optOut: boolean) {\n    this.plugins.forEach((plugin) => {\n      // Intentionally to not await plugin.onOptOutChanged() for non-blocking.\n      // Ignore optional channing next line for test coverage.\n      // If the plugin doesn't implement it, it won't be called.\n      /* istanbul ignore next */\n      void plugin.onOptOutChanged?.(optOut);\n    });\n    void this._callOptOutListeners(optOut);\n  }\n\n  async _callOptOutListeners(optOut: boolean) {\n    for (const listener of this._optOutListeners) {\n      try {\n        await listener(optOut);\n      } catch (e) {\n        /* istanbul ignore next */\n        this.loggerProvider.error('Error calling optOut listener', e);\n      }\n    }\n  }\n\n  onReset() {\n    this.plugins.forEach((plugin) => {\n      // Intentionally to not await plugin.onReset() for non-blocking.\n      // Ignore optional channing next line for test coverage.\n      // If the plugin doesn't implement it, it won't be called.\n      /* istanbul ignore next */\n      void plugin.onReset?.();\n    });\n  }\n}\n"
  },
  {
    "path": "packages/analytics-core/src/transports/base.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unsafe-argument */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-unsafe-call */\nimport { Transport } from '../types/transport';\nimport { Status } from '../types/status';\nimport { Payload } from '../types/payload';\nimport { Response } from '../types/response';\nimport { isSuccessStatusCode } from '../utils/status-code';\n\nexport class BaseTransport implements Transport {\n  send(_serverUrl: string, _payload: Payload, _enableRequestBodyCompression?: boolean): Promise<Response | null> {\n    return Promise.resolve(null);\n  }\n\n  buildResponse(responseJSON: Record<string, any>): Response | null {\n    if (typeof responseJSON !== 'object') {\n      return null;\n    }\n\n    const statusCode = responseJSON.code || 0;\n    const status = this.buildStatus(statusCode);\n\n    switch (status) {\n      case Status.Success:\n        return {\n          status,\n          statusCode,\n          body: {\n            eventsIngested: responseJSON.events_ingested ?? 0,\n            payloadSizeBytes: responseJSON.payload_size_bytes ?? 0,\n            serverUploadTime: responseJSON.server_upload_time ?? 0,\n          },\n        };\n\n      case Status.Invalid:\n        return {\n          status,\n          statusCode,\n          body: {\n            error: responseJSON.error ?? '',\n            missingField: responseJSON.missing_field ?? '',\n            eventsWithInvalidFields: responseJSON.events_with_invalid_fields ?? {},\n            eventsWithMissingFields: responseJSON.events_with_missing_fields ?? {},\n            eventsWithInvalidIdLengths: responseJSON.events_with_invalid_id_lengths ?? {},\n            epsThreshold: responseJSON.eps_threshold ?? 0,\n            exceededDailyQuotaDevices: responseJSON.exceeded_daily_quota_devices ?? {},\n            silencedDevices: responseJSON.silenced_devices ?? [],\n            silencedEvents: responseJSON.silenced_events ?? [],\n            throttledDevices: responseJSON.throttled_devices ?? {},\n            throttledEvents: responseJSON.throttled_events ?? [],\n          },\n        };\n      case Status.PayloadTooLarge:\n        return {\n          status,\n          statusCode,\n          body: {\n            error: responseJSON.error ?? '',\n          },\n        };\n      case Status.RateLimit:\n        return {\n          status,\n          statusCode,\n          body: {\n            error: responseJSON.error ?? '',\n            epsThreshold: responseJSON.eps_threshold ?? 0,\n            throttledDevices: responseJSON.throttled_devices ?? {},\n            throttledUsers: responseJSON.throttled_users ?? {},\n            exceededDailyQuotaDevices: responseJSON.exceeded_daily_quota_devices ?? {},\n            exceededDailyQuotaUsers: responseJSON.exceeded_daily_quota_users ?? {},\n            throttledEvents: responseJSON.throttled_events ?? [],\n          },\n        };\n      case Status.Timeout:\n      default:\n        return {\n          status,\n          statusCode,\n        };\n    }\n  }\n\n  buildStatus(code: number): Status {\n    if (isSuccessStatusCode(code)) {\n      return Status.Success;\n    }\n\n    if (code === 429) {\n      return Status.RateLimit;\n    }\n\n    if (code === 413) {\n      return Status.PayloadTooLarge;\n    }\n\n    if (code === 408) {\n      return Status.Timeout;\n    }\n\n    if (code >= 400 && code < 500) {\n      return Status.Invalid;\n    }\n\n    if (code >= 500) {\n      return Status.Failed;\n    }\n\n    return Status.Unknown;\n  }\n}\n"
  },
  {
    "path": "packages/analytics-core/src/transports/fetch.ts",
    "content": "import { BaseTransport } from './base';\nimport { Transport } from '../types/transport';\nimport { Payload } from '../types/payload';\nimport { Response } from '../types/response';\n\nexport class FetchTransport extends BaseTransport implements Transport {\n  private customHeaders: Record<string, string>;\n\n  constructor(customHeaders: Record<string, string> = {}) {\n    super();\n    this.customHeaders = customHeaders;\n  }\n\n  async send(serverUrl: string, payload: Payload): Promise<Response | null> {\n    /* istanbul ignore if */\n    if (typeof fetch === 'undefined') {\n      throw new Error('FetchTransport is not supported');\n    }\n    const options: RequestInit = {\n      headers: {\n        'Content-Type': 'application/json',\n        Accept: '*/*',\n        ...this.customHeaders,\n      },\n      body: JSON.stringify(payload),\n      method: 'POST',\n    };\n    const response = await fetch(serverUrl, options);\n    const responseText = await response.text();\n    try {\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n      return this.buildResponse(JSON.parse(responseText));\n    } catch {\n      return this.buildResponse({ code: response.status });\n    }\n  }\n}\n"
  },
  {
    "path": "packages/analytics-core/src/transports/gzip.ts",
    "content": "// CompressionStream is a Web API not included in TypeScript's dom/es6 libs.\ndeclare const CompressionStream:\n  | {\n      new (format: string): { readable: ReadableStream; writable: WritableStream };\n    }\n  | undefined;\n\nexport const MIN_GZIP_UPLOAD_BODY_SIZE_BYTES = 2 * 1024;\n\n/**\n * Returns true if CompressionStream is available (e.g. in supported browsers).\n */\nexport function isCompressionStreamAvailable(): boolean {\n  return typeof CompressionStream !== 'undefined';\n}\n\n/**\n * Compress a string to gzip and return the result as an ArrayBuffer.\n * Best-effort: returns undefined if CompressionStream is unavailable or compression fails.\n * Payload is small so buffering is fine. Used by Fetch and XHR transports.\n */\nexport async function compressToGzipArrayBuffer(data: string): Promise<ArrayBuffer | undefined> {\n  const CompressionStreamImpl = CompressionStream;\n  if (typeof CompressionStreamImpl === 'undefined') {\n    return undefined;\n  }\n  try {\n    const stream = new Blob([data]).stream().pipeThrough(new CompressionStreamImpl('gzip'));\n    return await new Response(stream).arrayBuffer();\n  } catch {\n    return undefined;\n  }\n}\n"
  },
  {
    "path": "packages/analytics-core/src/types/amplitude-context.ts",
    "content": "import { ServerZoneType } from './server-zone';\nimport { IRemoteConfigClient } from '../remote-config/remote-config';\nimport { ILogger } from '../logger';\nimport { IDiagnosticsClient } from '../diagnostics/diagnostics-client';\n\n/**\n * @experimental\n * AmplitudeContext holds the core configuration and dependencies for an Amplitude instance.\n * This includes API key, instance name, server zone, remote config client, and logger.\n * They are all readonly and not nullable.\n */\nexport interface AmplitudeContext {\n  readonly apiKey: string;\n  readonly instanceName: string;\n  readonly serverZone: ServerZoneType;\n  readonly loggerProvider: ILogger;\n\n  readonly remoteConfigClient: IRemoteConfigClient;\n  readonly diagnosticsClient: IDiagnosticsClient;\n}\n"
  },
  {
    "path": "packages/analytics-core/src/types/campaign.ts",
    "content": "export interface Campaign\n  extends Record<string, string | undefined>,\n    UTMParameters,\n    ReferrerParameters,\n    ClickIdParameters {}\n\nexport interface ICampaignParser {\n  parse(): Promise<Campaign>;\n}\n\nexport interface UTMParameters {\n  utm_campaign: string | undefined;\n  utm_content: string | undefined;\n  utm_id: string | undefined;\n  utm_medium: string | undefined;\n  utm_source: string | undefined;\n  utm_term: string | undefined;\n}\n\nexport interface ReferrerParameters {\n  referrer: string | undefined;\n  referring_domain: string | undefined;\n}\n\nexport interface ClickIdParameters {\n  dclid: string | undefined;\n  fbclid: string | undefined;\n  gbraid: string | undefined;\n  gclid: string | undefined;\n  ko_click_id: string | undefined;\n  li_fat_id: string | undefined;\n  msclkid: string | undefined;\n  rdt_cid: string | undefined;\n  ttclid: string | undefined;\n  twclid: string | undefined;\n  wbraid: string | undefined;\n}\n"
  },
  {
    "path": "packages/analytics-core/src/types/client/analytics-client.ts",
    "content": "import { AnalyticsIdentity } from '../plugin';\n\n/**\n * Generic analytics client interface adaptable to any analytics provider (e.g., Segment, Amplitude) with configurable identity type.\n *\n * Note: This interface is intended for client-side use only (e.g., browser SDK, React Native SDK).\n * It is not designed for use with the Node.js SDK.\n */\nexport interface AnalyticsClient<Identity extends AnalyticsIdentity = AnalyticsIdentity> {\n  /**\n   * Returns the current identity.\n   *\n   * ```typescript\n   * const identity = getIdentity();\n   * ```\n   */\n  getIdentity(): Identity;\n\n  /**\n   * Returns the current session identifier.\n   *\n   * ```typescript\n   * const sessionId = getSessionId();\n   * ```\n   */\n  getSessionId(): number | undefined;\n\n  /**\n   * Returns the current optOut config value.\n   *\n   * ```typescript\n   * const optOut = getOptOut();\n   * ```\n   */\n  getOptOut(): boolean | undefined;\n\n  /**\n   * Tracks an event with the specified type and optional properties.\n   *\n   * @param eventType - The type/name of the event to track\n   * @param eventProperties - Optional properties to attach to the event\n   */\n  track(eventType: string, eventProperties?: Record<string, any>): void;\n}\n"
  },
  {
    "path": "packages/analytics-core/src/types/client/browser-client.ts",
    "content": "import { TransportTypeOrOptions } from '../transport';\nimport { Client } from './core-client';\nimport { AnalyticsIdentity, Plugin } from '../plugin';\nimport { AmplitudeReturn } from '../../utils/return-wrapper';\nimport { BrowserConfig, BrowserOptions } from '../config/browser-config';\n\nexport interface BrowserClient extends Client {\n  /**\n   * Initializes the Amplitude SDK with your apiKey, optional configurations.\n   * This method must be called before any other operations.\n   *\n   * ```typescript\n   * await init(API_KEY, options).promise;\n   * ```\n   */\n  init(apiKey: string, options?: BrowserOptions): AmplitudeReturn<void>;\n\n  init(apiKey: string, userId?: string, options?: BrowserOptions): AmplitudeReturn<void>;\n\n  /**\n   * Sets the network transport type for events.\n   *\n   * ```typescript\n   * // Use Fetch API\n   * setTransport('fetch');\n   *\n   * // Use XMLHttpRequest API\n   * setTransport('xhr');\n   *\n   * // Use navigator.sendBeacon API\n   * setTransport('beacon');\n   *\n   * // Use Fetch API with custom headers\n   * setTransport({ type: 'fetch', headers: { 'X-Custom-Header': 'value' } });\n   * ```\n   */\n  setTransport(transport: TransportTypeOrOptions): void;\n\n  /**\n   * Adds a new plugin.\n   *\n   * ```typescript\n   * const plugin = {\n   *   name: 'my-plugin',\n   *   type: 'enrichment',\n   *   async setup(config: BrowserConfig, amplitude: BrowserClient) {\n   *     return;\n   *   },\n   *   async execute(event: Event) {\n   *     return event;\n   *   },\n   * };\n   * amplitude.add(plugin);\n   * ```\n   */\n  add(plugin: Plugin<BrowserClient, BrowserConfig>): AmplitudeReturn<void>;\n\n  /**\n   * Returns the current identity.\n   *\n   * ```typescript\n   * const identity = getIdentity();\n   * ```\n   */\n  getIdentity(): AnalyticsIdentity;\n\n  /**\n   * Sets the identity (userId, deviceId, and/or userProperties).\n   * This is a unified shortcut for `setUserId()`, `setDeviceId()`, and setting user properties.\n   * When userProperties change, an identify event is automatically sent.\n   *\n   * **Important limitation:** When userProperties are replaced, the local state is fully replaced\n   * but the identify event sent to the server only includes `$set` operations for the new properties.\n   * Properties removed from the local state are **not** `$unset` on the server.\n   *\n   * For example, changing from `{plan: 'premium', theme: 'dark'}` to `{plan: 'basic'}` removes\n   * `theme` locally but leaves it on the server. To remove a property from the server, use\n   * `identify()` with `Identify.unset()` directly.\n   *\n   * ```typescript\n   * // Set user properties (auto-sends identify event with $set)\n   * setIdentity({ userProperties: { plan: 'premium' } });\n   *\n   * // Set userId (equivalent to setUserId('user-123'))\n   * setIdentity({ userId: 'user-123' });\n   *\n   * // Set deviceId (equivalent to setDeviceId('device-456'))\n   * setIdentity({ deviceId: 'device-456' });\n   *\n   * // Set multiple identity fields together\n   * setIdentity({ userId: 'user-123', deviceId: 'device-456', userProperties: { name: 'John' } });\n   *\n   * // To remove a property from the server, use identify() directly:\n   * const identify = new Identify();\n   * identify.unset('theme');\n   * amplitude.identify(identify);\n   * ```\n   */\n  setIdentity(identity: Partial<AnalyticsIdentity>): void;\n\n  /**\n   * Returns the current optOut config value.\n   *\n   * ```typescript\n   * const optOut = getOptOut();\n   * ```\n   */\n  getOptOut(): boolean | undefined;\n\n  /**\n   * @experimental\n   * WARNING: This method is for internal testing only and is not part of the public API.\n   * It may be changed or removed at any time without notice.\n   *\n   * Sets the diagnostics sample rate before amplitude.init()\n   * @param sampleRate - The sample rate to set\n   */\n  _setDiagnosticsSampleRate(sampleRate: number): void;\n}\n"
  },
  {
    "path": "packages/analytics-core/src/types/client/core-client.ts",
    "content": "import { AmplitudeReturn } from '../../utils/return-wrapper';\nimport { BaseEvent, EventOptions } from '../event/base-event';\nimport { Result } from '../result';\nimport { IIdentify } from '../../identify';\nimport { IRevenue } from '../../revenue';\nimport { Plugin } from '../plugin';\n\nexport interface PluginHost {\n  plugin(name: string): Plugin | undefined;\n  plugins<T extends Plugin>(pluginClass: new (...args: any[]) => T): T[];\n}\n\nexport interface Client extends CoreClient {\n  /**\n   * Returns current user ID.\n   *\n   * ```typescript\n   * const userId = getUserId();\n   * ```\n   */\n  getUserId(): string | undefined;\n\n  /**\n   * Sets a new user ID.\n   *\n   * ```typescript\n   * setUserId('userId');\n   * ```\n   */\n  setUserId(userId: string | undefined): void;\n\n  /**\n   * Returns current device ID.\n   *\n   * ```typescript\n   * const deviceId = getDeviceId();\n   * ```\n   */\n  getDeviceId(): string | undefined;\n\n  /**\n   * Sets a new device ID.\n   * When setting a custom device ID, make sure the value is sufficiently unique.\n   * A uuid is recommended.\n   *\n   * ```typescript\n   * setDeviceId('deviceId');\n   * ```\n   */\n  setDeviceId(deviceId: string): void;\n\n  /**\n   * Returns current session ID.\n   *\n   * ```typescript\n   * const sessionId = getSessionId();\n   * ```\n   */\n  getSessionId(): number | undefined;\n\n  /**\n   * Sets a new session ID.\n   * When setting a custom session ID, make sure the value is in milliseconds since epoch (Unix Timestamp).\n   *\n   * ```typescript\n   * setSessionId(Date.now());\n   * ```\n   */\n  setSessionId(sessionId: number): void;\n\n  /**\n   * Extends the current session (advanced)\n   *\n   * Normally sessions are extended automatically by track()'ing events. If you want to extend the session without\n   * tracking and event, this will set the last user interaction to the current time.\n   *\n   * ```typescript\n   * extendSession();\n   * ```\n   */\n  extendSession(): void;\n\n  /**\n   * Anonymizes users after they log out, by:\n   *\n   * * setting userId to undefined\n   * * setting deviceId to a new uuid value\n   *\n   * With an undefined userId and a completely new deviceId, the current user would appear as a brand new user in dashboard.\n   *\n   * ```typescript\n   * import { reset } from '@amplitude/analytics-browser';\n   *\n   * reset();\n   * ```\n   */\n  reset(): void;\n}\n\nexport interface CoreClient {\n  /**\n   * Adds a new plugin.\n   *\n   * ```typescript\n   * const plugin = {\n   *   name: 'myPlugin',\n   *   type: 'enrichment',\n   *   setup(config: Config) {\n   *     return;\n   *   },\n   *   execute(context: Event) {\n   *     return context;\n   *   },\n   * };\n   * amplitude.add(plugin);\n   * ```\n   */\n  add(plugin: Plugin): AmplitudeReturn<void>;\n\n  /**\n   * Removes a plugin.\n   *\n   * ```typescript\n   * amplitude.remove('myPlugin');\n   * ```\n   */\n  remove(pluginName: string): AmplitudeReturn<void>;\n\n  /**\n   * Tracks user-defined event, with specified type, optional event properties and optional overwrites.\n   *\n   * ```typescript\n   * // event tracking with event type only\n   * track('Page Load');\n   *\n   * // event tracking with event type and additional event properties\n   * track('Page Load', { loadTime: 1000 });\n   *\n   * // event tracking with event type, additional event properties, and overwritten event options\n   * track('Page Load', { loadTime: 1000 }, { sessionId: -1 });\n   *\n   * // alternatively, this tracking method is awaitable\n   * const result = await track('Page Load').promise;\n   * console.log(result.event); // {...}\n   * console.log(result.code); // 200\n   * console.log(result.message); // \"Event tracked successfully\"\n   * ```\n   */\n  track(\n    eventInput: BaseEvent | string,\n    eventProperties?: Record<string, any>,\n    eventOptions?: EventOptions,\n  ): AmplitudeReturn<Result>;\n\n  /**\n   * Alias for track()\n   */\n  logEvent(\n    eventInput: BaseEvent | string,\n    eventProperties?: Record<string, any>,\n    eventOptions?: EventOptions,\n  ): AmplitudeReturn<Result>;\n\n  /**\n   * Sends an identify event containing user property operations\n   *\n   * ```typescript\n   * const id = new Identify();\n   * id.set('colors', ['rose', 'gold']);\n   * identify(id);\n   *\n   * // alternatively, this tracking method is awaitable\n   * const result = await identify(id).promise;\n   * console.log(result.event); // {...}\n   * console.log(result.code); // 200\n   * console.log(result.message); // \"Event tracked successfully\"\n   * ```\n   */\n  identify(identify: IIdentify, eventOptions?: EventOptions): AmplitudeReturn<Result>;\n\n  /**\n   * Sends a group identify event containing group property operations.\n   *\n   * ```typescript\n   * const id = new Identify();\n   * id.set('skills', ['js', 'ts']);\n   * const groupType = 'org';\n   * const groupName = 'engineering';\n   * groupIdentify(groupType, groupName, id);\n   *\n   * // alternatively, this tracking method is awaitable\n   * const result = await groupIdentify(groupType, groupName, id).promise;\n   * console.log(result.event); // {...}\n   * console.log(result.code); // 200\n   * console.log(result.message); // \"Event tracked successfully\"\n   * ```\n   */\n  groupIdentify(\n    groupType: string,\n    groupName: string | string[],\n    identify: IIdentify,\n    eventOptions?: EventOptions,\n  ): AmplitudeReturn<Result>;\n\n  /**\n   * Assigns a user to group\n   *\n   * ```typescript\n   * const groupType = 'orgId';\n   * const groupName = '15';\n   * setGroup(groupType, groupName, { user_id: '12345' })\n   * ```\n   */\n  setGroup(groupType: string, groupName: string | string[], eventOptions?: EventOptions): AmplitudeReturn<Result>;\n\n  /**\n   * Sends a revenue event containing revenue property operations.\n   *\n   * ```typescript\n   * const rev = new Revenue();\n   * rev.setRevenue(100);\n   * revenue(rev);\n   *\n   * // alternatively, this tracking method is awaitable\n   * const result = await revenue(rev).promise;\n   * console.log(result.event); // {...}\n   * console.log(result.code); // 200\n   * console.log(result.message); // \"Event tracked successfully\"\n   * ```\n   */\n  revenue(revenue: IRevenue, eventOptions?: EventOptions): AmplitudeReturn<Result>;\n\n  /**\n   * Sets a new optOut config value. This toggles event tracking on/off.\n   *\n   *```typescript\n   * // Stops tracking\n   * setOptOut(true);\n   *\n   * // Starts/resumes tracking\n   * setOptOut(false);\n   * ```\n   */\n  setOptOut(optOut: boolean): void;\n\n  /**\n   * Flush all unsent events.\n   *\n   *```typescript\n   * flush();\n   * ```\n   */\n  flush(): AmplitudeReturn<void>;\n}\n"
  },
  {
    "path": "packages/analytics-core/src/types/client/node-client.ts",
    "content": "import { AmplitudeReturn } from '../../utils/return-wrapper';\nimport { NodeConfig, NodeOptions } from '../config/node-config';\nimport { CoreClient } from './core-client';\nimport { Plugin } from '../plugin';\n\nexport interface NodeClient extends CoreClient {\n  /**\n   * Initializes the Amplitude SDK with your apiKey, optional configurations.\n   * This method must be called before any other operations.\n   *\n   * ```typescript\n   * await init(API_KEY, options).promise;\n   * ```\n   */\n  init(apiKey: string, options?: NodeOptions): AmplitudeReturn<void>;\n\n  /**\n   * Adds a new plugin.\n   *\n   * ```typescript\n   * const plugin = {\n   *   name: 'my-plugin',\n   *   type: 'enrichment',\n   *   async setup(config: NodeConfig, amplitude: NodeClient) {\n   *     return;\n   *   },\n   *   async execute(event: Event) {\n   *     return event;\n   *   },\n   * };\n   * amplitude.add(plugin);\n   * ```\n   */\n  add(plugin: Plugin<NodeClient, NodeConfig>): AmplitudeReturn<void>;\n}\n"
  },
  {
    "path": "packages/analytics-core/src/types/client/react-native-client.ts",
    "content": "import { Client } from './core-client';\nimport { ReactNativeConfig, ReactNativeOptions } from '../config/react-native-config';\nimport { AmplitudeReturn } from '../../utils/return-wrapper';\nimport { Plugin } from '../plugin';\n\nexport interface ReactNativeClient extends Client {\n  /**\n   * Initializes the Amplitude SDK with your apiKey, optional configurations.\n   * This method must be called before any other operations.\n   *\n   * ```typescript\n   * await init(API_KEY, options).promise;\n   * ```\n   */\n  init(apiKey: string, userId?: string, options?: ReactNativeOptions): AmplitudeReturn<void>;\n\n  /**\n   * Adds a new plugin.\n   *\n   * ```typescript\n   * const plugin = {\n   *   name: 'my-plugin',\n   *   type: 'enrichment',\n   *   async setup(config: ReactNativeConfig, amplitude: ReactNativeClient) {\n   *     return;\n   *   },\n   *   async execute(event: Event) {\n   *     return event;\n   *   },\n   * };\n   * amplitude.add(plugin);\n   * ```\n   */\n  add(plugin: Plugin<ReactNativeClient, ReactNativeConfig>): AmplitudeReturn<void>;\n}\n"
  },
  {
    "path": "packages/analytics-core/src/types/config/browser-config.ts",
    "content": "import { UserSession } from '../user-session';\nimport { IdentityStorageType, Storage } from '../storage';\nimport { Transport, TransportTypeOrOptions } from '../transport';\nimport { IConfig } from './core-config';\nimport { ElementInteractionsOptions } from '../element-interactions';\nimport { FormInteractionsOptions } from '../form-interactions';\nimport { PageTrackingOptions } from '../page-view-tracking';\nimport { NetworkTrackingOptions } from '../network-tracking';\nimport { FrustrationInteractionsOptions } from '../frustration-interactions';\nimport { PerformanceTrackingOptions } from '../performance-tracking';\nimport { IDiagnosticsClient } from '../../diagnostics/diagnostics-client';\nimport { IRemoteConfigClient } from '../../remote-config/remote-config';\nimport { CustomEnrichmentOptions } from '../custom-enrichment';\n\nexport interface BrowserConfig extends ExternalBrowserConfig, InternalBrowserConfig {}\n\nexport interface ExternalBrowserConfig extends IConfig {\n  /**\n   * An app version for events tracked. This can be the version of your application.\n   * @defaultValue `undefined`\n   */\n  appVersion?: string;\n  /**\n   * @deprecated This property is deprecated and will be removed in future versions. Please migrate to using `autocapture` instead.\n   * The default event tracking configuration.\n   * See {@link https://www.docs.developers.amplitude.com/data/sdks/browser-2/#tracking-default-events}.\n   * @defaultValue `true`\n   */\n  defaultTracking?: boolean | DefaultTrackingOptions;\n  /**\n   * The configurations for auto-captured events.\n   * See {@link https://www.docs.developers.amplitude.com/data/sdks/browser-2/autocapture/}.\n   */\n  autocapture?: boolean | AutocaptureOptions;\n  /**\n   * The configurations for custom enrichment.\n   * @defaultValue `false`\n   */\n  customEnrichment?: boolean | CustomEnrichmentOptions;\n  /**\n   * The identifier for the device running your application.\n   * @defaultValue `UUID()`\n   */\n  deviceId?: string;\n  /**\n   * Configuration for cookie.\n   */\n  cookieOptions?: CookieOptions;\n  /**\n   * The storage for user identify.\n   * @defaultValue `\"cookie\"`\n   */\n  identityStorage?: IdentityStorageType;\n  /**\n   * The partner identifier.\n   * Amplitude requires the customer who built an event ingestion integration to add the partner identifier to partner_id.\n   * @defaultValue `undefined`\n   */\n  partnerId?: string;\n  /**\n   * The custom Session ID for the current session.\n   * @defaultValue `timestamp`\n   */\n  sessionId?: number;\n  /**\n   * The period of inactivity from the last tracked event before a session expires in milliseconds.\n   * @defaultValue `1,800,000` (30 minutes)\n   */\n  sessionTimeout: number;\n  /**\n   * The configurations for tracking additional properties.\n   * See {@link https://www.docs.developers.amplitude.com/data/sdks/browser-2/#optional-tracking}.\n   */\n  trackingOptions: TrackingOptions;\n  /**\n   * Network transport mechanism used to send events.\n   * @defaultValue `\"fetch\"`\n   */\n  transport?: TransportTypeOrOptions;\n  /**\n   * The identifier for the user being tracked.\n   * @defaultValue `undefined`\n   */\n  userId?: string;\n  /**\n   * User's Nth instance of performing a default Page Viewed event within a session.\n   * Used for landing page analysis.\n   */\n  pageCounter?: number;\n  /**\n   * Whether to fetch remote configuration. The remote configuration can be updated in the Amplitude platform here:\n   * https://app.amplitude.com/data/amplitude/{your_org_name}/settings/autocapture\n   * @defaultValue `true`\n   * @deprecated This property is deprecated and will be removed in future versions. Please use `remoteConfig.fetchRemoteConfig` instead.\n   */\n  fetchRemoteConfig?: boolean;\n  /**\n   * Remote configuration options.\n   * @defaultValue `undefined`\n   */\n  remoteConfig?: RemoteConfigOptions;\n  /**\n   * Captures network requests and responses.\n   * @defaultValue `undefined`\n   * @deprecated use autocapture.networkTracking instead\n   */\n  networkTrackingOptions?: NetworkTrackingOptions;\n  /**\n   * Whether to enable diagnostics.\n   * @defaultValue `true`\n   */\n  enableDiagnostics?: boolean;\n}\n\ninterface InternalBrowserConfig {\n  cookieStorage: Storage<UserSession>;\n  lastEventTime?: number;\n  lastEventId?: number;\n  transportProvider: Transport;\n  version?: string;\n  diagnosticsSampleRate?: number;\n  diagnosticsClient?: IDiagnosticsClient;\n  remoteConfigClient?: IRemoteConfigClient;\n  deferredSessionId?: number;\n  topLevelDomain?: string;\n}\n\n/**\n * @deprecated This interface is deprecated and will be removed in future versions. Please migrate to using `AutocaptureOptions` instead.\n */\nexport interface DefaultTrackingOptions {\n  /**\n   * Enables/disables marketing attribution tracking or config with detailed attribution options.\n   * @defaultValue `true`\n   */\n  attribution?: boolean | AttributionOptions;\n  /**\n   * Enables/disables form downloads tracking.\n   * @defaultValue `true`\n   */\n  fileDownloads?: boolean;\n  /**\n   * Enables/disables form interaction tracking or configures with detailed options.\n   * @defaultValue `true`\n   */\n  formInteractions?: boolean | FormInteractionsOptions;\n  /**\n   * Enables/disables default page view tracking.\n   * @defaultValue `true`\n   */\n  pageViews?: boolean | PageTrackingOptions;\n  /**\n   * Enables/disables session tracking.\n   * @defaultValue `true`\n   */\n  sessions?: boolean;\n}\n\nexport interface AutocaptureOptions {\n  /**\n   * Enables/disables marketing attribution tracking or config with detailed attribution options.\n   * @defaultValue `true`\n   */\n  attribution?: boolean | AttributionOptions;\n  /**\n   * Enables/disables form downloads tracking.\n   * @defaultValue `true`\n   */\n  fileDownloads?: boolean;\n  /**\n   * Enables/disables form interaction tracking or configures with detailed options.\n   * @defaultValue `true`\n   */\n  formInteractions?: boolean | FormInteractionsOptions;\n  /**\n   * Enables/disables default page view tracking.\n   * @defaultValue `true`\n   */\n  pageViews?: boolean | PageTrackingOptions;\n  /**\n   * Enables/disables session tracking.\n   * @defaultValue `true`\n   */\n  sessions?: boolean;\n  /**\n   * Enables/disables user interactions tracking.\n   * @defaultValue `false`\n   */\n  elementInteractions?: boolean | ElementInteractionsOptions;\n  /**\n   * Enables/disables frustration interactions tracking.\n   * @defaultValue `false`\n   */\n  frustrationInteractions?: boolean | FrustrationInteractionsOptions;\n  /**\n   * Enables/disables network request tracking or config with detailed network tracking options.\n   * @defaultValue `false`\n   */\n  networkTracking?: boolean | NetworkTrackingOptions;\n  /**\n   * Enables/disables web vitals tracking.\n   * @defaultValue `false`\n   */\n  webVitals?: boolean;\n  /**\n   * Enables/disables performance tracking.\n   * @defaultValue `false`\n   */\n  performanceTracking?: boolean | PerformanceTrackingOptions;\n  /**\n   * Enables/disables page url enrichment.\n   * @defaultValue `true`\n   * @experimental This feature is experimental and may not be stable\n   */\n  pageUrlEnrichment?: boolean;\n}\n\nexport interface TrackingOptions {\n  /**\n   * Enables/disables ip address tracking.\n   * @defaultValue `true`\n   */\n  ipAddress?: boolean;\n  /**\n   * Enables/disables language tracking.\n   * @defaultValue `true`\n   */\n  language?: boolean;\n  /**\n   * Enables/disables plantform tracking.\n   * @defaultValue `true`\n   */\n  platform?: boolean;\n}\n\nexport type TrackingMethod = 'userProperty' | 'eventProperty';\n\nexport interface AttributionOptions {\n  /**\n   * The rules to determine which referrers are excluded from being tracked as traffic source.\n   * Applies only to `userProperty` tracking.\n   * Ignored by `eventProperty` tracking.\n   * @defaultValue `[/your-domain\\.com$/]`\n   */\n  excludeReferrers?: (string | RegExp)[];\n  /**\n   * Exclude internal referrers from campaign attribution.\n   * (a referrer is 'internal' if it is on the same domain as the current page)\n   * Applies only to `userProperty` tracking.\n   * Ignored by `eventProperty` tracking.\n   * @defaultValue `false`\n   */\n  excludeInternalReferrers?: true | false | ExcludeInternalReferrersOptions;\n  /**\n   * The value to represent undefined/no initial campaign parameter for first-touch attribution.\n   * Applies only to `userProperty` tracking.\n   * Ignored by `eventProperty` tracking.\n   * @defaultValue `\"EMPTY\"`\n   */\n  initialEmptyValue?: string;\n  /**\n   * The flag of if Amplitude to start a new session if any campaign parameter changes.\n   * Applies only to `userProperty` tracking.\n   * Ignored by `eventProperty` tracking.\n   * @defaultValue `false`\n   */\n  resetSessionOnNewCampaign?: boolean;\n  /**\n   * The attribution persistence strategy for campaign parameters.\n   * Provide a single method to enable one strategy, or an array to enable multiple methods at the same time.\n   * When multiple methods are provided, each enabled method runs independently and their behaviors are combined.\n   * For example, `['userProperty', 'eventProperty']` updates user properties and also attaches campaign params\n   * to event properties.\n   * @experimental this feature is experimental and may not be stable\n   * @defaultValue `\"userProperty\"`\n   */\n  trackingMethod?: TrackingMethod | TrackingMethod[];\n  /**\n   * Fires an `[Amplitude] Attribution` event as a heartbeat on every page view,\n   * such as on page load and SPA URL changes.\n   * Applies only to `eventProperty` tracking.\n   * Ignored by `userProperty` tracking.\n   * @experimental this feature is experimental and may not be stable\n   * @defaultValue `false`\n   */\n  fallbackAttributionEvent?: boolean;\n}\n\nexport const EXCLUDE_INTERNAL_REFERRERS_CONDITIONS = {\n  always: 'always',\n  ifEmptyCampaign: 'ifEmptyCampaign',\n} as const;\n\ntype ExcludeInternalReferrersCondition =\n  (typeof EXCLUDE_INTERNAL_REFERRERS_CONDITIONS)[keyof typeof EXCLUDE_INTERNAL_REFERRERS_CONDITIONS];\n\nexport interface ExcludeInternalReferrersOptions {\n  /*\n   * The condition on which to exclude internal referrers for campaign attribution.\n   * @defaultValue `\"always\"`\n   */\n  condition?: ExcludeInternalReferrersCondition;\n}\n\nexport interface RemoteConfigOptions {\n  /**\n   * Whether to fetch remote configuration. The remote configuration can be updated in the Amplitude platform here:\n   * https://app.amplitude.com/data/amplitude/{your_org_name}/settings/autocapture\n   * @defaultValue `true`\n   */\n  fetchRemoteConfig?: boolean;\n  /**\n   * Custom server URL for remote configuration requests. If not provided, defaults to the standard\n   * Amplitude remote config endpoint based on serverZone (US or EU).\n   * Use this to proxy remote config requests through your own server.\n   * @defaultValue `undefined` (uses standard Amplitude remote config endpoint)\n   */\n  serverUrl?: string;\n}\n\nexport interface CookieOptions {\n  /**\n   * The domain property of cookies created.\n   * @defaultValue `Your top level domain`\n   */\n  domain?: string;\n  /**\n   * The expiration of cookies created in days.\n   * @defaultValue `365`\n   */\n  expiration?: number;\n  /**\n   * How cookies are sent with cross-site requests.\n   * @defaultValue `\"Lax\"`\n   */\n  sameSite?: 'Strict' | 'Lax' | 'None';\n  /**\n   * The flag of if send cookies over secure protocols.\n   * @defaultValue `false`\n   */\n  secure?: boolean;\n  /**\n   * The flag of if upgrade the cookies created by maintenance Browser SDK.\n   * @defaultValue `true`\n   */\n  upgrade?: boolean;\n}\n\ntype HiddenOptions = 'apiKey' | 'transportProvider' | 'requestMetadata';\n\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface BrowserOptions extends Omit<Partial<ExternalBrowserConfig>, HiddenOptions> {}\n"
  },
  {
    "path": "packages/analytics-core/src/types/config/core-config.ts",
    "content": "import { LogLevel } from '../loglevel';\nimport { ILogger } from '../../logger';\nimport { OfflineDisabled } from '../offline';\nimport { Plan } from '../event/plan';\nimport { IngestionMetadata } from '../event/ingestion-metadata';\nimport { ServerZoneType } from '../server-zone';\nimport { Transport } from '../transport';\nimport { Storage } from '../storage';\nimport { Event } from '../event/event';\nimport { IIdentify } from '../../identify';\n\nexport interface IConfig {\n  /**\n   * Your Amplitude Project API key.\n   */\n  apiKey: string;\n  /**\n   * The interval of uploading events to Amplitude in milliseconds.\n   */\n  flushIntervalMillis: number;\n  /**\n   * The maximum number of retries for failed upload attempts. This is only applicable to retryable errors.\n   */\n  flushMaxRetries: number;\n  /**\n   * The maximum number of events that are batched in a single upload attempt.\n   */\n  flushQueueSize: number;\n  /**\n   * The instance name. For tracking events to multiple Amplitude projects in your application.\n   */\n  instanceName?: string;\n  /**\n   * Level of logs to be printed in the developer console.\n   * Valid values are `LogLevel.None`, `LogLevel.Error`, `LogLevel.Warn`, `LogLevel.Verbose`,  `LogLevel.Debug`\n   */\n  logLevel: LogLevel;\n  /**\n   * A custom Logger class to emit log messages to desired destination.\n   */\n  loggerProvider: ILogger;\n  /**\n   * The minimum length for the value of userId and deviceId properties.\n   */\n  minIdLength?: number;\n  /**\n   * Whether the SDK is connected to network.\n   */\n  offline?: boolean | typeof OfflineDisabled;\n  /**\n   *  The flag to opt this device out of Amplitude tracking.\n   *  If this flag is set, no additional information will be stored for the user.\n   */\n  optOut: boolean;\n  /**\n   * Tracking plan properties.\n   * Amplitude internal use.\n   */\n  plan?: Plan;\n  /**\n   * Ingestion metadata.\n   * Amplitude internal use.\n   */\n  ingestionMetadata?: IngestionMetadata;\n  /**\n   * Compress network request body payloads with gzip.\n   *\n   * For custom `serverUrl` values, this option controls whether compression is attempted.\n   * For default Amplitude endpoints, compression remains enabled.\n   * Compression is best-effort and only applies when the platform supports it,\n   * the payload meets the minimum size threshold, and the transport can set request headers.\n   * @defaultValue `false`\n   */\n  enableRequestBodyCompression?: boolean;\n  /**\n   * The URL where events are upload to.\n   */\n  serverUrl?: string;\n  /**\n   * The Amplitude server zone.\n   * Set this to EU for Amplitude projects created in EU data center.\n   */\n  serverZone?: ServerZoneType;\n  /**\n   *  The storage provider to persist unsent events.\n   */\n  storageProvider?: Storage<Event[]>;\n  /**\n   * A customer Transport Class for sending data to a server.\n   */\n  transportProvider: Transport;\n  /**\n   * The flag of whether to upload events to Batch API instead of the default HTTP V2 API.\n   */\n  useBatch: boolean;\n  /**\n   * Metrics of the SDK.\n   */\n  requestMetadata?: IRequestMetadata;\n  /**\n   * Invokes identify on this Identify object prior to initializing the SDK.\n   */\n  identify?: IIdentify;\n}\n\nexport interface IRequestMetadata {\n  sdk: {\n    metrics: {\n      histogram: IHistogramOptions;\n    };\n  };\n\n  recordHistogram<T extends HistogramKey>(key: T, value: IHistogramOptions[T]): void;\n}\n\nexport interface IHistogramOptions {\n  remote_config_fetch_time_IDB?: number;\n  remote_config_fetch_time_API_success?: number;\n  remote_config_fetch_time_API_fail?: number;\n}\n\nexport type HistogramKey = keyof IHistogramOptions;\n\nexport interface ConfigOptions extends Partial<IConfig> {\n  apiKey: string;\n  transportProvider: Transport;\n}\n"
  },
  {
    "path": "packages/analytics-core/src/types/config/node-config.ts",
    "content": "import { IConfig } from './core-config';\n\nexport type NodeConfig = IConfig;\n\nexport type NodeOptions = Omit<Partial<NodeConfig>, 'apiKey'>;\n"
  },
  {
    "path": "packages/analytics-core/src/types/config/react-native-config.ts",
    "content": "import { IConfig } from './core-config';\nimport { Storage } from '../storage';\nimport { UserSession } from '../user-session';\n\ntype HiddenOptions = 'apiKey' | 'lastEventId';\n\nexport type ReactNativeOptions = Omit<Partial<ReactNativeConfig>, HiddenOptions>;\n\nexport interface ReactNativeConfig extends Omit<IConfig, 'offline' | 'requestMetadata'> {\n  trackingOptions: ReactNativeTrackingOptions;\n  trackingSessionEvents?: boolean;\n  migrateLegacyData?: boolean;\n  appVersion?: string;\n  attribution?: ReactNativeAttributionOptions;\n  deviceId?: string;\n  cookieExpiration: number;\n  cookieSameSite: string;\n  cookieSecure: boolean;\n  cookieStorage: Storage<UserSession>;\n  cookieUpgrade: boolean;\n  disableCookies: boolean;\n  domain: string;\n  lastEventTime?: number;\n  lastEventId?: number;\n  partnerId?: string;\n  sessionId?: number;\n  sessionTimeout: number;\n  userId?: string;\n}\n\nexport interface ReactNativeAttributionOptions {\n  disabled?: boolean;\n  excludeReferrers?: string[];\n  initialEmptyValue?: string;\n  trackNewCampaigns?: boolean;\n  trackPageViews?: boolean;\n  resetSessionOnNewCampaign?: boolean;\n}\n\nexport interface ReactNativeTrackingOptions {\n  adid?: boolean;\n  carrier?: boolean;\n  appSetId?: boolean;\n  idfv?: boolean;\n  country?: boolean;\n\n  deviceManufacturer?: boolean;\n  deviceModel?: boolean;\n  ipAddress?: boolean;\n  language?: boolean;\n  osName?: boolean;\n  osVersion?: boolean;\n  platform?: boolean;\n  [key: string]: boolean | undefined;\n}\n"
  },
  {
    "path": "packages/analytics-core/src/types/constants.ts",
    "content": "import { Campaign } from './campaign';\n\nexport const UNSET_VALUE = '-';\nexport const AMPLITUDE_PREFIX = 'AMP';\nexport const STORAGE_PREFIX = `${AMPLITUDE_PREFIX}_unsent`;\nexport const DEFAULT_INSTANCE_NAME = '$default_instance';\nexport const AMPLITUDE_SERVER_URL = 'https://api2.amplitude.com/2/httpapi';\nexport const EU_AMPLITUDE_SERVER_URL = 'https://api.eu.amplitude.com/2/httpapi';\nexport const AMPLITUDE_BATCH_SERVER_URL = 'https://api2.amplitude.com/batch';\nexport const EU_AMPLITUDE_BATCH_SERVER_URL = 'https://api.eu.amplitude.com/batch';\n\n// Campaign constants\nexport const UTM_CAMPAIGN = 'utm_campaign';\nexport const UTM_CONTENT = 'utm_content';\nexport const UTM_ID = 'utm_id';\nexport const UTM_MEDIUM = 'utm_medium';\nexport const UTM_SOURCE = 'utm_source';\nexport const UTM_TERM = 'utm_term';\n\nexport const DCLID = 'dclid';\nexport const FBCLID = 'fbclid';\nexport const GBRAID = 'gbraid';\nexport const GCLID = 'gclid';\nexport const KO_CLICK_ID = 'ko_click_id';\nexport const LI_FAT_ID = 'li_fat_id';\nexport const MSCLKID = 'msclkid';\nexport const RDT_CID = 'rdt_cid';\nexport const TTCLID = 'ttclid';\nexport const TWCLID = 'twclid';\nexport const WBRAID = 'wbraid';\n\nexport const EMPTY_VALUE = 'EMPTY';\n\nexport const BASE_CAMPAIGN: Campaign = {\n  utm_campaign: undefined,\n  utm_content: undefined,\n  utm_id: undefined,\n  utm_medium: undefined,\n  utm_source: undefined,\n  utm_term: undefined,\n  referrer: undefined,\n  referring_domain: undefined,\n  dclid: undefined,\n  gbraid: undefined,\n  gclid: undefined,\n  fbclid: undefined,\n  ko_click_id: undefined,\n  li_fat_id: undefined,\n  msclkid: undefined,\n  rdt_cid: undefined,\n  ttclid: undefined,\n  twclid: undefined,\n  wbraid: undefined,\n};\n\nexport const MKTG = 'MKTG';\n\n// list of Network headers that are safe to capture\nexport const SAFE_HEADERS = [\n  'access-control-allow-origin',\n  'access-control-allow-credentials',\n  'access-control-expose-headers',\n  'access-control-max-age',\n  'access-control-allow-methods',\n  'access-control-allow-headers',\n  'accept-patch',\n  'accept-ranges',\n  'age',\n  'allow',\n  'alt-svc',\n  'cache-control',\n  'connection',\n  'content-disposition',\n  'content-encoding',\n  'content-language',\n  'content-length',\n  'content-location',\n  'content-md5',\n  'content-range',\n  'content-type',\n  'date',\n  'delta-base',\n  'etag',\n  'expires',\n  'im',\n  'last-modified',\n  'link',\n  'location',\n  'permanent',\n  'p3p',\n  'pragma',\n  'proxy-authenticate',\n  'public-key-pins',\n  'retry-after',\n  'server',\n  'status',\n  'strict-transport-security',\n  'trailer',\n  'transfer-encoding',\n  'tk',\n  'upgrade',\n  'vary',\n  'via',\n  'warning',\n  'www-authenticate',\n  'x-b3-traceid',\n  'x-frame-options',\n];\n\n// list of Network headers to never capture\nexport const FORBIDDEN_HEADERS = ['authorization', 'cookie', 'set-cookie'];\n"
  },
  {
    "path": "packages/analytics-core/src/types/custom-enrichment.ts",
    "content": "/**\n * @experimental this feature is experimental and may not be stable\n */\n\nexport interface CustomEnrichmentOptions {\n  enabled?: boolean;\n  body: string;\n}\n"
  },
  {
    "path": "packages/analytics-core/src/types/element-interactions.ts",
    "content": "import { ILogger } from '../logger';\n\nexport type ActionType = 'click' | 'change';\n\n/**\n * Default CSS selectors to define which elements on the page to track.\n * Extend this list to include additional elements to track. For example:\n * ```\n * autocapturePlugin({\n *    cssSelectorAllowlist: [...DEFAULT_CSS_SELECTOR_ALLOWLIST, \".my-class\"],\n * })\n * ```\n */\nexport const DEFAULT_CSS_SELECTOR_ALLOWLIST = [\n  'a',\n  'button',\n  'input',\n  'select',\n  'textarea',\n  'label',\n  'video',\n  'audio',\n  '[contenteditable=\"true\" i]',\n  '[data-amp-default-track]',\n  '.amp-default-track',\n];\n\n/**\n * Default prefix to allow the plugin to capture data attributes as an event property.\n */\nexport const DEFAULT_DATA_ATTRIBUTE_PREFIX = 'data-amp-track-';\n\n/**\n * Default list of elements on the page should be tracked when the page changes.\n */\nexport const DEFAULT_ACTION_CLICK_ALLOWLIST = ['div', 'span', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'];\n\nexport const DEFAULT_EXPOSURE_DURATION = 150;\n\nexport interface ElementInteractionsOptions {\n  /**\n   * List of CSS selectors to allow auto tracking on.\n   * When provided, allow elements matching any selector to be tracked.\n   * Default is ['a', 'button', 'input', 'select', 'textarea', 'label', '[data-amp-default-track]', '.amp-default-track'].\n   */\n  cssSelectorAllowlist?: string[];\n\n  /**\n   * List of page URLs to allow auto tracking on.\n   * When provided, only allow tracking on these URLs.\n   * Both full URLs and regex are supported.\n   */\n  pageUrlAllowlist?: (string | RegExp)[];\n\n  /**\n   * List of page URLs to exclude from auto tracking.\n   * When provided, tracking will be blocked on these URLs.\n   * Both full URLs and regex are supported.\n   * This takes precedence over pageUrlAllowlist.\n   */\n  pageUrlExcludelist?: (RegExp | string | { pattern: string })[];\n\n  /**\n   * Function to determine whether an event should be tracked.\n   * When provided, this function overwrites all other allowlists and configurations.\n   * If the function returns true, the event will be tracked.\n   * If the function returns false, the event will not be tracked.\n   * @param actionType - The type of action that triggered the event.\n   * @param element - The [Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) that triggered the event.\n   */\n  shouldTrackEventResolver?: (actionType: ActionType, element: DomElement) => boolean;\n\n  /**\n   * Prefix for data attributes to allow auto collecting.\n   * Default is 'data-amp-track-'.\n   */\n  dataAttributePrefix?: string;\n\n  /**\n   * Options for integrating visual tagging selector.\n   */\n  visualTaggingOptions?: {\n    enabled?: boolean;\n  };\n\n  /**\n   * This has been deprecated in favor of rage clicks tracking\n   * via frustrationInteractions.\n   *\n   * Setting this will have no effect.\n   *\n   * @deprecated\n   */\n  debounceTime?: number;\n\n  /**\n   * CSS selector allowlist for tracking clicks that result in a DOM change/navigation\n   * on elements not already allowed by the cssSelectorAllowlist.\n   * Only applies to click-based interaction tracking; has no effect on\n   * viewport/exposure-based features (e.g., zoning).\n   */\n  actionClickAllowlist?: string[];\n\n  /**\n   * Remote config for page actions\n   */\n  pageActions?: {\n    triggers: Trigger[];\n    labeledEvents: Record<string, LabeledEvent>;\n  };\n\n  /**\n   * RegExp pattern list to allow custom patterns for text masking\n   */\n  maskTextRegex?: (RegExp | { pattern: string; description: string })[];\n\n  /**\n   * Duration in milliseconds an element must be visible before it is considered exposed.\n   * Default is 150ms.\n   * @deprecated Use `viewportContentUpdated.exposureDuration` instead.\n   */\n  exposureDuration?: number;\n\n  /**\n   * Options for viewport content updated tracking (zoning).\n   */\n  viewportContentUpdated?: {\n    /**\n     * Whether viewport content updated tracking is enabled.\n     * Default is true.\n     */\n    enabled?: boolean;\n    /**\n     * Duration in milliseconds an element must be visible before it is considered exposed.\n     * Default is 150ms.\n     */\n    exposureDuration?: number;\n  };\n}\n\ntype MatchingCondition = {\n  type: 'LABELED_EVENT';\n  match: {\n    eventId: string;\n  };\n};\n\nexport type Trigger = {\n  id: string;\n  name: string; // Human friendly name for the trigger\n  conditions: MatchingCondition[]; // Configures when the actions should be executed; AND\n  actions: Array<PageAction | string>; // Actions to execute if conditions are met\n};\n\nexport type PageAction = {\n  id: string;\n  actionType: 'ATTACH_EVENT_PROPERTY';\n  dataSource: DataSource; // Defines where and how to get the data\n  destinationKey: string; // Property key name for the data (e.g. event property name, data layer key, user property name)\n};\n\nexport type DataSource = {\n  sourceType: 'DOM_ELEMENT' | 'PAGE_CONTEXT'; // | 'URL' ;\n} & (\n  | {\n      sourceType: 'DOM_ELEMENT';\n      selector?: string; // For DOM_ELEMENT: CSS selector for the target element\n      elementExtractType: 'TEXT' | 'ATTRIBUTE';\n      attribute?: string; // For DOM_ELEMENT: Attribute name to extract (null/empty for text content)\n      scope?: string; // CSS selector for the scope of the element, document by default\n    }\n  | {\n      sourceType: 'PAGE_CONTEXT';\n      propertyPath: string; // For PAGE_CONTEXT: e.g., 'document.title'\n    }\n);\n\nexport type EventSubpropKey = '[Amplitude] Element Text' | '[Amplitude] Element Hierarchy';\n\nexport type Filter = {\n  subprop_key: EventSubpropKey;\n  subprop_op: string; // exact, autotrack css match\n  subprop_value: string[];\n};\n\nexport type LabeledEvent = {\n  id: string;\n  definition: {\n    event_type: '[Amplitude] Element Clicked' | '[Amplitude] Element Changed';\n    filters: Filter[];\n  }[];\n};\n\nexport interface Messenger {\n  logger?: ILogger;\n  setup: () => void;\n}\n\n// DomElement is [Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) if the dom library is included in tsconfig.json\n// and never if it is not included\n// eslint-disable-next-line no-restricted-globals\ntype DomElement = typeof globalThis extends {\n  Element: new (...args: any) => infer T;\n}\n  ? T\n  : never;\n"
  },
  {
    "path": "packages/analytics-core/src/types/event/base-event.ts",
    "content": "import { Plan } from './plan';\nimport { IngestionMetadataEventProperty } from './ingestion-metadata';\n\nexport interface BaseEvent extends EventOptions {\n  event_type: string;\n  event_properties?: { [key: string]: any } | undefined;\n  user_properties?: { [key: string]: any } | undefined;\n  group_properties?: { [key: string]: any } | undefined;\n}\n\nexport interface EventOptions {\n  user_id?: string;\n  device_id?: string;\n  time?: number;\n  location_lat?: number;\n  location_lng?: number;\n  app_version?: string;\n  version_name?: string;\n  library?: string;\n  platform?: string;\n  os_name?: string;\n  os_version?: string;\n  device_brand?: string;\n  device_manufacturer?: string;\n  device_model?: string;\n  carrier?: string;\n  country?: string;\n  region?: string;\n  city?: string;\n  dma?: string;\n  idfa?: string;\n  idfv?: string;\n  adid?: string;\n  android_id?: string;\n  language?: string;\n  ip?: string;\n  price?: number;\n  quantity?: number;\n  revenue?: number;\n  receipt?: string;\n  receiptSig?: string;\n  productId?: string;\n  revenueType?: string;\n  currency?: string;\n  event_id?: number;\n  session_id?: number;\n  insert_id?: string;\n  plan?: Plan;\n  ingestion_metadata?: IngestionMetadataEventProperty;\n  partner_id?: string;\n  user_agent?: string;\n  android_app_set_id?: string;\n  extra?: { [key: string]: any };\n  groups?: { [key: string]: any } | undefined;\n}\n"
  },
  {
    "path": "packages/analytics-core/src/types/event/event.ts",
    "content": "import { BaseEvent } from './base-event';\nimport { RevenueEventProperties } from '../../revenue';\n\nexport enum IdentifyOperation {\n  // Base Operations to set values\n  SET = '$set',\n  SET_ONCE = '$setOnce',\n\n  // Operations around modifying existing values\n  ADD = '$add',\n  APPEND = '$append',\n  PREPEND = '$prepend',\n  REMOVE = '$remove',\n\n  // Operations around appending values *if* they aren't present\n  PREINSERT = '$preInsert',\n  POSTINSERT = '$postInsert',\n\n  // Operations around removing properties/values\n  UNSET = '$unset',\n  CLEAR_ALL = '$clearAll',\n}\n\nexport type ValidPropertyType =\n  | number\n  | string\n  | boolean\n  | Array<string | number>\n  | { [key: string]: ValidPropertyType }\n  | Array<{ [key: string]: ValidPropertyType }>;\n\ninterface BaseOperationConfig {\n  [key: string]: ValidPropertyType;\n}\n\nexport interface IdentifyUserProperties {\n  // Add operations can only take numbers\n  [IdentifyOperation.ADD]?: { [key: string]: number };\n\n  // This reads the keys of the passed object, but the values are not used\n  [IdentifyOperation.UNSET]?: BaseOperationConfig;\n  // This option does not read the key as it unsets all user properties\n  [IdentifyOperation.CLEAR_ALL]?: any;\n\n  // These operations can take numbers, strings, or arrays of both.\n  [IdentifyOperation.SET]?: BaseOperationConfig;\n  [IdentifyOperation.SET_ONCE]?: BaseOperationConfig;\n  [IdentifyOperation.APPEND]?: BaseOperationConfig;\n  [IdentifyOperation.PREPEND]?: BaseOperationConfig;\n  [IdentifyOperation.POSTINSERT]?: BaseOperationConfig;\n  [IdentifyOperation.PREINSERT]?: BaseOperationConfig;\n  [IdentifyOperation.REMOVE]?: BaseOperationConfig;\n}\n\n/**\n * Represents the structure of user properties that can be sent with an Identify or GroupIdentify event.\n *\n * This type supports both:\n *\n * 1. Reserved Amplitude identify operations via `IdentifyUserProperties`:\n *    These operations enable structured updates to user properties.\n *\n *    Example:\n *    ```ts\n *    {\n *      $set: { plan: 'premium', login_count: 1 },\n *      $add: { login_count: 1 },\n *      $unset: { plan: '-' },\n *      $clearAll: '-'\n *    }\n *    ```\n *\n * 2. Custom user-defined properties (excluding reserved operation keys):\n *    Useful for assigning static properties without using Identify operations.\n *\n *    Example:\n *    ```ts\n *    {\n *      custom_flag: true,\n *      experiment_group: 'B',\n *      favorite_color: 'blue'\n *    }\n *    ```\n *\n * This union ensures compatibility with Amplitude's identify semantics\n * while allowing flexibility to define arbitrary non-reserved properties.\n */\nexport type UserProperties =\n  | IdentifyUserProperties\n  | {\n      [key in Exclude<string, IdentifyOperation>]: any;\n    };\n\n/**\n * Strings that have special meaning when used as an event's type\n * and have different specifications.\n */\nexport enum SpecialEventType {\n  IDENTIFY = '$identify',\n  GROUP_IDENTIFY = '$groupidentify',\n  REVENUE = 'revenue_amount',\n}\n\nexport interface TrackEvent extends BaseEvent {\n  event_type: Exclude<string, SpecialEventType>;\n}\n\nexport interface IdentifyEvent extends BaseEvent {\n  event_type: SpecialEventType.IDENTIFY;\n  user_properties: UserProperties;\n}\n\nexport interface GroupIdentifyEvent extends BaseEvent {\n  event_type: SpecialEventType.GROUP_IDENTIFY;\n  group_properties: UserProperties;\n}\n\nexport interface RevenueEvent extends BaseEvent {\n  event_type: SpecialEventType.REVENUE;\n  event_properties:\n    | RevenueEventProperties\n    | {\n        [key: string]: any;\n      };\n}\n\nexport type Event = TrackEvent | IdentifyEvent | GroupIdentifyEvent | RevenueEvent;\n"
  },
  {
    "path": "packages/analytics-core/src/types/event/ingestion-metadata.ts",
    "content": "/**\n * Ingestion metadata\n */\nexport interface IngestionMetadata {\n  /** The source name of ingestion metadata e.g. \"ampli\" */\n  sourceName?: string;\n  /** The source version of ingestion metadata e.g. \"2.0.0\" */\n  sourceVersion?: string;\n}\n\n/**\n * Ingestion metadata event property, snake-case\n */\nexport interface IngestionMetadataEventProperty {\n  /** The source name of ingestion metadata e.g. \"ampli\" */\n  source_name?: string;\n  /** The source version of ingestion metadata e.g. \"2.0.0\" */\n  source_version?: string;\n}\n"
  },
  {
    "path": "packages/analytics-core/src/types/event/plan.ts",
    "content": "/**\n * Tracking plan\n */\nexport interface Plan {\n  /** The tracking plan branch name e.g. \"main\" */\n  branch?: string;\n  /** The tracking plan source e.g. \"web\" */\n  source?: string;\n  /** The tracking plan version e.g. \"1\", \"15\" */\n  version?: string;\n  /** The tracking plan version Id e.g. \"9ec23ba0-275f-468f-80d1-66b88bff9529\" */\n  versionId?: string;\n}\n"
  },
  {
    "path": "packages/analytics-core/src/types/event-callback.ts",
    "content": "import { Result } from './result';\n\nexport type EventCallback = (result: Result) => void;\n"
  },
  {
    "path": "packages/analytics-core/src/types/form-interactions.ts",
    "content": "export interface FormInteractionsOptions {\n  /**\n   * A callback function to control when form submit events are tracked.\n   * Use this for custom form validation logic when native HTML5 validation is disabled\n   * (e.g., forms with the `novalidate` attribute).\n   *\n   * Note: This only controls the `[Amplitude] Form Submitted` event, not the\n   * `[Amplitude] Form Started` event which is tracked on first field change.\n   *\n   * @param event - The SubmitEvent triggered by the form submission\n   * @returns `true` to track the form submit event, `false` to skip tracking\n   *\n   * @example\n   * ```typescript\n   * // Track only when form passes custom validation\n   * formInteractions: {\n   *   shouldTrackSubmit: (event) => {\n   *     const form = event.target as HTMLFormElement;\n   *     return form.checkValidity() && myCustomValidation(form);\n   *   }\n   * }\n   * ```\n   */\n  shouldTrackSubmit?: (event: SubmitEvent) => boolean;\n}\n"
  },
  {
    "path": "packages/analytics-core/src/types/frustration-interactions.ts",
    "content": "import { ActionType } from './element-interactions';\n\n/**\n * Configuration options for dead clicks tracking\n */\nexport interface DeadClickOptions {\n  /**\n   * CSS selectors to define which elements on the page to track for dead clicks.\n   * A dead click is a click that doesn't result in any visible change or navigation.\n   */\n  cssSelectorAllowlist?: string[];\n}\n\n/**\n * Configuration options for rage clicks tracking\n */\nexport interface RageClickOptions {\n  /**\n   * CSS selectors to define which elements on the page to track for rage clicks.\n   * A rage click is multiple rapid clicks on the same element within a 3s time window.\n   */\n  cssSelectorAllowlist?: string[];\n}\n\n/**\n * Configuration options for thrashed cursor tracking\n */\nexport interface ThrashedCursorOptions {\n  /**\n   * Number of direction changes required to consider a thrashed cursor.\n   * Minimum of 5\n   * (x axis changes and y axis changes are counted separately)\n   * @default 20\n   */\n  directionChanges?: number;\n  /**\n   * Time window in milliseconds to consider a thrashed cursor.\n   * Maximum of of 4000\n   * @default 2000\n   */\n  threshold?: number;\n}\n\n/**\n * Configuration options for error clicks tracking\n */\nexport interface ErrorClickOptions {\n  /**\n   * CSS selectors to define which elements on the page to track for error clicks.\n   * An error click is a click that results in an error.\n   */\n  cssSelectorAllowlist?: string[];\n}\n\n/**\n * Configuration options for frustration interactions tracking.\n * This includes dead clicks and rage clicks tracking.\n */\nexport interface FrustrationInteractionsOptions {\n  /**\n   * List of page URLs to allow auto tracking on.\n   * When provided, only allow tracking on these URLs.\n   * Both full URLs and regex are supported.\n   */\n  pageUrlAllowlist?: (string | RegExp)[];\n\n  /**\n   * List of page URLs to exclude from auto tracking.\n   * When provided, tracking will be blocked on these URLs.\n   * Both full URLs and regex are supported.\n   * This takes precedence over pageUrlAllowlist.\n   */\n  pageUrlExcludelist?: (string | RegExp)[];\n\n  /**\n   * Function to determine whether an event should be tracked.\n   * When provided, this function overwrites all other allowlists and configurations.\n   * If the function returns true, the event will be tracked.\n   * If the function returns false, the event will not be tracked.\n   * @param actionType - The type of action that triggered the event.\n   * @param element - The [Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) that triggered the event.\n   */\n  shouldTrackEventResolver?: (actionType: ActionType, element: DomElement) => boolean;\n\n  /**\n   * Prefix for data attributes to allow auto collecting.\n   * Default is 'data-amp-track-'.\n   */\n  dataAttributePrefix?: string;\n\n  /**\n   * Configuration for dead clicks tracking.\n   * Set to `false` to disable dead click tracking.\n   * Set to `true` or an options object to enable with default or custom settings.\n   * Default is false.\n   */\n  deadClicks?: boolean | DeadClickOptions;\n\n  /**\n   * Configuration for rage clicks tracking.\n   * Set to `false` to disable rage click tracking.\n   * Set to `true` or an options object to enable with default settings.\n   * Default is false.\n   */\n  rageClicks?: boolean | RageClickOptions;\n\n  /**\n   * Configuration for error clicks tracking\n   * Set to `false` to disable error click tracking.\n   * Set to `true` or an options object to enable with default settings.\n   * Default is false.\n   */\n  errorClicks?: boolean | ErrorClickOptions;\n  /**\n   * Configuration for thrashed cursor tracking.\n   * Set to `false` to disable thrashed cursor tracking.\n   * Set to `true` or an options object to enable with default settings.\n   * Default is false.\n   */\n  thrashedCursor?: boolean | ThrashedCursorOptions;\n\n  /**\n   * RegExp pattern list to allow custom patterns for text masking\n   */\n  maskTextRegex?: (RegExp | { pattern: string; description: string })[];\n}\n\nconst CLICKABLE_ELEMENT_SELECTORS = [\n  'a',\n  'button',\n  '[role=\"button\"]',\n  '[role=\"link\"]',\n  '[role=\"menuitem\"]',\n  '[role=\"menuitemcheckbox\"]',\n  '[role=\"menuitemradio\"]',\n  '[role=\"option\"]',\n  '[role=\"tab\"]',\n  '[role=\"treeitem\"]',\n  '[contenteditable=\"true\" i]',\n];\n\nconst DEFAULT_ERROR_AND_DEAD_CLICK_ALLOWLIST = [\n  'input[type=\"button\"]',\n  'input[type=\"submit\"]',\n  'input[type=\"reset\"]',\n  'input[type=\"image\"]',\n  'input[type=\"file\"]',\n  ...CLICKABLE_ELEMENT_SELECTORS,\n];\n\n/**\n * Default CSS selectors for dead clicks tracking\n */\nexport const DEFAULT_DEAD_CLICK_ALLOWLIST = DEFAULT_ERROR_AND_DEAD_CLICK_ALLOWLIST;\n\n/**\n * Default CSS selectors for error tracking\n */\nexport const DEFAULT_ERROR_CLICK_ALLOWLIST = DEFAULT_ERROR_AND_DEAD_CLICK_ALLOWLIST;\n\n/**\n * Default CSS selectors for rage clicks tracking\n */\nexport const DEFAULT_RAGE_CLICK_ALLOWLIST = ['*'];\n\n/**\n * Default time window for dead clicks (3 seconds)\n */\nexport const DEFAULT_DEAD_CLICK_WINDOW_MS = 3_000;\n\n/**\n * Default time window for rage clicks (1 second)\n */\nexport const DEFAULT_RAGE_CLICK_WINDOW_MS = 1_000;\n\n/**\n * Default threshold for rage clicks (4 clicks)\n */\nexport const DEFAULT_RAGE_CLICK_THRESHOLD = 4;\n\n/**\n * Default threshold for rage clicks to be considered out of bounds (50 pixels)\n */\nexport const DEFAULT_RAGE_CLICK_OUT_OF_BOUNDS_THRESHOLD = 50; // pixels\n\n// DomElement is [Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) if the dom library is included in tsconfig.json\n// and never if it is not included\n// eslint-disable-next-line no-restricted-globals\ntype DomElement = typeof globalThis extends {\n  Element: new (...args: any) => infer T;\n}\n  ? T\n  : never;\n"
  },
  {
    "path": "packages/analytics-core/src/types/loglevel.ts",
    "content": "export enum LogLevel {\n  None = 0,\n  Error = 1,\n  Warn = 2,\n  Verbose = 3,\n  Debug = 4,\n}\n"
  },
  {
    "path": "packages/analytics-core/src/types/messages.ts",
    "content": "export const SUCCESS_MESSAGE = 'Event tracked successfully';\nexport const UNEXPECTED_ERROR_MESSAGE = 'Unexpected error occurred';\nexport const MAX_RETRIES_EXCEEDED_MESSAGE = 'Event rejected due to exceeded retry count';\nexport const OPT_OUT_MESSAGE = 'Event skipped due to optOut config';\nexport const MISSING_API_KEY_MESSAGE = 'Event rejected due to missing API key';\nexport const INVALID_API_KEY = 'Invalid API key';\nexport const CLIENT_NOT_INITIALIZED = 'Client not initialized';\n"
  },
  {
    "path": "packages/analytics-core/src/types/network-tracking.ts",
    "content": "export interface NetworkTrackingOptions {\n  /**\n   * Suppresses tracking Amplitude requests from network capture.\n   * @defaultValue `true`\n   */\n  ignoreAmplitudeRequests?: boolean;\n  /**\n   * Hosts to ignore for network capture. Supports wildcard.\n   * @defaultValue `[]`\n   */\n  ignoreHosts?: string[];\n  /**\n   * Rules to determine which network requests should be captured.\n   *\n   * Performs matching on array in reverse order.\n   */\n  captureRules?: NetworkCaptureRule[];\n}\n\nexport interface BodyCaptureRule {\n  /**\n   * List of JSON pointers to capture from a request or response body (JSON objects only)\n   *\n   * Includes nothing, by default.\n   * Any keys defined in excludelist will be excluded from the capture.\n   *\n   * Follows a syntax similar to [JSON Pointer](https://datatracker.ietf.org/doc/html/rfc6901), except:\n   * - The leading / is optional\n   * - A wildcard * can be used to match any key\n   * - A double-wildcard ** can be used to match any number of keys (or no keys)\n   * - The structure of the JSON is preserved (ie: the captured body is a subset of the original body)\n   */\n  allowlist?: string[];\n  /**\n   * List of JSON pointers to exclude from a request or response body (JSON objects only)\n   *\n   * This \"uncaptures\" any attributes that are captured by the allowlist.\n   * @deprecated this property is deprecated in favor of \"excludelist\"\n   */\n  blocklist?: string[];\n  /**\n   * List of JSON pointers to exclude from a request or response body (JSON objects only)\n   *\n   * This \"uncaptures\" any attributes that are captured by the allowlist.\n   */\n  excludelist?: string[];\n}\n\nexport interface NetworkCaptureRule {\n  /**\n   * Hosts to allow for network capture. Supports wildcard.\n   * @defaultValue `[\"*\"]` all hosts (except amplitude)\n   */\n  hosts?: string[];\n  /**\n   * URL patterns to allow for network capture. Supports wildcard.\n   *\n   * This takes precedence over `hosts`\n   * @defaultValue `[\"*\"]` all URLs\n   */\n  urls?: (string | RegExp)[];\n  /**\n   * Methods to allow for network capture.\n   * @defaultValue `[\"*\"]` all methods\n   */\n  methods?: string[];\n  /**\n   * Range list that defines the status codes to be captured.\n   * @defaultValue `500-599`\n   */\n  statusCodeRange?: string;\n  /**\n   * Capture headers from network response.\n   *\n   * If true, SAFE_HEADERS are captured. If false, no headers are captured.\n   * If a string array, the headers in the array are captured.\n   *\n   * @defaultValue `false`\n   */\n  responseHeaders?: string[] | boolean;\n  /**\n   * Capture headers from network request.\n   *\n   * If true, SAFE_HEADERS are captured. If false, no headers are captured.\n   * If a string array, the headers in the array are captured.\n   *\n   * @defaultValue `false`\n   */\n  requestHeaders?: string[] | boolean;\n  /**\n   * Determines what to capture from the response body.\n   */\n  responseBody?: BodyCaptureRule;\n  /**\n   * Determines what to capture from the request body.\n   */\n  requestBody?: BodyCaptureRule;\n  /**\n   * Threshold   for what is classified as a slow request (in seconds).\n   * @defaultValue `3`\n   */\n  // slowThreshold?: number;\n}\n"
  },
  {
    "path": "packages/analytics-core/src/types/offline.ts",
    "content": "export const OfflineDisabled = null;\n"
  },
  {
    "path": "packages/analytics-core/src/types/page-url-enrichment.ts",
    "content": "/**\n * @experimental this feature is experimental and may not be stable\n */\nexport type PageUrlEnrichmentOptions = {\n  // a list of domains that are to be considered internal, e.g. 'example.com', 'example.co.uk'.\n  // Previous Page URLs will be matched to these strings to determine the Previous Page URL type.\n  // Adding the domain is sufficient, there is no need to add the subdomain.\n  internalDomains?: string[];\n};\n"
  },
  {
    "path": "packages/analytics-core/src/types/page-view-tracking.ts",
    "content": "export interface PageTrackingOptions {\n  trackOn?: PageTrackingTrackOn;\n  trackHistoryChanges?: PageTrackingHistoryChanges;\n  eventType?: string;\n  pageCounter?: number;\n}\n\nexport type PageTrackingTrackOn = 'attribution' | (() => boolean);\n\nexport type PageTrackingHistoryChanges = 'all' | 'pathOnly';\n"
  },
  {
    "path": "packages/analytics-core/src/types/payload.ts",
    "content": "import { Event } from './event/event';\nimport { RequestMetadata } from '../config';\n\nexport interface PayloadOptions {\n  min_id_length?: number;\n}\n\nexport interface Payload {\n  api_key: string;\n  events: readonly Event[];\n  options?: PayloadOptions;\n  client_upload_time?: string;\n  request_metadata?: RequestMetadata;\n}\n"
  },
  {
    "path": "packages/analytics-core/src/types/performance-tracking.ts",
    "content": "/**\n * Configuration options for main thread block tracking\n */\nexport interface MainThreadBlockOptions {\n  /**\n   * Minimum duration in milliseconds to consider a main thread block.\n   * @default 100\n   */\n  durationThreshold?: number;\n}\n\n/**\n * Configuration options for performance tracking.\n */\nexport interface PerformanceTrackingOptions {\n  /**\n   * List of page URLs to allow auto tracking on.\n   * When provided, only allow tracking on these URLs.\n   * Both full URLs and regex are supported.\n   */\n  pageUrlAllowlist?: (string | RegExp)[];\n\n  /**\n   * List of page URLs to exclude from auto tracking.\n   * When provided, tracking will be blocked on these URLs.\n   * Both full URLs and regex are supported.\n   * This takes precedence over pageUrlAllowlist.\n   */\n  pageUrlExcludelist?: (string | RegExp)[];\n\n  /**\n   * Configuration for main thread block tracking.\n   * Uses the Long Animation Frames API where available, falling back to Long Tasks.\n   * Set to `false` to disable tracking.\n   * Set to `true` or an options object to enable with default or custom settings.\n   * Default is false.\n   */\n  mainThreadBlock?: boolean | MainThreadBlockOptions;\n}\n"
  },
  {
    "path": "packages/analytics-core/src/types/plugin.ts",
    "content": "import { Event } from './event/event';\nimport { IConfig } from './config/core-config';\nimport { Result } from './result';\nimport { CoreClient } from './client/core-client';\n\ntype PluginTypeBefore = 'before';\ntype PluginTypeEnrichment = 'enrichment';\ntype PluginTypeDestination = 'destination';\nexport type PluginType = PluginTypeBefore | PluginTypeEnrichment | PluginTypeDestination;\n\nexport interface AnalyticsIdentity {\n  deviceId?: string;\n  userId?: string;\n  userProperties?: { [key: string]: any };\n}\n\ninterface PluginBase<T = CoreClient, U = IConfig> {\n  name?: string;\n  type?: PluginType;\n  setup?(config: U, client: T): Promise<void>;\n  teardown?(): Promise<void>;\n  /**\n   * Called when the identity is changed. This is a **best-effort** API and may not be triggered in all scenarios.\n   *\n   * Currently supported only in the Browser SDK. Not supported in React Native or Node SDKs.\n   *\n   * @param identity The changed identity. If a field is missing, it means it has not changed.\n   * For example, `{ userId: undefined }` means the userId was explicitly changed to `undefined`,\n   * while deviceId and userProperties remain unchanged.\n   *\n   * Note: `onIdentityChanged()` will be triggered when a user logs in via `setUserId()`.\n   * It will not be triggered on subsequent page loads (e.g., when a user reopens the site in a new tab).\n   */\n  onIdentityChanged?(identity: AnalyticsIdentity): Promise<void>;\n  onSessionIdChanged?(sessionId: number): Promise<void>;\n  onOptOutChanged?(optOut: boolean): Promise<void>;\n  /**\n   * Called when reset() is invoked on the client.\n   *\n   * Currently supported only in the Browser SDK. Not supported in React Native or Node SDKs.\n   */\n  onReset?(): Promise<void>;\n}\n\nexport interface BeforePlugin<T = CoreClient, U = IConfig> extends PluginBase<T, U> {\n  type: PluginTypeBefore;\n  execute?(context: Event): Promise<Event | null>;\n}\n\nexport interface EnrichmentPlugin<T = CoreClient, U = IConfig> extends PluginBase<T, U> {\n  type?: PluginTypeEnrichment;\n  execute?(context: Event): Promise<Event | null>;\n}\n\nexport interface DestinationPlugin<T = CoreClient, U = IConfig> extends PluginBase<T, U> {\n  type: PluginTypeDestination;\n  execute(context: Event): Promise<Result>;\n  flush?(): Promise<void>;\n}\n\nexport type Plugin<T = CoreClient, U = IConfig> = BeforePlugin<T, U> | EnrichmentPlugin<T, U> | DestinationPlugin<T, U>;\n"
  },
  {
    "path": "packages/analytics-core/src/types/proxy.ts",
    "content": "import { Result } from './result';\n\ninterface ProxyItem {\n  name: string;\n  args: any[];\n  resolve?: (promise: Promise<Result>) => void;\n}\n\nexport type QueueProxy = Array<ProxyItem>;\n\nexport interface InstanceProxy {\n  _q: QueueProxy;\n  _iq: Record<string, InstanceProxy>;\n}\n"
  },
  {
    "path": "packages/analytics-core/src/types/response.ts",
    "content": "import { Status } from './status';\n\nexport interface SuccessBody {\n  eventsIngested: number;\n  payloadSizeBytes: number;\n  serverUploadTime: number;\n}\n\nexport interface InvalidRequestBody {\n  error: string;\n  missingField: string;\n  eventsWithInvalidFields: { [eventField: string]: number[] };\n  eventsWithMissingFields: { [eventField: string]: number[] };\n  eventsWithInvalidIdLengths: { [eventField: string]: number[] };\n  epsThreshold: 0;\n  exceededDailyQuotaDevices: { [deviceId: string]: number };\n  silencedDevices: string[];\n  silencedEvents: number[];\n  throttledDevices: { [deviceId: string]: number };\n  throttledEvents: number[];\n}\nexport interface PayloadTooLargeBody {\n  error: string;\n}\nexport interface RateLimitBody {\n  error: string;\n  epsThreshold: number;\n  throttledDevices: { [deviceId: string]: number };\n  throttledUsers: { [userId: string]: number };\n  exceededDailyQuotaDevices: { [deviceId: string]: number };\n  exceededDailyQuotaUsers: { [userId: string]: number };\n  throttledEvents: number[];\n}\n\nexport type StatusWithResponseBody = Status.Invalid | Status.PayloadTooLarge | Status.RateLimit | Status.Success;\n\nexport type ResponseBody = SuccessBody | InvalidRequestBody | PayloadTooLargeBody | RateLimitBody;\n\nexport interface SuccessResponse {\n  status: Status.Success;\n  statusCode: number;\n  body: SuccessBody;\n}\n\nexport interface InvalidResponse {\n  status: Status.Invalid;\n  statusCode: number;\n  body: InvalidRequestBody;\n}\n\nexport interface PayloadTooLargeResponse {\n  status: Status.PayloadTooLarge;\n  statusCode: number;\n  body: PayloadTooLargeBody;\n}\n\nexport interface RateLimitResponse {\n  status: Status.RateLimit;\n  statusCode: number;\n  body: RateLimitBody;\n}\n\nexport interface TimeoutResponse {\n  status: Status.Timeout;\n  statusCode: number;\n}\n\nexport interface OtherResponse {\n  status: Exclude<Status, StatusWithResponseBody>;\n  statusCode: number;\n}\n\nexport type Response =\n  | SuccessResponse\n  | InvalidResponse\n  | PayloadTooLargeResponse\n  | RateLimitResponse\n  | TimeoutResponse\n  | OtherResponse;\n"
  },
  {
    "path": "packages/analytics-core/src/types/result.ts",
    "content": "import { Event } from './event/event';\n\nexport interface Result {\n  event: Event;\n  code: number;\n  message: string;\n}\n"
  },
  {
    "path": "packages/analytics-core/src/types/server-zone.ts",
    "content": "/**\n * @deprecated use ServerZoneType instead\n */\nexport enum ServerZone {\n  US = 'US',\n  EU = 'EU',\n  /**\n   * Add for session-replay-browser migration from analytics-type v1.x.\n   */\n  STAGING = 'STAGING',\n}\n\nexport type ServerZoneType = 'US' | 'EU';\n"
  },
  {
    "path": "packages/analytics-core/src/types/status.ts",
    "content": "/** The status of an event. */\nexport enum Status {\n  /** The status could not be determined. */\n  Unknown = 'unknown',\n  /** The event was skipped due to configuration or callbacks. */\n  Skipped = 'skipped',\n  /** The event was sent successfully. */\n  Success = 'success',\n  /** A user or device in the payload is currently rate limited and should try again later. */\n  RateLimit = 'rate_limit',\n  /** The sent payload was too large to be processed. */\n  PayloadTooLarge = 'payload_too_large',\n  /** The event could not be processed. */\n  Invalid = 'invalid',\n  /** A server-side error ocurred during submission. */\n  Failed = 'failed',\n  /** a server or client side error occuring when a request takes too long and is cancelled */\n  Timeout = 'Timeout',\n  /** NodeJS runtime environment error.. E.g. disconnected from network */\n  SystemError = 'SystemError',\n}\n"
  },
  {
    "path": "packages/analytics-core/src/types/storage.ts",
    "content": "import { IDiagnosticsClient } from '../diagnostics/diagnostics-client';\n\nexport interface Storage<T> {\n  isEnabled(): Promise<boolean>;\n  get(key: string): Promise<T | undefined>;\n  getRaw(key: string): Promise<string | undefined>;\n  set(key: string, value: T): Promise<void>;\n  remove(key: string): Promise<void>;\n  reset(): Promise<void>;\n}\n\nexport interface StorageSync<T> {\n  get: () => T | undefined;\n  set: (value: T | null) => void;\n}\n\nexport interface CookieStorageOptions {\n  domain?: string;\n  expirationDays?: number;\n  sameSite?: string;\n  secure?: boolean;\n}\n\n/**\n * Configuration for CookieStorage behavior.\n * Separated from options to keep storage-specific config distinct from cookie attributes.\n */\nexport interface CookieStorageConfig {\n  /**\n   * Function to resolve duplicate cookies when multiple cookies with the same key exist.\n   * Returns true if the cookie value should be used, false otherwise.\n   */\n  duplicateResolverFn?: (value: string) => boolean;\n  diagnosticsClient?: IDiagnosticsClient;\n}\n\nexport type IdentityStorageType = 'cookie' | 'localStorage' | 'sessionStorage' | 'none';\n"
  },
  {
    "path": "packages/analytics-core/src/types/transport.ts",
    "content": "import { Payload } from './payload';\nimport { Response } from './response';\n\nexport interface Transport {\n  send(serverUrl: string, payload: Payload, enableRequestBodyCompression?: boolean): Promise<Response | null>;\n}\n\nexport type TransportType = 'xhr' | 'beacon' | 'fetch';\n\nexport interface TransportOptions {\n  type?: TransportType;\n  headers?: Record<string, string>;\n}\n\nexport type TransportTypeOrOptions = TransportType | TransportOptions;\n"
  },
  {
    "path": "packages/analytics-core/src/types/user-session.ts",
    "content": "export interface UserSession {\n  userId?: string;\n  deviceId?: string;\n  sessionId?: number;\n  deferredSessionId?: number;\n  lastEventTime?: number;\n  optOut: boolean;\n  lastEventId?: number;\n  pageCounter?: number;\n  debugLogsEnabled?: boolean;\n  cookieDomain?: string;\n}\n"
  },
  {
    "path": "packages/analytics-core/src/utils/chunk.ts",
    "content": "// Creates an array of elements split into groups the length of size.\n// If array can't be split evenly, the final chunk will be the remaining elements.\n// Works similary as https://lodash.com/docs/4.17.15#chunk\n\nexport const chunk = <T>(arr: T[], size: number) => {\n  const chunkSize = Math.max(size, 1);\n  return arr.reduce<T[][]>((chunks, element, index) => {\n    const chunkIndex = Math.floor(index / chunkSize);\n    if (!chunks[chunkIndex]) {\n      chunks[chunkIndex] = [];\n    }\n    chunks[chunkIndex].push(element);\n    return chunks;\n  }, []);\n};\n"
  },
  {
    "path": "packages/analytics-core/src/utils/debug.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-unsafe-call */\n/* eslint-disable @typescript-eslint/no-non-null-assertion */\nimport { AmplitudeCore } from '../core-client';\nimport { LogConfig, DebugContext } from '../logger';\nimport { LogLevel } from '../types/loglevel';\n\nexport const getStacktrace = (ignoreDepth = 0): string[] => {\n  const trace = new Error().stack || '';\n  return trace\n    .split('\\n')\n    .slice(2 + ignoreDepth)\n    .map((text) => text.trim());\n};\n\n// This hook makes sure we always get the latest logger and logLevel.\nexport const getClientLogConfig = (client: AmplitudeCore) => (): LogConfig => {\n  const { loggerProvider: logger, logLevel } = { ...client.config };\n  return {\n    logger,\n    logLevel,\n  };\n};\n\n// This is a convenient function to get the attribute from object with string path, similar to lodash '#get'.\nexport const getValueByStringPath = (obj: any, path: string): any => {\n  path = path.replace(/\\[(\\w+)\\]/g, '.$1'); // convert indexes to properties\n  path = path.replace(/^\\./, ''); // strip a leading dot\n  for (const attr of path.split('.')) {\n    if (attr in obj) {\n      obj = obj[attr];\n    } else {\n      return;\n    }\n  }\n  return obj;\n};\n\nexport const getClientStates = (client: AmplitudeCore, paths: Array<string>) => (): { [key: string]: any } => {\n  const res: { [key: string]: any } = {};\n  for (const path of paths) {\n    res[path] = getValueByStringPath(client, path);\n  }\n  return res;\n};\n\nexport const debugWrapper =\n  <T extends Array<any>, R>(\n    fn: (...args: T) => R,\n    fnName: string,\n    getLogConfig: () => LogConfig,\n    getStates?: () => { [key: string]: any },\n    fnContext: any = null,\n  ) =>\n  (...args: T): R => {\n    const { logger, logLevel } = getLogConfig();\n    // return early if possible to reduce overhead\n    if ((logLevel && logLevel < LogLevel.Debug) || !logLevel || !logger) {\n      return fn.apply(fnContext, args);\n    }\n    const debugContext: DebugContext = {\n      type: 'invoke public method',\n      name: fnName,\n      args,\n      stacktrace: getStacktrace(1),\n      time: {\n        start: new Date().toISOString(),\n      },\n      states: {},\n    };\n    if (getStates && debugContext.states) {\n      debugContext.states.before = getStates();\n    }\n    const result = fn.apply(fnContext, args);\n    if (result && (result as any).promise) {\n      // if result is a promise, add the callback\n      (result as any).promise.then(() => {\n        if (getStates && debugContext.states) {\n          debugContext.states.after = getStates();\n        }\n        if (debugContext.time) {\n          debugContext.time.end = new Date().toISOString();\n        }\n        logger.debug(JSON.stringify(debugContext, null, 2));\n      });\n    } else {\n      if (getStates && debugContext.states) {\n        debugContext.states.after = getStates();\n      }\n      if (debugContext.time) {\n        debugContext.time.end = new Date().toISOString();\n      }\n      logger.debug(JSON.stringify(debugContext, null, 2));\n    }\n    return result;\n  };\n"
  },
  {
    "path": "packages/analytics-core/src/utils/environment.ts",
    "content": "import { getGlobalScope } from '../global-scope';\n\nexport function isChromeExtension(): boolean {\n  const globalScope = getGlobalScope() as { chrome?: { runtime?: { id?: string } } };\n  return typeof globalScope?.chrome?.runtime?.id === 'string';\n}\n"
  },
  {
    "path": "packages/analytics-core/src/utils/event-builder.ts",
    "content": "import { Identify, IIdentify } from '../identify';\nimport { IRevenue } from '../revenue';\nimport { BaseEvent, EventOptions } from '../types/event/base-event';\nimport { TrackEvent, IdentifyEvent, GroupIdentifyEvent, SpecialEventType, RevenueEvent } from '../types/event/event';\n\nexport const createTrackEvent = (\n  eventInput: BaseEvent | string,\n  eventProperties?: Record<string, any>,\n  eventOptions?: EventOptions,\n): TrackEvent => {\n  const baseEvent: BaseEvent = typeof eventInput === 'string' ? { event_type: eventInput } : eventInput;\n  return {\n    ...baseEvent,\n    ...eventOptions,\n    ...(eventProperties && { event_properties: eventProperties }),\n  };\n};\n\nexport const createIdentifyEvent = (identify: IIdentify, eventOptions?: EventOptions): IdentifyEvent => {\n  const identifyEvent: IdentifyEvent = {\n    ...eventOptions,\n    event_type: SpecialEventType.IDENTIFY,\n    user_properties: identify.getUserProperties(),\n  };\n\n  return identifyEvent;\n};\n\nexport const createGroupIdentifyEvent = (\n  groupType: string,\n  groupName: string | string[],\n  identify: IIdentify,\n  eventOptions?: EventOptions,\n): GroupIdentifyEvent => {\n  const groupIdentify: GroupIdentifyEvent = {\n    ...eventOptions,\n    event_type: SpecialEventType.GROUP_IDENTIFY,\n    group_properties: identify.getUserProperties(),\n    groups: {\n      [groupType]: groupName,\n    },\n  };\n\n  return groupIdentify;\n};\n\nexport const createGroupEvent = (groupType: string, groupName: string | string[], eventOptions?: EventOptions) => {\n  const identify = new Identify();\n  identify.set(groupType, groupName);\n\n  const groupEvent: IdentifyEvent = {\n    ...eventOptions,\n    event_type: SpecialEventType.IDENTIFY,\n    user_properties: identify.getUserProperties(),\n    groups: {\n      [groupType]: groupName,\n    },\n  };\n  return groupEvent;\n};\n\nexport const createRevenueEvent = (revenue: IRevenue, eventOptions?: EventOptions): RevenueEvent => {\n  return {\n    ...eventOptions,\n    event_type: SpecialEventType.REVENUE,\n    event_properties: revenue.getEventProperties(),\n  };\n};\n"
  },
  {
    "path": "packages/analytics-core/src/utils/json-query.ts",
    "content": "type Json = Record<string, any>;\n\nfunction isJsonPrimitive(json?: Json): boolean {\n  return (\n    typeof json === 'string' ||\n    typeof json === 'number' ||\n    typeof json === 'boolean' ||\n    json === null ||\n    json === undefined\n  );\n}\n\n/**\n * Prune a JSON object to only include the keys in the allowlist and excludes the keys\n * in the exclude list.\n *\n * This function is a mutative function that will modify the original JSON object.\n * This is done to avoid creating a new JSON object and copying the data.\n *\n * @param json - The JSON object to prune.\n * @param allowlist - The keys to include in the pruned JSON object.\n * @param excludelist - The keys to exclude from the pruned JSON object.\n */\nexport function pruneJson(json: Json | null | undefined, allowlist: string[], excludelist: string[]) {\n  if (!json) return;\n  // tokenize the allowlist and excludelist\n  const allowlistTokens = allowlist.map(tokenizeJsonPath);\n  const excludelistTokens = excludelist.map(tokenizeJsonPath);\n\n  _pruneJson({\n    json,\n    allowlist: allowlistTokens,\n    excludelist: excludelistTokens,\n    ancestors: [],\n  });\n}\n\nexport function _pruneJson({\n  json,\n  targetObject,\n  allowlist,\n  excludelist,\n  ancestors,\n  parentObject,\n  targetKey,\n}: {\n  json: Json;\n  targetObject?: Json;\n  allowlist: string[][];\n  excludelist: string[][];\n  ancestors: string[];\n  parentObject?: Json;\n  targetKey?: string;\n}) {\n  if (!targetObject) {\n    targetObject = json;\n  }\n\n  const keys = Object.keys(targetObject);\n  for (const key of keys) {\n    const path = [...ancestors, key];\n    if (isJsonPrimitive(targetObject[key] as Json)) {\n      // if the value does not match allowlist or matches exclude list, delete it\n      if (!hasPathMatchInList(path, allowlist) || hasPathMatchInList(path, excludelist)) {\n        delete targetObject[key];\n      }\n    } else {\n      _pruneJson({\n        json,\n        targetObject: targetObject[key] as Json,\n        allowlist,\n        excludelist,\n        ancestors: path,\n        parentObject: targetObject,\n        targetKey: key,\n      });\n    }\n  }\n\n  // if this object is empty now, delete the whole object\n  if (Object.keys(targetObject).length === 0 && parentObject && targetKey) {\n    delete parentObject[targetKey];\n  }\n}\n\n/**\n * Tokenize a JSON path string into an array of strings.\n * Escapes ~0 and ~1 to ~ and / respectively.\n *\n * e.g.) turns string \"a/b/c\" into [\"a\", \"b\", \"c\"]\n *\n * @param path - The JSON path to tokenize.\n * @returns The tokenized JSON path.\n */\nexport function tokenizeJsonPath(path: string): string[] {\n  if (path.startsWith('/')) {\n    path = path.slice(1);\n  }\n  return path.split('/').map((token) => token.replace(/~0/g, '~').replace(/~1/g, '/'));\n}\n\n/**\n * Check if a JSON path matches a path matcher.\n *\n * Rules:\n * 1. If a key in a path and a matcher are the same, then they match, move to the next\n * 2. If the matcher is a *, then it matches the key, move to the next\n * 3. If the matcher is a **, then it matches >=0 keys\n *\n * @param path - The path to check.\n * @param pathMatcher - The path matcher to check against.\n * @param i - The current index of the path.\n * @param j - The current index of the path matcher.\n * @returns True if the path matches the path matcher, false otherwise.\n */\nexport function isPathMatch(path: string[], pathMatcher: string[], i = 0, j = 0): boolean {\n  if (j === pathMatcher.length) {\n    return i === path.length;\n  }\n\n  if (i === path.length) {\n    while (j < pathMatcher.length && pathMatcher[j] === '**') {\n      j++;\n    }\n    return j === pathMatcher.length;\n  }\n\n  const currentMatcher = pathMatcher[j];\n\n  if (currentMatcher === '**') {\n    if (j + 1 === pathMatcher.length) {\n      return true;\n    }\n    for (let k = i; k <= path.length; k++) {\n      if (isPathMatch(path, pathMatcher, k, j + 1)) {\n        return true;\n      }\n    }\n    return false;\n  } else if (currentMatcher === '*' || currentMatcher === path[i]) {\n    return isPathMatch(path, pathMatcher, i + 1, j + 1);\n  } else {\n    return false;\n  }\n}\n\n/**\n * Check if a JSON path matches any of the path matchers in the allow or exclude list.\n *\n * @param path - The JSON path to check.\n * @param allowOrExcludeList - The allow or exclude list to check against.\n * @returns True if the path matches any of the path matchers in the allow or exclude list, false otherwise.\n */\nfunction hasPathMatchInList(path: string[], allowOrExcludeList: string[][]): boolean {\n  return allowOrExcludeList.some((l) => isPathMatch(path, l));\n}\n"
  },
  {
    "path": "packages/analytics-core/src/utils/observable.ts",
    "content": "import ZenObservable from 'zen-observable';\n\nexport { ZenObservable as Observable };\n\n/** Subscription type for zen-observable */\ninterface Subscription {\n  closed: boolean;\n  unsubscribe(): void;\n}\n\n/** Observer type for zen-observable */\ninterface Observer<T> {\n  start?(subscription: Subscription): unknown;\n  next?(value: T): void;\n  error?(errorValue: unknown): void;\n  complete?(): void;\n}\n\n/**\n * asyncMap operator for Zen Observable\n *\n * Maps each value emitted by the source Observable using an async function,\n * emitting the resolved values in the same order they arrive.\n */\nfunction asyncMap<T, R>(observable: ZenObservable<T>, fn: (value: T) => Promise<R>): ZenObservable<R> {\n  return new ZenObservable(\n    (observer: { next: (value: R) => void; error: (error: any) => void; complete: () => void }) => {\n      observable.subscribe({\n        next: (value: T) => {\n          fn(value)\n            .then((result: R) => {\n              return observer.next(result);\n            })\n            .catch((error: any) => observer.error(error));\n        },\n        error: (error: any) => {\n          observer.error(error);\n        },\n        complete: () => {\n          observer.complete();\n        },\n      });\n    },\n  );\n}\n\ntype Unsubscribable = {\n  unsubscribe: () => void;\n};\n\ntype ZenObserver<A, B> = { next: (v: A | B) => void; error: (e: unknown) => void; complete: () => void };\n\n/**\n * merge operator for Zen Observable\n *\n * Merges two observables into a single observable, emitting values from both sources in the order they arrive.\n * @param sourceA Observable to merge\n * @param sourceB Observable to merge\n * @returns Unsubscribable cleanup function\n */\nfunction merge<A, B>(sourceA: ZenObservable<A>, sourceB: ZenObservable<B>): ZenObservable<A | B> {\n  return new ZenObservable<A | B>((observer: ZenObserver<A, B>) => {\n    let closed = false;\n\n    const subscriptions: Set<Unsubscribable> = new Set();\n\n    const cleanup = (): void => {\n      closed = true;\n      for (const sub of subscriptions) {\n        try {\n          sub.unsubscribe();\n        } catch {\n          /* do nothing */\n        }\n      }\n      subscriptions.clear();\n    };\n\n    const subscribeTo = <T>(source: ZenObservable<T>) => {\n      const sub = source.subscribe({\n        next(value: T) {\n          if (!closed) observer.next(value as A | B);\n        },\n        error(err: unknown) {\n          if (!closed) {\n            closed = true;\n            observer.error(err);\n            cleanup();\n          }\n        },\n        complete() {\n          subscriptions.delete(sub);\n          if (!closed && subscriptions.size === 0) {\n            observer.complete();\n            cleanup();\n            closed = true;\n          }\n        },\n      });\n\n      subscriptions.add(sub);\n    };\n\n    subscribeTo(sourceA);\n    subscribeTo(sourceB);\n\n    return cleanup;\n  });\n}\n\n// function share() {\nfunction multicast<T>(source: ZenObservable<T>): ZenObservable<T> {\n  const observers: Set<Observer<T>> = new Set();\n  let subscription: Subscription | null = null;\n\n  function cleanup() {\n    /* istanbul ignore next */\n    subscription?.unsubscribe();\n    subscription = null;\n    observers.clear();\n  }\n\n  return new ZenObservable<T>((observer: Observer<T>) => {\n    observers.add(observer);\n\n    if (subscription === null) {\n      subscription = source.subscribe({\n        next(value: T) {\n          for (const obs of observers) {\n            /* istanbul ignore next */\n            obs.next?.(value);\n          }\n        },\n        error(err: unknown) {\n          for (const obs of observers) {\n            /* istanbul ignore next */\n            obs.error?.(err);\n          }\n          cleanup();\n        },\n        complete() {\n          for (const obs of observers) {\n            /* istanbul ignore next */\n            obs.complete?.();\n          }\n          cleanup();\n        },\n      });\n    }\n\n    // Return unsubscribe function for this observer\n    return () => {\n      observers.delete(observer);\n\n      // If no observers left, unsubscribe from the source\n      if (observers.size === 0 && subscription) {\n        subscription.unsubscribe();\n        subscription = null;\n      }\n    };\n  });\n}\n\nexport { asyncMap, multicast, merge, Unsubscribable };\n"
  },
  {
    "path": "packages/analytics-core/src/utils/omit-undefined.ts",
    "content": "export const omitUndefined = (input: Record<string, string | undefined>) => {\n  const obj: Record<string, string> = {};\n  for (const key in input) {\n    const val = input[key];\n    if (val) {\n      obj[key] = val;\n    }\n  }\n  return obj;\n};\n"
  },
  {
    "path": "packages/analytics-core/src/utils/result-builder.ts",
    "content": "import { Event } from '../types/event/event';\nimport { Result } from '../types/result';\nimport { Status } from '../types/status';\n\nexport const buildResult = (event: Event, code = 0, message: string = Status.Unknown): Result => {\n  return { event, code, message };\n};\n"
  },
  {
    "path": "packages/analytics-core/src/utils/return-wrapper.ts",
    "content": "export interface AmplitudeReturn<T> {\n  promise: Promise<T>;\n}\n\nexport const returnWrapper: {\n  (): AmplitudeReturn<void>;\n  <T>(awaitable: Promise<T>): AmplitudeReturn<T>;\n} = <T>(awaitable?: Promise<T>) => ({\n  promise: awaitable || Promise.resolve(),\n});\n"
  },
  {
    "path": "packages/analytics-core/src/utils/safe-stringify.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\nimport * as safeJsonStringifyModule from 'safe-json-stringify';\n\n// do a simple, typed re-export of \"safe-json-stringify\"\ntype SafeJsonStringifyFn = (data: object, replacer?: any, space?: string | number) => string;\n/* istanbul ignore next */\nconst safeJsonStringify: SafeJsonStringifyFn =\n  (safeJsonStringifyModule as any).default || (safeJsonStringifyModule as any);\n\nexport { safeJsonStringify };\n"
  },
  {
    "path": "packages/analytics-core/src/utils/sampling.ts",
    "content": "export const generateHashCode = function (str: string) {\n  let hash = 0;\n  if (str.length === 0) return hash;\n  for (let i = 0; i < str.length; i++) {\n    const chr = str.charCodeAt(i);\n    hash = (hash << 5) - hash + chr;\n    hash |= 0;\n  }\n  return hash;\n};\n\nexport const isTimestampInSample = function (timestamp: string | number, sampleRate: number) {\n  const hashNumber = generateHashCode(timestamp.toString());\n  const absHash = Math.abs(hashNumber);\n  const absHashMultiply = absHash * 31;\n  const mod = absHashMultiply % 1000000;\n  return mod / 1000000 < sampleRate;\n};\n\n// TODO(xinyi): replace the temp one in diagnostics client after the fix\n// istanbul ignore next\nexport const isTimestampInSampleTemp = function (timestamp: string | number, sampleRate: number) {\n  const hashNumber = generateHashCode(timestamp.toString());\n  const absHash = Math.abs(hashNumber);\n  const absHashMultiply = absHash * 31;\n  const mod = absHashMultiply % 100000;\n  return mod / 100000 < sampleRate;\n};\n"
  },
  {
    "path": "packages/analytics-core/src/utils/status-code.ts",
    "content": "/**\n * Checks if an HTTP status code indicates success (2xx range)\n * @param code - The HTTP status code to check\n * @returns true if the status code is in the 2xx range, false otherwise\n */\nexport function isSuccessStatusCode(code: number): boolean {\n  return code >= 200 && code < 300;\n}\n"
  },
  {
    "path": "packages/analytics-core/src/utils/url-utils.ts",
    "content": "import { ILogger } from '../logger';\n\n/**\n * Checks if a given URL matches any pattern in an allowlist of URLs or regex patterns.\n * @param url - The URL to check\n * @param allowlist - Array of allowed URLs (strings) or regex patterns\n * @returns true if the URL matches any pattern in the allowlist, false otherwise\n */\nexport const isUrlMatchAllowlist = (url: string, allowlist: (string | RegExp)[] | undefined): boolean => {\n  if (!allowlist || !allowlist.length) {\n    return true;\n  }\n  return allowlist.some((allowedUrl) => {\n    if (typeof allowedUrl === 'string') {\n      return url === allowedUrl;\n    }\n    return url.match(allowedUrl);\n  });\n};\n\nexport const getDecodeURI = (locationStr: string, loggerProvider?: ILogger): string => {\n  let decodedLocationStr = locationStr;\n  try {\n    decodedLocationStr = decodeURI(locationStr);\n  } catch (e) {\n    /* istanbul ignore next */\n    loggerProvider?.error('Malformed URI sequence: ', e);\n  }\n\n  return decodedLocationStr;\n};\n"
  },
  {
    "path": "packages/analytics-core/src/utils/uuid.ts",
    "content": "/**\n * Source: [jed's gist's comment]{@link https://gist.github.com/jed/982883?permalink_comment_id=3223002#gistcomment-3223002}.\n * Returns a random v4 UUID of the form xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx,\n * where each x is replaced with a random hexadecimal digit from 0 to f, and\n * y is replaced with a random hexadecimal digit from 8 to b.\n * Used to generate UUIDs for deviceIds.\n * @private\n */\n\nimport { getGlobalScope } from '../global-scope';\n\nconst legacyUUID = function (a?: any): string {\n  return a // if the placeholder was passed, return\n    ? // a random number from 0 to 15\n      (\n        a ^ // unless b is 8,\n        ((Math.random() * // in which case\n          16) >> // a random number from\n          (a / 4))\n      ) // 8 to 11\n        .toString(16) // in hexadecimal\n    : // or otherwise a concatenated string:\n      (\n        String(1e7) + // 10000000 +\n        String(-1e3) + // -1000 +\n        String(-4e3) + // -4000 +\n        String(-8e3) + // -80000000 +\n        String(-1e11)\n      ) // -100000000000,\n        .replace(\n          // replacing\n          /[018]/g, // zeroes, ones, and eights with\n          UUID, // random hex digits\n        );\n};\n\nconst hex: string[] = [...Array(256).keys()].map((index) => index.toString(16).padStart(2, '0'));\n\nexport const UUID = (a?: any): string => {\n  const globalScope = getGlobalScope();\n\n  /* istanbul ignore next */\n  if (!globalScope?.crypto?.getRandomValues) {\n    // Fallback to legacy UUID generation if crypto is not available\n    return legacyUUID(a);\n  }\n\n  const r = globalScope.crypto.getRandomValues(new Uint8Array(16));\n\n  r[6] = (r[6] & 0x0f) | 0x40;\n  r[8] = (r[8] & 0x3f) | 0x80;\n\n  return [...r.entries()].map(([index, int]) => ([4, 6, 8, 10].includes(index) ? `-${hex[int]}` : hex[int])).join('');\n};\n"
  },
  {
    "path": "packages/analytics-core/src/utils/valid-properties.ts",
    "content": "const MAX_PROPERTY_KEYS = 1000;\n\nexport const isValidObject = (properties: { [key: string]: any }): boolean => {\n  if (Object.keys(properties).length > MAX_PROPERTY_KEYS) {\n    return false;\n  }\n  for (const key in properties) {\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n    const value = properties[key];\n    if (!isValidProperties(key, value)) return false;\n  }\n  return true;\n};\n\nexport const isValidProperties = (property: string, value: any): boolean => {\n  if (typeof property !== 'string') return false;\n  if (Array.isArray(value)) {\n    let isValid = true;\n    for (const valueElement of value) {\n      if (Array.isArray(valueElement)) {\n        return false;\n      } else if (typeof valueElement === 'object') {\n        isValid = isValid && isValidObject(valueElement as object);\n      } else if (!['number', 'string'].includes(typeof valueElement)) {\n        return false;\n      }\n      if (!isValid) {\n        return false;\n      }\n    }\n  } else if (value === null || value === undefined) {\n    return false;\n  } else if (typeof value === 'object') {\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n    return isValidObject(value);\n  } else if (!['number', 'string', 'boolean'].includes(typeof value)) {\n    return false;\n  }\n  return true;\n};\n"
  },
  {
    "path": "packages/analytics-core/src/video-analytics/track-video.ts",
    "content": "import {\n  VideoHandler,\n  VideoEvent,\n  EmbeddedVideoPlayer,\n  MuxElement,\n  Vendor,\n  VideoStopReason,\n  TimeUpdateEvent,\n} from './types';\n\nfunction calculatePercentCompleted(currentTime: number, duration: number) {\n  let percentCompleted = 0;\n  if (Number.isFinite(currentTime) && Number.isFinite(duration) && duration > 0) {\n    const rawPercent = (currentTime / duration) * 100;\n    percentCompleted = Math.min(100, Math.max(0, rawPercent));\n  }\n  return percentCompleted;\n}\n\nfunction getVideoData(videoEl: HTMLVideoElement | MuxElement, stopReason?: VideoStopReason) {\n  const currentTime = videoEl.currentTime;\n  const duration = videoEl.duration;\n  return {\n    duration,\n    start_time: currentTime,\n    last_position: currentTime,\n    percent_completed: calculatePercentCompleted(currentTime, duration),\n    ...(stopReason !== undefined ? { stop_reason: stopReason } : {}),\n  };\n}\n\nfunction getMuxMetadata(videoEl: MuxElement) {\n  return {\n    mux_playback_id: videoEl.getAttribute('playback-id'),\n    mux_video_id: videoEl.getAttribute('metadata-video-id'),\n    mux_video_title: videoEl.getAttribute('metadata-video-title'),\n  };\n}\n\n/**\n * Track a standard HTML video element.\n *\n * @param videoEl - The HTML video element to track.\n * @param handlers - The video handlers to call when on video lifecycle events.\n * @returns A function to untrack the video.\n */\nexport function trackHtmlVideo(videoEl: HTMLVideoElement | MuxElement, handlers: VideoHandler, vendor?: Vendor) {\n  const playHandler = () => {\n    const startEvent: VideoEvent = {\n      ...getVideoData(videoEl),\n      ...(vendor === 'mux' ? getMuxMetadata(videoEl) : {}),\n    };\n    handlers.onPlay(startEvent);\n  };\n  videoEl.addEventListener('play', playHandler);\n\n  const pauseHandler = () => {\n    const pauseEvent: VideoEvent = {\n      ...getVideoData(videoEl, 'paused'),\n      ...(vendor === 'mux' ? getMuxMetadata(videoEl) : {}),\n    };\n    handlers.onPause(pauseEvent);\n  };\n  videoEl.addEventListener('pause', pauseHandler);\n\n  const endedHandler = () => {\n    const endedEvent: VideoEvent = {\n      ...getVideoData(videoEl, 'ended'),\n      ...(vendor === 'mux' ? getMuxMetadata(videoEl) : {}),\n    };\n    handlers.onEnded(endedEvent);\n  };\n  videoEl.addEventListener('ended', endedHandler);\n\n  const seekingHandler = () => {\n    const seekingEvent: VideoEvent = {\n      ...getVideoData(videoEl, 'seeking'),\n      ...(vendor === 'mux' ? getMuxMetadata(videoEl) : {}),\n    };\n    handlers.onSeeking(seekingEvent);\n  };\n  videoEl.addEventListener('seeking', seekingHandler);\n\n  const seekedHandler = () => {\n    const seekedEvent: VideoEvent = {\n      ...getVideoData(videoEl),\n      ...(vendor === 'mux' ? getMuxMetadata(videoEl) : {}),\n    };\n    handlers.onSeeked(seekedEvent);\n  };\n  videoEl.addEventListener('seeked', seekedHandler);\n\n  const timeupdateHandler = () => {\n    const media = videoEl as HTMLVideoElement;\n    const timeupdateEvent: TimeUpdateEvent = {\n      position: videoEl.currentTime,\n      isSeeking: !!media.seeking,\n    };\n    handlers.onTimeUpdate(timeupdateEvent);\n  };\n  videoEl.addEventListener('timeupdate', timeupdateHandler);\n\n  return () => {\n    videoEl.removeEventListener('play', playHandler);\n    videoEl.removeEventListener('pause', pauseHandler);\n    videoEl.removeEventListener('ended', endedHandler);\n    videoEl.removeEventListener('seeking', seekingHandler);\n    videoEl.removeEventListener('seeked', seekedHandler);\n    videoEl.removeEventListener('timeupdate', timeupdateHandler);\n  };\n}\n\nasync function getTimeUpdateInfo(player: EmbeddedVideoPlayer) {\n  const currentTime = await new Promise<number>((resolve) => player.getCurrentTime(resolve));\n  return { currentTime };\n}\n\nasync function getIframeMetadata(\n  player: EmbeddedVideoPlayer,\n  elem: HTMLIFrameElement,\n  vendor: Vendor | null,\n  stopReason?: VideoStopReason,\n) {\n  const [duration, currentTime] = await Promise.all([\n    new Promise<number>((resolve) => player.getDuration(resolve)),\n    new Promise<number>((resolve) => player.getCurrentTime(resolve)),\n  ]);\n\n  const vendorMetadata: Record<string, string | null | undefined> = {};\n  if (vendor === 'mux') {\n    let url;\n    try {\n      url = new URL(elem.getAttribute('src') as string);\n      vendorMetadata.mux_video_title = url.searchParams.get('metadata-video-title');\n      vendorMetadata.mux_video_id = url.searchParams.get('metadata-video-id');\n      vendorMetadata.mux_playback_id = url.pathname.split('/').pop();\n    } catch (error) {\n      // invalid or no src url, skip the header metadata\n    }\n  }\n  return {\n    duration,\n    start_time: currentTime,\n    last_position: currentTime,\n    percent_completed: calculatePercentCompleted(currentTime, duration),\n    ...(stopReason !== undefined ? { stop_reason: stopReason } : {}),\n    ...vendorMetadata,\n  };\n}\n\nexport function trackEmbeddedVideo(player: EmbeddedVideoPlayer, handlers: VideoHandler, vendor: Vendor | null = null) {\n  const onUnsubscribe: (() => void)[] = [];\n  const readyHandler = () => {\n    const { elem } = player;\n    let isSeeking = false;\n\n    const playHandler = () => {\n      getIframeMetadata(player, elem, vendor)\n        .then((playerState) => {\n          handlers.onPlay(playerState);\n        })\n        .catch((error) => {\n          handlers.onError(`Error getting iframe metadata from 'play' handler: ${error as string}`);\n        });\n    };\n    player.on('play', playHandler);\n    onUnsubscribe.push(() => player.off('play', playHandler));\n\n    const pauseHandler = () => {\n      getIframeMetadata(player, elem, vendor, 'paused')\n        .then((playerState) => {\n          handlers.onPause(playerState);\n        })\n        .catch((error) => {\n          handlers.onError(`Error getting iframe metadata from 'pause' handler: ${error as string}`);\n        });\n    };\n    player.on('pause', pauseHandler);\n    onUnsubscribe.push(() => player.off('pause', pauseHandler));\n\n    const endedHandler = () => {\n      getIframeMetadata(player, elem, vendor, 'ended')\n        .then((playerState) => {\n          handlers.onEnded(playerState);\n        })\n        .catch((error) => {\n          handlers.onError(`Error getting iframe metadata from 'ended' handler: ${error as string}`);\n        });\n    };\n    player.on('ended', endedHandler);\n    onUnsubscribe.push(() => player.off('ended', endedHandler));\n\n    const seekingHandler = () => {\n      isSeeking = true;\n      getIframeMetadata(player, elem, vendor, 'seeking')\n        .then((playerState) => {\n          handlers.onSeeking(playerState);\n        })\n        .catch((error) => {\n          handlers.onError(`Error getting iframe metadata from 'seeking' handler: ${error as string}`);\n        });\n    };\n    player.on('seeking', seekingHandler);\n    onUnsubscribe.push(() => player.off('seeking', seekingHandler));\n\n    const seekedHandler = () => {\n      isSeeking = false;\n      getIframeMetadata(player, elem, vendor)\n        .then((playerState) => {\n          handlers.onSeeked(playerState);\n        })\n        .catch((error) => {\n          handlers.onError(`Error getting iframe metadata from 'seeked' handler: ${error as string}`);\n        });\n    };\n    player.on('seeked', seekedHandler);\n    onUnsubscribe.push(() => player.off('seeked', seekedHandler));\n\n    const timeupdateHandler = () => {\n      getTimeUpdateInfo(player)\n        .then(({ currentTime }) => {\n          const timeupdateEvent: TimeUpdateEvent = {\n            position: currentTime,\n            isSeeking: isSeeking,\n          };\n          handlers.onTimeUpdate(timeupdateEvent);\n        })\n        .catch((error) => {\n          handlers.onError(`Error getting iframe metadata from 'timeupdate' handler: ${error as string}`);\n        });\n    };\n    player.on('timeupdate', timeupdateHandler);\n    onUnsubscribe.push(() => player.off('timeupdate', timeupdateHandler));\n  };\n  player.on('ready', readyHandler);\n\n  return () => {\n    player.off('ready', readyHandler);\n    onUnsubscribe.forEach((unsubscribe) => unsubscribe());\n  };\n}\n"
  },
  {
    "path": "packages/analytics-core/src/video-analytics/types.ts",
    "content": "export type Vendor = 'mux'; // | 'vimeo' | 'youtube' | 'other'\n\nexport type VideoStopReason = 'paused' | 'ended' | 'seeking';\n\nexport type VideoHandler = {\n  onPlay: (startEvent: VideoEvent) => void;\n  onPause: (pauseEvent: VideoEvent) => void;\n  onEnded: (endedEvent: VideoEvent) => void;\n  onSeeking: (seekingEvent: VideoEvent) => void;\n  onSeeked: (seekedEvent: VideoEvent) => void;\n  onError: (error: string) => void;\n  onTimeUpdate: (timeUpdateEvent: TimeUpdateEvent) => void;\n};\n\nexport type VideoEvent = {\n  duration: number;\n  start_time?: number;\n  playback_id?: string | undefined;\n  video_id?: string | undefined;\n  video_title?: string | undefined;\n  content_id?: string | undefined;\n  content_type?: string | undefined;\n  session_id?: string | undefined;\n  mux_playback_id?: string | undefined | null;\n  mux_video_id?: string | undefined | null;\n  mux_video_title?: string | undefined | null;\n  mux_session_id?: string | undefined | null;\n  last_position: number | undefined | null;\n  percent_completed?: number;\n  stop_reason?: VideoStopReason;\n};\n\nexport type TimeUpdateEvent = {\n  position: number;\n  isSeeking: boolean;\n};\n\ntype EmbeddedVideoPlayer = {\n  getCurrentTime: (cb: (time: number) => void) => void;\n  getDuration: (cb: (duration: number) => void) => void;\n  on: (event: string, callback: () => void) => void;\n  off: (event: string, callback: () => void) => void;\n  elem: HTMLIFrameElement;\n};\n\ntype MuxElement = EventTarget &\n  Element & {\n    seeking: boolean;\n    duration: number;\n    currentTime: number;\n    play?: () => Promise<unknown>;\n    pause?: () => void;\n  };\n\nexport { MuxElement, EmbeddedVideoPlayer };\n"
  },
  {
    "path": "packages/analytics-core/test/analytics-connector.test.ts",
    "content": "import { AnalyticsConnector } from '@amplitude/analytics-connector';\nimport { getAnalyticsConnector, setConnectorDeviceId, setConnectorUserId } from '../src/analytics-connector';\n\ndescribe('analytics-connector', () => {\n  describe('getAnalyticsConnector', () => {\n    test('should return connector instance', () => {\n      const instance = new AnalyticsConnector();\n      const getInstance = jest.spyOn(AnalyticsConnector, 'getInstance').mockReturnValueOnce(instance);\n      expect(getAnalyticsConnector()).toBe(instance);\n      expect(getInstance).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('setConnectorUserId', () => {\n    test('should return connector instance', () => {\n      const commit = jest.fn();\n      const identityEditor = {\n        setUserId: function () {\n          return this;\n        },\n        setDeviceId: function () {\n          return this;\n        },\n        setUserProperties: function () {\n          return this;\n        },\n        updateUserProperties: function () {\n          return this;\n        },\n        setOptOut: function () {\n          return this;\n        },\n        commit,\n      };\n      const instance = new AnalyticsConnector();\n      jest.spyOn(instance.identityStore, 'editIdentity').mockReturnValueOnce(identityEditor);\n      const getInstance = jest.spyOn(AnalyticsConnector, 'getInstance').mockReturnValueOnce(instance);\n      expect(setConnectorUserId('123')).toBe(undefined);\n      expect(getInstance).toHaveBeenCalledTimes(1);\n      expect(commit).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('setConnectorDeviceId', () => {\n    test('should return connector instance', () => {\n      const commit = jest.fn();\n      const identityEditor = {\n        setUserId: function () {\n          return this;\n        },\n        setDeviceId: function () {\n          return this;\n        },\n        setUserProperties: function () {\n          return this;\n        },\n        updateUserProperties: function () {\n          return this;\n        },\n        setOptOut: function () {\n          return this;\n        },\n        commit,\n      };\n      const instance = new AnalyticsConnector();\n      jest.spyOn(instance.identityStore, 'editIdentity').mockReturnValueOnce(identityEditor);\n      const getInstance = jest.spyOn(AnalyticsConnector, 'getInstance').mockReturnValueOnce(instance);\n      expect(setConnectorDeviceId('123')).toBe(undefined);\n      expect(getInstance).toHaveBeenCalledTimes(1);\n      expect(commit).toHaveBeenCalledTimes(1);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/campaign/campaign-parser.test.ts",
    "content": "/**\n * @jest-environment jsdom\n */\n\nimport { BASE_CAMPAIGN } from '../../src/types/constants';\nimport { CampaignParser } from '../../src/campaign/campaign-parser';\nimport * as queryParams from '../../src/query-params';\n\nbeforeAll(() => {\n  Object.defineProperty(window, 'location', {\n    value: {\n      hostname: '',\n      href: '',\n      pathname: '',\n      search: '',\n    },\n    writable: true,\n  });\n  Object.defineProperty(document, 'referrer', {\n    value: '',\n    writable: true,\n  });\n});\n\ndescribe('campaign-parser', () => {\n  describe('parse', () => {\n    test('should return parameters', async () => {\n      const parser = new CampaignParser();\n      const referringDomain = 'https://google.com';\n      const search = '?utm_campaign=utm_campaign&gclid=123';\n      (document.referrer as any) = referringDomain;\n      window.location.search = search;\n\n      const campaign = await parser.parse();\n      expect(campaign).toEqual({\n        ...BASE_CAMPAIGN,\n        utm_campaign: 'utm_campaign',\n        referrer: 'https://google.com',\n        referring_domain: 'google.com',\n        gclid: '123',\n      });\n    });\n  });\n\n  describe('getUtmParam', () => {\n    test('should return utm param from query params', async () => {\n      const parser = new CampaignParser();\n      const getQueryParams = jest.spyOn(queryParams, 'getQueryParams');\n      window.location.search =\n        '?utm_source=utm_source&utm_medium=utm_medium&utm_campaign=utm_campaign&utm_term=utm_term&utm_content=utm_content';\n      const utmParam = parser.getUtmParam();\n      expect(utmParam).toEqual({\n        utm_source: 'utm_source',\n        utm_medium: 'utm_medium',\n        utm_campaign: 'utm_campaign',\n        utm_term: 'utm_term',\n        utm_content: 'utm_content',\n      });\n      expect(getQueryParams).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('getReferrer', () => {\n    afterEach(() => {\n      Object.defineProperty(document, 'referrer', {\n        value: '',\n        writable: true,\n      });\n    });\n\n    test('should return referrer info', () => {\n      Object.defineProperty(document, 'referrer', {\n        value: 'https://amplitude.com',\n        writable: true,\n      });\n      const parser = new CampaignParser();\n      const referrer = parser.getReferrer();\n      expect(referrer).toEqual({\n        referrer: 'https://amplitude.com',\n        referring_domain: 'amplitude.com',\n      });\n    });\n\n    test('should return not referrer info', () => {\n      Object.defineProperty(document, 'referrer', {\n        value: undefined,\n        writable: true,\n      });\n      const parser = new CampaignParser();\n      const referrer = parser.getReferrer();\n      expect(referrer).toEqual({});\n    });\n  });\n\n  describe('getGclid', () => {\n    test('should return gclid data', () => {\n      const parser = new CampaignParser();\n      jest.spyOn(queryParams, 'getQueryParams').mockReturnValueOnce({\n        gclid: 'hello google',\n        fbclid: 'hello fb',\n      });\n      const data = parser.getClickIds();\n      expect(data).toEqual({\n        gclid: 'hello google',\n        fbclid: 'hello fb',\n      });\n    });\n\n    test('should return empty data', () => {\n      const parser = new CampaignParser();\n      jest.spyOn(queryParams, 'getQueryParams').mockReturnValueOnce({});\n      const data = parser.getClickIds();\n      expect(data).toEqual({});\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/config.test.ts",
    "content": "import { LogLevel } from '../src/types/loglevel';\nimport {\n  AMPLITUDE_BATCH_SERVER_URL,\n  AMPLITUDE_SERVER_URL,\n  EU_AMPLITUDE_BATCH_SERVER_URL,\n  EU_AMPLITUDE_SERVER_URL,\n  DEFAULT_INSTANCE_NAME,\n} from '../src/types/constants';\nimport { Config, createServerConfig, getServerUrl, RequestMetadata } from '../src/config';\nimport { Logger } from '../src/logger';\nimport { API_KEY, useDefaultConfig } from './helpers/default';\n\ndescribe('config', () => {\n  test('should create default config', () => {\n    const defaultConfig = useDefaultConfig();\n    const config = new Config({\n      apiKey: API_KEY,\n      storageProvider: defaultConfig.storageProvider,\n      transportProvider: defaultConfig.transportProvider,\n    });\n    expect(config).toEqual({\n      apiKey: 'apiKey',\n      flushIntervalMillis: 10000,\n      flushMaxRetries: 12,\n      flushQueueSize: 200,\n      instanceName: DEFAULT_INSTANCE_NAME,\n      logLevel: LogLevel.Warn,\n      loggerProvider: new Logger(),\n      minIdLength: undefined,\n      offline: false,\n      _optOut: false, // private for `optOut` getter/setter\n      partnerId: undefined,\n      plan: undefined,\n      ingestionMetadata: undefined,\n      serverUrl: 'https://api2.amplitude.com/2/httpapi',\n      serverZone: 'US',\n      storageProvider: defaultConfig.storageProvider,\n      transportProvider: defaultConfig.transportProvider,\n      useBatch: false,\n      requestMetadata: undefined,\n    });\n    expect(config.optOut).toBe(false);\n  });\n\n  test('should overwrite default config', () => {\n    const defaultConfig = useDefaultConfig();\n    const config = new Config({\n      apiKey: API_KEY,\n      logLevel: LogLevel.Verbose,\n      offline: true,\n      optOut: true,\n      plan: { version: '0' },\n      ingestionMetadata: {\n        sourceName: 'ampli',\n        sourceVersion: '2.0.0',\n      },\n      storageProvider: defaultConfig.storageProvider,\n      transportProvider: defaultConfig.transportProvider,\n      useBatch: true,\n    });\n    expect(config).toEqual({\n      apiKey: 'apiKey',\n      flushIntervalMillis: 10000,\n      flushMaxRetries: 12,\n      flushQueueSize: 200,\n      instanceName: DEFAULT_INSTANCE_NAME,\n      logLevel: LogLevel.Verbose,\n      loggerProvider: new Logger(),\n      minIdLength: undefined,\n      offline: true,\n      _optOut: true,\n      plan: {\n        version: '0',\n      },\n      ingestionMetadata: {\n        sourceName: 'ampli',\n        sourceVersion: '2.0.0',\n      },\n      serverUrl: 'https://api2.amplitude.com/batch',\n      serverZone: 'US',\n      storageProvider: defaultConfig.storageProvider,\n      transportProvider: defaultConfig.transportProvider,\n      useBatch: true,\n    });\n  });\n\n  describe('getServerUrl', () => {\n    test('should return eu batch url', () => {\n      expect(getServerUrl('EU', true)).toBe(EU_AMPLITUDE_BATCH_SERVER_URL);\n    });\n    test('should return eu http url', () => {\n      expect(getServerUrl('EU', false)).toBe(EU_AMPLITUDE_SERVER_URL);\n    });\n    test('should return us batch url', () => {\n      expect(getServerUrl('US', true)).toBe(AMPLITUDE_BATCH_SERVER_URL);\n    });\n    test('should return us http url', () => {\n      expect(getServerUrl('US', false)).toBe(AMPLITUDE_SERVER_URL);\n    });\n  });\n\n  describe('createServerConfig', () => {\n    test('should return custom server url', () => {\n      expect(createServerConfig('https://domain.com')).toEqual({\n        serverZone: undefined,\n        serverUrl: 'https://domain.com',\n      });\n    });\n\n    test('should return default', () => {\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore to test invalid values\n      expect(createServerConfig('', '', undefined)).toEqual({\n        serverZone: 'US',\n        serverUrl: AMPLITUDE_SERVER_URL,\n      });\n    });\n  });\n\n  test('should not overwrite flushIntervalMillis=0 with default value', () => {\n    const defaultConfig = useDefaultConfig();\n    const config = new Config({\n      apiKey: API_KEY,\n      storageProvider: defaultConfig.storageProvider,\n      transportProvider: defaultConfig.transportProvider,\n      flushIntervalMillis: 0,\n    });\n    expect(config.flushIntervalMillis).toEqual(0);\n  });\n});\n\ndescribe('RequestMetadata', () => {\n  test('constructor', () => {\n    const requestMetadata = new RequestMetadata();\n    expect(requestMetadata).toEqual({\n      sdk: {\n        metrics: {\n          histogram: {},\n        },\n      },\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/cookie-name.test.ts",
    "content": "import { getCookieName, getOldCookieName } from '../src/cookie-name';\n\ndescribe('cookie-name', () => {\n  const API_KEY = 'apiKey';\n  describe('getCookieName', () => {\n    test('should return cookie name', () => {\n      expect(getCookieName(API_KEY)).toBe('AMP_apiKey');\n    });\n\n    test('should handle apiKey is empty string', () => {\n      expect(getCookieName('')).toBe('AMP');\n    });\n  });\n\n  describe('getOldCookieName', () => {\n    test('should return cookie name', () => {\n      expect(getOldCookieName(API_KEY)).toBe('amp_apiKey');\n    });\n\n    test('should handle apiKey is empty string', () => {\n      expect(getOldCookieName('')).toBe('amp_');\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/core-client.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unsafe-call */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\nimport { Event, IdentifyEvent, SpecialEventType, UserProperties } from '../src/types/event/event';\nimport { Plugin, EnrichmentPlugin } from '../src/types/plugin';\nimport { Status } from '../src/types/status';\nimport { AmplitudeCore, Identify, Revenue } from '../src/index';\nimport { CLIENT_NOT_INITIALIZED, OPT_OUT_MESSAGE } from '../src/types/messages';\nimport { useDefaultConfig } from './helpers/default';\nimport { IdentifyOperation } from '../src/identify';\nimport { UNSET_VALUE } from '../src/types/constants';\nimport type { BrowserConfig } from '../src/types/config/browser-config';\nimport { LogLevel } from '../src/types/loglevel';\n\nasync function runScheduleTimers() {\n  // eslint-disable-next-line @typescript-eslint/unbound-method\n  await new Promise(process.nextTick);\n  jest.runAllTimers();\n}\n\nfunction sleep(ms: number) {\n  return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\ndescribe('core-client', () => {\n  const success = { event: { event_type: 'sample' }, code: 200, message: Status.Success };\n  const badRequest = { event: { event_type: 'sample' }, code: 400, message: Status.Invalid };\n  const continueRequest = { event: { event_type: 'sample' }, code: 100, message: Status.Unknown };\n  const client = new AmplitudeCore();\n  const mockLoggerProvider = {\n    error: jest.fn(),\n    log: jest.fn(),\n    disable: jest.fn(),\n    enable: jest.fn(),\n    warn: jest.fn(),\n    debug: jest.fn(),\n  };\n  const mockConfig: BrowserConfig = {\n    apiKey: 'static_key',\n    flushIntervalMillis: 0,\n    flushMaxRetries: 1,\n    flushQueueSize: 0,\n    logLevel: LogLevel.None,\n    loggerProvider: mockLoggerProvider,\n    optOut: false,\n    deviceId: '1a2b3c',\n    serverUrl: 'url',\n    serverZone: 'US',\n    useBatch: false,\n    sessionId: 123,\n    cookieExpiration: 365,\n    cookieSameSite: 'Lax',\n    cookieSecure: false,\n    cookieUpgrade: true,\n    disableCookies: false,\n    domain: '.amplitude.com',\n    sessionTimeout: 30 * 60 * 1000,\n    trackingOptions: {\n      ipAddress: true,\n      language: true,\n      platform: true,\n    },\n  } as unknown as BrowserConfig;\n\n  beforeEach(() => {\n    jest.useFakeTimers({ doNotFake: ['nextTick'] });\n  });\n\n  afterEach(() => {\n    jest.useRealTimers();\n  });\n\n  describe('init', () => {\n    test('should call init', async () => {\n      expect(client.config).toBeUndefined();\n      await (client as any)._init(useDefaultConfig());\n      expect(client.config).toBeDefined();\n    });\n  });\n\n  describe('track', () => {\n    test('should call track', async () => {\n      const dispatch = jest.spyOn(client, 'dispatch').mockReturnValueOnce(Promise.resolve(success));\n      const eventType = 'eventType';\n      const eventProperties = { event: 'test' };\n      const response = await client.track(eventType, eventProperties).promise;\n      expect(response).toEqual(success);\n      expect(dispatch).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('identify', () => {\n    test('should call identify', async () => {\n      const dispatch = jest.spyOn(client, 'dispatch').mockReturnValueOnce(Promise.resolve(success));\n      const identify: Identify = new Identify();\n      const response = await client.identify(identify, undefined).promise;\n      expect(response).toEqual(success);\n      expect(dispatch).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('groupIdentify', () => {\n    test('should call groupIdentify', async () => {\n      const dispatch = jest.spyOn(client, 'dispatch').mockReturnValueOnce(Promise.resolve(success));\n      const identify = new Identify();\n      const response = await client.groupIdentify('groupType', 'groupName', identify, undefined).promise;\n      expect(response).toEqual(success);\n      expect(dispatch).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('setGroup', () => {\n    test('should call setGroup', async () => {\n      const dispatch = jest.spyOn(client, 'dispatch').mockReturnValueOnce(Promise.resolve(success));\n      const response = await client.setGroup('groupType', 'groupName').promise;\n      expect(response).toEqual(success);\n      expect(dispatch).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('revenue', () => {\n    test('should call revenue', async () => {\n      const dispatch = jest.spyOn(client, 'dispatch').mockReturnValueOnce(Promise.resolve(success));\n      const revenue = new Revenue();\n      const response = await client.revenue(revenue).promise;\n      expect(response).toEqual(success);\n      expect(dispatch).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('add/remove', () => {\n    test('should call add', async () => {\n      const register = jest.spyOn(client.timeline, 'register').mockReturnValueOnce(Promise.resolve());\n      const deregister = jest.spyOn(client.timeline, 'deregister').mockReturnValueOnce(Promise.resolve());\n      const setup = jest.fn();\n      const execute = jest.fn();\n      const plugin: Plugin = {\n        name: 'plugin',\n        type: 'before',\n        setup: setup,\n        execute: execute,\n      };\n\n      // add\n      await client.add(plugin).promise;\n      expect(register).toHaveBeenCalledTimes(1);\n\n      // remove\n      await client.remove('plugin').promise;\n      expect(deregister).toHaveBeenCalledTimes(1);\n    });\n\n    test('should queue add/remove', async () => {\n      const client = new AmplitudeCore();\n      const register = jest.spyOn(client.timeline, 'register');\n      const deregister = jest.spyOn(client.timeline, 'deregister');\n      await client.add({\n        name: 'example',\n        type: 'before',\n        setup: jest.fn(),\n        execute: jest.fn(),\n      }).promise;\n      await client.remove('example').promise;\n      await (client as any)._init(useDefaultConfig());\n      expect(register).toHaveBeenCalledTimes(1);\n      expect(deregister).toHaveBeenCalledTimes(1);\n    });\n\n    test('should queue promises in correct order', async () => {\n      const client = new AmplitudeCore();\n      const register = jest.spyOn(client.timeline, 'register');\n      const setupMockResolve = Promise.resolve();\n      const setupMock = jest.fn().mockResolvedValue(setupMockResolve);\n      await client.add({\n        name: 'firstPlugin',\n        type: 'before',\n        setup: async () => {\n          await sleep(10);\n          setupMock('firstPlugin');\n          return;\n        },\n        execute: jest.fn(),\n      }).promise;\n      client.add({\n        name: 'secondPlugin',\n        type: 'before',\n        setup: async () => {\n          setupMock('secondPlugin');\n          return;\n        },\n        execute: jest.fn(),\n      });\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n      const initPromise = (client as any)._init(useDefaultConfig());\n      await runScheduleTimers();\n      await initPromise;\n      await setupMockResolve;\n      expect(register).toHaveBeenCalledTimes(2);\n      expect(setupMock).toHaveBeenCalledTimes(2);\n      expect(setupMock.mock.calls[0][0]).toEqual('firstPlugin');\n      expect(setupMock.mock.calls[1][0]).toEqual('secondPlugin');\n    });\n\n    test('should queue while promise is being awaited', async () => {\n      const client = new AmplitudeCore();\n      const process = jest.spyOn(client, 'process');\n      const setupMockResolve = Promise.resolve();\n      const setupMock = jest.fn().mockResolvedValue(setupMockResolve);\n      await client.add({\n        name: 'firstPlugin',\n        type: 'before',\n        setup: async () => {\n          await sleep(10);\n          setupMock('firstPlugin');\n          return;\n        },\n        execute: jest.fn(),\n      }).promise;\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n      const initPromise = (client as any)._init(useDefaultConfig());\n      client.track('myEvent');\n      await runScheduleTimers();\n      await initPromise;\n      await setupMockResolve;\n      expect(process).not.toHaveBeenCalled();\n      await client.runQueuedFunctions('dispatchQ');\n      expect(process).toHaveBeenCalled();\n      expect(process).toHaveBeenCalledWith({ event_type: 'myEvent' });\n    });\n\n    test('should flush queue if new functions are queued while awaiting a promise', async () => {\n      const client = new AmplitudeCore();\n      const _setOptOut = jest.spyOn(client, '_setOptOut');\n      const setupMockResolve = Promise.resolve();\n      const setupMock = jest.fn().mockResolvedValue(setupMockResolve);\n      await client.add({\n        name: 'firstPlugin',\n        type: 'before',\n        setup: async () => {\n          await sleep(10);\n          setupMock('firstPlugin');\n          return;\n        },\n        execute: jest.fn(),\n      }).promise;\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n      const initPromise = (client as any)._init(useDefaultConfig());\n      client.setOptOut(true);\n      await runScheduleTimers();\n      await setupMockResolve;\n      expect(_setOptOut).not.toHaveBeenCalled();\n      expect(client.config.optOut).toBe(false);\n      await initPromise;\n      expect(_setOptOut).toHaveBeenCalledWith(true);\n      expect(client.config.optOut).toBe(true);\n    });\n  });\n\n  describe('dispatchWithCallback', () => {\n    test('should handle success', async () => {\n      const push = jest.spyOn(client.timeline, 'push').mockReturnValueOnce(Promise.resolve(success));\n      const event: Event = {\n        event_type: 'event_type',\n      };\n\n      return new Promise<void>((resolve) => {\n        client.dispatchWithCallback(event, (result) => {\n          expect(result).toBe(success);\n          expect(push).toHaveBeenCalledTimes(1);\n          resolve();\n        });\n      });\n    });\n\n    test('should handle undefined config', async () => {\n      const client = new AmplitudeCore();\n      const event: Event = {\n        event_type: 'event_type',\n      };\n\n      return new Promise<void>((resolve) => {\n        client.dispatchWithCallback(event, (result) => {\n          expect(result).toEqual({\n            event,\n            code: 0,\n            message: CLIENT_NOT_INITIALIZED,\n          });\n          resolve();\n        });\n      });\n    });\n  });\n\n  describe('dispatch', () => {\n    test('should handle success', async () => {\n      const push = jest.spyOn(client.timeline, 'push').mockReturnValueOnce(Promise.resolve(success));\n      const event: Event = {\n        event_type: 'event_type',\n      };\n\n      const result = await client.dispatch(event);\n      expect(result).toBe(success);\n      expect(push).toHaveBeenCalledTimes(1);\n    });\n\n    test('should handle non-200 error', async () => {\n      const push = jest.spyOn(client.timeline, 'push').mockReturnValueOnce(Promise.resolve(badRequest));\n      const event: Event = {\n        event_type: 'event_type',\n      };\n\n      const result = await client.dispatch(event);\n      expect(result).toBe(badRequest);\n      expect(push).toHaveBeenCalledTimes(1);\n    });\n\n    test('should handle warning', async () => {\n      const push = jest.spyOn(client.timeline, 'push').mockReturnValueOnce(Promise.resolve(continueRequest));\n      const event: Event = {\n        event_type: 'event_type',\n      };\n\n      const result = await client.dispatch(event);\n      expect(result).toBe(continueRequest);\n      expect(push).toHaveBeenCalledTimes(1);\n    });\n\n    test('should handle unexpected error', async () => {\n      const push = jest.spyOn(client.timeline, 'push').mockImplementation(() => {\n        throw new Error();\n      });\n      const event: Event = {\n        event_type: 'event_type',\n      };\n\n      const result = await client.dispatch(event);\n      expect(result).toEqual({\n        event,\n        message: 'Error',\n        code: 0,\n      });\n      expect(push).toHaveBeenCalledTimes(1);\n    });\n\n    test('should handle opt out', async () => {\n      const push = jest.spyOn(client.timeline, 'push').mockReturnValueOnce(Promise.resolve(success));\n      const event: Event = {\n        event_type: 'event_type',\n      };\n\n      client.setOptOut(true);\n      const result = await client.dispatch(event);\n      expect(result).toEqual({\n        event,\n        message: OPT_OUT_MESSAGE,\n        code: 0,\n      });\n      expect(push).toHaveBeenCalledTimes(0);\n    });\n\n    test('should handle undefined config', async () => {\n      const client = new AmplitudeCore();\n      const push = jest.spyOn(client.timeline, 'push').mockReturnValueOnce(Promise.resolve(success));\n      const event: Event = {\n        event_type: 'event_type',\n      };\n\n      const dispathPromise = client.dispatch(event);\n      await (client as any)._init(useDefaultConfig());\n      await client.runQueuedFunctions('dispatchQ');\n      const result = await dispathPromise;\n      expect(push).toHaveBeenCalledTimes(1);\n      expect(result).toBe(success);\n    });\n  });\n\n  describe('getNoOperationFormattedUserProperties', () => {\n    test('should strip out identify operations $set', () => {\n      const client = new AmplitudeCore();\n      const userProperties: UserProperties = {\n        [IdentifyOperation.SET]: { key1: 'value1' },\n      };\n      const result = client.getOperationAppliedUserProperties(userProperties);\n      expect(result).toEqual({ key1: 'value1' });\n    });\n\n    test('should apply by order', () => {\n      const client = new AmplitudeCore();\n      const userProperties: UserProperties = {\n        [IdentifyOperation.CLEAR_ALL]: UNSET_VALUE,\n        [IdentifyOperation.SET]: { key1: 'value1', key2: 'value2' },\n        [IdentifyOperation.UNSET]: { key1: UNSET_VALUE },\n      };\n      const result = client.getOperationAppliedUserProperties(userProperties);\n      expect(result).toEqual({ key1: 'value1', key2: 'value2' });\n    });\n\n    test('should keep items without identify operations', () => {\n      const client = new AmplitudeCore();\n      const userProperties: UserProperties = { key1: 'value1', key2: 'value2' };\n      const result = client.getOperationAppliedUserProperties(userProperties);\n      expect(result).toEqual(userProperties);\n    });\n\n    test('should handle mixed user properties', () => {\n      const client = new AmplitudeCore();\n      const userProperties: UserProperties = {\n        [IdentifyOperation.CLEAR_ALL]: UNSET_VALUE,\n        [IdentifyOperation.SET]: { key1: 'value1', key2: 'value2' },\n        [IdentifyOperation.UNSET]: { key1: UNSET_VALUE },\n        key3: 'value3',\n      };\n      const result = client.getOperationAppliedUserProperties(userProperties);\n      expect(result).toEqual({\n        key1: 'value1',\n        key2: 'value2',\n        key3: 'value3',\n      });\n    });\n\n    test('should return empty object when user properties is undefined', () => {\n      const client = new AmplitudeCore();\n      expect(client.getOperationAppliedUserProperties(undefined)).toEqual({});\n    });\n\n    test('should use empty object as base when this.userProperties is undefined', () => {\n      const client = new AmplitudeCore();\n      expect(client.userProperties).toBeUndefined();\n      const userProperties: UserProperties = {\n        [IdentifyOperation.SET]: { plan: 'premium' },\n      };\n      const result = client.getOperationAppliedUserProperties(userProperties);\n      expect(result).toEqual({ plan: 'premium' });\n    });\n\n    test('should use this.userProperties as base when defined', () => {\n      const client = new AmplitudeCore();\n      client.userProperties = { existing: 'value' };\n      const userProperties: UserProperties = {\n        [IdentifyOperation.SET]: { plan: 'premium' },\n      };\n      const result = client.getOperationAppliedUserProperties(userProperties);\n      expect(result).toEqual({ existing: 'value', plan: 'premium' });\n    });\n  });\n\n  describe('process', () => {\n    test('should call onIdentifyChanged on identify events', async () => {\n      const client = new AmplitudeCore();\n      client.config = mockConfig;\n      const onIdentityChanged = jest.spyOn(client.timeline, 'onIdentityChanged');\n      jest.spyOn(client.timeline, 'push').mockReturnValueOnce(\n        Promise.resolve({\n          event: { event_type: 'test' },\n          code: 200,\n          message: '',\n        }),\n      );\n\n      const identifyEvent: IdentifyEvent = {\n        user_properties: {},\n        event_type: SpecialEventType.IDENTIFY,\n      };\n      await client.process(identifyEvent);\n\n      expect(onIdentityChanged).toHaveBeenCalledTimes(1);\n      expect(onIdentityChanged).toHaveBeenCalledWith({ userProperties: undefined });\n    });\n  });\n\n  describe('setOptOut', () => {\n    test('should update opt out value', () => {\n      client.setOptOut(true);\n      expect(client.config.optOut).toBe(true);\n    });\n\n    test('should defer update opt out value', async () => {\n      const client = new AmplitudeCore();\n      client.setOptOut(true);\n      await (client as any)._init(useDefaultConfig());\n      expect(client.config.optOut).toBe(true);\n    });\n  });\n\n  describe('flush', () => {\n    test('should call flush', async () => {\n      const flush = jest.spyOn(client.timeline, 'flush').mockReturnValueOnce(Promise.resolve());\n      const setup = jest.fn();\n      const execute = jest.fn();\n      const plugin: Plugin = {\n        name: 'plugin',\n        type: 'destination',\n        setup: setup,\n        execute: execute,\n      };\n\n      // add\n      await client.add(plugin).promise;\n      await client.flush().promise;\n      expect(flush).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('plugin', () => {\n    test('should return plugin by name', async () => {\n      const mockPlugin: Plugin = {\n        name: 'mock-plugin',\n      };\n      client.timeline.plugins.push(mockPlugin);\n\n      const result = client.plugin('mock-plugin');\n\n      expect(result).toBe(mockPlugin);\n\n      // Clean timeline plugins\n      client.timeline.plugins = [];\n    });\n\n    test('should return undefined when name does not exist', async () => {\n      client.config = mockConfig;\n      const result = client.plugin('mock-plugin');\n\n      expect(result).toBe(undefined);\n      expect(mockLoggerProvider.debug).toHaveBeenCalledWith('Cannot find plugin with name mock-plugin');\n    });\n  });\n\n  describe('plugins', () => {\n    class TestPlugin implements EnrichmentPlugin {\n      name = 'test-plugin';\n      setup = jest.fn();\n      execute = jest.fn();\n    }\n\n    test('should return plugins of a specific class', async () => {\n      const testPlugin1 = new TestPlugin();\n      const testPlugin2 = new TestPlugin();\n      const otherPlugin: Plugin = {\n        name: 'other-plugin',\n        setup: jest.fn(),\n        execute: jest.fn(),\n      };\n\n      client.timeline.plugins.push(testPlugin1, otherPlugin, testPlugin2);\n\n      const result = client.plugins(TestPlugin);\n\n      expect(result).toHaveLength(2);\n      expect(result).toContain(testPlugin1);\n      expect(result).toContain(testPlugin2);\n\n      // Clean up\n      client.timeline.plugins = [];\n    });\n\n    test('should return empty array if no plugins of the class exist', () => {\n      const result = client.plugins(TestPlugin);\n      expect(result).toEqual([]);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/diagnostics/diagnostics-client.test.ts",
    "content": "import { ILogger } from '../../src/logger';\nimport {\n  DiagnosticsClient,\n  DIAGNOSTICS_US_SERVER_URL,\n  DIAGNOSTICS_EU_SERVER_URL,\n  FLUSH_INTERVAL_MS,\n  SAVE_INTERVAL_MS,\n  MAX_MEMORY_STORAGE_COUNT,\n} from '../../src/diagnostics/diagnostics-client';\nimport { DiagnosticsStorage } from '../../src/diagnostics/diagnostics-storage';\nimport { getGlobalScope } from '../../src/global-scope';\nimport { isTimestampInSampleTemp } from '../../src/utils/sampling';\n\n// Mock logger\nconst mockLogger: ILogger = {\n  disable: jest.fn(),\n  enable: jest.fn(),\n  log: jest.fn(),\n  warn: jest.fn(),\n  error: jest.fn(),\n  debug: jest.fn(),\n};\nconst apiKey = '1234567890abcdefg';\n\n// Mock the DiagnosticsStorage module\njest.mock('../../src/diagnostics/diagnostics-storage');\njest.mock('../../src/global-scope');\n\n// Mock the sampling utils\njest.mock('../../src/utils/sampling', () => ({\n  isTimestampInSampleTemp: jest.fn(),\n}));\n\ndescribe('DiagnosticsClient', () => {\n  let initializeFlushIntervalSpy: jest.SpyInstance;\n\n  beforeEach(() => {\n    jest.clearAllMocks();\n    jest.clearAllTimers();\n    // Mock initializeFlushInterval globally to prevent async operations\n    initializeFlushIntervalSpy = jest\n      .spyOn(DiagnosticsClient.prototype, 'initializeFlushInterval')\n      .mockImplementation(() => Promise.resolve());\n\n    // Mock isTimestampInSampleTemp to return true\n    (isTimestampInSampleTemp as jest.Mock).mockReturnValue(true);\n\n    // Set up DiagnosticsStorage mock\n    (DiagnosticsStorage.isSupported as jest.Mock).mockReturnValue(true);\n    (DiagnosticsStorage as jest.MockedClass<typeof DiagnosticsStorage>).mockImplementation(\n      () =>\n        ({\n          setTags: jest.fn(),\n          incrementCounters: jest.fn(),\n          setHistogramStats: jest.fn(),\n          addEventRecords: jest.fn(),\n          setLastFlushTimestamp: jest.fn(),\n          getLastFlushTimestamp: jest.fn(),\n          getAllAndClear: jest.fn(),\n        } as unknown as DiagnosticsStorage),\n    );\n  });\n\n  afterEach(() => {\n    jest.resetAllMocks();\n    jest.clearAllTimers();\n    initializeFlushIntervalSpy.mockRestore();\n  });\n\n  describe('constructor', () => {\n    test('should create DiagnosticsClient with required parameters', () => {\n      const incrementSpy = jest.spyOn(DiagnosticsClient.prototype, 'increment').mockImplementation(() => {\n        // Mock to prevent increment from being called\n      });\n\n      const client = new DiagnosticsClient(apiKey, mockLogger);\n\n      expect(client.apiKey).toBe(apiKey);\n      expect(client.logger).toBe(mockLogger);\n      expect(client.serverUrl).toBe(DIAGNOSTICS_US_SERVER_URL);\n      expect(client.storage).toBeDefined();\n      expect(client.inMemoryTags).toEqual({});\n      expect(client.inMemoryCounters).toEqual({});\n      expect(client.inMemoryHistograms).toEqual({});\n      expect(client.inMemoryEvents).toEqual([]);\n      expect(client.saveTimer).toBeNull();\n      expect(client.flushTimer).toBeNull();\n      expect(client.shouldTrack).toBe(true);\n      expect(initializeFlushIntervalSpy).toHaveBeenCalledTimes(1);\n      expect(incrementSpy).toHaveBeenCalledWith('sdk.diagnostics.sampled.in.and.enabled');\n\n      incrementSpy.mockRestore();\n    });\n\n    test('should create DiagnosticsClient with EU server zone', () => {\n      const client = new DiagnosticsClient(apiKey, mockLogger, 'EU');\n\n      expect(client.serverUrl).toBe(DIAGNOSTICS_EU_SERVER_URL);\n    });\n\n    test('should debug log when storage is not supported', () => {\n      (DiagnosticsStorage.isSupported as jest.Mock).mockReturnValue(false);\n      const client = new DiagnosticsClient(apiKey, mockLogger);\n\n      expect(client.storage).toBeUndefined();\n      expect(mockLogger['debug']).toHaveBeenCalledWith('DiagnosticsClient: IndexedDB is not supported');\n    });\n\n    test('should set shouldTrack to false if not in sample', () => {\n      (isTimestampInSampleTemp as jest.Mock).mockReturnValue(false);\n      const client = new DiagnosticsClient(apiKey, mockLogger);\n      expect(client.shouldTrack).toBe(false);\n    });\n\n    test('should set shouldTrack to false if not enabled', () => {\n      const client = new DiagnosticsClient(apiKey, mockLogger, 'US', { enabled: false });\n      expect(client.shouldTrack).toBe(false);\n    });\n\n    test.each([\n      { isSampled: true, enabled: true, expectedCount: 1, description: 'when sampled and enabled' },\n      { isSampled: true, enabled: false, expectedCount: undefined, description: 'when sampled but disabled' },\n      { isSampled: false, enabled: true, expectedCount: undefined, description: 'when not sampled' },\n    ])('should track sdk.diagnostics.sampled.in.and.enabled $description', ({ isSampled, enabled, expectedCount }) => {\n      (isTimestampInSampleTemp as jest.Mock).mockReturnValue(isSampled);\n\n      const client = new DiagnosticsClient(apiKey, mockLogger, 'US', { enabled });\n\n      expect(client.inMemoryCounters['sdk.diagnostics.sampled.in.and.enabled']).toBe(expectedCount);\n    });\n  });\n\n  describe('initializeFlushInterval', () => {\n    let mockStorage: {\n      getLastFlushTimestamp: jest.MockedFunction<() => Promise<number | undefined>>;\n      setLastFlushTimestamp: jest.MockedFunction<(timestamp: number) => Promise<void>>;\n    };\n    let client: DiagnosticsClient;\n    let flushSpy: jest.SpyInstance;\n\n    beforeEach(() => {\n      // Restore the real initializeFlushInterval method for this describe block\n      initializeFlushIntervalSpy.mockRestore();\n\n      mockStorage = {\n        getLastFlushTimestamp: jest.fn(),\n        setLastFlushTimestamp: jest.fn(),\n      };\n      flushSpy = jest.spyOn(DiagnosticsClient.prototype, '_flush').mockResolvedValue();\n    });\n\n    afterEach(() => {\n      // Clean up timer if it exists\n      if (client?.flushTimer) {\n        clearTimeout(client.flushTimer);\n      }\n      flushSpy.mockRestore();\n\n      // Re-establish the mock for other describe blocks\n      initializeFlushIntervalSpy = jest\n        .spyOn(DiagnosticsClient.prototype, 'initializeFlushInterval')\n        .mockImplementation(() => Promise.resolve());\n    });\n\n    const createClientWithMockStorage = (timestampValue: number | undefined) => {\n      mockStorage.getLastFlushTimestamp.mockResolvedValue(timestampValue);\n\n      // Mock the storage support check to prevent constructor from calling initializeFlushInterval\n      const isStorageSupportedSpy = jest.spyOn(DiagnosticsStorage, 'isSupported').mockReturnValue(false);\n\n      client = new DiagnosticsClient(apiKey, mockLogger);\n\n      // Now set the mock storage after construction\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n      client.storage = mockStorage as any;\n\n      // Restore the storage support check\n      isStorageSupportedSpy.mockRestore();\n\n      return client;\n    };\n\n    test('should early return if storage is not supported', async () => {\n      createClientWithMockStorage(undefined);\n      client.storage = undefined;\n\n      await client.initializeFlushInterval();\n\n      expect(mockStorage.getLastFlushTimestamp).not.toHaveBeenCalled();\n    });\n\n    test('should set timestamp and timer for new client', async () => {\n      jest.useFakeTimers();\n      createClientWithMockStorage(undefined);\n\n      await client.initializeFlushInterval();\n\n      expect(mockStorage.getLastFlushTimestamp).toHaveBeenCalled();\n      expect(mockStorage.setLastFlushTimestamp).toHaveBeenCalledWith(expect.any(Number));\n      expect(flushSpy).not.toHaveBeenCalled();\n      expect(client.flushTimer).not.toBeNull();\n\n      jest.useRealTimers();\n    });\n\n    test('should flush immediately if 5 minutes have passed since last flush', async () => {\n      const oldTimestamp = Date.now() - 6 * 60 * 1000; // 6 minutes ago\n      createClientWithMockStorage(oldTimestamp);\n\n      await client.initializeFlushInterval();\n\n      expect(mockStorage.getLastFlushTimestamp).toHaveBeenCalled();\n      expect(flushSpy).toHaveBeenCalled();\n    });\n\n    test('should set timer for remaining time if less than 5 minutes have passed since last flush', async () => {\n      jest.useFakeTimers();\n      const pastTime = 2 * 60 * 1000;\n      const recentTimestamp = Date.now() - pastTime; // 2 minutes ago\n      createClientWithMockStorage(recentTimestamp);\n\n      await client.initializeFlushInterval();\n\n      expect(mockStorage.getLastFlushTimestamp).toHaveBeenCalled();\n      expect(flushSpy).not.toHaveBeenCalled();\n      expect(client.flushTimer).not.toBeNull();\n      jest.advanceTimersByTime(FLUSH_INTERVAL_MS - pastTime);\n      expect(flushSpy).toHaveBeenCalled();\n\n      jest.useRealTimers();\n    });\n\n    test('should handle flush promise rejection and clear timer', async () => {\n      jest.useFakeTimers();\n      const pastTime = 2 * 60 * 1000;\n      const recentTimestamp = Date.now() - pastTime; // 2 minutes ago\n      const flushError = new Error('Flush operation failed');\n\n      createClientWithMockStorage(recentTimestamp);\n      flushSpy.mockRejectedValue(flushError);\n\n      await client.initializeFlushInterval();\n\n      expect(mockStorage.getLastFlushTimestamp).toHaveBeenCalled();\n      expect(flushSpy).not.toHaveBeenCalled(); // Should not flush immediately\n      expect(client.flushTimer).not.toBeNull(); // Timer should be set\n\n      // Wait for all promises to resolve\n      await jest.runAllTimersAsync();\n\n      expect(flushSpy).toHaveBeenCalled();\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith('DiagnosticsClient: Failed to flush', flushError);\n\n      // Timer should be cleared even on error\n      expect(client.flushTimer).toBeNull();\n\n      jest.useRealTimers();\n    });\n  });\n\n  describe('setters', () => {\n    let client: DiagnosticsClient;\n    let startSaveTimerIfNeededSpy: jest.SpyInstance;\n\n    beforeEach(() => {\n      // Mock increment temporarily to prevent diagnostic counter during construction\n      const incrementSpy = jest.spyOn(DiagnosticsClient.prototype, 'increment').mockImplementation(() => {\n        // Mock implementation\n      });\n\n      client = new DiagnosticsClient(apiKey, mockLogger);\n\n      // Restore increment for the actual tests\n      incrementSpy.mockRestore();\n\n      startSaveTimerIfNeededSpy = jest.spyOn(client, 'startTimersIfNeeded').mockImplementation(() => {\n        // Mock implementation\n      });\n    });\n\n    afterEach(() => {\n      // Clear any timers that might have been set\n      if (client?.saveTimer) {\n        clearTimeout(client.saveTimer);\n        client.saveTimer = null;\n      }\n      if (client?.flushTimer) {\n        clearTimeout(client.flushTimer);\n        client.flushTimer = null;\n      }\n      startSaveTimerIfNeededSpy.mockRestore();\n      jest.clearAllTimers();\n    });\n\n    test('setTag', () => {\n      const key = 'library';\n      const value = 'amplitude-typescript/2.0.0';\n\n      client.setTag(key, value);\n\n      expect(client.inMemoryTags).toEqual({ [key]: value });\n      expect(startSaveTimerIfNeededSpy).toHaveBeenCalled();\n    });\n\n    test('setTag should early return if storage is not supported', () => {\n      (DiagnosticsStorage.isSupported as jest.Mock).mockReturnValue(false);\n      const client = new DiagnosticsClient(apiKey, mockLogger);\n\n      client.setTag('library', 'amplitude-typescript/2.0.0');\n\n      expect(client.inMemoryTags).toEqual({});\n    });\n\n    test('setTag should early return if exceeding memory limit', () => {\n      for (let i = 0; i < MAX_MEMORY_STORAGE_COUNT; i++) {\n        client.inMemoryTags[`tag${i}`] = `value${i}`;\n      }\n\n      expect(Object.keys(client.inMemoryTags).length).toBe(MAX_MEMORY_STORAGE_COUNT);\n\n      client.setTag('library', 'amplitude-typescript/2.0.0');\n\n      expect(Object.keys(client.inMemoryTags).length).toBe(MAX_MEMORY_STORAGE_COUNT);\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith('DiagnosticsClient: Early return setTags as reaching memory limit');\n    });\n\n    test('setTag should early return if shouldTrack is false', () => {\n      client.shouldTrack = false;\n      client.setTag('library', 'amplitude-typescript/2.0.0');\n      expect(client.inMemoryTags).toEqual({});\n    });\n\n    test('increment', () => {\n      const key = 'analytics.fileNotFound';\n      const size = 3;\n\n      client.increment(key, size);\n\n      expect(client.inMemoryCounters).toEqual({ [key]: size });\n      expect(startSaveTimerIfNeededSpy).toHaveBeenCalled();\n    });\n\n    test('increment with default size', () => {\n      const key = 'analytics.fileNotFound';\n\n      client.increment(key);\n\n      expect(client.inMemoryCounters).toEqual({ [key]: 1 });\n      expect(startSaveTimerIfNeededSpy).toHaveBeenCalled();\n    });\n\n    test('increment should early return if storage is not supported', () => {\n      (DiagnosticsStorage.isSupported as jest.Mock).mockReturnValue(false);\n      const client = new DiagnosticsClient(apiKey, mockLogger);\n\n      client.increment('analytics.fileNotFound', 5);\n\n      expect(client.inMemoryCounters).toEqual({});\n    });\n\n    test('increment should early return if exceeding memory limit', () => {\n      for (let i = 0; i < MAX_MEMORY_STORAGE_COUNT; i++) {\n        client.inMemoryCounters[`counter${i}`] = i;\n      }\n\n      expect(Object.keys(client.inMemoryCounters).length).toBe(MAX_MEMORY_STORAGE_COUNT);\n\n      client.increment('analytics.fileNotFound', 5);\n\n      expect(Object.keys(client.inMemoryCounters).length).toBe(MAX_MEMORY_STORAGE_COUNT);\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith(\n        'DiagnosticsClient: Early return increment as reaching memory limit',\n      );\n    });\n\n    test('increment should early return if shouldTrack is false', () => {\n      client.shouldTrack = false;\n      client.increment('analytics.fileNotFound', 5);\n      expect(client.inMemoryCounters).toEqual({});\n    });\n\n    test('recordHistogram', () => {\n      client.recordHistogram('sr.time', 50);\n      client.recordHistogram('sr.time', 100);\n      client.recordHistogram('sr.time', 150);\n      client.recordHistogram('sr.time', 100);\n\n      expect(client.inMemoryHistograms).toEqual({\n        'sr.time': {\n          count: 4,\n          min: 50,\n          max: 150,\n          sum: 400,\n        },\n      });\n      expect(startSaveTimerIfNeededSpy).toHaveBeenCalled();\n    });\n\n    test('recordHistogram should early return if storage is not supported', () => {\n      (DiagnosticsStorage.isSupported as jest.Mock).mockReturnValue(false);\n      const client = new DiagnosticsClient(apiKey, mockLogger);\n\n      client.recordHistogram('sr.time', 50);\n\n      expect(client.inMemoryHistograms).toEqual({});\n    });\n\n    test('recordHistogram should early return if exceeding memory limit', () => {\n      for (let i = 0; i < MAX_MEMORY_STORAGE_COUNT; i++) {\n        client.inMemoryHistograms[`histogram${i}`] = {\n          count: 1,\n          min: i,\n          max: i,\n          sum: i,\n        };\n      }\n\n      expect(Object.keys(client.inMemoryHistograms).length).toBe(MAX_MEMORY_STORAGE_COUNT);\n\n      client.recordHistogram('sr.time', 50);\n\n      expect(Object.keys(client.inMemoryHistograms).length).toBe(MAX_MEMORY_STORAGE_COUNT);\n      expect(client.inMemoryHistograms['sr.time']).toBeUndefined();\n    });\n\n    test('recordHistogram should early return if shouldTrack is false', () => {\n      client.shouldTrack = false;\n      client.recordHistogram('sr.time', 50);\n      expect(client.inMemoryHistograms).toEqual({});\n    });\n\n    test('recordEvent', () => {\n      const eventName = 'error';\n      const properties = { stack_trace: 'test stack trace' };\n\n      client.recordEvent(eventName, properties);\n\n      expect(client.inMemoryEvents).toHaveLength(1);\n      expect(client.inMemoryEvents[0]).toEqual({\n        event_name: eventName,\n        time: expect.any(Number) as number,\n        event_properties: properties,\n      });\n      expect(startSaveTimerIfNeededSpy).toHaveBeenCalled();\n    });\n\n    test('recordEvent should early return if storage is not supported', () => {\n      (DiagnosticsStorage.isSupported as jest.Mock).mockReturnValue(false);\n      const client = new DiagnosticsClient(apiKey, mockLogger);\n\n      client.recordEvent('error', { stack_trace: 'test stack trace' });\n\n      expect(client.inMemoryEvents).toEqual([]);\n    });\n\n    test('recordEvent should early return if exceeding memory limit', () => {\n      for (let i = 0; i < 10; i++) {\n        client.inMemoryEvents.push({\n          event_name: `event${i}`,\n          time: Date.now(),\n          event_properties: { index: i },\n        });\n      }\n\n      expect(client.inMemoryEvents).toHaveLength(10);\n\n      client.recordEvent('error', { stack_trace: 'test stack trace' });\n\n      expect(client.inMemoryEvents).toHaveLength(10);\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith(\n        'DiagnosticsClient: Early return recordEvent as reaching memory limit',\n      );\n    });\n\n    test('recordEvent should early return if shouldTrack is false', () => {\n      client.shouldTrack = false;\n      client.recordEvent('error', { stack_trace: 'test stack trace' });\n      expect(client.inMemoryEvents).toEqual([]);\n    });\n  });\n\n  describe('startSaveTimerIfNeeded', () => {\n    let client: DiagnosticsClient;\n    let saveAllDataToStorageSpy: jest.SpyInstance;\n    let flushSpy: jest.SpyInstance;\n\n    beforeEach(() => {\n      jest.useFakeTimers();\n      client = new DiagnosticsClient(apiKey, mockLogger);\n      saveAllDataToStorageSpy = jest.spyOn(client, 'saveAllDataToStorage').mockResolvedValue();\n      flushSpy = jest.spyOn(client, '_flush').mockResolvedValue();\n    });\n\n    afterEach(() => {\n      jest.clearAllTimers();\n      jest.useRealTimers();\n      saveAllDataToStorageSpy.mockRestore();\n      flushSpy.mockRestore();\n    });\n\n    test('should set saveTimer if it is not set', () => {\n      client.saveTimer = null;\n\n      client.startTimersIfNeeded();\n\n      expect(client.saveTimer).not.toBeNull();\n      jest.advanceTimersByTime(SAVE_INTERVAL_MS);\n      expect(saveAllDataToStorageSpy).toHaveBeenCalled();\n    });\n\n    test('should not set saveTimer if it is already set', () => {\n      client.saveTimer = setTimeout(() => {\n        // Mock timer callback\n      }, 500);\n      const originalTimer = client.saveTimer;\n\n      client.startTimersIfNeeded();\n\n      expect(client.saveTimer).toBe(originalTimer);\n    });\n\n    test('should set flushTimer if it is not set', () => {\n      client.flushTimer = null;\n\n      client.startTimersIfNeeded();\n\n      expect(client.flushTimer).not.toBeNull();\n      jest.advanceTimersByTime(FLUSH_INTERVAL_MS);\n      expect(flushSpy).toHaveBeenCalled();\n    });\n\n    test('should not set flushTimer if it is already set', () => {\n      client.flushTimer = setTimeout(() => {\n        // Mock timer callback\n      }, FLUSH_INTERVAL_MS);\n      const originalTimer = client.flushTimer;\n\n      client.startTimersIfNeeded();\n\n      expect(client.flushTimer).toBe(originalTimer);\n    });\n\n    test('should handle saveAllDataToStorage errors in timer callback and clear timer', async () => {\n      const storageError = new Error('Storage failed');\n      saveAllDataToStorageSpy.mockRejectedValue(storageError);\n      client.saveTimer = null;\n\n      client.startTimersIfNeeded();\n\n      expect(client.saveTimer).not.toBeNull();\n\n      // Wait for all promises to resolve\n      await jest.runAllTimersAsync();\n\n      expect(saveAllDataToStorageSpy).toHaveBeenCalled();\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith(\n        'DiagnosticsClient: Failed to save all data to storage',\n        storageError,\n      );\n\n      // Timer should be cleared even on error\n      expect(client.saveTimer).toBeNull();\n    });\n\n    test('should handle _flush errors in timer callback and clear timer', async () => {\n      const flushError = new Error('Flush failed');\n      flushSpy.mockRejectedValue(flushError);\n      client.flushTimer = null;\n\n      client.startTimersIfNeeded();\n\n      expect(client.flushTimer).not.toBeNull();\n\n      // Wait for all promises to resolve\n      await jest.runAllTimersAsync();\n\n      expect(flushSpy).toHaveBeenCalled();\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith('DiagnosticsClient: Failed to flush', flushError);\n\n      // Timer should be cleared even on error\n      expect(client.flushTimer).toBeNull();\n    });\n  });\n\n  describe('saveAllDataToStorage', () => {\n    let client: DiagnosticsClient;\n    let mockStorage: {\n      setTags: jest.MockedFunction<(tags: Record<string, string>) => Promise<void>>;\n      incrementCounters: jest.MockedFunction<(counters: Record<string, number>) => Promise<void>>;\n      setHistogramStats: jest.MockedFunction<(histograms: Record<string, any>) => Promise<void>>;\n      addEventRecords: jest.MockedFunction<(events: any[]) => Promise<void>>;\n    };\n\n    // Test data constants\n    const TEST_TAGS = { library: 'amplitude-typescript/2.0.0', platform: 'web' };\n    const TEST_COUNTERS = { 'analytics.error': 5, 'network.retry': 3 };\n    const TEST_HISTOGRAMS = { 'sr.time': { count: 2, min: 50, max: 100, sum: 150 } };\n    const TEST_EVENTS = [{ event_name: 'error', time: 123456789, event_properties: { type: 'network' } }];\n\n    beforeEach(() => {\n      // Mock increment temporarily to prevent diagnostic counter and timers during construction\n      const incrementSpy = jest.spyOn(DiagnosticsClient.prototype, 'increment').mockImplementation(() => {\n        // Mock implementation\n      });\n\n      client = new DiagnosticsClient(apiKey, mockLogger);\n\n      // Restore increment\n      incrementSpy.mockRestore();\n\n      mockStorage = {\n        setTags: jest.fn().mockResolvedValue(undefined),\n        incrementCounters: jest.fn().mockResolvedValue(undefined),\n        setHistogramStats: jest.fn().mockResolvedValue(undefined),\n        addEventRecords: jest.fn().mockResolvedValue(undefined),\n      };\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n      client.storage = mockStorage as any;\n    });\n\n    afterEach(() => {\n      jest.clearAllMocks();\n    });\n\n    test('should early return if storage is not supported', async () => {\n      (DiagnosticsStorage.isSupported as jest.Mock).mockReturnValue(false);\n      const client = new DiagnosticsClient(apiKey, mockLogger);\n\n      await client.saveAllDataToStorage();\n\n      expect(mockStorage.setTags).not.toHaveBeenCalled();\n    });\n\n    test('should save all in-memory data to storage and clear memory', async () => {\n      // Set up in-memory data\n      client.inMemoryTags = { ...TEST_TAGS };\n      client.inMemoryCounters = { ...TEST_COUNTERS };\n      client.inMemoryHistograms = { ...TEST_HISTOGRAMS };\n      client.inMemoryEvents = [...TEST_EVENTS];\n\n      await client.saveAllDataToStorage();\n\n      // Verify storage methods were called with correct data\n      expect(mockStorage.setTags).toHaveBeenCalledWith(TEST_TAGS);\n      expect(mockStorage.incrementCounters).toHaveBeenCalledWith(TEST_COUNTERS);\n      expect(mockStorage.setHistogramStats).toHaveBeenCalledWith(TEST_HISTOGRAMS);\n      expect(mockStorage.addEventRecords).toHaveBeenCalledWith(TEST_EVENTS);\n\n      // Verify in-memory data is cleared\n      expect(client.inMemoryTags).toEqual({});\n      expect(client.inMemoryCounters).toEqual({});\n      expect(client.inMemoryHistograms).toEqual({});\n      expect(client.inMemoryEvents).toEqual([]);\n\n      // Verify saveTimer is cleared\n      expect(client.saveTimer).toBeNull();\n    });\n  });\n\n  describe('_flush', () => {\n    let client: DiagnosticsClient;\n    let mockStorage: {\n      getAllAndClear: jest.MockedFunction<\n        () => Promise<{\n          tags: Array<{ key: string; value: string }>;\n          counters: Array<{ key: string; value: number }>;\n          histogramStats: Array<{ key: string; count: number; min: number; max: number; sum: number }>;\n          events: Array<{ event_name: string; time: number; event_properties: any }>;\n        }>\n      >;\n      setLastFlushTimestamp: jest.MockedFunction<(timestamp: number) => Promise<void>>;\n    };\n    let fetchSpy: jest.SpyInstance;\n\n    // Test data constants for storage records\n    const MOCK_TAG_RECORDS = [\n      { key: 'library', value: 'amplitude-typescript/2.0.0' },\n      { key: 'platform', value: 'web' },\n    ];\n    const MOCK_COUNTER_RECORDS = [\n      { key: 'analytics.error', value: 5 },\n      { key: 'network.retry', value: 3 },\n    ];\n    const MOCK_HISTOGRAM_RECORDS = [{ key: 'sr.time', count: 2, min: 50, max: 100, sum: 150 }];\n    const MOCK_EVENT_RECORDS = [{ event_name: 'error', time: 123456789, event_properties: { type: 'network' } }];\n\n    // Expected transformed data\n    const EXPECTED_TAGS = { library: 'amplitude-typescript/2.0.0', platform: 'web' };\n    const EXPECTED_COUNTERS = { 'analytics.error': 5, 'network.retry': 3 };\n    const EXPECTED_HISTOGRAMS = { 'sr.time': { count: 2, min: 50, max: 100, avg: 75 } };\n    // const EXPECTED_EVENTS = [{ event_name: 'error', time: 123456789, event_properties: { type: 'network' } }];\n\n    beforeEach(() => {\n      client = new DiagnosticsClient(apiKey, mockLogger);\n      mockStorage = {\n        getAllAndClear: jest.fn().mockResolvedValue({\n          tags: MOCK_TAG_RECORDS,\n          counters: MOCK_COUNTER_RECORDS,\n          histogramStats: MOCK_HISTOGRAM_RECORDS,\n          events: MOCK_EVENT_RECORDS,\n        }),\n        setLastFlushTimestamp: jest.fn().mockResolvedValue(undefined),\n      };\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n      client.storage = mockStorage as any;\n      fetchSpy = jest.spyOn(client, 'fetch').mockResolvedValue();\n    });\n\n    afterEach(() => {\n      jest.clearAllMocks();\n      fetchSpy.mockRestore();\n    });\n\n    test('should early return if storage is not supported', async () => {\n      (DiagnosticsStorage.isSupported as jest.Mock).mockReturnValue(false);\n      const client = new DiagnosticsClient(apiKey, mockLogger);\n\n      await client._flush();\n\n      expect(mockStorage.getAllAndClear).not.toHaveBeenCalled();\n    });\n\n    test('should call necessary APIs', async () => {\n      const saveAllDataToStorageSpy = jest.spyOn(client, 'saveAllDataToStorage').mockResolvedValue();\n      client.flushTimer = setTimeout(() => {\n        // Mock timer callback\n      }, 1000);\n\n      await client._flush();\n\n      expect(saveAllDataToStorageSpy).toHaveBeenCalled();\n      expect(mockStorage.getAllAndClear).toHaveBeenCalled();\n      expect(mockStorage.setLastFlushTimestamp).toHaveBeenCalled();\n      // Also test histogram calculation\n      expect(fetchSpy).toHaveBeenCalledWith({\n        tags: EXPECTED_TAGS,\n        histogram: EXPECTED_HISTOGRAMS,\n        counters: EXPECTED_COUNTERS,\n        events: [{ event_name: 'error', time: 123456789, event_properties: { type: 'network' } }],\n      });\n    });\n\n    test('should early return if all data collections are empty', async () => {\n      // Mock storage to return empty data\n      const emptyMockStorage = {\n        getAllAndClear: jest.fn().mockResolvedValue({\n          tags: [],\n          counters: [],\n          histogramStats: [],\n          events: [],\n        }),\n        setLastFlushTimestamp: jest.fn().mockResolvedValue(undefined),\n        setTags: jest.fn().mockResolvedValue(undefined),\n        incrementCounters: jest.fn().mockResolvedValue(undefined),\n        setHistogramStats: jest.fn().mockResolvedValue(undefined),\n        addEventRecords: jest.fn().mockResolvedValue(undefined),\n      };\n\n      // Replace the storage with empty mock\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n      client.storage = emptyMockStorage as any;\n\n      // Call _flush\n      await client._flush();\n\n      // Verify that fetch was NOT called since all collections are empty\n      expect(fetchSpy).not.toHaveBeenCalled();\n\n      // Verify that storage methods were still called\n      expect(emptyMockStorage.getAllAndClear).toHaveBeenCalled();\n      expect(emptyMockStorage.setLastFlushTimestamp).toHaveBeenCalled();\n    });\n  });\n\n  describe('fetch', () => {\n    let client: DiagnosticsClient;\n    let mockFetch: jest.SpyInstance;\n\n    // Test payload constant\n    const TEST_PAYLOAD = {\n      tags: { library: 'amplitude-typescript/2.0.0', platform: 'web' },\n      histogram: { 'sr.time': { count: 2, min: 50, max: 100, avg: 75 } },\n      counters: { 'analytics.error': 5, 'network.retry': 3 },\n      events: [{ event_name: 'error', time: 123456789, event_properties: { type: 'network' } }],\n    };\n\n    beforeEach(() => {\n      client = new DiagnosticsClient(apiKey, mockLogger);\n      mockFetch = jest.spyOn(global, 'fetch');\n      (getGlobalScope as jest.Mock).mockReturnValue(globalThis);\n    });\n\n    afterEach(() => {\n      mockFetch.mockRestore();\n      jest.clearAllMocks();\n    });\n\n    test('should early return if fetch is not supported', async () => {\n      (getGlobalScope as jest.Mock).mockReturnValue(undefined);\n      const client = new DiagnosticsClient(apiKey, mockLogger);\n\n      await client.fetch(TEST_PAYLOAD);\n\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith(\n        'DiagnosticsClient: Failed to send diagnostics data. ',\n        expect.any(Error),\n      );\n    });\n\n    test('should send POST request with correct parameters', async () => {\n      const mockResponse = {\n        ok: true,\n        status: 200,\n        statusText: 'OK',\n      };\n      mockFetch.mockResolvedValue(mockResponse as Response);\n\n      await client.fetch(TEST_PAYLOAD);\n\n      expect(mockFetch).toHaveBeenCalledWith(client.serverUrl, {\n        method: 'POST',\n        headers: {\n          'X-ApiKey': apiKey,\n          'Content-Type': 'application/json',\n        },\n        body: JSON.stringify(TEST_PAYLOAD),\n      });\n    });\n\n    test('should log success message on successful response', async () => {\n      const mockResponse = {\n        ok: true,\n        status: 200,\n        statusText: 'OK',\n      };\n      mockFetch.mockResolvedValue(mockResponse as Response);\n\n      await client.fetch(TEST_PAYLOAD);\n\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith('DiagnosticsClient: Successfully sent diagnostics data');\n    });\n\n    test('should log error message on HTTP error response', async () => {\n      const mockResponse = {\n        ok: false,\n        status: 400,\n        statusText: 'Bad Request',\n      };\n      mockFetch.mockResolvedValue(mockResponse as Response);\n\n      await client.fetch(TEST_PAYLOAD);\n\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith('DiagnosticsClient: Failed to send diagnostics data.');\n    });\n\n    test('should log error message on fetch exception', async () => {\n      const error = new Error('error');\n      mockFetch.mockRejectedValue(error);\n\n      await client.fetch(TEST_PAYLOAD);\n\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith('DiagnosticsClient: Failed to send diagnostics data. ', error);\n    });\n\n    test('should use US server URL by default', async () => {\n      const usClient = new DiagnosticsClient(apiKey, mockLogger);\n      const mockResponse = { ok: true, status: 200, statusText: 'OK' };\n      mockFetch.mockResolvedValue(mockResponse as Response);\n\n      await usClient.fetch(TEST_PAYLOAD);\n\n      expect(mockFetch).toHaveBeenCalledWith(DIAGNOSTICS_US_SERVER_URL, expect.any(Object));\n    });\n\n    test('should use EU server URL when specified', async () => {\n      const euClient = new DiagnosticsClient(apiKey, mockLogger, 'EU');\n      const mockResponse = { ok: true, status: 200, statusText: 'OK' };\n      mockFetch.mockResolvedValue(mockResponse as Response);\n\n      await euClient.fetch(TEST_PAYLOAD);\n\n      expect(mockFetch).toHaveBeenCalledWith(DIAGNOSTICS_EU_SERVER_URL, expect.any(Object));\n    });\n  });\n\n  describe('_setSampleRate', () => {\n    let client: DiagnosticsClient;\n    let mockIsTimestampInSampleTemp: jest.SpyInstance;\n\n    beforeEach(() => {\n      // Mock isTimestampInSampleTemp with realistic implementation: compare sample rate with 0.5\n      mockIsTimestampInSampleTemp = jest\n        .spyOn({ isTimestampInSampleTemp }, 'isTimestampInSampleTemp')\n        .mockImplementation((_timestamp: string | number, sampleRate: number) => {\n          return sampleRate >= 0.5;\n        });\n      client = new DiagnosticsClient(apiKey, mockLogger);\n    });\n\n    afterEach(() => {\n      mockIsTimestampInSampleTemp.mockRestore();\n    });\n\n    test('should update sample rate and shouldTrack when rate >= 0.5 and enabled', () => {\n      const newSampleRate = 0.8;\n      client.config.enabled = true;\n\n      client._setSampleRate(newSampleRate);\n\n      expect(client.config.sampleRate).toBe(newSampleRate);\n      expect(mockIsTimestampInSampleTemp).toHaveBeenCalledWith(client.startTimestamp, newSampleRate);\n      expect(client.shouldTrack).toBe(true);\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith('DiagnosticsClient: Setting sample rate to', newSampleRate);\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith('DiagnosticsClient: Should track is', true);\n    });\n\n    test('should update sample rate and set shouldTrack to false when rate < 0.5', () => {\n      const newSampleRate = 0.2;\n      client.config.enabled = true;\n\n      client._setSampleRate(newSampleRate);\n\n      expect(client.config.sampleRate).toBe(newSampleRate);\n      expect(mockIsTimestampInSampleTemp).toHaveBeenCalledWith(client.startTimestamp, newSampleRate);\n      expect(client.shouldTrack).toBe(false);\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith('DiagnosticsClient: Setting sample rate to', newSampleRate);\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith('DiagnosticsClient: Should track is', false);\n    });\n\n    test('should set shouldTrack to false when disabled even with high sample rate', () => {\n      const newSampleRate = 1.0;\n      client.config.enabled = false;\n\n      client._setSampleRate(newSampleRate);\n\n      expect(client.config.sampleRate).toBe(newSampleRate);\n      expect(mockIsTimestampInSampleTemp).toHaveBeenCalledWith(client.startTimestamp, newSampleRate);\n      expect(client.shouldTrack).toBe(false);\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith('DiagnosticsClient: Setting sample rate to', newSampleRate);\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith('DiagnosticsClient: Should track is', false);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/diagnostics/diagnostics-storage.test.ts",
    "content": "import 'fake-indexeddb/auto';\nimport { DiagnosticsStorage } from '../../src/diagnostics/diagnostics-storage';\nimport { ILogger } from '../../src/logger';\nimport { getGlobalScope } from '../../src/global-scope';\n\njest.mock('../../src/global-scope');\n\n// Mock logger\nconst mockLogger: ILogger = {\n  disable: jest.fn(),\n  enable: jest.fn(),\n  log: jest.fn(),\n  warn: jest.fn(),\n  error: jest.fn(),\n  debug: jest.fn(),\n};\n\nconst apiKey = '1234567890abcdefg';\n\ndescribe('DiagnosticsStorage', () => {\n  let storage: DiagnosticsStorage;\n  beforeEach(() => {\n    jest.clearAllMocks();\n    storage = new DiagnosticsStorage(apiKey, mockLogger);\n    (getGlobalScope as jest.Mock).mockReturnValue(globalThis);\n  });\n\n  afterEach(() => {\n    jest.resetAllMocks();\n    (getGlobalScope as jest.Mock).mockRestore();\n  });\n\n  describe('constructor', () => {\n    test('should initialize with apiKey and logger', () => {\n      expect(storage.dbName).toBe('AMP_diagnostics_1234567890');\n      expect(storage.logger).toBe(mockLogger);\n    });\n  });\n\n  describe('isSupported', () => {\n    test('should return true if IndexedDB is supported', () => {\n      expect(DiagnosticsStorage.isSupported()).toBe(true);\n    });\n    test('should return false if IndexedDB is not supported', () => {\n      (getGlobalScope as jest.Mock).mockReturnValue(undefined);\n      expect(DiagnosticsStorage.isSupported()).toBe(false);\n    });\n  });\n\n  describe('getDB', () => {\n    test('should return the db', async () => {\n      await expect(storage.getDB()).resolves.toBeDefined();\n    });\n\n    test('should call openDB if dbPromise is not set', async () => {\n      storage.dbPromise = null;\n      const mockDB = {} as IDBDatabase;\n      const openDBSpy = jest.spyOn(storage, 'openDB').mockResolvedValue(mockDB);\n\n      await expect(storage.getDB()).resolves.toBeDefined();\n      expect(openDBSpy).toHaveBeenCalled();\n    });\n  });\n\n  describe('openDB', () => {\n    test('should reject on open DB request errors', async () => {\n      // Mock indexedDB.open to simulate an error\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      const originalOpen = indexedDB.open;\n      const mockRequest = {\n        onerror: null as ((event: Event) => void) | null,\n        onsuccess: null as ((event: Event) => void) | null,\n        onupgradeneeded: null as ((event: Event) => void) | null,\n      };\n\n      indexedDB.open = jest.fn().mockReturnValue(mockRequest);\n\n      // Start the openDB operation\n      const openDBPromise = storage.openDB();\n\n      // Simulate the error event\n      if (mockRequest.onerror) {\n        mockRequest.onerror(new Event('error'));\n      }\n\n      // Verify the promise rejects with the correct error\n      await expect(openDBPromise).rejects.toThrow('Failed to open IndexedDB');\n\n      // Restore the original method\n      indexedDB.open = originalOpen;\n    });\n\n    test('should handle database close event', async () => {\n      // Mock indexedDB.open to simulate a successful open\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      const originalOpen = indexedDB.open;\n      const mockDB = {\n        onclose: null as ((event: Event) => void) | null,\n        onerror: null as ((event: Event) => void) | null,\n        close: jest.fn(),\n      };\n      const mockRequest = {\n        onerror: null as ((event: Event) => void) | null,\n        onsuccess: null as ((event: Event) => void) | null,\n        onupgradeneeded: null as ((event: Event) => void) | null,\n        result: mockDB,\n      };\n\n      indexedDB.open = jest.fn().mockReturnValue(mockRequest);\n\n      // Call getDB to trigger the openDB and set dbPromise\n      const getDBPromise = storage.getDB();\n\n      // Simulate the success event\n      if (mockRequest.onsuccess) {\n        mockRequest.onsuccess(new Event('success'));\n      }\n\n      // Wait for the promise to resolve\n      const db = await getDBPromise;\n      expect(db).toBe(mockDB);\n\n      // Verify dbPromise is set\n      expect(storage.dbPromise).toBeTruthy();\n\n      // Simulate the database close event\n      if (mockDB.onclose) {\n        mockDB.onclose(new Event('close'));\n      }\n\n      // Verify that dbPromise is cleared when connection closes\n      expect(storage.dbPromise).toBeNull();\n\n      // Verify that the debug message was logged\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith('DiagnosticsStorage: DB connection closed.');\n\n      // Restore the original method\n      indexedDB.open = originalOpen;\n    });\n\n    test('should handle database error event', async () => {\n      // Mock indexedDB.open to simulate a successful open\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      const originalOpen = indexedDB.open;\n      const mockDB = {\n        onclose: null as ((event: Event) => void) | null,\n        onerror: null as ((event: Event) => void) | null,\n        close: jest.fn(),\n      };\n      const mockRequest = {\n        onerror: null as ((event: Event) => void) | null,\n        onsuccess: null as ((event: Event) => void) | null,\n        onupgradeneeded: null as ((event: Event) => void) | null,\n        result: mockDB,\n      };\n\n      indexedDB.open = jest.fn().mockReturnValue(mockRequest);\n\n      // Call getDB to trigger the openDB and set dbPromise\n      const getDBPromise = storage.getDB();\n\n      // Simulate the success event\n      if (mockRequest.onsuccess) {\n        mockRequest.onsuccess(new Event('success'));\n      }\n\n      // Wait for the promise to resolve\n      const db = await getDBPromise;\n      expect(db).toBe(mockDB);\n\n      // Simulate the database error event\n      const errorEvent = new Event('error');\n      if (mockDB.onerror) {\n        mockDB.onerror(errorEvent);\n      }\n\n      // Verify that the error was logged\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith(\n        'DiagnosticsStorage: A global database error occurred.',\n        errorEvent,\n      );\n\n      // Verify that db.close() was called\n      expect(mockDB.close).toHaveBeenCalled();\n\n      // Restore the original method\n      indexedDB.open = originalOpen;\n    });\n  });\n\n  describe('setTags', () => {\n    test('should set tags', async () => {\n      const testTags = { test: 'test', library: 'amplitude-typescript' };\n\n      await expect(storage.setTags(testTags)).resolves.toBeUndefined();\n\n      // Verify the tags were actually stored in IndexedDB by reading directly\n      const dbName = `AMP_diagnostics_${apiKey.substring(0, 10)}`;\n      const db = await new Promise<IDBDatabase>((resolve, reject) => {\n        const request = indexedDB.open(dbName, 1);\n        request.onsuccess = () => resolve(request.result);\n        request.onerror = () => reject(request.error);\n      });\n\n      const transaction = db.transaction(['tags'], 'readonly');\n      const store = transaction.objectStore('tags');\n\n      const allRecords = await new Promise<any[]>((resolve, reject) => {\n        const request = store.getAll();\n        request.onsuccess = () => resolve(request.result);\n        request.onerror = () => reject(request.error);\n      });\n\n      expect(allRecords).toHaveLength(2);\n      expect(allRecords).toEqual(\n        expect.arrayContaining([\n          { key: 'test', value: 'test' },\n          { key: 'library', value: 'amplitude-typescript' },\n        ]),\n      );\n\n      db.close();\n    });\n\n    test('should early return if tags is empty', async () => {\n      const getDBSpy = jest.spyOn(storage, 'getDB');\n\n      await expect(storage.setTags({})).resolves.toBeUndefined();\n\n      expect(getDBSpy).not.toHaveBeenCalled();\n      getDBSpy.mockRestore();\n    });\n\n    test('should handle put request errors', async () => {\n      const testTags = { test: 'test' };\n\n      // Create a mock put request that will automatically trigger error\n      const mockPutRequest = {\n        onerror: null as ((event: Event) => void) | null,\n      };\n\n      // Mock the store.put to return a request that will fail\n      const mockStore = {\n        put: jest.fn().mockImplementation(() => {\n          // Simulate async error by triggering onerror after handlers are set\n          setTimeout(() => {\n            if (mockPutRequest.onerror) {\n              const errorEvent = new Event('error');\n              mockPutRequest.onerror(errorEvent);\n            }\n            // Also trigger transaction abort\n            if (mockTransaction.onabort) {\n              const abortEvent = new Event('abort');\n              mockTransaction.onabort(abortEvent);\n            }\n          }, 0);\n          return mockPutRequest;\n        }),\n      };\n\n      // Mock the transaction that will abort due to put error\n      const mockTransaction = {\n        oncomplete: null as ((event: Event) => void) | null,\n        onabort: null as ((event: Event) => void) | null,\n        objectStore: jest.fn().mockReturnValue(mockStore),\n      };\n\n      // Mock the database\n      const mockDB = {\n        transaction: jest.fn().mockReturnValue(mockTransaction),\n      };\n\n      // Spy on getDB and make it return our mock database\n      const getDBSpy = jest.spyOn(storage, 'getDB').mockResolvedValue(mockDB as unknown as IDBDatabase);\n\n      // The setTags should handle the error gracefully\n      await expect(storage.setTags(testTags)).resolves.toBeUndefined();\n\n      // Give time for async error to be processed\n      await new Promise((resolve) => setTimeout(resolve, 10));\n\n      // Verify the put request was attempted\n      expect(mockStore.put).toHaveBeenCalledWith({ key: 'test', value: 'test' });\n\n      // Verify both put error and transaction abort were logged\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith(\n        'DiagnosticsStorage: Failed to set tag',\n        'test',\n        'test',\n        expect.any(Event),\n      );\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith('DiagnosticsStorage: Failed to set tags', expect.any(Event));\n\n      // Restore spy\n      getDBSpy.mockRestore();\n    });\n\n    test('should handle error when openDB promise rejects', async () => {\n      const testTags = { test: 'test' };\n      const testError = new Error('Failed to open IndexedDB');\n      const openDBSpy = jest.spyOn(storage, 'openDB').mockRejectedValue(testError);\n\n      // The setTags should handle the error gracefully\n      await expect(storage.setTags(testTags)).resolves.toBeUndefined();\n\n      // Verify error was logged\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith('DiagnosticsStorage: Failed to set tags', testError);\n\n      // Restore spy\n      openDBSpy.mockRestore();\n    });\n  });\n\n  describe('incrementCounters', () => {\n    test('should increment counters', async () => {\n      await expect(storage.incrementCounters({ clicks: 5, errors: 1 })).resolves.toBeUndefined();\n    });\n\n    test('should early return if counters is empty', async () => {\n      await expect(storage.incrementCounters({})).resolves.toBeUndefined();\n    });\n\n    test('should handle put request errors', async () => {\n      const testCounters = { clicks: 5 };\n\n      // Create mock requests\n      const mockGetRequest = {\n        onsuccess: null as ((event: Event) => void) | null,\n        onerror: null as ((event: Event) => void) | null,\n        result: undefined, // No existing value\n      };\n\n      const mockPutRequest = {\n        onerror: null as ((event: Event) => void) | null,\n      };\n\n      // Mock the store get and put methods (incrementCounters uses read-modify-write)\n      const mockStore = {\n        get: jest.fn().mockImplementation(() => {\n          // Simulate successful get (no existing value)\n          setTimeout(() => {\n            if (mockGetRequest.onsuccess) {\n              mockGetRequest.onsuccess(new Event('success'));\n            }\n          }, 0);\n          return mockGetRequest;\n        }),\n        put: jest.fn().mockImplementation(() => {\n          // Simulate async error by triggering onerror after handlers are set\n          setTimeout(() => {\n            if (mockPutRequest.onerror) {\n              const errorEvent = new Event('error');\n              mockPutRequest.onerror(errorEvent);\n            }\n            // Also trigger transaction abort\n            if (mockTransaction.onabort) {\n              const abortEvent = new Event('abort');\n              mockTransaction.onabort(abortEvent);\n            }\n          }, 0);\n          return mockPutRequest;\n        }),\n      };\n\n      // Mock the transaction that will abort due to put error\n      const mockTransaction = {\n        oncomplete: null as ((event: Event) => void) | null,\n        onabort: null as ((event: Event) => void) | null,\n        objectStore: jest.fn().mockReturnValue(mockStore),\n      };\n\n      // Mock the database\n      const mockDB = {\n        transaction: jest.fn().mockReturnValue(mockTransaction),\n      };\n\n      // Spy on getDB and make it return our mock database\n      const getDBSpy = jest.spyOn(storage, 'getDB').mockResolvedValue(mockDB as unknown as IDBDatabase);\n\n      // The incrementCounters should handle the error gracefully\n      await expect(storage.incrementCounters(testCounters)).resolves.toBeUndefined();\n\n      // Give time for async error to be processed\n      await new Promise((resolve) => setTimeout(resolve, 10));\n\n      // Verify the put request was attempted\n      expect(mockStore.put).toHaveBeenCalledWith({ key: 'clicks', value: 5 });\n\n      // Verify both get and put were called\n      expect(mockStore.get).toHaveBeenCalledWith('clicks');\n      expect(mockStore.put).toHaveBeenCalledWith({ key: 'clicks', value: 5 });\n\n      // Verify both put error and transaction abort were logged\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith(\n        'DiagnosticsStorage: Failed to update counter',\n        'clicks',\n        expect.any(Event),\n      );\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith(\n        'DiagnosticsStorage: Failed to increment counters',\n        expect.any(Event),\n      );\n\n      // Restore spy\n      getDBSpy.mockRestore();\n    });\n\n    test('should handle error when openDB promise rejects', async () => {\n      const testCounters = { clicks: 5 };\n      const testError = new Error('Failed to open IndexedDB');\n      const openDBSpy = jest.spyOn(storage, 'openDB').mockRejectedValue(testError);\n\n      // The incrementCounters should handle the error gracefully\n      await expect(storage.incrementCounters(testCounters)).resolves.toBeUndefined();\n\n      // Verify error was logged\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith('DiagnosticsStorage: Failed to increment counters', testError);\n\n      // Restore spy\n      openDBSpy.mockRestore();\n    });\n\n    test('should handle get request error when reading existing counter', async () => {\n      const testCounters = { clicks: 5 };\n\n      // Create mock requests\n      const mockGetRequest = {\n        onsuccess: null as ((event: Event) => void) | null,\n        onerror: null as ((event: Event) => void) | null,\n        result: undefined,\n      };\n\n      // Mock the transaction first so we can reference it\n      const mockTransaction = {\n        oncomplete: null as ((event: Event) => void) | null,\n        onabort: null as ((event: Event) => void) | null,\n        objectStore: jest.fn(),\n      };\n\n      // Mock the store get method to return a request that will fail\n      const mockStore = {\n        get: jest.fn().mockImplementation(() => {\n          // Simulate async error by triggering onerror after handlers are set\n          setTimeout(() => {\n            if (mockGetRequest.onerror) {\n              const errorEvent = new Event('error');\n              mockGetRequest.onerror(errorEvent);\n            }\n            // Also trigger transaction complete to resolve the Promise\n            if (mockTransaction.oncomplete) {\n              mockTransaction.oncomplete(new Event('complete'));\n            }\n          }, 0);\n          return mockGetRequest;\n        }),\n        put: jest.fn().mockReturnValue({ onerror: null }),\n      };\n\n      // Set up the mock store reference\n      mockTransaction.objectStore.mockReturnValue(mockStore);\n\n      // Mock the database\n      const mockDB = {\n        transaction: jest.fn().mockReturnValue(mockTransaction),\n      };\n\n      // Spy on getDB and make it return our mock database\n      const getDBSpy = jest.spyOn(storage, 'getDB').mockResolvedValue(mockDB as unknown as IDBDatabase);\n\n      // The incrementCounters should handle the error gracefully\n      await expect(storage.incrementCounters(testCounters)).resolves.toBeUndefined();\n\n      // Give time for async error to be processed\n      await new Promise((resolve) => setTimeout(resolve, 10));\n\n      // Verify the get request was attempted\n      expect(mockStore.get).toHaveBeenCalledWith('clicks');\n\n      // Verify get error was logged\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith(\n        'DiagnosticsStorage: Failed to read existing counter',\n        'clicks',\n        expect.any(Event),\n      );\n\n      // Restore spy\n      getDBSpy.mockRestore();\n    });\n  });\n\n  describe('setHistogramStats', () => {\n    test('should set histogram stats', async () => {\n      const histogramStats = {\n        responseTime: { count: 10, min: 50, max: 500, sum: 2500 },\n        loadTime: { count: 5, min: 100, max: 1000, sum: 3000 },\n      };\n      await expect(storage.setHistogramStats(histogramStats)).resolves.toBeUndefined();\n    });\n\n    test('should early return if histogram stats is empty', async () => {\n      await expect(storage.setHistogramStats({})).resolves.toBeUndefined();\n    });\n\n    test('should handle put request errors', async () => {\n      const testHistogramStats = { responseTime: { count: 10, min: 50, max: 500, sum: 2500 } };\n\n      // Create mock requests\n      const mockGetRequest = {\n        onsuccess: null as ((event: Event) => void) | null,\n        onerror: null as ((event: Event) => void) | null,\n        result: undefined, // No existing value\n      };\n\n      const mockPutRequest = {\n        onerror: null as ((event: Event) => void) | null,\n      };\n\n      // Mock the store get and put methods (setHistogramStats uses read-modify-write)\n      const mockStore = {\n        get: jest.fn().mockImplementation(() => {\n          // Simulate successful get (no existing value)\n          setTimeout(() => {\n            if (mockGetRequest.onsuccess) {\n              mockGetRequest.onsuccess(new Event('success'));\n            }\n          }, 0);\n          return mockGetRequest;\n        }),\n        put: jest.fn().mockImplementation(() => {\n          // Simulate async error by triggering onerror after handlers are set\n          setTimeout(() => {\n            if (mockPutRequest.onerror) {\n              const errorEvent = new Event('error');\n              mockPutRequest.onerror(errorEvent);\n            }\n            // Also trigger transaction abort\n            if (mockTransaction.onabort) {\n              const abortEvent = new Event('abort');\n              mockTransaction.onabort(abortEvent);\n            }\n          }, 0);\n          return mockPutRequest;\n        }),\n      };\n\n      // Mock the transaction that will abort due to put error\n      const mockTransaction = {\n        oncomplete: null as ((event: Event) => void) | null,\n        onabort: null as ((event: Event) => void) | null,\n        objectStore: jest.fn().mockReturnValue(mockStore),\n      };\n\n      // Mock the database\n      const mockDB = {\n        transaction: jest.fn().mockReturnValue(mockTransaction),\n      };\n\n      // Spy on getDB and make it return our mock database\n      const getDBSpy = jest.spyOn(storage, 'getDB').mockResolvedValue(mockDB as unknown as IDBDatabase);\n\n      // The setHistogramStats should handle the error gracefully\n      await expect(storage.setHistogramStats(testHistogramStats)).resolves.toBeUndefined();\n\n      // Give time for async error to be processed\n      await new Promise((resolve) => setTimeout(resolve, 10));\n\n      // Verify both get and put were called\n      expect(mockStore.get).toHaveBeenCalledWith('responseTime');\n      expect(mockStore.put).toHaveBeenCalledWith({\n        key: 'responseTime',\n        count: 10,\n        min: 50,\n        max: 500,\n        sum: 2500,\n      });\n\n      // Verify both put error and transaction abort were logged\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith(\n        'DiagnosticsStorage: Failed to set histogram stats',\n        'responseTime',\n        expect.any(Event),\n      );\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith(\n        'DiagnosticsStorage: Failed to set histogram stats',\n        expect.any(Event),\n      );\n\n      // Restore spy\n      getDBSpy.mockRestore();\n    });\n\n    test('should handle error when openDB promise rejects', async () => {\n      const testHistogramStats = { responseTime: { count: 10, min: 50, max: 500, sum: 2500 } };\n      const testError = new Error('Failed to open IndexedDB');\n      const openDBSpy = jest.spyOn(storage, 'openDB').mockRejectedValue(testError);\n\n      // The setHistogramStats should handle the error gracefully\n      await expect(storage.setHistogramStats(testHistogramStats)).resolves.toBeUndefined();\n\n      // Verify error was logged\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith('DiagnosticsStorage: Failed to set histogram stats', testError);\n\n      // Restore spy\n      openDBSpy.mockRestore();\n    });\n\n    test('should handle get request error when reading existing histogram', async () => {\n      const testHistogramStats = { responseTime: { count: 10, min: 50, max: 500, sum: 2500 } };\n\n      // Create mock requests\n      const mockGetRequest = {\n        onsuccess: null as ((event: Event) => void) | null,\n        onerror: null as ((event: Event) => void) | null,\n        result: undefined,\n      };\n\n      // Mock the transaction first so we can reference it\n      const mockTransaction = {\n        oncomplete: null as ((event: Event) => void) | null,\n        onabort: null as ((event: Event) => void) | null,\n        objectStore: jest.fn(),\n      };\n\n      // Mock the store get method to return a request that will fail\n      const mockStore = {\n        get: jest.fn().mockImplementation(() => {\n          // Simulate async error by triggering onerror after handlers are set\n          setTimeout(() => {\n            if (mockGetRequest.onerror) {\n              const errorEvent = new Event('error');\n              mockGetRequest.onerror(errorEvent);\n            }\n            // Also trigger transaction complete to resolve the Promise\n            if (mockTransaction.oncomplete) {\n              mockTransaction.oncomplete(new Event('complete'));\n            }\n          }, 0);\n          return mockGetRequest;\n        }),\n        put: jest.fn().mockReturnValue({ onerror: null }),\n      };\n\n      // Set up the mock store reference\n      mockTransaction.objectStore.mockReturnValue(mockStore);\n\n      // Mock the database\n      const mockDB = {\n        transaction: jest.fn().mockReturnValue(mockTransaction),\n      };\n\n      // Spy on getDB and make it return our mock database\n      const getDBSpy = jest.spyOn(storage, 'getDB').mockResolvedValue(mockDB as unknown as IDBDatabase);\n\n      // The setHistogramStats should handle the error gracefully\n      await expect(storage.setHistogramStats(testHistogramStats)).resolves.toBeUndefined();\n\n      // Give time for async error to be processed\n      await new Promise((resolve) => setTimeout(resolve, 10));\n\n      // Verify the get request was attempted\n      expect(mockStore.get).toHaveBeenCalledWith('responseTime');\n\n      // Verify get error was logged\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith(\n        'DiagnosticsStorage: Failed to read existing histogram stats',\n        'responseTime',\n        expect.any(Event),\n      );\n\n      // Restore spy\n      getDBSpy.mockRestore();\n    });\n  });\n\n  describe('addEventRecords', () => {\n    // Helper function to clear events table after each test\n    afterEach(async () => {\n      try {\n        const dbName = `AMP_diagnostics_${apiKey.substring(0, 10)}`;\n        const db = await new Promise<IDBDatabase>((resolve, reject) => {\n          const request = indexedDB.open(dbName, 1);\n          request.onsuccess = () => resolve(request.result);\n          request.onerror = () => reject(request.error);\n          request.onupgradeneeded = (event) => {\n            const db = (event.target as IDBOpenDBRequest).result;\n            // Create the events table if it doesn't exist\n            if (!db.objectStoreNames.contains('events')) {\n              const eventsStore = db.createObjectStore('events', {\n                keyPath: 'id',\n                autoIncrement: true,\n              });\n              eventsStore.createIndex('time_idx', 'time', { unique: false });\n            }\n          };\n        });\n\n        // Only clear if the events table exists\n        if (db.objectStoreNames.contains('events')) {\n          const transaction = db.transaction(['events'], 'readwrite');\n          const store = transaction.objectStore('events');\n\n          await new Promise<void>((resolve, reject) => {\n            const clearRequest = store.clear();\n            clearRequest.onsuccess = () => resolve();\n            clearRequest.onerror = () => reject(clearRequest.error);\n          });\n        }\n\n        db.close();\n      } catch (error) {\n        // Ignore errors - the database might not exist yet for early return tests\n      }\n    });\n\n    test('should add event records', async () => {\n      const events = [\n        { event_name: 'page_view', time: Date.now(), event_properties: { page: '/home' } },\n        { event_name: 'button_click', time: Date.now() + 1000, event_properties: { button_id: 'submit' } },\n      ];\n      await expect(storage.addEventRecords(events)).resolves.toBeUndefined();\n    });\n\n    test('should limit to at most 10 events in database', async () => {\n      // First, add exactly 10 events\n      const firstBatch = [];\n      const baseTime = Date.now();\n      for (let i = 0; i < 10; i++) {\n        firstBatch.push({\n          event_name: `event_${i}`,\n          time: baseTime + i * 1000,\n          event_properties: { index: i },\n        });\n      }\n\n      await expect(storage.addEventRecords(firstBatch)).resolves.toBeUndefined();\n\n      // Clear previous debug calls to focus on the limit-exceeding call\n      jest.clearAllMocks();\n\n      // Try to add 2 more events - these should be rejected\n      const secondBatch = [\n        { event_name: 'event_10', time: baseTime + 10000, event_properties: { index: 10 } },\n        { event_name: 'event_11', time: baseTime + 11000, event_properties: { index: 11 } },\n      ];\n\n      await expect(storage.addEventRecords(secondBatch)).resolves.toBeUndefined();\n\n      // Verify debug log was called indicating 0 events added due to storage limit\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith(\n        'DiagnosticsStorage: Only added 0 of 2 events due to storage limit',\n      );\n\n      // Verify still only 10 events in database\n      const dbName = `AMP_diagnostics_${apiKey.substring(0, 10)}`;\n      const db = await new Promise<IDBDatabase>((resolve, reject) => {\n        const request = indexedDB.open(dbName, 1);\n        request.onsuccess = () => resolve(request.result);\n        request.onerror = () => reject(request.error);\n      });\n\n      const transaction = db.transaction(['events'], 'readonly');\n      const store = transaction.objectStore('events');\n\n      const allRecords = await new Promise<Array<{ event_name: string; time: number; event_properties: any }>>(\n        (resolve, reject) => {\n          const request = store.getAll();\n          request.onsuccess = () => resolve(request.result);\n          request.onerror = () => reject(request.error);\n        },\n      );\n\n      // Should still have exactly 10 events (the original ones)\n      expect(allRecords).toHaveLength(10);\n\n      // Verify the events are the original ones (event_0 to event_9)\n      const sortedRecords = allRecords.sort((a, b) => a.time - b.time);\n      expect(sortedRecords[0].event_name).toBe('event_0');\n      expect(sortedRecords[9].event_name).toBe('event_9');\n\n      db.close();\n    });\n\n    test('should add partial batch when space is limited', async () => {\n      // First, add 8 events\n      const firstBatch = [];\n      const baseTime = Date.now();\n      for (let i = 0; i < 8; i++) {\n        firstBatch.push({\n          event_name: `event_${i}`,\n          time: baseTime + i * 1000,\n          event_properties: { index: i },\n        });\n      }\n\n      await expect(storage.addEventRecords(firstBatch)).resolves.toBeUndefined();\n\n      // Clear previous debug calls to focus on the limit-exceeding call\n      jest.clearAllMocks();\n\n      // Try to add 5 more events - only 2 should be added (the least recent ones)\n      const secondBatch = [];\n      for (let i = 8; i < 13; i++) {\n        secondBatch.push({\n          event_name: `event_${i}`,\n          time: baseTime + i * 1000,\n          event_properties: { index: i },\n        });\n      }\n\n      await expect(storage.addEventRecords(secondBatch)).resolves.toBeUndefined();\n\n      // Verify debug log was called indicating only 2 of 5 events were added\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith(\n        'DiagnosticsStorage: Only added 2 of 5 events due to storage limit',\n      );\n\n      // Verify exactly 10 events in database\n      const dbName = `AMP_diagnostics_${apiKey.substring(0, 10)}`;\n      const db = await new Promise<IDBDatabase>((resolve, reject) => {\n        const request = indexedDB.open(dbName, 1);\n        request.onsuccess = () => resolve(request.result);\n        request.onerror = () => reject(request.error);\n      });\n\n      const transaction = db.transaction(['events'], 'readonly');\n      const store = transaction.objectStore('events');\n\n      const allRecords = await new Promise<Array<{ event_name: string; time: number; event_properties: any }>>(\n        (resolve, reject) => {\n          const request = store.getAll();\n          request.onsuccess = () => resolve(request.result);\n          request.onerror = () => reject(request.error);\n        },\n      );\n\n      // Should have exactly 10 events\n      expect(allRecords).toHaveLength(10);\n\n      // Verify we have the first 8 events plus the first 2 from the second batch (least recent)\n      const sortedRecords = allRecords.sort((a, b) => a.time - b.time);\n      expect(sortedRecords[0].event_name).toBe('event_0');\n      expect(sortedRecords[7].event_name).toBe('event_7');\n      expect(sortedRecords[8].event_name).toBe('event_8'); // First from second batch\n      expect(sortedRecords[9].event_name).toBe('event_9'); // Second from second batch\n\n      db.close();\n    });\n\n    test('should early return if events is empty', async () => {\n      await expect(storage.addEventRecords([])).resolves.toBeUndefined();\n    });\n\n    test('should handle add request errors', async () => {\n      const testEvents = [{ event_name: 'page_view', time: Date.now(), event_properties: { page: '/home' } }];\n\n      // Create a mock add request that will automatically trigger error\n      const mockAddRequest = {\n        onerror: null as ((event: Event) => void) | null,\n      };\n\n      // Create a mock count request that succeeds\n      const mockCountRequest = {\n        onsuccess: null as ((event: Event) => void) | null,\n        onerror: null as ((event: Event) => void) | null,\n        result: 0, // Simulate empty database\n      };\n\n      // Mock the store with both count and add methods\n      const mockStore = {\n        count: jest.fn().mockImplementation(() => {\n          // Simulate successful count\n          setTimeout(() => {\n            if (mockCountRequest.onsuccess) {\n              mockCountRequest.onsuccess(new Event('success'));\n            }\n          }, 0);\n          return mockCountRequest;\n        }),\n        add: jest.fn().mockImplementation(() => {\n          // Simulate async error by triggering onerror after handlers are set\n          setTimeout(() => {\n            if (mockAddRequest.onerror) {\n              const errorEvent = new Event('error');\n              mockAddRequest.onerror(errorEvent);\n            }\n            // Also trigger transaction completion (even with errors, transaction can complete)\n            if (mockTransaction.oncomplete) {\n              const completeEvent = new Event('complete');\n              mockTransaction.oncomplete(completeEvent);\n            }\n          }, 0);\n          return mockAddRequest;\n        }),\n      };\n\n      // Mock the transaction\n      const mockTransaction = {\n        oncomplete: null as ((event: Event) => void) | null,\n        onabort: null as ((event: Event) => void) | null,\n        objectStore: jest.fn().mockReturnValue(mockStore),\n      };\n\n      // Mock the database\n      const mockDB = {\n        transaction: jest.fn().mockReturnValue(mockTransaction),\n      };\n\n      // Spy on getDB and make it return our mock database\n      const getDBSpy = jest.spyOn(storage, 'getDB').mockResolvedValue(mockDB as unknown as IDBDatabase);\n\n      // The addEventRecords should handle the error gracefully\n      await expect(storage.addEventRecords(testEvents)).resolves.toBeUndefined();\n\n      // Give time for async error to be processed\n      await new Promise((resolve) => setTimeout(resolve, 10));\n\n      // Verify the count request was attempted first\n      expect(mockStore.count).toHaveBeenCalled();\n\n      // Verify the add request was attempted\n      expect(mockStore.add).toHaveBeenCalledWith({\n        event_name: 'page_view',\n        event_properties: { page: '/home' },\n        time: expect.any(Number) as number,\n      });\n\n      // Verify error was logged\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith(\n        'DiagnosticsStorage: Failed to add event record',\n        expect.any(Event),\n      );\n\n      // Restore spy\n      getDBSpy.mockRestore();\n    });\n\n    test('should handle count request error', async () => {\n      const testEvents = [{ event_name: 'page_view', time: Date.now(), event_properties: { page: '/home' } }];\n\n      // Create a mock count request that will fail\n      const mockCountRequest = {\n        onsuccess: null as ((event: Event) => void) | null,\n        onerror: null as ((event: Event) => void) | null,\n        result: undefined,\n      };\n\n      // Mock the transaction first so we can reference it\n      const mockTransaction = {\n        oncomplete: null as ((event: Event) => void) | null,\n        onabort: null as ((event: Event) => void) | null,\n        objectStore: jest.fn(),\n      };\n\n      // Mock the store with count method that fails\n      const mockStore = {\n        count: jest.fn().mockImplementation(() => {\n          // Simulate async error by triggering onerror after handlers are set\n          setTimeout(() => {\n            if (mockCountRequest.onerror) {\n              const errorEvent = new Event('error');\n              mockCountRequest.onerror(errorEvent);\n            }\n            // Also trigger transaction complete to resolve the Promise\n            if (mockTransaction.oncomplete) {\n              mockTransaction.oncomplete(new Event('complete'));\n            }\n          }, 0);\n          return mockCountRequest;\n        }),\n      };\n\n      // Set up the mock store reference\n      mockTransaction.objectStore.mockReturnValue(mockStore);\n\n      // Mock the database\n      const mockDB = {\n        transaction: jest.fn().mockReturnValue(mockTransaction),\n      };\n\n      // Spy on getDB and make it return our mock database\n      const getDBSpy = jest.spyOn(storage, 'getDB').mockResolvedValue(mockDB as unknown as IDBDatabase);\n\n      // The addEventRecords should handle the error gracefully\n      await expect(storage.addEventRecords(testEvents)).resolves.toBeUndefined();\n\n      // Give time for async error to be processed\n      await new Promise((resolve) => setTimeout(resolve, 10));\n\n      // Verify the count request was attempted\n      expect(mockStore.count).toHaveBeenCalled();\n\n      // Verify count error was logged\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith(\n        'DiagnosticsStorage: Failed to count existing events',\n        expect.any(Event),\n      );\n\n      // Restore spy\n      getDBSpy.mockRestore();\n    });\n\n    test('should handle error when openDB promise rejects', async () => {\n      const testEvents = [{ event_name: 'page_view', time: Date.now(), event_properties: { page: '/home' } }];\n      const testError = new Error('Failed to open IndexedDB');\n      const openDBSpy = jest.spyOn(storage, 'openDB').mockRejectedValue(testError);\n\n      // The addEventRecords should handle the error gracefully\n      await expect(storage.addEventRecords(testEvents)).resolves.toBeUndefined();\n\n      // Verify error was logged\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith('DiagnosticsStorage: Failed to add event records', testError);\n\n      // Restore spy\n      openDBSpy.mockRestore();\n    });\n  });\n\n  describe('setInternal', () => {\n    test('should set internal value', async () => {\n      await expect(storage.setInternal('lastFlushTimestamp', '1234567890')).resolves.toBeUndefined();\n    });\n  });\n\n  describe('getInternal', () => {\n    test('should return undefined for non-existent key', async () => {\n      await expect(storage.getInternal('nonExistentKey')).resolves.toBeUndefined();\n    });\n\n    test('should get internal value after setting it', async () => {\n      const key = 'testKey';\n      const value = 'testValue';\n\n      // Set the value first\n      await storage.setInternal(key, value);\n\n      // Then get it back\n      const result = await storage.getInternal(key);\n      expect(result).toEqual({ key, value });\n    });\n\n    test('should return undefined when openDB promise rejects', async () => {\n      const testError = new Error('Failed to open IndexedDB');\n      const openDBSpy = jest.spyOn(storage, 'openDB').mockRejectedValue(testError);\n\n      const result = await storage.getInternal('testKey');\n\n      expect(result).toBeUndefined();\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLogger.debug).toHaveBeenCalledWith('DiagnosticsStorage: Failed to get internal value', testError);\n\n      openDBSpy.mockRestore();\n    });\n  });\n\n  describe('setLastFlushTimestamp', () => {\n    test('should set last flush timestamp', async () => {\n      const spy = jest.spyOn(storage, 'setInternal');\n      const timestamp = Date.now();\n      await expect(storage.setLastFlushTimestamp(timestamp)).resolves.toBeUndefined();\n      expect(spy).toHaveBeenCalledWith('last_flush_timestamp', timestamp.toString());\n      spy.mockRestore();\n    });\n  });\n\n  describe('getLastFlushTimestamp', () => {\n    test('should get last flush timestamp after setting it', async () => {\n      const spy = jest.spyOn(storage, 'getInternal');\n      const timestamp = 1234567890000;\n\n      // Set the timestamp first\n      await storage.setLastFlushTimestamp(timestamp);\n\n      // Then get it back\n      const result = await storage.getLastFlushTimestamp();\n      expect(result).toBe(timestamp);\n      expect(spy).toHaveBeenCalledWith('last_flush_timestamp');\n      spy.mockRestore();\n    });\n\n    test('should return undefined when getInternal returns undefined', async () => {\n      const spy = jest.spyOn(storage, 'getInternal').mockResolvedValue(undefined);\n\n      const result = await storage.getLastFlushTimestamp();\n\n      expect(result).toBeUndefined();\n      expect(spy).toHaveBeenCalledWith('last_flush_timestamp');\n      spy.mockRestore();\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/diagnostics/uncaught-sdk-errors.test.ts",
    "content": "import {\n  registerSdkLoaderMetadata,\n  enableSdkErrorListeners,\n  GLOBAL_KEY,\n  EVENT_NAME_ERROR_UNCAUGHT,\n} from '../../src/diagnostics/uncaught-sdk-errors';\nimport { IDiagnosticsClient } from '../../src/diagnostics/diagnostics-client';\nimport * as globalScopeModule from '../../src/global-scope';\n\ndescribe('uncaught-sdk-errors', () => {\n  let mockGlobalScope: Record<string, unknown> & {\n    addEventListener: jest.Mock;\n    removeEventListener: jest.Mock;\n  };\n  let mockDiagnosticsClient: jest.Mocked<IDiagnosticsClient>;\n  let errorHandler: ((event: ErrorEvent) => void) | undefined;\n  let rejectionHandler: ((event: PromiseRejectionEvent) => void) | undefined;\n\n  beforeEach(() => {\n    // Reset global state\n    mockGlobalScope = {\n      addEventListener: jest.fn((type: string, handler: unknown) => {\n        if (type === 'error') {\n          errorHandler = handler as (event: ErrorEvent) => void;\n        } else if (type === 'unhandledrejection') {\n          rejectionHandler = handler as (event: PromiseRejectionEvent) => void;\n        }\n      }),\n      removeEventListener: jest.fn(),\n    };\n\n    jest.spyOn(globalScopeModule, 'getGlobalScope').mockReturnValue(mockGlobalScope as unknown as typeof globalThis);\n\n    mockDiagnosticsClient = {\n      setTag: jest.fn(),\n      increment: jest.fn(),\n      recordHistogram: jest.fn(),\n      recordEvent: jest.fn(),\n      _flush: jest.fn(),\n      _setSampleRate: jest.fn(),\n    };\n\n    errorHandler = undefined;\n    rejectionHandler = undefined;\n  });\n\n  afterEach(() => {\n    jest.restoreAllMocks();\n    // Clean up global state\n    delete mockGlobalScope[GLOBAL_KEY];\n  });\n\n  describe('registerSdkLoaderMetadata', () => {\n    it('should register script URL in global scope', () => {\n      registerSdkLoaderMetadata({ scriptUrl: 'https://cdn.amplitude.com/libs/amplitude.js' });\n\n      expect(mockGlobalScope[GLOBAL_KEY]).toEqual(['https://cdn.amplitude.com/libs/amplitude.js']);\n    });\n\n    it('should normalize script URL by removing query params', () => {\n      registerSdkLoaderMetadata({ scriptUrl: 'https://cdn.amplitude.com/libs/amplitude.js?v=1.0.0' });\n\n      expect(mockGlobalScope[GLOBAL_KEY]).toEqual(['https://cdn.amplitude.com/libs/amplitude.js']);\n    });\n\n    it('should normalize script URL by removing hash', () => {\n      registerSdkLoaderMetadata({ scriptUrl: 'https://cdn.amplitude.com/libs/amplitude.js#section' });\n\n      expect(mockGlobalScope[GLOBAL_KEY]).toEqual(['https://cdn.amplitude.com/libs/amplitude.js']);\n    });\n\n    it('should normalize script URL by removing both query params and hash', () => {\n      registerSdkLoaderMetadata({ scriptUrl: 'https://cdn.amplitude.com/libs/amplitude.js?v=1.0.0#section' });\n\n      expect(mockGlobalScope[GLOBAL_KEY]).toEqual(['https://cdn.amplitude.com/libs/amplitude.js']);\n    });\n\n    it('should merge multiple script URLs when called multiple times', () => {\n      registerSdkLoaderMetadata({ scriptUrl: 'https://cdn.amplitude.com/libs/amplitude.js' });\n      registerSdkLoaderMetadata({ scriptUrl: 'https://cdn.amplitude.com/libs/plugin.js' });\n\n      expect(mockGlobalScope[GLOBAL_KEY]).toEqual([\n        'https://cdn.amplitude.com/libs/amplitude.js',\n        'https://cdn.amplitude.com/libs/plugin.js',\n      ]);\n    });\n\n    it('should not duplicate same normalized URL when called multiple times', () => {\n      registerSdkLoaderMetadata({ scriptUrl: 'https://cdn.amplitude.com/libs/amplitude.js' });\n      registerSdkLoaderMetadata({ scriptUrl: 'https://cdn.amplitude.com/libs/amplitude.js?v=2.0.0' });\n\n      expect(mockGlobalScope[GLOBAL_KEY]).toEqual(['https://cdn.amplitude.com/libs/amplitude.js']);\n    });\n\n    it('should not register if scriptUrl is undefined', () => {\n      registerSdkLoaderMetadata({});\n\n      expect(mockGlobalScope[GLOBAL_KEY]).toBeUndefined();\n    });\n\n    it('should not register if scriptUrl is empty string', () => {\n      registerSdkLoaderMetadata({ scriptUrl: '' });\n\n      expect(mockGlobalScope[GLOBAL_KEY]).toBeUndefined();\n    });\n\n    it('should not register if scriptUrl is an invalid URL', () => {\n      registerSdkLoaderMetadata({ scriptUrl: 'not-a-valid-url' });\n\n      expect(mockGlobalScope[GLOBAL_KEY]).toBeUndefined();\n    });\n  });\n\n  describe('enableSdkErrorListeners', () => {\n    it('should add error and unhandledrejection event listeners', () => {\n      enableSdkErrorListeners(mockDiagnosticsClient);\n\n      expect(mockGlobalScope.addEventListener).toHaveBeenCalledWith('error', expect.any(Function), true);\n      expect(mockGlobalScope.addEventListener).toHaveBeenCalledWith('unhandledrejection', expect.any(Function), true);\n    });\n\n    it('should not add listeners if global scope is null', () => {\n      jest.spyOn(globalScopeModule, 'getGlobalScope').mockReturnValue(null as unknown as typeof globalThis);\n\n      enableSdkErrorListeners(mockDiagnosticsClient);\n\n      expect(mockGlobalScope.addEventListener).not.toHaveBeenCalled();\n    });\n\n    it('should not add listeners if addEventListener is not a function', () => {\n      const scopeWithoutAddEventListener = { ...mockGlobalScope };\n      delete (scopeWithoutAddEventListener as Record<string, unknown>).addEventListener;\n      jest\n        .spyOn(globalScopeModule, 'getGlobalScope')\n        .mockReturnValue(scopeWithoutAddEventListener as unknown as typeof globalThis);\n\n      enableSdkErrorListeners(mockDiagnosticsClient);\n\n      // Should not throw\n    });\n  });\n\n  describe('error handling', () => {\n    beforeEach(() => {\n      // Register script URL first\n      registerSdkLoaderMetadata({ scriptUrl: 'https://cdn.amplitude.com/libs/amplitude.js' });\n      enableSdkErrorListeners(mockDiagnosticsClient);\n    });\n\n    describe('ErrorEvent handling', () => {\n      it('should capture error when filename matches SDK script URL', () => {\n        const error = new Error('Test error');\n        const errorEvent = {\n          message: 'Test error',\n          filename: 'https://cdn.amplitude.com/libs/amplitude.js',\n          lineno: 100,\n          colno: 50,\n          error,\n          isTrusted: true,\n        } as ErrorEvent;\n\n        errorHandler?.(errorEvent);\n\n        // eslint-disable-next-line @typescript-eslint/unbound-method\n        expect(mockDiagnosticsClient.recordEvent).toHaveBeenCalledWith(EVENT_NAME_ERROR_UNCAUGHT, {\n          type: 'error',\n          message: 'Test error',\n          filename: 'https://cdn.amplitude.com/libs/amplitude.js',\n          error_name: 'Error',\n          stack: error.stack,\n          colno: 50,\n          lineno: 100,\n          isTrusted: true,\n          matchReason: 'filename',\n        });\n      });\n\n      it('should capture error when stack trace contains SDK script URL', () => {\n        const error = new Error('Test error');\n        error.stack = `Error: Test error\n    at functionName (https://cdn.amplitude.com/libs/amplitude.js:100:50)\n    at anotherFunction (https://example.com/app.js:200:30)`;\n\n        const errorEvent = {\n          message: 'Test error',\n          filename: 'https://example.com/app.js',\n          lineno: 200,\n          colno: 30,\n          error,\n          isTrusted: true,\n        } as ErrorEvent;\n\n        errorHandler?.(errorEvent);\n\n        // eslint-disable-next-line @typescript-eslint/unbound-method\n        expect(mockDiagnosticsClient.recordEvent).toHaveBeenCalledWith(EVENT_NAME_ERROR_UNCAUGHT, {\n          type: 'error',\n          message: 'Test error',\n          filename: 'https://example.com/app.js',\n          error_name: 'Error',\n          stack: error.stack,\n          colno: 30,\n          lineno: 200,\n          isTrusted: true,\n          matchReason: 'stack',\n        });\n      });\n\n      it('should capture error when filename matches second of multiple registered SDK script URLs', () => {\n        registerSdkLoaderMetadata({ scriptUrl: 'https://cdn.amplitude.com/libs/plugin.js' });\n\n        const error = new Error('Test error');\n        const errorEvent = {\n          message: 'Test error',\n          filename: 'https://cdn.amplitude.com/libs/plugin.js',\n          lineno: 100,\n          colno: 50,\n          error,\n          isTrusted: true,\n        } as ErrorEvent;\n\n        errorHandler?.(errorEvent);\n\n        // eslint-disable-next-line @typescript-eslint/unbound-method\n        expect(mockDiagnosticsClient.recordEvent).toHaveBeenCalledWith(EVENT_NAME_ERROR_UNCAUGHT, {\n          type: 'error',\n          message: 'Test error',\n          filename: 'https://cdn.amplitude.com/libs/plugin.js',\n          error_name: 'Error',\n          stack: error.stack,\n          colno: 50,\n          lineno: 100,\n          isTrusted: true,\n          matchReason: 'filename',\n        });\n      });\n\n      it('should NOT capture error when neither filename nor stack matches SDK script URL', () => {\n        const error = new Error('Test error');\n        error.stack = `Error: Test error\n    at functionName (https://example.com/app.js:100:50)`;\n\n        const errorEvent = {\n          message: 'Test error',\n          filename: 'https://example.com/app.js',\n          lineno: 100,\n          colno: 50,\n          error,\n          isTrusted: true,\n        } as ErrorEvent;\n\n        errorHandler?.(errorEvent);\n\n        // eslint-disable-next-line @typescript-eslint/unbound-method\n        expect(mockDiagnosticsClient.recordEvent).not.toHaveBeenCalled();\n      });\n\n      it('should handle error event without error object', () => {\n        const errorEvent = {\n          message: 'Script error',\n          filename: 'https://cdn.amplitude.com/libs/amplitude.js',\n          lineno: 0,\n          colno: 0,\n          error: null,\n          isTrusted: true,\n        } as ErrorEvent;\n\n        errorHandler?.(errorEvent);\n\n        // eslint-disable-next-line @typescript-eslint/unbound-method\n        expect(mockDiagnosticsClient.recordEvent).toHaveBeenCalledWith(EVENT_NAME_ERROR_UNCAUGHT, {\n          type: 'error',\n          message: 'Script error',\n          filename: 'https://cdn.amplitude.com/libs/amplitude.js',\n          error_name: undefined,\n          stack: undefined,\n          colno: 0,\n          lineno: 0,\n          isTrusted: true,\n          matchReason: 'filename',\n        });\n      });\n    });\n\n    describe('PromiseRejectionEvent handling', () => {\n      it('should capture unhandled rejection when stack contains SDK script URL', () => {\n        const error = new Error('Promise rejected');\n        error.stack = `Error: Promise rejected\n    at async functionName (https://cdn.amplitude.com/libs/amplitude.js:100:50)`;\n\n        const rejectionEvent = {\n          reason: error,\n          isTrusted: true,\n        } as PromiseRejectionEvent;\n\n        rejectionHandler?.(rejectionEvent);\n\n        // eslint-disable-next-line @typescript-eslint/unbound-method\n        expect(mockDiagnosticsClient.recordEvent).toHaveBeenCalledWith(EVENT_NAME_ERROR_UNCAUGHT, {\n          type: 'unhandledrejection',\n          message: 'Promise rejected',\n          filename: 'https://cdn.amplitude.com/libs/amplitude.js:100:50',\n          error_name: 'Error',\n          stack: error.stack,\n          isTrusted: true,\n          matchReason: 'filename',\n        });\n      });\n\n      it('should NOT capture unhandled rejection when stack does not contain SDK script URL', () => {\n        const error = new Error('Promise rejected');\n        error.stack = `Error: Promise rejected\n    at async functionName (https://example.com/app.js:100:50)`;\n\n        const rejectionEvent = {\n          reason: error,\n          isTrusted: true,\n        } as PromiseRejectionEvent;\n\n        rejectionHandler?.(rejectionEvent);\n\n        // eslint-disable-next-line @typescript-eslint/unbound-method\n        expect(mockDiagnosticsClient.recordEvent).not.toHaveBeenCalled();\n      });\n\n      it('should handle non-Error rejection reason as string', () => {\n        // First need to set up a scenario where it would match\n        // Since reason is not an Error, stack will be undefined, so it won't match\n        const rejectionEvent = {\n          reason: 'Simple string rejection',\n          isTrusted: true,\n        } as PromiseRejectionEvent;\n\n        rejectionHandler?.(rejectionEvent);\n\n        // Should not be captured because there's no way to match without stack\n        // eslint-disable-next-line @typescript-eslint/unbound-method\n        expect(mockDiagnosticsClient.recordEvent).not.toHaveBeenCalled();\n      });\n\n      it('should handle object rejection reason by stringifying', () => {\n        const rejectionEvent = {\n          reason: { code: 'ERR_001', details: 'Something went wrong' },\n          isTrusted: true,\n        } as PromiseRejectionEvent;\n\n        rejectionHandler?.(rejectionEvent);\n\n        // Should not be captured because there's no way to match without stack\n        // eslint-disable-next-line @typescript-eslint/unbound-method\n        expect(mockDiagnosticsClient.recordEvent).not.toHaveBeenCalled();\n      });\n    });\n  });\n\n  describe('without registered script URL', () => {\n    beforeEach(() => {\n      // Don't register script URL\n      enableSdkErrorListeners(mockDiagnosticsClient);\n    });\n\n    it('should NOT capture any errors when no script URL is registered', () => {\n      const error = new Error('Test error');\n      const errorEvent = {\n        message: 'Test error',\n        filename: 'https://cdn.amplitude.com/libs/amplitude.js',\n        lineno: 100,\n        colno: 50,\n        error,\n        isTrusted: true,\n      } as ErrorEvent;\n\n      errorHandler?.(errorEvent);\n\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockDiagnosticsClient.recordEvent).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('URL normalization edge cases', () => {\n    it('should handle filename with query params when matching', () => {\n      registerSdkLoaderMetadata({ scriptUrl: 'https://cdn.amplitude.com/libs/amplitude.js' });\n      enableSdkErrorListeners(mockDiagnosticsClient);\n\n      const error = new Error('Test error');\n      const errorEvent = {\n        message: 'Test error',\n        filename: 'https://cdn.amplitude.com/libs/amplitude.js?v=2.0.0',\n        lineno: 100,\n        colno: 50,\n        error,\n        isTrusted: true,\n      } as ErrorEvent;\n\n      errorHandler?.(errorEvent);\n\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockDiagnosticsClient.recordEvent).toHaveBeenCalledWith(\n        EVENT_NAME_ERROR_UNCAUGHT,\n        expect.objectContaining({\n          matchReason: 'filename',\n        }),\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/event-bridge/event-bridge-channel.test.ts",
    "content": "import { EventBridgeChannel } from '../../src/event-bridge/event-bridge-channel';\n\ndescribe('EventBridgeChannel', () => {\n  describe('sendEvent', () => {\n    test('should send event', () => {\n      const eventBridge = new EventBridgeChannel('channel');\n      const event1 = {\n        event_type: 'event_type',\n      };\n      const event2 = {\n        event_type: 'event_type',\n      };\n      const receiver1 = {\n        receive: jest.fn(),\n      };\n      const receiver2 = {\n        receive: jest.fn(),\n      };\n\n      // send without receiver\n      eventBridge.sendEvent(event1);\n      expect(receiver1.receive).toHaveBeenCalledTimes(0);\n      expect(receiver2.receive).toHaveBeenCalledTimes(0);\n\n      // register receiver\n      eventBridge.setReceiver(receiver1);\n      expect(receiver1.receive).toHaveBeenCalledTimes(1);\n\n      // register receiver, but not accepted\n      eventBridge.setReceiver(receiver2);\n      expect(receiver2.receive).toHaveBeenCalledTimes(0);\n\n      // send with receiver\n      eventBridge.sendEvent(event2);\n      expect(receiver1.receive).toHaveBeenCalledTimes(2);\n      expect(receiver2.receive).toHaveBeenCalledTimes(0);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/event-bridge/event-bridge-container.test.ts",
    "content": "import { EventBridgeContainer } from '../../src/event-bridge/event-bridge-container';\nimport * as EventBridgeModule from '../../src/event-bridge/event-bridge';\n\ndescribe('EventBridgeContainer', () => {\n  beforeEach(() => {\n    EventBridgeContainer.instances = {};\n  });\n\n  describe('getInstance', () => {\n    test('should create and reuse existing instance', () => {\n      const eventBridge = {\n        eventBridgeChannels: {},\n        sendEvent: jest.fn(),\n        setReceiver: jest.fn(),\n      };\n      jest.spyOn(EventBridgeModule, 'EventBridge').mockReturnValueOnce(eventBridge);\n      expect(Object.keys(EventBridgeContainer.instances).length).toBe(0);\n      // creates new instance\n      expect(EventBridgeContainer.getInstance('default')).toBe(eventBridge);\n      expect(Object.keys(EventBridgeContainer.instances).length).toBe(1);\n\n      // reuses existing instance\n      expect(EventBridgeContainer.getInstance('default')).toBe(eventBridge);\n      expect(Object.keys(EventBridgeContainer.instances).length).toBe(1);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/event-bridge/event-bridge.test.ts",
    "content": "import { EventBridge } from '../../src/event-bridge/event-bridge';\nimport * as EventBridgeChannelModule from '../../src/event-bridge/event-bridge-channel';\n\ndescribe('EventBridge', () => {\n  describe('sendEvent', () => {\n    test('should send event', () => {\n      const sendEvent = jest.fn();\n      const setReceiver = jest.fn();\n      jest.spyOn(EventBridgeChannelModule, 'EventBridgeChannel').mockReturnValueOnce({\n        channel: 'channel',\n        queue: [],\n        receiver: undefined,\n        sendEvent,\n        setReceiver,\n      });\n      const eventBridge = new EventBridge();\n\n      // creates new bridge for channel\n      eventBridge.sendEvent('channel', { event_type: 'event_type' });\n      expect(sendEvent).toHaveBeenCalledTimes(1);\n\n      // reuses existing bridge for channel\n      eventBridge.sendEvent('channel', { event_type: 'event_type' });\n      expect(sendEvent).toHaveBeenCalledTimes(2);\n    });\n  });\n\n  describe('setReceiver', () => {\n    test('should set receiver', () => {\n      const sendEvent = jest.fn();\n      const setReceiver = jest.fn();\n      jest.spyOn(EventBridgeChannelModule, 'EventBridgeChannel').mockReturnValueOnce({\n        channel: 'channel',\n        queue: [],\n        receiver: undefined,\n        sendEvent,\n        setReceiver,\n      });\n      const eventBridge = new EventBridge();\n      const receiver = {\n        receive: jest.fn(),\n      };\n\n      // creates new bridge for channel\n      eventBridge.setReceiver('channel', receiver);\n      expect(setReceiver).toHaveBeenCalledTimes(1);\n\n      // reuses existing bridge for channel\n      eventBridge.setReceiver('channel', receiver);\n      expect(setReceiver).toHaveBeenCalledTimes(2);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/global-scope.test.ts",
    "content": "/**\n * @jest-environment jsdom\n */\n\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\nimport { getGlobalScope } from '../src/global-scope';\n\ndescribe('getGlobalScope', () => {\n  let originalGlobalThis: any;\n\n  beforeEach(() => {\n    originalGlobalThis = globalThis;\n  });\n\n  afterEach(() => {\n    // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n    // @ts-ignore\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n    globalThis = originalGlobalThis;\n    delete (globalThis as any).ampIntegrationContext;\n  });\n\n  test('returns ampIntegrationContext if it exists', () => {\n    (globalThis as any).ampIntegrationContext = { someKey: 'someValue' };\n    expect(getGlobalScope()).toBe((globalThis as any).ampIntegrationContext);\n  });\n\n  test('returns globalThis if ampIntegrationContext does not exist', () => {\n    const scope = getGlobalScope();\n    // Need to use Object.is because expect(scope).toBe(globalThis) will throw an error\n    expect(Object.is(scope, globalThis)).toBeTruthy();\n  });\n\n  test('should return window if globalThis is undefined and window is defined', () => {\n    // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n    // @ts-ignore\n    globalThis = undefined;\n\n    const scope = getGlobalScope();\n\n    // Note: We NEED to reassign globalThis to its original state because the jest expect function requires it\n    // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n    // @ts-ignore\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n    globalThis = originalGlobalThis;\n    // Need to use Object.is because expect(scope).toBe(globalThis) will throw an error\n    expect(Object.is(scope, window)).toBeTruthy();\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/helpers/default.ts",
    "content": "import { getDefaultConfig } from '../../src/config';\nimport { IConfig } from '../../src/types/config/core-config';\n\nexport const useDefaultConfig = (): IConfig => ({\n  apiKey: API_KEY,\n  transportProvider: {\n    send: () => Promise.resolve(null),\n  },\n  storageProvider: {\n    isEnabled: async () => true,\n    get: async () => undefined,\n    set: async () => undefined,\n    remove: async () => undefined,\n    reset: async () => undefined,\n    getRaw: async () => undefined,\n  },\n  ...getDefaultConfig(),\n});\n\nexport const API_KEY = 'apiKey';\nexport const USER_ID = 'userId';\nexport const DEVICE_ID = 'deviceId';\n\n/*\nThere is no way to figure out the state of a promise with normal API.\nThis helper expose the state of a promise via race.\nhttps://stackoverflow.com/a/35820220\n\nExample:\nconst a = Promise.resolve();\nconst b = Promise.reject();\nconst c = new Promise(() => {});\n\npromiseState(a).then(state => console.log(state)); // fulfilled\npromiseState(b).then(state => console.log(state)); // rejected\npromiseState(c).then(state => console.log(state)); // pending\n*/\nexport function promiseState(p: Promise<any>) {\n  const t = {};\n  return Promise.race([p, t]).then(\n    (v) => (v === t ? 'pending' : 'fulfilled'),\n    () => 'rejected',\n  );\n}\n"
  },
  {
    "path": "packages/analytics-core/test/helpers/util.ts",
    "content": "import { CookieStorage } from '../../src/storage/cookie';\n\nexport const uuidPattern = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/;\n\n/**\n * Cookie names that are allowed to be set.\n *\n * IMPORTANT: do not add or modify these without good reason and\n * without very careful consideration. Cookie names should be very\n * stable and not changed without a good reason.\n */\nconst LEGAL_COOKIE_NAMES: Record<string, boolean> = {\n  AMP_TEST: true,\n  AMP_TLDTEST: true,\n};\n\nexport function enforceStrictCookieNames() {\n  const Proto = CookieStorage.prototype as unknown as { setSync: (key: string, value: unknown) => void };\n  const originalSetSync = Proto.setSync;\n  Proto.setSync = function (this: unknown, key: string, value: unknown) {\n    if (!LEGAL_COOKIE_NAMES[key]) {\n      throw new Error(`Illegal cookie name: ${key}`);\n    }\n    return originalSetSync.call(this, key, value);\n  };\n\n  return () => {\n    Proto.setSync = originalSetSync;\n  };\n}\n"
  },
  {
    "path": "packages/analytics-core/test/identify.test.ts",
    "content": "import { UNSET_VALUE } from '../src/types/constants';\nimport { IdentifyOperation } from '../src/types/event/event';\nimport { Identify } from '../src/index';\n\ndescribe('Identify class', () => {\n  test('should see user property when using set', () => {\n    const identify = new Identify();\n    identify.set('PROPERTY_NAME', 'PROPERTY_VALUE');\n    const properties = identify.getUserProperties();\n\n    const expectedProperties = {\n      [IdentifyOperation.SET]: { PROPERTY_NAME: 'PROPERTY_VALUE' },\n    };\n\n    expect(properties).toStrictEqual(expectedProperties);\n  });\n\n  test('should see user property when using set once', () => {\n    const identify = new Identify();\n    identify.setOnce('PROPERTY_NAME', 'PROPERTY_VALUE');\n\n    const expectedProperties = {\n      [IdentifyOperation.SET_ONCE]: { PROPERTY_NAME: 'PROPERTY_VALUE' },\n    };\n\n    expect(identify.getUserProperties()).toStrictEqual(expectedProperties);\n  });\n\n  test('should see user property when using add', () => {\n    const identify = new Identify();\n    identify.add('PROPERTY_NAME', 1);\n    const expectedProperties = {\n      [IdentifyOperation.ADD]: { PROPERTY_NAME: 1 },\n    };\n\n    expect(identify.getUserProperties()).toStrictEqual(expectedProperties);\n  });\n\n  test('should see user property when using append', () => {\n    const identify = new Identify();\n    identify.append('PROPERTY_NAME', 'PROPERTY_VALUE');\n    const expectedProperties = {\n      [IdentifyOperation.APPEND]: { PROPERTY_NAME: 'PROPERTY_VALUE' },\n    };\n\n    expect(identify.getUserProperties()).toStrictEqual(expectedProperties);\n  });\n\n  test('should see user property when using prepend', () => {\n    const identify = new Identify();\n    identify.prepend('PROPERTY_NAME', 'PROPERTY_VALUE');\n    const expectedProperties = {\n      [IdentifyOperation.PREPEND]: { PROPERTY_NAME: 'PROPERTY_VALUE' },\n    };\n\n    expect(identify.getUserProperties()).toStrictEqual(expectedProperties);\n  });\n\n  test('should see user property when using post-insert', () => {\n    const identify = new Identify();\n    identify.postInsert('PROPERTY_NAME', 'PROPERTY_VALUE');\n    const expectedProperties = {\n      [IdentifyOperation.POSTINSERT]: { PROPERTY_NAME: 'PROPERTY_VALUE' },\n    };\n\n    expect(identify.getUserProperties()).toStrictEqual(expectedProperties);\n  });\n\n  test('should see user property when using pre-insert', () => {\n    const identify = new Identify();\n    identify.preInsert('PROPERTY_NAME', 'PROPERTY_VALUE');\n    const expectedProperties = {\n      [IdentifyOperation.PREINSERT]: { PROPERTY_NAME: 'PROPERTY_VALUE' },\n    };\n\n    expect(identify.getUserProperties()).toStrictEqual(expectedProperties);\n  });\n\n  test('should see user property when using remove', () => {\n    const identify = new Identify();\n    identify.remove('PROPERTY_NAME', 'PROPERTY_VALUE');\n    const expectedProperties = {\n      [IdentifyOperation.REMOVE]: { PROPERTY_NAME: 'PROPERTY_VALUE' },\n    };\n\n    expect(identify.getUserProperties()).toStrictEqual(expectedProperties);\n  });\n\n  test('should see user property when using unset', () => {\n    const identify = new Identify();\n    identify.unset('PROPERTY_NAME');\n    const expectedProperties = {\n      [IdentifyOperation.UNSET]: { PROPERTY_NAME: UNSET_VALUE },\n    };\n\n    expect(identify.getUserProperties()).toStrictEqual(expectedProperties);\n  });\n\n  test('should see user property when using clear all', () => {\n    const identify = new Identify();\n    identify.clearAll();\n    const expectedProperties = {\n      [IdentifyOperation.CLEAR_ALL]: UNSET_VALUE,\n    };\n\n    expect(identify.getUserProperties()).toStrictEqual(expectedProperties);\n  });\n\n  test('should allow multiple properties to be added', () => {\n    const identify = new Identify();\n    identify.set('PROPERTY_NAME', 'PROPERTY_VALUE');\n    identify.set('PROPERTY_NAME_TWO', 1);\n    identify.append('PROPERTY_NAME_THREE', 'PROPERTY_VALUE');\n    const expectedProperties = {\n      [IdentifyOperation.SET]: {\n        PROPERTY_NAME: 'PROPERTY_VALUE',\n        PROPERTY_NAME_TWO: 1,\n      },\n      [IdentifyOperation.APPEND]: {\n        PROPERTY_NAME_THREE: 'PROPERTY_VALUE',\n      },\n    };\n\n    expect(identify.getUserProperties()).toStrictEqual(expectedProperties);\n  });\n\n  test('should not allow non-string property names', () => {\n    const identify = new Identify();\n    // this should be ignored\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n    identify.set(3 as any, 'PROPERTY_VALUE');\n    const expectedProperties = {};\n\n    expect(identify.getUserProperties()).toStrictEqual(expectedProperties);\n  });\n\n  test('should not set any new properties after clear all', () => {\n    const identify = new Identify();\n    identify.clearAll().set('PROPERTY_NAME', 'PROPERTY_VALUE');\n    const expectedProperties = {\n      [IdentifyOperation.CLEAR_ALL]: UNSET_VALUE,\n    };\n\n    expect(identify.getUserProperties()).toStrictEqual(expectedProperties);\n  });\n\n  test('should not set any properties twice', () => {\n    const identify = new Identify();\n    identify.set('PROPERTY_NAME', 'PROPERTY_VALUE');\n    // these two should be ignored\n    identify.set('PROPERTY_NAME', 1);\n    identify.append('PROPERTY_NAME', 'PROPERTY_VALUE');\n    const expectedProperties = {\n      [IdentifyOperation.SET]: { PROPERTY_NAME: 'PROPERTY_VALUE' },\n    };\n\n    expect(identify.getUserProperties()).toStrictEqual(expectedProperties);\n  });\n\n  test('should not allow non-numeric add values', () => {\n    const identify = new Identify();\n    // this should be ignored\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n    identify.add('PROPERTY_NAME', 'PROPERTY_VALUE' as any);\n    const expectedProperties = {};\n\n    expect(identify.getUserProperties()).toStrictEqual(expectedProperties);\n  });\n\n  test('should not allow to set a key to null', () => {\n    const identify = new Identify();\n    // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n    // @ts-ignore bypassing ts rules to test unexpected input\n    identify.set('PROPERTY_NAME', null);\n    const expectedProperties = {};\n\n    expect(identify.getUserProperties()).toStrictEqual(expectedProperties);\n  });\n\n  test('should not allow to set a key to undefined', () => {\n    const identify = new Identify();\n    // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n    // @ts-ignore bypassing ts rules to test unexpected input\n    identify.set('PROPERTY_NAME', undefined);\n    const expectedProperties = {};\n\n    expect(identify.getUserProperties()).toStrictEqual(expectedProperties);\n  });\n\n  test('should allow to set an array of objects', () => {\n    const identify = new Identify();\n    const propertyValue = [\n      {\n        key1: 'value1',\n        key2: 'value2',\n      },\n      {\n        key1: 'value3',\n        key2: 'value4',\n      },\n    ];\n    // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n    // @ts-ignore bypassing ts rules to test unexpected input\n    identify.set('PROPERTY_NAME', propertyValue);\n    const expectedProperties = {\n      [IdentifyOperation.SET]: { PROPERTY_NAME: propertyValue },\n    };\n\n    expect(identify.getUserProperties()).toStrictEqual(expectedProperties);\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/index.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unsafe-member-access */\nimport {\n  AmplitudeCore,\n  BaseTransport,\n  Destination,\n  Config,\n  Logger,\n  LogLevel,\n  AMPLITUDE_PREFIX,\n  STORAGE_PREFIX,\n  returnWrapper,\n  debugWrapper,\n  getClientLogConfig,\n  getClientStates,\n  UUID,\n  MemoryStorage,\n  createIdentifyEvent,\n  RequestMetadata,\n  getGlobalScope,\n  getAnalyticsConnector,\n  setConnectorDeviceId,\n  setConnectorUserId,\n  isNewSession,\n  getQueryParams,\n  getCookieName,\n  getOldCookieName,\n  getLanguage,\n  IdentityEventSender,\n  compressToGzipArrayBuffer,\n  MIN_GZIP_UPLOAD_BODY_SIZE_BYTES,\n  CookieStorage,\n  FetchTransport,\n  isCompressionStreamAvailable,\n  RemoteConfigClient,\n  Identify,\n  Revenue,\n  getStorageKey,\n  OfflineDisabled,\n  Status,\n  DEFAULT_ACTION_CLICK_ALLOWLIST,\n  DEFAULT_DEAD_CLICK_ALLOWLIST,\n  DEFAULT_RAGE_CLICK_ALLOWLIST,\n  DEFAULT_EXPOSURE_DURATION,\n  DEFAULT_ERROR_CLICK_ALLOWLIST,\n  DEFAULT_RAGE_CLICK_OUT_OF_BOUNDS_THRESHOLD,\n  DEFAULT_CSS_SELECTOR_ALLOWLIST,\n  DEFAULT_RAGE_CLICK_THRESHOLD,\n  DEFAULT_RAGE_CLICK_WINDOW_MS,\n  DEFAULT_DEAD_CLICK_WINDOW_MS,\n  DEFAULT_DATA_ATTRIBUTE_PREFIX,\n  RevenueProperty,\n  IdentifyOperation,\n  SpecialEventType,\n  ServerZone,\n  BASE_CAMPAIGN,\n  CampaignParser,\n  EMPTY_VALUE,\n  MKTG,\n  getPageTitle,\n  TEXT_MASK_ATTRIBUTE,\n  MASKED_TEXT_VALUE,\n  replaceSensitiveString,\n  CC_REGEX,\n  SSN_REGEX,\n  EMAIL_REGEX,\n  generateHashCode,\n  isTimestampInSample,\n  DiagnosticsClient,\n  registerSdkLoaderMetadata,\n  getOrCreateWindowMessenger,\n  enableBackgroundCapture,\n  AMPLITUDE_ORIGIN,\n  AMPLITUDE_ORIGIN_EU,\n  AMPLITUDE_ORIGIN_STAGING,\n  AMPLITUDE_ORIGINS_MAP,\n  AMPLITUDE_BACKGROUND_CAPTURE_SCRIPT_URL,\n  EXCLUDE_INTERNAL_REFERRERS_CONDITIONS,\n  omitUndefined,\n} from '../src/index';\n\ndescribe('index', () => {\n  test('should expose apis', () => {\n    const client = new AmplitudeCore();\n    expect(typeof (client as any)._init).toBe('function');\n    expect(typeof client.track).toBe('function');\n    expect(typeof client.logEvent).toBe('function');\n    expect(typeof client.identify).toBe('function');\n    expect(typeof client.groupIdentify).toBe('function');\n    expect(typeof client.setGroup).toBe('function');\n    expect(typeof client.setOptOut).toBe('function');\n    expect(typeof client.revenue).toBe('function');\n    expect(typeof client.add).toBe('function');\n    expect(typeof client.remove).toBe('function');\n    expect(typeof Identify).toBe('function');\n    expect(typeof Revenue).toBe('function');\n    expect(typeof BaseTransport).toBe('function');\n    expect(typeof Destination).toBe('function');\n    expect(typeof Config).toBe('function');\n    expect(typeof RequestMetadata).toEqual('function');\n    expect(typeof Logger).toBe('function');\n    expect(typeof LogLevel).toBe('object');\n    expect(typeof returnWrapper).toBe('function');\n    expect(typeof debugWrapper).toBe('function');\n    expect(typeof getClientLogConfig).toBe('function');\n    expect(typeof getClientStates).toBe('function');\n    expect(typeof UUID).toBe('function');\n    expect(typeof MemoryStorage).toBe('function');\n    expect(typeof createIdentifyEvent).toBe('function');\n    expect(AMPLITUDE_PREFIX).toBe('AMP');\n    expect(STORAGE_PREFIX).toBe('AMP_unsent');\n    expect(typeof getStorageKey).toBe('function');\n    expect(typeof getGlobalScope).toBe('function');\n    expect(typeof getAnalyticsConnector).toBe('function');\n    expect(typeof setConnectorDeviceId).toBe('function');\n    expect(typeof setConnectorUserId).toBe('function');\n    expect(typeof isNewSession).toBe('function');\n    expect(typeof getQueryParams).toBe('function');\n    expect(typeof getCookieName).toBe('function');\n    expect(typeof getOldCookieName).toBe('function');\n    expect(typeof getLanguage).toBe('function');\n    expect(typeof IdentityEventSender).toBe('function');\n    expect(() => new IdentityEventSender()).not.toThrow();\n    expect(typeof compressToGzipArrayBuffer).toBe('function');\n    expect(MIN_GZIP_UPLOAD_BODY_SIZE_BYTES).toBe(2 * 1024);\n    expect(typeof CookieStorage).toBe('function');\n    expect(() => new CookieStorage()).not.toThrow();\n    expect(typeof FetchTransport).toBe('function');\n    expect(typeof isCompressionStreamAvailable).toBe('function');\n    expect(() => new FetchTransport()).not.toThrow();\n    expect(typeof RemoteConfigClient).toBe('function');\n    expect(() => new RemoteConfigClient('api-key', new Logger())).not.toThrow();\n    expect(OfflineDisabled).toBe(null);\n    expect(typeof OfflineDisabled).toBe('object');\n    expect(typeof Status).toBe('object');\n    expect(typeof DEFAULT_ACTION_CLICK_ALLOWLIST).toBe('object');\n    expect(typeof DEFAULT_CSS_SELECTOR_ALLOWLIST).toBe('object');\n    expect(typeof DEFAULT_EXPOSURE_DURATION).toBe('number');\n    expect(typeof DEFAULT_DEAD_CLICK_ALLOWLIST).toBe('object');\n    expect(typeof DEFAULT_RAGE_CLICK_ALLOWLIST).toBe('object');\n    expect(typeof DEFAULT_DATA_ATTRIBUTE_PREFIX).toBe('string');\n    expect(typeof RevenueProperty).toBe('object');\n    expect(typeof IdentifyOperation).toBe('object');\n    expect(typeof SpecialEventType).toBe('object');\n    expect(typeof ServerZone).toBe('object');\n    expect(typeof DEFAULT_ERROR_CLICK_ALLOWLIST).toBe('object');\n    expect(typeof DEFAULT_RAGE_CLICK_OUT_OF_BOUNDS_THRESHOLD).toBe('number');\n    expect(DEFAULT_RAGE_CLICK_THRESHOLD).toBeGreaterThan(1);\n    expect(DEFAULT_RAGE_CLICK_WINDOW_MS).toBeGreaterThan(1);\n    expect(DEFAULT_DEAD_CLICK_WINDOW_MS).toBeGreaterThan(1);\n    expect(EMPTY_VALUE).toBe('EMPTY');\n    expect(typeof BASE_CAMPAIGN).toBe('object');\n    expect(typeof MKTG).toBe('string');\n    expect(typeof CampaignParser).toBe('function');\n    expect(typeof getPageTitle).toBe('function');\n    expect(TEXT_MASK_ATTRIBUTE).toBe('data-amp-mask');\n    expect(MASKED_TEXT_VALUE).toBe('*****');\n    expect(typeof replaceSensitiveString).toBe('function');\n    expect(CC_REGEX).toBeInstanceOf(RegExp);\n    expect(SSN_REGEX).toBeInstanceOf(RegExp);\n    expect(EMAIL_REGEX).toBeInstanceOf(RegExp);\n    expect(typeof generateHashCode).toBe('function');\n    expect(typeof isTimestampInSample).toBe('function');\n    expect(typeof DiagnosticsClient).toBe('function');\n    expect(typeof registerSdkLoaderMetadata).toBe('function');\n    expect(typeof getOrCreateWindowMessenger).toBe('function');\n    expect(typeof enableBackgroundCapture).toBe('function');\n    expect(typeof AMPLITUDE_ORIGIN).toBe('string');\n    expect(typeof AMPLITUDE_ORIGIN_EU).toBe('string');\n    expect(typeof AMPLITUDE_ORIGIN_STAGING).toBe('string');\n    expect(typeof AMPLITUDE_ORIGINS_MAP).toBe('object');\n    expect(typeof AMPLITUDE_BACKGROUND_CAPTURE_SCRIPT_URL).toBe('string');\n    expect(typeof EXCLUDE_INTERNAL_REFERRERS_CONDITIONS).toBe('object');\n    expect(typeof omitUndefined).toBe('function');\n  });\n\n  describe('EXCLUDE_INTERNAL_REFERRERS_CONDITIONS export', () => {\n    test('should be an object', () => {\n      expect(typeof EXCLUDE_INTERNAL_REFERRERS_CONDITIONS).toBe('object');\n    });\n    test('keys and values should be strings with same value', () => {\n      Object.entries(EXCLUDE_INTERNAL_REFERRERS_CONDITIONS).forEach(([key, value]) => {\n        expect(key).toBe(value);\n      });\n    });\n  });\n\n  describe('replaceSensitiveString export', () => {\n    test('should mask credit card numbers', () => {\n      const result = replaceSensitiveString('CC: 4111111111111111');\n      expect(result).toContain(MASKED_TEXT_VALUE);\n    });\n\n    test('should mask SSN', () => {\n      const result = replaceSensitiveString('SSN: 123-45-6789');\n      expect(result).toContain(MASKED_TEXT_VALUE);\n    });\n\n    test('should mask email addresses', () => {\n      const result = replaceSensitiveString('Email: user@example.com');\n      expect(result).toContain(MASKED_TEXT_VALUE);\n    });\n\n    test('should work with custom patterns', () => {\n      const customPattern = /secret/gi;\n      const result = replaceSensitiveString('This is secret', [customPattern]);\n      expect(result).toContain(MASKED_TEXT_VALUE);\n    });\n  });\n\n  describe('Regex exports', () => {\n    test('CC_REGEX should match credit card numbers', () => {\n      expect(CC_REGEX.test('4111111111111111')).toBe(true);\n      expect(CC_REGEX.test('4111 1111 1111 1111')).toBe(true);\n    });\n\n    test('SSN_REGEX should match social security numbers', () => {\n      SSN_REGEX.lastIndex = 0;\n      expect(SSN_REGEX.test('123-45-6789')).toBe(true);\n      SSN_REGEX.lastIndex = 0;\n      expect(SSN_REGEX.test('123456789')).toBe(true);\n    });\n\n    test('EMAIL_REGEX should match email addresses', () => {\n      EMAIL_REGEX.lastIndex = 0;\n      expect(EMAIL_REGEX.test('user@example.com')).toBe(true);\n      EMAIL_REGEX.lastIndex = 0;\n      expect(EMAIL_REGEX.test('test.email@domain.co.uk')).toBe(true);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/language.test.ts",
    "content": "/**\n * @jest-environment jsdom\n */\n\nimport { getLanguage } from '../src/language';\ninterface Navigator {\n  language: string | undefined;\n  languages: string[] | undefined;\n  userLanguage: string | undefined;\n}\n\ndescribe('language', () => {\n  // Simulates other browser version\n  // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n  // @ts-ignore\n  const nav: Navigator = navigator;\n\n  beforeAll(() => {\n    Object.defineProperty(nav, 'userLanguage', {\n      get: () => '',\n      configurable: true,\n      enumerable: true,\n    });\n  });\n\n  afterAll(() => {\n    if (nav.userLanguage) {\n      delete nav.userLanguage;\n    }\n  });\n\n  test('should return a language', () => {\n    enableNavigatorLanguageProperties(['languages', 'language', 'userLanguage']);\n    expect(getLanguage()).not.toBeNull();\n  });\n\n  test('should prioritize the first language of navigator.languages', () => {\n    enableNavigatorLanguageProperties(['languages', 'language', 'userLanguage']);\n    expect(getLanguage()).toBe('some-locale');\n  });\n\n  test('should secondly use the language of navigator.language', () => {\n    enableNavigatorLanguageProperties(['language', 'userLanguage']);\n    expect(getLanguage()).toBe('some-second-locale');\n  });\n\n  test('should thirdly use the language of navigator.userLanguage', () => {\n    enableNavigatorLanguageProperties(['userLanguage']);\n    expect(getLanguage()).toBe('some-third-locale');\n  });\n\n  test('should return empty string if navigator language is not set', () => {\n    enableNavigatorLanguageProperties([]);\n    expect(getLanguage()).toBe('');\n  });\n\n  test('should return empty string if navigator is not set', () => {\n    jest.spyOn(window as any, 'navigator', 'get').mockReturnValue(undefined);\n    expect(getLanguage()).toBe('');\n  });\n\n  function enableNavigatorLanguageProperties(properties: Array<'languages' | 'language' | 'userLanguage'>) {\n    jest\n      .spyOn(nav, 'languages', 'get')\n      .mockReturnValue(properties.includes('languages') ? ['some-locale', 'some-other-locale'] : undefined);\n    jest\n      .spyOn(nav, 'language', 'get')\n      .mockReturnValue(properties.includes('language') ? 'some-second-locale' : undefined);\n    jest\n      .spyOn(nav, 'userLanguage', 'get')\n      .mockReturnValue(properties.includes('userLanguage') ? 'some-third-locale' : undefined);\n  }\n});\n"
  },
  {
    "path": "packages/analytics-core/test/logger.test.ts",
    "content": "import { LogLevel } from '../src/types/loglevel';\nimport { Logger } from '../src/logger';\n\njest.unmock('../src/logger');\n\ndescribe('logger', () => {\n  describe('enable/disable', () => {\n    test('should set log level to NONE', () => {\n      const logger = new Logger();\n      expect(logger.logLevel).toBe(LogLevel.None);\n      logger.enable();\n      expect(logger.logLevel).toBe(LogLevel.Warn);\n      logger.enable(LogLevel.Error);\n      expect(logger.logLevel).toBe(LogLevel.Error);\n      logger.disable();\n      expect(logger.logLevel).toBe(LogLevel.None);\n    });\n  });\n\n  describe('log', () => {\n    test('should log event', () => {\n      const logger = new Logger();\n      logger.enable(LogLevel.Verbose);\n      const log = jest.spyOn(console, 'log').mockReturnValueOnce(undefined);\n      logger.log('Success');\n      expect(log).toHaveBeenCalledTimes(1);\n      expect(log).toHaveBeenCalledWith('Amplitude Logger [Log]: Success');\n    });\n\n    test('should not log event', () => {\n      const logger = new Logger();\n      logger.enable(LogLevel.Warn);\n      const log = jest.spyOn(console, 'log');\n      logger.log('Success');\n      expect(log).toHaveBeenCalledTimes(0);\n    });\n  });\n\n  describe('warn', () => {\n    test('should log event', () => {\n      const logger = new Logger();\n      logger.enable(LogLevel.Warn);\n      const log = jest.spyOn(console, 'warn').mockReturnValueOnce(undefined);\n      logger.warn('Success');\n      expect(log).toHaveBeenCalledTimes(1);\n      expect(log).toHaveBeenCalledWith('Amplitude Logger [Warn]: Success');\n    });\n\n    test('should not log event', () => {\n      const logger = new Logger();\n      logger.enable(LogLevel.Error);\n      const log = jest.spyOn(console, 'warn');\n      logger.warn('Success');\n      expect(log).toHaveBeenCalledTimes(0);\n    });\n  });\n\n  describe('error', () => {\n    test('should log event', () => {\n      const logger = new Logger();\n      logger.enable(LogLevel.Error);\n      const log = jest.spyOn(console, 'error').mockReturnValueOnce(undefined);\n      logger.error('Success');\n      expect(log).toHaveBeenCalledTimes(1);\n      expect(log).toHaveBeenCalledWith('Amplitude Logger [Error]: Success');\n    });\n\n    test('should not log event', () => {\n      const logger = new Logger();\n      logger.enable(LogLevel.None);\n      const log = jest.spyOn(console, 'error');\n      logger.error('Success');\n      expect(log).toHaveBeenCalledTimes(0);\n    });\n  });\n\n  describe('debug', () => {\n    test('should log event', () => {\n      const logger = new Logger();\n      logger.enable(LogLevel.Debug);\n      const log = jest.spyOn(console, 'log').mockReturnValueOnce(undefined);\n      logger.debug('Success');\n      expect(log).toHaveBeenCalledTimes(1);\n      expect(log).toHaveBeenCalledWith('Amplitude Logger [Debug]: Success');\n    });\n\n    test('should not log event', () => {\n      const logger = new Logger();\n      logger.enable(LogLevel.Verbose);\n      const log = jest.spyOn(console, 'log');\n      logger.debug('Success');\n      expect(log).toHaveBeenCalledTimes(0);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/messenger/background-capture.test.ts",
    "content": "/**\n * @jest-environment jsdom\n */\n\n/* eslint-disable @typescript-eslint/unbound-method */\nimport { enableBackgroundCapture } from '../../src/messenger/background-capture';\nimport type { BaseWindowMessenger, ActionHandler } from '../../src/messenger/base-window-messenger';\nimport { AMPLITUDE_BACKGROUND_CAPTURE_SCRIPT_URL } from '../../src/messenger/constants';\n\nconst BG_CAPTURE_BRAND = '__AMPLITUDE_BACKGROUND_CAPTURE__';\n\nfunction createMockMessenger(overrides: Partial<BaseWindowMessenger> = {}): BaseWindowMessenger {\n  return {\n    endpoint: 'https://app.amplitude.com',\n    logger: {\n      debug: jest.fn(),\n      warn: jest.fn(),\n      log: jest.fn(),\n      error: jest.fn(),\n      enable: jest.fn(),\n      disable: jest.fn(),\n    },\n    notify: jest.fn(),\n    registerActionHandler: jest.fn(),\n    loadScriptOnce: jest.fn().mockResolvedValue(undefined),\n    ...overrides,\n  } as unknown as BaseWindowMessenger;\n}\n\ndescribe('enableBackgroundCapture', () => {\n  afterEach(() => {\n    jest.restoreAllMocks();\n  });\n\n  test('should register action handlers on first call', () => {\n    const messenger = createMockMessenger();\n\n    enableBackgroundCapture(messenger);\n\n    expect(messenger.registerActionHandler).toHaveBeenCalledTimes(2);\n    expect(messenger.registerActionHandler).toHaveBeenCalledWith('initialize-background-capture', expect.any(Function));\n    expect(messenger.registerActionHandler).toHaveBeenCalledWith('close-background-capture', expect.any(Function));\n  });\n\n  test('should brand the messenger on first call', () => {\n    const messenger = createMockMessenger();\n\n    enableBackgroundCapture(messenger);\n\n    expect((messenger as unknown as Record<string, unknown>)[BG_CAPTURE_BRAND]).toBe(true);\n  });\n\n  test('should be a no-op if already branded', () => {\n    const messenger = createMockMessenger();\n    (messenger as unknown as Record<string, unknown>)[BG_CAPTURE_BRAND] = true;\n\n    enableBackgroundCapture(messenger);\n\n    expect(messenger.registerActionHandler).not.toHaveBeenCalled();\n  });\n\n  describe('initialize-background-capture handler', () => {\n    function getInitHandler(messenger: BaseWindowMessenger): ActionHandler {\n      const calls = (messenger.registerActionHandler as jest.Mock).mock.calls;\n      const match = calls.find(([action]: [string]) => action === 'initialize-background-capture');\n      return match[1] as ActionHandler;\n    }\n\n    test('should load script from default URL and notify on success', async () => {\n      const messenger = createMockMessenger();\n      const mockClose = jest.fn();\n      (window as any).amplitudeBackgroundCapture = jest.fn().mockReturnValue({ close: mockClose });\n\n      enableBackgroundCapture(messenger);\n      const handler = getInitHandler(messenger);\n\n      handler({});\n      await new Promise(process.nextTick);\n\n      const expectedUrl = new URL(AMPLITUDE_BACKGROUND_CAPTURE_SCRIPT_URL, 'https://app.amplitude.com').toString();\n      expect(messenger.loadScriptOnce).toHaveBeenCalledWith(expectedUrl);\n      expect(messenger.logger?.debug).toHaveBeenCalledWith('Initializing background capture (external script)');\n      expect(messenger.logger?.debug).toHaveBeenCalledWith('Background capture script loaded (external)');\n      expect((window as any).amplitudeBackgroundCapture).toHaveBeenCalledWith({\n        messenger,\n        onBackgroundCapture: expect.any(Function),\n      });\n      expect(messenger.notify).toHaveBeenCalledWith({ action: 'background-capture-loaded' });\n\n      delete (window as any).amplitudeBackgroundCapture;\n    });\n\n    test('should use custom scriptUrl when provided', async () => {\n      const messenger = createMockMessenger();\n      (window as any).amplitudeBackgroundCapture = jest.fn().mockReturnValue(null);\n\n      enableBackgroundCapture(messenger, { scriptUrl: 'https://custom.cdn.com/bg.js' });\n      const handler = getInitHandler(messenger);\n\n      handler({});\n      await new Promise(process.nextTick);\n\n      const expectedUrl = new URL('https://custom.cdn.com/bg.js', 'https://app.amplitude.com').toString();\n      expect(messenger.loadScriptOnce).toHaveBeenCalledWith(expectedUrl);\n\n      delete (window as any).amplitudeBackgroundCapture;\n    });\n\n    test('should warn on script load failure', async () => {\n      const messenger = createMockMessenger({\n        loadScriptOnce: jest.fn().mockRejectedValue(new Error('network error')),\n      } as any);\n\n      enableBackgroundCapture(messenger);\n      const handler = getInitHandler(messenger);\n\n      handler({});\n      await new Promise(process.nextTick);\n\n      expect(messenger.logger?.warn).toHaveBeenCalledWith('Failed to initialize background capture');\n      expect(messenger.notify).not.toHaveBeenCalledWith(\n        expect.objectContaining({ action: 'background-capture-loaded' }),\n      );\n    });\n\n    test('should handle missing amplitudeBackgroundCapture on window', async () => {\n      const messenger = createMockMessenger();\n      delete (window as any).amplitudeBackgroundCapture;\n\n      enableBackgroundCapture(messenger);\n      const handler = getInitHandler(messenger);\n\n      handler({});\n      await new Promise(process.nextTick);\n\n      expect(messenger.notify).toHaveBeenCalledWith({ action: 'background-capture-loaded' });\n    });\n  });\n\n  describe('close-background-capture handler', () => {\n    function getCloseHandler(messenger: BaseWindowMessenger): ActionHandler {\n      const calls = (messenger.registerActionHandler as jest.Mock).mock.calls;\n      const match = calls.find(([action]: [string]) => action === 'close-background-capture');\n      return match[1] as ActionHandler;\n    }\n\n    function getInitHandler(messenger: BaseWindowMessenger): ActionHandler {\n      const calls = (messenger.registerActionHandler as jest.Mock).mock.calls;\n      const match = calls.find(([action]: [string]) => action === 'initialize-background-capture');\n      return match[1] as ActionHandler;\n    }\n\n    test('should call close on the background capture instance', async () => {\n      const messenger = createMockMessenger();\n      const mockClose = jest.fn();\n      (window as any).amplitudeBackgroundCapture = jest.fn().mockReturnValue({ close: mockClose });\n\n      enableBackgroundCapture(messenger);\n\n      const initHandler = getInitHandler(messenger);\n      initHandler({});\n      await new Promise(process.nextTick);\n\n      const closeHandler = getCloseHandler(messenger);\n      closeHandler({});\n\n      expect(mockClose).toHaveBeenCalledTimes(1);\n\n      delete (window as any).amplitudeBackgroundCapture;\n    });\n\n    test('should be safe to call when no instance exists', () => {\n      const messenger = createMockMessenger();\n\n      enableBackgroundCapture(messenger);\n      const closeHandler = getCloseHandler(messenger);\n\n      expect(() => closeHandler({})).not.toThrow();\n    });\n  });\n\n  describe('onBackgroundCapture callback', () => {\n    function getInitHandler(messenger: BaseWindowMessenger): ActionHandler {\n      const calls = (messenger.registerActionHandler as jest.Mock).mock.calls;\n      const match = calls.find(([action]: [string]) => action === 'initialize-background-capture');\n      return match[1] as ActionHandler;\n    }\n\n    test('should notify on background-capture-complete', async () => {\n      const messenger = createMockMessenger();\n      let capturedCallback: (type: string, data: any) => void = jest.fn();\n      (window as any).amplitudeBackgroundCapture = jest.fn().mockImplementation(({ onBackgroundCapture }) => {\n        capturedCallback = onBackgroundCapture;\n        return { close: jest.fn() };\n      });\n\n      enableBackgroundCapture(messenger);\n      const handler = getInitHandler(messenger);\n\n      handler({});\n      await new Promise(process.nextTick);\n\n      const captureData = { key: 'value', count: 42 };\n      capturedCallback('background-capture-complete', captureData);\n\n      expect(messenger.logger?.debug).toHaveBeenCalledWith('Background capture complete');\n      expect(messenger.notify).toHaveBeenCalledWith({\n        action: 'background-capture-complete',\n        data: captureData,\n      });\n\n      delete (window as any).amplitudeBackgroundCapture;\n    });\n\n    test('should not notify for other event types', async () => {\n      const messenger = createMockMessenger();\n      let capturedCallback: (type: string, data: any) => void = jest.fn();\n      (window as any).amplitudeBackgroundCapture = jest.fn().mockImplementation(({ onBackgroundCapture }) => {\n        capturedCallback = onBackgroundCapture;\n        return { close: jest.fn() };\n      });\n\n      enableBackgroundCapture(messenger);\n      const handler = getInitHandler(messenger);\n\n      handler({});\n      await new Promise(process.nextTick);\n\n      (messenger.notify as jest.Mock).mockClear();\n      (messenger.logger?.debug as jest.Mock).mockClear();\n\n      capturedCallback('some-other-type', { key: 'value' });\n\n      expect(messenger.notify).not.toHaveBeenCalled();\n\n      delete (window as any).amplitudeBackgroundCapture;\n    });\n  });\n\n  test('should work without logger', async () => {\n    const messenger = createMockMessenger({ logger: undefined } as any);\n\n    enableBackgroundCapture(messenger);\n\n    const calls = (messenger.registerActionHandler as jest.Mock).mock.calls;\n    const initHandler = calls.find(([a]: [string]) => a === 'initialize-background-capture')[1] as ActionHandler;\n\n    (window as any).amplitudeBackgroundCapture = jest.fn().mockReturnValue({ close: jest.fn() });\n\n    expect(() => initHandler({})).not.toThrow();\n    await new Promise(process.nextTick);\n\n    expect(messenger.notify).toHaveBeenCalledWith({ action: 'background-capture-loaded' });\n\n    delete (window as any).amplitudeBackgroundCapture;\n  });\n\n  test('should work without logger on failure', async () => {\n    const messenger = createMockMessenger({\n      logger: undefined,\n      loadScriptOnce: jest.fn().mockRejectedValue(new Error('fail')),\n    } as any);\n\n    enableBackgroundCapture(messenger);\n\n    const calls = (messenger.registerActionHandler as jest.Mock).mock.calls;\n    const initHandler = calls.find(([a]: [string]) => a === 'initialize-background-capture')[1] as ActionHandler;\n\n    expect(() => initHandler({})).not.toThrow();\n    await new Promise(process.nextTick);\n  });\n\n  test('should handle logger without debug method in onBackgroundCapture', async () => {\n    const messenger = createMockMessenger({\n      logger: { warn: jest.fn(), log: jest.fn(), error: jest.fn() } as any,\n    });\n    let capturedCallback: (type: string, data: any) => void = jest.fn();\n    (window as any).amplitudeBackgroundCapture = jest.fn().mockImplementation(({ onBackgroundCapture }) => {\n      capturedCallback = onBackgroundCapture;\n      return { close: jest.fn() };\n    });\n\n    enableBackgroundCapture(messenger);\n\n    const calls = (messenger.registerActionHandler as jest.Mock).mock.calls;\n    const initHandler = calls.find(([a]: [string]) => a === 'initialize-background-capture')[1] as ActionHandler;\n\n    initHandler({});\n    await new Promise(process.nextTick);\n\n    expect(() => capturedCallback('background-capture-complete', { key: 'val' })).not.toThrow();\n    expect(messenger.notify).toHaveBeenCalledWith({\n      action: 'background-capture-complete',\n      data: { key: 'val' },\n    });\n\n    delete (window as any).amplitudeBackgroundCapture;\n  });\n\n  test('should handle onBackgroundCapture callback without logger', async () => {\n    const messenger = createMockMessenger({ logger: undefined } as any);\n    let capturedCallback: (type: string, data: any) => void = jest.fn();\n    (window as any).amplitudeBackgroundCapture = jest.fn().mockImplementation(({ onBackgroundCapture }) => {\n      capturedCallback = onBackgroundCapture;\n      return { close: jest.fn() };\n    });\n\n    enableBackgroundCapture(messenger);\n\n    const calls = (messenger.registerActionHandler as jest.Mock).mock.calls;\n    const initHandler = calls.find(([a]: [string]) => a === 'initialize-background-capture')[1] as ActionHandler;\n\n    initHandler({});\n    await new Promise(process.nextTick);\n\n    expect(() => capturedCallback('background-capture-complete', { key: 'val' })).not.toThrow();\n    expect(messenger.notify).toHaveBeenCalledWith({\n      action: 'background-capture-complete',\n      data: { key: 'val' },\n    });\n\n    delete (window as any).amplitudeBackgroundCapture;\n  });\n\n  test('should handle amplitudeBackgroundCapture being non-callable', async () => {\n    const messenger = createMockMessenger();\n    (window as any).amplitudeBackgroundCapture = 'not-a-function';\n\n    enableBackgroundCapture(messenger);\n\n    const calls = (messenger.registerActionHandler as jest.Mock).mock.calls;\n    const initHandler = calls.find(([a]: [string]) => a === 'initialize-background-capture')[1] as ActionHandler;\n\n    initHandler({});\n    await new Promise(process.nextTick);\n\n    expect(messenger.logger?.warn).toHaveBeenCalledWith('Failed to initialize background capture');\n\n    delete (window as any).amplitudeBackgroundCapture;\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/messenger/base-window-messenger.test.ts",
    "content": "/**\n * @jest-environment jsdom\n */\n\n/* eslint-disable @typescript-eslint/unbound-method */\nimport { getOrCreateWindowMessenger } from '../../src/messenger/base-window-messenger';\nimport type { BaseWindowMessenger } from '../../src/messenger/base-window-messenger';\nimport { AMPLITUDE_ORIGIN } from '../../src/messenger/constants';\nimport * as utils from '../../src/messenger/utils';\nimport * as globalScopeModule from '../../src/global-scope';\n\nconst MESSENGER_GLOBAL_KEY = '__AMPLITUDE_MESSENGER__';\nconst MESSENGER_BRAND = '__AMPLITUDE_MESSENGER_INSTANCE__';\n\nfunction createLogger() {\n  return {\n    disable: jest.fn(),\n    enable: jest.fn(),\n    log: jest.fn(),\n    warn: jest.fn(),\n    error: jest.fn(),\n    debug: jest.fn(),\n  };\n}\n\nfunction postMessageToWindow(data: any, origin: string) {\n  const event = new MessageEvent('message', { data, origin });\n  window.dispatchEvent(event);\n}\n\ndescribe('BaseWindowMessenger', () => {\n  let messenger: BaseWindowMessenger;\n\n  beforeEach(() => {\n    // Clean global singleton between tests\n    const g = globalThis as Record<string, unknown>;\n    delete g[MESSENGER_GLOBAL_KEY];\n  });\n\n  afterEach(() => {\n    messenger?.destroy();\n    jest.restoreAllMocks();\n    const g = globalThis as Record<string, unknown>;\n    delete g[MESSENGER_GLOBAL_KEY];\n  });\n\n  describe('getOrCreateWindowMessenger', () => {\n    test('should create a new messenger with default origin', () => {\n      messenger = getOrCreateWindowMessenger();\n\n      expect(messenger.endpoint).toBe(AMPLITUDE_ORIGIN);\n      expect((messenger as any)[MESSENGER_BRAND]).toBe(true);\n    });\n\n    test('should create a new messenger with custom origin', () => {\n      messenger = getOrCreateWindowMessenger({ origin: 'https://custom.example.com' });\n\n      expect(messenger.endpoint).toBe('https://custom.example.com');\n    });\n\n    test('should return the same singleton on subsequent calls', () => {\n      messenger = getOrCreateWindowMessenger();\n      const second = getOrCreateWindowMessenger();\n\n      expect(second).toBe(messenger);\n    });\n\n    test('should store messenger on globalScope', () => {\n      messenger = getOrCreateWindowMessenger();\n\n      const g = globalThis as Record<string, unknown>;\n      expect(g[MESSENGER_GLOBAL_KEY]).toBe(messenger);\n    });\n\n    test('should not reuse a non-branded value on globalScope', () => {\n      const g = globalThis as Record<string, unknown>;\n      g[MESSENGER_GLOBAL_KEY] = { fake: true };\n\n      messenger = getOrCreateWindowMessenger();\n\n      expect((messenger as any)[MESSENGER_BRAND]).toBe(true);\n      expect(g[MESSENGER_GLOBAL_KEY]).toBe(messenger);\n    });\n\n    test('should handle undefined globalScope', () => {\n      jest.spyOn(globalScopeModule, 'getGlobalScope').mockReturnValue(undefined);\n\n      messenger = getOrCreateWindowMessenger();\n\n      expect(messenger.endpoint).toBe(AMPLITUDE_ORIGIN);\n    });\n  });\n\n  describe('notify', () => {\n    test('should call postMessage on window.opener', () => {\n      messenger = getOrCreateWindowMessenger();\n      const mockPostMessage = jest.fn();\n      Object.defineProperty(window, 'opener', {\n        value: { postMessage: mockPostMessage },\n        writable: true,\n        configurable: true,\n      });\n\n      messenger.notify({ action: 'test-action', data: { key: 'value' } });\n\n      expect(mockPostMessage).toHaveBeenCalledWith({ action: 'test-action', data: { key: 'value' } }, AMPLITUDE_ORIGIN);\n\n      Object.defineProperty(window, 'opener', { value: null, writable: true, configurable: true });\n    });\n\n    test('should log debug when logger is set', () => {\n      messenger = getOrCreateWindowMessenger();\n      const logger = createLogger();\n      messenger.setup({ logger });\n\n      Object.defineProperty(window, 'opener', { value: null, writable: true, configurable: true });\n      messenger.notify({ action: 'test' });\n\n      expect(logger.debug).toHaveBeenCalledWith('Message sent: ', expect.any(String));\n    });\n\n    test('should not throw when window.opener is null', () => {\n      messenger = getOrCreateWindowMessenger();\n      Object.defineProperty(window, 'opener', { value: null, writable: true, configurable: true });\n\n      expect(() => messenger.notify({ action: 'test' })).not.toThrow();\n    });\n  });\n\n  describe('setup', () => {\n    test('should set the logger', () => {\n      messenger = getOrCreateWindowMessenger();\n      const logger = createLogger();\n\n      messenger.setup({ logger });\n\n      expect(messenger.logger).toBe(logger);\n    });\n\n    test('should override endpoint when still at default', () => {\n      messenger = getOrCreateWindowMessenger();\n\n      messenger.setup({ endpoint: 'https://app.eu.amplitude.com' });\n\n      expect(messenger.endpoint).toBe('https://app.eu.amplitude.com');\n    });\n\n    test('should not override a previously customized endpoint', () => {\n      messenger = getOrCreateWindowMessenger({ origin: 'https://custom.example.com' });\n\n      messenger.setup({ endpoint: 'https://app.eu.amplitude.com' });\n\n      expect(messenger.endpoint).toBe('https://custom.example.com');\n    });\n\n    test('should be idempotent — second call should not attach another listener', () => {\n      messenger = getOrCreateWindowMessenger();\n      const addSpy = jest.spyOn(window, 'addEventListener');\n\n      messenger.setup();\n      messenger.setup();\n\n      const messageCalls = addSpy.mock.calls.filter(([type]) => type === 'message');\n      expect(messageCalls).toHaveLength(1);\n    });\n\n    test('should notify page-loaded on first setup', () => {\n      messenger = getOrCreateWindowMessenger();\n      const mockPostMessage = jest.fn();\n      Object.defineProperty(window, 'opener', {\n        value: { postMessage: mockPostMessage },\n        writable: true,\n        configurable: true,\n      });\n\n      messenger.setup();\n\n      expect(mockPostMessage).toHaveBeenCalledWith({ action: 'page-loaded' }, AMPLITUDE_ORIGIN);\n\n      Object.defineProperty(window, 'opener', { value: null, writable: true, configurable: true });\n    });\n\n    test('should update logger on second setup call', () => {\n      messenger = getOrCreateWindowMessenger();\n      const logger1 = createLogger();\n      const logger2 = createLogger();\n\n      messenger.setup({ logger: logger1 });\n      messenger.setup({ logger: logger2 });\n\n      expect(messenger.logger).toBe(logger2);\n    });\n\n    test('should work when called with no arguments', () => {\n      messenger = getOrCreateWindowMessenger();\n\n      expect(() => messenger.setup()).not.toThrow();\n    });\n  });\n\n  describe('message handling', () => {\n    beforeEach(() => {\n      Object.defineProperty(window, 'opener', { value: null, writable: true, configurable: true });\n    });\n\n    test('should ignore messages from non-matching origins', () => {\n      messenger = getOrCreateWindowMessenger();\n      const handler = jest.fn();\n      messenger.registerActionHandler('test-action', handler);\n      messenger.setup();\n\n      postMessageToWindow({ action: 'test-action' }, 'https://evil.example.com');\n\n      expect(handler).not.toHaveBeenCalled();\n    });\n\n    test('should ignore messages without action', () => {\n      messenger = getOrCreateWindowMessenger();\n      const logger = createLogger();\n      messenger.setup({ logger });\n\n      postMessageToWindow({ noAction: true }, AMPLITUDE_ORIGIN);\n\n      expect(logger.debug).toHaveBeenCalledWith('Message received: ', expect.any(String));\n    });\n\n    test('should dispatch to registered action handlers', () => {\n      messenger = getOrCreateWindowMessenger();\n      const handler = jest.fn();\n      messenger.registerActionHandler('my-action', handler);\n      messenger.setup();\n\n      postMessageToWindow({ action: 'my-action', data: { foo: 'bar' } }, AMPLITUDE_ORIGIN);\n\n      expect(handler).toHaveBeenCalledWith({ foo: 'bar' });\n    });\n\n    test('should respond to ping with pong and not buffer the message', () => {\n      messenger = getOrCreateWindowMessenger();\n      const mockPostMessage = jest.fn();\n      Object.defineProperty(window, 'opener', {\n        value: { postMessage: mockPostMessage },\n        writable: true,\n        configurable: true,\n      });\n      messenger.setup();\n      mockPostMessage.mockClear();\n\n      postMessageToWindow({ action: 'ping' }, AMPLITUDE_ORIGIN);\n      postMessageToWindow({ action: 'ping' }, AMPLITUDE_ORIGIN);\n\n      expect(mockPostMessage).toHaveBeenCalledWith({ action: 'pong' }, AMPLITUDE_ORIGIN);\n      expect(mockPostMessage).toHaveBeenCalledTimes(2);\n      // Ping should NOT accumulate in the pending messages buffer\n      expect((messenger as any).pendingMessages.has('ping')).toBe(false);\n    });\n\n    test('should handle response messages with id by resolving the callback', async () => {\n      messenger = getOrCreateWindowMessenger();\n      const logger = createLogger();\n      messenger.setup({ logger });\n\n      const callbackId = 'test-id-123';\n      const resolveFn = jest.fn();\n      messenger.requestCallbacks[callbackId] = { resolve: resolveFn, reject: jest.fn() };\n\n      postMessageToWindow(\n        { action: 'some-response', id: callbackId, responseData: { result: 'ok' } },\n        AMPLITUDE_ORIGIN,\n      );\n\n      expect(resolveFn).toHaveBeenCalledWith({ result: 'ok' });\n      expect(messenger.requestCallbacks[callbackId]).toBeUndefined();\n    });\n\n    test('should warn when no callback exists for a response id', () => {\n      messenger = getOrCreateWindowMessenger();\n      const logger = createLogger();\n      messenger.setup({ logger });\n\n      postMessageToWindow({ action: 'some-response', id: 'nonexistent-id', responseData: {} }, AMPLITUDE_ORIGIN);\n\n      expect(logger.warn).toHaveBeenCalledWith(expect.stringContaining('nonexistent-id'));\n    });\n\n    test('should not dispatch action handler for messages with id', () => {\n      messenger = getOrCreateWindowMessenger();\n      const handler = jest.fn();\n      messenger.registerActionHandler('my-action', handler);\n      messenger.setup();\n\n      messenger.requestCallbacks['req-1'] = { resolve: jest.fn(), reject: jest.fn() };\n      postMessageToWindow({ action: 'my-action', id: 'req-1', responseData: {} }, AMPLITUDE_ORIGIN);\n\n      expect(handler).not.toHaveBeenCalled();\n    });\n\n    test('should buffer action without a registered handler', () => {\n      messenger = getOrCreateWindowMessenger();\n      messenger.setup();\n\n      expect(() => {\n        postMessageToWindow({ action: 'unregistered-action' }, AMPLITUDE_ORIGIN);\n      }).not.toThrow();\n\n      const handler = jest.fn();\n      messenger.registerActionHandler('unregistered-action', handler);\n\n      expect(handler).toHaveBeenCalledTimes(1);\n    });\n\n    test('should warn for unknown response id without logger', () => {\n      messenger = getOrCreateWindowMessenger();\n      messenger.setup();\n\n      expect(() => {\n        postMessageToWindow({ action: 'resp', id: 'unknown-id', responseData: {} }, AMPLITUDE_ORIGIN);\n      }).not.toThrow();\n    });\n\n    test('should handle null event data', () => {\n      messenger = getOrCreateWindowMessenger();\n      messenger.setup();\n\n      expect(() => {\n        postMessageToWindow(null, AMPLITUDE_ORIGIN);\n      }).not.toThrow();\n    });\n\n    test('should handle event data with no action field', () => {\n      messenger = getOrCreateWindowMessenger();\n      messenger.setup();\n\n      expect(() => {\n        postMessageToWindow({}, AMPLITUDE_ORIGIN);\n      }).not.toThrow();\n    });\n  });\n\n  describe('message buffering', () => {\n    beforeEach(() => {\n      Object.defineProperty(window, 'opener', { value: null, writable: true, configurable: true });\n    });\n\n    test('should replay buffered messages when handler is registered after message arrives', () => {\n      messenger = getOrCreateWindowMessenger();\n      messenger.setup();\n\n      postMessageToWindow({ action: 'late-action', data: { step: 1 } }, AMPLITUDE_ORIGIN);\n\n      const handler = jest.fn();\n      messenger.registerActionHandler('late-action', handler);\n\n      expect(handler).toHaveBeenCalledWith({ step: 1 });\n    });\n\n    test('should replay multiple buffered messages in order', () => {\n      messenger = getOrCreateWindowMessenger();\n      messenger.setup();\n\n      postMessageToWindow({ action: 'late-action', data: { step: 1 } }, AMPLITUDE_ORIGIN);\n      postMessageToWindow({ action: 'late-action', data: { step: 2 } }, AMPLITUDE_ORIGIN);\n\n      const calls: any[] = [];\n      messenger.registerActionHandler('late-action', (data) => calls.push(data));\n\n      expect(calls).toEqual([{ step: 1 }, { step: 2 }]);\n    });\n\n    test('should not replay messages for a different action', () => {\n      messenger = getOrCreateWindowMessenger();\n      messenger.setup();\n\n      postMessageToWindow({ action: 'action-a', data: 'a' }, AMPLITUDE_ORIGIN);\n\n      const handlerB = jest.fn();\n      messenger.registerActionHandler('action-b', handlerB);\n\n      expect(handlerB).not.toHaveBeenCalled();\n    });\n\n    test('should clear the buffer for an action after replaying', () => {\n      messenger = getOrCreateWindowMessenger();\n      messenger.setup();\n\n      postMessageToWindow({ action: 'once', data: 'first' }, AMPLITUDE_ORIGIN);\n\n      const handler1 = jest.fn();\n      messenger.registerActionHandler('once', handler1);\n      expect(handler1).toHaveBeenCalledWith('first');\n\n      // Overwrite handler — should not get the old buffered message again\n      const handler2 = jest.fn();\n      messenger.registerActionHandler('once', handler2);\n      expect(handler2).not.toHaveBeenCalled();\n    });\n\n    test('should not buffer messages that have a registered handler', () => {\n      messenger = getOrCreateWindowMessenger();\n      const handler = jest.fn();\n      messenger.registerActionHandler('existing', handler);\n      messenger.setup();\n\n      postMessageToWindow({ action: 'existing', data: 'live' }, AMPLITUDE_ORIGIN);\n\n      expect(handler).toHaveBeenCalledWith('live');\n\n      // Overwrite handler — no buffered messages should replay\n      const handler2 = jest.fn();\n      messenger.registerActionHandler('existing', handler2);\n      expect(handler2).not.toHaveBeenCalled();\n    });\n\n    test('should handle the autocapture + session-replay race condition', () => {\n      messenger = getOrCreateWindowMessenger();\n      messenger.setup();\n\n      // Parent sends initialize-visual-tagging-selector before autocapture registers its handler\n      postMessageToWindow(\n        { action: 'initialize-visual-tagging-selector', data: { actionType: 'click' } },\n        AMPLITUDE_ORIGIN,\n      );\n\n      // Autocapture registers its handler later\n      const visualTaggingHandler = jest.fn();\n      messenger.registerActionHandler('initialize-visual-tagging-selector', visualTaggingHandler);\n\n      expect(visualTaggingHandler).toHaveBeenCalledWith({ actionType: 'click' });\n    });\n  });\n\n  describe('registerActionHandler', () => {\n    test('should register a handler', () => {\n      messenger = getOrCreateWindowMessenger();\n      const handler = jest.fn();\n\n      messenger.registerActionHandler('my-action', handler);\n      messenger.setup();\n\n      Object.defineProperty(window, 'opener', { value: null, writable: true, configurable: true });\n      postMessageToWindow({ action: 'my-action', data: 42 }, AMPLITUDE_ORIGIN);\n\n      expect(handler).toHaveBeenCalledWith(42);\n    });\n\n    test('should warn when overwriting an existing handler', () => {\n      messenger = getOrCreateWindowMessenger();\n      const logger = createLogger();\n      messenger.setup({ logger });\n\n      messenger.registerActionHandler('dup', jest.fn());\n      messenger.registerActionHandler('dup', jest.fn());\n\n      expect(logger.warn).toHaveBeenCalledWith(expect.stringContaining('Overwriting'));\n    });\n\n    test('should not throw when overwriting without a logger', () => {\n      messenger = getOrCreateWindowMessenger();\n\n      messenger.registerActionHandler('dup', jest.fn());\n\n      expect(() => messenger.registerActionHandler('dup', jest.fn())).not.toThrow();\n    });\n  });\n\n  describe('sendRequest', () => {\n    test('should send a request and register a callback', () => {\n      messenger = getOrCreateWindowMessenger();\n      const mockPostMessage = jest.fn();\n      Object.defineProperty(window, 'opener', {\n        value: { postMessage: mockPostMessage },\n        writable: true,\n        configurable: true,\n      });\n      jest.spyOn(utils, 'generateUniqueId').mockReturnValue('fixed-id');\n\n      const promise = messenger.sendRequest('get-data', { key: 'val' });\n\n      expect(mockPostMessage).toHaveBeenCalledWith(\n        expect.objectContaining({ id: 'fixed-id', action: 'get-data', args: { key: 'val' } }),\n        AMPLITUDE_ORIGIN,\n      );\n      expect(messenger.requestCallbacks['fixed-id']).toBeDefined();\n\n      messenger.requestCallbacks['fixed-id'].resolve('result');\n\n      return expect(promise).resolves.toBe('result');\n    });\n\n    test('should reject on timeout', async () => {\n      messenger = getOrCreateWindowMessenger();\n      Object.defineProperty(window, 'opener', { value: null, writable: true, configurable: true });\n      jest.useFakeTimers();\n      jest.spyOn(utils, 'generateUniqueId').mockReturnValue('timeout-id');\n\n      const promise = messenger.sendRequest('slow-action', {}, { timeout: 500 });\n\n      jest.advanceTimersByTime(500);\n\n      await expect(promise).rejects.toThrow('slow-action timed out (id: timeout-id)');\n      expect(messenger.requestCallbacks['timeout-id']).toBeUndefined();\n\n      jest.useRealTimers();\n    });\n\n    test('should reject on timeout with negative timeout', async () => {\n      messenger = getOrCreateWindowMessenger();\n      Object.defineProperty(window, 'opener', { value: null, writable: true, configurable: true });\n      jest.spyOn(utils, 'generateUniqueId').mockReturnValue('neg-timeout-id');\n\n      // timeout <= 0 should not set a timer\n      void messenger.sendRequest('action', {}, { timeout: -1 });\n\n      expect(messenger.requestCallbacks['neg-timeout-id']).toBeDefined();\n\n      messenger.requestCallbacks['neg-timeout-id'].resolve(undefined);\n    });\n\n    test('should not timeout when timeout is 0', async () => {\n      messenger = getOrCreateWindowMessenger();\n      Object.defineProperty(window, 'opener', { value: null, writable: true, configurable: true });\n      jest.useFakeTimers();\n      jest.spyOn(utils, 'generateUniqueId').mockReturnValue('no-timeout-id');\n\n      void messenger.sendRequest('no-timeout-action', {}, { timeout: 0 });\n\n      jest.advanceTimersByTime(60_000);\n\n      expect(messenger.requestCallbacks['no-timeout-id']).toBeDefined();\n\n      messenger.requestCallbacks['no-timeout-id'].resolve(undefined);\n      jest.useRealTimers();\n    });\n  });\n\n  describe('loadScriptOnce', () => {\n    test('should call asyncLoadScript and resolve', async () => {\n      messenger = getOrCreateWindowMessenger();\n      jest.spyOn(utils, 'asyncLoadScript').mockResolvedValue({ status: true });\n\n      await messenger.loadScriptOnce('https://cdn.example.com/script.js');\n\n      expect(utils.asyncLoadScript).toHaveBeenCalledWith('https://cdn.example.com/script.js');\n    });\n\n    test('should deduplicate concurrent calls to the same URL', async () => {\n      messenger = getOrCreateWindowMessenger();\n      jest.spyOn(utils, 'asyncLoadScript').mockResolvedValue({ status: true });\n\n      const p1 = messenger.loadScriptOnce('https://cdn.example.com/script.js');\n      const p2 = messenger.loadScriptOnce('https://cdn.example.com/script.js');\n\n      await Promise.all([p1, p2]);\n\n      expect(utils.asyncLoadScript).toHaveBeenCalledTimes(1);\n    });\n\n    test('should allow different URLs to load independently', async () => {\n      messenger = getOrCreateWindowMessenger();\n      jest.spyOn(utils, 'asyncLoadScript').mockResolvedValue({ status: true });\n\n      await messenger.loadScriptOnce('https://cdn.example.com/a.js');\n      await messenger.loadScriptOnce('https://cdn.example.com/b.js');\n\n      expect(utils.asyncLoadScript).toHaveBeenCalledTimes(2);\n    });\n\n    test('should remove failed loads from cache so retries work', async () => {\n      messenger = getOrCreateWindowMessenger();\n      const loadSpy = jest.spyOn(utils, 'asyncLoadScript');\n      loadSpy.mockRejectedValueOnce(new Error('network error'));\n      loadSpy.mockResolvedValueOnce({ status: true });\n\n      await expect(messenger.loadScriptOnce('https://cdn.example.com/retry.js')).rejects.toThrow('network error');\n\n      await messenger.loadScriptOnce('https://cdn.example.com/retry.js');\n\n      expect(loadSpy).toHaveBeenCalledTimes(2);\n    });\n\n    test('should not retry a successful load', async () => {\n      messenger = getOrCreateWindowMessenger();\n      jest.spyOn(utils, 'asyncLoadScript').mockResolvedValue({ status: true });\n\n      await messenger.loadScriptOnce('https://cdn.example.com/once.js');\n      await messenger.loadScriptOnce('https://cdn.example.com/once.js');\n\n      expect(utils.asyncLoadScript).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('destroy', () => {\n    test('should remove the message listener', () => {\n      messenger = getOrCreateWindowMessenger();\n      const removeSpy = jest.spyOn(window, 'removeEventListener');\n      messenger.setup();\n\n      messenger.destroy();\n\n      expect(removeSpy.mock.calls.some(([type]) => type === 'message')).toBe(true);\n    });\n\n    test('should clear all state', () => {\n      messenger = getOrCreateWindowMessenger();\n      messenger.setup();\n      messenger.registerActionHandler('foo', jest.fn());\n      messenger.requestCallbacks['test'] = { resolve: jest.fn(), reject: jest.fn() };\n\n      messenger.destroy();\n\n      expect(messenger.requestCallbacks).toEqual({});\n    });\n\n    test('should remove the singleton from globalScope', () => {\n      messenger = getOrCreateWindowMessenger();\n      const g = globalThis as Record<string, unknown>;\n\n      expect(g[MESSENGER_GLOBAL_KEY]).toBe(messenger);\n\n      messenger.destroy();\n\n      expect(g[MESSENGER_GLOBAL_KEY]).toBeUndefined();\n    });\n\n    test('should not remove a different messenger from globalScope', () => {\n      messenger = getOrCreateWindowMessenger();\n      const g = globalThis as Record<string, unknown>;\n      const other = { different: true };\n      g[MESSENGER_GLOBAL_KEY] = other;\n\n      messenger.destroy();\n\n      expect(g[MESSENGER_GLOBAL_KEY]).toBe(other);\n    });\n\n    test('should be safe to call when not set up', () => {\n      messenger = getOrCreateWindowMessenger();\n\n      expect(() => messenger.destroy()).not.toThrow();\n    });\n\n    test('should allow re-setup after destroy', () => {\n      messenger = getOrCreateWindowMessenger();\n      const addSpy = jest.spyOn(window, 'addEventListener');\n\n      messenger.setup();\n      messenger.destroy();\n      messenger.setup();\n\n      const messageCalls = addSpy.mock.calls.filter(([type]) => type === 'message');\n      expect(messageCalls).toHaveLength(2);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/messenger/utils.test.ts",
    "content": "/**\n * @jest-environment jsdom\n */\n\nimport { asyncLoadScript, generateUniqueId } from '../../src/messenger/utils';\n\nbeforeAll(() => {\n  if (!globalThis.CSS?.escape) {\n    // jsdom does not implement CSS.escape; provide a minimal polyfill\n    globalThis.CSS = { escape: (v: string) => v.replace(/([^\\w-])/g, '\\\\$1') } as typeof CSS;\n  }\n});\n\ndescribe('asyncLoadScript', () => {\n  afterEach(() => {\n    document.head.querySelectorAll('script').forEach((s) => s.remove());\n  });\n\n  test('should append a script element and resolve on load', async () => {\n    const promise = asyncLoadScript('https://cdn.example.com/test.js');\n\n    const script = document.querySelector('script[src=\"https://cdn.example.com/test.js\"]') as HTMLScriptElement;\n    expect(script).not.toBeNull();\n    expect(script.async).toBe(true);\n    expect(script.type).toBe('text/javascript');\n\n    script.dispatchEvent(new Event('load'));\n\n    await expect(promise).resolves.toEqual({ status: true });\n  });\n\n  test('should reject when the script fails to load', async () => {\n    const promise = asyncLoadScript('https://cdn.example.com/bad.js');\n\n    const script = document.querySelector('script[src=\"https://cdn.example.com/bad.js\"]') as HTMLScriptElement;\n    script.dispatchEvent(new Event('error'));\n\n    await expect(promise).rejects.toEqual({\n      status: false,\n      message: 'Failed to load the script https://cdn.example.com/bad.js',\n    });\n  });\n\n  test('should resolve immediately if a script with the same src already exists', async () => {\n    const existing = document.createElement('script');\n    existing.src = 'https://cdn.example.com/dup.js';\n    document.head.appendChild(existing);\n\n    const result = await asyncLoadScript('https://cdn.example.com/dup.js');\n\n    expect(result).toEqual({ status: true });\n\n    const scripts = document.querySelectorAll('script[src=\"https://cdn.example.com/dup.js\"]');\n    expect(scripts).toHaveLength(1);\n  });\n\n  test('should handle URLs with special CSS characters', async () => {\n    const url = 'https://cdn.example.com/script.js?v=1&t=2';\n    const promise = asyncLoadScript(url);\n\n    const script = document.querySelector(`script[src=\"${CSS.escape(url)}\"]`) as HTMLScriptElement;\n    expect(script).not.toBeNull();\n\n    script.dispatchEvent(new Event('load'));\n\n    await expect(promise).resolves.toEqual({ status: true });\n  });\n});\n\ndescribe('generateUniqueId', () => {\n  test('should return a string', () => {\n    expect(typeof generateUniqueId()).toBe('string');\n  });\n\n  test('should contain a timestamp and random portion separated by a hyphen', () => {\n    const id = generateUniqueId();\n    const parts = id.split('-');\n\n    expect(parts.length).toBe(2);\n    expect(Number(parts[0])).not.toBeNaN();\n    expect(parts[1].length).toBeGreaterThan(0);\n  });\n\n  test('should produce unique values across calls', () => {\n    const ids = new Set(Array.from({ length: 100 }, () => generateUniqueId()));\n    expect(ids.size).toBe(100);\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/network-observer.test.ts",
    "content": "import {\n  FORBIDDEN_HEADERS,\n  NetworkEventCallback,\n  NetworkRequestEvent,\n  SAFE_HEADERS,\n  networkObserver,\n} from '../src/index';\nimport { NetworkObserver } from '../src/observers/network';\nimport {\n  FetchRequestBody,\n  PRUNE_STRATEGY,\n  pruneHeaders,\n  RequestInitSafe,\n  RequestWrapperFetch,\n  RequestWrapperXhr,\n  ResponseWrapperFetch,\n  ResponseWrapperXhr,\n} from '../src/network-request-event';\nimport * as AnalyticsCore from '../src/index';\nimport { TextEncoder } from 'util';\nimport * as streams from 'stream/web';\nimport * as Global from '../src/global-scope';\ntype PartialGlobal = Pick<typeof globalThis, 'fetch' | 'structuredClone'>;\n\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-unsafe-argument */\n/* eslint-disable @typescript-eslint/no-unsafe-call */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-empty-function */\n/* eslint-disable @typescript-eslint/no-floating-promises */\n/* eslint-disable jest/valid-expect */\n/* eslint-disable @typescript-eslint/no-unsafe-return */\n\n// Test subclass to access protected methods\nclass TestNetworkObserver extends NetworkObserver {\n  public testNotifyEvent(event: NetworkRequestEvent) {\n    this.triggerEventCallbacks(event);\n  }\n}\n\ndescribe('NetworkObserver', () => {\n  let networkObserver: TestNetworkObserver;\n  let originalFetchMock: jest.Mock;\n  let events: NetworkRequestEvent[] = [];\n  let globalScope: PartialGlobal;\n\n  let originalFetch: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;\n\n  beforeAll(() => {\n    originalFetch = globalThis.fetch;\n  });\n\n  afterAll(() => {\n    globalThis.fetch = originalFetch;\n  });\n\n  beforeEach(() => {\n    jest.useFakeTimers();\n    events = [];\n    originalFetchMock = jest.fn();\n    globalScope = {\n      fetch: originalFetchMock,\n      TextEncoder,\n      ReadableStream: streams.ReadableStream,\n      structuredClone: (obj: any) => JSON.parse(JSON.stringify(obj)),\n    } as PartialGlobal;\n\n    jest.spyOn(Global, 'getGlobalScope').mockReturnValue(globalScope as typeof globalThis);\n\n    networkObserver = new TestNetworkObserver();\n  });\n\n  afterEach(() => {\n    jest.useRealTimers();\n    jest.restoreAllMocks();\n  });\n\n  const callback = (event: NetworkRequestEvent) => {\n    events.push(event);\n  };\n\n  describe('successful requests', () => {\n    it('should track successful fetch requests with headers', async () => {\n      // Create a simple mock response\n      const headers = new Headers();\n      headers.set('content-type', 'application/json');\n      headers.set('content-length', '20');\n      headers.set('server', 'test-server');\n      const mockResponse = {\n        status: 200,\n        headers,\n      };\n      originalFetchMock.mockResolvedValue(mockResponse);\n\n      networkObserver.subscribe(new NetworkEventCallback(callback));\n\n      const requestHeaders = {\n        'Content-Type': 'application/json',\n        Authorization: 'Bearer token123',\n      };\n\n      await globalScope.fetch('https://api.example.com/data', {\n        method: 'POST',\n        headers: requestHeaders,\n      });\n\n      expect(events).toHaveLength(1);\n      expect(events[0]).toMatchObject({\n        type: 'fetch',\n        method: 'POST',\n        url: 'https://api.example.com/data',\n        status: 200,\n      });\n      expect(events[0].duration).toBeGreaterThanOrEqual(0);\n      expect(events[0].requestWrapper?.headers([...SAFE_HEADERS])).toEqual({\n        'Content-Type': 'application/json',\n      });\n      const expectedResponseHeaders = {\n        'content-type': 'application/json',\n        'content-length': '20',\n        server: 'test-server',\n      };\n      expect(events[0].responseWrapper?.headers([...SAFE_HEADERS])).toEqual(expectedResponseHeaders);\n    });\n\n    it('should track successful fetch requests with headers (uses Headers object)', async () => {\n      // Create a simple mock response\n      const headers = new Headers();\n      headers.set('content-type', 'application/json');\n      headers.set('content-length', '20');\n      headers.set('server', 'test-server');\n      const mockResponse = {\n        status: 200,\n        headers,\n      };\n      originalFetchMock.mockResolvedValue(mockResponse);\n\n      networkObserver.subscribe(new NetworkEventCallback(callback));\n\n      const requestHeaders = new Headers();\n      requestHeaders.set('Content-Type', 'application/json');\n      requestHeaders.set('Authorization', 'Bearer token123');\n      requestHeaders.set('safe-header', 'safe-value');\n      requestHeaders.set('omitted-header', 'omitted-value');\n\n      await globalScope.fetch('https://api.example.com/data', {\n        method: 'POST',\n        headers: requestHeaders,\n      });\n\n      expect(events).toHaveLength(1);\n      expect(events[0]).toMatchObject({\n        type: 'fetch',\n        method: 'POST',\n        url: 'https://api.example.com/data',\n        status: 200,\n      });\n      expect(events[0].duration).toBeGreaterThanOrEqual(0);\n      expect(events[0].requestWrapper?.headers(['safe-header', ...SAFE_HEADERS])).toEqual({\n        'content-type': 'application/json',\n        'safe-header': 'safe-value',\n      });\n      expect(events[0].responseWrapper?.headers([...SAFE_HEADERS])).toEqual({\n        'content-type': 'application/json',\n        'content-length': '20',\n        server: 'test-server',\n      });\n    });\n\n    it('should track successful fetch requests without headers', async () => {\n      const mockResponse = {\n        status: 200,\n        headers: {\n          forEach: jest.fn(), // Mock function that does nothing\n        },\n      };\n      originalFetchMock.mockResolvedValue(mockResponse);\n\n      networkObserver.subscribe(new NetworkEventCallback(callback));\n\n      await globalScope.fetch('https://api.example.com/data');\n\n      expect(events).toHaveLength(1);\n      expect(events[0]).toMatchObject({\n        type: 'fetch',\n        method: 'GET',\n        url: 'https://api.example.com/data',\n        status: 200,\n      });\n      expect(events[0].duration).toBeGreaterThanOrEqual(0);\n      expect(events[0].requestWrapper?.headers()).toEqual(undefined);\n      expect(events[0].responseWrapper?.headers()).toEqual(undefined);\n    });\n\n    it('should still fetch even if eventCallback throws error', async () => {\n      const headers = new Headers();\n      headers.set('content-type', 'application/json');\n      headers.set('content-length', '20');\n      const mockResponse = {\n        status: 200,\n        headers,\n      };\n      originalFetchMock.mockResolvedValue(mockResponse);\n      const errorCallback = (event: NetworkRequestEvent) => {\n        expect(event.status).toBe(200);\n        throw new Error('Error in event callback');\n      };\n      networkObserver.subscribe(new NetworkEventCallback(errorCallback));\n      const res = await globalScope.fetch('https://api.example.com/data');\n      expect(res.status).toBe(200);\n    });\n\n    it('should track successful fetch requests formed with request object', async () => {\n      const mockResponse = {\n        status: 200,\n        headers: {\n          forEach: jest.fn(), // Mock function that does nothing\n        },\n      };\n      originalFetchMock.mockResolvedValue(mockResponse);\n\n      networkObserver.subscribe(new NetworkEventCallback(callback));\n\n      const req = {\n        url: 'https://api.example.com/data',\n        method: 'POST',\n        headers: {\n          'Content-Type': 'application/json',\n        },\n        body: '{\"message\": \"Hello from mock!\"}',\n      } as any;\n      await globalScope.fetch(req);\n\n      expect(events).toHaveLength(1);\n      expect(events[0]).toMatchObject({\n        type: 'fetch',\n        method: 'POST',\n        url: 'https://api.example.com/data',\n        status: 200,\n      });\n    });\n  });\n\n  describe('failed requests', () => {\n    it('should track network errors', async () => {\n      const networkError = new TypeError('Failed to fetch');\n      originalFetchMock.mockRejectedValue(networkError);\n\n      networkObserver.subscribe(new NetworkEventCallback(callback));\n\n      await expect(globalScope.fetch('https://api.example.com/data')).rejects.toThrow('Failed to fetch');\n\n      expect(events).toHaveLength(1);\n      const networkRequestEvent = events[0];\n      expect(networkRequestEvent.toSerializable()).toEqual({\n        type: 'fetch',\n        method: 'GET',\n        url: 'https://api.example.com/data',\n        error: {\n          name: 'TypeError',\n          message: 'Failed to fetch',\n        },\n        duration: networkRequestEvent.duration,\n        status: networkRequestEvent.status,\n        startTime: expect.any(Number),\n        endTime: expect.any(Number),\n        timestamp: expect.any(Number),\n        requestHeaders: networkRequestEvent.requestWrapper?.headers([...SAFE_HEADERS]),\n        requestBodySize: networkRequestEvent.requestWrapper?.bodySize,\n        responseHeaders: networkRequestEvent.responseWrapper?.headers([...SAFE_HEADERS]),\n        responseBodySize: networkRequestEvent.responseWrapper?.bodySize,\n      });\n    });\n\n    it('should track aborted requests', async () => {\n      const abortError = new DOMException('Aborted', 'AbortError');\n      originalFetchMock.mockRejectedValue(abortError);\n      networkObserver.subscribe(new NetworkEventCallback(callback));\n      const controller = new AbortController();\n      const signal = controller.signal;\n      controller.abort();\n      await expect(globalScope.fetch('https://api.example.com/data', { signal })).rejects.toThrow('Aborted');\n      expect(events).toHaveLength(1);\n      expect(events[0]).toMatchObject({\n        type: 'fetch',\n        method: 'GET',\n        url: 'https://api.example.com/data',\n        error: {\n          name: 'AbortError',\n          message: 'Aborted',\n        },\n      });\n      expect(events[0].status).toBe(0);\n      expect(events[0].duration).toBeGreaterThanOrEqual(0);\n    });\n\n    it('should handle non-Error throws', async () => {\n      originalFetchMock.mockRejectedValue('string error');\n      const cb = new NetworkEventCallback(callback);\n      networkObserver.subscribe(cb);\n\n      await expect(globalScope.fetch('https://api.example.com/data')).rejects.toBe('string error');\n\n      expect(events).toHaveLength(1);\n      expect(events[0].error).toEqual({\n        name: 'UnknownError',\n        message: 'An unknown error occurred',\n      });\n    });\n  });\n\n  describe('fetch calls with junk data', () => {\n    it('should pass junk data to originalfetch', async () => {\n      const mockResponse = {\n        status: 500,\n        headers: {\n          forEach: jest.fn(), // Mock function that does nothing\n        },\n      };\n      originalFetchMock.mockResolvedValue(mockResponse);\n      networkObserver.subscribe(new NetworkEventCallback(callback));\n      expect(globalScope.fetch).not.toBe(originalFetchMock);\n\n      const fetchJunkArgs = [\n        [12345 as any, undefined],\n        [null, null],\n        [[1, 2, 3], { a: 1 }],\n        [true, [1, 2, 3]],\n        [undefined, undefined],\n        ['two', 'args'],\n        [undefined, { method: 'POST' }],\n      ];\n\n      // checks that the original fetch is called with the same junk data\n      for (const args of fetchJunkArgs) {\n        /* eslint-disable @typescript-eslint/no-unsafe-argument */\n        const res = await globalScope.fetch(...(args as [any, any]));\n        expect(originalFetchMock).toHaveBeenCalledWith(...args);\n        expect(res).toEqual(mockResponse);\n        /* eslint-enable @typescript-eslint/no-unsafe-argument */\n      }\n    });\n  });\n\n  describe('observer lifecycle', () => {\n    it('should throw an exception if fetch is not supported', async () => {\n      // Mock the global scope to not have fetch\n      const scopeWithoutFetch = {} as typeof globalThis;\n      jest.spyOn(Global, 'getGlobalScope').mockReturnValue(scopeWithoutFetch);\n      const localLogger = {\n        error: jest.fn(),\n        disable: jest.fn(),\n        enable: jest.fn(),\n        warn: jest.fn(),\n        debug: jest.fn(),\n        log: jest.fn(),\n      };\n      new NetworkObserver(localLogger);\n    });\n\n    it('should handle missing global scope', () => {\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue(undefined);\n      const cb = new NetworkEventCallback(callback);\n      networkObserver.subscribe(cb);\n\n      expect(() => networkObserver.unsubscribe(cb)).not.toThrow();\n    });\n\n    it('should call eventCallback with request event data', async () => {\n      const mockCallback = jest.fn();\n      const mockResponse = {\n        status: 200,\n        headers: {\n          forEach: (callback: (value: string, key: string) => void) => {\n            callback('application/json', 'content-type');\n          },\n        },\n      };\n      originalFetchMock.mockResolvedValue(mockResponse);\n      const cb = new NetworkEventCallback(mockCallback);\n      networkObserver.subscribe(cb);\n\n      await globalScope.fetch('https://api.example.com/data', {\n        method: 'POST',\n        headers: { 'Content-Type': 'application/json' },\n      });\n\n      expect(mockCallback).toHaveBeenCalledTimes(1);\n    });\n\n    it('should handle notifyEvent with optional chaining', async () => {\n      const mockEvent = {\n        timestamp: Date.now(),\n        type: 'fetch' as const,\n        method: 'GET',\n        url: 'https://api.example.com/data',\n        startTime: Date.now(),\n        status: 200,\n        toSerializable: () => ({ ...mockEvent }),\n      };\n\n      // Test with callback\n      const mockCallback = jest.fn();\n      const cb = new NetworkEventCallback(mockCallback);\n      networkObserver.subscribe(cb);\n      networkObserver.testNotifyEvent(mockEvent);\n      expect(mockCallback).toHaveBeenCalledWith(mockEvent);\n\n      // Test without callback\n      networkObserver.unsubscribe(cb);\n      networkObserver.testNotifyEvent(mockEvent);\n      expect(mockCallback).toHaveBeenCalledTimes(1); // Still only called once\n    });\n  });\n\n  describe('RequestWrapperFetch', () => {\n    describe('body should return the text', () => {\n      it('string', () => {\n        const body = 'Hello World!';\n        const requestWrapper = new RequestWrapperFetch({\n          body,\n        } as RequestInitSafe);\n        expect(requestWrapper.body).toBe(body);\n      });\n    });\n    describe('bodySize should return the body length when the body is of type', () => {\n      it('string', () => {\n        const body = 'Hello World!';\n        const requestWrapper = new RequestWrapperFetch({\n          body,\n        } as RequestInitSafe);\n        expect(requestWrapper.bodySize).toBe(body.length);\n        expect(requestWrapper.bodySize).toBe(body.length); // do it again to make sure it's cached\n      });\n      it('Blob', () => {\n        const blob = new Blob(['Hello World!']);\n        const requestWrapper = new RequestWrapperFetch({\n          body: blob,\n        } as RequestInitSafe);\n        expect(requestWrapper.bodySize).toBe(blob.size);\n      });\n      it('ArrayBuffer', () => {\n        const buffer = new ArrayBuffer(8);\n        for (let i = 0; i < buffer.byteLength; i++) {\n          (buffer as any)[i] = i;\n        }\n        const requestWrapper = new RequestWrapperFetch({\n          body: buffer,\n          text: () => Promise.resolve(null),\n        } as RequestInitSafe);\n        expect(requestWrapper.bodySize).toBe(buffer.byteLength);\n        expect(buffer.byteLength).toBe(8);\n\n        // check that the array buffer is not modified\n        for (let i = 0; i < buffer.byteLength; i++) {\n          expect((buffer as any)[i]).toBe(i);\n        }\n      });\n      it('ArrayBufferView', () => {\n        const buffer = new ArrayBuffer(8);\n        const arr = new Uint8Array(buffer);\n        for (let i = 0; i < arr.length; i++) {\n          arr[i] = i;\n        }\n        const requestWrapper = new RequestWrapperFetch({\n          body: arr,\n          text: () => Promise.resolve(null),\n        } as RequestInitSafe);\n        expect(requestWrapper.bodySize).toBe(arr.byteLength);\n\n        // check that the array buffer is not modified\n        expect(arr.byteLength).toBe(8);\n        for (let i = 0; i < arr.length; i++) {\n          expect(arr[i]).toBe(i);\n        }\n      });\n      it('FormData', () => {\n        // construct FormData with 2 entries\n        const formData = new FormData();\n        const val = 'value';\n        formData.append('key', val);\n        const blob = new Blob(['Hello World!']);\n        formData.append('file', blob);\n        const expectedSize = val.length + blob.size + 'key'.length + 'file'.length;\n        const requestWrapper = new RequestWrapperFetch({\n          body: formData as unknown as FetchRequestBody,\n        } as RequestInitSafe);\n\n        // spy on all methods that are not safe to call on FormData\n        const unsafeFormDataMethods = ['append', 'delete', 'set'];\n        const spies = [];\n        for (const method of unsafeFormDataMethods) {\n          // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n          const spy = jest.spyOn(FormData.prototype, method as any);\n          spies.push({ spy, method });\n        }\n\n        // assert bodySize is correct and that no unsafe methods were called\n        expect(requestWrapper.bodySize).toBe(expectedSize);\n        expect(spies.length).toBe(unsafeFormDataMethods.length);\n        for (const { spy } of spies) {\n          expect(spy.mock.calls.length).toBe(0);\n        }\n      });\n      it('URLSearchParams', () => {\n        const params = new URLSearchParams();\n        const val = 'value';\n        params.append('key', val);\n        const val2 = 'value2';\n        params.append('key2', val2);\n        const expectedSize = 'key='.length + val.length + '&key2='.length + val2.length;\n\n        const unsafeURLSearchParamsMethods = ['append', 'delete', 'set'];\n        const spies = [];\n        for (const method of unsafeURLSearchParamsMethods) {\n          // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n          const spy = jest.spyOn(URLSearchParams.prototype, method as any);\n          spies.push({ spy, method });\n        }\n\n        const requestWrapper = new RequestWrapperFetch({\n          body: params,\n          text: () => Promise.resolve(null),\n        } as RequestInitSafe);\n        expect(requestWrapper.bodySize).toBe(expectedSize);\n        expect(spies.length).toBe(unsafeURLSearchParamsMethods.length);\n        for (const { spy } of spies) {\n          expect(spy.mock.calls.length).toBe(0);\n        }\n      });\n    });\n\n    describe('bodySize should return undefined when', () => {\n      it('FormData has an unexpected type', () => {\n        // hack FormData to include an entry with an unexpected type\n        // (this test )\n        // eslint-disable-next-line @typescript-eslint/no-empty-function\n        const HackedFormData = function () {};\n        HackedFormData.prototype = Object.create(FormData.prototype);\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n        HackedFormData.prototype.entries = function () {\n          return [\n            ['key', 'value'],\n            ['unknown', new ArrayBuffer(8)],\n          ];\n        };\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n        const formData = new (HackedFormData as any)();\n        const requestWrapper = new RequestWrapperFetch({\n          body: formData as unknown as FetchRequestBody,\n        } as RequestInitSafe);\n        expect(requestWrapper.bodySize).toBeUndefined();\n      });\n      it('FormData has >100 entries', () => {\n        const formData = new FormData();\n        for (let i = 0; i < 101; i++) {\n          formData.append(`key${i}`, `value${i}`);\n        }\n        const requestWrapper = new RequestWrapperFetch({\n          body: formData as unknown as FetchRequestBody,\n        } as RequestInitSafe);\n        expect(requestWrapper.bodySize).toBeUndefined();\n      });\n      it('body is undefined', () => {\n        const body = undefined;\n        const requestWrapper = new RequestWrapperFetch({\n          body,\n        } as RequestInitSafe);\n        expect(requestWrapper.bodySize).toBeUndefined();\n      });\n      it('globalScope is not available', () => {\n        jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue(undefined);\n        const body = 'Hello World!';\n        const requestWrapper = new RequestWrapperFetch({\n          body,\n        } as RequestInitSafe);\n        expect(requestWrapper.bodySize).toBeUndefined();\n      });\n    });\n\n    describe('headers() should return', () => {\n      it('{} when allowlist is empty', () => {\n        const requestWrapper = new RequestWrapperFetch({\n          headers: {\n            'Content-Type': 'application/fake',\n            'Content-Length': '100',\n          },\n        } as RequestInitSafe);\n        expect(requestWrapper.headers([])).toEqual({});\n      });\n      it('an object when headers is an array', () => {\n        const requestWrapper = new RequestWrapperFetch({\n          headers: [\n            ['Content-Type', 'application/fake'],\n            ['Content-Length', '1234'],\n          ],\n        } as RequestInitSafe);\n        expect(requestWrapper.headers([...SAFE_HEADERS])).toEqual({\n          'Content-Type': 'application/fake',\n          'Content-Length': '1234',\n        });\n      });\n      it('{} when headers is undefined', () => {\n        const requestWrapper = new RequestWrapperFetch({\n          headers: undefined,\n        } as RequestInitSafe);\n        expect(requestWrapper.headers()).toEqual({});\n      });\n    });\n\n    test('RequestWrapper interface changed. Make sure you know what you are doing.', () => {\n      const props = Object.getOwnPropertyNames(RequestWrapperFetch.prototype);\n      const expectedProps = ['headers', 'bodySize'];\n      expectedProps.forEach((prop) => {\n        expect(props).toContain(prop);\n      });\n    });\n  });\n\n  describe('ResponseWrapperFetch', () => {\n    let mockResponse: any;\n    const mockBody = { message: 'Hello from mock!', secret: 'secret' };\n    beforeEach(() => {\n      mockResponse = {\n        body: null,\n        bodyUsed: false,\n        headers: new Headers({ 'Content-Type': 'application/json' }),\n        ok: true,\n        redirected: false,\n        status: 200,\n        statusText: 'OK',\n        type: 'basic',\n        url: 'https://api.example.com/data',\n        clone: () => mockResponse as unknown as Response,\n        arrayBuffer: async () => new ArrayBuffer(0),\n        blob: async () => new Blob(),\n        formData: async () => new FormData(),\n        json: async () => mockBody,\n        text: async () => JSON.stringify(mockBody),\n      };\n    });\n\n    describe('.json()', () => {\n      test('should return null if allowlist and exclude are undefined', async () => {\n        const responseWrapper = new ResponseWrapperFetch(mockResponse as unknown as Response);\n        const json = await responseWrapper.json();\n        expect(json).toEqual(null);\n      });\n\n      test('json should return null if no rules are set', async () => {\n        const responseWrapper = new ResponseWrapperFetch(mockResponse as unknown as Response);\n        const json = await responseWrapper.json([], []);\n        expect(json).toEqual(null);\n      });\n\n      test('json should include allowed fields in response', async () => {\n        const responseWrapper = new ResponseWrapperFetch(mockResponse as unknown as Response);\n        const json = await responseWrapper.json(['message'], []);\n        expect(json).toEqual({ message: 'Hello from mock!' });\n      });\n\n      test('json should exclude excluded fields in response', async () => {\n        const responseWrapper = new ResponseWrapperFetch(mockResponse as unknown as Response);\n        const json = await responseWrapper.json(['**'], ['secret']);\n        expect(json).toEqual({ message: 'Hello from mock!' });\n      });\n\n      test('should gracefully handle non-json responses', async () => {\n        const mockResponseBadJson = {\n          ...mockResponse,\n          text: async () => 'not valid json',\n          clone: () => mockResponseBadJson as unknown as Response,\n        };\n        const responseWrapper = new ResponseWrapperFetch(mockResponseBadJson as unknown as Response);\n        const json = await responseWrapper.json(['**'], []);\n        expect(json).toEqual(null);\n      });\n\n      test('should gracefully handle no body in response', async () => {\n        const mockResponseNoText = {\n          ...mockResponse,\n          text: async () => undefined,\n          clone: () => mockResponseNoText as unknown as Response,\n        };\n        const responseWrapper = new ResponseWrapperFetch(mockResponseNoText as unknown as Response);\n        const json = await responseWrapper.json(['**'], []);\n        expect(json).toEqual(null);\n      });\n    });\n\n    describe('.headers()', () => {\n      test('should return {} if allowlist is empty', () => {\n        const responseWrapper = new ResponseWrapperFetch(mockResponse as unknown as Response);\n        expect(responseWrapper.headers()).toEqual({});\n      });\n    });\n\n    test('text should return null if text returns nothing', async () => {\n      const mockResponseNonJson = {\n        ...mockResponse,\n        text: async () => null,\n        clone: () => mockResponseNonJson as unknown as Response,\n      };\n      const responseWrapper = new ResponseWrapperFetch(mockResponseNonJson as unknown as Response);\n      const json = await responseWrapper.text();\n      expect(json).toBeNull();\n    });\n\n    test('text should return null if text throws an error', async () => {\n      const mockResponseNonJson = {\n        ...mockResponse,\n        text: async () => {\n          throw new Error('some error');\n        },\n        clone: () => mockResponseNonJson as unknown as Response,\n      };\n      const responseWrapper = new ResponseWrapperFetch(mockResponseNonJson as unknown as Response);\n      const json = await responseWrapper.text();\n      expect(json).toBeNull();\n    });\n\n    test('text should return a value', async () => {\n      const mockedClone: any = jest.fn(() => mockResponseNonJson as unknown as Response);\n      const mockResponseNonJson = {\n        ...mockResponse,\n        text: async () => 'some text',\n        clone: mockedClone,\n      };\n      const responseWrapper = new ResponseWrapperFetch(mockResponseNonJson as unknown as Response);\n      const text = await responseWrapper.text();\n      expect(text).toBe('some text');\n      const text2 = await responseWrapper.text();\n      expect(text2).toBe('some text');\n\n      // calling text 2x should not clone the response again\n      expect(mockedClone).toHaveBeenCalledTimes(1);\n    });\n\n    test('bodySize should return undefined if content-length is not set', () => {\n      const responseWrapper = new ResponseWrapperFetch(mockResponse as unknown as Response);\n      const bodySize = responseWrapper.bodySize;\n      expect(bodySize).toBeUndefined();\n    });\n\n    test('bodySize should return the content-length if set', () => {\n      const responseWithContentLength = {\n        ...mockResponse,\n        headers: new Headers({ 'Content-Type': 'application/json', 'Content-Length': '1234' }),\n      };\n      const responseWrapper = new ResponseWrapperFetch(responseWithContentLength as unknown as Response);\n      expect(responseWrapper.bodySize).toBe(1234);\n      expect(responseWrapper.bodySize).toBe(1234); // 2x to check that it's cached\n    });\n\n    test('ResponseWrapper interface changed. Make sure you know what you are doing.', () => {\n      const props = Object.getOwnPropertyNames(ResponseWrapperFetch.prototype);\n      const expectedProps = ['headers', 'bodySize'];\n      expectedProps.forEach((prop) => {\n        expect(props).toContain(prop);\n      });\n    });\n  });\n});\n\ndescribe('serializeNetworkRequestEvent', () => {\n  it('should serialize a NetworkRequestEvent', () => {\n    const event = {\n      type: 'fetch',\n      method: 'GET',\n      url: 'https://api.example.com/data',\n      status: 200,\n      duration: 100,\n      startTime: 100,\n      endTime: 200,\n      timestamp: 100,\n      requestWrapper: {\n        bodySize: 100,\n        headers: () => ({\n          'Content-Type': 'application/json',\n        }),\n      },\n      responseWrapper: {\n        bodySize: 100,\n        headers: () => ({\n          'Content-Type': 'application/json',\n        }),\n      },\n    } as unknown as NetworkRequestEvent;\n    /* eslint-disable @typescript-eslint/unbound-method */\n    event.toSerializable = NetworkRequestEvent.prototype.toSerializable;\n    const serialized = event.toSerializable();\n    expect(serialized).toEqual({\n      type: 'fetch',\n      method: 'GET',\n      url: 'https://api.example.com/data',\n      status: 200,\n      duration: 100,\n      startTime: 100,\n      endTime: 200,\n      timestamp: 100,\n      requestBodySize: 100,\n      requestHeaders: {\n        'Content-Type': 'application/json',\n      },\n      responseBodySize: 100,\n      responseHeaders: {\n        'Content-Type': 'application/json',\n      },\n    });\n  });\n});\n\ndescribe('RequestWrapperXhr', () => {\n  test('body should return string if request.body is a string', async () => {\n    const requestWrapper = new RequestWrapperXhr('Hello World!', {});\n    expect(requestWrapper.body).toBe('Hello World!');\n  });\n\n  test('body should return null if request.body is not a string', async () => {\n    const requestWrapper = new RequestWrapperXhr(new Blob(['Hello World!']), {});\n    expect(requestWrapper.body).toBeNull();\n  });\n\n  describe('.headers()', () => {\n    test('should return undefined if allowlist empty', () => {\n      const requestWrapper = new RequestWrapperXhr('Hello World!', {});\n      expect(requestWrapper.headers()).toEqual({});\n    });\n  });\n\n  describe('.json()', () => {\n    test('should return null if allowlist and exclude are empty', async () => {\n      const requestWrapper = new RequestWrapperXhr(\n        JSON.stringify({ message: 'Hello from mock!', secret: 'secret' }),\n        {},\n      );\n      const json = await requestWrapper.json();\n      expect(json).toEqual(null);\n    });\n\n    test('should parse body as JSON', async () => {\n      const requestWrapper = new RequestWrapperXhr(\n        JSON.stringify({ message: 'Hello from mock!', secret: 'secret' }),\n        {},\n      );\n      const json = await requestWrapper.json(['message', 'secret'], ['secret']);\n      expect(json).toEqual({ message: 'Hello from mock!' });\n    });\n  });\n});\n\ndescribe('observeXhr', () => {\n  interface MockXHROptions {\n    readyState?: number;\n    status?: number;\n    responseText?: string;\n  }\n\n  class MockXHR {\n    readyState = 4;\n    status = 200;\n    responseText: string = JSON.stringify({ success: true });\n    responseType: XMLHttpRequestResponseType = '';\n    response: any = { success: true };\n    onreadystatechange: (() => void) | null = null;\n    openCalled = false;\n    sendCalled = false;\n    setRequestHeaderCalled = false;\n\n    constructor(options?: MockXHROptions) {\n      if (options) {\n        if (options.readyState !== undefined) this.readyState = options.readyState;\n        if (options.status !== undefined) this.status = options.status;\n        if (options.responseText !== undefined) this.responseText = options.responseText;\n      }\n    }\n\n    getAllResponseHeaders(): string {\n      return 'Content-Type: application/json\\r\\nContent-Length: 1234';\n    }\n\n    getResponseHeader(header: string): string | null {\n      if (header === 'content-type') {\n        return 'application/json';\n      }\n      if (header === 'content-length') {\n        return '1234';\n      }\n      return null;\n    }\n\n    addEventListener(event: string, callback: () => void): void {\n      if (event === 'loadend') {\n        this.onreadystatechange = callback;\n      }\n    }\n\n    open(): void {\n      this.openCalled = true;\n    }\n\n    send(): void {\n      this.sendCalled = true;\n      if (typeof this.onreadystatechange === 'function') {\n        this.onreadystatechange();\n      }\n    }\n\n    setRequestHeader(header: string, value: string): void {\n      this.setRequestHeaderCalled = true;\n      (this as any)[header] = value;\n    }\n  }\n\n  let networkObserver: any, originalGlobal;\n  let originalMockXhrOpen: typeof MockXHR.prototype.open;\n  let originalMockXhrSend: typeof MockXHR.prototype.send;\n  let originalMockXhrSetRequestHeader: typeof MockXHR.prototype.setRequestHeader;\n\n  beforeAll(() => {\n    // override globalScope to include mock XHR\n    originalGlobal = AnalyticsCore.getGlobalScope();\n    networkObserver = new NetworkObserver();\n    (networkObserver as unknown as any).globalScope = {\n      ...originalGlobal,\n      XMLHttpRequest: MockXHR,\n      TextEncoder,\n    } as any;\n    // Save original MockXHR methods so we can restore between tests (patch persists across tests otherwise)\n    originalMockXhrOpen = MockXHR.prototype.open;\n    originalMockXhrSend = MockXHR.prototype.send;\n    originalMockXhrSetRequestHeader = MockXHR.prototype.setRequestHeader;\n  });\n\n  afterAll(() => {});\n\n  describe('calls mock XHR', () => {\n    // eslint-disable-next-line jest/no-done-callback\n    it('should call mockXHR and retrieve event and still call original open/send', (done) => {\n      const originalOpenSpy = jest.spyOn(MockXHR.prototype, 'open');\n      const originalSendSpy = jest.spyOn(MockXHR.prototype, 'send');\n      const originalSetRequestHeaderSpy = jest.spyOn(MockXHR.prototype, 'setRequestHeader');\n      const callback = (event: NetworkRequestEvent) => {\n        try {\n          expect(originalOpenSpy).toHaveBeenCalledWith('GET', 'https://api.example.com/data');\n          expect(originalSendSpy).toHaveBeenCalledWith('hello world!');\n          expect(originalSetRequestHeaderSpy).toHaveBeenCalledWith('Authorization', 'secretpassword!');\n          expect(originalSetRequestHeaderSpy).toHaveBeenCalledWith('X-Custom-Header', 'customvalue');\n          expect(event.status).toBe(200);\n          expect(event.type).toBe('xhr');\n          expect(event.method).toBe('GET');\n          expect(event.url).toBe('https://api.example.com/data');\n          expect(event.responseWrapper?.headers([...SAFE_HEADERS])).toEqual({\n            'Content-Type': 'application/json',\n            'Content-Length': '1234',\n          });\n          expect(event.responseWrapper?.bodySize).toBe(1234);\n          const responseWrapperXhr = event.responseWrapper as ResponseWrapperXhr;\n          expect(responseWrapperXhr.getJson?.()).toEqual({ success: true });\n          expect(event.requestWrapper?.headers([])).toEqual({});\n          expect(event.requestWrapper?.bodySize).toBe('hello world!'.length);\n          expect(event.duration).toBeGreaterThanOrEqual(0);\n          expect(event.startTime).toBeGreaterThanOrEqual(0);\n          expect(event.endTime).toBeGreaterThanOrEqual(event.startTime);\n          expect(event.timestamp).toBeGreaterThanOrEqual(event.startTime);\n          expect(xhr.openCalled).toBe(true);\n          expect(xhr.sendCalled).toBe(true);\n          done();\n        } catch (error) {\n          done(error);\n        }\n      };\n      networkObserver.subscribe(new NetworkEventCallback(callback), undefined, true);\n      const XMLHttpRequest = (networkObserver as unknown as any).globalScope.XMLHttpRequest;\n      const xhr = new XMLHttpRequest();\n      xhr.open('GET', 'https://api.example.com/data');\n      xhr.setRequestHeader('Authorization', 'secretpassword!');\n      xhr.setRequestHeader('X-Custom-Header', 'customvalue');\n      xhr.send('hello world!');\n    });\n\n    // eslint-disable-next-line jest/no-done-callback\n    describe('xhr.open monkey-patching order matters', () => {\n      // Use a fresh observer so the first test's subscribe() actually patches MockXHR (shared observer already has isObserving=true)\n      let networkObserver2: NetworkObserver;\n      beforeAll(() => {\n        MockXHR.prototype.open = originalMockXhrOpen;\n        MockXHR.prototype.send = originalMockXhrSend;\n        MockXHR.prototype.setRequestHeader = originalMockXhrSetRequestHeader;\n        networkObserver2 = new NetworkObserver();\n        (networkObserver2 as unknown as any).globalScope = (networkObserver as unknown as any).globalScope;\n      });\n      beforeEach(() => {\n        jest.useFakeTimers();\n      });\n      afterEach(() => {\n        jest.useRealTimers();\n      });\n      it('should not track event when xhr.open is called before patch ($$AmplitudeAnalyticsEvent not set)', () => {\n        const XMLHttpRequest = (networkObserver2 as unknown as any).globalScope.XMLHttpRequest;\n        const xhr = new XMLHttpRequest();\n        xhr.open('GET', 'https://api.example.com/data');\n        let callbackInvoked = false;\n        const callback = () => {\n          callbackInvoked = true;\n        };\n        const callbackToUnsubscribe = new NetworkEventCallback(callback);\n        networkObserver2.subscribe(callbackToUnsubscribe);\n        networkObserver2.subscribe(new NetworkEventCallback(callback));\n        expect(xhr.sendCalled).toBe(false);\n        expect(xhr.setRequestHeaderCalled).toBe(false);\n        xhr.setRequestHeader('X-Custom-Header', 'customvalue');\n        xhr.send('body');\n        jest.runAllTimers();\n        expect(callbackInvoked).toBe(false);\n        expect(xhr.sendCalled).toBe(true);\n        expect(xhr.setRequestHeaderCalled).toBe(true);\n        expect(xhr.$$AmplitudeAnalyticsEvent).toBeUndefined();\n        networkObserver2.unsubscribe(callbackToUnsubscribe);\n      });\n\n      it('should invoke callback when xhr.open is called after patch ($$AmplitudeAnalyticsEvent set)', () => {\n        const XMLHttpRequest = (networkObserver2 as unknown as any).globalScope.XMLHttpRequest;\n        const xhr = new XMLHttpRequest();\n        let callbackInvoked = false;\n        const callback = () => {\n          callbackInvoked = true;\n        };\n        networkObserver2.subscribe(new NetworkEventCallback(callback));\n        xhr.open('GET', 'https://api.example.com/data');\n        expect(xhr.sendCalled).toBe(false);\n        expect(xhr.setRequestHeaderCalled).toBe(false);\n        xhr.setRequestHeader('X-Custom-Header', 'customvalue');\n        xhr.send('body');\n        jest.advanceTimersByTime(100);\n        expect(xhr.$$AmplitudeAnalyticsEvent).toBeDefined();\n        expect(callbackInvoked).toBe(true);\n      });\n    });\n  });\n\n  describe('createXhrJsonParser()', () => {\n    test('should return null if responseType is not supported', () => {\n      const xhr = {\n        responseType: 'ArrayBuffer',\n        get responseText() {\n          throw new Error('some error');\n        },\n        get response() {\n          throw new Error('some error');\n        },\n      };\n      const networkObserver = new NetworkObserver();\n      const getJson = NetworkObserver.createXhrJsonParser(xhr as unknown as XMLHttpRequest, networkObserver);\n      expect(getJson()).toBeNull();\n    });\n\n    test('should return parsed JSON if responseType is text', () => {\n      const xhr = {\n        responseType: 'text',\n        responseText: '{\"message\": \"Hello from mock!\"}',\n        get response() {\n          throw new Error('some error');\n        },\n      };\n      const networkObserver = new NetworkObserver();\n      const getJson = NetworkObserver.createXhrJsonParser(xhr as unknown as XMLHttpRequest, networkObserver);\n      expect(getJson()).toEqual({ message: 'Hello from mock!' });\n    });\n\n    test('should return JS object if responseType is json', () => {\n      const xhr = {\n        responseType: 'json',\n        response: { message: 'Hello from mock!' },\n        get responseText() {\n          throw new Error('some error');\n        },\n      };\n      const networkObserver = new NetworkObserver();\n      (networkObserver as unknown as any).globalScope = {\n        structuredClone: (obj: any) => JSON.parse(JSON.stringify(obj)),\n      };\n      const getJson = NetworkObserver.createXhrJsonParser(xhr as unknown as XMLHttpRequest, networkObserver);\n      const jsOutput = getJson();\n      expect(jsOutput).toEqual({ message: 'Hello from mock!' });\n      expect(jsOutput).not.toBe(xhr.response);\n    });\n\n    test('should return null if browser is very old and does not support structuredClone', () => {\n      const xhr = {\n        responseType: 'json',\n        response: { message: 'Hello from mock!' },\n        get responseText() {\n          throw new Error('some error');\n        },\n      };\n      const networkObserver = new NetworkObserver();\n      (networkObserver as unknown as any).globalScope = null;\n      const getJson = NetworkObserver.createXhrJsonParser(xhr as unknown as XMLHttpRequest, networkObserver);\n      expect(getJson()).toEqual(null);\n    });\n\n    test('should return null if response is string andnot valid JSON', () => {\n      const xhr = {\n        responseType: 'text',\n        responseText: 'not valid json',\n        get response() {\n          throw new Error('some error');\n        },\n      };\n      const networkObserver = new NetworkObserver();\n      const getJson = NetworkObserver.createXhrJsonParser(xhr as unknown as XMLHttpRequest, networkObserver);\n      expect(getJson()).toEqual(null);\n    });\n  });\n});\n\ndescribe('ResponseWrapperXhr', () => {\n  describe('.headers()', () => {\n    test('should return {} if allowlist is empty', () => {\n      const responseWrapper = new ResponseWrapperXhr(200, '', 0, () => 'some body');\n      expect(responseWrapper.headers()).toEqual({});\n    });\n\n    test('should return {} if headerString is empty', () => {\n      const responseWrapper = new ResponseWrapperXhr(200, '', 0, () => 'some body');\n      expect(responseWrapper.headers()).toEqual({});\n    });\n  });\n\n  test('should return {} if headersString is empty', async () => {\n    const responseWrapper = new ResponseWrapperXhr(200, 'hello=world', 0, () => 'some text');\n    expect(responseWrapper.headers()).toEqual({});\n  });\n\n  describe('.json()', () => {\n    test('should return null if allowlist and exclude are empty', async () => {\n      const responseWrapper = new ResponseWrapperXhr(200, '', 0, () => 'some body');\n      const json = await responseWrapper.json();\n      expect(json).toEqual(null);\n    });\n\n    test('should return null if allowlist is empty', async () => {\n      const responseWrapper = new ResponseWrapperXhr(200, '', 0, () => 'some body');\n      const json = await responseWrapper.json([], ['secret']);\n      expect(json).toEqual(null);\n    });\n\n    test('should parse JSON response', async () => {\n      const response = {\n        message: 'Hello from mock!',\n        secret: 'secret',\n      };\n      const responseWrapper = new ResponseWrapperXhr(200, '', 0, () => response);\n      const json = await responseWrapper.json(['message'], ['secret']);\n      expect(json).toEqual({ message: 'Hello from mock!' });\n    });\n\n    test('should return null if text is empty', async () => {\n      const responseWrapper = new ResponseWrapperXhr(200, '', 0, () => '');\n      const json = await responseWrapper.json(['**'], []);\n      expect(json).toEqual(null);\n    });\n\n    test('should return null if text is not valid json', async () => {\n      const getJson = () => {\n        try {\n          return JSON.parse('not valid json');\n        } catch (e) {\n          return null;\n        }\n      };\n      const responseWrapper = new ResponseWrapperXhr(200, '', 0, getJson);\n      const json = await responseWrapper.json(['**'], []);\n      expect(json).toEqual(null);\n    });\n  });\n});\n\ndescribe('RequestWrapperFetch', () => {\n  test(\n    `ReadableStream should always return bodySize=undefined and never be consumed. ` +\n      `If this test fails, it means that the ReadableStream is being consumed ` +\n      `and needs to be fixed. No exceptions.`,\n    () => {\n      const readableStream = new streams.ReadableStream({\n        start(controller) {\n          controller.enqueue(new TextEncoder().encode('Hello World!'));\n          controller.close();\n        },\n      });\n\n      // spy on all of ReadableStream methods\n      const spies = [];\n      const methods = Object.getOwnPropertyNames(streams.ReadableStream.prototype);\n      for (const method of methods) {\n        if (typeof (readableStream as any)[method] === 'function') {\n          const spy = jest.spyOn(readableStream as any, method);\n          spies.push(spy);\n        }\n      }\n\n      const responseWrapper = new RequestWrapperFetch({\n        body: readableStream,\n        headers: new Headers({ 'Content-Type': 'application/json', 'Content-Length': '1234' }),\n        status: 200,\n      } as unknown as RequestInitSafe);\n      const bodySize = responseWrapper.bodySize;\n      expect(bodySize).toBeUndefined();\n\n      // check that no methods were called on ReadableStream\n      expect(spies.length).toBeGreaterThan(0);\n      for (const spy of spies) {\n        expect(spy).not.toHaveBeenCalled();\n      }\n    },\n  );\n\n  test('should return string if request.body is a string', () => {\n    const requestWrapper = new RequestWrapperFetch({\n      body: 'Hello World!',\n      headers: new Headers({ 'Content-Type': 'application/json', 'Content-Length': '1234' }),\n      status: 200,\n    } as unknown as RequestInitSafe);\n    expect(requestWrapper.body).toBe('Hello World!');\n  });\n\n  it('should return null if request.body is not a string', () => {\n    const requestWrapper = new RequestWrapperFetch({\n      body: null,\n      headers: new Headers({ 'Content-Type': 'application/json', 'Content-Length': '1234' }),\n      status: 200,\n    } as unknown as RequestInitSafe);\n    expect(requestWrapper.body).toBe(null);\n  });\n\n  describe('.json()', () => {\n    test('should return null if allowlist and exclude are empty', async () => {\n      const requestWrapper = new RequestWrapperFetch({\n        body: JSON.stringify({ message: 'Hello from mock!', secret: 'secret' }),\n        headers: new Headers({ 'Content-Type': 'application/json', 'Content-Length': '1234' }),\n        status: 200,\n      } as unknown as RequestInitSafe);\n      const json = await requestWrapper.json();\n      expect(json).toEqual(null);\n    });\n\n    test('should return null if allowlist is empty', async () => {\n      const requestWrapper = new RequestWrapperFetch({\n        body: JSON.stringify({ message: 'Hello from mock!', secret: 'secret' }),\n        headers: new Headers({ 'Content-Type': 'application/json', 'Content-Length': '1234' }),\n        status: 200,\n      } as unknown as RequestInitSafe);\n      const json = await requestWrapper.json([], ['secret']);\n      expect(json).toEqual(null);\n    });\n\n    test('should parse body as JSON', async () => {\n      const requestWrapper = new RequestWrapperFetch({\n        body: JSON.stringify({ message: 'Hello from mock!', secret: 'secret' }),\n        headers: new Headers({ 'Content-Type': 'application/json', 'Content-Length': '1234' }),\n        status: 200,\n      } as unknown as RequestInitSafe);\n      const json = await requestWrapper.json(['message'], ['secret']);\n      expect(json).toEqual({ message: 'Hello from mock!' });\n    });\n  });\n});\n\ndescribe('networkObserver', () => {\n  test('singleton should be an instance of NetworkObserver', () => {\n    expect(networkObserver).toBeInstanceOf(NetworkObserver);\n  });\n});\n\ndescribe('NetworkRequestEvent', () => {\n  test('status should be 0 if not set', () => {\n    const event = new NetworkRequestEvent('xhr', 'GET', 0, 0, 'https://api.example.com/data');\n    expect(event.status).toBe(0);\n  });\n});\n\ndescribe('pruneHeaders', () => {\n  test('should be empty object if allowlist is undefined', () => {\n    const headers = {\n      'Content-Type': 'application/json',\n      'Content-Length': '1234',\n      authorization: 'secretpassword!',\n    };\n    const prunedHeaders = pruneHeaders(headers, { allow: undefined });\n    expect(prunedHeaders).toEqual({});\n  });\n  test('should exclude headers that are forbidden', () => {\n    const headers = {\n      'Content-Type': 'application/json',\n      'Content-Length': '1234',\n      authorization: 'secretpassword!',\n    };\n    const prunedHeaders = pruneHeaders(headers, { allow: [...SAFE_HEADERS] });\n    expect(prunedHeaders).toEqual({\n      'Content-Type': 'application/json',\n      'Content-Length': '1234',\n    });\n  });\n\n  test('should include headers that are safe', () => {\n    const headers = {\n      'Content-Type': 'application/json',\n      'Content-Length': '1234',\n      'X-Custom-Header': 'customvalue',\n      authorization: 'secretpassword!',\n    };\n    const prunedHeaders = pruneHeaders(headers, { allow: [...SAFE_HEADERS] });\n    expect(prunedHeaders).toEqual({\n      'Content-Type': 'application/json',\n      'Content-Length': '1234',\n    });\n  });\n\n  test('should exclude unsafe headers even if in allowlist', () => {\n    const headers = {\n      'Content-Type': 'application/json',\n      'Content-Length': '1234',\n      'X-Custom-Header': 'customvalue',\n      authorization: 'secretpassword!',\n    };\n    const prunedHeaders = pruneHeaders(headers, { allow: ['authorization'] });\n    expect(prunedHeaders).toEqual({});\n  });\n\n  test('should delete forbidden headers if strategy is remove', () => {\n    const headers = {\n      'Content-Type': 'application/json',\n      'Content-Length': '1234',\n      'X-Custom-Header': 'customvalue',\n      authorization: 'secretpassword!',\n    };\n    const prunedHeaders = pruneHeaders(headers, {\n      allow: [...SAFE_HEADERS],\n      strategy: PRUNE_STRATEGY.REMOVE,\n    });\n    expect(prunedHeaders).toEqual({\n      'Content-Length': '1234',\n      'Content-Type': 'application/json',\n    });\n  });\n\n  test('should show headers as redacted if strategy is redact', () => {\n    const headers = {\n      'Content-Type': 'application/json',\n      'Content-Length': '1234',\n      authorization: 'secretpassword!',\n      cookie: 'secretcookie!',\n      'set-cookie': 'secretsetcookie!',\n      'X-Custom-Header': 'customvalue',\n      'Unallowed-Header': 'unallowed-value',\n    };\n    const prunedHeaders = pruneHeaders(headers, {\n      allow: [...SAFE_HEADERS, 'X-Custom-Header'],\n      strategy: PRUNE_STRATEGY.REDACT,\n    });\n    expect(prunedHeaders).toEqual({\n      'Content-Type': 'application/json',\n      'Content-Length': '1234',\n      authorization: '[REDACTED]',\n      cookie: '[REDACTED]',\n      'set-cookie': '[REDACTED]',\n      'X-Custom-Header': 'customvalue',\n      'Unallowed-Header': '[REDACTED]',\n    });\n\n    for (const forbiddenHeader of FORBIDDEN_HEADERS) {\n      expect(prunedHeaders[forbiddenHeader.toLowerCase()]).toBe('[REDACTED]');\n    }\n  });\n});\n\ndescribe('basic auth', () => {\n  test('should not capture basic auth', () => {\n    const networkObserver = new NetworkObserver();\n    const events: NetworkRequestEvent[] = [];\n    jest.spyOn(networkObserver as unknown as any, 'triggerEventCallbacks').mockImplementation((event) => {\n      events.push(event as NetworkRequestEvent);\n    });\n    networkObserver.handleNetworkRequestEvent(\n      'fetch',\n      'https://username:password@api.example.com/data',\n      undefined,\n      undefined,\n      undefined,\n      0,\n      0,\n    );\n    expect(events).toHaveLength(1);\n    console.log(events[0].url);\n    expect(events[0].url).toBe('https://api.example.com/data');\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/observers/console.test.ts",
    "content": "import { consoleObserver } from '../../src';\n\ndescribe('consoleObserver', () => {\n  beforeEach(() => {\n    // add memory property to console prototype\n    (globalThis.console as any).__proto__.memory = 12345;\n  });\n\n  afterEach(() => {\n    consoleObserver._restoreConsole();\n  });\n\n  describe('addListener', () => {\n    it('should call callback when console method is invoked', () => {\n      const callback = jest.fn();\n      consoleObserver.addListener('log', callback);\n      console.log('test message');\n      expect(callback).toHaveBeenCalledWith('log', ['test message']);\n    });\n\n    it('should support multiple callbacks for the same level', () => {\n      const callback1 = jest.fn();\n      consoleObserver.addListener('warn', callback1);\n      const callback2 = jest.fn();\n      consoleObserver.addListener('warn', callback2);\n\n      console.warn('warning');\n\n      expect(callback1).toHaveBeenCalledWith('warn', ['warning']);\n      expect(callback2).toHaveBeenCalledWith('warn', ['warning']);\n    });\n\n    it('should not call callback when console method is not a function', () => {\n      const callback = jest.fn();\n      consoleObserver.addListener('memory' as keyof Console, callback);\n      expect(typeof (globalThis.console as any).memory).toBe('number');\n      expect(callback).not.toHaveBeenCalled();\n    });\n\n    it('should not call callback if console is inside of a callback override', () => {\n      const callback = jest.fn(function () {\n        console.log('RECURSION!');\n      });\n      consoleObserver.addListener('log', callback);\n      console.log('test message');\n      expect(callback).toHaveBeenCalledWith('log', ['test message']);\n    });\n\n    it('should not break if callback throws an exception', () => {\n      const callback = jest.fn(function () {\n        throw new Error('Exception in callback!');\n      });\n      consoleObserver.addListener('log', callback);\n      console.log('test message');\n      expect(callback).toHaveBeenCalledWith('log', ['test message']);\n    });\n  });\n\n  describe('removeListener', () => {\n    it('should stop calling callback after removeListener', () => {\n      const callback1 = jest.fn();\n      const callback2 = jest.fn();\n      consoleObserver.addListener('log', callback1);\n      consoleObserver.addListener('log', callback2);\n\n      console.log('before');\n      expect(callback1).toHaveBeenCalledTimes(1);\n      expect(callback2).toHaveBeenCalledTimes(1);\n\n      consoleObserver.removeListener(callback1);\n\n      console.log('after');\n      expect(callback1).toHaveBeenCalledTimes(1);\n      expect(callback2).toHaveBeenCalledTimes(2);\n\n      consoleObserver.removeListener(callback2);\n\n      console.log('after remove all listeners');\n      expect(callback1).toHaveBeenCalledTimes(1);\n      expect(callback2).toHaveBeenCalledTimes(2);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/observers/video.test.ts",
    "content": "/**\n * @jest-environment jsdom\n */\n\njest.mock('../../src/video-analytics/track-video', () => ({\n  trackHtmlVideo: jest.fn(() => jest.fn()),\n  trackEmbeddedVideo: jest.fn(() => jest.fn()),\n}));\n\nimport { trackHtmlVideo, trackEmbeddedVideo } from '../../src/video-analytics/track-video';\nimport { EmbeddedVideoPlayer, VideoHandler } from '../../src/video-analytics/types';\nimport { VideoObserver } from '../../src/index';\n\ndescribe('VideoObserver', () => {\n  beforeEach(() => {\n    jest.clearAllMocks();\n  });\n\n  describe('constructor', () => {\n    it('should call trackHtmlVideo for a non-embedded HTML video element', () => {\n      const video = document.createElement('video');\n      new VideoObserver({\n        videoEl: video,\n        onStateChange: jest.fn(),\n      });\n      expect(trackHtmlVideo).toHaveBeenCalledTimes(1);\n    });\n\n    it('should call trackEmbeddedVideo when isEmbedded is true and vendor is mux', () => {\n      const player = null;\n      new VideoObserver({\n        videoEl: player as unknown as any,\n        onStateChange: jest.fn(),\n        vendor: 'mux',\n        isEmbedded: true,\n      });\n      expect(trackEmbeddedVideo).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('player state changes', () => {\n    let internalHandler: VideoHandler;\n    let videoObserver: VideoObserver;\n    let onStateChange: jest.Mock;\n\n    beforeEach(() => {\n      // trackEmbeddedVideo returns untrack; capture the handler when it is *registered*,\n      // not when destroy() runs the returned function.\n      (trackEmbeddedVideo as jest.Mock).mockImplementation(\n        (_player: EmbeddedVideoPlayer, handler: VideoHandler, _metadata: Record<string, string | number | boolean>) => {\n          internalHandler = handler;\n          return jest.fn();\n        },\n      );\n      onStateChange = jest.fn();\n      const mockPlayer = null;\n      videoObserver = new VideoObserver({\n        videoEl: mockPlayer as unknown as any,\n        onStateChange,\n        vendor: 'mux',\n        isEmbedded: true,\n      });\n    });\n\n    afterEach(() => {\n      videoObserver.destroy();\n    });\n\n    it('should track state changes', () => {\n      internalHandler.onPlay({\n        duration: 10,\n        last_position: undefined,\n      });\n      expect(onStateChange).toHaveBeenCalledWith(\n        { playbackState: 'paused', lastEvent: undefined },\n        expect.objectContaining({\n          playbackState: 'playing',\n          lastEvent: { duration: 10, last_position: undefined },\n        }),\n      );\n      internalHandler.onPause({\n        last_position: 5,\n        percent_completed: 50,\n        duration: 10,\n        stop_reason: 'paused',\n      });\n      expect(onStateChange).toHaveBeenCalledWith(\n        expect.objectContaining({\n          playbackState: 'playing',\n          lastEvent: { duration: 10, last_position: undefined },\n        }),\n        expect.objectContaining({\n          playbackState: 'paused',\n          lastEvent: {\n            last_position: 5,\n            percent_completed: 50,\n            duration: 10,\n            stop_reason: 'paused',\n          },\n        }),\n      );\n      internalHandler.onEnded({\n        last_position: 10,\n        percent_completed: 100,\n        duration: 10,\n        stop_reason: 'ended',\n      });\n      expect(onStateChange).toHaveBeenCalledWith(\n        expect.objectContaining({\n          playbackState: 'paused',\n          lastEvent: {\n            last_position: 5,\n            percent_completed: 50,\n            duration: 10,\n            stop_reason: 'paused',\n          },\n        }),\n        expect.objectContaining({\n          playbackState: 'ended',\n          lastEvent: {\n            last_position: 10,\n            percent_completed: 100,\n            duration: 10,\n            stop_reason: 'ended',\n          },\n        }),\n      );\n      internalHandler.onError('test error');\n    });\n\n    it('should not transition to seeking when onSeeking is called', () => {\n      internalHandler.onPlay({\n        duration: 10,\n        last_position: undefined,\n      });\n      expect(onStateChange).toHaveBeenCalledTimes(1);\n      internalHandler.onSeeking({\n        duration: 10,\n        last_position: undefined,\n        stop_reason: 'seeking',\n      });\n      internalHandler.onTimeUpdate({ position: 5, isSeeking: true });\n      expect(onStateChange).toHaveBeenCalledTimes(2);\n      expect(onStateChange).toHaveBeenCalledWith(\n        { playbackState: 'paused', lastEvent: undefined },\n        { playbackState: 'playing', lastEvent: { duration: 10, last_position: undefined } },\n      );\n    });\n\n    it('should clear isSeeking and sync position on onSeeked', () => {\n      internalHandler.onSeeking({\n        duration: 10,\n        last_position: undefined,\n      });\n      internalHandler.onSeeked({\n        duration: 10,\n        last_position: 8,\n      });\n      expect(onStateChange).toHaveBeenLastCalledWith(\n        expect.objectContaining({\n          isSeeking: true,\n        }),\n        expect.objectContaining({\n          isSeeking: false,\n        }),\n      );\n    });\n\n    describe('watch time (onTimeUpdate)', () => {\n      it('should not add position delta to watch time when not playing', () => {\n        internalHandler.onTimeUpdate({ position: 4, isSeeking: false });\n        expect(onStateChange).not.toHaveBeenCalled();\n      });\n\n      it('should not inflate watch time when isSeeking is true on timeupdate before observer onSeeking runs (embedded race)', () => {\n        internalHandler.onPlay({ duration: 10, last_position: 10 });\n        onStateChange.mockClear();\n        internalHandler.onTimeUpdate({ position: 100, isSeeking: true });\n        expect(onStateChange).not.toHaveBeenCalled();\n      });\n\n      it('should accumulate watch time from last_position while playing (delta from lastEvent.last_position)', () => {\n        internalHandler.onPlay({ duration: 10, last_position: 0 });\n        onStateChange.mockClear();\n\n        internalHandler.onTimeUpdate({ position: 2, isSeeking: false });\n        expect(onStateChange).toHaveBeenLastCalledWith(\n          expect.objectContaining({ playbackState: 'playing', lastEvent: { duration: 10, last_position: 0 } }),\n          expect.objectContaining({ playbackState: 'playing', watchTime: 2 }),\n        );\n\n        internalHandler.onTimeUpdate({ position: 5, isSeeking: false });\n        expect(onStateChange).toHaveBeenLastCalledWith(\n          expect.objectContaining({ playbackState: 'playing', watchTime: 2 }),\n          expect.objectContaining({ playbackState: 'playing', watchTime: 5 }),\n        );\n\n        // seeking should not add to watch time\n        internalHandler.onTimeUpdate({ position: 20, isSeeking: true });\n        internalHandler.onTimeUpdate({ position: 23, isSeeking: false });\n        expect(onStateChange).toHaveBeenLastCalledWith(\n          expect.objectContaining({ playbackState: 'playing', watchTime: 5 }),\n          expect.objectContaining({ playbackState: 'playing', watchTime: 8 }),\n        );\n      });\n\n      it('should use last_position on lastEvent as the previous position when present', () => {\n        internalHandler.onPlay({ duration: 10, last_position: 0 });\n        internalHandler.onTimeUpdate({ position: 3, isSeeking: false });\n        internalHandler.onPause({\n          duration: 10,\n          last_position: 3,\n          percent_completed: 30,\n          stop_reason: 'paused',\n        });\n        onStateChange.mockClear();\n\n        internalHandler.onPlay({ duration: 10, last_position: 3 });\n        internalHandler.onTimeUpdate({ position: 5, isSeeking: false });\n\n        expect(onStateChange).toHaveBeenLastCalledWith(\n          expect.objectContaining({ playbackState: 'playing', watchTime: 3 }),\n          expect.objectContaining({ playbackState: 'playing', watchTime: 5 }),\n        );\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/plugins/destination.test.ts",
    "content": "import { Destination, getResponseBodyString, Context } from '../../src/plugins/destination';\nimport { IConfig } from '../../src/types/config/core-config';\nimport { ILogger } from '../../src/logger';\nimport { Payload } from '../../src/types/payload';\nimport { Status } from '../../src/types/status';\nimport { Response } from '../../src/types/response';\nimport { API_KEY, useDefaultConfig } from '../helpers/default';\nimport {\n  INVALID_API_KEY,\n  MISSING_API_KEY_MESSAGE,\n  SUCCESS_MESSAGE,\n  UNEXPECTED_ERROR_MESSAGE,\n} from '../../src/types/messages';\nimport { uuidPattern } from '../helpers/util';\nimport { DiagnosticsClient, RequestMetadata } from '../../src';\nimport { TrackEvent } from '../../src/types/event/event';\nimport { AMPLITUDE_SERVER_URL } from '../../src/types/constants';\n\nconst jsons = (obj: any) => JSON.stringify(obj, null, 2);\n\nconst getMockLogger = (): ILogger => ({\n  log: jest.fn(),\n  debug: jest.fn(),\n  warn: jest.fn(),\n  error: jest.fn(),\n  enable: jest.fn(),\n  disable: jest.fn(),\n});\n\ndescribe('destination', () => {\n  describe('constructor', () => {\n    test('should pass diagnostics client to destination', () => {\n      const diagnosticsClient = new DiagnosticsClient(API_KEY, getMockLogger());\n      const destination = new Destination({ diagnosticsClient });\n      expect(destination.diagnosticsClient).toBe(diagnosticsClient);\n    });\n  });\n\n  describe('setup', () => {\n    test('should setup plugin', async () => {\n      const destination = new Destination();\n      const config = useDefaultConfig();\n      config.serverUrl = 'url';\n      config.flushMaxRetries = 0;\n      config.flushQueueSize = 0;\n      config.flushIntervalMillis = 0;\n      await destination.setup(config);\n      expect(destination.config.transportProvider).toBeDefined();\n      expect(destination.config.serverUrl).toBe('url');\n      expect(destination.config.flushMaxRetries).toBe(0);\n      expect(destination.config.flushQueueSize).toBe(0);\n      expect(destination.config.flushIntervalMillis).toBe(0);\n    });\n\n    test('should read from storage', async () => {\n      const destination = new Destination();\n      const config = useDefaultConfig();\n      const event = {\n        event_type: 'hello',\n      };\n      config.storageProvider = {\n        isEnabled: async () => true,\n        get: async () => undefined,\n        set: async () => undefined,\n        remove: async () => undefined,\n        reset: async () => undefined,\n        getRaw: async () => undefined,\n      };\n      const get = jest.spyOn(config.storageProvider, 'get').mockResolvedValueOnce([event]);\n      const execute = jest.spyOn(destination, 'execute').mockReturnValueOnce(\n        Promise.resolve({\n          event,\n          message: Status.Success,\n          code: 200,\n        }),\n      );\n      await destination.setup(config);\n      expect(get).toHaveBeenCalledTimes(1);\n      expect(execute).toHaveBeenCalledTimes(1);\n    });\n\n    test('should be ok with undefined storage', async () => {\n      const destination = new Destination();\n      const config = useDefaultConfig();\n      config.storageProvider = undefined;\n      const execute = jest.spyOn(destination, 'execute');\n      await destination.setup(config);\n      expect(execute).toHaveBeenCalledTimes(0);\n    });\n  });\n\n  describe('execute', () => {\n    test('should execute plugin', async () => {\n      const uuid: string = expect.stringMatching(uuidPattern) as string;\n      const destination = new Destination();\n      destination.config = useDefaultConfig();\n      const event = {\n        event_type: 'event_type',\n      };\n      const expectedEvent = {\n        event_type: 'event_type',\n        insert_id: uuid,\n      };\n      const schedule = jest.spyOn(destination, 'schedule').mockImplementation(jest.fn);\n      const saveEvents = jest.spyOn(destination, 'saveEvents').mockImplementation(jest.fn);\n\n      void destination.execute(event);\n\n      expect(destination.queue.length).toBe(1);\n      expect(destination.queue[0].event).toEqual(expectedEvent);\n      expect(schedule).toHaveBeenCalledTimes(1);\n      expect(saveEvents).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('removeEventsExceedFlushMaxRetries', () => {\n    test('should remove events exceed flushMaxRetries', async () => {\n      const destination = new Destination();\n      destination.config = {\n        ...useDefaultConfig(),\n        flushMaxRetries: 3,\n      };\n      const fulfillRequest = jest.spyOn(destination, 'fulfillRequest').mockImplementation(jest.fn);\n      const list = [\n        {\n          event: { event_type: 'event_1' },\n          attempts: 2,\n          callback: () => undefined,\n          timeout: 0,\n        },\n        {\n          event: { event_type: 'event_2' },\n          attempts: 2,\n          callback: () => undefined,\n          timeout: 0,\n        },\n        {\n          event: { event_type: 'event_3' },\n          attempts: 0,\n          callback: () => undefined,\n          timeout: 0,\n        },\n      ];\n      const result = destination.removeEventsExceedFlushMaxRetries(list);\n      expect(fulfillRequest).toHaveBeenCalledTimes(2);\n      expect(result.length).toBe(1);\n      expect(result[0].event.event_type).toBe('event_3');\n    });\n  });\n\n  describe('schedule', () => {\n    beforeEach(() => {\n      jest.useFakeTimers();\n    });\n\n    afterEach(() => {\n      jest.useRealTimers();\n    });\n\n    test('should schedule a flush when no one scheduled', async () => {\n      const destination = new Destination();\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n      (destination as any).scheduled = null;\n      destination.queue = [\n        {\n          event: { event_type: 'event_type' },\n          attempts: 0,\n          callback: () => undefined,\n          timeout: 0,\n        },\n      ];\n      destination.config = {\n        ...destination.config,\n        offline: false,\n      };\n      const flush = jest\n        .spyOn(destination, 'flush')\n        .mockImplementationOnce(() => {\n          // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n          (destination as any).scheduled = null;\n          return Promise.resolve(undefined);\n        })\n        .mockReturnValueOnce(Promise.resolve(undefined));\n      destination.schedule(1000);\n      // exhause setTimeout\n      jest.runAllTimers();\n      expect(flush).toHaveBeenCalledTimes(1);\n    });\n\n    test.each([\n      [1, 0],\n      [3, 1],\n    ])('should schedule a flush based on timeout', async (timeout, flushCalledTimes) => {\n      const destination = new Destination();\n      // eslint-disable-next-line @typescript-eslint/no-empty-function\n      destination.scheduleId = setTimeout(() => {}, 2);\n      destination.scheduledTimeout = 2;\n      destination.queue = [\n        {\n          event: { event_type: 'event_type' },\n          attempts: 0,\n          callback: () => undefined,\n          timeout: 0,\n        },\n      ];\n      destination.config = {\n        ...destination.config,\n        offline: false,\n      };\n      const flush = jest\n        .spyOn(destination, 'flush')\n        .mockImplementationOnce(() => {\n          // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n          (destination as any).scheduled = null;\n          return Promise.resolve(undefined);\n        })\n        .mockReturnValueOnce(Promise.resolve(undefined));\n      destination.schedule(timeout);\n      // exhause setTimeout\n      jest.runAllTimers();\n      expect(flush).toHaveBeenCalledTimes(flushCalledTimes);\n    });\n\n    test('should not schedule a flush if offline', async () => {\n      const destination = new Destination();\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n      (destination as any).scheduled = null;\n      destination.queue = [\n        {\n          event: { event_type: 'event_type' },\n          attempts: 0,\n          callback: () => undefined,\n          timeout: 0,\n        },\n      ];\n      destination.config = {\n        ...destination.config,\n        offline: true,\n      };\n      const flush = jest\n        .spyOn(destination, 'flush')\n        .mockImplementationOnce(() => {\n          // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n          (destination as any).scheduled = null;\n          return Promise.resolve(undefined);\n        })\n        .mockReturnValueOnce(Promise.resolve(undefined));\n      destination.schedule(0);\n      // exhause first setTimeout\n      jest.runAllTimers();\n      // wait for next tick to call nested setTimeout\n      await Promise.resolve();\n      // exhause nested setTimeout\n      jest.runAllTimers();\n      expect(flush).toHaveBeenCalledTimes(0);\n    });\n  });\n\n  describe('flush', () => {\n    test('should skip flush if offline', async () => {\n      const loggerProvider = {\n        log: jest.fn(),\n        debug: jest.fn(),\n        warn: jest.fn(),\n        error: jest.fn(),\n        enable: jest.fn(),\n        disable: jest.fn(),\n      };\n\n      const destination = new Destination();\n      destination.config = {\n        ...useDefaultConfig(),\n        offline: true,\n        loggerProvider: loggerProvider,\n      };\n      destination.queue = [\n        {\n          event: { event_type: 'event_type' },\n          attempts: 0,\n          callback: () => undefined,\n          timeout: 0,\n        },\n      ];\n      const send = jest.spyOn(destination, 'send').mockReturnValueOnce(Promise.resolve());\n      await destination.flush();\n      expect(send).toHaveBeenCalledTimes(0);\n      expect(loggerProvider.debug).toHaveBeenCalledTimes(1);\n      expect(loggerProvider.debug).toHaveBeenCalledWith('Skipping flush while offline.');\n    });\n\n    test('should skip flush if previous one has not resolved', async () => {\n      const loggerProvider = {\n        log: jest.fn(),\n        debug: jest.fn(),\n        warn: jest.fn(),\n        error: jest.fn(),\n        enable: jest.fn(),\n        disable: jest.fn(),\n      };\n\n      const destination = new Destination();\n      destination.config = {\n        ...useDefaultConfig(),\n        offline: false,\n        loggerProvider: loggerProvider,\n      };\n      destination.flushId = setTimeout(jest.fn, 1);\n\n      const send = jest.spyOn(destination, 'send').mockReturnValueOnce(Promise.resolve());\n      await destination.flush();\n      expect(send).toHaveBeenCalledTimes(0);\n      expect(loggerProvider.debug).toHaveBeenCalledTimes(1);\n      expect(loggerProvider.debug).toHaveBeenCalledWith('Skipping flush because previous flush has not resolved.');\n    });\n\n    test('should get batch and call send', async () => {\n      const destination = new Destination();\n      destination.config = {\n        ...useDefaultConfig(),\n        flushQueueSize: 1,\n      };\n      destination.queue = [\n        {\n          event: { event_type: 'event_type' },\n          attempts: 0,\n          callback: () => undefined,\n          timeout: 0,\n        },\n      ];\n      const send = jest.spyOn(destination, 'send').mockReturnValueOnce(Promise.resolve());\n      const result = await destination.flush();\n      expect(result).toBe(undefined);\n      expect(send).toHaveBeenCalledTimes(1);\n    });\n\n    test('should send with queue', async () => {\n      const destination = new Destination();\n      destination.config = {\n        ...useDefaultConfig(),\n      };\n      destination.queue = [\n        {\n          event: { event_type: 'event_type' },\n          attempts: 0,\n          callback: () => undefined,\n          timeout: 0,\n        },\n      ];\n      const send = jest.spyOn(destination, 'send').mockReturnValueOnce(Promise.resolve());\n      const result = await destination.flush();\n      expect(result).toBe(undefined);\n      expect(send).toHaveBeenCalledTimes(1);\n    });\n\n    test('should send later', async () => {\n      const destination = new Destination();\n      destination.config = {\n        ...useDefaultConfig(),\n      };\n      destination.queue = [\n        {\n          event: { event_type: 'event_type' },\n          attempts: 0,\n          callback: () => undefined,\n          timeout: 1000,\n        },\n      ];\n      const send = jest.spyOn(destination, 'send').mockReturnValueOnce(Promise.resolve());\n      const result = await destination.flush();\n      expect(destination.queue).toEqual([\n        {\n          event: { event_type: 'event_type' },\n          attempts: 0,\n          // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n          callback: expect.any(Function),\n          timeout: 1000,\n        },\n      ]);\n      expect(result).toBe(undefined);\n      expect(send).toHaveBeenCalledTimes(0);\n    });\n\n    test('should send batches in order', async () => {\n      const destination = new Destination();\n      destination.config = {\n        ...useDefaultConfig(),\n        flushQueueSize: 1,\n      };\n\n      const context1 = {\n        event: { event_type: 'event_type_1' },\n        attempts: 0,\n        callback: () => undefined,\n        timeout: 0,\n      };\n      const context2 = {\n        event: { event_type: 'event_type_2' },\n        attempts: 0,\n        callback: () => undefined,\n        timeout: 0,\n      };\n      destination.queue = [context1, context2];\n\n      const resolveOrder: number[] = [];\n      const send = jest\n        .spyOn(destination, 'send')\n        .mockImplementationOnce(\n          () =>\n            new Promise((resolve) =>\n              setTimeout(() => {\n                resolveOrder.push(1);\n                resolve();\n              }, 1000),\n            ),\n        ) // 1st call resolves in 1 sec\n        .mockImplementationOnce(\n          () =>\n            new Promise((resolve) =>\n              setTimeout(() => {\n                resolveOrder.push(2);\n                resolve();\n              }, 500),\n            ),\n        ); // 2nd call resolves in 0.5 sec\n\n      const result = await destination.flush();\n\n      expect(result).toBe(undefined);\n      expect(send).toHaveBeenNthCalledWith(1, [context1], false);\n      expect(send).toHaveBeenNthCalledWith(2, [context2], false);\n      expect(send).toHaveBeenCalledTimes(2);\n      expect(resolveOrder).toEqual([1, 2]);\n    });\n  });\n\n  describe('send', () => {\n    test('should include client upload time', async () => {\n      const destination = new Destination();\n      const callback = jest.fn();\n      const event = {\n        event_type: 'event_type',\n      };\n      const context = {\n        attempts: 0,\n        callback,\n        event,\n        timeout: 0,\n      };\n      const event_upload_time = '2023-01-01T12:00:00:000Z';\n      Date.prototype.toISOString = jest.fn().mockReturnValueOnce(event_upload_time);\n\n      const transportProvider = {\n        send: jest.fn().mockImplementationOnce((_url: string, payload: Payload) => {\n          expect(payload.client_upload_time).toBe(event_upload_time);\n          return Promise.resolve({\n            status: Status.Success,\n            statusCode: 200,\n            body: {\n              eventsIngested: 1,\n              payloadSizeBytes: 1,\n              serverUploadTime: 1,\n            },\n          });\n        }),\n      };\n      await destination.setup({\n        ...useDefaultConfig(),\n        transportProvider,\n        apiKey: API_KEY,\n        minIdLength: 10,\n      });\n      await destination.send([context]);\n      expect(callback).toHaveBeenCalledTimes(1);\n      expect(callback).toHaveBeenCalledWith({\n        event,\n        code: 200,\n        message: SUCCESS_MESSAGE,\n      });\n    });\n\n    test('should include request metadata', async () => {\n      const destination = new Destination();\n      const callback = jest.fn();\n      const event = {\n        event_type: 'event_type',\n      };\n      const context = {\n        attempts: 0,\n        callback,\n        event,\n        timeout: 0,\n      };\n      const request_metadata = new RequestMetadata();\n      request_metadata.recordHistogram('remote_config_fetch_time_API_success', 100);\n\n      const transportProvider = {\n        send: jest.fn().mockImplementationOnce((_url: string, payload: Payload) => {\n          expect(payload.request_metadata).toBe(request_metadata);\n          return Promise.resolve({\n            status: Status.Success,\n            statusCode: 200,\n            body: {\n              eventsIngested: 1,\n              payloadSizeBytes: 1,\n              serverUploadTime: 1,\n            },\n          });\n        }),\n      };\n      await destination.setup({\n        ...useDefaultConfig(),\n        transportProvider,\n        apiKey: API_KEY,\n        requestMetadata: request_metadata,\n      });\n      await destination.send([context]);\n      // request metadata should be reset after sending\n      expect(destination.config.requestMetadata).toEqual(new RequestMetadata());\n      expect(callback).toHaveBeenCalledTimes(1);\n      expect(callback).toHaveBeenCalledWith({\n        event,\n        code: 200,\n        message: SUCCESS_MESSAGE,\n      });\n    });\n\n    test('should include min id length', async () => {\n      const destination = new Destination();\n      const callback = jest.fn();\n      const event = {\n        event_type: 'event_type',\n      };\n      const context = {\n        attempts: 0,\n        callback,\n        event,\n        timeout: 0,\n      };\n      const transportProvider = {\n        send: jest.fn().mockImplementationOnce((_url: string, payload: Payload) => {\n          expect(payload.options?.min_id_length).toBe(10);\n          return Promise.resolve({\n            status: Status.Success,\n            statusCode: 200,\n            body: {\n              eventsIngested: 1,\n              payloadSizeBytes: 1,\n              serverUploadTime: 1,\n            },\n          });\n        }),\n      };\n      await destination.setup({\n        ...useDefaultConfig(),\n        transportProvider,\n        apiKey: API_KEY,\n        minIdLength: 10,\n      });\n      await destination.send([context]);\n      expect(callback).toHaveBeenCalledTimes(1);\n      expect(callback).toHaveBeenCalledWith({\n        event,\n        code: 200,\n        message: SUCCESS_MESSAGE,\n      });\n    });\n\n    test('should keep compression enabled for default server URL', async () => {\n      const destination = new Destination();\n      const callback = jest.fn();\n      const event = { event_type: 'event_type' };\n      const context = {\n        attempts: 0,\n        callback,\n        event,\n        timeout: 0,\n      };\n      const transportProvider = {\n        send: jest.fn().mockResolvedValueOnce({\n          status: Status.Success,\n          statusCode: 200,\n          body: {\n            eventsIngested: 1,\n            payloadSizeBytes: 1,\n            serverUploadTime: 1,\n          },\n        }),\n      };\n      await destination.setup({\n        ...useDefaultConfig(),\n        transportProvider,\n        apiKey: API_KEY,\n        serverUrl: AMPLITUDE_SERVER_URL,\n      });\n\n      await destination.send([context]);\n\n      expect(transportProvider.send).toHaveBeenCalledWith(AMPLITUDE_SERVER_URL, expect.any(Object), true);\n    });\n\n    test.each([\n      [false, false],\n      [true, true],\n    ])(\n      'should use enableRequestBodyCompression for custom server URL (enable=%s)',\n      async (enableRequestBodyCompression, expectedShouldCompress) => {\n        const destination = new Destination();\n        const callback = jest.fn();\n        const event = { event_type: 'event_type' };\n        const context = {\n          attempts: 0,\n          callback,\n          event,\n          timeout: 0,\n        };\n        const transportProvider = {\n          send: jest.fn().mockResolvedValueOnce({\n            status: Status.Success,\n            statusCode: 200,\n            body: {\n              eventsIngested: 1,\n              payloadSizeBytes: 1,\n              serverUploadTime: 1,\n            },\n          }),\n        };\n        const customServerUrl = 'https://custom.example.com/2/httpapi';\n        await destination.setup({\n          ...useDefaultConfig(),\n          transportProvider,\n          apiKey: API_KEY,\n          serverUrl: customServerUrl,\n          enableRequestBodyCompression,\n        });\n\n        await destination.send([context]);\n\n        expect(transportProvider.send).toHaveBeenCalledWith(\n          customServerUrl,\n          expect.any(Object),\n          expectedShouldCompress,\n        );\n      },\n    );\n\n    test('should not include extra', async () => {\n      const destination = new Destination();\n      const callback = jest.fn();\n      const event = {\n        event_type: 'event_type',\n        extra: { 'extra-key': 'extra-value' },\n      };\n      const context = {\n        attempts: 0,\n        callback,\n        event,\n        timeout: 0,\n      };\n      const transportProvider = {\n        send: jest.fn().mockImplementationOnce((_url: string, payload: Payload) => {\n          expect(payload.options?.min_id_length).toBe(10);\n          expect(payload.events.some((event) => !!event.extra)).toBeFalsy();\n          return Promise.resolve({\n            status: Status.Success,\n            statusCode: 200,\n            body: {\n              eventsIngested: 1,\n              payloadSizeBytes: 1,\n              serverUploadTime: 1,\n            },\n          });\n        }),\n      };\n      await destination.setup({\n        ...useDefaultConfig(),\n        transportProvider,\n        apiKey: API_KEY,\n        minIdLength: 10,\n      });\n      await destination.send([context]);\n      expect(callback).toHaveBeenCalledTimes(1);\n      expect(callback).toHaveBeenCalledWith({\n        event,\n        code: 200,\n        message: SUCCESS_MESSAGE,\n      });\n    });\n\n    test('should not retry', async () => {\n      const destination = new Destination();\n      const callback = jest.fn();\n      const event = {\n        event_type: 'event_type',\n      };\n      const context = {\n        attempts: 0,\n        callback,\n        event,\n        timeout: 0,\n      };\n      const transportProvider = {\n        send: jest.fn().mockImplementationOnce(() => {\n          return Promise.resolve({\n            status: Status.Failed,\n            statusCode: 500,\n          });\n        }),\n      };\n      await destination.setup({\n        ...useDefaultConfig(),\n        transportProvider,\n        apiKey: API_KEY,\n      });\n      await destination.send([context], false);\n      expect(callback).toHaveBeenCalledTimes(1);\n      expect(callback).toHaveBeenCalledWith({\n        event,\n        code: 500,\n        message: Status.Failed,\n      });\n    });\n\n    test('should provide error details', async () => {\n      const destination = new Destination();\n      const callback = jest.fn();\n      const event = {\n        event_type: 'event_type',\n      };\n      const context = {\n        attempts: 0,\n        callback,\n        event,\n        timeout: 0,\n      };\n      const body = {\n        error: 'Request missing required field',\n        missingField: 'user_id',\n      };\n      const transportProvider = {\n        send: jest.fn().mockImplementationOnce(() => {\n          return Promise.resolve({\n            status: Status.Invalid,\n            statusCode: 400,\n            body,\n          });\n        }),\n      };\n      await destination.setup({\n        ...useDefaultConfig(),\n        transportProvider,\n        apiKey: API_KEY,\n      });\n      await destination.send([context], false);\n      expect(callback).toHaveBeenCalledTimes(1);\n      expect(callback).toHaveBeenCalledWith({\n        event,\n        code: 400,\n        message: `${Status.Invalid}: ${jsons(body)}`,\n      });\n    });\n\n    test('should handle no api key', async () => {\n      const destination = new Destination();\n      const callback = jest.fn();\n      const event = {\n        event_type: 'event_type',\n      };\n      const context = {\n        attempts: 0,\n        callback,\n        event,\n        timeout: 0,\n      };\n      const transportProvider = {\n        send: jest.fn().mockImplementationOnce(() => {\n          throw new Error();\n        }),\n      };\n      await destination.setup({\n        ...useDefaultConfig(),\n        transportProvider,\n        apiKey: '',\n      });\n      await destination.send([context]);\n      expect(callback).toHaveBeenCalledTimes(1);\n      expect(callback).toHaveBeenCalledWith({\n        event,\n        code: 400,\n        message: MISSING_API_KEY_MESSAGE,\n      });\n    });\n\n    test('should not drop data on unexpected error', async () => {\n      const destination = new Destination();\n      const callback = jest.fn();\n      const context = {\n        attempts: 0,\n        callback,\n        event: {\n          event_type: 'event_type',\n        },\n        timeout: 0,\n      };\n      const transportProvider = {\n        send: jest.fn().mockImplementationOnce(() => {\n          throw new Error();\n        }),\n      };\n      await destination.setup({\n        ...useDefaultConfig(),\n        transportProvider,\n      });\n      await destination.send([context]);\n      // We should not fulfill request when the request fails with an unknown error. This should be retried\n      expect(callback).toHaveBeenCalledTimes(0);\n    });\n\n    test('should record diagnostics event when send throws an error', async () => {\n      const diagnosticsClient = new DiagnosticsClient(API_KEY, getMockLogger());\n      const recordEventSpy = jest.spyOn(diagnosticsClient, 'recordEvent');\n\n      const destination = new Destination({ diagnosticsClient });\n      const transportProvider = {\n        send: jest.fn().mockImplementationOnce(() => {\n          throw new Error('Network error');\n        }),\n      };\n      await destination.setup({\n        ...useDefaultConfig(),\n        transportProvider,\n      });\n\n      const event1 = { event_type: 'event1', user_id: 'user1' };\n      const event2 = { event_type: 'event2', user_id: 'user2' };\n\n      const contexts: Context[] = [\n        { event: event1, attempts: 0, callback: jest.fn(), timeout: 0 },\n        { event: event2, attempts: 0, callback: jest.fn(), timeout: 0 },\n      ];\n\n      // Call send which should catch the error and record diagnostics\n      await destination.send(contexts);\n\n      // Verify diagnostics recordEvent was called with the expected parameters\n      expect(recordEventSpy).toHaveBeenCalledWith('analytics.events.unsuccessful.from.catch.error', {\n        events: ['event1', 'event2'],\n        message: 'Network error',\n        stack_trace: expect.any(Array),\n      });\n\n      // Verify stack_trace is an array of strings\n      const recordEventCall = recordEventSpy.mock.calls[0];\n      expect(Array.isArray(recordEventCall[1].stack_trace)).toBe(true);\n      expect(recordEventCall[1].stack_trace.length).toBeGreaterThan(0);\n    });\n  });\n\n  describe('handleResponse', () => {\n    test('should record diagnostics event for 408 timeout from load balancer', () => {\n      const diagnosticsClient = new DiagnosticsClient(API_KEY, getMockLogger());\n      const recordEventSpy = jest.spyOn(diagnosticsClient, 'recordEvent');\n\n      const destination = new Destination({ diagnosticsClient });\n      destination.config = useDefaultConfig();\n\n      const event1 = { event_type: 'event1', user_id: 'user1' };\n      const event2 = { event_type: 'event2', user_id: 'user2' };\n\n      const contexts: Context[] = [\n        { event: event1, attempts: 0, callback: jest.fn(), timeout: 0 },\n        { event: event2, attempts: 0, callback: jest.fn(), timeout: 0 },\n      ];\n\n      const response: Response = {\n        status: Status.Timeout,\n        statusCode: 408,\n      };\n\n      // Call handleResponse with a 408 timeout response\n      destination.handleResponse(response, contexts);\n\n      // Verify diagnostics recordEvent was called with the expected parameters\n      expect(recordEventSpy).toHaveBeenCalledWith('analytics.events.unsuccessful', {\n        events: ['event1', 'event2'],\n        code: 408,\n        status: Status.Timeout,\n        body: '',\n        stack_trace: expect.any(Array),\n      });\n\n      // Verify stack_trace is an array of strings\n      const recordEventCall = recordEventSpy.mock.calls[0];\n      expect(Array.isArray(recordEventCall[1].stack_trace)).toBe(true);\n      expect(recordEventCall[1].stack_trace.length).toBeGreaterThan(0);\n    });\n\n    test('should record diagnostics event with response body for unsuccessful request', () => {\n      const diagnosticsClient = new DiagnosticsClient(API_KEY, getMockLogger());\n      const recordEventSpy = jest.spyOn(diagnosticsClient, 'recordEvent');\n\n      const destination = new Destination({ diagnosticsClient });\n      destination.config = useDefaultConfig();\n\n      const event1 = { event_type: 'event1', user_id: 'user1' };\n\n      const contexts: Context[] = [{ event: event1, attempts: 0, callback: jest.fn(), timeout: 0 }];\n\n      const response: Response = {\n        status: Status.PayloadTooLarge,\n        statusCode: 413,\n        body: {\n          error: 'Payload too large',\n        },\n      };\n\n      // Call handleResponse with a 413 error response\n      destination.handleResponse(response, contexts);\n\n      // Verify diagnostics recordEvent was called with the expected parameters including body\n      expect(recordEventSpy).toHaveBeenCalledWith('analytics.events.unsuccessful', {\n        events: ['event1'],\n        code: 413,\n        status: Status.PayloadTooLarge,\n        body: JSON.stringify({ error: 'Payload too large' }, null, 2),\n        stack_trace: expect.any(Array),\n      });\n\n      // Verify stack_trace is an array of strings\n      const recordEventCall = recordEventSpy.mock.calls[0];\n      expect(Array.isArray(recordEventCall[1].stack_trace)).toBe(true);\n      expect(recordEventCall[1].stack_trace.length).toBeGreaterThan(0);\n    });\n  });\n\n  describe('fulfillRequest', () => {\n    test('should record diagnostics when events are dropped (non-200 status code)', () => {\n      const diagnosticsClient = new DiagnosticsClient(API_KEY, getMockLogger());\n      const incrementSpy = jest.spyOn(diagnosticsClient, 'increment');\n      const recordEventSpy = jest.spyOn(diagnosticsClient, 'recordEvent');\n\n      const destination = new Destination({ diagnosticsClient });\n      destination.config = useDefaultConfig();\n\n      const callback1 = jest.fn();\n      const callback2 = jest.fn();\n      const event1 = { event_type: 'event1', user_id: 'user1' };\n      const event2 = { event_type: 'event2', user_id: 'user2' };\n\n      const contexts: Context[] = [\n        { event: event1, attempts: 1, callback: callback1, timeout: 0 },\n        { event: event2, attempts: 1, callback: callback2, timeout: 0 },\n      ];\n\n      // Call fulfillRequest with a 400 status code (non-200)\n      destination.fulfillRequest(contexts, 400, 'Bad Request');\n\n      // Verify diagnostics increment was called with the correct count\n      expect(incrementSpy).toHaveBeenCalledWith('analytics.events.dropped', 2);\n\n      // Verify diagnostics recordEvent was called with the correct data\n      expect(recordEventSpy).toHaveBeenCalledWith('analytics.events.dropped', {\n        events: ['event1', 'event2'],\n        code: 400,\n        message: 'Bad Request',\n        stack_trace: expect.any(Array),\n      });\n\n      // Verify stack_trace is an array of strings\n      const recordEventCall = recordEventSpy.mock.calls[0];\n      expect(Array.isArray(recordEventCall[1].stack_trace)).toBe(true);\n      expect(recordEventCall[1].stack_trace.length).toBeGreaterThan(0);\n\n      // Verify callbacks were called\n      expect(callback1).toHaveBeenCalledTimes(1);\n      expect(callback2).toHaveBeenCalledTimes(1);\n    });\n\n    test('should handle undefined stack trace gracefully', () => {\n      const diagnosticsClient = new DiagnosticsClient(API_KEY, getMockLogger());\n      const recordEventSpy = jest.spyOn(diagnosticsClient, 'recordEvent');\n\n      const destination = new Destination({ diagnosticsClient });\n      destination.config = useDefaultConfig();\n\n      const callback = jest.fn();\n      const event = { event_type: 'event1', user_id: 'user1' };\n      const context: Context = { event, attempts: 1, callback, timeout: 0 };\n\n      // Mock Error to return undefined stack\n      const originalError = global.Error;\n      global.Error = class extends originalError {\n        constructor(message?: string) {\n          super(message);\n          this.stack = undefined;\n        }\n      } as any;\n\n      try {\n        // Call fulfillRequest with a 500 status code\n        destination.fulfillRequest([context], 500, 'Internal Server Error');\n\n        // Verify stack_trace defaults to empty array when stack is undefined\n        expect(recordEventSpy).toHaveBeenCalledWith('analytics.events.dropped', {\n          events: ['event1'],\n          code: 500,\n          message: 'Internal Server Error',\n          stack_trace: [],\n        });\n      } finally {\n        // Restore original Error\n        global.Error = originalError;\n      }\n    });\n\n    test('should record diagnostics when events are successfully sent (200 status code)', () => {\n      const diagnosticsClient = new DiagnosticsClient(API_KEY, getMockLogger());\n      const incrementSpy = jest.spyOn(diagnosticsClient, 'increment');\n\n      const destination = new Destination({ diagnosticsClient });\n      destination.config = useDefaultConfig();\n\n      const callback1 = jest.fn();\n      const callback2 = jest.fn();\n      const event1 = { event_type: 'event1', user_id: 'user1' };\n      const event2 = { event_type: 'event2', user_id: 'user2' };\n\n      const contexts: Context[] = [\n        { event: event1, attempts: 1, callback: callback1, timeout: 0 },\n        { event: event2, attempts: 1, callback: callback2, timeout: 0 },\n      ];\n\n      // Call fulfillRequest with a 200 status code (success)\n      destination.fulfillRequest(contexts, 200, 'OK');\n\n      // Verify diagnostics increment was called with the correct count for sent events\n      expect(incrementSpy).toHaveBeenCalledWith('analytics.events.sent', 2);\n\n      // Verify callbacks were called\n      expect(callback1).toHaveBeenCalledTimes(1);\n      expect(callback2).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('updateEventStorage', () => {\n    test('should be ok with no storage provider', async () => {\n      const destination = new Destination();\n      destination.config = useDefaultConfig();\n      destination.config.storageProvider = undefined;\n      expect(destination.saveEvents()).toBe(undefined);\n    });\n\n    test('should filter dropped event and update the storage provider', async () => {\n      const destination = new Destination();\n      destination.config = useDefaultConfig();\n      destination.config.storageProvider = {\n        isEnabled: async () => true,\n        get: async () => undefined,\n        set: async () => undefined,\n        remove: async () => undefined,\n        reset: async () => undefined,\n        getRaw: async () => undefined,\n      };\n      const event1 = { event_type: 'event', insert_id: '1' };\n      const event2 = { event_type: 'filtered_event', insert_id: '2' };\n      const events = [event1, event2];\n      const eventsToAdd = events.map((event) => {\n        return {\n          event,\n          attempts: 0,\n          callback: () => undefined,\n          timeout: 0,\n        };\n      });\n      const set = jest.spyOn(destination.config.storageProvider, 'set').mockResolvedValueOnce(undefined);\n      destination.queue = eventsToAdd;\n      const eventsToRemove = [eventsToAdd[1]];\n      destination.removeEvents(eventsToRemove);\n      expect(set).toHaveBeenCalledTimes(1);\n      expect(set).toHaveBeenCalledWith('', expect.objectContaining([event1]));\n    });\n\n    test('should save event to the storage provider', async () => {\n      const destination = new Destination();\n      destination.config = useDefaultConfig();\n      destination.config.storageProvider = {\n        isEnabled: async () => true,\n        get: async () => undefined,\n        set: async () => undefined,\n        remove: async () => undefined,\n        reset: async () => undefined,\n        getRaw: async () => undefined,\n      };\n      const event = { event_type: 'event', insert_id: '1' };\n      const set = jest.spyOn(destination.config.storageProvider, 'set').mockResolvedValueOnce(undefined);\n      const context = {\n        event: event,\n        attempts: 0,\n        callback: () => undefined,\n        timeout: 0,\n      };\n      destination.queue = [context];\n      destination.removeEvents([]);\n      expect(set).toHaveBeenCalledTimes(1);\n      expect(set).toHaveBeenCalledWith('', expect.objectContaining([event]));\n    });\n  });\n\n  describe('module level integration', () => {\n    const successResponse = {\n      status: Status.Success,\n      statusCode: 200,\n      body: {\n        eventsIngested: 1,\n        payloadSizeBytes: 1,\n        serverUploadTime: 1,\n      },\n    };\n\n    // timeline:\n    //  0       -> event1\n    //  1000    -> flush(event1) because of flush interval\n    //  1050    -> event2\n    //  2050 (1050 + 1000)   -> no flush(event2) because request1 has not resolved\n    //  2200(1000 + 1200)    -> request1 resolved, schedule unsent events\n    //  3200    -> flush(event2)\n    test('should schedule another flush after the previous resolves', async () => {\n      const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));\n      const testFlushIntervalMillis = 1000;\n      let request1Payload: { events: TrackEvent[] } = { events: [{ event_type: 'init' }] };\n      let request2Payload: { events: TrackEvent[] } = { events: [{ event_type: 'init' }] };\n\n      class Http {\n        send = jest\n          .fn()\n          .mockImplementationOnce((_, payload: { events: TrackEvent[] }) => {\n            // expect() doesn't work here so move it outside\n            request1Payload = payload;\n            return new Promise((resolve) => {\n              setTimeout(() => {\n                resolve(successResponse);\n              }, 1200);\n            });\n          })\n          .mockImplementationOnce((_, payload: { events: TrackEvent[] }) => {\n            // expect() doesn't work here so move it outside\n            request2Payload = payload;\n            return Promise.resolve(successResponse);\n          });\n      }\n\n      const transportProvider = new Http();\n      const destination = new Destination();\n      const config = {\n        ...useDefaultConfig(),\n        flushQueueSize: 3,\n        flushIntervalMillis: testFlushIntervalMillis,\n        transportProvider,\n        loggerProvider: getMockLogger(),\n      };\n\n      await destination.setup(config);\n      void destination.execute({ event_type: 'event_type_1' });\n\n      await wait(1050);\n      void destination.execute({ event_type: 'event_type_2' });\n\n      await wait(2200);\n\n      expect(request1Payload.events.length).toBe(1);\n      expect(request1Payload.events[0].event_type).toBe('event_type_1');\n      expect(request2Payload.events.length).toBe(1);\n      expect(request2Payload.events[0].event_type).toBe('event_type_2');\n      expect(transportProvider.send).toHaveBeenCalledTimes(2);\n    });\n\n    test('should handle unexpected error', async () => {\n      class Http {\n        send = jest.fn().mockImplementationOnce(() => {\n          return Promise.resolve(null);\n        });\n      }\n      const transportProvider = new Http();\n      const destination = new Destination();\n      const config = {\n        ...useDefaultConfig(),\n        flushQueueSize: 2,\n        flushIntervalMillis: 500,\n        transportProvider,\n      };\n      await destination.setup(config);\n      const result = await destination.execute({\n        event_type: 'event_type',\n      });\n      expect(result.code).toBe(0);\n      expect(result.message).toBe(UNEXPECTED_ERROR_MESSAGE);\n      expect(transportProvider.send).toHaveBeenCalledTimes(1);\n    });\n\n    test('should not retry with invalid api key', async () => {\n      class Http {\n        send = jest.fn().mockImplementationOnce(() => {\n          return Promise.resolve({\n            status: Status.Invalid,\n            statusCode: 400,\n            body: {\n              error: INVALID_API_KEY,\n            },\n          });\n        });\n      }\n      const transportProvider = new Http();\n      const destination = new Destination();\n      destination.retryTimeout = 10;\n      const config = {\n        ...useDefaultConfig(),\n        flushQueueSize: 2,\n        flushIntervalMillis: 500,\n        transportProvider,\n      };\n      await destination.setup(config);\n      const results = await Promise.all([\n        destination.execute({\n          event_type: 'event_type',\n        }),\n        destination.execute({\n          event_type: 'event_type',\n        }),\n      ]);\n      expect(results[0].code).toBe(400);\n      expect(destination.queue.length).toBe(0);\n      expect(transportProvider.send).toHaveBeenCalledTimes(1);\n    });\n\n    test('should handle retry for 400 error', async () => {\n      class Http {\n        send = jest\n          .fn()\n          .mockImplementationOnce(() => {\n            return Promise.resolve({\n              status: Status.Invalid,\n              statusCode: 400,\n              body: {\n                error: 'error',\n                missingField: '',\n                eventsWithInvalidFields: { a: [0] },\n                eventsWithMissingFields: { b: [] },\n                eventsWithInvalidIdLengths: {},\n                silencedEvents: [],\n              },\n            });\n          })\n          .mockImplementationOnce(() => {\n            return Promise.resolve(successResponse);\n          });\n      }\n      const transportProvider = new Http();\n      const destination = new Destination();\n      destination.retryTimeout = 10;\n      const config = {\n        ...useDefaultConfig(),\n        flushQueueSize: 2,\n        flushIntervalMillis: 500,\n        transportProvider,\n      };\n      await destination.setup(config);\n      const results = await Promise.all([\n        destination.execute({\n          event_type: 'event_type',\n          insert_id: '0',\n        }),\n        destination.execute({\n          event_type: 'event_type',\n          insert_id: '1',\n        }),\n      ]);\n      expect(results[0].code).toBe(400);\n      expect(results[1].code).toBe(200);\n      expect(destination.queue.length).toBe(0);\n      expect(transportProvider.send).toHaveBeenCalledTimes(2);\n    });\n\n    test('should handle retry for 400 error with missing body field', async () => {\n      class Http {\n        send = jest.fn().mockImplementationOnce(() => {\n          return Promise.resolve({\n            status: Status.Invalid,\n            statusCode: 400,\n            body: {\n              error: 'error',\n              missingField: 'key',\n              eventsWithInvalidFields: {},\n              eventsWithMissingFields: {},\n              silencedEvents: [],\n            },\n          });\n        });\n      }\n      const transportProvider = new Http();\n      const destination = new Destination();\n      const config = {\n        ...useDefaultConfig(),\n        flushQueueSize: 2,\n        flushIntervalMillis: 500,\n        transportProvider,\n      };\n      await destination.setup(config);\n      const results = await Promise.all([\n        destination.execute({\n          event_type: 'event_type',\n        }),\n        destination.execute({\n          event_type: 'event_type',\n        }),\n      ]);\n      expect(results[0].code).toBe(400);\n      expect(results[1].code).toBe(400);\n      expect(destination.queue.length).toBe(0);\n      expect(transportProvider.send).toHaveBeenCalledTimes(1);\n    });\n\n    test('should handle retry for 413 error with flushQueueSize of 1', async () => {\n      class Http {\n        send = jest.fn().mockImplementationOnce(() => {\n          return Promise.resolve({\n            status: Status.PayloadTooLarge,\n            statusCode: 413,\n            body: {\n              error: 'error',\n            },\n          });\n        });\n      }\n      const transportProvider = new Http();\n      const destination = new Destination();\n      const config = {\n        ...useDefaultConfig(),\n        flushQueueSize: 1,\n        flushIntervalMillis: 500,\n        transportProvider,\n      };\n      await destination.setup(config);\n      const event = {\n        event_type: 'event_type',\n      };\n      const result = await destination.execute(event);\n      expect(result).toEqual({\n        event,\n        message: 'error',\n        code: 413,\n      });\n      expect(destination.queue.length).toBe(0);\n      expect(transportProvider.send).toHaveBeenCalledTimes(1);\n    });\n\n    test('should handle retry for 413 error', async () => {\n      class Http {\n        send = jest\n          .fn()\n          .mockImplementationOnce(() => {\n            return Promise.resolve({\n              status: Status.PayloadTooLarge,\n              statusCode: 413,\n              body: {\n                error: 'error',\n              },\n            });\n          })\n          .mockImplementationOnce(() => {\n            return Promise.resolve(successResponse);\n          })\n          .mockImplementationOnce(() => {\n            return Promise.resolve(successResponse);\n          });\n      }\n      const transportProvider = new Http();\n      const destination = new Destination();\n      destination.retryTimeout = 10;\n      const config = {\n        ...useDefaultConfig(),\n        flushQueueSize: 2,\n        flushIntervalMillis: 500,\n        transportProvider,\n      };\n      await destination.setup(config);\n      await Promise.all([\n        destination.execute({\n          event_type: 'event_type',\n        }),\n        destination.execute({\n          event_type: 'event_type',\n        }),\n      ]);\n      expect(destination.queue.length).toBe(0);\n      expect(transportProvider.send).toHaveBeenCalledTimes(3);\n    });\n\n    test('should handle retry for 429 error', async () => {\n      class Http {\n        send = jest\n          .fn()\n          .mockImplementationOnce(() => {\n            return Promise.resolve({\n              status: Status.RateLimit,\n              statusCode: 429,\n              body: {\n                error: 'error',\n                epsThreshold: 1,\n                throttledDevices: {},\n                throttledUsers: {},\n                exceededDailyQuotaDevices: {\n                  '1': 1,\n                },\n                exceededDailyQuotaUsers: {\n                  '2': 1,\n                },\n                throttledEvents: [0],\n              },\n            });\n          })\n          .mockImplementationOnce(() => {\n            return Promise.resolve(successResponse);\n          })\n          .mockImplementationOnce(() => {\n            return Promise.resolve(successResponse);\n          });\n      }\n      const transportProvider = new Http();\n      const destination = new Destination();\n      destination.retryTimeout = 10;\n      destination.throttleTimeout = 1;\n      const config = {\n        ...useDefaultConfig(),\n        flushQueueSize: 4,\n        flushIntervalMillis: 500,\n        transportProvider,\n      };\n      await destination.setup(config);\n      const results = await Promise.all([\n        // throttled\n        destination.execute({\n          event_type: 'event_type',\n          user_id: '0',\n          device_id: '0',\n          insert_id: '0',\n        }),\n        // exceed daily device quota\n        destination.execute({\n          event_type: 'event_type',\n          user_id: '1',\n          device_id: '1',\n          insert_id: '1',\n        }),\n        // exceed daily user quota\n        destination.execute({\n          event_type: 'event_type',\n          user_id: '2',\n          device_id: '2',\n          insert_id: '2',\n        }),\n        // success\n        destination.execute({\n          event_type: 'event_type',\n          user_id: '3',\n          device_id: '3',\n          insert_id: '3',\n        }),\n      ]);\n      expect(results[0].code).toBe(200);\n      expect(results[1].code).toBe(429);\n      expect(results[2].code).toBe(429);\n      expect(results[3].code).toBe(200);\n      expect(destination.queue.length).toBe(0);\n      expect(transportProvider.send).toHaveBeenCalledTimes(2);\n    });\n\n    test('should handle retry for 500 error', async () => {\n      class Http {\n        send = jest\n          .fn()\n          .mockImplementationOnce(() => {\n            return Promise.resolve({\n              statusCode: 500,\n              status: Status.Failed,\n            });\n          })\n          .mockImplementationOnce(() => {\n            return Promise.resolve(successResponse);\n          });\n      }\n      const transportProvider = new Http();\n      const destination = new Destination();\n      destination.retryTimeout = 10;\n      const config = {\n        ...useDefaultConfig(),\n        flushQueueSize: 2,\n        flushIntervalMillis: 500,\n        transportProvider,\n      };\n      await destination.setup(config);\n      await Promise.all([\n        destination.execute({\n          event_type: 'event_type',\n        }),\n        destination.execute({\n          event_type: 'event_type',\n        }),\n      ]);\n      expect(destination.queue.length).toBe(0);\n      expect(transportProvider.send).toHaveBeenCalledTimes(2);\n    });\n  });\n\n  describe('logging', () => {\n    test('should handle null loggerProvider', async () => {\n      class Http {\n        send = jest.fn().mockImplementationOnce(() => {\n          return Promise.resolve({\n            status: Status.Success,\n            statusCode: 200,\n            body: {\n              message: 'success',\n            },\n          });\n        });\n      }\n\n      const transportProvider = new Http();\n      const destination = new Destination();\n\n      const config: IConfig = {\n        ...useDefaultConfig(),\n        flushQueueSize: 1,\n        flushIntervalMillis: 1,\n        transportProvider,\n      };\n      await destination.setup(config);\n      const event = {\n        event_type: 'event_type',\n      };\n      const result = await destination.execute(event);\n      expect(result).toEqual({\n        event,\n        message: SUCCESS_MESSAGE,\n        code: 200,\n      });\n      expect(transportProvider.send).toHaveBeenCalledTimes(1);\n    });\n\n    test.each([\n      {\n        statusCode: 400,\n        status: Status.Invalid,\n        body: {\n          code: 400,\n          error: 'error',\n          missingField: undefined,\n          eventsWithInvalidFields: {},\n          eventsWithMissingFields: {},\n          eventsWithInvalidIdLengths: {},\n          silencedEvents: [],\n        },\n      },\n      {\n        statusCode: 413,\n        status: Status.PayloadTooLarge,\n        body: {\n          code: 413,\n          error: 'error',\n        },\n      },\n      {\n        statusCode: 429,\n        status: Status.RateLimit,\n        body: {\n          code: 429,\n          error: 'error',\n          epsThreshold: 1,\n          throttledDevices: {},\n          throttledUsers: {},\n          exceededDailyQuotaDevices: {\n            '1': 1,\n          },\n          exceededDailyQuotaUsers: {\n            '2': 1,\n          },\n          throttledEvents: [0],\n        },\n      },\n    ])(\n      'should log intermediate response body for retries of $statusCode $status',\n      async ({ statusCode, status, body }) => {\n        const response = {\n          status,\n          statusCode,\n          body,\n        };\n\n        class Http {\n          send = jest\n            .fn()\n            .mockImplementationOnce(() => {\n              return Promise.resolve(response);\n            })\n            .mockImplementation(() => {\n              return Promise.resolve({\n                status: Status.Success,\n                statusCode: 200,\n                body: {\n                  message: SUCCESS_MESSAGE,\n                },\n              });\n            });\n        }\n        const transportProvider = new Http();\n        const destination = new Destination();\n        const loggerProvider = getMockLogger();\n        const eventCount = status === Status.PayloadTooLarge ? 2 : 1;\n        const config = {\n          ...useDefaultConfig(),\n          flushQueueSize: eventCount,\n          flushIntervalMillis: 1,\n          transportProvider,\n          loggerProvider,\n        };\n        await destination.setup(config);\n        destination.retryTimeout = 10;\n        destination.throttleTimeout = 10;\n        const event = {\n          event_type: 'event_type',\n        };\n        let result;\n        if (eventCount > 1) {\n          // Need 2 events for 413 to retry, send them both at the same time\n          const context: Context = {\n            event,\n            attempts: 0,\n            callback: jest.fn(),\n            timeout: 0,\n          };\n          destination.queue.push(context);\n          result = await destination.execute(event);\n        } else {\n          result = await destination.execute(event);\n        }\n\n        expect(result).toEqual({\n          event,\n          message: SUCCESS_MESSAGE,\n          code: 200,\n        });\n\n        expect(transportProvider.send).toHaveBeenCalledTimes(status === Status.PayloadTooLarge ? 3 : 2);\n        // eslint-disable-next-line @typescript-eslint/unbound-method\n        expect(loggerProvider.warn).toHaveBeenCalledTimes(1);\n        // eslint-disable-next-line @typescript-eslint/unbound-method,@typescript-eslint/restrict-template-expressions\n        expect(loggerProvider.warn).toHaveBeenCalledWith(jsons(response.body));\n      },\n    );\n\n    test.each([\n      { err: new Error('Error'), message: 'Error' },\n      { err: 'string error', message: 'string error' },\n    ])('should log unexpected error \"$message\"', async ({ err, message }) => {\n      const destination = new Destination();\n      const callback = jest.fn();\n      const context = {\n        attempts: 0,\n        callback,\n        event: {\n          event_type: 'event_type',\n        },\n        timeout: 0,\n      };\n      const transportProvider = {\n        send: jest.fn().mockImplementationOnce(() => {\n          throw err;\n        }),\n      };\n      const loggerProvider = getMockLogger();\n\n      await destination.setup({\n        ...useDefaultConfig(),\n        transportProvider,\n        loggerProvider,\n      });\n      await destination.send([context]);\n      // Callback should not be called since errors get retried\n      expect(callback).toHaveBeenCalledTimes(0);\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(loggerProvider.error).toHaveBeenCalledTimes(1);\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(loggerProvider.error).toHaveBeenCalledWith(message);\n    });\n\n    test('should parse response without body', async () => {\n      const result = getResponseBodyString({\n        status: Status.Unknown,\n        statusCode: 700,\n      });\n      expect(result).toBe('');\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/plugins/helpers.test.ts",
    "content": "/** @jest-environment jsdom */\nimport {\n  MASKED_TEXT_VALUE,\n  TEXT_MASK_ATTRIBUTE,\n  getPageTitle,\n  replaceSensitiveString,\n  CC_REGEX,\n  SSN_REGEX,\n  EMAIL_REGEX,\n} from '../../src/plugins/helpers';\n\ndescribe('Constants', () => {\n  describe('TEXT_MASK_ATTRIBUTE', () => {\n    test('has the correct value', () => {\n      expect(TEXT_MASK_ATTRIBUTE).toBe('data-amp-mask');\n    });\n\n    test('is a string', () => {\n      expect(typeof TEXT_MASK_ATTRIBUTE).toBe('string');\n    });\n  });\n\n  describe('MASKED_TEXT_VALUE', () => {\n    test('has the correct value', () => {\n      expect(MASKED_TEXT_VALUE).toBe('*****');\n    });\n\n    test('is a string', () => {\n      expect(typeof MASKED_TEXT_VALUE).toBe('string');\n    });\n  });\n});\n\ndescribe('Regex Constants', () => {\n  test('CC_REGEX is a RegExp', () => {\n    expect(CC_REGEX).toBeInstanceOf(RegExp);\n  });\n\n  test('SSN_REGEX is a RegExp', () => {\n    expect(SSN_REGEX).toBeInstanceOf(RegExp);\n  });\n\n  test('EMAIL_REGEX is a RegExp', () => {\n    expect(EMAIL_REGEX).toBeInstanceOf(RegExp);\n  });\n});\n\ndescribe('replaceSensitiveString', () => {\n  describe('null and undefined inputs', () => {\n    test('should return empty string when text is null', () => {\n      const result = replaceSensitiveString(null);\n      expect(result).toBe('');\n    });\n\n    test('should return empty string when text is undefined', () => {\n      const result = replaceSensitiveString(undefined as unknown as string);\n      expect(result).toBe('');\n    });\n\n    test('should return empty string when text is not a string', () => {\n      const result = replaceSensitiveString(123 as unknown as string);\n      expect(result).toBe('');\n    });\n  });\n\n  describe('non-sensitive text', () => {\n    test('should return original text when text is not sensitive', () => {\n      const text = 'test-string';\n      const result = replaceSensitiveString(text);\n      expect(result).toBe('test-string');\n    });\n\n    test('should return original text with no patterns', () => {\n      const text = 'Hello World';\n      const result = replaceSensitiveString(text);\n      expect(result).toBe('Hello World');\n    });\n  });\n\n  describe('credit card masking', () => {\n    // https://www.paypalobjects.com/en_AU/vhelp/paypalmanager_help/credit_card_numbers.htm\n    test('should mask credit card numbers', () => {\n      const sampleCreditCardNumbers = [\n        '378282246310005', // American Express\n        '371449635398431', // American Express\n        '378734493671000', // American Express Corporate\n        '30569309025904', // Diners Club\n        '38520000023237', // Diners Club\n        '6011111111111117', // Discover\n        '6011000990139424', // Discover\n        '3530111333300000', // JCB\n        '3566002020360505', // JCB\n        '5555555555554444', // MasterCard\n        '5105105105105100', // MasterCard\n        '4111111111111111', // Visa\n        '4012888888881881', // Visa\n        '4222222222222', // Visa (13 digits)\n        '4916024123820164', // Visa\n      ];\n\n      for (const ccNumber of sampleCreditCardNumbers) {\n        const result = replaceSensitiveString(ccNumber);\n        expect(result).toBe(MASKED_TEXT_VALUE);\n      }\n    });\n\n    test('should handle credit card numbers with spaces', () => {\n      const text = '4111 1111 1111 1111';\n      const result = replaceSensitiveString(text);\n      expect(result).toBe(MASKED_TEXT_VALUE);\n    });\n\n    test('should handle credit card numbers with dashes', () => {\n      const text = '4111-1111-1111-1111';\n      const result = replaceSensitiveString(text);\n      expect(result).toBe(MASKED_TEXT_VALUE);\n    });\n\n    test('should handle credit card numbers with mixed spaces and dashes', () => {\n      const text = '4111 1111-1111 1111';\n      const result = replaceSensitiveString(text);\n      expect(result).toBe(MASKED_TEXT_VALUE);\n    });\n  });\n\n  describe('SSN masking', () => {\n    test('should mask social security numbers', () => {\n      const text = '269-28-9315';\n      const result = replaceSensitiveString(text);\n      expect(result).toBe(MASKED_TEXT_VALUE);\n    });\n\n    test('should mask SSN without dashes', () => {\n      const text = '269289315';\n      const result = replaceSensitiveString(text);\n      expect(result).toBe(MASKED_TEXT_VALUE);\n    });\n  });\n\n  describe('email masking', () => {\n    test('should mask email addresses', () => {\n      const text = 'user@example.com';\n      const result = replaceSensitiveString(text);\n      expect(result).toBe(MASKED_TEXT_VALUE);\n    });\n\n    test('should mask email within text', () => {\n      const text = 'Contact us at support@example.com for help';\n      const result = replaceSensitiveString(text);\n      expect(result).toBe(`Contact us at ${MASKED_TEXT_VALUE} for help`);\n    });\n\n    test('should mask email at the beginning', () => {\n      const text = 'user@example.com is the admin';\n      const result = replaceSensitiveString(text);\n      expect(result).toBe(`${MASKED_TEXT_VALUE} is the admin`);\n    });\n\n    test('should mask email at the end', () => {\n      const text = 'The admin is user@example.com';\n      const result = replaceSensitiveString(text);\n      expect(result).toBe(`The admin is ${MASKED_TEXT_VALUE}`);\n    });\n\n    test('should mask multiple emails', () => {\n      const text = 'Contact user@example.com or admin@test.org';\n      const result = replaceSensitiveString(text);\n      expect(result).toBe(`Contact ${MASKED_TEXT_VALUE} or ${MASKED_TEXT_VALUE}`);\n    });\n\n    test('should mask email with dots in domain', () => {\n      const text = 'user@mail.example.com';\n      const result = replaceSensitiveString(text);\n      expect(result).toBe(MASKED_TEXT_VALUE);\n    });\n  });\n\n  describe('custom patterns', () => {\n    test('should mask text matching custom regex patterns', () => {\n      const customPattern = /Florida|California/;\n      const text = 'I live in Florida';\n      const result = replaceSensitiveString(text, [customPattern]);\n      expect(result).toBe(`I live in ${MASKED_TEXT_VALUE}`);\n    });\n\n    test('should mask text with multiple custom patterns', () => {\n      const patterns = [/Florida|California/, /Pennsylvania/];\n      const text1 = 'Pittsburgh, Pennsylvania';\n      const text2 = 'Florida';\n\n      expect(replaceSensitiveString(text1, patterns)).toBe(`Pittsburgh, ${MASKED_TEXT_VALUE}`);\n      expect(replaceSensitiveString(text2, patterns)).toBe(MASKED_TEXT_VALUE);\n    });\n\n    test('should handle invalid patterns gracefully', () => {\n      // Create an invalid regex that will throw on replace\n      const badPattern = /test/;\n      // Override the replace method to throw\n      Object.defineProperty(badPattern, Symbol.replace, {\n        value: () => {\n          throw new Error('Invalid pattern');\n        },\n      });\n\n      const text = 'test string';\n      const result = replaceSensitiveString(text, [badPattern]);\n      // Should still process other built-in patterns\n      expect(result).toBeDefined();\n    });\n\n    test('should apply custom patterns after built-in patterns', () => {\n      const customPattern = /secret/gi;\n      const text = 'user@example.com has a secret';\n      const result = replaceSensitiveString(text, [customPattern]);\n      expect(result).toBe(`${MASKED_TEXT_VALUE} has a ${MASKED_TEXT_VALUE}`);\n    });\n  });\n\n  describe('combined masking', () => {\n    test('should mask multiple types of sensitive data', () => {\n      const text = 'Email: user@example.com CC: 4111111111111111 SSN: 123-45-6789';\n      const result = replaceSensitiveString(text);\n      expect(result).toBe(`Email: ${MASKED_TEXT_VALUE} CC: ${MASKED_TEXT_VALUE} SSN: ${MASKED_TEXT_VALUE}`);\n    });\n\n    test('should mask built-in and custom patterns together', () => {\n      const customPattern = /secret/gi;\n      const text = 'secret data: user@example.com';\n      const result = replaceSensitiveString(text, [customPattern]);\n      expect(result).toBe(`${MASKED_TEXT_VALUE} data: ${MASKED_TEXT_VALUE}`);\n    });\n  });\n\n  describe('edge cases', () => {\n    test('should handle empty string', () => {\n      const result = replaceSensitiveString('');\n      expect(result).toBe('');\n    });\n\n    test('should handle empty custom patterns array', () => {\n      const text = 'test string';\n      const result = replaceSensitiveString(text, []);\n      expect(result).toBe('test string');\n    });\n\n    test('should handle text with only sensitive data', () => {\n      const result = replaceSensitiveString('user@example.com');\n      expect(result).toBe(MASKED_TEXT_VALUE);\n    });\n  });\n});\n\ndescribe('getPageTitle (core)', () => {\n  beforeEach(() => {\n    Object.defineProperty(document, 'title', {\n      value: 'Test Page Title',\n      writable: true,\n    });\n  });\n\n  afterEach(() => {\n    const titleElements = document.querySelectorAll('title');\n    titleElements.forEach((el) => el.remove());\n  });\n\n  test('returns document title when no title element has data-amp-mask', () => {\n    const result = getPageTitle();\n    expect(result).toBe('Test Page Title');\n  });\n\n  test('returns MASKED_TEXT_VALUE when title element has data-amp-mask attribute', () => {\n    const titleElement = document.createElement('title');\n    titleElement.setAttribute(TEXT_MASK_ATTRIBUTE, 'true');\n    titleElement.textContent = 'Sensitive Title';\n    document.head.appendChild(titleElement);\n\n    const result = getPageTitle();\n    expect(result).toBe(MASKED_TEXT_VALUE);\n  });\n\n  test('returns document title when title element exists but does not have data-amp-mask', () => {\n    const titleElement = document.createElement('title');\n    titleElement.textContent = 'Regular Title';\n    document.head.appendChild(titleElement);\n\n    const result = getPageTitle();\n    expect(result).toBe('Test Page Title');\n  });\n\n  test('applies parse function when provided', () => {\n    Object.defineProperty(document, 'title', {\n      value: 'Contact us at test@example.com',\n      writable: true,\n    });\n\n    const maskSensitiveEmail = (title: string) => title.replace(/[^\\s@]+@[^\\s@.]+\\.[^\\s@]+/g, MASKED_TEXT_VALUE);\n    const result = getPageTitle(maskSensitiveEmail);\n    expect(result).toBe('Contact us at *****');\n  });\n\n  test('returns empty string when document title is null or undefined', () => {\n    Object.defineProperty(document, 'title', {\n      value: null,\n      writable: true,\n    });\n\n    const result = getPageTitle();\n    expect(result).toBe('');\n\n    Object.defineProperty(document, 'title', {\n      value: 'Test Page Title',\n      writable: true,\n    });\n  });\n\n  test('returns empty string when document is undefined (server-side scenario)', () => {\n    const globalWithDocument = global as typeof global & { document?: Document };\n    const originalDescriptor = Object.getOwnPropertyDescriptor(globalWithDocument, 'document');\n\n    Object.defineProperty(globalWithDocument, 'document', {\n      value: undefined,\n      writable: true,\n      configurable: true,\n    });\n\n    try {\n      const result = getPageTitle();\n      expect(result).toBe('');\n    } finally {\n      if (originalDescriptor) {\n        Object.defineProperty(globalWithDocument, 'document', originalDescriptor);\n      } else {\n        Reflect.deleteProperty(globalWithDocument, 'document');\n      }\n    }\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/plugins/identity.test.ts",
    "content": "import { IdentityEventSender } from '../../src/plugins/identity';\nimport { IConfig } from '../../src/types/config/core-config';\nimport { getAnalyticsConnector } from '../../src/analytics-connector';\n\ndescribe('identity', () => {\n  describe('execute', () => {\n    beforeEach(() => {\n      getAnalyticsConnector().identityStore.setIdentity({ userProperties: {} });\n    });\n\n    test('should set identity in analytics connector on identify with default instance', async () => {\n      const plugin = new IdentityEventSender();\n      await plugin.setup({} as IConfig);\n      const event = {\n        event_type: '$identify',\n        user_properties: {\n          $set: { k: 'v' },\n        },\n      };\n      const result = await plugin.execute(event);\n      const identity = getAnalyticsConnector().identityStore.getIdentity();\n      expect(result).toEqual(event);\n      expect(identity.userProperties).toEqual({ k: 'v' });\n    });\n\n    test('should set identity in analytics connector on identify with instance name', async () => {\n      const plugin = new IdentityEventSender();\n      await plugin.setup({\n        instanceName: 'env',\n      } as IConfig);\n      const event = {\n        event_type: '$identify',\n        user_properties: {\n          $set: { k: 'v' },\n        },\n      };\n      const result = await plugin.execute(event);\n      const identity = getAnalyticsConnector('env').identityStore.getIdentity();\n      expect(result).toEqual(event);\n      expect(identity.userProperties).toEqual({ k: 'v' });\n    });\n\n    test('should do nothing on track event', async () => {\n      const plugin = new IdentityEventSender();\n      await plugin.setup({} as IConfig);\n      const event = {\n        event_type: 'test_track',\n      };\n      const result = await plugin.execute(event);\n      expect(result).toEqual(event);\n      const emptyIdentity = { userProperties: {} };\n      const identity = getAnalyticsConnector().identityStore.getIdentity();\n      expect(identity).toEqual(emptyIdentity);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/query-params.test.ts",
    "content": "/**\n * @jest-environment jsdom\n */\n\nimport { getQueryParams } from '../src/query-params';\nimport * as GlobalScopeModule from '../src/global-scope';\n\ndescribe('query-params', () => {\n  describe('getQueryParams', () => {\n    beforeAll(() => {\n      Object.defineProperty(window, 'location', {\n        value: {\n          search: '',\n          writable: true,\n        },\n      });\n    });\n\n    afterAll(() => {\n      Object.defineProperty(window, 'location', {\n        value: {\n          search: '',\n          writable: false,\n        },\n      });\n    });\n\n    test('should parse query params', () => {\n      window.location.search = '?a=1&b=2%20test&&c%24=hello&d';\n      const params = getQueryParams();\n      expect(params).toEqual({\n        a: '1',\n        b: '2 test',\n        c$: 'hello',\n      });\n    });\n\n    test('should parse malformed uri', () => {\n      window.location.search = '?fb=X+%EF%BF%BD%93+C';\n      const params = getQueryParams();\n      expect(params).toEqual({});\n    });\n\n    test('should handle undefined global scope', () => {\n      jest.spyOn(GlobalScopeModule, 'getGlobalScope').mockReturnValueOnce(undefined);\n      const params = getQueryParams();\n      expect(params).toEqual({});\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/remote-config/remote-config-localstorage.test.ts",
    "content": "/**\n * @jest-environment jsdom\n */\n\nimport { RemoteConfigLocalStorage } from '../../src/remote-config/remote-config-localstorage';\nimport { RemoteConfig, RemoteConfigInfo } from '../../src/remote-config/remote-config';\nimport { ILogger } from '../../src/logger';\n\ndescribe('RemoteConfigLocalStorage', () => {\n  let logger: ILogger;\n  let loggerDebug: jest.SpyInstance;\n  let storage: RemoteConfigLocalStorage;\n  const apiKey = '12345678901234567890';\n  const storageKey = `AMP_remote_config_${apiKey.substring(0, 10)}`;\n  const mockDate = new Date('2025-03-18T12:00:00Z');\n\n  beforeEach(() => {\n    logger = {\n      disable: jest.fn(),\n      enable: jest.fn(),\n      debug: jest.fn(),\n      log: jest.fn(),\n      warn: jest.fn(),\n      error: jest.fn(),\n    };\n    loggerDebug = jest.spyOn(logger, 'debug');\n\n    storage = new RemoteConfigLocalStorage(apiKey, logger);\n    localStorage.clear();\n\n    jest.useFakeTimers().setSystemTime(mockDate);\n  });\n\n  afterEach(() => {\n    jest.useRealTimers();\n  });\n\n  describe('fetchConfig', () => {\n    it('should return remote config info', async () => {\n      const lastFetch = new Date('2025-03-20T12:00:00Z');\n      const remoteConfig: RemoteConfig = { key1: 'value1' };\n      const mockConfigInfo: RemoteConfigInfo = {\n        remoteConfig: remoteConfig,\n        lastFetch: lastFetch,\n      };\n      localStorage.setItem(storageKey, JSON.stringify(mockConfigInfo));\n\n      const result = await storage.fetchConfig();\n\n      expect(result.remoteConfig).toEqual(remoteConfig);\n      expect(result.lastFetch).toEqual(lastFetch);\n      expect(loggerDebug).toHaveBeenCalledWith(\n        expect.stringContaining('Remote config localstorage parsed successfully:'),\n      );\n    });\n\n    it('should return remote config info null and clear storage if JSON parsing fails', async () => {\n      localStorage.setItem(storageKey, '{ invalid json }');\n\n      const result = await storage.fetchConfig();\n\n      expect(result.remoteConfig).toBeNull();\n      expect(result.lastFetch).toEqual(mockDate);\n      expect(loggerDebug).toHaveBeenCalledWith('Remote config localstorage failed to parse: ', expect.any(Error));\n      expect(localStorage.getItem(storageKey)).toBeNull();\n    });\n\n    it('should return remote config info null localStorage is empty', async () => {\n      const result = await storage.fetchConfig();\n\n      expect(result.remoteConfig).toBeNull();\n      expect(result.lastFetch).toBeInstanceOf(Date);\n      expect(loggerDebug).toHaveBeenCalledWith('Remote config localstorage gets null because the key does not exist');\n    });\n\n    it('should return remote config info null if localStorage.getItem throws an error', async () => {\n      const getItemSpy = jest.spyOn(Storage.prototype, 'getItem').mockImplementation(() => {\n        throw new Error('localStorage is undefined');\n      });\n\n      const result = await storage.fetchConfig();\n\n      expect(result.remoteConfig).toBeNull();\n      expect(result.lastFetch).toBeInstanceOf(Date);\n      expect(loggerDebug).toHaveBeenCalledWith('Remote config localstorage failed to access: ', expect.any(Error));\n\n      // Restore the original getItem implementation\n      getItemSpy.mockRestore();\n    });\n  });\n\n  describe('setConfig', () => {\n    it('should store the config in localStorage and return true', async () => {\n      const info: RemoteConfigInfo = {\n        remoteConfig: { key1: 'value1' },\n        lastFetch: new Date(),\n      };\n\n      const result = await storage.setConfig(info);\n\n      expect(result).toBe(true);\n      expect(localStorage.getItem(storageKey)).toEqual(JSON.stringify(info));\n      expect(loggerDebug).toHaveBeenCalledWith('Remote config localstorage set successfully.');\n    });\n\n    it('should return false and log an error if storing the config fails', async () => {\n      // Mock localStorage.setItem to throw an error\n      jest.spyOn(Storage.prototype, 'setItem').mockImplementation(() => {\n        throw new Error('Storage quota exceeded');\n      });\n\n      const info: RemoteConfigInfo = {\n        remoteConfig: { key1: 'value1' },\n        lastFetch: new Date(),\n      };\n\n      const result = await storage.setConfig(info);\n\n      expect(result).toBe(false);\n      expect(loggerDebug).toHaveBeenCalledWith('Remote config localstorage failed to set: ', expect.any(Error));\n\n      // Restore the mock\n      jest.restoreAllMocks();\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/remote-config/remote-config.test.ts",
    "content": "import {\n  CallbackInfo,\n  DeliveryMode,\n  EU_SERVER_URL,\n  RemoteConfigClient,\n  RemoteConfigInfo,\n  US_SERVER_URL,\n} from '../../src/remote-config/remote-config';\nimport { ILogger } from '../../src/logger';\nimport { RemoteConfigLocalStorage } from '../../src/remote-config/remote-config-localstorage';\n\njest.mock('../../src/remote-config/remote-config-localstorage');\nconst mockUuid = 'uuid123456789';\njest.mock('../../src/utils/uuid', () => ({\n  __esModule: true, // This is important for ES modules\n  UUID: jest.fn(() => mockUuid),\n}));\njest.mock('../../src/remote-config/remote-config', () => {\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n  const actual = jest.requireActual('../../src/remote-config/remote-config');\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n  return {\n    ...actual,\n    FETCHED_KEYS: ['test_key_1', 'test_key_2'],\n  };\n});\n\nconst mockLogger: ILogger = {\n  disable: jest.fn(),\n  enable: jest.fn(),\n  debug: jest.fn(),\n  log: jest.fn(),\n  warn: jest.fn(),\n  error: jest.fn(),\n};\nconst mockStorage = {\n  fetchConfig: jest.fn(),\n  setConfig: jest.fn(),\n};\nconst mockApiKey = 'test-api-key';\nconst testKey = 'browser';\n\ndescribe('RemoteConfigClient', () => {\n  let client: RemoteConfigClient;\n  let loggerDebug: jest.SpyInstance;\n  let loggerError: jest.SpyInstance;\n  let storageFetchConfig: jest.SpyInstance;\n\n  beforeEach(() => {\n    loggerDebug = jest.spyOn(mockLogger, 'debug');\n    loggerError = jest.spyOn(mockLogger, 'error');\n    storageFetchConfig = jest.spyOn(mockStorage, 'fetchConfig');\n\n    (RemoteConfigLocalStorage as jest.Mock).mockImplementation(() => mockStorage);\n    client = new RemoteConfigClient(mockApiKey, mockLogger);\n\n    // Clears only the call history but keeps the original mock implementation\n    jest.clearAllMocks();\n  });\n\n  describe('constructor', () => {\n    test('should initialize correctly', () => {\n      expect(client.serverUrl).toBe(US_SERVER_URL);\n      expect(client.apiKey).toBe(mockApiKey);\n      expect(client.logger).toBeDefined();\n      expect(client.storage).toBeDefined();\n\n      const usClient = new RemoteConfigClient(mockApiKey, mockLogger, 'US');\n      expect(usClient.serverUrl).toBe(US_SERVER_URL);\n\n      const euClient = new RemoteConfigClient(mockApiKey, mockLogger, 'EU');\n      expect(euClient.serverUrl).toBe(EU_SERVER_URL);\n    });\n\n    test('should use custom serverUrl when provided', () => {\n      const customServerUrl = 'https://custom-proxy.example.com/config';\n      const customClient = new RemoteConfigClient(mockApiKey, mockLogger, 'US', customServerUrl);\n      expect(customClient.serverUrl).toBe(customServerUrl);\n    });\n\n    test('should prioritize custom serverUrl over serverZone', () => {\n      const customServerUrl = 'https://my-proxy.company.com/amplitude-config';\n      const euClientWithCustomUrl = new RemoteConfigClient(mockApiKey, mockLogger, 'EU', customServerUrl);\n      expect(euClientWithCustomUrl.serverUrl).toBe(customServerUrl);\n      expect(euClientWithCustomUrl.serverUrl).not.toBe(EU_SERVER_URL);\n    });\n  });\n\n  describe('subscribe', () => {\n    test('should set callback info and call subscribeAll', async () => {\n      const subscribeAll = jest.spyOn(client, 'subscribeAll');\n      subscribeAll.mockImplementation(jest.fn());\n      const callback = jest.fn();\n      const callbackInfo = {\n        id: mockUuid,\n        key: testKey,\n        deliveryMode: 'all',\n        callback: callback,\n      };\n\n      expect(client.callbackInfos.length).toBe(0);\n      client.subscribe(testKey, 'all', callback);\n      expect(client.callbackInfos.length).toBe(1);\n      expect(client.callbackInfos[0]).toEqual(callbackInfo);\n      expect(subscribeAll).toHaveBeenCalledTimes(1);\n      expect(subscribeAll).toHaveBeenCalledWith(callbackInfo);\n    });\n\n    test('should set callback info and call subscribeWaitForRemote', async () => {\n      const subscribeWaitForRemote = jest.spyOn(client, 'subscribeWaitForRemote');\n      subscribeWaitForRemote.mockImplementation(jest.fn());\n      const timeout = 5000;\n      const callback = jest.fn();\n      const callbackInfo = {\n        id: mockUuid,\n        key: testKey,\n        deliveryMode: { timeout: timeout },\n        callback: callback,\n      };\n\n      expect(client.callbackInfos.length).toBe(0);\n      client.subscribe(testKey, { timeout: timeout }, callback);\n      expect(client.callbackInfos.length).toBe(1);\n      expect(client.callbackInfos[0]).toEqual(callbackInfo);\n      expect(subscribeWaitForRemote).toHaveBeenCalledTimes(1);\n      expect(subscribeWaitForRemote).toHaveBeenCalledWith(callbackInfo, timeout);\n    });\n  });\n\n  describe('unsubscribe', () => {\n    test('should remove callback', () => {\n      const callbackInfo = {\n        id: mockUuid,\n        key: testKey,\n        deliveryMode: 'all' as DeliveryMode,\n        callback: jest.fn(),\n      };\n      client.callbackInfos.push(callbackInfo);\n\n      expect(client.callbackInfos.length).toBe(1);\n      const result = client.unsubscribe(mockUuid);\n      expect(client.callbackInfos.length).toBe(0);\n      expect(loggerDebug).toHaveBeenCalledWith(\n        `Remote config client unsubscribe succeeded removing callback with id ${mockUuid}.`,\n      );\n      expect(result).toBe(true);\n    });\n\n    test('should log when id does not exit', () => {\n      const callbackInfo = {\n        id: mockUuid,\n        key: testKey,\n        deliveryMode: 'all' as DeliveryMode,\n        callback: jest.fn(),\n      };\n      client.callbackInfos.push(callbackInfo);\n\n      expect(client.callbackInfos.length).toBe(1);\n      const testId = 'id-does-not-exist';\n      const result = client.unsubscribe(testId);\n      expect(client.callbackInfos.length).toBe(1);\n      expect(loggerDebug).toHaveBeenCalledWith(\n        `Remote config client unsubscribe failed because callback with id ${testId} doesn't exist.`,\n      );\n      expect(result).toBe(false);\n    });\n  });\n\n  describe('updateConfigs', () => {\n    test('should call fetch, storage set, and call callbacks', async () => {\n      const fetch = jest.spyOn(client, 'fetch');\n      const sendCallback = jest.spyOn(client, 'sendCallback');\n      const remoteConfigInfo = {\n        remoteConfig: { key: 'value' },\n        lastFetch: new Date(),\n      };\n      const fetchPromise = Promise.resolve(remoteConfigInfo);\n      fetch.mockReturnValueOnce(fetchPromise);\n\n      const callbackInfo = {\n        id: mockUuid,\n        key: testKey,\n        deliveryMode: 'all' as DeliveryMode,\n        callback: jest.fn(),\n      };\n      client.callbackInfos.push(callbackInfo);\n\n      await client.updateConfigs();\n      expect(fetch).toHaveBeenCalledTimes(1);\n      expect(mockStorage.setConfig).toHaveBeenCalledWith(remoteConfigInfo);\n      expect(sendCallback).toHaveBeenCalledWith(callbackInfo, remoteConfigInfo, 'remote');\n      expect(client.lastSuccessfulFetch).toEqual(expect.any(Number));\n    });\n\n    test('should skip fetch if called within 5 minutes of last successful fetch', async () => {\n      const fetch = jest.spyOn(client, 'fetch');\n      const remoteConfigInfo = {\n        remoteConfig: { key: 'value' },\n        lastFetch: new Date(),\n      };\n      fetch.mockReturnValueOnce(Promise.resolve(remoteConfigInfo));\n\n      // First call should succeed\n      await client.updateConfigs();\n      expect(fetch).toHaveBeenCalledTimes(1);\n      expect(client.lastSuccessfulFetch).toEqual(expect.any(Number));\n\n      // Second call within 5 minutes should be skipped\n      await client.updateConfigs();\n      expect(fetch).toHaveBeenCalledTimes(1); // Still 1, not called again\n      expect(loggerDebug).toHaveBeenCalledWith('Remote config client skipping updateConfigs: Too recent');\n    });\n\n    test('should allow fetch if called after 5 minutes of last successful fetch', async () => {\n      const fetch = jest.spyOn(client, 'fetch');\n      const remoteConfigInfo = {\n        remoteConfig: { key: 'value' },\n        lastFetch: new Date(),\n      };\n      fetch.mockReturnValue(Promise.resolve(remoteConfigInfo));\n\n      // First call\n      await client.updateConfigs();\n      expect(fetch).toHaveBeenCalledTimes(1);\n\n      // Set lastSuccessfulFetch to 6 minutes ago\n      const sixMinutesAgo = Date.now() - 6 * 60 * 1000;\n      client.lastSuccessfulFetch = sixMinutesAgo;\n\n      // Second call should succeed\n      await client.updateConfigs();\n      expect(fetch).toHaveBeenCalledTimes(2);\n    });\n\n    test('should not update lastSuccessfulFetch if fetch returns null config', async () => {\n      const fetch = jest.spyOn(client, 'fetch');\n      const remoteConfigInfo = {\n        remoteConfig: null, // Failed fetch\n        lastFetch: new Date(),\n      };\n      fetch.mockReturnValueOnce(Promise.resolve(remoteConfigInfo));\n\n      expect(client.lastSuccessfulFetch).toBeNull();\n      await client.updateConfigs();\n      expect(fetch).toHaveBeenCalledTimes(1);\n      expect(client.lastSuccessfulFetch).toBeNull(); // Should still be null\n    });\n\n    test('should skip future updateConfigs calls after invalid API key response', async () => {\n      global.fetch = jest.fn(() =>\n        Promise.resolve({\n          ok: false,\n          status: 401,\n          text: () => Promise.resolve('Invalid API key'),\n        } as Response),\n      );\n\n      await client.updateConfigs();\n      expect(global.fetch).toHaveBeenCalledTimes(1);\n\n      await client.updateConfigs();\n      expect(global.fetch).toHaveBeenCalledTimes(1);\n      expect(loggerDebug).toHaveBeenCalledWith('Remote config client skipping fetch: Invalid API key');\n      expect(loggerError).toHaveBeenCalledTimes(1);\n      expect(loggerError).toHaveBeenCalledWith(\n        expect.stringContaining('Remote config client fetch failed with 401. Invalid API key'),\n      );\n    });\n  });\n\n  describe('getOrCreateFetchPromise', () => {\n    test('should create a new fetch promise if none exists', async () => {\n      const fetch = jest.spyOn(client, 'fetch');\n      const remoteConfigInfo = {\n        remoteConfig: { key: 'value' },\n        lastFetch: new Date(),\n      };\n      fetch.mockReturnValueOnce(Promise.resolve(remoteConfigInfo));\n\n      expect(client.fetchPromise).toBeNull();\n      const promise = client.getOrCreateFetchPromise();\n      expect(client.fetchPromise).not.toBeNull();\n\n      const result = await promise;\n      expect(result).toEqual(remoteConfigInfo);\n      expect(fetch).toHaveBeenCalledTimes(1);\n      expect(client.lastSuccessfulFetch).toEqual(expect.any(Number));\n    });\n\n    test('should return existing fetch promise if one is in flight', async () => {\n      const fetch = jest.spyOn(client, 'fetch');\n      const remoteConfigInfo = {\n        remoteConfig: { key: 'value' },\n        lastFetch: new Date(),\n      };\n      // Mock fetch to take some time\n      fetch.mockImplementation(\n        () =>\n          new Promise((resolve) => {\n            setTimeout(() => {\n              resolve(remoteConfigInfo);\n            }, 100);\n          }),\n      );\n\n      // Call getOrCreateFetchPromise twice quickly\n      const promise1 = client.getOrCreateFetchPromise();\n      const promise2 = client.getOrCreateFetchPromise();\n\n      // Should return the same promise\n      expect(promise1).toBe(promise2);\n      expect(fetch).toHaveBeenCalledTimes(1); // Only one fetch call\n\n      const [result1, result2] = await Promise.all([promise1, promise2]);\n      expect(result1).toEqual(remoteConfigInfo);\n      expect(result2).toEqual(remoteConfigInfo);\n    });\n\n    test('should clear fetchPromise after promise settles successfully', async () => {\n      const fetch = jest.spyOn(client, 'fetch');\n      const remoteConfigInfo = {\n        remoteConfig: { key: 'value' },\n        lastFetch: new Date(),\n      };\n      fetch.mockReturnValueOnce(Promise.resolve(remoteConfigInfo));\n\n      expect(client.fetchPromise).toBeNull();\n      const promise = client.getOrCreateFetchPromise();\n      expect(client.fetchPromise).not.toBeNull();\n\n      await promise;\n      expect(client.fetchPromise).toBeNull();\n    });\n\n    test('should clear fetchPromise after promise settles with failure', async () => {\n      const fetch = jest.spyOn(client, 'fetch');\n      const remoteConfigInfo = {\n        remoteConfig: null, // Failed fetch\n        lastFetch: new Date(),\n      };\n      fetch.mockReturnValueOnce(Promise.resolve(remoteConfigInfo));\n\n      expect(client.fetchPromise).toBeNull();\n      const promise = client.getOrCreateFetchPromise();\n      expect(client.fetchPromise).not.toBeNull();\n\n      await promise;\n      expect(client.fetchPromise).toBeNull();\n      expect(client.lastSuccessfulFetch).toBeNull(); // Should not update on failure\n    });\n\n    test('should allow new fetch promise after previous one completes', async () => {\n      const fetch = jest.spyOn(client, 'fetch');\n      const remoteConfigInfo = {\n        remoteConfig: { key: 'value' },\n        lastFetch: new Date(),\n      };\n      fetch.mockReturnValue(Promise.resolve(remoteConfigInfo));\n\n      // First fetch\n      const promise1 = client.getOrCreateFetchPromise();\n      await promise1;\n      expect(client.fetchPromise).toBeNull();\n\n      // Second fetch should create a new promise\n      const promise2 = client.getOrCreateFetchPromise();\n      expect(promise2).not.toBe(promise1);\n      expect(client.fetchPromise).not.toBeNull();\n      await promise2;\n\n      expect(fetch).toHaveBeenCalledTimes(2);\n    });\n\n    test('should short-circuit and skip fetch when API key is invalid', async () => {\n      const fetch = jest.spyOn(client, 'fetch');\n      client.isLastFetchInvalidApiKey = true;\n\n      const result = await client.getOrCreateFetchPromise();\n\n      expect(fetch).not.toHaveBeenCalled();\n      expect(result.remoteConfig).toBeNull();\n      expect(result.lastFetch).toBeInstanceOf(Date);\n      expect(loggerDebug).toHaveBeenCalledWith('Remote config client skipping fetch: Invalid API key');\n    });\n  });\n\n  describe('subscribeAll', () => {\n    test('should batch multiple simultaneous subscribe calls into one request', async () => {\n      const fetch = jest.spyOn(client, 'fetch');\n      const sendCallback = jest.spyOn(client, 'sendCallback');\n      const remoteConfigInfo = {\n        remoteConfig: { key: 'value' },\n        lastFetch: new Date(),\n      };\n      // Mock fetch to take some time\n      fetch.mockImplementation(\n        () =>\n          new Promise((resolve) => {\n            setTimeout(() => {\n              resolve(remoteConfigInfo);\n            }, 100);\n          }),\n      );\n      storageFetchConfig.mockReturnValue(\n        new Promise((resolve) => {\n          setTimeout(() => {\n            resolve(remoteConfigInfo);\n          }, 200);\n        }),\n      );\n\n      const callback1 = jest.fn();\n      const callback2 = jest.fn();\n\n      const callbackInfo1 = {\n        id: 'id1',\n        key: testKey,\n        deliveryMode: 'all' as DeliveryMode,\n        callback: callback1,\n      };\n      const callbackInfo2 = {\n        id: 'id2',\n        key: testKey,\n        deliveryMode: 'all' as DeliveryMode,\n        callback: callback2,\n      };\n\n      // Call subscribeAll twice simultaneously\n      await Promise.all([client.subscribeAll(callbackInfo1), client.subscribeAll(callbackInfo2)]);\n\n      // Should only make one fetch call (batched)\n      expect(fetch).toHaveBeenCalledTimes(1);\n      // But both callbacks should be called\n      expect(sendCallback).toHaveBeenCalledWith(callbackInfo1, remoteConfigInfo, 'remote');\n      expect(sendCallback).toHaveBeenCalledWith(callbackInfo2, remoteConfigInfo, 'remote');\n    });\n\n    test('should return remote only if remote returns first', async () => {\n      // fetch() returns immediately\n      const fetch = jest.spyOn(client, 'fetch');\n      const sendCallback = jest.spyOn(client, 'sendCallback');\n      const remoteConfigInfo = {\n        remoteConfig: null,\n        lastFetch: new Date(),\n      };\n      const fetchPromise = Promise.resolve(remoteConfigInfo);\n      fetch.mockReturnValueOnce(fetchPromise);\n\n      // storage.fetchConfig() returns after 1s\n      storageFetchConfig.mockImplementation(\n        () =>\n          new Promise((resolve) => {\n            setTimeout(() => {\n              resolve(remoteConfigInfo);\n            }, 1000);\n          }),\n      );\n\n      const callbackInfo = {\n        id: mockUuid,\n        key: testKey,\n        deliveryMode: 'all' as DeliveryMode,\n        callback: jest.fn(),\n      };\n      await client.subscribeAll(callbackInfo);\n\n      expect(fetch).toHaveBeenCalledTimes(1);\n      expect(mockStorage.fetchConfig).toHaveBeenCalledTimes(1);\n      expect(loggerDebug).toHaveBeenCalledWith(\n        expect.stringContaining('Remote config client subscription all mode fetched from remote:'),\n      );\n      expect(sendCallback).toHaveBeenCalledWith(callbackInfo, remoteConfigInfo, 'remote');\n      expect(mockStorage.setConfig).toHaveBeenCalledWith(remoteConfigInfo);\n    });\n\n    test('should return cache and then remote if cache returns first', async () => {\n      // fetch() returns after 1s\n      const fetch = jest.spyOn(client, 'fetch');\n      const sendCallback = jest.spyOn(client, 'sendCallback');\n      const remoteConfigInfo = {\n        remoteConfig: { a: { b: 1 } },\n        lastFetch: new Date(),\n      };\n      fetch.mockImplementation(\n        () =>\n          new Promise((resolve) => {\n            setTimeout(() => {\n              resolve(remoteConfigInfo);\n            }, 1000);\n          }),\n      );\n\n      // storage.fetchConfig() returns immediately\n      storageFetchConfig.mockReturnValueOnce(Promise.resolve(remoteConfigInfo));\n\n      const callbackInfo = {\n        id: mockUuid,\n        key: testKey,\n        deliveryMode: 'all' as DeliveryMode,\n        callback: jest.fn(),\n      };\n      await client.subscribeAll(callbackInfo);\n      // Wait 1s for fetch() returns\n      await new Promise((resolve) => setTimeout(resolve, 1000));\n\n      expect(fetch).toHaveBeenCalledTimes(1);\n      expect(mockStorage.fetchConfig).toHaveBeenCalledTimes(1);\n      expect(loggerDebug).toHaveBeenCalledWith(\n        expect.stringContaining('Remote config client subscription all mode fetched from cache:'),\n      );\n      expect(loggerDebug).toHaveBeenCalledWith(\n        expect.stringContaining('Remote config client subscription all mode fetched from remote:'),\n      );\n      expect(sendCallback).toHaveBeenCalledWith(callbackInfo, remoteConfigInfo, 'remote');\n      expect(sendCallback).toHaveBeenCalledWith(callbackInfo, remoteConfigInfo, 'cache');\n      expect(mockStorage.setConfig).toHaveBeenCalledTimes(1);\n    });\n\n    test('should skip cache callback when cache is empty (first time user) but still return remote', async () => {\n      // fetch() returns after 1s with valid data\n      const fetch = jest.spyOn(client, 'fetch');\n      const sendCallback = jest.spyOn(client, 'sendCallback');\n      const remoteFetchResult = {\n        remoteConfig: { a: { b: 1 } },\n        lastFetch: new Date(),\n      };\n      fetch.mockImplementation(\n        () =>\n          new Promise((resolve) => {\n            setTimeout(() => {\n              resolve(remoteFetchResult);\n            }, 1000);\n          }),\n      );\n\n      // storage.fetchConfig() returns immediately with null remoteConfig (first time user)\n      const emptyCacheResult = {\n        remoteConfig: null,\n        lastFetch: new Date(),\n      };\n      storageFetchConfig.mockReturnValueOnce(Promise.resolve(emptyCacheResult));\n\n      const callbackInfo = {\n        id: mockUuid,\n        key: testKey,\n        deliveryMode: 'all' as DeliveryMode,\n        callback: jest.fn(),\n      };\n      await client.subscribeAll(callbackInfo);\n      // Wait 1s for fetch() returns\n      await new Promise((resolve) => setTimeout(resolve, 1000));\n\n      expect(fetch).toHaveBeenCalledTimes(1);\n      expect(mockStorage.fetchConfig).toHaveBeenCalledTimes(1);\n      // Should log that callback is skipped for empty cache\n      expect(loggerDebug).toHaveBeenCalledWith(\n        'Remote config client skips sending callback because cache is empty (first time user).',\n      );\n      expect(loggerDebug).toHaveBeenCalledWith(\n        expect.stringContaining('Remote config client subscription all mode fetched from remote:'),\n      );\n      // Should only send callback for remote, NOT for cache\n      expect(sendCallback).toHaveBeenCalledTimes(1);\n      expect(sendCallback).toHaveBeenCalledWith(callbackInfo, remoteFetchResult, 'remote');\n      expect(sendCallback).not.toHaveBeenCalledWith(callbackInfo, emptyCacheResult, 'cache');\n      expect(mockStorage.setConfig).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('subscribeWaitForRemote', () => {\n    test('should batch multiple simultaneous subscribe calls into one request', async () => {\n      const fetch = jest.spyOn(client, 'fetch');\n      const sendCallback = jest.spyOn(client, 'sendCallback');\n      const remoteConfigInfo = {\n        remoteConfig: { key: 'value' },\n        lastFetch: new Date(),\n      };\n      // Mock fetch to take some time but less than timeout\n      fetch.mockImplementation(\n        () =>\n          new Promise((resolve) => {\n            setTimeout(() => {\n              resolve(remoteConfigInfo);\n            }, 100);\n          }),\n      );\n\n      const callback1 = jest.fn();\n      const callback2 = jest.fn();\n\n      const callbackInfo1 = {\n        id: 'id1',\n        key: testKey,\n        deliveryMode: { timeout: 1000 } as DeliveryMode,\n        callback: callback1,\n      };\n      const callbackInfo2 = {\n        id: 'id2',\n        key: testKey,\n        deliveryMode: { timeout: 1000 } as DeliveryMode,\n        callback: callback2,\n      };\n\n      // Call subscribeWaitForRemote twice simultaneously\n      await Promise.all([\n        client.subscribeWaitForRemote(callbackInfo1, 1000),\n        client.subscribeWaitForRemote(callbackInfo2, 1000),\n      ]);\n\n      // Should only make one fetch call (batched)\n      expect(fetch).toHaveBeenCalledTimes(1);\n      // But both callbacks should be called\n      expect(sendCallback).toHaveBeenCalledWith(callbackInfo1, remoteConfigInfo, 'remote');\n      expect(sendCallback).toHaveBeenCalledWith(callbackInfo2, remoteConfigInfo, 'remote');\n    });\n\n    test('should return remote', async () => {\n      // fetch() returns immediately\n      const fetch = jest.spyOn(client, 'fetch');\n      const sendCallback = jest.spyOn(client, 'sendCallback');\n      const remoteConfigInfo = {\n        remoteConfig: null,\n        lastFetch: new Date(),\n      };\n      fetch.mockReturnValueOnce(Promise.resolve(remoteConfigInfo));\n\n      const callbackInfo = {\n        id: mockUuid,\n        key: testKey,\n        deliveryMode: 'all' as DeliveryMode,\n        callback: jest.fn(),\n      };\n      await client.subscribeWaitForRemote(callbackInfo, 1000);\n\n      expect(fetch).toHaveBeenCalledTimes(1);\n      expect(loggerDebug).toHaveBeenCalledWith(\n        'Remote config client subscription wait for remote mode returns from remote.',\n      );\n      expect(sendCallback).toHaveBeenCalledWith(callbackInfo, remoteConfigInfo, 'remote');\n    });\n\n    test('should return cache if remote fetch exceed timeout', async () => {\n      // fetch() returns in 1.5s\n      const fetch = jest.spyOn(client, 'fetch');\n      const sendCallback = jest.spyOn(client, 'sendCallback');\n      const remoteConfigInfo = {\n        remoteConfig: { a: { b: 1 } },\n        lastFetch: new Date(),\n      };\n      fetch.mockImplementation(\n        () =>\n          new Promise((resolve) => {\n            setTimeout(() => {\n              resolve(remoteConfigInfo);\n            }, 1500);\n          }),\n      );\n\n      // storage.fetchConfig() returns immediately\n      storageFetchConfig.mockReturnValueOnce(Promise.resolve(remoteConfigInfo));\n\n      const callbackInfo = {\n        id: mockUuid,\n        key: testKey,\n        deliveryMode: 'all' as DeliveryMode,\n        callback: jest.fn(),\n      };\n      await client.subscribeWaitForRemote(callbackInfo, 1000);\n\n      expect(fetch).toHaveBeenCalledTimes(1);\n      expect(loggerDebug).toHaveBeenCalledWith(\n        'Remote config client subscription wait for remote mode exceeded timeout. Try to fetch from cache.',\n      );\n      expect(storageFetchConfig).toHaveBeenCalledTimes(1);\n      expect(loggerDebug).toHaveBeenCalledWith(\n        'Remote config client subscription wait for remote mode returns a cached copy.',\n      );\n      expect(sendCallback).toHaveBeenCalledWith(callbackInfo, remoteConfigInfo, 'cache');\n    });\n\n    test('should return nil if remote fetch exceed timeout and cache is empty', async () => {\n      // fetch() returns in 1.5s\n      const fetch = jest.spyOn(client, 'fetch');\n      const sendCallback = jest.spyOn(client, 'sendCallback');\n      const remoteConfigInfo = {\n        remoteConfig: null, // cache is empty\n        lastFetch: new Date(),\n      };\n      fetch.mockImplementation(\n        () =>\n          new Promise((resolve) => {\n            setTimeout(() => {\n              resolve(remoteConfigInfo);\n            }, 1500);\n          }),\n      );\n\n      // storage.fetchConfig() returns immediately\n      storageFetchConfig.mockReturnValueOnce(Promise.resolve(remoteConfigInfo));\n\n      const callbackInfo = {\n        id: mockUuid,\n        key: testKey,\n        deliveryMode: 'all' as DeliveryMode,\n        callback: jest.fn(),\n      };\n      await client.subscribeWaitForRemote(callbackInfo, 1000);\n\n      expect(fetch).toHaveBeenCalledTimes(1);\n      expect(loggerDebug).toHaveBeenCalledWith(\n        'Remote config client subscription wait for remote mode exceeded timeout. Try to fetch from cache.',\n      );\n      expect(storageFetchConfig).toHaveBeenCalledTimes(1);\n      expect(loggerDebug).toHaveBeenCalledWith(\n        'Remote config client subscription wait for remote mode failed to fetch cache.',\n      );\n      expect(sendCallback).toHaveBeenCalledWith(callbackInfo, remoteConfigInfo, 'remote');\n    });\n  });\n\n  describe('sendCallback', () => {\n    let callback: jest.Mock;\n    let remoteConfigInfo: RemoteConfigInfo;\n\n    beforeEach(() => {\n      callback = jest.fn();\n      remoteConfigInfo = {\n        remoteConfig: {\n          a: {\n            b: {\n              c: 1,\n            },\n            d: 2,\n          },\n        },\n        lastFetch: new Date(),\n      };\n    });\n\n    test('should call callback with filtered config if key exists', () => {\n      const callbackInfo: CallbackInfo = {\n        id: mockUuid,\n        key: 'a.b',\n        deliveryMode: 'all' as DeliveryMode,\n        callback,\n      };\n\n      client.sendCallback(callbackInfo, remoteConfigInfo, 'remote');\n\n      expect(callback).toHaveBeenCalledWith(\n        { c: 1 }, // Expected filtered config\n        'remote',\n        remoteConfigInfo.lastFetch,\n      );\n      expect(callbackInfo.lastCallback).toBeDefined();\n    });\n\n    test('should call callback with filtered config with real example', () => {\n      const autocapture = {\n        sessions: true,\n        pageViews: true,\n        elementInteractions: {\n          pageUrlAllowlistRegex: [],\n          actionClickAllowlist: ['div', 'span', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'],\n          pageUrlAllowlist: ['https://www.test.com'],\n          cssSelectorAllowlist: [\n            'a',\n            'button',\n            'input',\n            'select',\n            'textarea',\n            'label',\n            'video',\n            'audio',\n            '[contenteditable=\"true\" i]',\n            '[data-amp-default-track]',\n            '.amp-default-track',\n          ],\n          dataAttributePrefix: 'data-amp-track-',\n        },\n        fileDownloads: true,\n        formInteractions: true,\n      };\n      remoteConfigInfo = {\n        remoteConfig: {\n          configs: {\n            analyticsSDK: {\n              browserSDK: {\n                autocapture: autocapture,\n              },\n            },\n          },\n        },\n        lastFetch: new Date(),\n      };\n      const callbackInfo: CallbackInfo = {\n        id: mockUuid,\n        key: 'configs.analyticsSDK.browserSDK',\n        deliveryMode: 'all' as DeliveryMode,\n        callback,\n      };\n\n      client.sendCallback(callbackInfo, remoteConfigInfo, 'remote');\n\n      expect(callback).toHaveBeenCalledWith(\n        { autocapture: autocapture }, // Expected filtered config\n        'remote',\n        remoteConfigInfo.lastFetch,\n      );\n      expect(callbackInfo.lastCallback).toBeDefined();\n    });\n\n    test('should call callback with null if key is not found', () => {\n      const callbackInfo: CallbackInfo = {\n        id: mockUuid,\n        key: 'x.y', // Non-existent key\n        deliveryMode: 'all' as DeliveryMode,\n        callback,\n      };\n\n      client.sendCallback(callbackInfo, remoteConfigInfo, 'remote');\n\n      expect(callback).toHaveBeenCalledWith(null, 'remote', remoteConfigInfo.lastFetch);\n      expect(callbackInfo.lastCallback).toBeDefined();\n    });\n\n    test('should call callback with full config if key is empty', () => {\n      const callbackInfo: CallbackInfo = {\n        id: mockUuid,\n        key: '',\n        deliveryMode: 'all' as DeliveryMode,\n        callback,\n      };\n\n      client.sendCallback(callbackInfo, remoteConfigInfo, 'remote');\n\n      expect(callback).toHaveBeenCalledWith(remoteConfigInfo.remoteConfig, 'remote', remoteConfigInfo.lastFetch);\n      expect(callbackInfo.lastCallback).toBeDefined();\n    });\n\n    test('should call callback with full config if key is undefined', () => {\n      const callbackInfo: CallbackInfo = {\n        id: mockUuid,\n        key: undefined,\n        deliveryMode: 'all' as DeliveryMode,\n        callback,\n      };\n\n      client.sendCallback(callbackInfo, remoteConfigInfo, 'remote');\n\n      expect(callback).toHaveBeenCalledWith(remoteConfigInfo.remoteConfig, 'remote', remoteConfigInfo.lastFetch);\n      expect(callbackInfo.lastCallback).toBeDefined();\n    });\n  });\n\n  describe('fetch', () => {\n    test('should return successful response when fetch succeeds', async () => {\n      const mockResponse = {\n        remoteConfig: { key: 'value' },\n        lastFetch: new Date(),\n      };\n      global.fetch = jest.fn(() =>\n        Promise.resolve({\n          ok: true,\n          json: () => Promise.resolve(mockResponse.remoteConfig),\n        } as Response),\n      );\n\n      const result = await client.fetch();\n\n      expect(result.remoteConfig).toEqual(mockResponse.remoteConfig);\n      expect(result.lastFetch).toBeInstanceOf(Date);\n    });\n\n    test('should retry and succeed when the first attempt fails', async () => {\n      const mockResponse = {\n        remoteConfig: { key: 'value' },\n        lastFetch: new Date(),\n      };\n\n      global.fetch = jest\n        .fn()\n        .mockResolvedValueOnce({\n          ok: false,\n          status: 500,\n          text: () => Promise.resolve('Server error'),\n        } as Response)\n        .mockResolvedValueOnce({\n          ok: true,\n          json: () => Promise.resolve(mockResponse.remoteConfig),\n        } as Response);\n\n      const result = await client.fetch(2);\n\n      expect(result.remoteConfig).toEqual(mockResponse.remoteConfig);\n      expect(result.lastFetch).toBeInstanceOf(Date);\n      expect(loggerDebug).toHaveBeenCalledWith(expect.stringContaining('failed with 500'));\n    });\n\n    test('should not retry on bad request response', async () => {\n      global.fetch = jest.fn(() =>\n        Promise.resolve({\n          ok: false,\n          status: 400,\n          text: () => Promise.resolve('Bad Request'),\n        } as Response),\n      );\n\n      const result = await client.fetch(3);\n      expect(result.remoteConfig).toBeNull();\n      expect(result.lastFetch).toBeInstanceOf(Date);\n      expect(global.fetch).toHaveBeenCalledTimes(1);\n      expect(loggerDebug).toHaveBeenCalledTimes(1);\n      expect(loggerDebug).toHaveBeenCalledWith(expect.stringContaining('failed with 400'));\n    });\n\n    test('should not retry on invalid API key response', async () => {\n      global.fetch = jest.fn(() =>\n        Promise.resolve({\n          ok: false,\n          status: 401,\n          text: () => Promise.resolve('Invalid API key'),\n        } as Response),\n      );\n\n      const result = await client.fetch(3);\n      expect(result.remoteConfig).toBeNull();\n      expect(result.lastFetch).toBeInstanceOf(Date);\n      expect(global.fetch).toHaveBeenCalledTimes(1);\n      expect(client.isLastFetchInvalidApiKey).toBe(true);\n      expect(loggerDebug).toHaveBeenCalledTimes(1);\n      expect(loggerDebug).toHaveBeenCalledWith(expect.stringContaining('failed with 401'));\n      expect(loggerError).toHaveBeenCalledTimes(1);\n      expect(loggerError).toHaveBeenCalledWith(\n        expect.stringContaining('Remote config client fetch failed with 401. Invalid API key'),\n      );\n    });\n\n    test('should not retry on forbidden (403) response and treat as invalid API key', async () => {\n      global.fetch = jest.fn(() =>\n        Promise.resolve({\n          ok: false,\n          status: 403,\n          text: () => Promise.resolve('Forbidden'),\n        } as Response),\n      );\n\n      const result = await client.fetch(3);\n      expect(result.remoteConfig).toBeNull();\n      expect(result.lastFetch).toBeInstanceOf(Date);\n      expect(global.fetch).toHaveBeenCalledTimes(1);\n      expect(client.isLastFetchInvalidApiKey).toBe(true);\n      expect(loggerDebug).toHaveBeenCalledTimes(1);\n      expect(loggerDebug).toHaveBeenCalledWith(expect.stringContaining('failed with 403'));\n      expect(loggerError).toHaveBeenCalledTimes(1);\n      expect(loggerError).toHaveBeenCalledWith(\n        expect.stringContaining('Remote config client fetch failed with 403. Invalid API key'),\n      );\n    });\n\n    test('should skip future fetches after a 403 response', async () => {\n      global.fetch = jest.fn(() =>\n        Promise.resolve({\n          ok: false,\n          status: 403,\n          text: () => Promise.resolve('Forbidden'),\n        } as Response),\n      );\n\n      // First call triggers the 403\n      await client.getOrCreateFetchPromise();\n      expect(global.fetch).toHaveBeenCalledTimes(1);\n      expect(client.isLastFetchInvalidApiKey).toBe(true);\n\n      jest.clearAllMocks();\n\n      // Subsequent call should be skipped entirely\n      const result = await client.getOrCreateFetchPromise();\n      expect(global.fetch).not.toHaveBeenCalled();\n      expect(result.remoteConfig).toBeNull();\n      expect(loggerDebug).toHaveBeenCalledWith('Remote config client skipping fetch: Invalid API key');\n    });\n\n    test('should retry on rate limit and recover', async () => {\n      global.fetch = jest\n        .fn()\n        .mockResolvedValueOnce({\n          ok: false,\n          status: 429,\n          text: () => Promise.resolve('Rate Limited'),\n        } as Response)\n        .mockResolvedValueOnce({\n          ok: true,\n          json: () => Promise.resolve({ key: 'value' }),\n        } as Response);\n\n      const result = await client.fetch(3);\n      expect(result.remoteConfig).toEqual({ key: 'value' });\n      expect(result.lastFetch).toBeInstanceOf(Date);\n      expect(global.fetch).toHaveBeenCalledTimes(2);\n      expect(loggerDebug).toHaveBeenCalledWith(expect.stringContaining('failed with 429'));\n    });\n\n    test('should retry and fail after maximum retries', async () => {\n      global.fetch = jest.fn(() =>\n        Promise.resolve({\n          ok: false,\n          status: 500,\n          text: () => Promise.resolve('Server error'),\n        } as Response),\n      );\n\n      const result = await client.fetch(2);\n      expect(result.remoteConfig).toBeNull();\n      expect(result.lastFetch).toBeInstanceOf(Date);\n      expect(loggerDebug).toHaveBeenCalledTimes(2);\n      expect(loggerDebug).toHaveBeenCalledWith(expect.stringContaining('failed with 500'));\n    });\n\n    test('should handle network errors and retry', async () => {\n      global.fetch = jest\n        .fn()\n        .mockRejectedValueOnce(new Error('Network Error'))\n        .mockResolvedValueOnce({\n          ok: true,\n          json: () => Promise.resolve({ key: 'value' }),\n        } as Response);\n\n      const result = await client.fetch(2);\n      expect(result.remoteConfig).toEqual({ key: 'value' });\n      expect(result.lastFetch).toBeInstanceOf(Date);\n      expect(loggerDebug).toHaveBeenCalledWith(expect.stringContaining('is rejected because:'), expect.any(Error));\n    });\n\n    test('should retry and fail after max retries on network error', async () => {\n      global.fetch = jest.fn(() => Promise.reject(new Error('Network Error')));\n\n      const result = await client.fetch(2);\n      expect(result.remoteConfig).toBeNull();\n      expect(result.lastFetch).toBeInstanceOf(Date);\n      expect(loggerDebug).toHaveBeenCalledTimes(2);\n      expect(loggerDebug).toHaveBeenCalledWith(expect.stringContaining('is rejected because:'), expect.any(Error));\n    });\n\n    test('should retry on invalid JSON and eventually fail', async () => {\n      global.fetch = jest.fn(() =>\n        Promise.resolve({\n          ok: true,\n          json: () => Promise.reject(new SyntaxError('Invalid JSON')),\n        } as Response),\n      );\n\n      const result = await client.fetch(3);\n      expect(result.remoteConfig).toBeNull();\n      expect(result.lastFetch).toBeInstanceOf(Date);\n      expect(loggerDebug).toHaveBeenCalledTimes(3);\n      expect(loggerDebug).toHaveBeenCalledWith(\n        expect.stringContaining('is rejected because:'),\n        expect.any(SyntaxError),\n      );\n    });\n\n    test('should handle request timeout with AbortController', async () => {\n      // Mock a fetch that respects the AbortController signal\n      global.fetch = jest.fn((_url: string | URL | Request, options?: RequestInit) => {\n        return new Promise<Response>((resolve, reject) => {\n          const timeoutId = setTimeout(() => {\n            resolve({\n              ok: true,\n              json: () => Promise.resolve({ key: 'value' }),\n            } as Response);\n          }, 1500); // Takes 1.5 seconds\n\n          // Listen for abort signal\n          if (options?.signal) {\n            const abortHandler = () => {\n              clearTimeout(timeoutId);\n              const error = new Error('The operation was aborted');\n              error.name = 'AbortError';\n              reject(error);\n            };\n\n            if (options.signal.aborted) {\n              abortHandler();\n            } else {\n              options.signal.addEventListener('abort', abortHandler);\n            }\n          }\n        });\n      });\n\n      const result = await client.fetch(2);\n      expect(result.remoteConfig).toBeNull();\n      expect(loggerDebug).toHaveBeenCalledWith(expect.stringContaining('timed out after 1000ms'));\n    });\n\n    test('should clear timeout when request completes successfully', async () => {\n      const clearTimeoutSpy = jest.spyOn(global, 'clearTimeout');\n\n      global.fetch = jest.fn((_url: string | URL | Request, _options?: RequestInit) => {\n        return Promise.resolve({\n          ok: true,\n          json: () => Promise.resolve({ key: 'value' }),\n        } as Response);\n      });\n\n      const result = await client.fetch(1);\n      expect(result.remoteConfig).toEqual({ key: 'value' });\n      expect(clearTimeoutSpy).toHaveBeenCalled();\n\n      clearTimeoutSpy.mockRestore();\n    });\n  });\n\n  describe('getUrlParams', () => {\n    test('should generate correct US URL', () => {\n      const expectedUrl = `https://sr-client-cfg.amplitude.com/config/test-api-key?config_group=browser`;\n      const url = client.getUrlParams();\n      expect(url).toBe(expectedUrl);\n    });\n\n    test('should generate correct EU URL', () => {\n      client = new RemoteConfigClient(mockApiKey, mockLogger, 'EU');\n      const expectedUrl = `https://sr-client-cfg.eu.amplitude.com/config/test-api-key?config_group=browser`;\n      const url = client.getUrlParams();\n      expect(url).toBe(expectedUrl);\n    });\n\n    test('should generate URL with custom server URL', () => {\n      const customServerUrl = 'https://my-proxy.example.com/remote-config';\n      client = new RemoteConfigClient(mockApiKey, mockLogger, 'US', customServerUrl);\n      const expectedUrl = `https://my-proxy.example.com/remote-config/test-api-key?config_group=browser`;\n      const url = client.getUrlParams();\n      expect(url).toBe(expectedUrl);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/revenue.test.ts",
    "content": "import { createRevenueEvent } from '../src/utils/event-builder';\nimport { Revenue, RevenueProperty } from '../src/revenue';\n\nconst defaultRevenueProperty = {\n  [RevenueProperty.REVENUE_PRODUCT_ID]: '',\n  [RevenueProperty.REVENUE_QUANTITY]: 1,\n  [RevenueProperty.REVENUE_PRICE]: 0,\n};\ndescribe('Revenue class', () => {\n  test('setProjectId', () => {\n    const productId = 'testProductId';\n    const revenue = new Revenue();\n    revenue.setProductId(productId);\n    const event = createRevenueEvent(revenue);\n\n    const expectedProperties = { ...defaultRevenueProperty, [RevenueProperty.REVENUE_PRODUCT_ID]: productId };\n\n    expect(event.event_properties).toEqual(expectedProperties);\n  });\n\n  test('Set invalid quantity', () => {\n    const invalidQuantity = -1;\n    const revenue = new Revenue();\n    revenue.setQuantity(invalidQuantity);\n    const event = createRevenueEvent(revenue);\n\n    const expectedProperties = { ...defaultRevenueProperty, [RevenueProperty.REVENUE_QUANTITY]: 1 };\n\n    expect(event.event_properties).toEqual(expectedProperties);\n  });\n\n  test('Set valid quantity', () => {\n    const validQuantity = 10;\n    const revenue = new Revenue();\n    revenue.setQuantity(validQuantity);\n    const event = createRevenueEvent(revenue);\n\n    const expectedProperties = { ...defaultRevenueProperty, [RevenueProperty.REVENUE_QUANTITY]: validQuantity };\n\n    expect(event.event_properties).toEqual(expectedProperties);\n  });\n\n  test('setPrice', () => {\n    const price = 10;\n    const revenue = new Revenue();\n    revenue.setPrice(price);\n    const event = createRevenueEvent(revenue);\n\n    const expectedProperties = {\n      ...defaultRevenueProperty,\n      [RevenueProperty.REVENUE_PRICE]: price,\n    };\n\n    expect(event.event_properties).toEqual(expectedProperties);\n  });\n\n  test('setRevenueType', () => {\n    const revenueType = 'testRevenueType';\n    const revenue = new Revenue();\n    revenue.setRevenueType(revenueType);\n    revenue.setCurrency('USD');\n    const event = createRevenueEvent(revenue);\n\n    const expectedProperties = {\n      ...defaultRevenueProperty,\n      [RevenueProperty.REVENUE_TYPE]: revenueType,\n      [RevenueProperty.REVENUE_CURRENCY]: 'USD',\n    };\n\n    expect(event.event_properties).toEqual(expectedProperties);\n  });\n\n  test('setRevenue', () => {\n    const revenueAmount = 100;\n    const revenue = new Revenue();\n    revenue.setRevenue(revenueAmount);\n    const event = createRevenueEvent(revenue);\n\n    const expectedProperties = { ...defaultRevenueProperty, [RevenueProperty.REVENUE]: revenueAmount };\n\n    expect(event.event_properties).toEqual(expectedProperties);\n  });\n\n  test('setReceipt', () => {\n    const receipt = 'test receipt';\n    const revenue = new Revenue();\n    revenue.setReceipt(receipt);\n    const event = createRevenueEvent(revenue);\n\n    const expectedProperties = { ...defaultRevenueProperty, [RevenueProperty.RECEIPT]: receipt };\n\n    expect(event.event_properties).toEqual(expectedProperties);\n  });\n\n  test('setReceiptSig', () => {\n    const receiptSig = 'test receiptSig';\n    const revenue = new Revenue();\n    revenue.setReceiptSig(receiptSig);\n    const event = createRevenueEvent(revenue);\n\n    const expectedProperties = { ...defaultRevenueProperty, [RevenueProperty.RECEIPT_SIG]: receiptSig };\n    expect(event.event_properties).toEqual(expectedProperties);\n  });\n\n  test('setEventProperties', () => {\n    const property = { testStringKey: 'string value', testBooleanKey: true };\n    const revenue = new Revenue();\n    revenue.setEventProperties(property);\n    const event = createRevenueEvent(revenue);\n\n    const expectedProperties = { ...defaultRevenueProperty, ...property };\n\n    expect(event.event_properties).toEqual(expectedProperties);\n  });\n\n  test('setEventProperties filters out undefined properties instead of rejecting the whole object', () => {\n    const property = { validKey: 'valid value', invalidKey: undefined as any };\n    const revenue = new Revenue();\n    revenue.setEventProperties(property);\n    const event = createRevenueEvent(revenue);\n\n    const expectedProperties = { ...defaultRevenueProperty, validKey: 'valid value' };\n\n    expect(event.event_properties).toEqual(expectedProperties);\n  });\n\n  test('setEventProperties ignores properties with circular references', () => {\n    const property: { [key: string]: any } = { validKey: 'valid value' };\n    property.circular = property;\n    const revenue = new Revenue();\n    revenue.setEventProperties(property);\n    const event = createRevenueEvent(revenue);\n\n    expect(event.event_properties).toEqual(defaultRevenueProperty);\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/session.test.ts",
    "content": "import { isNewSession } from '../src/session';\n\ndescribe('session', () => {\n  const sessionTimeout: number = 30 * 60 * 1000;\n\n  test('should be in a same session for undefined lastEventTime', () => {\n    const isEventInNewSession = isNewSession(sessionTimeout, undefined);\n\n    expect(isEventInNewSession).toBe(false);\n  });\n\n  test('should be a new session', () => {\n    const lastEventTime = Date.now() - sessionTimeout * 2;\n    const isEventInNewSession = isNewSession(sessionTimeout, lastEventTime);\n\n    expect(isEventInNewSession).toBe(true);\n  });\n\n  test('should be in a same session', () => {\n    const lastEventTime = Date.now();\n    const isEventInNewSession = isNewSession(sessionTimeout, lastEventTime);\n\n    expect(isEventInNewSession).toBe(false);\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/setup.js",
    "content": "jest.mock('../src/logger');\n"
  },
  {
    "path": "packages/analytics-core/test/storage/browser-storage.test.ts",
    "content": "/**\n * @jest-environment jsdom\n */\n\nimport { getGlobalScope, BrowserStorage } from '../../src/index';\nimport * as AnalyticsCore from '../../src/index';\n\ndescribe('browser-storage', () => {\n  describe('isEnabled', () => {\n    test('should return true', async () => {\n      const sessionStorage = new BrowserStorage(getGlobalScope()?.sessionStorage);\n      expect(await sessionStorage.isEnabled()).toBe(true);\n    });\n  });\n\n  describe('get', () => {\n    test('should return undefined if not set', async () => {\n      const sessionStorage = new BrowserStorage(getGlobalScope()?.sessionStorage);\n      expect(await sessionStorage.get('1')).toBe(undefined);\n    });\n\n    test('should return undefined if invalid json is stored at key', async () => {\n      const storage = getGlobalScope()?.sessionStorage;\n      const sessionStorage = new BrowserStorage<number[]>(storage);\n      storage?.setItem('1', 'not a json string');\n      expect(await sessionStorage.get('1')).toEqual(undefined);\n    });\n\n    test('should return object', async () => {\n      const sessionStorage = new BrowserStorage<Record<string, number>>(getGlobalScope()?.sessionStorage);\n      await sessionStorage.set('1', { a: 1 });\n      expect(await sessionStorage.get('1')).toEqual({ a: 1 });\n    });\n\n    test('should return array', async () => {\n      const sessionStorage = new BrowserStorage<number[]>(getGlobalScope()?.sessionStorage);\n      await sessionStorage.set('1', [1]);\n      expect(await sessionStorage.get('1')).toEqual([1]);\n    });\n  });\n\n  describe('set', () => {\n    test('should set value', async () => {\n      const sessionStorage = new BrowserStorage(getGlobalScope()?.sessionStorage);\n      await sessionStorage.set('1', 'a');\n      expect(await sessionStorage.get('1')).toBe('a');\n    });\n  });\n\n  describe('remove', () => {\n    test('should remove value of key', async () => {\n      const sessionStorage = new BrowserStorage(getGlobalScope()?.sessionStorage);\n      await sessionStorage.set('1', 'a');\n      await sessionStorage.set('2', 'b');\n      expect(await sessionStorage.get('1')).toBe('a');\n      expect(await sessionStorage.get('2')).toBe('b');\n      await sessionStorage.remove('1');\n      expect(await sessionStorage.get('1')).toBe(undefined);\n      expect(await sessionStorage.get('2')).toBe('b');\n    });\n\n    test('should handle when GlobalScope is not defined', async () => {\n      const sessionStorage = new BrowserStorage<number[]>(undefined);\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue(undefined);\n      await sessionStorage.set('1', [1]);\n      expect(await sessionStorage.get('1')).toEqual(undefined);\n      await sessionStorage.remove('1');\n    });\n  });\n\n  describe('reset', () => {\n    test('should remove all values', async () => {\n      const sessionStorage = new BrowserStorage(getGlobalScope()?.sessionStorage);\n      await sessionStorage.set('1', 'a');\n      await sessionStorage.set('2', 'b');\n      expect(await sessionStorage.get('1')).toBe('a');\n      expect(await sessionStorage.get('2')).toBe('b');\n      await sessionStorage.reset();\n      expect(await sessionStorage.get('1')).toBe(undefined);\n      expect(await sessionStorage.get('2')).toBe(undefined);\n    });\n\n    test('should handle when GlobalScope is not defined', async () => {\n      const sessionStorage = new BrowserStorage<number[]>(undefined);\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue(undefined);\n      await sessionStorage.set('1', [1]);\n      expect(await sessionStorage.get('1')).toEqual(undefined);\n      await sessionStorage.reset();\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/storage/cookies.test.ts",
    "content": "/**\n * @jest-environment jsdom\n * @jest-environment-options { \"url\": \"https://www.example.com\" }\n */\n/* eslint-disable @typescript-eslint/no-unsafe-return */\nimport { CookieStorage } from '../../src/storage/cookie';\nimport { isDomainEqual, decodeCookieValue } from '../../src/index';\nimport * as GlobalScopeModule from '../../src/global-scope';\nimport { StorageSync } from '../../src/types/storage';\nimport { enforceStrictCookieNames } from '../helpers/util';\n\ndescribe('cookies', () => {\n  let undoStrictCookieNames: () => void;\n  beforeEach(() => {\n    // Enforce strict cookie names. This is important, do not remove it.\n    undoStrictCookieNames = enforceStrictCookieNames();\n  });\n\n  afterEach(() => {\n    undoStrictCookieNames();\n  });\n\n  describe('isEnabled', () => {\n    describe('concurrent calls', () => {\n      beforeEach(() => {\n        jest.useFakeTimers();\n      });\n      afterEach(() => {\n        jest.useRealTimers();\n      });\n\n      test('regression test re-entrancy issue', async () => {\n        const c1 = new CookieStorage();\n        const c2 = new CookieStorage();\n        // calling isEnabled one after the other should not cause a re-entrancy issue\n        const p1 = c1.isEnabled();\n        jest.advanceTimersByTime(10);\n        const p2 = c2.isEnabled();\n        await Promise.all([p1, p2]);\n        expect(await p1).toBe(true);\n        expect(await p2).toBe(true);\n      });\n    });\n\n    test('should return true', async () => {\n      const cookies = new CookieStorage();\n      expect(await cookies.isEnabled()).toBe(true);\n    });\n\n    describe('when document is not available', () => {\n      let getGlobalScopeSpy: jest.SpyInstance;\n      beforeEach(() => {\n        getGlobalScopeSpy = jest.spyOn(GlobalScopeModule, 'getGlobalScope').mockReturnValue({} as typeof globalThis);\n      });\n      afterEach(() => {\n        getGlobalScopeSpy.mockRestore();\n      });\n      test('should return false', async () => {\n        const cookies = new CookieStorage();\n        expect(await cookies.isEnabled()).toBe(false);\n      });\n    });\n\n    describe('when document.cookie throws an error', () => {\n      let getGlobalScopeSpy: jest.SpyInstance;\n      beforeEach(() => {\n        getGlobalScopeSpy = jest.spyOn(GlobalScopeModule, 'getGlobalScope').mockReturnValue({} as typeof globalThis);\n        getGlobalScopeSpy.mockImplementation(() => {\n          return {\n            document: {\n              cookie: {\n                get() {\n                  throw new Error('getter error');\n                },\n                set() {\n                  throw new Error('setter error');\n                },\n              },\n            },\n          };\n        });\n      });\n      afterEach(() => {\n        getGlobalScopeSpy.mockRestore();\n      });\n\n      test('should return false', async () => {\n        const mockDiagnosticsClient = {\n          recordEvent: jest.fn(),\n          increment: jest.fn(),\n          recordHistogram: jest.fn(),\n          setTag: jest.fn(),\n          _flush: jest.fn(),\n          _setSampleRate: jest.fn(),\n        };\n        const cookies = new CookieStorage(undefined, { diagnosticsClient: mockDiagnosticsClient as any });\n        expect(await cookies.isEnabled()).toBe(false);\n        expect(mockDiagnosticsClient.recordEvent).toHaveBeenCalledTimes(1);\n      });\n    });\n\n    describe('when document.cookie returns wrong test value', () => {\n      let getGlobalScopeSpy: jest.SpyInstance;\n      beforeEach(() => {\n        getGlobalScopeSpy = jest.spyOn(GlobalScopeModule, 'getGlobalScope').mockReturnValue({} as typeof globalThis);\n        getGlobalScopeSpy.mockImplementation(() => {\n          return {\n            document: {\n              cookie: {\n                get() {\n                  return 'wrong value';\n                },\n                set() {\n                  return 'wrong value';\n                },\n              },\n            },\n          };\n        });\n      });\n      afterEach(() => {\n        getGlobalScopeSpy.mockRestore();\n      });\n      test('should return false', async () => {\n        const mockDiagnosticsClient = {\n          recordEvent: jest.fn(),\n          increment: jest.fn(),\n          recordHistogram: jest.fn(),\n          setTag: jest.fn(),\n          _flush: jest.fn(),\n          _setSampleRate: jest.fn(),\n        };\n        const cookies = new CookieStorage(undefined, { diagnosticsClient: mockDiagnosticsClient as any });\n        expect(await cookies.isEnabled()).toBe(false);\n        expect(mockDiagnosticsClient.recordEvent).toHaveBeenCalledTimes(1);\n      });\n    });\n  });\n\n  describe('get', () => {\n    beforeEach(() => {\n      undoStrictCookieNames?.();\n    });\n\n    test('should return undefined for no cookie value', async () => {\n      const cookies = new CookieStorage();\n      expect(await cookies.get('hello')).toBe(undefined);\n    });\n\n    test('should return non-encoded value', async () => {\n      const cookies = new CookieStorage();\n      document.cookie = 'hello=world';\n      expect(await cookies.get('hello')).toBe(undefined);\n      await cookies.remove('world');\n    });\n\n    test('should handle double url encoded value for Ruby Rails', async () => {\n      const cookies = new CookieStorage();\n      const value = { a: 1 };\n      const cookieValue = encodeURIComponent(btoa(encodeURIComponent(JSON.stringify(value))));\n      document.cookie = `hello=${cookieValue}`;\n      expect(await cookies.get('hello')).toEqual(value);\n      await cookies.remove('world');\n    });\n\n    test('should return cookie object value', async () => {\n      const cookies = new CookieStorage<Record<string, number>>();\n      await cookies.set('hello', { a: 1 });\n      expect(await cookies.get('hello')).toEqual({ a: 1 });\n      await cookies.remove('hello');\n    });\n\n    test('should catch non-json format value', async () => {\n      const cookies = new CookieStorage();\n      const value = '{\"a\":1';\n      const encodedValue = btoa(encodeURIComponent(value));\n      document.cookie = `hello=${encodedValue}`;\n      expect(await cookies.get('hello')).toBe(undefined);\n    });\n\n    test('should return cookie array value', async () => {\n      const cookies = new CookieStorage<number[]>();\n      await cookies.set('hello', [1]);\n      expect(await cookies.get('hello')).toEqual([1]);\n      await cookies.remove('hello');\n    });\n\n    test('should return undefined when global scope is not defined', async () => {\n      const cookies = new CookieStorage<number[]>();\n      await cookies.set('hello', [1]);\n      jest.spyOn(GlobalScopeModule, 'getGlobalScope').mockReturnValue(undefined);\n      expect(await cookies.get('hello')).toEqual(undefined);\n      await cookies.remove('hello');\n    });\n\n    test('should return undefined when global scope is defined but document is not', async () => {\n      const cookies = new CookieStorage<number[]>();\n      await cookies.set('hello', [1]);\n      jest.spyOn(GlobalScopeModule, 'getGlobalScope').mockReturnValue({} as typeof globalThis);\n      expect(await cookies.get('hello')).toEqual(undefined);\n      await cookies.remove('hello');\n    });\n  });\n\n  describe('set', () => {\n    beforeEach(() => {\n      undoStrictCookieNames?.();\n    });\n\n    test('should set cookie value', async () => {\n      const cookies = new CookieStorage();\n      await cookies.set('hello', 'world');\n      expect(await cookies.get('hello')).toBe('world');\n      await cookies.remove('hello');\n    });\n\n    test('should set cookie value with options', async () => {\n      const cookies = new CookieStorage({\n        expirationDays: 365,\n        domain: '',\n        secure: false,\n        sameSite: 'Lax',\n      });\n      await cookies.set('hello', 'world');\n      expect(await cookies.get('hello')).toBe('world');\n      await cookies.remove('hello');\n    });\n\n    test('should set restricted cookie value with options', async () => {\n      const cookies = new CookieStorage({\n        expirationDays: 365,\n        domain: '.amplitude.com',\n        secure: true,\n        sameSite: 'Lax',\n      });\n      await cookies.set('hello', 'world');\n      expect(await cookies.get('hello')).toBe(undefined);\n      await cookies.remove('hello');\n    });\n\n    test.each([new Error('Simulated error'), 'Simulated error'])(\n      'logs an error message when setting a cookie fails',\n      async (error) => {\n        console.error = jest.fn();\n        jest.spyOn(global, 'btoa').mockImplementation(() => {\n          throw error;\n        });\n\n        const cookies = new CookieStorage();\n        await cookies.set('hello', 'world');\n\n        expect(console.error).toHaveBeenCalledWith(\n          expect.stringContaining(\n            `Amplitude Logger [Error]: Failed to set cookie for key: hello. Error: Simulated error`,\n          ),\n        );\n\n        jest.restoreAllMocks();\n      },\n    );\n\n    describe('when document is not available on globalScope (like React Native)', () => {\n      let getGlobalScopeSpy: jest.SpyInstance;\n\n      beforeEach(() => {\n        document.cookie = '';\n        getGlobalScopeSpy = jest.spyOn(GlobalScopeModule, 'getGlobalScope').mockReturnValue({} as typeof globalThis);\n      });\n\n      afterEach(() => {\n        getGlobalScopeSpy.mockRestore();\n      });\n\n      test('setSync exits without error', async () => {\n        const cookies = new CookieStorage();\n        await expect(cookies.set('key', 'value')).resolves.toBeUndefined();\n        expect(document.cookie).toBe('');\n        getGlobalScopeSpy.mockRestore();\n      });\n    });\n  });\n\n  describe('remove', () => {\n    beforeEach(() => {\n      undoStrictCookieNames?.();\n    });\n\n    test('should call set', async () => {\n      const cookies = new CookieStorage();\n      const set = jest.spyOn(cookies, 'set');\n      await cookies.remove('key');\n      expect(set).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('reset', () => {\n    test('should return undefined', async () => {\n      const cookies = new CookieStorage();\n      expect(await cookies.reset()).toBe(undefined);\n    });\n  });\n  describe('duplicateResolverFn', () => {\n    let tldCookies: CookieStorage<Record<string, string>>;\n    let subdomainCookies: CookieStorage<Record<string, string>>;\n    beforeEach(() => {\n      undoStrictCookieNames?.();\n      tldCookies = new CookieStorage<Record<string, string>>(\n        {\n          domain: 'example.com',\n        },\n        {\n          duplicateResolverFn: (value: string) => {\n            const decodedValue = decodeURIComponent(atob(value));\n            const parsedValue = JSON.parse(decodedValue);\n            if (parsedValue.a === 'keep') {\n              return true;\n            }\n            return false;\n          },\n        },\n      );\n      subdomainCookies = new CookieStorage<Record<string, string>>({\n        domain: 'www.example.com',\n      });\n    });\n    test('should de-duplicate cookies', async () => {\n      await tldCookies.set('dummy', { a: 'ignore' });\n\n      // set 2 conflicting cookies on example.com and www.example.com\n      await tldCookies.set('hello', { a: 'ignore' });\n      await subdomainCookies.set('hello', { a: 'keep' });\n\n      // should resolve to the cookie that\n      expect(await tldCookies.get('hello')).toEqual({ a: 'keep' });\n      await tldCookies.remove('hello');\n    });\n\n    test('should record diagnostics when duplicateResolverFn returns false', async () => {\n      const diagnosticsClient = {\n        recordEvent: jest.fn(),\n        increment: jest.fn(),\n      };\n      const cookieStorageWithDiagnostics = new CookieStorage<Record<string, string>>(\n        {\n          domain: 'example.com',\n        },\n        {\n          duplicateResolverFn: (value: string) => {\n            const decodedValue = decodeURIComponent(atob(value));\n            const parsedValue = JSON.parse(decodedValue);\n            // Return false for \"ignore\", true for \"keep\"\n            return parsedValue.a === 'keep';\n          },\n          diagnosticsClient: diagnosticsClient as any,\n        },\n      );\n\n      // Set up duplicate cookies - one to ignore, one to keep\n      await tldCookies.set('test', { a: 'ignore' });\n      await subdomainCookies.set('test', { a: 'keep' });\n\n      await cookieStorageWithDiagnostics.get('test');\n\n      expect(diagnosticsClient.increment).toHaveBeenCalledWith('cookies.duplicate.occurrence.document.cookie');\n      await tldCookies.remove('test');\n    });\n  });\n\n  describe('cookieStore', () => {\n    let cookieStorage: CookieStorage<string>;\n    let globalScope: any;\n    beforeEach(() => {\n      cookieStorage = new CookieStorage({\n        domain: 'domain.com',\n      });\n      globalScope = GlobalScopeModule.getGlobalScope() || {};\n      const cookies: any = {};\n\n      // setting up cookieStore mock because JSDom doesn't support cookieStore\n      globalScope.cookieStore = {\n        set({ name, value, domain }: any) {\n          cookies[domain] = cookies[domain] || {};\n          cookies[domain][name] = value;\n        },\n        getAll(key: string) {\n          const output: any[] = [];\n          for (const domain of Object.keys(cookies)) {\n            output.push({\n              key,\n              value: cookies[domain][key],\n              domain,\n            });\n          }\n          return output;\n        },\n      };\n    });\n\n    afterAll(() => {\n      delete globalScope.cookieStore;\n    });\n\n    test('should read from cookieStore', async () => {\n      const value = {\n        hello: 'world!',\n      };\n      await globalScope.cookieStore.set({\n        name: 'hello',\n        value: btoa(encodeURIComponent(JSON.stringify(value))),\n        domain: 'domain.com',\n      });\n      expect(await cookieStorage.get('hello')).toEqual({ hello: 'world!' });\n    });\n\n    test('should record diagnostics when duplicate cookies are detected', async () => {\n      const diagnosticsClient = {\n        recordEvent: jest.fn(),\n        increment: jest.fn(),\n      };\n      const cookieStorageWithDiagnostics = new CookieStorage<string>(\n        {\n          domain: 'domain.com',\n        },\n        {\n          diagnosticsClient: diagnosticsClient as any,\n        },\n      );\n\n      // Mock cookieStore to return multiple cookies\n      globalScope.cookieStore.getAll = jest.fn().mockResolvedValue([\n        { name: 'hello', value: btoa(encodeURIComponent(JSON.stringify('value1'))), domain: 'domain.com' },\n        { name: 'hello', value: btoa(encodeURIComponent(JSON.stringify('value2'))), domain: 'other.com' },\n      ]);\n\n      await cookieStorageWithDiagnostics.get('hello');\n\n      expect(diagnosticsClient.recordEvent).toHaveBeenCalledWith('cookies.duplicate', {\n        cookies: ['domain.com', 'other.com'],\n      });\n      expect(diagnosticsClient.increment).toHaveBeenCalledWith('cookies.duplicate.occurrence.cookieStore');\n    });\n  });\n\n  describe('isDomainEqual', () => {\n    test('should return true if domains are equal disregard leading .', () => {\n      expect(isDomainEqual('.domain.com', 'domain.com')).toBe(true);\n      expect(isDomainEqual('domain.com', '.domain.com')).toBe(true);\n    });\n\n    it('should return false if either domain is undefined', () => {\n      expect(isDomainEqual(undefined, 'domain.com')).toBe(false);\n      expect(isDomainEqual('domain.com', undefined)).toBe(false);\n      expect(isDomainEqual(undefined, undefined)).toBe(false);\n    });\n\n    it('should return false if domains are not equal', () => {\n      expect(isDomainEqual('domain.com', 'www.domain.com')).toBe(false);\n      expect(isDomainEqual('www.domain.com', 'domain.com')).toBe(false);\n    });\n\n    describe('empty values and empty strings', () => {\n      test('should return true when both domains are empty strings', () => {\n        expect(isDomainEqual('', '')).toBe(true);\n      });\n      test('should return false if one domain is empty string and other is falsey', () => {\n        expect(isDomainEqual('', undefined)).toBe(false);\n        expect(isDomainEqual(undefined, '')).toBe(false);\n      });\n    });\n  });\n\n  describe('decodeCookieValue', () => {\n    test('should decode standard encoded cookie value', () => {\n      const value = { hello: 'world' };\n      const encoded = btoa(encodeURIComponent(JSON.stringify(value)));\n      expect(decodeCookieValue(encoded)).toBe(JSON.stringify(value));\n    });\n\n    test('should decode double URL encoded cookie value (Ruby Rails)', () => {\n      const value = { hello: 'world' };\n      const encoded = encodeURIComponent(btoa(encodeURIComponent(JSON.stringify(value))));\n      expect(decodeCookieValue(encoded)).toBe(JSON.stringify(value));\n    });\n\n    test('should return undefined for invalid encoded value', () => {\n      expect(decodeCookieValue('not-valid-base64!')).toBe(undefined);\n    });\n  });\n\n  describe('isDomainWritable', () => {\n    beforeEach(() => {\n      (CookieStorage as any).cachedTlds = {};\n    });\n\n    test('should return true when domain is writable', async () => {\n      // jest env is https://www.example.com, so example.com should be writable\n      const result = await CookieStorage.isDomainWritable('example.com');\n      expect(result).toBe(true);\n      // call it again to cover the cachedTlds check\n      const result2 = await CookieStorage.isDomainWritable('example.com');\n      expect(result2).toBe(true);\n    });\n\n    test('should return true from inner cachedTlds check when a concurrent call already cached the domain', async () => {\n      const lockQueue: Array<() => Promise<unknown>> = [];\n      const processQueue = (): void => {\n        if (lockQueue.length === 0) return;\n        const run = lockQueue.shift();\n        if (!run) return;\n        void run().then(processQueue, processQueue);\n      };\n      const locks = {\n        request: (_lockName: string, callback: () => unknown) => {\n          const promise = new Promise<unknown>((resolve, reject) => {\n            lockQueue.push(() =>\n              Promise.resolve()\n                .then(() => callback())\n                .then(resolve, reject),\n            );\n            if (lockQueue.length === 1) {\n              void Promise.resolve().then(processQueue);\n            }\n          });\n          return promise;\n        },\n      };\n      const nav = global.navigator;\n      Object.defineProperty(global, 'navigator', { value: { ...nav, locks }, configurable: true });\n      try {\n        const [result1, result2] = await Promise.all([\n          CookieStorage.isDomainWritable('example.com'),\n          CookieStorage.isDomainWritable('example.com'),\n        ]);\n        expect(result1).toBe(true);\n        expect(result2).toBe(true);\n      } finally {\n        Object.defineProperty(global, 'navigator', { value: nav, configurable: true });\n      }\n    });\n\n    test('should return false when document is not available', async () => {\n      const getGlobalScopeSpy = jest\n        .spyOn(GlobalScopeModule, 'getGlobalScope')\n        .mockReturnValue({} as typeof globalThis);\n      const result = await CookieStorage.isDomainWritable('example.com');\n      getGlobalScopeSpy.mockRestore();\n      expect(result).toBe(false);\n    });\n\n    test('should return false for non-writable domain', async () => {\n      // .amplitude.com is not writable from www.example.com\n      const result = await CookieStorage.isDomainWritable('amplitude.com');\n      expect(result).toBe(false);\n    });\n\n    test('should return false if cookie transactions throws error', async () => {\n      const getGlobalScopeSpy = jest\n        .spyOn(GlobalScopeModule, 'getGlobalScope')\n        .mockReturnValue({} as typeof globalThis);\n      jest.spyOn(CookieStorage.prototype as any, 'transaction').mockImplementation(() => {\n        throw new Error('getter error');\n      });\n      const result = await CookieStorage.isDomainWritable('example.com');\n      getGlobalScopeSpy.mockRestore();\n      expect(result).toBe(false);\n    });\n  });\n\n  describe('transaction', () => {\n    beforeEach(() => {\n      undoStrictCookieNames?.();\n    });\n\n    test('should return the result of the callback', async () => {\n      const cookies = new CookieStorage<string>();\n      const result = await (cookies as any).transaction('test', (storageSync: StorageSync<string>) => {\n        storageSync.set('TEST_VALUE_NO_LOCK');\n        return storageSync.get();\n      });\n      expect(result).toBe('TEST_VALUE_NO_LOCK');\n      expect(await cookies.get('test')).toBe('TEST_VALUE_NO_LOCK');\n    });\n\n    describe('with mock navigator.locks', () => {\n      let lockCallList: string[] = [];\n\n      beforeEach(() => {\n        Object.defineProperty(global, 'navigator', {\n          value: {\n            locks: {\n              request: (lockName: string, callback: () => Promise<any>) => {\n                lockCallList.push(lockName);\n                return callback();\n              },\n            },\n          },\n        });\n      });\n      afterEach(() => {\n        lockCallList = [];\n        Object.defineProperty(global, 'navigator', {\n          value: {\n            locks: undefined,\n          },\n        });\n      });\n      test('should return the result of the callback', async () => {\n        const cookies = new CookieStorage<string>();\n        const result = await (cookies as any).transaction('test', (storageSync: StorageSync<string>) => {\n          storageSync.set('TEST_VALUE_WITH_LOCK');\n          return storageSync.get();\n        });\n        expect(result).toBe('TEST_VALUE_WITH_LOCK');\n        expect(await cookies.get('test')).toBe('TEST_VALUE_WITH_LOCK');\n        await cookies.remove('test');\n        expect(lockCallList).toEqual(['com.amplitude:cookie-lock:test']);\n      });\n\n      test('should fall back to callback when locks.request throws', async () => {\n        Object.defineProperty(global, 'navigator', {\n          value: {\n            locks: {\n              request: () => {\n                throw new Error('security error');\n              },\n            },\n          },\n          configurable: true,\n        });\n        const cookies = new CookieStorage<string>();\n        const result = await (cookies as any).transaction('test', (storageSync: StorageSync<string>) => {\n          storageSync.set('VALUE');\n          return storageSync.get();\n        });\n        expect(result).toBe('VALUE');\n        expect(await cookies.get('test')).toBe('VALUE');\n      });\n\n      test('should handle promise rejection from locks.request', async () => {\n        Object.defineProperty(global, 'navigator', {\n          value: {\n            locks: {\n              // Simulate an async locks.request where the callback throws,\n              // causing the returned promise to be rejected.\n              request: (_lockName: string, callback: () => any) => {\n                return Promise.resolve().then(() => callback());\n              },\n            },\n          },\n          configurable: true,\n        });\n\n        const cookies = new CookieStorage<string>();\n        const transactionPromise = (cookies as any).transaction('test', (storageSync: StorageSync<string>) => {\n          storageSync.set('VALUE_REJECTED_LOCK');\n          throw new Error('callback error');\n        });\n\n        await expect(transactionPromise).rejects.toThrow('callback error');\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/storage/helpers.test.ts",
    "content": "import { getStorageKey } from '../../src/storage/helpers';\n\ndescribe('getStorageKey', () => {\n  test('should return storage key without explicit suffix and limit', () => {\n    expect(getStorageKey('API_KEY')).toBe('AMP_API_KEY');\n  });\n\n  test('should return storage key', () => {\n    expect(getStorageKey('API_KEY', 'MKTG', 3)).toBe('AMP_MKTG_API');\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/storage/memory.test.ts",
    "content": "import { MemoryStorage } from '../../src/storage/memory';\n\ndescribe('memory', () => {\n  describe('isEnabled', () => {\n    test('should return true', async () => {\n      const memoryStorage = new MemoryStorage();\n      expect(await memoryStorage.isEnabled()).toBe(true);\n    });\n  });\n\n  describe('get', () => {\n    test('should return null if not set', async () => {\n      const memoryStorage = new MemoryStorage();\n      expect(await memoryStorage.get('1')).toBe(undefined);\n    });\n\n    test('should return value', async () => {\n      const memoryStorage = new MemoryStorage();\n      await memoryStorage.set('1', 'a');\n      expect(await memoryStorage.get('1')).toBe('a');\n    });\n  });\n\n  describe('getRaw', () => {\n    test('should return null if not set', async () => {\n      const memoryStorage = new MemoryStorage();\n      expect(await memoryStorage.getRaw('1')).toBe(undefined);\n    });\n\n    test('should return value', async () => {\n      const memoryStorage = new MemoryStorage();\n      await memoryStorage.set('1', 'a');\n      expect(await memoryStorage.getRaw('1')).toBe('\"a\"');\n    });\n  });\n\n  describe('set', () => {\n    test('should set value', async () => {\n      const memoryStorage = new MemoryStorage();\n      await memoryStorage.set('1', 'a');\n      expect(await memoryStorage.get('1')).toBe('a');\n    });\n  });\n\n  describe('remove', () => {\n    test('should remove value of key', async () => {\n      const memoryStorage = new MemoryStorage();\n      await memoryStorage.set('1', 'a');\n      await memoryStorage.set('2', 'b');\n      expect(await memoryStorage.get('1')).toBe('a');\n      expect(await memoryStorage.get('2')).toBe('b');\n      await memoryStorage.remove('1');\n      expect(await memoryStorage.get('1')).toBe(undefined);\n      expect(await memoryStorage.get('2')).toBe('b');\n    });\n  });\n\n  describe('reset', () => {\n    test('should remove all values', async () => {\n      const memoryStorage = new MemoryStorage();\n      await memoryStorage.set('1', 'a');\n      await memoryStorage.set('2', 'b');\n      expect(await memoryStorage.get('1')).toBe('a');\n      expect(await memoryStorage.get('2')).toBe('b');\n      await memoryStorage.reset();\n      expect(await memoryStorage.get('1')).toBe(undefined);\n      expect(await memoryStorage.get('2')).toBe(undefined);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/timeline.test.ts",
    "content": "import { Timeline } from '../src/timeline';\nimport { DestinationPlugin, EnrichmentPlugin, Plugin } from '../src/types/plugin';\nimport { Event } from '../src/types/event/event';\nimport { useDefaultConfig, promiseState } from './helpers/default';\nimport { createTrackEvent } from '../src/utils/event-builder';\nimport { AmplitudeCore } from '../src/core-client';\n\ndescribe('timeline', () => {\n  let timeline = new Timeline(new AmplitudeCore());\n  const mockLoggerProvider = {\n    error: jest.fn(),\n    log: jest.fn(),\n    disable: jest.fn(),\n    enable: jest.fn(),\n    warn: jest.fn(),\n    debug: jest.fn(),\n  };\n  timeline.loggerProvider = mockLoggerProvider;\n  const config = useDefaultConfig();\n\n  beforeEach(() => {\n    timeline = new Timeline(new AmplitudeCore());\n    timeline.loggerProvider = mockLoggerProvider;\n    jest.clearAllMocks();\n  });\n\n  describe('register', () => {\n    test('should accept empty plugin', async () => {\n      await timeline.register({}, config);\n      expect(timeline.plugins[0].name).toBeDefined();\n      expect(timeline.plugins[0].type).toBe('enrichment');\n    });\n\n    test('should not register a plugin with the same name twice', async () => {\n      const pluginName = 'TestPlugin';\n      const plugin: EnrichmentPlugin = {\n        name: pluginName,\n        type: 'enrichment',\n        setup: jest.fn(),\n        teardown: jest.fn(),\n        execute: jest.fn(),\n      };\n\n      await timeline.register(plugin, config);\n      await timeline.register(plugin, config);\n\n      expect(timeline.plugins).toHaveLength(1);\n      expect(timeline.plugins[0].name).toBe('TestPlugin');\n      expect(mockLoggerProvider.warn).toHaveBeenCalledTimes(1);\n      expect(mockLoggerProvider.warn).toHaveBeenCalledWith(\n        `Plugin with name ${pluginName} already exists, skipping registration`,\n      );\n    });\n\n    test('should register plugins with different names', async () => {\n      const plugin1: EnrichmentPlugin = {\n        name: 'Plugin1',\n        type: 'enrichment',\n        setup: jest.fn(),\n        teardown: jest.fn(),\n        execute: jest.fn(),\n      };\n      const plugin2: EnrichmentPlugin = {\n        name: 'Plugin2',\n        type: 'enrichment',\n        setup: jest.fn(),\n        teardown: jest.fn(),\n        execute: jest.fn(),\n      };\n\n      await timeline.register(plugin1, config);\n      await timeline.register(plugin2, config);\n\n      expect(timeline.plugins).toHaveLength(2);\n      expect(timeline.plugins[0].name).toBe('Plugin1');\n      expect(timeline.plugins[1].name).toBe('Plugin2');\n    });\n\n    test('should log when a plugin name is not set', async () => {\n      const plugin: EnrichmentPlugin = {\n        type: 'enrichment',\n        setup: jest.fn(),\n        teardown: jest.fn(),\n        execute: jest.fn(),\n      };\n\n      await timeline.register(plugin, config);\n\n      expect(timeline.plugins).toHaveLength(1);\n      expect(timeline.plugins[0].name).not.toBeUndefined();\n      expect(mockLoggerProvider.warn).toHaveBeenCalledTimes(1);\n      expect(mockLoggerProvider.warn).toHaveBeenCalledWith(expect.stringContaining('Plugin name is undefined'));\n    });\n\n    test('should not register the same plugin twice when called concurrently', async () => {\n      let resolveSetup!: () => void;\n      const setupPromise = new Promise<void>((resolve) => {\n        resolveSetup = resolve;\n      });\n      const setup = jest.fn().mockReturnValue(setupPromise);\n      const plugin: EnrichmentPlugin = {\n        name: 'TestPlugin',\n        type: 'enrichment',\n        setup,\n        teardown: jest.fn(),\n        execute: jest.fn(),\n      };\n\n      const registrations = Promise.all([timeline.register(plugin, config), timeline.register(plugin, config)]);\n      resolveSetup();\n      await registrations;\n\n      expect(setup).toHaveBeenCalledTimes(1);\n      expect(timeline.plugins).toHaveLength(1);\n      expect(mockLoggerProvider.warn).toHaveBeenCalledWith(\n        `Plugin with name TestPlugin already exists, skipping registration`,\n      );\n    });\n\n    test('should re-throw when setup throws and block re-registration of the same name', async () => {\n      const setupError = new Error('setup failed');\n      const setup = jest.fn().mockRejectedValue(setupError);\n      const plugin: EnrichmentPlugin = {\n        name: 'FailingPlugin',\n        type: 'enrichment',\n        setup,\n      };\n\n      await expect(timeline.register(plugin, config)).rejects.toBe(setupError);\n      expect(timeline.plugins).toHaveLength(0);\n      // Status remains 'locked' — same name would just fail again, so retry isn't useful.\n      expect(timeline.pluginStatus.get('FailingPlugin')).toBe('locked');\n\n      await timeline.register(plugin, config);\n      expect(setup).toHaveBeenCalledTimes(1);\n      expect(timeline.plugins).toHaveLength(0);\n      expect(mockLoggerProvider.warn).toHaveBeenCalledWith(\n        `Plugin with name FailingPlugin already exists, skipping registration`,\n      );\n    });\n\n    test('should not push a plugin if reset() is called during setup', async () => {\n      let resolveSetup!: () => void;\n      const setupPromise = new Promise<void>((resolve) => {\n        resolveSetup = resolve;\n      });\n      const setup = jest.fn().mockReturnValue(setupPromise);\n      const plugin: EnrichmentPlugin = {\n        name: 'InterruptedPlugin',\n        type: 'enrichment',\n        setup,\n      };\n\n      const registration = timeline.register(plugin, config);\n      timeline.reset(new AmplitudeCore());\n      resolveSetup();\n      await registration;\n\n      expect(timeline.plugins).toHaveLength(0);\n      expect(timeline.pluginStatus.size).toBe(0);\n    });\n\n    test('should register two unnamed plugins concurrently with unique UUIDs', async () => {\n      const plugin1: EnrichmentPlugin = { type: 'enrichment', setup: jest.fn() };\n      const plugin2: EnrichmentPlugin = { type: 'enrichment', setup: jest.fn() };\n\n      await Promise.all([timeline.register(plugin1, config), timeline.register(plugin2, config)]);\n\n      expect(timeline.plugins).toHaveLength(2);\n      expect(timeline.plugins[0].name).not.toBe(timeline.plugins[1].name);\n    });\n\n    test('apply() should not invoke execute on a plugin while its setup is in flight', async () => {\n      let resolveSetup!: () => void;\n      const setupPromise = new Promise<void>((resolve) => {\n        resolveSetup = resolve;\n      });\n      const execute = jest.fn().mockImplementation((event: Event) => Promise.resolve(event));\n      const plugin: EnrichmentPlugin = {\n        name: 'SlowPlugin',\n        type: 'enrichment',\n        setup: jest.fn().mockReturnValue(setupPromise),\n        execute,\n      };\n\n      const registration = timeline.register(plugin, config);\n      await timeline.apply([{ event_type: 'mid-install' }, jest.fn()]);\n      expect(execute).not.toHaveBeenCalled();\n\n      resolveSetup();\n      await registration;\n\n      await timeline.apply([{ event_type: 'after-install' }, jest.fn()]);\n      expect(execute).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('deregister', () => {\n    test('should remove plugin correctly', async () => {\n      await timeline.register(\n        {\n          name: 'test-plugin',\n        },\n        config,\n      );\n      expect(timeline.plugins.length).toBe(1);\n      await timeline.deregister('test-plugin', config);\n      expect(timeline.plugins.length).toBe(0);\n    });\n\n    test('should only remove plugin that was already registered', async () => {\n      await timeline.register(\n        {\n          name: 'test-plugin',\n        },\n        config,\n      );\n      expect(timeline.plugins.length).toBe(1);\n      await timeline.deregister('bad-test-plugin', config);\n      expect(timeline.plugins.length).toBe(1);\n    });\n\n    test('should clear the status lock for a name stuck in locked', async () => {\n      const failingSetup = jest.fn().mockRejectedValueOnce(new Error('boom'));\n      const plugin: EnrichmentPlugin = {\n        name: 'StuckPlugin',\n        type: 'enrichment',\n        setup: failingSetup,\n      };\n      await expect(timeline.register(plugin, config)).rejects.toThrow('boom');\n      expect(timeline.pluginStatus.get('StuckPlugin')).toBe('locked');\n\n      await timeline.deregister('StuckPlugin', config);\n      expect(timeline.pluginStatus.has('StuckPlugin')).toBe(false);\n\n      // Lock is gone, so the same name can be re-registered.\n      const successSetup = jest.fn().mockResolvedValueOnce(undefined);\n      await timeline.register({ name: 'StuckPlugin', type: 'enrichment', setup: successSetup }, config);\n      expect(timeline.plugins).toHaveLength(1);\n      expect(successSetup).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('reset', () => {\n    test('should reset timeline', () => {\n      const timeline = new Timeline(new AmplitudeCore());\n      timeline.plugins = [];\n      timeline.reset(new AmplitudeCore());\n      expect(timeline.applying).toEqual(false);\n      expect(timeline.plugins).toEqual([]);\n    });\n\n    test('should reset timeline without plugin.teardown', () => {\n      const setup = jest.fn();\n      const timeline = new Timeline(new AmplitudeCore());\n      timeline.plugins = [\n        {\n          setup,\n        },\n      ];\n      timeline.reset(new AmplitudeCore());\n      expect(setup).toHaveBeenCalledTimes(0);\n      expect(timeline.applying).toEqual(false);\n      expect(timeline.plugins).toEqual([]);\n    });\n\n    test('should reset timeline with plugin.teardown', () => {\n      const teardown = jest.fn();\n      const timeline = new Timeline(new AmplitudeCore());\n      timeline.plugins = [\n        {\n          teardown,\n        },\n      ];\n      timeline.reset(new AmplitudeCore());\n      expect(teardown).toHaveBeenCalledTimes(1);\n      expect(timeline.applying).toEqual(false);\n      expect(timeline.plugins).toEqual([]);\n    });\n  });\n\n  test('should update event using before/enrichment plugin', async () => {\n    const beforeSetup = jest.fn().mockReturnValue(Promise.resolve());\n    const beforeTeardown = jest.fn().mockReturnValue(Promise.resolve());\n    const beforeExecute = jest.fn().mockImplementation((event: Event) =>\n      Promise.resolve({\n        ...event,\n        event_id: '1',\n      }),\n    );\n    const before: Plugin = {\n      name: 'plugin:before',\n      type: 'before',\n      setup: beforeSetup,\n      teardown: beforeTeardown,\n      execute: beforeExecute,\n    };\n    const enrichmentSetup = jest.fn().mockReturnValue(Promise.resolve());\n    const enrichmentExecute = jest.fn().mockImplementation((event: Event) =>\n      Promise.resolve({\n        ...event,\n        user_id: '2',\n      }),\n    );\n    const enrichment: Plugin = {\n      name: 'plugin:enrichment',\n      type: 'enrichment',\n      setup: enrichmentSetup,\n      execute: enrichmentExecute,\n    };\n\n    const destinationSetup = jest.fn().mockReturnValue(Promise.resolve());\n    const destinationExecute = jest\n      .fn()\n      // error once\n      .mockImplementationOnce((event: Event) => {\n        expect(event.event_id).toBe('1');\n        expect(event.user_id).toBe('2');\n        return Promise.reject({});\n      })\n      // success for the rest\n      .mockImplementation((event: Event) => {\n        expect(event.event_id).toBe('1');\n        expect(event.user_id).toBe('2');\n        return Promise.resolve();\n      });\n    const destination: Plugin = {\n      name: 'plugin:destination',\n      type: 'destination',\n      setup: destinationSetup,\n      execute: destinationExecute,\n    };\n    // register\n    await timeline.register(before, config);\n    await timeline.register(enrichment, config);\n    await timeline.register(destination, config);\n\n    expect(beforeSetup).toHaveBeenCalledTimes(1);\n    expect(enrichmentSetup).toHaveBeenCalledTimes(1);\n    expect(destinationSetup).toHaveBeenCalledTimes(1);\n    expect(timeline.plugins.length).toBe(3);\n    const event = (id: number): Event => ({\n      event_type: `${id}:event_type`,\n    });\n    await Promise.all([\n      timeline.push(event(1)).then(() => timeline.push(event(1.1))),\n      timeline.push(event(2)).then(() => Promise.all([timeline.push(event(2.1)), timeline.push(event(2.2))])),\n      timeline\n        .push(event(3))\n        .then(() =>\n          Promise.all([\n            timeline.push(event(3.1)).then(() => Promise.all([timeline.push(event(3.11)), timeline.push(event(3.12))])),\n            timeline.push(event(3.2)),\n          ]),\n        ),\n    ]);\n    expect(beforeExecute).toHaveBeenCalledTimes(10);\n    expect(enrichmentExecute).toHaveBeenCalledTimes(10);\n    expect(destinationExecute).toHaveBeenCalledTimes(10);\n\n    // deregister\n    await timeline.deregister('plugin:before', config);\n    await timeline.deregister('plugin:enrichment', config);\n    await timeline.deregister('plugin:destination', config);\n    expect(timeline.plugins.length).toBe(0);\n  });\n\n  describe('push', () => {\n    test('should skip event processing when config is missing', async () => {\n      const event = {\n        event_type: 'hello',\n      };\n      const result = timeline.push(event);\n      expect(await promiseState(result)).toEqual('pending');\n      expect(timeline.queue.length).toBe(1);\n    });\n  });\n\n  describe('apply', () => {\n    test('should handle undefined event', async () => {\n      const beforeSetup = jest.fn().mockReturnValueOnce(Promise.resolve());\n      const beforeExecute = jest.fn().mockImplementationOnce((event: Event) =>\n        Promise.resolve({\n          ...event,\n          event_id: '1',\n        }),\n      );\n      const before: Plugin = {\n        name: 'plugin:before',\n        type: 'before',\n        setup: beforeSetup,\n        execute: beforeExecute,\n      };\n      await timeline.register(before, config);\n      await timeline.apply(undefined);\n      await timeline.deregister('plugin:before', config);\n      expect(beforeExecute).toHaveBeenCalledTimes(0);\n    });\n\n    test(\"should pass event's extra to plugins\", async () => {\n      const beforeExecute = jest.fn().mockImplementationOnce((event: Event) => {\n        expect(event.extra).toStrictEqual({ 'extra-key': 'extra-value' });\n        return Promise.resolve(event);\n      });\n      const before: Plugin = {\n        name: 'plugin:before',\n        type: 'before',\n        setup: jest.fn().mockReturnValueOnce(Promise.resolve()),\n        execute: beforeExecute,\n      };\n\n      const enrichmentExecute = jest.fn().mockImplementationOnce((event: Event) => {\n        expect(event.extra).toStrictEqual({ 'extra-key': 'extra-value' });\n        return Promise.resolve(event);\n      });\n      const enrichment: Plugin = {\n        name: 'plugin:enrichment',\n        type: 'enrichment',\n        setup: jest.fn().mockReturnValueOnce(Promise.resolve()),\n        execute: enrichmentExecute,\n      };\n\n      const destinationExecute = jest.fn().mockImplementationOnce((event: Event) => {\n        expect(event.extra).toStrictEqual({ 'extra-key': 'extra-value' });\n        return Promise.resolve(event);\n      });\n      const destination: Plugin = {\n        name: 'plugin:destination',\n        type: 'destination',\n        setup: jest.fn().mockReturnValueOnce(Promise.resolve()),\n        execute: destinationExecute,\n      };\n\n      await timeline.register(before, config);\n      await timeline.register(enrichment, config);\n      await timeline.register(destination, config);\n\n      const event = {\n        event_type: 'some-event',\n        extra: { 'extra-key': 'extra-value' },\n      };\n      const callback = jest.fn();\n      await timeline.apply([event, callback]);\n\n      await timeline.deregister('plugin:before', config);\n      await timeline.deregister('plugin:enrichment', config);\n      await timeline.deregister('plugin:destination', config);\n\n      expect(beforeExecute).toHaveBeenCalledTimes(1);\n      expect(enrichmentExecute).toHaveBeenCalledTimes(1);\n      expect(destinationExecute).toHaveBeenCalledTimes(1);\n      expect(callback).toHaveBeenCalledTimes(1);\n    });\n\n    test('should stop if a before plugin returns null', async () => {\n      const beforeExecute1 = jest.fn().mockImplementationOnce((event: Event) => {\n        return Promise.resolve(event);\n      });\n      const beforeExecute2 = jest.fn().mockImplementationOnce(() => {\n        return Promise.resolve(null);\n      });\n      const beforeExecute3 = jest.fn().mockImplementationOnce((event: Event) => {\n        return Promise.resolve(event);\n      });\n      const before1: Plugin = {\n        name: 'plugin:before:1',\n        type: 'before',\n        setup: jest.fn().mockReturnValueOnce(Promise.resolve()),\n        execute: beforeExecute1,\n      };\n      const before2: Plugin = {\n        name: 'plugin:before:2',\n        type: 'before',\n        setup: jest.fn().mockReturnValueOnce(Promise.resolve()),\n        execute: beforeExecute2,\n      };\n      const before3: Plugin = {\n        name: 'plugin:before:3',\n        type: 'before',\n        setup: jest.fn().mockReturnValueOnce(Promise.resolve()),\n        execute: beforeExecute3,\n      };\n\n      const enrichmentExecute = jest.fn().mockImplementationOnce((event: Event) => {\n        return Promise.resolve(event);\n      });\n      const enrichment: Plugin = {\n        name: 'plugin:enrichment',\n        type: 'enrichment',\n        setup: jest.fn().mockReturnValueOnce(Promise.resolve()),\n        execute: enrichmentExecute,\n      };\n\n      const destinationExecute = jest.fn().mockImplementationOnce((event: Event) => {\n        return Promise.resolve(event);\n      });\n      const destination: Plugin = {\n        name: 'plugin:destination',\n        type: 'destination',\n        setup: jest.fn().mockReturnValueOnce(Promise.resolve()),\n        execute: destinationExecute,\n      };\n\n      await timeline.register(before1, config);\n      await timeline.register(before2, config);\n      await timeline.register(before3, config);\n      await timeline.register(enrichment, config);\n      await timeline.register(destination, config);\n\n      const event = {\n        event_type: 'some-event',\n      };\n      const callback = jest.fn();\n      await timeline.apply([event, callback]);\n\n      await timeline.deregister('plugin:before:1', config);\n      await timeline.deregister('plugin:before:2', config);\n      await timeline.deregister('plugin:before:3', config);\n      await timeline.deregister('plugin:enrichment', config);\n      await timeline.deregister('plugin:destination', config);\n\n      expect(beforeExecute1).toHaveBeenCalledTimes(1);\n      expect(beforeExecute2).toHaveBeenCalledTimes(1);\n      expect(beforeExecute3).toHaveBeenCalledTimes(0);\n      expect(enrichmentExecute).toHaveBeenCalledTimes(0);\n      expect(destinationExecute).toHaveBeenCalledTimes(0);\n      expect(callback).toHaveBeenCalledTimes(1);\n    });\n\n    test('should stop if an enrichment plugin returns null', async () => {\n      const beforeExecute = jest.fn().mockImplementationOnce((event: Event) => {\n        return Promise.resolve(event);\n      });\n      const before: Plugin = {\n        name: 'plugin:before',\n        type: 'before',\n        setup: jest.fn().mockReturnValueOnce(Promise.resolve()),\n        execute: beforeExecute,\n      };\n\n      const enrichmentExecute1 = jest.fn().mockImplementationOnce((event: Event) => {\n        return Promise.resolve(event);\n      });\n      const enrichmentExecute2 = jest.fn().mockImplementationOnce(() => {\n        return Promise.resolve(null);\n      });\n      const enrichmentExecute3 = jest.fn().mockImplementationOnce((event: Event) => {\n        return Promise.resolve(event);\n      });\n      const enrichment1: Plugin = {\n        name: 'plugin:enrichment:1',\n        type: 'enrichment',\n        setup: jest.fn().mockReturnValueOnce(Promise.resolve()),\n        execute: enrichmentExecute1,\n      };\n      const enrichment2: Plugin = {\n        name: 'plugin:enrichment:2',\n        type: 'enrichment',\n        setup: jest.fn().mockReturnValueOnce(Promise.resolve()),\n        execute: enrichmentExecute2,\n      };\n      const enrichment3: Plugin = {\n        name: 'plugin:enrichment:3',\n        type: 'enrichment',\n        setup: jest.fn().mockReturnValueOnce(Promise.resolve()),\n        execute: enrichmentExecute3,\n      };\n\n      const destinationExecute = jest.fn().mockImplementationOnce((event: Event) => {\n        return Promise.resolve(event);\n      });\n      const destination: Plugin = {\n        name: 'plugin:destination',\n        type: 'destination',\n        setup: jest.fn().mockReturnValueOnce(Promise.resolve()),\n        execute: destinationExecute,\n      };\n\n      await timeline.register(before, config);\n      await timeline.register(enrichment1, config);\n      await timeline.register(enrichment2, config);\n      await timeline.register(enrichment3, config);\n      await timeline.register(destination, config);\n\n      const event = {\n        event_type: 'some-event',\n      };\n      const callback = jest.fn();\n      await timeline.apply([event, callback]);\n\n      await timeline.deregister('plugin:before', config);\n      await timeline.deregister('plugin:enrichment:1', config);\n      await timeline.deregister('plugin:enrichment:2', config);\n      await timeline.deregister('plugin:enrichment:3', config);\n      await timeline.deregister('plugin:destination', config);\n\n      expect(beforeExecute).toHaveBeenCalledTimes(1);\n      expect(enrichmentExecute1).toHaveBeenCalledTimes(1);\n      expect(enrichmentExecute2).toHaveBeenCalledTimes(1);\n      expect(enrichmentExecute3).toHaveBeenCalledTimes(0);\n      expect(destinationExecute).toHaveBeenCalledTimes(0);\n      expect(callback).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('flush', () => {\n    test('should flush events', async () => {\n      const setup = jest.fn().mockReturnValueOnce(Promise.resolve(undefined));\n      const execute = jest.fn().mockReturnValue(Promise.resolve(undefined));\n      const flush = jest.fn().mockReturnValue(Promise.resolve(undefined));\n      const plugin: DestinationPlugin = {\n        name: 'mock',\n        type: 'destination',\n        setup,\n        execute,\n        flush,\n      };\n      await timeline.register(plugin, config);\n      void timeline.push(createTrackEvent('a'));\n      void timeline.push(createTrackEvent('b'));\n      void timeline.push(createTrackEvent('c'));\n      void timeline.push(createTrackEvent('d'));\n      expect(timeline.queue.length).toBe(4);\n      await timeline.flush();\n      expect(timeline.queue.length).toBe(0);\n      expect(execute).toHaveBeenCalledTimes(4);\n      expect(flush).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('onIdentityChanged', () => {\n    test('should call onIdentityChanged() of each plugin', async () => {\n      const onIdentityChanged = jest.fn().mockReturnValue(Promise.resolve(undefined));\n      const plugin: EnrichmentPlugin = {\n        name: 'mock',\n        type: 'enrichment',\n        onIdentityChanged,\n      };\n      const mockIdentity = {\n        deviceId: 'test-device-id',\n        userId: 'test-user-id',\n      };\n      timeline.plugins.push(plugin);\n\n      timeline.onIdentityChanged(mockIdentity);\n\n      expect(onIdentityChanged).toHaveBeenCalledTimes(1);\n      expect(onIdentityChanged).toHaveBeenCalledWith(mockIdentity);\n    });\n  });\n\n  describe('onSessionIdChanged', () => {\n    test('should call onSessionIdChanged() of each plugin', async () => {\n      const onSessionIdChanged = jest.fn().mockReturnValue(Promise.resolve(undefined));\n      const plugin: EnrichmentPlugin = {\n        name: 'mock',\n        type: 'enrichment',\n        onSessionIdChanged,\n      };\n      const mockSessionId = 123;\n      timeline.plugins.push(plugin);\n\n      timeline.onSessionIdChanged?.(mockSessionId);\n\n      expect(onSessionIdChanged).toHaveBeenCalledTimes(1);\n      expect(onSessionIdChanged).toHaveBeenCalledWith(mockSessionId);\n    });\n  });\n\n  describe('onOptOutChanged', () => {\n    test('should call onOptOutChanged() of each plugin', async () => {\n      const onOptOutChanged = jest.fn().mockReturnValue(Promise.resolve(undefined));\n      const plugin: EnrichmentPlugin = {\n        name: 'mock',\n        type: 'enrichment',\n        onOptOutChanged,\n      };\n      const mockOptOut = true;\n      timeline.plugins.push(plugin);\n\n      timeline.onOptOutChanged?.(mockOptOut);\n\n      expect(onOptOutChanged).toHaveBeenCalledTimes(1);\n      expect(onOptOutChanged).toHaveBeenCalledWith(mockOptOut);\n    });\n  });\n\n  describe('onReset', () => {\n    test('should call onReset() of each plugin', async () => {\n      const onReset = jest.fn().mockReturnValue(Promise.resolve(undefined));\n      const plugin: EnrichmentPlugin = {\n        name: 'mock',\n        type: 'enrichment',\n        onReset,\n      };\n      timeline.plugins.push(plugin);\n      timeline.onReset?.();\n      expect(onReset).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('addOptOutListener', () => {\n    let mockOptOutListener: jest.Mock;\n\n    beforeEach(() => {\n      timeline.reset(new AmplitudeCore());\n    });\n\n    test('optOut listener should be called when optOut is changed', async () => {\n      mockOptOutListener = jest.fn();\n      timeline.addOptOutListener(mockOptOutListener);\n      expect(timeline._optOutListeners.length).toBe(1);\n      timeline.onOptOutChanged(true);\n      expect(mockOptOutListener).toHaveBeenCalledTimes(1);\n      expect(mockOptOutListener).toHaveBeenCalledWith(true);\n    });\n\n    test('should call optOut listeners one by one', async () => {\n      jest.useFakeTimers();\n      const calls: number[] = [];\n\n      // add a long async listener\n      timeline.addOptOutListener(async () => {\n        return new Promise((resolve) => {\n          setTimeout(() => {\n            resolve();\n            calls.push(1);\n            console.log('listener 1 resolved');\n          }, 1000);\n        });\n      });\n\n      // add a short async listener\n      timeline.addOptOutListener(async () => {\n        return new Promise((resolve) => {\n          setTimeout(() => {\n            resolve();\n            calls.push(2);\n            console.log('listener 2 resolved');\n          }, 100);\n        });\n      });\n      timeline.onOptOutChanged(true);\n      // Advance timers to allow setTimeout callbacks to execute\n      await jest.runAllTimersAsync();\n\n      // check that long listener finished first\n      expect(calls).toEqual([1, 2]);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/transports/base.test.ts",
    "content": "import { Status } from '../../src/types/status';\nimport { BaseTransport } from '../../src/transports/base';\n\ndescribe('BaseTransport', () => {\n  describe('send', () => {\n    test('should return null', async () => {\n      const transport = new BaseTransport();\n      const response = await transport.send('', {\n        api_key: '',\n        events: [],\n      });\n      expect(response).toBeNull();\n    });\n  });\n\n  describe('response-builder', () => {\n    test('should handle malformed input', () => {\n      const transport = new BaseTransport();\n      // Simulates a malformed input at runtime\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore\n      const response = transport.buildResponse('');\n      expect(response).toBe(null);\n    });\n\n    describe('success', () => {\n      test('should return success response', () => {\n        const transport = new BaseTransport();\n        const response = transport.buildResponse({\n          code: 200,\n          events_ingested: 1,\n          payload_size_bytes: 1,\n          server_upload_time: 1,\n        });\n        expect(response).toEqual({\n          status: Status.Success,\n          statusCode: 200,\n          body: {\n            eventsIngested: 1,\n            payloadSizeBytes: 1,\n            serverUploadTime: 1,\n          },\n        });\n      });\n\n      test('should return success response with default values', () => {\n        const transport = new BaseTransport();\n        const response = transport.buildResponse({\n          code: 200,\n        });\n        expect(response).toEqual({\n          status: Status.Success,\n          statusCode: 200,\n          body: {\n            eventsIngested: 0,\n            payloadSizeBytes: 0,\n            serverUploadTime: 0,\n          },\n        });\n      });\n    });\n\n    describe('invalid response', () => {\n      test('should return invalid response', () => {\n        const transport = new BaseTransport();\n        const response = transport.buildResponse({\n          code: 400,\n          error: 'error',\n          missing_field: 'field',\n          events_with_invalid_fields: { a: 1 },\n          events_with_missing_fields: { a: 2 },\n          events_with_invalid_id_lengths: {},\n          eps_threshold: 1,\n          exceeded_daily_quota_devices: { a: 3 },\n          silenced_devices: ['a'],\n          silenced_events: [1],\n          throttled_devices: { a: 4 },\n          throttled_events: [1],\n        });\n        expect(response).toEqual({\n          status: Status.Invalid,\n          statusCode: 400,\n          body: {\n            error: 'error',\n            missingField: 'field',\n            eventsWithInvalidFields: { a: 1 },\n            eventsWithMissingFields: { a: 2 },\n            eventsWithInvalidIdLengths: {},\n            epsThreshold: 1,\n            exceededDailyQuotaDevices: { a: 3 },\n            silencedDevices: ['a'],\n            silencedEvents: [1],\n            throttledDevices: { a: 4 },\n            throttledEvents: [1],\n          },\n        });\n      });\n\n      test('should return invalid response with default values', () => {\n        const transport = new BaseTransport();\n        const response = transport.buildResponse({\n          code: 400,\n        });\n        expect(response).toEqual({\n          status: Status.Invalid,\n          statusCode: 400,\n          body: {\n            error: '',\n            missingField: '',\n            eventsWithInvalidFields: {},\n            eventsWithMissingFields: {},\n            eventsWithInvalidIdLengths: {},\n            epsThreshold: 0,\n            exceededDailyQuotaDevices: {},\n            silencedDevices: [],\n            silencedEvents: [],\n            throttledDevices: {},\n            throttledEvents: [],\n          },\n        });\n      });\n    });\n\n    describe('pay load too large response', () => {\n      test('should return payload too large response', () => {\n        const transport = new BaseTransport();\n        const response = transport.buildResponse({\n          code: 413,\n          error: 'error',\n        });\n        expect(response).toEqual({\n          status: Status.PayloadTooLarge,\n          statusCode: 413,\n          body: {\n            error: 'error',\n          },\n        });\n      });\n\n      test('should return payload too large response wtih default values', () => {\n        const transport = new BaseTransport();\n        const response = transport.buildResponse({\n          code: 413,\n        });\n        expect(response).toEqual({\n          status: Status.PayloadTooLarge,\n          statusCode: 413,\n          body: {\n            error: '',\n          },\n        });\n      });\n    });\n\n    describe('rate limit response', () => {\n      test('should return rate limit response', () => {\n        const transport = new BaseTransport();\n        const response = transport.buildResponse({\n          code: 429,\n          error: 'error',\n          eps_threshold: 1,\n          throttled_devices: { a: 1 },\n          throttled_users: { b: 1 },\n          exceeded_daily_quota_devices: { c: 1 },\n          exceeded_daily_quota_users: { d: 1 },\n          throttled_events: [1],\n        });\n        expect(response).toEqual({\n          status: Status.RateLimit,\n          statusCode: 429,\n          body: {\n            error: 'error',\n            epsThreshold: 1,\n            throttledDevices: { a: 1 },\n            throttledUsers: { b: 1 },\n            exceededDailyQuotaDevices: { c: 1 },\n            exceededDailyQuotaUsers: { d: 1 },\n            throttledEvents: [1],\n          },\n        });\n      });\n\n      test('should return rate limit response with default values', () => {\n        const transport = new BaseTransport();\n        const response = transport.buildResponse({\n          code: 429,\n        });\n        expect(response).toEqual({\n          status: Status.RateLimit,\n          statusCode: 429,\n          body: {\n            error: '',\n            epsThreshold: 0,\n            throttledDevices: {},\n            throttledUsers: {},\n            exceededDailyQuotaDevices: {},\n            exceededDailyQuotaUsers: {},\n            throttledEvents: [],\n          },\n        });\n      });\n    });\n\n    describe('timeout', () => {\n      test('should generic response', () => {\n        const transport = new BaseTransport();\n        const response = transport.buildResponse({\n          code: 408,\n        });\n        expect(response).toEqual({\n          status: Status.Timeout,\n          statusCode: 408,\n        });\n      });\n    });\n\n    describe('other error', () => {\n      test('should generic response', () => {\n        const transport = new BaseTransport();\n        const response = transport.buildResponse({\n          code: 500,\n        });\n        expect(response).toEqual({\n          status: Status.Failed,\n          statusCode: 500,\n        });\n      });\n    });\n\n    describe('other unknown error', () => {\n      test('should generic response', () => {\n        const transport = new BaseTransport();\n        const response = transport.buildResponse({});\n        expect(response).toEqual({\n          status: Status.Unknown,\n          statusCode: 0,\n        });\n      });\n    });\n  });\n\n  describe('buildStatus', () => {\n    test('should return success', () => {\n      const transport = new BaseTransport();\n      expect(transport.buildStatus(200)).toBe(Status.Success);\n    });\n\n    test('should return rate limit', () => {\n      const transport = new BaseTransport();\n      expect(transport.buildStatus(429)).toBe(Status.RateLimit);\n    });\n\n    test('should return payload too large', () => {\n      const transport = new BaseTransport();\n      expect(transport.buildStatus(413)).toBe(Status.PayloadTooLarge);\n    });\n\n    test('should return timeout', () => {\n      const transport = new BaseTransport();\n      expect(transport.buildStatus(408)).toBe(Status.Timeout);\n    });\n\n    test('should return invalid', () => {\n      const transport = new BaseTransport();\n      expect(transport.buildStatus(400)).toBe(Status.Invalid);\n    });\n\n    test('should return failed', () => {\n      const transport = new BaseTransport();\n      expect(transport.buildStatus(500)).toBe(Status.Failed);\n    });\n\n    test('should return unknown', () => {\n      const transport = new BaseTransport();\n      expect(transport.buildStatus(0)).toBe(Status.Unknown);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/transports/fetch.test.ts",
    "content": "/**\n * @jest-environment jsdom\n */\n\nimport { FetchTransport } from '../../src/transports/fetch';\nimport { Status } from '../../src/types/status';\nimport 'isomorphic-fetch';\n\ndescribe('fetch', () => {\n  describe('send', () => {\n    test.each([\n      ['{}'], // ideally response body should be json format to an application/json request\n      [''], // test the edge case where response body is non-json format\n      ['<'],\n    ])('should resolve with response', async (body) => {\n      const transport = new FetchTransport();\n      const url = 'http://localhost:3000';\n      const payload = {\n        api_key: '',\n        events: [],\n      };\n      const result = {\n        statusCode: 200,\n        status: Status.Success as const,\n        body: {\n          eventsIngested: 0,\n          payloadSizeBytes: 0,\n          serverUploadTime: 0,\n        },\n      };\n      jest.spyOn(window, 'fetch').mockReturnValueOnce(Promise.resolve(new Response(body)));\n      jest.spyOn(transport, 'buildResponse').mockReturnValueOnce(result);\n      const response = await transport.send(url, payload);\n      expect(response).toEqual(result);\n    });\n\n    test('should include custom headers in request', async () => {\n      const customHeaders = {\n        Authorization: 'Bearer token123',\n      };\n      const transport = new FetchTransport(customHeaders);\n      const url = 'http://localhost:3000';\n      const payload = {\n        api_key: '',\n        events: [],\n      };\n\n      const fetchSpy = jest.spyOn(window, 'fetch').mockReturnValueOnce(Promise.resolve(new Response('{}')));\n\n      await transport.send(url, payload);\n\n      expect(fetchSpy).toHaveBeenCalledWith(url, {\n        headers: {\n          'Content-Type': 'application/json',\n          Accept: '*/*',\n          Authorization: 'Bearer token123',\n        },\n        body: JSON.stringify(payload),\n        method: 'POST',\n      });\n    });\n\n    test('should allow custom headers to override defaults', async () => {\n      const customHeaders = {\n        'Content-Type': 'text/plain',\n        Accept: 'application/json',\n      };\n      const transport = new FetchTransport(customHeaders);\n      const url = 'http://localhost:3000';\n      const payload = {\n        api_key: '',\n        events: [],\n      };\n\n      const fetchSpy = jest.spyOn(window, 'fetch').mockReturnValueOnce(Promise.resolve(new Response('{}')));\n\n      await transport.send(url, payload);\n\n      expect(fetchSpy).toHaveBeenCalledWith(url, {\n        headers: {\n          'Content-Type': 'text/plain',\n          Accept: 'application/json',\n        },\n        body: JSON.stringify(payload),\n        method: 'POST',\n      });\n    });\n\n    test('should work without custom headers (backward compatibility)', async () => {\n      const transport = new FetchTransport();\n      const url = 'http://localhost:3000';\n      const payload = {\n        api_key: '',\n        events: [],\n      };\n\n      const fetchSpy = jest.spyOn(window, 'fetch').mockReturnValueOnce(Promise.resolve(new Response('{}')));\n\n      await transport.send(url, payload);\n\n      expect(fetchSpy).toHaveBeenCalledWith(url, {\n        headers: {\n          'Content-Type': 'application/json',\n          Accept: '*/*',\n        },\n        body: JSON.stringify(payload),\n        method: 'POST',\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/transports/gzip.test.ts",
    "content": "/**\n * @jest-environment jsdom\n */\n\nimport { TextEncoder } from 'util';\nimport { compressToGzipArrayBuffer, isCompressionStreamAvailable } from '../../src/transports/gzip';\n\nif (typeof global.TextEncoder === 'undefined') {\n  (global as typeof globalThis & { TextEncoder?: typeof TextEncoder }).TextEncoder = TextEncoder;\n}\n\ndescribe('gzip', () => {\n  describe('compressToGzipArrayBuffer', () => {\n    test('returns undefined when CompressionStream is not available', async () => {\n      const g = global as { CompressionStream?: unknown };\n      const originalCompressionStream = g.CompressionStream;\n      // Set to undefined (don't delete) so the code hits our return instead of ReferenceError\n      g.CompressionStream = undefined;\n\n      const result = await compressToGzipArrayBuffer('data');\n      expect(result).toBeUndefined();\n\n      g.CompressionStream = originalCompressionStream;\n    });\n\n    test('returns undefined when compression fails at runtime', async () => {\n      const g = global as { CompressionStream?: unknown; Response?: unknown };\n      const originalCompressionStream = g.CompressionStream;\n      const originalResponse = g.Response;\n\n      const mockCompressedStream = {};\n      const pipeThrough = jest.fn().mockReturnValue(mockCompressedStream);\n      Object.defineProperty(Blob.prototype, 'stream', {\n        value: () => ({ pipeThrough }),\n        configurable: true,\n        writable: true,\n      });\n\n      g.CompressionStream = jest.fn();\n      g.Response = jest.fn().mockImplementation(() => ({\n        arrayBuffer: () => Promise.reject(new Error('compression failed')),\n      }));\n\n      const result = await compressToGzipArrayBuffer('data');\n      expect(result).toBeUndefined();\n\n      g.CompressionStream = originalCompressionStream;\n      g.Response = originalResponse;\n      delete (Blob.prototype as unknown as { stream?: () => unknown }).stream;\n    });\n\n    test('compresses with gzip and returns array buffer', async () => {\n      const g = global as { CompressionStream?: unknown; Response?: unknown };\n      const originalCompressionStream = g.CompressionStream;\n      const originalResponse = g.Response;\n\n      const mockCompressedStream = {};\n      const pipeThrough = jest.fn().mockReturnValue(mockCompressedStream);\n      Object.defineProperty(Blob.prototype, 'stream', {\n        value: () => ({ pipeThrough }),\n        configurable: true,\n        writable: true,\n      });\n\n      const MockCompressionStream = jest.fn();\n      g.CompressionStream = MockCompressionStream;\n\n      const mockArrayBuffer = new Uint8Array([0x1f, 0x8b]).buffer;\n      g.Response = jest.fn().mockImplementation(() => ({\n        arrayBuffer: () => Promise.resolve(mockArrayBuffer),\n      }));\n\n      const result = await compressToGzipArrayBuffer('data');\n\n      expect(MockCompressionStream).toHaveBeenCalledWith('gzip');\n      expect(pipeThrough).toHaveBeenCalledWith(expect.anything());\n      expect(g.Response as jest.Mock).toHaveBeenCalledWith(mockCompressedStream);\n      expect(result).toBeDefined();\n      expect(new Uint8Array(result as ArrayBuffer)).toEqual(new Uint8Array([0x1f, 0x8b]));\n\n      g.CompressionStream = originalCompressionStream;\n      g.Response = originalResponse;\n      delete (Blob.prototype as unknown as { stream?: () => unknown }).stream;\n    });\n  });\n\n  describe('isCompressionStreamAvailable', () => {\n    test('returns false when CompressionStream is undefined', () => {\n      const g = global as { CompressionStream?: unknown };\n      const originalCompressionStream = g.CompressionStream;\n      delete g.CompressionStream;\n\n      expect(isCompressionStreamAvailable()).toBe(false);\n\n      g.CompressionStream = originalCompressionStream;\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/tsconfig.json",
    "content": "{\n  \"extends\": \"../tsconfig.json\",\n  \"compilerOptions\": {\n    \"types\": [\"jest\", \"node\"]\n  }\n}\n\n"
  },
  {
    "path": "packages/analytics-core/test/utils/chunk.test.ts",
    "content": "import { chunk } from '../../src/utils/chunk';\n\ndescribe('chunk', () => {\n  test('should split in chunks', () => {\n    const arr = [1, 2, 3, 4, 5];\n    expect(chunk(arr, 0)).toEqual([[1], [2], [3], [4], [5]]);\n    expect(chunk(arr, 1)).toEqual([[1], [2], [3], [4], [5]]);\n    expect(chunk(arr, 2)).toEqual([[1, 2], [3, 4], [5]]);\n    expect(chunk(arr, 3)).toEqual([\n      [1, 2, 3],\n      [4, 5],\n    ]);\n    expect(chunk(arr, 4)).toEqual([[1, 2, 3, 4], [5]]);\n    expect(chunk(arr, 5)).toEqual([[1, 2, 3, 4, 5]]);\n    expect(chunk(arr, 6)).toEqual([[1, 2, 3, 4, 5]]);\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/utils/debug.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-unsafe-call */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\nimport { LogLevel } from '../../src/types/loglevel';\nimport {\n  getStacktrace,\n  getClientLogConfig,\n  getValueByStringPath,\n  getClientStates,\n  debugWrapper,\n} from '../../src/utils/debug';\nimport { returnWrapper } from '../../src/utils/return-wrapper';\nimport { AmplitudeCore } from '../../src/index';\nimport { useDefaultConfig } from '../helpers/default';\n\ndescribe('debug', () => {\n  describe('getStacktrace', () => {\n    test('should get the stacktrace of a function call', () => {\n      let stacktrace: string[] = [];\n      const twoSum = (a: number, b: number): number => {\n        stacktrace = getStacktrace();\n        return a + b;\n      };\n      twoSum(1, 2);\n      expect(stacktrace[0].includes('twoSum')).toBe(true);\n    });\n\n    test('should return empty string when Error is not available', () => {\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore\n      global.Error = jest.fn();\n      let stacktrace: string[] = [];\n      const twoSum = (a: number, b: number): number => {\n        stacktrace = getStacktrace();\n        return a + b;\n      };\n      twoSum(1, 2);\n      expect(stacktrace).toEqual([]);\n    });\n  });\n\n  describe('getClientLogConfig', () => {\n    test('should get client log config', async () => {\n      const client = new AmplitudeCore();\n      const defaultConfig = useDefaultConfig();\n      await (client as any)._init(defaultConfig);\n      const getLogConfig = getClientLogConfig(client);\n      const logConfig = getLogConfig();\n      expect(logConfig.logLevel).toEqual(defaultConfig.logLevel);\n      expect(logConfig.logger).toEqual(defaultConfig.loggerProvider);\n    });\n  });\n\n  describe('getValueByStringPath', () => {\n    test('should get attribute with string path', () => {\n      let obj: any = { a: 1 };\n      expect(getValueByStringPath(obj, 'a')).toEqual(1);\n\n      obj = { a: { b: 1 } };\n      expect(getValueByStringPath(obj, 'a.b')).toEqual(1);\n\n      obj = { a: { b: [1, 2] } };\n      expect(getValueByStringPath(obj, 'a.b[1]')).toEqual(2);\n\n      obj = { a: { b: 1 } };\n      expect(getValueByStringPath(obj, 'a.c')).toEqual(undefined);\n    });\n  });\n\n  describe('getClientStates', () => {\n    test('should get client states', async () => {\n      const client = new AmplitudeCore();\n      const defaultConfig = useDefaultConfig();\n      await (client as any)._init(defaultConfig);\n      const getStates = getClientStates(client, ['config', 'timeline.queue']);\n      const clientStates = getStates();\n      expect(clientStates['config']).toEqual(defaultConfig);\n      expect(clientStates['timeline.queue']).toEqual(client.timeline.queue);\n    });\n  });\n\n  describe('debugWrapper', () => {\n    let logger: any;\n\n    beforeEach(() => {\n      // init new logger to reset mock call times\n      logger = {\n        disable: jest.fn(),\n        enable: jest.fn(),\n        debug: jest.fn(),\n        log: jest.fn(),\n        warn: jest.fn(),\n        error: jest.fn(),\n      };\n    });\n\n    test('should not call debug when not reaching debug level', async () => {\n      const fn = jest.fn<Promise<number>, []>().mockReturnValueOnce(Promise.resolve(1));\n      const wrappedFn = debugWrapper(\n        fn,\n        'fn',\n        () => ({\n          logger,\n          logLevel: LogLevel.Verbose,\n        }),\n        () => ({ state1: 1 }),\n      );\n      const result = await wrappedFn();\n      expect(logger.debug).toHaveBeenCalledTimes(0);\n      expect(result).toBe(1);\n    });\n\n    test('should not call debug when logger is missing', async () => {\n      const fn = jest.fn<Promise<number>, []>().mockReturnValueOnce(Promise.resolve(1));\n      const wrappedFn = debugWrapper(\n        fn,\n        'fn',\n        () => ({\n          logger: null as any,\n          logLevel: LogLevel.Debug,\n        }),\n        () => ({ state1: 1 }),\n      );\n      const result = await wrappedFn();\n      expect(logger.debug).toHaveBeenCalledTimes(0);\n      expect(result).toBe(1);\n    });\n\n    test('should call debug when reaching debug level', async () => {\n      const fn = jest.fn<Promise<number>, []>().mockReturnValueOnce(Promise.resolve(1));\n      const wrappedFn = debugWrapper(\n        fn,\n        'fn',\n        () => ({\n          logger,\n          logLevel: LogLevel.Debug,\n        }),\n        () => ({ state1: 1 }),\n      );\n      const result = await wrappedFn();\n      expect(result).toBe(1);\n      expect(logger.debug).toHaveBeenCalledTimes(1);\n      const debugContext = JSON.parse(logger.debug.mock.calls[0] as string);\n      expect(debugContext.type).toBeDefined();\n      expect(debugContext.name).toEqual('fn');\n      expect(debugContext.args).toBeDefined();\n      expect(debugContext.stacktrace).toBeDefined();\n      expect(debugContext.time).toBeDefined();\n      expect(debugContext.states).toBeDefined();\n    });\n\n    test('should work with returnWrapper', async () => {\n      const fn = jest.fn<Promise<number>, []>().mockReturnValueOnce(Promise.resolve(1));\n      const wrappedFn = debugWrapper(\n        () => returnWrapper(fn()),\n        'fn',\n        () => ({\n          logger,\n          logLevel: LogLevel.Debug,\n        }),\n        () => ({ state1: 1 }),\n      );\n      const result = await wrappedFn().promise;\n      expect(result).toBe(1);\n      expect(logger.debug).toHaveBeenCalledTimes(1);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/utils/environment.test.ts",
    "content": "import * as analyticsCoreModule from '../../src/index';\nimport * as globalScopeModule from '../../src/global-scope';\n\ntype ChromeStub = { runtime?: { id?: string | number } };\n\ndescribe('isChromeExtension', () => {\n  const originalChrome = (globalThis as typeof globalThis & { chrome?: ChromeStub }).chrome;\n\n  afterEach(() => {\n    jest.restoreAllMocks();\n    if (originalChrome === undefined) {\n      delete (globalThis as typeof globalThis & { chrome?: ChromeStub }).chrome;\n    } else {\n      (globalThis as typeof globalThis & { chrome?: ChromeStub }).chrome = originalChrome;\n    }\n  });\n\n  test('returns false when globalScope is undefined', () => {\n    jest.spyOn(globalScopeModule, 'getGlobalScope').mockReturnValue(undefined);\n    expect(analyticsCoreModule.isChromeExtension()).toBe(false);\n  });\n\n  test('returns false when chrome is undefined', () => {\n    delete (globalThis as typeof globalThis & { chrome?: ChromeStub }).chrome;\n    expect(analyticsCoreModule.isChromeExtension()).toBe(false);\n  });\n\n  test('returns false when chrome.runtime is undefined', () => {\n    (globalThis as typeof globalThis & { chrome?: ChromeStub }).chrome = {};\n    expect(analyticsCoreModule.isChromeExtension()).toBe(false);\n  });\n\n  test('returns false when runtime.id is not a string', () => {\n    (globalThis as typeof globalThis & { chrome?: ChromeStub }).chrome = { runtime: { id: 1 } };\n    expect(analyticsCoreModule.isChromeExtension()).toBe(false);\n  });\n\n  test('returns true when chrome.runtime.id is a string', () => {\n    (globalThis as typeof globalThis & { chrome?: ChromeStub }).chrome = { runtime: { id: 'ext-abc' } };\n    expect(analyticsCoreModule.isChromeExtension()).toBe(true);\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/utils/event-builder.test.ts",
    "content": "import { SpecialEventType } from '../../src/types/event/event';\nimport { Identify } from '../../src/identify';\nimport {\n  createTrackEvent,\n  createIdentifyEvent,\n  createGroupIdentifyEvent,\n  createGroupEvent,\n} from '../../src/utils/event-builder';\n\ndescribe('event-builder', () => {\n  describe('createTrackEvent', () => {\n    test('should create event', () => {\n      const eventType = 'track event';\n      const eventProperties = { event: 'test' };\n      const eventOptions = { user_id: 'eventUserId' };\n      const event = createTrackEvent(eventType, eventProperties, eventOptions);\n      expect(event).toEqual({\n        event_properties: { event: 'test' },\n        event_type: 'track event',\n        user_id: 'eventUserId',\n      });\n    });\n\n    test('should create with plain event', () => {\n      const plainEvent = {\n        event_type: 'track event',\n        groups: {\n          org: '15',\n        },\n      };\n      const event = createTrackEvent(plainEvent);\n      expect(event).toEqual({\n        event_type: 'track event',\n        groups: {\n          org: '15',\n        },\n      });\n    });\n\n    test('should handle missing event properties', () => {\n      const eventType = 'track event';\n      const event = createTrackEvent(eventType);\n      expect(event).toEqual({\n        event_type: 'track event',\n      });\n    });\n  });\n\n  describe('createIdentifyEvent', () => {\n    test('should create event', () => {\n      const identify = new Identify();\n      const eventOptions = { user_id: 'userId', device_id: 'deviceId' };\n      const event = createIdentifyEvent(identify, eventOptions);\n      expect(event).toEqual({\n        event_type: SpecialEventType.IDENTIFY,\n        user_properties: {},\n        user_id: 'userId',\n        device_id: 'deviceId',\n      });\n    });\n\n    test('should handle missing deviceId', () => {\n      const identify = new Identify();\n      const event = createIdentifyEvent(identify);\n      expect(event).toEqual({\n        event_type: SpecialEventType.IDENTIFY,\n        user_properties: {},\n      });\n    });\n  });\n\n  describe('createGroupEvent', () => {\n    test('should create group event', () => {\n      const eventOptions = { user_id: 'userId', device_id: 'deviceId' };\n      const event = createGroupEvent('a', 'b', eventOptions);\n      expect(event).toEqual({\n        event_type: SpecialEventType.IDENTIFY,\n        user_properties: {\n          $set: {\n            a: 'b',\n          },\n        },\n        groups: {\n          a: 'b',\n        },\n        user_id: 'userId',\n        device_id: 'deviceId',\n      });\n    });\n\n    test('should handle missing event options', () => {\n      const event = createGroupEvent('a', 'b');\n      expect(event).toEqual({\n        event_type: SpecialEventType.IDENTIFY,\n        user_properties: {\n          $set: {\n            a: 'b',\n          },\n        },\n        groups: {\n          a: 'b',\n        },\n      });\n    });\n  });\n\n  describe('createGroupIdentifyEvent', () => {\n    test('should create event', () => {\n      const groupType = 'groupType';\n      const groupName = 'groupName';\n      const identify = new Identify();\n      const eventOptions = { user_id: 'userId', device_id: 'deviceId' };\n      const event = createGroupIdentifyEvent(groupType, groupName, identify, eventOptions);\n      expect(event).toEqual({\n        event_type: SpecialEventType.GROUP_IDENTIFY,\n        group_properties: {},\n        groups: {\n          groupType: 'groupName',\n        },\n        user_id: 'userId',\n        device_id: 'deviceId',\n      });\n    });\n\n    test('should handle missing deviceId', () => {\n      const groupType = 'groupType';\n      const groupName = 'groupName';\n      const identify = new Identify();\n      const event = createGroupIdentifyEvent(groupType, groupName, identify);\n      expect(event).toEqual({\n        event_type: SpecialEventType.GROUP_IDENTIFY,\n        group_properties: {},\n        groups: {\n          groupType: 'groupName',\n        },\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/utils/json-query.test.ts",
    "content": "import { isPathMatch, tokenizeJsonPath, pruneJson } from '../../src/utils/json-query';\n\ndescribe('pruneJson', () => {\n  describe('empty json', () => {\n    test('should pass through null objects', () => {\n      const obj = null;\n      pruneJson(obj, ['a'], []);\n      expect(obj).toEqual(null);\n    });\n\n    test('should pass through undefined objects', () => {\n      const obj = undefined;\n      pruneJson(obj, ['a'], []);\n      expect(obj).toEqual(undefined);\n    });\n  });\n\n  describe('flat json', () => {\n    describe('top level keys', () => {\n      test('should match single key', () => {\n        const obj = { a: 'b', c: 'd' };\n        pruneJson(obj, ['a'], []);\n        expect(obj).toEqual({ a: 'b' });\n      });\n\n      test('should match multiple keys', () => {\n        const obj = { a: 'b', c: 'd', e: 'f' };\n        pruneJson(obj, ['a', 'c'], []);\n        expect(obj).toEqual({ a: 'b', c: 'd' });\n      });\n\n      test('should match multiple keys with wildcards', () => {\n        const obj = { a: 'b', c: 'd', e: 'f' };\n        pruneJson(obj, ['*'], ['e']);\n        expect(obj).toEqual({ a: 'b', c: 'd' });\n      });\n    });\n  });\n\n  describe('one level deep', () => {\n    test('should match single key', () => {\n      const obj = { a: { b: 'c', d: 'e' } };\n      pruneJson(obj, ['a/b'], []);\n      expect(obj).toEqual({ a: { b: 'c' } });\n    });\n\n    test('should match with **', () => {\n      const obj = { a: { b: { c: 'd', e: 'f' } } };\n      pruneJson(obj, ['a/**'], ['a/b/e']);\n      expect(obj).toEqual({ a: { b: { c: 'd' } } });\n    });\n\n    test('should match with *', () => {\n      const obj = { a: { b: { c: 'd', e: 'f' }, e: 'f' } };\n      pruneJson(obj, ['a/*'], []);\n      expect(obj).toEqual({ a: { e: 'f' } });\n    });\n\n    test('should cleanup empty objects', () => {\n      const obj = { a: { b: { c: 'd' }, e: 'f' } };\n      pruneJson(obj, ['a/b'], []);\n      expect(obj).toEqual({});\n    });\n\n    test('exclude same as allow should return empty object', () => {\n      const obj = { a: { b: { c: 'd' }, e: 'f' } };\n      pruneJson(obj, ['*'], ['*']);\n      expect(obj).toEqual({});\n    });\n\n    test('should exclude keys not include in allowlist', () => {\n      const obj = { a: { b: { c: 'd' } }, e: 'f' };\n      pruneJson(obj, ['*'], ['a']);\n      expect(obj).toEqual({ e: 'f' });\n    });\n  });\n\n  describe('two levels deep', () => {\n    test('should match single key', () => {\n      const obj = { a: { b: { c: 'd', e: 'f' } } };\n      pruneJson(obj, ['a/b/c'], []);\n      expect(obj).toEqual({ a: { b: { c: 'd' } } });\n    });\n\n    test('should match with **', () => {\n      const obj = { a: { b: { c: 'd', e: 'f' } } };\n      pruneJson(obj, ['a/**'], []);\n      expect(obj).toEqual({ a: { b: { c: 'd', e: 'f' } } });\n    });\n\n    test('should match with *', () => {\n      const obj = { a: { b: { c: 'd', e: 'f' }, e: 'f' } };\n      pruneJson(obj, ['a/*'], []);\n      expect(obj).toEqual({ a: { e: 'f' } });\n    });\n\n    test('should cleanup empty objects', () => {\n      const obj = { a: { b: { c: 'd', e: 'f' } }, g: 'h' };\n      pruneJson(obj, ['*'], []);\n      expect(obj).toEqual({ g: 'h' });\n    });\n\n    test('should not cleanup empty objects if they are not empty', () => {\n      const obj = { a: { b: { c: 'd' }, e: 'f' } };\n      pruneJson(obj, ['a/*'], []);\n      expect(obj).toEqual({ a: { e: 'f' } });\n    });\n\n    test('should match on **', () => {\n      const obj = { a: { b: { c: 'd', e: 'f' } }, g: 'h' };\n      pruneJson(obj, ['a/**'], []);\n      expect(obj).toEqual({ a: { b: { c: 'd', e: 'f' } } });\n    });\n  });\n\n  describe('three levels deep', () => {\n    test('should match on *', () => {\n      const obj = { a: { f: 'f', b: { c: { d: 'e', f: 'f' } } } };\n      pruneJson(obj, ['*/f'], []);\n      expect(obj).toEqual({ a: { f: 'f' } });\n    });\n\n    test('should match any key after **', () => {\n      const obj = { a: { f: 'f', b: { c: { d: 'e', f: 'f' } } } };\n      pruneJson(obj, ['**/f'], []);\n      expect(obj).toEqual({ a: { f: 'f', b: { c: { f: 'f' } } } });\n    });\n    test('should exclude everything if exclude list is **', () => {\n      const obj = { a: { b: { c: 'd', e: 'f' } }, g: 'h' };\n      pruneJson(obj, ['a/g'], ['**']);\n      expect(obj).toEqual({});\n    });\n  });\n\n  describe('arrays', () => {\n    test('should match on *', () => {\n      const obj = { a: [1, 2, 3] };\n      pruneJson(obj, ['a/*'], []);\n      expect(obj).toEqual({ a: [1, 2, 3] });\n    });\n\n    test('should match on specific index', () => {\n      const obj = { a: [1, 2, 3] };\n      pruneJson(obj, ['a/1'], []);\n      expect(obj).toEqual({ a: [undefined, 2, undefined] });\n    });\n\n    test('should match all indices with * but exclude specific index', () => {\n      const obj = { a: [1, 2, 3] };\n      pruneJson(obj, ['a/*'], ['a/1']);\n      expect(obj).toEqual({ a: [1, undefined, 3] });\n    });\n  });\n});\n\ndescribe('tokenizePath', () => {\n  test('should tokenize paths with /', () => {\n    expect(tokenizeJsonPath('a/b/c')).toEqual(['a', 'b', 'c']);\n    expect(tokenizeJsonPath('a/*/**/c')).toEqual(['a', '*', '**', 'c']);\n  });\n\n  test('should accept leading /', () => {\n    expect(tokenizeJsonPath('/a/b/c')).toEqual(['a', 'b', 'c']);\n    expect(tokenizeJsonPath('/a/*/**/c')).toEqual(['a', '*', '**', 'c']);\n  });\n\n  test('should tokenize paths with single token', () => {\n    expect(tokenizeJsonPath('a')).toEqual(['a']);\n    expect(tokenizeJsonPath('a*')).toEqual(['a*']);\n  });\n\n  test('should translate ~0 to ~', () => {\n    expect(tokenizeJsonPath('a/b~0~0c/c~0~0d')).toEqual(['a', 'b~~c', 'c~~d']);\n  });\n\n  test('should translate ~1 to /', () => {\n    expect(tokenizeJsonPath('a/b~1~1c/c~1~1d')).toEqual(['a', 'b//c', 'c//d']);\n  });\n\n  test('should not translate ~ if not in ~0 or ~1', () => {\n    expect(tokenizeJsonPath('a/b~c/c~d')).toEqual(['a', 'b~c', 'c~d']);\n  });\n});\n\ndescribe('isPathMatching', () => {\n  describe('should be true', () => {\n    test('if path and patchMatcher are identical', () => {\n      expect(isPathMatch(['a'], ['a'])).toBe(true);\n      expect(isPathMatch(['a', 'b'], ['a', 'b'])).toBe(true);\n      expect(isPathMatch(['a', 'b', 'c'], ['a', 'b', 'c'])).toBe(true);\n    });\n\n    test('if path and patchMatchers match with wildcards', () => {\n      expect(isPathMatch(['a'], ['*'])).toBe(true);\n      expect(isPathMatch(['a', 'b'], ['a', '*'])).toBe(true);\n      expect(isPathMatch(['a', 'b', 'c'], ['a', '*', 'c'])).toBe(true);\n      expect(isPathMatch(['a', 'b', 'c'], ['*', '*', '*'])).toBe(true);\n    });\n\n    test('if pathMatcher is double wildcard (**)', () => {\n      expect(isPathMatch(['a'], ['**'])).toBe(true);\n      expect(isPathMatch(['a', 'b', 'c'], ['**'])).toBe(true);\n      expect(isPathMatch(['a', 'b'], ['a', '**'])).toBe(true);\n      expect(isPathMatch(['a', 'b', 'c'], ['a', '**'])).toBe(true);\n      expect(isPathMatch(['a', 'b', 'c', 'b', 'd'], ['a', '**', 'b', 'd'])).toBe(true);\n      expect(isPathMatch(['a', 'b'], ['a', '**', 'b'])).toBe(true);\n    });\n  });\n\n  describe('should be false', () => {\n    test('if path and patchMatchers do not match (no wildcards)', () => {\n      expect(isPathMatch(['a'], ['b'])).toBe(false);\n      expect(isPathMatch(['a', 'b'], ['a'])).toBe(false);\n      expect(isPathMatch(['a', 'b', 'c'], ['a', 'b', 'd'])).toBe(false);\n    });\n\n    test('if path and patchMatchers do not match (wildcard)', () => {\n      expect(isPathMatch(['a', 'b', 'c'], ['a', 'b', 'c', '*'])).toBe(false);\n      expect(isPathMatch(['a', 'b', 'c'], ['a', 'b', '*', 'c'])).toBe(false);\n      expect(isPathMatch(['a', 'b', 'c'], ['*', '*'])).toBe(false);\n    });\n\n    test('if path and patchMatchers do not match (double wildcard)', () => {\n      expect(isPathMatch(['a', 'b', 'c'], ['a', '**', 'b', 'd'])).toBe(false);\n      expect(isPathMatch(['a', 'b', 'c'], ['a', '**', 'd'])).toBe(false);\n      expect(isPathMatch(['a', 'b', 'c'], ['a', '**', '**', 'd'])).toBe(false);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/utils/observable.test.ts",
    "content": "import { Observable, asyncMap, merge, multicast } from '../../src/index';\n\n/* eslint-disable jest/no-conditional-expect, @typescript-eslint/no-empty-function */\n\n// Test helper functions\nconst createTimedObservable = <T>(values: T[], delay = 10): Observable<T> => {\n  return new Observable<T>((observer) => {\n    values.forEach((value, index) => {\n      setTimeout(() => observer.next(value), index * delay);\n    });\n    setTimeout(() => observer.complete(), values.length * delay + 10);\n  });\n};\n\nconst createEmptyObservable = (delay = 10): Observable<any> => {\n  return new Observable<any>((observer) => {\n    setTimeout(() => observer.complete(), delay);\n  });\n};\n\nconst createImmediateErrorObservable = <T>(error: Error): Observable<T> => {\n  return new Observable<T>((observer) => {\n    setTimeout(() => observer.error(error), 10);\n  });\n};\n\nconst createObservableWithUnsubscribe = <T>(\n  values: T[],\n  onSubscribe: () => void,\n  onUnsubscribe: () => void,\n): Observable<T> => {\n  return new Observable<T>((observer) => {\n    onSubscribe();\n    values.forEach((value, index) => {\n      setTimeout(() => observer.next(value), index * 10);\n    });\n    setTimeout(() => observer.complete(), values.length * 10 + 10);\n    return onUnsubscribe;\n  });\n};\n\ninterface SubscriptionResult<T> {\n  results: T[];\n  errors: any[];\n  completed: boolean;\n}\n\nconst subscribeToObservable = <T>(observable: Observable<T>): Promise<SubscriptionResult<T>> => {\n  return new Promise<SubscriptionResult<T>>((resolve) => {\n    const result: SubscriptionResult<T> = {\n      results: [],\n      errors: [],\n      completed: false,\n    };\n\n    observable.subscribe({\n      next: (value: T) => result.results.push(value),\n      error: (error: any) => result.errors.push(error),\n      complete: () => {\n        result.completed = true;\n        resolve(result);\n      },\n    });\n  });\n};\n\nconst subscribeToObservableWithError = <T>(observable: Observable<T>): Promise<SubscriptionResult<T>> => {\n  return new Promise<SubscriptionResult<T>>((resolve) => {\n    const result: SubscriptionResult<T> = {\n      results: [],\n      errors: [],\n      completed: false,\n    };\n\n    observable.subscribe({\n      next: (value: T) => result.results.push(value),\n      error: (error: any) => {\n        result.errors.push(error);\n        resolve(result);\n      },\n      complete: () => {\n        result.completed = true;\n        resolve(result);\n      },\n    });\n  });\n};\n\ninterface MultiObserverResult<T> {\n  observer1: SubscriptionResult<T>;\n  observer2: SubscriptionResult<T>;\n  observer3?: SubscriptionResult<T>;\n}\n\nconst subscribeMultipleObservers = <T>(\n  observable: Observable<T>,\n  observerCount: 2 | 3 = 2,\n): Promise<MultiObserverResult<T>> => {\n  return new Promise<MultiObserverResult<T>>((resolve) => {\n    const results: MultiObserverResult<T> = {\n      observer1: { results: [], errors: [], completed: false },\n      observer2: { results: [], errors: [], completed: false },\n    };\n\n    if (observerCount === 3) {\n      results.observer3 = { results: [], errors: [], completed: false };\n    }\n\n    let completedCount = 0;\n    const checkComplete = () => {\n      completedCount++;\n      const expectedCount = observerCount;\n      if (completedCount === expectedCount) {\n        resolve(results);\n      }\n    };\n\n    observable.subscribe({\n      next: (value: T) => results.observer1.results.push(value),\n      error: (error: any) => {\n        results.observer1.errors.push(error);\n        checkComplete();\n      },\n      complete: () => {\n        results.observer1.completed = true;\n        checkComplete();\n      },\n    });\n\n    observable.subscribe({\n      next: (value: T) => results.observer2.results.push(value),\n      error: (error: any) => {\n        results.observer2.errors.push(error);\n        checkComplete();\n      },\n      complete: () => {\n        results.observer2.completed = true;\n        checkComplete();\n      },\n    });\n\n    if (observerCount === 3 && results.observer3) {\n      observable.subscribe({\n        next: (value: T) => results.observer3!.results.push(value),\n        error: (error: any) => {\n          results.observer3!.errors.push(error);\n          checkComplete();\n        },\n        complete: () => {\n          results.observer3!.completed = true;\n          checkComplete();\n        },\n      });\n    }\n  });\n};\n\ndescribe('asyncMap', () => {\n  test('should map values using async function and emit results in order', async () => {\n    const source = createTimedObservable([1, 2, 3]);\n    const asyncFn = jest.fn((value: number) => Promise.resolve(value * 2));\n    const mappedObservable = asyncMap(source, asyncFn);\n    const result = await subscribeToObservable(mappedObservable);\n\n    expect(result.results).toEqual([2, 4, 6]);\n    expect(result.errors).toHaveLength(0);\n    expect(result.completed).toBe(true);\n  });\n\n  test('should handle async function errors', async () => {\n    const source = createTimedObservable([1, 2, 3]);\n    const asyncFn = jest.fn((value: number) => {\n      if (value === 2) {\n        return Promise.reject(new Error('Test error'));\n      }\n      return Promise.resolve(value);\n    });\n\n    const mappedObservable = asyncMap(source, asyncFn);\n    const result = await subscribeToObservableWithError(mappedObservable);\n\n    expect(result.errors[0].message).toBe('Test error');\n    expect(result.results).toEqual([1]); // Only first value should be emitted\n    expect(asyncFn).toHaveBeenCalledTimes(2); // Called for 1 and 2\n  });\n\n  test('should handle source observable errors', async () => {\n    const source = new Observable<number>((observer) => {\n      setTimeout(() => observer.next(1), 10);\n      setTimeout(() => observer.error(new Error('Source error')), 20);\n    });\n\n    const asyncFn = jest.fn((value: number) => Promise.resolve(value * 2));\n    const mappedObservable = asyncMap(source, asyncFn);\n    const result = await subscribeToObservableWithError(mappedObservable);\n\n    expect(result.errors[0].message).toBe('Source error');\n    expect(result.results).toEqual([2]); // First value should be processed\n    expect(asyncFn).toHaveBeenCalledTimes(1);\n  });\n\n  test('should handle empty source observable', async () => {\n    const source = createEmptyObservable();\n    const asyncFn = jest.fn((value: any) => Promise.resolve(value));\n    const mappedObservable = asyncMap(source, asyncFn);\n    const result = await subscribeToObservable(mappedObservable);\n\n    expect(result.results).toHaveLength(0);\n    expect(result.errors).toHaveLength(0);\n    expect(result.completed).toBe(true);\n    expect(asyncFn).not.toHaveBeenCalled();\n  });\n});\n\ndescribe('merge', () => {\n  beforeEach(() => {\n    jest.useFakeTimers();\n  });\n\n  afterEach(() => {\n    jest.useRealTimers();\n  });\n\n  test('should merge two observables', async () => {\n    const source1 = new Observable<number>((observer) => {\n      observer.next(1);\n      observer.complete();\n    });\n    const source2 = new Observable<number>((observer) => {\n      observer.next(2);\n      observer.complete();\n    });\n    const mergedObservable = merge(source1, source2);\n    const results: number[] = [];\n    mergedObservable.subscribe((value) => {\n      results.push(value);\n    });\n    await jest.runAllTimersAsync();\n    expect(results).toEqual([1, 2]);\n  });\n\n  test('should error if one of the observables errors', async () => {\n    const source1 = new Observable<number>((observer) => {\n      observer.next(1);\n    });\n    const source2 = new Observable<number>((observer) => {\n      setTimeout(() => {\n        observer.error(new Error('Error'));\n      }, 10);\n    });\n    const mergedObservable = merge(source1, source2);\n    const results: number[] = [];\n    const errors: Error[] = [];\n    mergedObservable.subscribe({\n      next: (value) => results.push(value),\n      error: (error) => errors.push(error as Error),\n      complete: () => {},\n    });\n    await jest.runAllTimersAsync();\n    expect(results).toEqual([1]);\n    expect(errors).toEqual([new Error('Error')]);\n  });\n});\n\ndescribe('multicast', () => {\n  test('should multicast values to multiple observers', async () => {\n    const source = createTimedObservable([1, 2, 3]);\n    const multicasted = multicast(source);\n    const results = await subscribeMultipleObservers(multicasted);\n\n    expect(results.observer1.results).toEqual([1, 2, 3]);\n    expect(results.observer2.results).toEqual([1, 2, 3]);\n    expect(results.observer1.completed).toBe(true);\n    expect(results.observer2.completed).toBe(true);\n  });\n\n  test('should only subscribe to source once with multiple observers', async () => {\n    let subscriptionCount = 0;\n    const source = new Observable<number>((observer) => {\n      subscriptionCount++;\n      setTimeout(() => observer.next(1), 10);\n      setTimeout(() => observer.next(2), 20);\n      setTimeout(() => observer.complete(), 30);\n    });\n\n    const multicasted = multicast(source);\n    const results = await subscribeMultipleObservers(multicasted, 3);\n\n    expect(subscriptionCount).toBe(1); // Should only subscribe once\n    expect(results.observer1.results).toEqual([1, 2]);\n    expect(results.observer2.results).toEqual([1, 2]);\n    expect(results.observer3!.results).toEqual([1, 2]);\n  });\n\n  test('should unsubscribe from source when all observers unsubscribe', async () => {\n    let isSubscribed = false;\n    let isUnsubscribed = false;\n    const source = createObservableWithUnsubscribe(\n      [1],\n      () => {\n        isSubscribed = true;\n      },\n      () => {\n        isUnsubscribed = true;\n      },\n    );\n\n    const multicasted = multicast(source);\n\n    const unsubscribe1 = multicasted.subscribe({\n      next: () => {},\n      complete: () => {},\n    });\n\n    const unsubscribe2 = multicasted.subscribe({\n      next: () => {},\n      complete: () => {},\n    });\n\n    // Wait for subscription to be established\n    await new Promise((resolve) => setTimeout(resolve, 5));\n    expect(isSubscribed).toBe(true);\n\n    // Unsubscribe all observers\n    unsubscribe1.unsubscribe();\n    unsubscribe2.unsubscribe();\n\n    // Wait a bit to ensure cleanup happens\n    await new Promise((resolve) => setTimeout(resolve, 5));\n    expect(isUnsubscribed).toBe(true);\n  });\n\n  test('should propagate completion to all observers', async () => {\n    const source = createTimedObservable([1, 2]);\n    const multicasted = multicast(source);\n    const results = await subscribeMultipleObservers(multicasted);\n\n    expect(results.observer1.results).toEqual([1, 2]);\n    expect(results.observer2.results).toEqual([1, 2]);\n    expect(results.observer1.completed).toBe(true);\n    expect(results.observer2.completed).toBe(true);\n  });\n\n  test('should handle empty source observable', async () => {\n    const source = createEmptyObservable();\n    const multicasted = multicast(source);\n    const results = await subscribeMultipleObservers(multicasted);\n\n    expect(results.observer1.results).toHaveLength(0);\n    expect(results.observer2.results).toHaveLength(0);\n    expect(results.observer1.completed).toBe(true);\n    expect(results.observer2.completed).toBe(true);\n  });\n\n  test('should handle source that errors immediately', async () => {\n    const multicasted = multicast(createImmediateErrorObservable(new Error('Immediate error')));\n    const results = await subscribeMultipleObservers(multicasted);\n\n    expect(results.observer1.errors).toHaveLength(1);\n    expect(results.observer2.errors).toHaveLength(1);\n    expect(results.observer1.errors[0].message).toBe('Immediate error');\n    expect(results.observer2.errors[0].message).toBe('Immediate error');\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/utils/omit-undefined.test.ts",
    "content": "import { omitUndefined } from '../../src/utils/omit-undefined';\n\ndescribe('omitUndefined', () => {\n  test('should omit undefined and empty values', () => {\n    expect(\n      omitUndefined({\n        utm_source: 'google',\n        utm_medium: '',\n        utm_campaign: undefined,\n      }),\n    ).toEqual({\n      utm_source: 'google',\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/utils/result-builder.test.ts",
    "content": "import { Status } from '../../src/types/status';\nimport { buildResult } from '../../src/utils/result-builder';\n\ndescribe('buildResult', () => {\n  test('should return success', () => {\n    const event = {\n      event_type: 'hello',\n    };\n    const result = buildResult(event, 200, Status.Success);\n    expect(result.event).toBeDefined();\n    expect(result.code).toBe(200);\n    expect(result.message).toBe(Status.Success);\n  });\n\n  test('should return default values', () => {\n    const event = {\n      event_type: 'hello',\n    };\n    const result = buildResult(event);\n    expect(result.code).toBe(0);\n    expect(result.message).toBe(Status.Unknown);\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/utils/return-wrapper.test.ts",
    "content": "import { returnWrapper } from '../../src/utils/return-wrapper';\n\ndescribe('return-wrapper', () => {\n  test('should undefined in promise interface', async () => {\n    const value = await returnWrapper().promise;\n    expect(value).toEqual(undefined);\n  });\n\n  test('should value in promise interface', async () => {\n    const fn = async () => {\n      return 1;\n    };\n    const value = await returnWrapper(fn()).promise;\n    expect(value).toEqual(1);\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/utils/safe-stringify.test.ts",
    "content": "import { safeJsonStringify } from '../../src/index';\n\ndescribe('safeJsonStringify', () => {\n  test('should stringify a simple object', () => {\n    const obj = { name: 'test', value: 123 };\n    const result = safeJsonStringify(obj);\n    expect(typeof result).toBe('string');\n    expect(JSON.parse(result)).toEqual(obj);\n  });\n\n  test('should handle circular references safely', () => {\n    const obj: any = { name: 'test' };\n    obj.circular = obj; // Create circular reference\n\n    // safe-json-stringify should handle this without throwing\n    const result = safeJsonStringify(obj);\n    expect(typeof result).toBe('string');\n    expect(result).toContain('name');\n    expect(result).toContain('test');\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/utils/sampling.test.ts",
    "content": "import { generateHashCode, isTimestampInSample } from '../../src/utils/sampling';\n\ndescribe('Sampling utilities', () => {\n  describe('generateHashCode', () => {\n    test('should return 0 if string length is 0', () => {\n      const hashCode = generateHashCode('');\n      expect(hashCode).toEqual(0);\n    });\n    test('should return hash for numeric string', () => {\n      const hashCode = generateHashCode('1691093770366');\n      expect(hashCode).toEqual(139812688);\n    });\n    test('should return hash for alphabetic string', () => {\n      const hashCode = generateHashCode('my_session_identifier');\n      expect(hashCode).toEqual(989939557);\n    });\n  });\n\n  describe('isTimestampInSample', () => {\n    test('should deterministically return true if calculation puts timestamp below sample rate', () => {\n      const result = isTimestampInSample(1691092433788, 0.56);\n      expect(result).toEqual(true);\n    });\n    test('should deterministically return false if calculation puts timestamp above sample rate', () => {\n      const result = isTimestampInSample(1691092416403, 0.13);\n      expect(result).toEqual(false);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/utils/url-utils.test.ts",
    "content": "import { getDecodeURI, isUrlMatchAllowlist } from '../../src/';\n\ndescribe('isUrlMatchAllowlist', () => {\n  const url = 'https://amplitude.com/blog';\n\n  test('should return true when allow list is not provided', () => {\n    const result = isUrlMatchAllowlist(url, undefined);\n    expect(result).toEqual(true);\n  });\n\n  test('should return true when allow list is empty', () => {\n    const result = isUrlMatchAllowlist(url, []);\n    expect(result).toEqual(true);\n  });\n\n  test('should return true only when full url string is in the allow list', () => {\n    let result = isUrlMatchAllowlist(url, ['https://amplitude.com/blog']);\n    expect(result).toEqual(true);\n\n    result = isUrlMatchAllowlist('https://amplitude.com/market', ['https://amplitude.com/blog']);\n    expect(result).toEqual(false);\n  });\n\n  test('should return true when url regex is in the allow list', () => {\n    let result = isUrlMatchAllowlist(url, [new RegExp('https://amplitude.com/')]);\n    expect(result).toEqual(true);\n\n    result = isUrlMatchAllowlist('https://amplitude.com/market', [new RegExp('https://amplitude.com/')]);\n    expect(result).toEqual(true);\n  });\n\n  test('should return false when url is not in the allow list at all', () => {\n    const result = isUrlMatchAllowlist(url, ['https://test.com', new RegExp('https://test.com/')]);\n    expect(result).toEqual(false);\n  });\n\n  test('should return true when url is matching an item in the allow list with regex wildcard', () => {\n    const result = isUrlMatchAllowlist(url, [new RegExp('http.?://amplitude.*'), new RegExp('http.?://test.*')]);\n    expect(result).toEqual(true);\n  });\n});\n\ndescribe('getDecodeURI', () => {\n  test('should decode URI', () => {\n    const result = getDecodeURI('https://www.topps.com/products/2025-bowman-chrome%C2%AE-baseball-mega-box');\n    expect(result).toEqual('https://www.topps.com/products/2025-bowman-chrome®-baseball-mega-box');\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/utils/uuid.test.ts",
    "content": "import { UUID } from '../../src/utils/uuid';\n\ndescribe('UUID', () => {\n  const testUuids = {} as Record<string, boolean>;\n\n  function assertUuidFormat(uuid: string) {\n    expect(uuid.length).toEqual(36);\n    expect(uuid.charAt(14)).toEqual('4');\n    expect(['8', '9', 'a', 'b'].includes(uuid.charAt(19))).toEqual(true);\n    expect(uuid).toMatch(/^[0-9a-fA-F-]+$/);\n    const tokens = uuid.split('-');\n    expect(tokens.length).toEqual(5);\n    expect(tokens[0].length).toEqual(8);\n    expect(tokens[1].length).toEqual(4);\n    expect(tokens[2].length).toEqual(4);\n    expect(tokens[3].length).toEqual(4);\n    expect(tokens[4].length).toEqual(12);\n    expect(testUuids[uuid]).toEqual(undefined); // check for duplicates\n    testUuids[uuid] = true;\n  }\n\n  /* eslint-disable @typescript-eslint/no-unsafe-member-access */\n  /* eslint-disable @typescript-eslint/no-unsafe-call */\n  test('should generate a valid UUID-4', () => {\n    // polyfill getRandomValues for Node < 20\n    // this is not needed in Node >= 20\n    if (!globalThis.crypto?.getRandomValues) {\n      (globalThis as any).crypto = {\n        getRandomValues: (arr: Uint8Array) => {\n          for (let i = 0; i < arr.length; i++) {\n            arr[i] = Math.floor(Math.random() * 256);\n          }\n          return arr;\n        },\n      };\n    }\n    const uuid = UUID();\n    assertUuidFormat(uuid);\n  });\n\n  test('should generate a valid UUID-4 (no native Crypto)', () => {\n    /* eslint-disable @typescript-eslint/no-unsafe-assignment */\n    const backupCrypto = (global as any).crypto;\n    Object.defineProperty(global, 'crypto', {\n      value: null,\n      writable: true,\n    });\n\n    try {\n      // Generate 100 UUIDs and check that they are all valid UUIDs\n      for (let i = 0; i < 100; i++) {\n        const uuid = UUID();\n        assertUuidFormat(uuid);\n      }\n    } finally {\n      // Restore the original crypto object\n      (global as any).crypto = backupCrypto;\n    }\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/utils/valid-properties.test.ts",
    "content": "import { isValidProperties } from '../../src/utils/valid-properties';\n\ndescribe('isValidProperties', () => {\n  test('should pass on valid properties', () => {\n    const validProperties = {\n      keyForString: 'stringValue',\n      keyForNumber: 123,\n      keyForArray: ['test', 456, { arrayObjKey1: 'arrayObjValue1' }],\n      keyForObj: {\n        objKey1: 'objValue1',\n        objKey2: 'objValue2',\n      },\n    };\n    expect(isValidProperties('property', validProperties)).toBe(true);\n  });\n\n  test('should fail on invalid object with property keys more than MAX_PROPERTY_KEYS', () => {\n    const inValidProperties: { [key: string]: number } = Array(1001)\n      .fill(true)\n      .reduce((acc: { [key: string]: number }, _, index) => {\n        acc[`key-${index}`] = index;\n        return acc;\n      }, {});\n\n    expect(isValidProperties('property', inValidProperties)).toBe(false);\n  });\n\n  test('should fail on invalid properties with function as value', () => {\n    const testFunc = (): string => {\n      return 'test';\n    };\n    const inValidProperties = {\n      keyForFunct: testFunc,\n    };\n    expect(isValidProperties('property', inValidProperties)).toBe(false);\n  });\n\n  test('should fail on invalid properties with array nested in array', () => {\n    const inValidProperties = ['item1', 123, ['subItem1', 'subItem2']];\n    expect(isValidProperties('property', inValidProperties)).toBe(false);\n  });\n\n  test('should fail on invalid property with no number and no string value', () => {\n    const inValidProperties = [true, false, false];\n    expect(isValidProperties('property', inValidProperties)).toBe(false);\n  });\n\n  test('should fail on invalid property with invalid object in array', () => {\n    const inValidProperties = [{ keyForString: 'stringValue' }, { keyForString: [['stringValue']] }, 15];\n    expect(isValidProperties('property', inValidProperties)).toBe(false);\n  });\n\n  test('should fail when any key is not string', () => {\n    const validProperties = {\n      keyForString: 'stringValue',\n      keyForNumber: 123,\n      keyForArray: ['test', 456],\n      keyForObj: {\n        objKey1: 'objValue1',\n        objKey2: 'objValue2',\n      },\n    };\n\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n    expect(isValidProperties(1 as any, validProperties)).toBe(false);\n  });\n\n  test('should return false for null value', () => {\n    expect(isValidProperties('key', null)).toBe(false);\n  });\n\n  test('should return false for undefined value', () => {\n    expect(isValidProperties('key', undefined)).toBe(false);\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/test/video-analytics/mock-video.ts",
    "content": "import type { EmbeddedVideoPlayer, VideoHandler } from '../../src/video-analytics/types';\n\nexport type MockEmbeddedVideoPlayer = EmbeddedVideoPlayer & {\n  emit: (event: string) => void;\n  setCurrentTime: (time: number) => void;\n};\n\n/**\n * Minimal player.js-style mock for {@link trackEmbeddedVideo} tests.\n */\nexport function createMockEmbeddedVideoPlayer(options?: {\n  playbackId?: string;\n  metadataVideoTitle?: string;\n  metadataVideoId?: string;\n}): { player: MockEmbeddedVideoPlayer } {\n  const playbackId = options?.playbackId ?? 'dE02GfTAlJD4RcqNAlgiS2m00LqbdFqlBm';\n  const metadataVideoTitle = options?.metadataVideoTitle ?? 'My Video';\n  const metadataVideoId = options?.metadataVideoId ?? 'video-123';\n\n  const params = new URLSearchParams({\n    'metadata-video-title': metadataVideoTitle,\n    'metadata-video-id': metadataVideoId,\n  });\n  const iframe = document.createElement('iframe');\n  iframe.setAttribute('src', `https://player.mux.com/${playbackId}?${params.toString()}`);\n\n  const listeners = new Map<string, Set<() => void>>();\n  let currentTime = 0;\n  const duration = 10;\n\n  const on = (event: string, callback: () => void) => {\n    let set = listeners.get(event);\n    if (!set) {\n      set = new Set();\n      listeners.set(event, set);\n    }\n    set.add(callback);\n  };\n\n  const off = (event: string, callback: () => void) => {\n    listeners.get(event)?.delete(callback);\n  };\n\n  const emit = (event: string) => {\n    const cbs = listeners.get(event);\n    if (cbs) {\n      [...cbs].forEach((cb) => {\n        cb();\n      });\n    }\n  };\n\n  const getDuration = (cb: (d: number) => void) => {\n    cb(duration);\n  };\n\n  const getCurrentTime = (cb: (t: number) => void) => {\n    cb(currentTime);\n  };\n\n  const player: MockEmbeddedVideoPlayer = {\n    elem: iframe,\n    on,\n    off,\n    getDuration,\n    getCurrentTime,\n    emit,\n    setCurrentTime(t: number) {\n      currentTime = t;\n    },\n  };\n\n  return { player };\n}\n\nexport function createMockVideo(options: { isMux: boolean } = { isMux: false }): {\n  video: HTMLVideoElement;\n  handler: VideoHandler;\n} {\n  const video = document.createElement('video');\n\n  if (options.isMux) {\n    video.setAttribute('playback-id', 'playback-id-123');\n    video.setAttribute('metadata-video-id', 'video-id-123');\n    video.setAttribute('metadata-video-title', 'video title');\n  }\n\n  Object.defineProperty(HTMLMediaElement.prototype, 'play', {\n    configurable: true,\n    value: jest.fn(() => {\n      Object.defineProperty(video, 'duration', {\n        configurable: true,\n        value: 10,\n      });\n      video.dispatchEvent(new Event('play'));\n      return Promise.resolve(undefined);\n    }),\n  });\n\n  Object.defineProperty(HTMLMediaElement.prototype, 'pause', {\n    configurable: true,\n    value: jest.fn(() => {\n      Object.defineProperty(video, 'currentTime', {\n        configurable: true,\n        value: 5,\n      });\n      video.dispatchEvent(new Event('pause'));\n      return Promise.resolve(undefined);\n    }),\n  });\n\n  Object.defineProperty(HTMLMediaElement.prototype, 'ended', {\n    configurable: true,\n    value: jest.fn(() => {\n      Object.defineProperty(video, 'currentTime', {\n        configurable: true,\n        value: 10,\n      });\n      video.dispatchEvent(new Event('ended'));\n      return Promise.resolve(undefined);\n    }),\n  });\n\n  Object.defineProperty(HTMLMediaElement.prototype, 'simulateSeek', {\n    configurable: true,\n    value: jest.fn(function (this: HTMLVideoElement, time?: number) {\n      Object.defineProperty(this, 'currentTime', {\n        configurable: true,\n        value: time ?? 3,\n      });\n      Object.defineProperty(this, 'seeking', { configurable: true, value: true });\n      this.dispatchEvent(new Event('seeking'));\n      return Promise.resolve(undefined);\n    }),\n  });\n\n  Object.defineProperty(HTMLMediaElement.prototype, 'seeked', {\n    configurable: true,\n    value: jest.fn(function (this: HTMLVideoElement, time?: number) {\n      if (time !== undefined) {\n        Object.defineProperty(this, 'currentTime', {\n          configurable: true,\n          value: time,\n        });\n      }\n      Object.defineProperty(this, 'seeking', { configurable: true, value: false });\n      this.dispatchEvent(new Event('seeked'));\n      return Promise.resolve(undefined);\n    }),\n  });\n\n  video.src = 'https://example.com/video.mp4';\n  video.width = 640;\n  video.height = 360;\n  video.muted = true;\n  video.controls = true;\n\n  document.body.appendChild(video);\n\n  const handler: VideoHandler = {\n    onPlay: jest.fn(),\n    onPause: jest.fn(),\n    onEnded: jest.fn(),\n    onError: jest.fn(),\n    onSeeking: jest.fn(),\n    onSeeked: jest.fn(),\n    onTimeUpdate: jest.fn(),\n  };\n\n  return { video, handler };\n}\n"
  },
  {
    "path": "packages/analytics-core/test/video-analytics/track-video.test.ts",
    "content": "/**\n * @jest-environment jsdom\n */\n\n/* eslint-disable @typescript-eslint/no-floating-promises */\n\nimport { trackHtmlVideo, trackEmbeddedVideo } from '../../src/video-analytics/track-video';\nimport type { VideoHandler } from '../../src/video-analytics/types';\nimport { createMockEmbeddedVideoPlayer, createMockVideo } from './mock-video';\n\ndescribe('trackHtmlVideo', () => {\n  let video: HTMLVideoElement;\n  let handler: VideoHandler;\n\n  beforeEach(() => {\n    const res = createMockVideo();\n    video = res.video;\n    handler = res.handler;\n  });\n\n  test('should track play, pause and ended events', () => {\n    const untrack = trackHtmlVideo(video, handler);\n\n    video.play();\n    expect(handler.onPlay).toHaveBeenCalledWith({\n      duration: 10,\n      start_time: 0,\n      last_position: 0,\n      percent_completed: 0,\n    });\n\n    video.pause();\n    expect(handler.onPause).toHaveBeenCalledWith({\n      last_position: 5,\n      start_time: 5,\n      percent_completed: 50,\n      duration: 10,\n      stop_reason: 'paused',\n    });\n\n    (video as any).ended();\n    expect(handler.onEnded).toHaveBeenCalledWith({\n      last_position: 10,\n      start_time: 10,\n      percent_completed: 100,\n      duration: 10,\n      stop_reason: 'ended',\n    });\n\n    untrack();\n    handler.onPlay = jest.fn();\n    video.play();\n    expect(handler.onPlay).not.toHaveBeenCalled();\n  });\n\n  test('should track seeking events', () => {\n    const untrack = trackHtmlVideo(video, handler);\n\n    video.play();\n    (video as any).simulateSeek(7);\n    expect(handler.onSeeking).toHaveBeenCalledWith({\n      last_position: 7,\n      start_time: 7,\n      percent_completed: 70,\n      duration: 10,\n      stop_reason: 'seeking',\n    });\n\n    untrack();\n    handler.onSeeking = jest.fn();\n    (video as any).simulateSeek(1);\n    expect(handler.onSeeking).not.toHaveBeenCalled();\n  });\n\n  test('should track seeked events', () => {\n    const untrack = trackHtmlVideo(video, handler);\n\n    video.play();\n    (video as any).simulateSeek(7);\n    (video as any).seeked();\n    expect(handler.onSeeked).toHaveBeenCalledWith({\n      last_position: 7,\n      start_time: 7,\n      percent_completed: 70,\n      duration: 10,\n    });\n\n    untrack();\n    handler.onSeeked = jest.fn();\n    (video as any).seeked(2);\n    expect(handler.onSeeked).not.toHaveBeenCalled();\n  });\n\n  test('should track timeupdate events', () => {\n    const untrack = trackHtmlVideo(video, handler);\n\n    video.play();\n    Object.defineProperty(video, 'currentTime', { configurable: true, value: 4 });\n    video.dispatchEvent(new Event('timeupdate'));\n    expect(handler.onTimeUpdate).toHaveBeenCalledWith({\n      position: 4,\n      isSeeking: false,\n    });\n\n    untrack();\n    handler.onTimeUpdate = jest.fn();\n    Object.defineProperty(video, 'currentTime', { configurable: true, value: 6 });\n    video.dispatchEvent(new Event('timeupdate'));\n    expect(handler.onTimeUpdate).not.toHaveBeenCalled();\n  });\n});\n\ndescribe('trackHtmlVideo with Mux vendor', () => {\n  let video: HTMLVideoElement;\n  let handler: VideoHandler;\n\n  beforeEach(() => {\n    const res = createMockVideo({ isMux: true });\n    video = res.video;\n    handler = res.handler;\n  });\n\n  test('should track play, pause and ended events', () => {\n    const untrack = trackHtmlVideo(video, handler, 'mux');\n\n    const muxMetadata = {\n      mux_playback_id: video.getAttribute('playback-id'),\n      mux_video_id: video.getAttribute('metadata-video-id'),\n      mux_video_title: video.getAttribute('metadata-video-title'),\n    };\n\n    video.play();\n    expect(handler.onPlay).toHaveBeenCalledWith({\n      duration: 10,\n      start_time: 0,\n      last_position: 0,\n      percent_completed: 0,\n      ...muxMetadata,\n    });\n\n    video.pause();\n    expect(handler.onPause).toHaveBeenCalledWith({\n      last_position: 5,\n      start_time: 5,\n      percent_completed: 50,\n      duration: 10,\n      stop_reason: 'paused',\n      ...muxMetadata,\n    });\n\n    (video as any).ended();\n    expect(handler.onEnded).toHaveBeenCalledWith({\n      last_position: 10,\n      start_time: 10,\n      percent_completed: 100,\n      duration: 10,\n      stop_reason: 'ended',\n      ...muxMetadata,\n    });\n\n    untrack();\n    handler.onPlay = jest.fn();\n    video.play();\n    expect(handler.onPlay).not.toHaveBeenCalled();\n  });\n\n  test('should track seeking events with Mux metadata', () => {\n    trackHtmlVideo(video, handler, 'mux');\n\n    const muxMetadata = {\n      mux_playback_id: video.getAttribute('playback-id'),\n      mux_video_id: video.getAttribute('metadata-video-id'),\n      mux_video_title: video.getAttribute('metadata-video-title'),\n    };\n\n    video.play();\n    (video as any).simulateSeek(4);\n    expect(handler.onSeeking).toHaveBeenCalledWith({\n      last_position: 4,\n      start_time: 4,\n      percent_completed: 40,\n      duration: 10,\n      stop_reason: 'seeking',\n      ...muxMetadata,\n    });\n  });\n\n  test('should track seeked events with Mux metadata', () => {\n    trackHtmlVideo(video, handler, 'mux');\n\n    const muxMetadata = {\n      mux_playback_id: video.getAttribute('playback-id'),\n      mux_video_id: video.getAttribute('metadata-video-id'),\n      mux_video_title: video.getAttribute('metadata-video-title'),\n    };\n\n    video.play();\n    (video as any).simulateSeek(3);\n    (video as any).seeked();\n    expect(handler.onSeeked).toHaveBeenCalledWith({\n      last_position: 3,\n      start_time: 3,\n      percent_completed: 30,\n      duration: 10,\n      ...muxMetadata,\n    });\n  });\n\n  test('should track timeupdate events with Mux metadata', () => {\n    trackHtmlVideo(video, handler, 'mux');\n\n    video.play();\n    Object.defineProperty(video, 'currentTime', { configurable: true, value: 2.5 });\n    video.dispatchEvent(new Event('timeupdate'));\n    expect(handler.onTimeUpdate).toHaveBeenCalledWith({\n      position: 2.5,\n      isSeeking: false,\n    });\n  });\n});\n\ndescribe('trackEmbeddedVideo', () => {\n  let player: ReturnType<typeof createMockEmbeddedVideoPlayer>['player'];\n  let handler: VideoHandler;\n\n  beforeEach(() => {\n    jest.useFakeTimers();\n    ({ player } = createMockEmbeddedVideoPlayer());\n    handler = {\n      onPlay: jest.fn(),\n      onPause: jest.fn(),\n      onEnded: jest.fn(),\n      onError: jest.fn(),\n      onSeeking: jest.fn(),\n      onSeeked: jest.fn(),\n      onTimeUpdate: jest.fn(),\n    };\n  });\n\n  afterEach(() => {\n    jest.useRealTimers();\n  });\n\n  describe('no vendor', () => {\n    test('should track play, pause and ended events', async () => {\n      const untrack = trackEmbeddedVideo(player, handler);\n      player.emit('ready');\n      player.emit('play');\n      await jest.runAllTimersAsync();\n      expect(handler.onPlay).toHaveBeenCalledWith({\n        last_position: 0,\n        start_time: 0,\n        percent_completed: 0,\n        duration: 10,\n      });\n\n      player.setCurrentTime(5);\n      player.emit('pause');\n      await jest.runAllTimersAsync();\n      expect(handler.onPause).toHaveBeenCalledWith({\n        last_position: 5,\n        start_time: 5,\n        percent_completed: 50,\n        duration: 10,\n        stop_reason: 'paused',\n      });\n\n      player.setCurrentTime(10);\n      player.emit('ended');\n      await jest.runAllTimersAsync();\n      expect(handler.onEnded).toHaveBeenCalledWith({\n        last_position: 10,\n        start_time: 10,\n        percent_completed: 100,\n        duration: 10,\n        stop_reason: 'ended',\n      });\n\n      untrack();\n      handler.onPlay = jest.fn();\n      player.emit('play');\n      await jest.runAllTimersAsync();\n      expect(handler.onPlay).not.toHaveBeenCalled();\n    });\n\n    test('should track seeking events', async () => {\n      const untrack = trackEmbeddedVideo(player, handler);\n      player.emit('ready');\n      player.setCurrentTime(6);\n      player.emit('seeking');\n      await jest.runAllTimersAsync();\n      expect(handler.onSeeking).toHaveBeenCalledWith({\n        last_position: 6,\n        start_time: 6,\n        percent_completed: 60,\n        duration: 10,\n        stop_reason: 'seeking',\n      });\n\n      untrack();\n      handler.onSeeking = jest.fn();\n      player.emit('seeking');\n      await jest.runAllTimersAsync();\n      expect(handler.onSeeking).not.toHaveBeenCalled();\n    });\n\n    test('should track seeked events', async () => {\n      const untrack = trackEmbeddedVideo(player, handler);\n      player.emit('ready');\n      player.setCurrentTime(8);\n      player.emit('seeked');\n      await jest.runAllTimersAsync();\n      expect(handler.onSeeked).toHaveBeenCalledWith({\n        last_position: 8,\n        start_time: 8,\n        percent_completed: 80,\n        duration: 10,\n      });\n\n      untrack();\n      handler.onSeeked = jest.fn();\n      player.emit('seeked');\n      await jest.runAllTimersAsync();\n      expect(handler.onSeeked).not.toHaveBeenCalled();\n    });\n\n    test('should track timeupdate events', async () => {\n      const untrack = trackEmbeddedVideo(player, handler);\n      player.emit('ready');\n      player.setCurrentTime(4);\n      player.emit('timeupdate');\n      await jest.runAllTimersAsync();\n      expect(handler.onTimeUpdate).toHaveBeenCalledWith({\n        position: 4,\n        isSeeking: false,\n      });\n\n      untrack();\n      handler.onTimeUpdate = jest.fn();\n      player.emit('timeupdate');\n      await jest.runAllTimersAsync();\n      expect(handler.onTimeUpdate).not.toHaveBeenCalled();\n    });\n\n    test('should set isSeeking on timeupdate before async seeking metadata resolves', async () => {\n      const untrack = trackEmbeddedVideo(player, handler);\n      player.emit('ready');\n      player.setCurrentTime(6);\n      player.emit('seeking');\n      player.emit('timeupdate');\n      await jest.runAllTimersAsync();\n      expect(handler.onTimeUpdate).toHaveBeenCalledWith({\n        position: 6,\n        isSeeking: true,\n      });\n      untrack();\n    });\n  });\n\n  describe('with Mux vendor', () => {\n    test('should track play, pause and ended events', async () => {\n      const untrack = trackEmbeddedVideo(player, handler, 'mux');\n\n      player.emit('ready');\n\n      const muxMetadata = {\n        mux_playback_id: 'dE02GfTAlJD4RcqNAlgiS2m00LqbdFqlBm',\n        mux_video_id: 'video-123',\n        mux_video_title: 'My Video',\n      };\n\n      player.setCurrentTime(0);\n      player.emit('play');\n      await jest.runAllTimersAsync();\n      expect(handler.onPlay).toHaveBeenCalledWith({\n        last_position: 0,\n        start_time: 0,\n        percent_completed: 0,\n        duration: 10,\n        ...muxMetadata,\n      });\n\n      player.setCurrentTime(5);\n      player.emit('pause');\n      await jest.runAllTimersAsync();\n      expect(handler.onPause).toHaveBeenCalledWith({\n        last_position: 5,\n        start_time: 5,\n        percent_completed: 50,\n        duration: 10,\n        stop_reason: 'paused',\n        ...muxMetadata,\n      });\n\n      player.setCurrentTime(10);\n      player.emit('ended');\n      await jest.runAllTimersAsync();\n      expect(handler.onEnded).toHaveBeenCalledWith({\n        last_position: 10,\n        start_time: 10,\n        percent_completed: 100,\n        duration: 10,\n        stop_reason: 'ended',\n        ...muxMetadata,\n      });\n\n      untrack();\n      handler.onPlay = jest.fn();\n      player.emit('play');\n      await jest.runAllTimersAsync();\n      expect(handler.onPlay).not.toHaveBeenCalled();\n    });\n\n    test('should track seeking events with Mux metadata', async () => {\n      trackEmbeddedVideo(player, handler, 'mux');\n      player.emit('ready');\n\n      const muxMetadata = {\n        mux_playback_id: 'dE02GfTAlJD4RcqNAlgiS2m00LqbdFqlBm',\n        mux_video_id: 'video-123',\n        mux_video_title: 'My Video',\n      };\n\n      player.setCurrentTime(2);\n      player.emit('seeking');\n      await jest.runAllTimersAsync();\n      expect(handler.onSeeking).toHaveBeenCalledWith({\n        last_position: 2,\n        start_time: 2,\n        percent_completed: 20,\n        duration: 10,\n        stop_reason: 'seeking',\n        ...muxMetadata,\n      });\n    });\n\n    test('should track seeked events with Mux metadata', async () => {\n      trackEmbeddedVideo(player, handler, 'mux');\n      player.emit('ready');\n\n      const muxMetadata = {\n        mux_playback_id: 'dE02GfTAlJD4RcqNAlgiS2m00LqbdFqlBm',\n        mux_video_id: 'video-123',\n        mux_video_title: 'My Video',\n      };\n\n      player.setCurrentTime(4);\n      player.emit('seeked');\n      await jest.runAllTimersAsync();\n      expect(handler.onSeeked).toHaveBeenCalledWith({\n        last_position: 4,\n        start_time: 4,\n        percent_completed: 40,\n        duration: 10,\n        ...muxMetadata,\n      });\n    });\n\n    test('should track timeupdate events with Mux metadata', async () => {\n      trackEmbeddedVideo(player, handler, 'mux');\n      player.emit('ready');\n\n      player.setCurrentTime(3);\n      player.emit('timeupdate');\n      await jest.runAllTimersAsync();\n      expect(handler.onTimeUpdate).toHaveBeenCalledWith({\n        position: 3,\n        isSeeking: false,\n      });\n    });\n\n    test('should work when there is no src url', async () => {\n      player.elem.setAttribute('src', null as unknown as string);\n      const untrack = trackEmbeddedVideo(player, handler, 'mux');\n      player.emit('ready');\n      player.emit('play');\n      await jest.runAllTimersAsync();\n      expect(handler.onPlay).toHaveBeenCalledWith({\n        last_position: 0,\n        start_time: 0,\n        duration: 10,\n        percent_completed: 0,\n      });\n      untrack();\n      handler.onPlay = jest.fn();\n      player.emit('play');\n      await jest.runAllTimersAsync();\n      expect(handler.onPlay).not.toHaveBeenCalled();\n    });\n\n    describe('when there is an error getting the metadata', () => {\n      let originalGetDuration: typeof player.getDuration;\n      beforeEach(() => {\n        originalGetDuration = player.getDuration;\n        player.getDuration = jest.fn().mockImplementation(() => {\n          throw new Error('Error getting duration');\n        });\n        trackEmbeddedVideo(player, handler);\n        player.emit('ready');\n      });\n\n      afterEach(() => {\n        player.getDuration = originalGetDuration;\n      });\n\n      test('should call the error handler (play)', async () => {\n        player.emit('play');\n        await jest.runAllTimersAsync();\n        expect(handler.onError).toHaveBeenCalledTimes(1);\n      });\n\n      test('should call the error handler (pause)', async () => {\n        player.emit('pause');\n        await jest.runAllTimersAsync();\n        expect(handler.onError).toHaveBeenCalledTimes(1);\n      });\n\n      test('should call the error handler (ended)', async () => {\n        player.emit('ended');\n        await jest.runAllTimersAsync();\n        expect(handler.onError).toHaveBeenCalledTimes(1);\n      });\n\n      test('should call the error handler (seeking)', async () => {\n        player.emit('seeking');\n        await jest.runAllTimersAsync();\n        expect(handler.onError).toHaveBeenCalledTimes(1);\n        expect(handler.onError).toHaveBeenCalledWith(expect.stringContaining(\"from 'seeking' handler\"));\n      });\n\n      test('should call the error handler (seeked)', async () => {\n        player.emit('seeked');\n        await jest.runAllTimersAsync();\n        expect(handler.onError).toHaveBeenCalledTimes(1);\n        expect(handler.onError).toHaveBeenCalledWith(expect.stringContaining(\"from 'seeked' handler\"));\n      });\n\n      test('should call the error handler (timeupdate)', async () => {\n        const originalGetCurrentTime = player.getCurrentTime;\n        player.getCurrentTime = jest.fn().mockImplementation(() => {\n          throw new Error('Error getting current time');\n        });\n        try {\n          player.emit('timeupdate');\n          await jest.runAllTimersAsync();\n          expect(handler.onError).toHaveBeenCalledTimes(1);\n          expect(handler.onError).toHaveBeenCalledWith(expect.stringContaining(\"from 'timeupdate' handler\"));\n        } finally {\n          player.getCurrentTime = originalGetCurrentTime;\n        }\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-core/tsconfig.es5.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/cjs\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/analytics-core/tsconfig.esm.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"es6\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/esm\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/analytics-core/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src/**/*\", \"test/**/*\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"esModuleInterop\": true,\n    \"noEmit\": true,\n    \"rootDir\": \".\",\n    \"lib\": [\"dom\", \"es6\"],\n  }\n}\n"
  },
  {
    "path": "packages/analytics-node/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.5.57](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.56...@amplitude/analytics-node@1.5.57) (2026-04-28)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.56](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.55...@amplitude/analytics-node@1.5.56) (2026-04-22)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.55](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.54...@amplitude/analytics-node@1.5.55) (2026-04-21)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.54](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.53...@amplitude/analytics-node@1.5.54) (2026-04-14)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.53](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.52...@amplitude/analytics-node@1.5.53) (2026-04-09)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.52](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.51...@amplitude/analytics-node@1.5.52) (2026-04-01)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.51](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.50...@amplitude/analytics-node@1.5.51) (2026-03-26)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.50](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.49...@amplitude/analytics-node@1.5.50) (2026-03-23)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.49](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.48...@amplitude/analytics-node@1.5.49) (2026-03-20)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.48](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.47...@amplitude/analytics-node@1.5.48) (2026-03-19)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.47](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.46...@amplitude/analytics-node@1.5.47) (2026-03-17)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.46](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.45...@amplitude/analytics-node@1.5.46) (2026-03-16)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.45](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.44...@amplitude/analytics-node@1.5.45) (2026-03-13)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.44](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.43...@amplitude/analytics-node@1.5.44) (2026-03-12)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.43](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.42...@amplitude/analytics-node@1.5.43) (2026-03-09)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.42](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.41...@amplitude/analytics-node@1.5.42) (2026-03-05)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.41](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.40...@amplitude/analytics-node@1.5.41) (2026-03-03)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.40](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.39...@amplitude/analytics-node@1.5.40) (2026-03-03)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.39](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.38...@amplitude/analytics-node@1.5.39) (2026-02-26)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.38](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.37...@amplitude/analytics-node@1.5.38) (2026-02-24)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.37](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.36...@amplitude/analytics-node@1.5.37) (2026-02-19)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.36](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.35...@amplitude/analytics-node@1.5.36) (2026-02-17)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.35](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.34...@amplitude/analytics-node@1.5.35) (2026-02-10)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.34](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.33...@amplitude/analytics-node@1.5.34) (2026-01-26)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.33](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.32...@amplitude/analytics-node@1.5.33) (2026-01-21)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.32](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.31...@amplitude/analytics-node@1.5.32) (2026-01-15)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.31](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.30...@amplitude/analytics-node@1.5.31) (2026-01-14)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.30](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.29...@amplitude/analytics-node@1.5.30) (2026-01-14)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.29](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.28...@amplitude/analytics-node@1.5.29) (2025-12-24)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.28](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.27...@amplitude/analytics-node@1.5.28) (2025-12-16)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.27](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.26...@amplitude/analytics-node@1.5.27) (2025-12-09)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.26](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.25...@amplitude/analytics-node@1.5.26) (2025-11-21)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.25](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.24...@amplitude/analytics-node@1.5.25) (2025-11-20)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.24](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.23...@amplitude/analytics-node@1.5.24) (2025-11-17)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.23](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.22...@amplitude/analytics-node@1.5.23) (2025-11-17)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.22](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.21...@amplitude/analytics-node@1.5.22) (2025-11-05)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.21](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.20...@amplitude/analytics-node@1.5.21) (2025-10-29)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.20](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.19...@amplitude/analytics-node@1.5.20) (2025-10-23)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.19](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.18...@amplitude/analytics-node@1.5.19) (2025-10-23)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.18](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.17...@amplitude/analytics-node@1.5.18) (2025-10-17)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.17](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.16...@amplitude/analytics-node@1.5.17) (2025-10-15)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.16](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.15...@amplitude/analytics-node@1.5.16) (2025-10-14)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.15](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.14...@amplitude/analytics-node@1.5.15) (2025-10-14)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.14](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.13...@amplitude/analytics-node@1.5.14) (2025-10-03)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.12...@amplitude/analytics-node@1.5.13) (2025-10-01)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.11...@amplitude/analytics-node@1.5.12) (2025-09-25)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.10...@amplitude/analytics-node@1.5.11) (2025-09-23)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.9...@amplitude/analytics-node@1.5.10) (2025-09-18)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.8...@amplitude/analytics-node@1.5.9) (2025-09-12)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.7...@amplitude/analytics-node@1.5.8) (2025-09-05)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.6...@amplitude/analytics-node@1.5.7) (2025-08-28)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.5...@amplitude/analytics-node@1.5.6) (2025-08-26)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.4...@amplitude/analytics-node@1.5.5) (2025-08-25)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.3...@amplitude/analytics-node@1.5.4) (2025-08-22)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.2...@amplitude/analytics-node@1.5.3) (2025-08-21)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.1...@amplitude/analytics-node@1.5.2) (2025-08-13)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.5.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.5.0...@amplitude/analytics-node@1.5.1) (2025-08-08)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n# [1.5.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.4.2...@amplitude/analytics-node@1.5.0) (2025-08-05)\n\n\n### Bug Fixes\n\n* **analtyics-browser): Revert \"feat(analytics-browser:** add page-url-previous-page plugin\" ([#1237](https://github.com/amplitude/Amplitude-TypeScript/issues/1237)) ([dfd7340](https://github.com/amplitude/Amplitude-TypeScript/commit/dfd7340f6519e647a814b3c66913b0c96b0567cf))\n\n\n### Features\n\n* **analytics-browser:** add page-url-previous-page plugin ([#1110](https://github.com/amplitude/Amplitude-TypeScript/issues/1110)) ([dc053ed](https://github.com/amplitude/Amplitude-TypeScript/commit/dc053ed9f0b6378fce6a49f6a6e4196f3622bd25))\n\n\n\n\n\n## [1.4.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.4.1...@amplitude/analytics-node@1.4.2) (2025-07-29)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n## [1.4.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.4.0...@amplitude/analytics-node@1.4.1) (2025-07-17)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n\n\n\n\n# [1.4.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.1.6...@amplitude/analytics-node@1.4.0) (2025-07-15)\n\n\n### Bug Fixes\n\n* response with non-json format ([#758](https://github.com/amplitude/Amplitude-TypeScript/issues/758)) ([3d234ca](https://github.com/amplitude/Amplitude-TypeScript/commit/3d234ca5a71bacf9ab7f82a115cb2010e94a3a33))\n* simplify plugins and eliminate enums ([#407](https://github.com/amplitude/Amplitude-TypeScript/issues/407)) ([890ec66](https://github.com/amplitude/Amplitude-TypeScript/commit/890ec6695a8b25cd6988e9f7ae584d4ba2835f67))\n\n\n### Features\n\n* add offline mode ([#644](https://github.com/amplitude/Amplitude-TypeScript/issues/644)) ([f2cd717](https://github.com/amplitude/Amplitude-TypeScript/commit/f2cd717316eef66b101153cb8eedf37fadc6de0c))\n* add option for instance name ([#428](https://github.com/amplitude/Amplitude-TypeScript/issues/428)) ([1a8ff7d](https://github.com/amplitude/Amplitude-TypeScript/commit/1a8ff7d665d2a936db7cb42f4cde5350379b7cae))\n* **analytics-browser:** autocapture network errors ([#1050](https://github.com/amplitude/Amplitude-TypeScript/issues/1050)) ([104350f](https://github.com/amplitude/Amplitude-TypeScript/commit/104350ffe8b1bd1a7090482ac3bf24d85672bd43))\n* **analytics-node:** migrate to v2.x core  ([#1207](https://github.com/amplitude/Amplitude-TypeScript/issues/1207)) ([e1c1b28](https://github.com/amplitude/Amplitude-TypeScript/commit/e1c1b28ed2036f7ebb68173f8da2e6cbb82cb287))\n* log response body from API to logger ([#415](https://github.com/amplitude/Amplitude-TypeScript/issues/415)) ([#422](https://github.com/amplitude/Amplitude-TypeScript/issues/422)) ([d14b5c0](https://github.com/amplitude/Amplitude-TypeScript/commit/d14b5c00a88f1a61149a61128bb4c4d07ed35836))\n* simplify browser SDK options and plugin options interface ([#384](https://github.com/amplitude/Amplitude-TypeScript/issues/384)) ([b464cfb](https://github.com/amplitude/Amplitude-TypeScript/commit/b464cfb8e09d722bf06ed3c11955f77465a23daf))\n\n\n### Reverts\n\n* Revert \"chore(release): publish\" ([d392f62](https://github.com/amplitude/Amplitude-TypeScript/commit/d392f6290b8bb4dd955d6e6f20b00191679489c4))\n\n\n\n\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.3.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.3.8...@amplitude/analytics-node@1.3.9) (2025-07-08)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.3.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.3.7...@amplitude/analytics-node@1.3.8) (2025-03-03)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.3.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.3.6...@amplitude/analytics-node@1.3.7) (2025-02-28)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.3.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.3.5...@amplitude/analytics-node@1.3.6) (2024-05-28)\n\n### Bug Fixes\n\n- response with non-json format ([#757](https://github.com/amplitude/Amplitude-TypeScript/issues/757))\n  ([6f072f6](https://github.com/amplitude/Amplitude-TypeScript/commit/6f072f68412bc439c4f562aecb265546e067b99b))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.3.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.3.4...@amplitude/analytics-node@1.3.5) (2023-12-19)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.3.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.3.3...@amplitude/analytics-node@1.3.4) (2023-10-26)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.3.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.3.2...@amplitude/analytics-node@1.3.3) (2023-08-22)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.3.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.3.1...@amplitude/analytics-node@1.3.2) (2023-08-10)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.3.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.3.0...@amplitude/analytics-node@1.3.1) (2023-07-05)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.3.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.2.2...@amplitude/analytics-node@1.3.0) (2023-06-26)\n\n### Features\n\n- add option for instance name ([#428](https://github.com/amplitude/Amplitude-TypeScript/issues/428))\n  ([#442](https://github.com/amplitude/Amplitude-TypeScript/issues/442))\n  ([569464c](https://github.com/amplitude/Amplitude-TypeScript/commit/569464c698eb54b3da05e203ac90cf1a399d96ed))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.2.1...@amplitude/analytics-node@1.2.2) (2023-06-14)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.2.0...@amplitude/analytics-node@1.2.1) (2023-06-13)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.2.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.1.7...@amplitude/analytics-node@1.2.0) (2023-06-08)\n\n### Features\n\n- log response body from API to logger ([#415](https://github.com/amplitude/Amplitude-TypeScript/issues/415))\n  ([86de7bd](https://github.com/amplitude/Amplitude-TypeScript/commit/86de7bd75c564601d980c029e548fe0303ba43f2))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.1.7-beta.0...@amplitude/analytics-node@1.1.7) (2023-06-06)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.7-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.1.6...@amplitude/analytics-node@1.1.7-beta.0) (2023-06-06)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.1.5...@amplitude/analytics-node@1.1.6) (2023-05-04)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.1.4...@amplitude/analytics-node@1.1.5) (2023-04-27)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.1.3...@amplitude/analytics-node@1.1.4) (2023-04-25)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.1.2...@amplitude/analytics-node@1.1.3) (2023-04-06)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.1.1...@amplitude/analytics-node@1.1.2) (2023-03-31)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.1.1-beta.0...@amplitude/analytics-node@1.1.1) (2023-03-31)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.1-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.1.0...@amplitude/analytics-node@1.1.1-beta.0) (2023-03-31)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.1.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.1.0-beta.0...@amplitude/analytics-node@1.1.0) (2023-02-27)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.1.0-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.0.5...@amplitude/analytics-node@1.1.0-beta.0) (2023-02-24)\n\n### Features\n\n- pass amplitude instance to plugin.setup for enhanced plugin capabilities\n  ([#328](https://github.com/amplitude/Amplitude-TypeScript/issues/328))\n  ([91eeaa0](https://github.com/amplitude/Amplitude-TypeScript/commit/91eeaa0d6bff6bde39538bb54548a938df784462))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.0.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.0.4...@amplitude/analytics-node@1.0.5) (2023-02-09)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.0.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.0.3...@amplitude/analytics-node@1.0.4) (2023-02-02)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.0.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.0.3-beta.0...@amplitude/analytics-node@1.0.3) (2023-01-31)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.0.3-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.0.2...@amplitude/analytics-node@1.0.3-beta.0) (2023-01-26)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.0.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.0.1...@amplitude/analytics-node@1.0.2) (2023-01-11)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.0.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@1.0.0...@amplitude/analytics-node@1.0.1) (2022-12-21)\n\n### Bug Fixes\n\n- upgrade dependencies to resolve dependabot vulnerability alerts\n  ([#299](https://github.com/amplitude/Amplitude-TypeScript/issues/299))\n  ([7dd1cd1](https://github.com/amplitude/Amplitude-TypeScript/commit/7dd1cd1b23a71981a4ad90b4b30cc9b7d28c4412))\n\n### Reverts\n\n- Revert \"Updated dependencies\"\n  ([7ca9964](https://github.com/amplitude/Amplitude-TypeScript/commit/7ca9964781e4b900c6c027bdddf2ae1e7428ba18))\n\n# [1.0.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@0.6.2...@amplitude/analytics-node@1.0.0) (2022-12-10)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n## [0.6.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@0.6.1...@amplitude/analytics-node@0.6.2) (2022-11-28)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n## [0.6.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@0.6.0...@amplitude/analytics-node@0.6.1) (2022-11-15)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n# [0.6.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@0.5.8...@amplitude/analytics-node@0.6.0) (2022-11-01)\n\n### Features\n\n- enhance logger with debug information ([#254](https://github.com/amplitude/Amplitude-TypeScript/issues/254))\n  ([5c6175e](https://github.com/amplitude/Amplitude-TypeScript/commit/5c6175e9372cbeea264ddb34c6cc68148063d4f7))\n\n## [0.5.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@0.5.7...@amplitude/analytics-node@0.5.8) (2022-10-25)\n\n### Bug Fixes\n\n- invoke pre-init track fns after attribution ([#253](https://github.com/amplitude/Amplitude-TypeScript/issues/253))\n  ([b8996d7](https://github.com/amplitude/Amplitude-TypeScript/commit/b8996d793f74d388c1a96e0cde5c0ac060c1e565))\n\n## [0.5.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@0.5.6...@amplitude/analytics-node@0.5.7) (2022-10-14)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n## [0.5.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@0.5.5...@amplitude/analytics-node@0.5.6) (2022-10-04)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n## [0.5.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@0.5.4...@amplitude/analytics-node@0.5.5) (2022-09-30)\n\n### Bug Fixes\n\n- cover the case when apiKey is missing in the runtime\n  ([#240](https://github.com/amplitude/Amplitude-TypeScript/issues/240))\n  ([308bbe8](https://github.com/amplitude/Amplitude-TypeScript/commit/308bbe8337cbab366a0ca255f2d665101f4781a0))\n\n## [0.5.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@0.5.4-beta.0...@amplitude/analytics-node@0.5.4) (2022-09-28)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n## [0.5.4-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@0.5.3...@amplitude/analytics-node@0.5.4-beta.0) (2022-09-26)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n## [0.5.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@0.5.2...@amplitude/analytics-node@0.5.3) (2022-09-26)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n## [0.5.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@0.5.1...@amplitude/analytics-node@0.5.2) (2022-09-22)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n## [0.5.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@0.5.0...@amplitude/analytics-node@0.5.1) (2022-09-16)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n# [0.5.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@0.4.1...@amplitude/analytics-node@0.5.0) (2022-09-08)\n\n### Features\n\n- add ingestion_metadata field ([#212](https://github.com/amplitude/Amplitude-TypeScript/issues/212))\n  ([ebe8448](https://github.com/amplitude/Amplitude-TypeScript/commit/ebe8448b23609134f846e18da2e769158ca30bf1))\n\n## [0.4.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@0.4.0...@amplitude/analytics-node@0.4.1) (2022-08-31)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n# [0.4.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@0.3.7...@amplitude/analytics-node@0.4.0) (2022-08-18)\n\n### Bug Fixes\n\n- prevent concurrent init calls ([#191](https://github.com/amplitude/Amplitude-TypeScript/issues/191))\n  ([efda076](https://github.com/amplitude/Amplitude-TypeScript/commit/efda0760f4f1e92e47a3150985e18efcc3b108d9))\n\n### Features\n\n- adds create instance api ([#188](https://github.com/amplitude/Amplitude-TypeScript/issues/188))\n  ([050c1d9](https://github.com/amplitude/Amplitude-TypeScript/commit/050c1d96cedbc9e68aedf6fd55e85d2d3dc2fee4))\n\n## [0.3.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@0.3.6...@amplitude/analytics-node@0.3.7) (2022-08-16)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n## [0.3.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@0.3.5...@amplitude/analytics-node@0.3.6) (2022-08-13)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n## [0.3.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@0.3.4...@amplitude/analytics-node@0.3.5) (2022-08-12)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n## [0.3.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@0.3.3...@amplitude/analytics-node@0.3.4) (2022-07-22)\n\n### Bug Fixes\n\n- allow undefined storage provider ([#146](https://github.com/amplitude/Amplitude-TypeScript/issues/146))\n  ([e704342](https://github.com/amplitude/Amplitude-TypeScript/commit/e704342761c8ad7de3921ba21901ef8d3a768188))\n- missing tracked events before init issue ([#144](https://github.com/amplitude/Amplitude-TypeScript/issues/144))\n  ([60d0f68](https://github.com/amplitude/Amplitude-TypeScript/commit/60d0f6848087f7b8fc3c870d55489a238e841b26))\n- removes saveEvents config ([#147](https://github.com/amplitude/Amplitude-TypeScript/issues/147))\n  ([6fde736](https://github.com/amplitude/Amplitude-TypeScript/commit/6fde736ca8a865462522082a8085673756dbcc7d))\n- update default flush config for node ([#152](https://github.com/amplitude/Amplitude-TypeScript/issues/152))\n  ([2445dff](https://github.com/amplitude/Amplitude-TypeScript/commit/2445dff0842e7e0a2b7ee767ab926b5a93348214))\n\n## [0.3.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@0.3.2...@amplitude/analytics-node@0.3.3) (2022-07-15)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n## [0.3.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@0.3.1...@amplitude/analytics-node@0.3.2) (2022-07-13)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n## [0.3.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@0.3.0...@amplitude/analytics-node@0.3.1) (2022-06-29)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n# [0.3.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@0.2.0...@amplitude/analytics-node@0.3.0) (2022-06-29)\n\n### Features\n\n- add flush() api to send all events immediately ([#125](https://github.com/amplitude/Amplitude-TypeScript/issues/125))\n  ([b5dbcbb](https://github.com/amplitude/Amplitude-TypeScript/commit/b5dbcbb803c76ee5ade7ea85f76fbea50d8bab49))\n- make storage interface async to enable react-native\n  ([#122](https://github.com/amplitude/Amplitude-TypeScript/issues/122))\n  ([42bb39c](https://github.com/amplitude/Amplitude-TypeScript/commit/42bb39c967db015d5899487618d066f3540c9f18))\n\n# [0.2.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@0.1.1...@amplitude/analytics-node@0.2.0) (2022-06-24)\n\n### Features\n\n- add marketing campaign tracking ([#112](https://github.com/amplitude/Amplitude-TypeScript/issues/112))\n  ([bca73ed](https://github.com/amplitude/Amplitude-TypeScript/commit/bca73ede308ecb1663986a99600657732969d60c))\n\n## [0.1.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node@0.1.0...@amplitude/analytics-node@0.1.1) (2022-06-21)\n\n**Note:** Version bump only for package @amplitude/analytics-node\n\n# 0.1.0 (2022-06-17)\n\n### Features\n\n- add Plan option to config ([#117](https://github.com/amplitude/Amplitude-TypeScript/issues/117))\n  ([194d7e6](https://github.com/amplitude/Amplitude-TypeScript/commit/194d7e66af0209cb8155cf6aa0b05a5dcb170f9d))\n- introduce NodeJS package ([#92](https://github.com/amplitude/Amplitude-TypeScript/issues/92))\n  ([476fb44](https://github.com/amplitude/Amplitude-TypeScript/commit/476fb44efcf2dfcd84af6f0ef45e141ad87dac43))\n"
  },
  {
    "path": "packages/analytics-node/README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://amplitude.com\" target=\"_blank\" align=\"center\">\n    <img src=\"https://static.amplitude.com/lightning/46c85bfd91905de8047f1ee65c7c93d6fa9ee6ea/static/media/amplitude-logo-with-text.4fb9e463.svg\" width=\"280\">\n  </a>\n  <br />\n</p>\n\n# @amplitude/analytics-node\n\nOfficial Amplitude SDK for Node.js\n\n# Doc\n\nSee our [Typescript Analytics Node SDK](https://amplitude.github.io/Amplitude-TypeScript/modules/_amplitude_analytics_node.html) Reference for a list and description of all available SDK methods.\n\n# Installation and Quick Start\n\nPlease visit our :100:[Developer Center](https://www.docs.developers.amplitude.com/data/sdks/typescript-node/) for instructions on installing and using our the SDK.\n\n## Installation\n\nTo get started with using Amplitude Node.js SDK, install the package to your project via NPM.\n\n### Using Node package\n\nThis package is published on NPM registry and is available to be installed using npm and yarn.\n\n```sh\n# npm\nnpm install @amplitude/analytics-node@^1.0.0\n\n# yarn\nyarn add @amplitude/analytics-node@^1.0.0\n```\n\n## Usage\n\n### Initializing SDK\n\nInitialization is necessary before any instrumentation is done. The API key for your Amplitude project is required.\n\n```typescript\namplitude.init(API_KEY);\n```\n\n### Tracking an Event\n\nEvents represent how users interact with your application. For example, \"Button Clicked\" may be an action you want to note.\n\n```typescript\nimport { track } from '@amplitude/analytics-node';\n\n// Track a basic event\ntrack('Button Clicked', undefined, {\n  user_id: 'user@amplitude.com',\n});\n\n// Track events with additional properties\nconst eventProperties = {\n  selectedColors: ['red', 'blue'],\n};\ntrack('Button Clicked', eventProperties, {\n  user_id: 'user@amplitude.com',\n});\n```\n\n### User Properties\n\nUser properties help you understand your users at the time they performed some action within your app such as their device details, their preferences, or language.\n\n```typescript\nimport { Identify, identify } from '@amplitude/analytics-node';\n\nconst event = new Identify();\n\n// sets the value of a user property\nevent.set('key1', 'value1');\n\n// sets the value of a user property only once\nevent.setOnce('key1', 'value1');\n\n// increments a user property by some numerical value.\nevent.add('value1', 10);\n\n// pre inserts a value or values to a user property\nevent.preInsert('ab-tests', 'new-user-test');\n\n// post inserts a value or values to a user property\nevent.postInsert('ab-tests', 'new-user-test');\n\n// removes a value or values to a user property\nevent.remove('ab-tests', 'new-user-test')\n\n// sends identify event\nidentify(event);\n```\n\n### prepend/append\n\n* append will append a value or values to a user property array.\n* prepend will prepend a value or values to a user property.\n\n### User Groups\n\n```typescript\nimport { setGroup } from '@amplitude/analytics-node';\n\n// set group with single group name\nsetGroup('orgId', '15');\n\n// set group with multiple group names\nsetGroup('sport', ['soccer', 'tennis']);\n```\n\n### Group Identify\n\nThis feature is only available to Growth and Enterprise customers who have purchased the [Accounts add-on](https://amplitude.zendesk.com/hc/en-us/articles/115001765532).\n\nUse the Group Identify API to set or update properties of particular groups. However, these updates will only affect events going forward.\n\n```typescript\nimport { Identify, groupIdentify } from '@amplitude/analytics-node';\n\nconst groupType = 'plan';\nconst groupName = 'enterprise';\nconst identity = new Identify()\nidentity.set('key1', 'value1');\n\ngroupIdentify(groupType, groupName, identity);\n```\n\n### Track Revenue\n\nRevenue instances will store each revenue transaction and allow you to define several special revenue properties (such as 'revenueType', 'productIdentifier', etc.) that are used in Amplitude's Event Segmentation and Revenue LTV charts. These Revenue instance objects are then passed into `revenue` to send as revenue events to Amplitude. This allows us to automatically display data relevant to revenue in the platform. You can use this to track both in-app and non-in-app purchases.\n\n```typescript\nimport { Revenue, revenue } from '@amplitude/analytics-node';\n\nconst event = new Revenue()\n  .setProductId('com.company.productId')\n  .setPrice(3.99)\n  .setQuantity(3);\n\nrevenue(event);\n```\n\n### Callback\n\nAll asynchronous API are optionally awaitable through a specific Promise interface. This also serves as callback interface.\n\n```typescript\n// Using async/await\nconst results = await track('Button Clicked').promise;\nresult.event; // {...} (The final event object sent to Amplitude)\nresult.code; // 200 (The HTTP response status code of the request.\nresult.message; // \"Event tracked successfully\" (The response message)\n\n// Using promises\ntrack('Button Clicked').promise.then((result) => {\n  result.event; // {...} (The final event object sent to Amplitude)\n  result.code; // 200 (The HTTP response status code of the request.\n  result.message; // \"Event tracked successfully\" (The response message)\n});\n```\n"
  },
  {
    "path": "packages/analytics-node/jest.config.js",
    "content": "const baseConfig = require('../../jest.config.js');\nconst package = require('./package');\n\nmodule.exports = {\n  ...baseConfig,\n  displayName: package.name,\n  rootDir: '.',\n  testEnvironment: 'node',\n};\n"
  },
  {
    "path": "packages/analytics-node/package.json",
    "content": "{\n  \"name\": \"@amplitude/analytics-node\",\n  \"version\": \"1.5.57\",\n  \"description\": \"Official Amplitude SDK for NodeJS\",\n  \"author\": \"Amplitude Inc\",\n  \"homepage\": \"https://github.com/amplitude/Amplitude-TypeScript\",\n  \"license\": \"MIT\",\n  \"main\": \"lib/cjs/index.js\",\n  \"module\": \"lib/esm/index.js\",\n  \"types\": \"lib/esm/index.d.ts\",\n  \"sideEffects\": false,\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"tag\": \"latest\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/amplitude/Amplitude-TypeScript.git\"\n  },\n  \"scripts\": {\n    \"build\": \"pnpm build:es5 & pnpm build:esm\",\n    \"build:es5\": \"tsc -p ./tsconfig.es5.json\",\n    \"build:esm\": \"tsc -p ./tsconfig.esm.json\",\n    \"clean\": \"rimraf node_modules lib coverage\",\n    \"fix\": \"pnpm fix:eslint & pnpm fix:prettier\",\n    \"fix:eslint\": \"eslint '{src,test}/**/*.ts' --fix\",\n    \"fix:prettier\": \"prettier --write \\\"{src,test}/**/*.ts\\\"\",\n    \"lint\": \"pnpm lint:eslint & pnpm lint:prettier\",\n    \"lint:eslint\": \"eslint '{src,test}/**/*.ts'\",\n    \"lint:prettier\": \"prettier --check \\\"{src,test}/**/*.ts\\\"\",\n    \"test\": \"jest\",\n    \"typecheck\": \"tsc -p ./tsconfig.json\",\n    \"version\": \"pnpm version-file && pnpm build\",\n    \"version-file\": \"node -p \\\"'export const VERSION = \\\\'' + require('./package.json').version + '\\\\';'\\\" > src/version.ts\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/amplitude/Amplitude-TypeScript/issues\"\n  },\n  \"dependencies\": {\n    \"@amplitude/analytics-core\": \"workspace:*\",\n    \"tslib\": \"^2.4.1\"\n  },\n  \"files\": [\n    \"lib\"\n  ]\n}\n"
  },
  {
    "path": "packages/analytics-node/src/config.ts",
    "content": "import { Config, NodeOptions, NodeConfig as INodeConfig } from '@amplitude/analytics-core';\nimport { Http } from './transports/http';\n\nexport class NodeConfig extends Config implements INodeConfig {\n  constructor(apiKey: string, options?: NodeOptions) {\n    super({\n      transportProvider: new Http(),\n      ...options,\n      apiKey,\n    });\n  }\n}\n\nexport const useNodeConfig = (apiKey: string, overrides?: NodeOptions): INodeConfig => {\n  return new NodeConfig(apiKey, overrides);\n};\n"
  },
  {
    "path": "packages/analytics-node/src/index.ts",
    "content": "/* eslint-disable @typescript-eslint/unbound-method */\n\nimport client from './node-client';\nexport { createInstance } from './node-client';\nexport const { add, groupIdentify, identify, init, logEvent, remove, revenue, setGroup, setOptOut, track, flush } =\n  client;\nexport { Revenue, Identify } from '@amplitude/analytics-core';\n\n// Export types to maintain backward compatibility with `analytics-types`.\n// In the next major version, only export customer-facing types to reduce the public API surface.\nexport * as Types from './types';\n"
  },
  {
    "path": "packages/analytics-node/src/node-client.ts",
    "content": "import {\n  AmplitudeCore,\n  Destination,\n  returnWrapper,\n  debugWrapper,\n  getClientLogConfig,\n  getClientStates,\n  NodeClient,\n  NodeConfig,\n  NodeOptions,\n} from '@amplitude/analytics-core';\nimport { Context } from './plugins/context';\nimport { useNodeConfig } from './config';\n\nexport class AmplitudeNode extends AmplitudeCore {\n  // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n  // @ts-ignore\n  config: NodeConfig;\n\n  init(apiKey = '', options?: NodeOptions) {\n    return returnWrapper(this._init({ ...options, apiKey }));\n  }\n  protected async _init(options: NodeOptions & { apiKey: string }) {\n    // Step 0: Block concurrent initialization\n    if (this.initializing) {\n      return;\n    }\n    this.initializing = true;\n\n    const nodeOptions = useNodeConfig(options.apiKey, {\n      ...options,\n    });\n\n    await super._init(nodeOptions);\n\n    await this.add(new Destination()).promise;\n    await this.add(new Context()).promise;\n\n    this.initializing = false;\n\n    await this.runQueuedFunctions('dispatchQ');\n  }\n}\n\nexport const createInstance = (): NodeClient => {\n  const client = new AmplitudeNode();\n  return {\n    init: debugWrapper(\n      client.init.bind(client),\n      'init',\n      getClientLogConfig(client),\n      getClientStates(client, ['config']),\n    ),\n    add: debugWrapper(\n      client.add.bind(client),\n      'add',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.plugins']),\n    ),\n    remove: debugWrapper(\n      client.remove.bind(client),\n      'remove',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.plugins']),\n    ),\n    track: debugWrapper(\n      client.track.bind(client),\n      'track',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.queue.length']),\n    ),\n    logEvent: debugWrapper(\n      client.logEvent.bind(client),\n      'logEvent',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.queue.length']),\n    ),\n    identify: debugWrapper(\n      client.identify.bind(client),\n      'identify',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.queue.length']),\n    ),\n    groupIdentify: debugWrapper(\n      client.groupIdentify.bind(client),\n      'groupIdentify',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.queue.length']),\n    ),\n    setGroup: debugWrapper(\n      client.setGroup.bind(client),\n      'setGroup',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.queue.length']),\n    ),\n    revenue: debugWrapper(\n      client.revenue.bind(client),\n      'revenue',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.queue.length']),\n    ),\n    flush: debugWrapper(\n      client.flush.bind(client),\n      'flush',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.queue.length']),\n    ),\n    setOptOut: debugWrapper(\n      client.setOptOut.bind(client),\n      'setOptOut',\n      getClientLogConfig(client),\n      getClientStates(client, ['config']),\n    ),\n  };\n};\n\nexport default createInstance();\n"
  },
  {
    "path": "packages/analytics-node/src/plugins/context.ts",
    "content": "import { UUID, BeforePlugin, NodeConfig, Event } from '@amplitude/analytics-core';\nimport { VERSION } from '../version';\n\nexport class Context implements BeforePlugin {\n  name = 'context';\n  type = 'before' as const;\n\n  // this.config is defined in setup() which will always be called first\n  // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n  // @ts-ignore\n  config: NodeConfig;\n  eventId = 0;\n  library = `amplitude-node-ts/${VERSION}`;\n\n  setup(config: NodeConfig): Promise<undefined> {\n    this.config = config;\n    return Promise.resolve(undefined);\n  }\n\n  execute(context: Event): Promise<Event> {\n    return new Promise((resolve) => {\n      const time = new Date().getTime();\n\n      const contextEvent: Event = {\n        time,\n        insert_id: UUID(),\n        plan: this.config.plan,\n        ...(this.config.ingestionMetadata && {\n          ingestion_metadata: {\n            source_name: this.config.ingestionMetadata.sourceName,\n            source_version: this.config.ingestionMetadata.sourceVersion,\n          },\n        }),\n        ...context,\n        event_id: this.eventId++,\n        library: this.library,\n      };\n      return resolve(contextEvent);\n    });\n  }\n}\n"
  },
  {
    "path": "packages/analytics-node/src/transports/http.ts",
    "content": "import { BaseTransport, Payload, Response, Transport } from '@amplitude/analytics-core';\nimport * as http from 'http';\nimport * as https from 'https';\n\nexport class Http extends BaseTransport implements Transport {\n  send(serverUrl: string, payload: Payload): Promise<Response | null> {\n    let protocol: typeof http | typeof https;\n    if (serverUrl.startsWith('http://')) {\n      protocol = http;\n    } else if (serverUrl.startsWith('https://')) {\n      protocol = https;\n    } else {\n      throw new Error('Invalid server url');\n    }\n\n    const url = new URL(serverUrl);\n    const requestPayload = JSON.stringify(payload);\n    const options = {\n      headers: {\n        'Content-Type': 'application/json',\n        'Content-Length': Buffer.byteLength(requestPayload),\n      },\n      hostname: url.hostname,\n      method: 'POST',\n      path: url.pathname,\n      port: url.port,\n      protocol: url.protocol,\n    };\n    return new Promise((resolve) => {\n      const req = protocol.request(options, (res) => {\n        res.setEncoding('utf8');\n        let responsePayload = '';\n        res.on('data', (chunk: string) => {\n          responsePayload += chunk;\n        });\n\n        res.on('end', () => {\n          if (res.complete && responsePayload.length > 0) {\n            try {\n              // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n              const parsedResponsePayload: Record<string, any> = JSON.parse(responsePayload);\n              const result = this.buildResponse(parsedResponsePayload);\n              resolve(result);\n            } catch {\n              resolve(this.buildResponse({ code: res.statusCode }));\n            }\n          }\n        });\n      });\n      req.on('error', () => resolve(null));\n      req.end(requestPayload);\n    });\n  }\n}\n"
  },
  {
    "path": "packages/analytics-node/src/types.ts",
    "content": "/* eslint-disable @typescript-eslint/unbound-method */\nexport {\n  AmplitudeReturn,\n  BaseEvent,\n  EventOptions,\n  IConfig,\n  Event,\n  IdentifyEvent,\n  GroupIdentifyEvent,\n  IdentifyOperation,\n  SpecialEventType,\n  IIdentify,\n  IRevenue,\n  RevenueProperty,\n  ILogger,\n  LogLevel,\n  Plugin,\n  BeforePlugin,\n  EnrichmentPlugin,\n  DestinationPlugin,\n  Result,\n  ServerZoneType,\n  ServerZone,\n  IdentityStorageType,\n  Storage,\n  TransportType,\n  OfflineDisabled,\n} from '@amplitude/analytics-core';\n"
  },
  {
    "path": "packages/analytics-node/src/version.ts",
    "content": "export const VERSION = '1.5.57';\n"
  },
  {
    "path": "packages/analytics-node/test/config.test.ts",
    "content": "import * as Config from '../src/config';\nimport * as core from '@amplitude/analytics-core';\nimport { LogLevel } from '@amplitude/analytics-core';\nimport { Http } from '../src/transports/http';\n\ndescribe('config', () => {\n  const API_KEY = 'apiKey';\n\n  describe('NodeConfig', () => {\n    test('should create overwrite config', () => {\n      const logger = new core.Logger();\n      logger.enable(LogLevel.Warn);\n      const config = new Config.NodeConfig(API_KEY);\n      expect(config).toEqual({\n        apiKey: API_KEY,\n        flushIntervalMillis: 10000,\n        flushMaxRetries: 12,\n        flushQueueSize: 200,\n        instanceName: '$default_instance',\n        loggerProvider: logger,\n        logLevel: LogLevel.Warn,\n        minIdLength: undefined,\n        offline: false,\n        _optOut: false,\n        plan: undefined,\n        ingestionMetadata: undefined,\n        serverUrl: 'https://api2.amplitude.com/2/httpapi',\n        serverZone: 'US',\n        storageProvider: undefined,\n        transportProvider: new Http(),\n        useBatch: false,\n      });\n    });\n  });\n\n  describe('useNodeConfig', () => {\n    test('should create default config', () => {\n      const logger = new core.Logger();\n      logger.enable(LogLevel.Warn);\n      const config = Config.useNodeConfig(API_KEY, undefined);\n      expect(config).toEqual({\n        apiKey: API_KEY,\n        flushIntervalMillis: 10000,\n        flushMaxRetries: 12,\n        flushQueueSize: 200,\n        instanceName: '$default_instance',\n        loggerProvider: logger,\n        logLevel: LogLevel.Warn,\n        minIdLength: undefined,\n        offline: false,\n        _optOut: false,\n        plan: undefined,\n        ingestionMetadata: undefined,\n        serverUrl: 'https://api2.amplitude.com/2/httpapi',\n        serverZone: 'US',\n        storageProvider: undefined,\n        transportProvider: new Http(),\n        useBatch: false,\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-node/test/helpers/default.ts",
    "content": "import { NodeConfig as INodeConfig, NodeOptions } from '@amplitude/analytics-core';\n\nimport { NodeConfig } from '../../src/config';\n\nexport const useDefaultConfig = (overrides?: NodeOptions) =>\n  new NodeConfig(API_KEY, { ...DEFAULT_OPTIONS, ...overrides });\n\nexport const API_KEY = 'apiKey';\n\nexport const USER_ID = 'userId';\n\nexport const DEFAULT_OPTIONS: Partial<INodeConfig> = {\n  apiKey: API_KEY,\n  storageProvider: {\n    isEnabled: async () => true,\n    get: async () => undefined,\n    set: async () => undefined,\n    remove: async () => undefined,\n    reset: async () => undefined,\n    getRaw: async () => undefined,\n  },\n  transportProvider: {\n    send: () => Promise.resolve(null),\n  },\n};\n"
  },
  {
    "path": "packages/analytics-node/test/index.test.ts",
    "content": "import {\n  add,\n  createInstance,\n  groupIdentify,\n  Identify,\n  identify,\n  init,\n  logEvent,\n  remove,\n  Revenue,\n  revenue,\n  setGroup,\n  setOptOut,\n  track,\n  flush,\n} from '../src/index';\n\ndescribe('index', () => {\n  test('should expose apis', () => {\n    expect(typeof add).toBe('function');\n    expect(typeof createInstance).toBe('function');\n    expect(typeof groupIdentify).toBe('function');\n    expect(typeof Identify).toBe('function');\n    expect(typeof identify).toBe('function');\n    expect(typeof init).toBe('function');\n    expect(typeof logEvent).toBe('function');\n    expect(typeof remove).toBe('function');\n    expect(typeof Revenue).toBe('function');\n    expect(typeof revenue).toBe('function');\n    expect(typeof setGroup).toBe('function');\n    expect(typeof setOptOut).toBe('function');\n    expect(typeof track).toBe('function');\n    expect(typeof flush).toBe('function');\n  });\n});\n"
  },
  {
    "path": "packages/analytics-node/test/node-client.test.ts",
    "content": "import { AmplitudeNode } from '../src/node-client';\nimport * as core from '@amplitude/analytics-core';\nimport { Status } from '@amplitude/analytics-core';\nimport * as Config from '../src/config';\n\ndescribe('node-client', () => {\n  const API_KEY = 'API_KEY';\n\n  describe('init', () => {\n    test('should return config', async () => {\n      const client = new AmplitudeNode();\n      await client.init(API_KEY, {\n        flushIntervalMillis: 1000,\n      }).promise;\n      expect(client.config).toBeDefined();\n    });\n\n    test('should initialize without error when apiKey is undefined', async () => {\n      const client = new AmplitudeNode();\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n      await client.init(undefined as any, {\n        flushIntervalMillis: 1000,\n      }).promise;\n      expect(client.config).toBeDefined();\n    });\n\n    test('should call prevent concurrent init executions', async () => {\n      const client = new AmplitudeNode();\n      const useNodeConfig = jest.spyOn(Config, 'useNodeConfig');\n      await Promise.all([client.init(API_KEY), client.init(API_KEY), client.init(API_KEY)]);\n      // NOTE: `useNodeConfig` is only called once despite multiple init calls\n      expect(useNodeConfig).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('setOptOut', () => {\n    test('should set opt out', async () => {\n      const client = new AmplitudeNode();\n      await client.init(API_KEY).promise;\n      client.setOptOut(true);\n      expect(client.config.optOut).toBe(true);\n    });\n  });\n\n  describe('identify', () => {\n    test('should track identify', async () => {\n      const send = jest.fn().mockReturnValueOnce({\n        status: Status.Success,\n        statusCode: 200,\n        body: {\n          eventsIngested: 1,\n          payloadSizeBytes: 1,\n          serverUploadTime: 1,\n        },\n      });\n      const client = new AmplitudeNode();\n      await client.init(API_KEY, {\n        flushIntervalMillis: 1000,\n        transportProvider: {\n          send,\n        },\n      }).promise;\n      const identifyObject = new core.Identify();\n      const result = await client.identify(identifyObject).promise;\n      expect(result.code).toEqual(200);\n      expect(send).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('groupIdentify', () => {\n    test('should track group identify', async () => {\n      const send = jest.fn().mockReturnValueOnce({\n        status: Status.Success,\n        statusCode: 200,\n        body: {\n          eventsIngested: 1,\n          payloadSizeBytes: 1,\n          serverUploadTime: 1,\n        },\n      });\n      const client = new AmplitudeNode();\n      await client.init(API_KEY, {\n        flushIntervalMillis: 1000,\n        transportProvider: {\n          send,\n        },\n      }).promise;\n      const identifyObject = new core.Identify();\n      const result = await client.groupIdentify('g', '1', identifyObject).promise;\n      expect(result.code).toEqual(200);\n      expect(send).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('revenue', () => {\n    test('should track revenue', async () => {\n      const send = jest.fn().mockReturnValueOnce({\n        status: Status.Success,\n        statusCode: 200,\n        body: {\n          eventsIngested: 1,\n          payloadSizeBytes: 1,\n          serverUploadTime: 1,\n        },\n      });\n      const client = new AmplitudeNode();\n      await client.init(API_KEY, {\n        flushIntervalMillis: 1000,\n        transportProvider: {\n          send,\n        },\n      }).promise;\n      const revenueObject = new core.Revenue();\n      const result = await client.revenue(revenueObject).promise;\n      expect(result.code).toEqual(200);\n      expect(send).toHaveBeenCalledTimes(1);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-node/test/plugins/context.test.ts",
    "content": "import { Context } from '../../src/plugins/context';\nimport { useDefaultConfig } from '../helpers/default';\n\ndescribe('context', () => {\n  describe('setup', () => {\n    test('should setup plugin', async () => {\n      const context = new Context();\n      const config = useDefaultConfig();\n      await context.setup(config);\n      expect(context.eventId).toEqual(0);\n    });\n\n    test('should setup plugin without app version', async () => {\n      const context = new Context();\n      const config = useDefaultConfig();\n      await context.setup(config);\n      expect(context.eventId).toEqual(0);\n    });\n  });\n\n  describe('execute', () => {\n    test('should execute plugin', async () => {\n      const context = new Context();\n      const config = useDefaultConfig();\n      await context.setup(config);\n\n      const event = {\n        event_type: 'event_type',\n        device_id: 'deviceId',\n        session_id: 1,\n        user_id: 'user@amplitude.com',\n      };\n      const firstContextEvent = await context.execute(event);\n      expect(firstContextEvent.event_id).toEqual(0);\n      expect(firstContextEvent.insert_id).toBeDefined();\n      expect(firstContextEvent.device_id).toEqual('deviceId');\n      expect(firstContextEvent.session_id).toEqual(1);\n      expect(firstContextEvent.user_id).toEqual('user@amplitude.com');\n\n      const secondContextEvent = await context.execute(event);\n      expect(secondContextEvent.event_id).toEqual(1);\n    });\n\n    test('should be overwritten by the context', async () => {\n      const sourceName = 'ampli';\n      const sourceVersion = '2.0.0';\n      const context = new Context();\n      const config = useDefaultConfig({\n        ingestionMetadata: {\n          sourceName,\n          sourceVersion,\n        },\n      });\n      await context.setup(config);\n\n      const event = {\n        event_type: 'event_type',\n        device_id: 'new deviceId',\n        session_id: 1,\n        user_id: 'user@amplitude.com',\n      };\n      const firstContextEvent = await context.execute(event);\n      expect(firstContextEvent.event_id).toEqual(0);\n      expect(firstContextEvent.insert_id).toBeDefined();\n      expect(firstContextEvent.event_type).toEqual('event_type');\n      expect(firstContextEvent.device_id).toEqual('new deviceId');\n      expect(firstContextEvent.session_id).toEqual(1);\n      expect(firstContextEvent.user_id).toEqual('user@amplitude.com');\n      expect(firstContextEvent.ingestion_metadata?.source_name).toEqual(sourceName);\n      expect(firstContextEvent.ingestion_metadata?.source_version).toEqual(sourceVersion);\n\n      const secondContextEvent = await context.execute(event);\n      expect(secondContextEvent.event_id).toEqual(1);\n    });\n\n    describe('ingestionMetadata config', () => {\n      test('sourceName should be optional', async () => {\n        const sourceVersion = '2.0.0';\n        const context = new Context();\n        const config = useDefaultConfig({\n          ingestionMetadata: {\n            sourceVersion,\n          },\n        });\n        await context.setup(config);\n\n        const event = {\n          event_type: 'event_type',\n        };\n        const firstContextEvent = await context.execute(event);\n        expect(firstContextEvent.event_id).toEqual(0);\n        expect(firstContextEvent.ingestion_metadata?.source_name).toBeUndefined();\n        expect(firstContextEvent.ingestion_metadata?.source_version).toEqual(sourceVersion);\n      });\n\n      test('sourceVersion should be optional', async () => {\n        const sourceName = 'ampli';\n        const context = new Context();\n        const config = useDefaultConfig({\n          ingestionMetadata: {\n            sourceName,\n          },\n        });\n        await context.setup(config);\n\n        const event = {\n          event_type: 'event_type',\n        };\n        const firstContextEvent = await context.execute(event);\n        expect(firstContextEvent.event_id).toEqual(0);\n        expect(firstContextEvent.ingestion_metadata?.source_name).toEqual(sourceName);\n        expect(firstContextEvent.ingestion_metadata?.source_version).toBeUndefined();\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-node/test/transport/http.test.ts",
    "content": "import { Http } from '../../src/transports/http';\nimport http from 'http';\nimport https from 'https';\nimport { Status } from '@amplitude/analytics-core';\n\ndescribe('http transport', () => {\n  test('should send to http url', async () => {\n    const provider = new Http();\n    const url = 'http://localhost:3000';\n    const payload = {\n      api_key: '',\n      events: [],\n    };\n\n    const request = jest.spyOn(http, 'request').mockImplementation((_, cb) => {\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore\n      cb({\n        complete: true,\n        on: jest.fn().mockImplementation((event: string, callback: (data?: string) => void) => {\n          if (event === 'data') {\n            callback(JSON.stringify({ code: 200 }));\n          }\n          if (event === 'end') {\n            callback();\n          }\n        }),\n        setEncoding: jest.fn(),\n      });\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n      return {\n        on: jest.fn().mockImplementation((_: string, cb: (error: Error) => void) => cb(new Error())),\n        end: jest.fn(),\n      } as any;\n    });\n\n    const response = await provider.send(url, payload);\n    expect(response?.statusCode).toBe(200);\n    expect(request).toHaveBeenCalledTimes(1);\n  });\n\n  test('should send to https url', async () => {\n    const provider = new Http();\n    const url = 'https://localhost:3000';\n    const payload = {\n      api_key: '',\n      events: [],\n    };\n\n    const request = jest.spyOn(https, 'request').mockImplementation((_, cb) => {\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore\n      cb({\n        complete: true,\n        on: jest.fn().mockImplementation((event: string, callback: (data?: string) => void) => {\n          if (event === 'data') {\n            callback(JSON.stringify({ code: 200 }));\n          }\n          if (event === 'end') {\n            callback();\n          }\n        }),\n        setEncoding: jest.fn(),\n      });\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n      return {\n        on: jest.fn().mockImplementation((_: string, cb: (error: Error) => void) => cb(new Error())),\n        end: jest.fn(),\n      } as any;\n    });\n\n    const response = await provider.send(url, payload);\n    expect(response?.statusCode).toBe(200);\n    expect(request).toHaveBeenCalledTimes(1);\n  });\n\n  test('should throw an error if no protocal', () => {\n    const provider = new Http();\n    const url = 'localhost:3000';\n    const payload = {\n      api_key: '',\n      events: [],\n    };\n\n    expect(() => provider.send(url, payload)).toThrow('Invalid server url');\n  });\n\n  test('should handle error', async () => {\n    const provider = new Http();\n    const url = 'http://localhost:3000';\n    const payload = {\n      api_key: '',\n      events: [],\n    };\n\n    const request = jest.spyOn(http, 'request').mockImplementation((_, cb) => {\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore\n      cb({\n        complete: true,\n        on: jest.fn().mockImplementation((event: string, callback: (data?: string) => void) => {\n          if (event === 'data') {\n            callback(JSON.stringify({ code: 400 }));\n          }\n          if (event === 'end') {\n            callback();\n          }\n        }),\n        setEncoding: jest.fn(),\n      });\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n      return {\n        on: jest.fn(),\n        end: jest.fn(),\n      } as any;\n    });\n\n    const response = await provider.send(url, payload);\n    expect(response?.statusCode).toBe(400);\n    expect(response?.status).toBe(Status.Invalid);\n    expect(request).toHaveBeenCalledTimes(1);\n  });\n\n  test('should handle unexpected error', async () => {\n    const provider = new Http();\n    const url = 'http://localhost:3000';\n    const payload = {\n      api_key: '',\n      events: [],\n    };\n\n    const request = jest.spyOn(http, 'request').mockImplementation((_, cb) => {\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore\n      cb({\n        statusCode: 502,\n        complete: true,\n        on: jest.fn().mockImplementation((event: string, callback: (data?: string) => void) => {\n          if (event === 'data') {\n            callback('<');\n          }\n          if (event === 'end') {\n            callback();\n          }\n        }),\n        setEncoding: jest.fn(),\n      });\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n      return {\n        on: jest.fn(),\n        end: jest.fn(),\n      } as any;\n    });\n\n    const response = await provider.send(url, payload);\n    expect(response?.status).toBe(Status.Failed);\n    expect(response?.statusCode).toBe(502);\n    expect(request).toHaveBeenCalledTimes(1);\n  });\n});\n"
  },
  {
    "path": "packages/analytics-node/test/types.test.ts",
    "content": "import * as amplitude from '../src/index';\n\ndescribe('Type Exports', () => {\n  test('IdentifyOperation should be an enum', () => {\n    expect(amplitude.Types.IdentifyOperation.ADD).toBe('$add');\n  });\n\n  test('SpecialEventType should be an enum', () => {\n    expect(amplitude.Types.SpecialEventType.IDENTIFY).toBe('$identify');\n  });\n\n  test('exported enums are proper enums', () => {\n    const enumTypes = ['RevenueProperty', 'LogLevel', 'ServerZone'];\n    enumTypes.forEach((enumType) => {\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n      expect((amplitude.Types as any)[enumType]).toBeDefined();\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n      expect(typeof (amplitude.Types as any)[enumType]).toBe('object');\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument\n      expect(Object.keys((amplitude.Types as any)[enumType]).length).toBeGreaterThan(0);\n    });\n  });\n\n  test('exported null to be null', () => {\n    expect(amplitude.Types.OfflineDisabled).toBe(null);\n  });\n});\n"
  },
  {
    "path": "packages/analytics-node/tsconfig.es5.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/cjs\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/analytics-node/tsconfig.esm.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"es6\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/esm\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/analytics-node/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src/**/*\", \"test/**/*\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"esModuleInterop\": true,\n    \"noEmit\": true,\n    \"rootDir\": \".\"\n  }\n}\n"
  },
  {
    "path": "packages/analytics-node-test/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.0.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@1.0.12...@amplitude/analytics-node-test@1.0.13) (2025-07-08)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.0.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@1.0.11...@amplitude/analytics-node-test@1.0.12) (2025-03-03)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.0.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@1.0.10...@amplitude/analytics-node-test@1.0.11) (2025-02-28)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.0.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@1.0.9...@amplitude/analytics-node-test@1.0.10) (2024-05-28)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.0.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@1.0.8...@amplitude/analytics-node-test@1.0.9) (2023-12-19)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.0.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@1.0.7...@amplitude/analytics-node-test@1.0.8) (2023-10-26)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.0.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@1.0.6...@amplitude/analytics-node-test@1.0.7) (2023-08-22)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.0.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@1.0.5...@amplitude/analytics-node-test@1.0.6) (2023-08-10)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.0.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@1.0.4...@amplitude/analytics-node-test@1.0.5) (2023-07-05)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.0.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@1.0.3...@amplitude/analytics-node-test@1.0.4) (2023-06-26)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.0.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@1.0.2...@amplitude/analytics-node-test@1.0.3) (2023-06-14)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.0.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@1.0.1...@amplitude/analytics-node-test@1.0.2) (2023-06-13)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.0.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@1.0.0...@amplitude/analytics-node-test@1.0.1) (2023-06-08)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.0.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@1.0.0-beta.1...@amplitude/analytics-node-test@1.0.0) (2023-06-06)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.0.0-beta.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.1.14...@amplitude/analytics-node-test@1.0.0-beta.1) (2023-06-06)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.1.14](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.1.13...@amplitude/analytics-node-test@0.1.14) (2023-05-04)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.1.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.1.12...@amplitude/analytics-node-test@0.1.13) (2023-04-27)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.1.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.1.11...@amplitude/analytics-node-test@0.1.12) (2023-04-25)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.1.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.1.10...@amplitude/analytics-node-test@0.1.11) (2023-04-06)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.1.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.1.9...@amplitude/analytics-node-test@0.1.10) (2023-03-31)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.1.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.1.9-beta.0...@amplitude/analytics-node-test@0.1.9) (2023-03-31)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.1.9-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.1.8...@amplitude/analytics-node-test@0.1.9-beta.0) (2023-03-31)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.1.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.1.8-beta.0...@amplitude/analytics-node-test@0.1.8) (2023-02-27)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.1.8-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.1.7...@amplitude/analytics-node-test@0.1.8-beta.0) (2023-02-24)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.1.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.1.6...@amplitude/analytics-node-test@0.1.7) (2023-02-09)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.1.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.1.5...@amplitude/analytics-node-test@0.1.6) (2023-02-02)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.1.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.1.5-beta.0...@amplitude/analytics-node-test@0.1.5) (2023-01-31)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.1.5-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.1.4...@amplitude/analytics-node-test@0.1.5-beta.0) (2023-01-26)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.1.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.1.3...@amplitude/analytics-node-test@0.1.4) (2023-01-11)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.1.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.1.2...@amplitude/analytics-node-test@0.1.3) (2022-12-21)\n\n### Bug Fixes\n\n- upgrade dependencies to resolve dependabot vulnerability alerts\n  ([#299](https://github.com/amplitude/Amplitude-TypeScript/issues/299))\n  ([7dd1cd1](https://github.com/amplitude/Amplitude-TypeScript/commit/7dd1cd1b23a71981a4ad90b4b30cc9b7d28c4412))\n\n## [0.1.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.1.1...@amplitude/analytics-node-test@0.1.2) (2022-11-28)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n## [0.1.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.1.0...@amplitude/analytics-node-test@0.1.1) (2022-11-15)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n# [0.1.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.0.22...@amplitude/analytics-node-test@0.1.0) (2022-11-01)\n\n### Features\n\n- enhance logger with debug information ([#254](https://github.com/amplitude/Amplitude-TypeScript/issues/254))\n  ([5c6175e](https://github.com/amplitude/Amplitude-TypeScript/commit/5c6175e9372cbeea264ddb34c6cc68148063d4f7))\n\n## [0.0.22](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.0.21...@amplitude/analytics-node-test@0.0.22) (2022-10-25)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n## [0.0.21](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.0.20...@amplitude/analytics-node-test@0.0.21) (2022-10-14)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n## [0.0.20](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.0.19...@amplitude/analytics-node-test@0.0.20) (2022-10-04)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n## [0.0.19](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.0.18...@amplitude/analytics-node-test@0.0.19) (2022-09-30)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n## [0.0.18](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.0.18-beta.0...@amplitude/analytics-node-test@0.0.18) (2022-09-28)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n## [0.0.18-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.0.17...@amplitude/analytics-node-test@0.0.18-beta.0) (2022-09-26)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n## [0.0.17](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.0.16...@amplitude/analytics-node-test@0.0.17) (2022-09-26)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n## [0.0.16](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.0.15...@amplitude/analytics-node-test@0.0.16) (2022-09-22)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n## [0.0.15](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.0.14...@amplitude/analytics-node-test@0.0.15) (2022-09-16)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n## [0.0.14](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.0.13...@amplitude/analytics-node-test@0.0.14) (2022-09-08)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n## [0.0.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.0.12...@amplitude/analytics-node-test@0.0.13) (2022-08-31)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n## [0.0.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.0.11...@amplitude/analytics-node-test@0.0.12) (2022-08-18)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n## [0.0.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.0.10...@amplitude/analytics-node-test@0.0.11) (2022-08-16)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n## [0.0.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.0.9...@amplitude/analytics-node-test@0.0.10) (2022-08-13)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n## [0.0.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.0.8...@amplitude/analytics-node-test@0.0.9) (2022-08-12)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n## [0.0.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.0.7...@amplitude/analytics-node-test@0.0.8) (2022-07-22)\n\n### Bug Fixes\n\n- adds error handling for invalid api ([#153](https://github.com/amplitude/Amplitude-TypeScript/issues/153))\n  ([c03f9d7](https://github.com/amplitude/Amplitude-TypeScript/commit/c03f9d7dad51e3026673dca31418a74591d79bbc))\n- missing tracked events before init issue ([#144](https://github.com/amplitude/Amplitude-TypeScript/issues/144))\n  ([60d0f68](https://github.com/amplitude/Amplitude-TypeScript/commit/60d0f6848087f7b8fc3c870d55489a238e841b26))\n- update default flush config for node ([#152](https://github.com/amplitude/Amplitude-TypeScript/issues/152))\n  ([2445dff](https://github.com/amplitude/Amplitude-TypeScript/commit/2445dff0842e7e0a2b7ee767ab926b5a93348214))\n\n## [0.0.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.0.6...@amplitude/analytics-node-test@0.0.7) (2022-07-15)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n## [0.0.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.0.5...@amplitude/analytics-node-test@0.0.6) (2022-07-13)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n## [0.0.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.0.4...@amplitude/analytics-node-test@0.0.5) (2022-06-29)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n## [0.0.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.0.3...@amplitude/analytics-node-test@0.0.4) (2022-06-29)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n## [0.0.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.0.2...@amplitude/analytics-node-test@0.0.3) (2022-06-24)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n## [0.0.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-node-test@0.0.1...@amplitude/analytics-node-test@0.0.2) (2022-06-21)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n\n## 0.0.1 (2022-06-17)\n\n**Note:** Version bump only for package @amplitude/analytics-node-test\n"
  },
  {
    "path": "packages/analytics-node-test/README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://amplitude.com\" target=\"_blank\" align=\"center\">\n    <img src=\"https://static.amplitude.com/lightning/46c85bfd91905de8047f1ee65c7c93d6fa9ee6ea/static/media/amplitude-logo-with-text.4fb9e463.svg\" width=\"280\">\n  </a>\n  <br />\n</p>\n\n# `@amplitude/analytics-node-test`\n\n> Internal Node package for Amplitude\n"
  },
  {
    "path": "packages/analytics-node-test/jest.config.js",
    "content": "const baseConfig = require('../../jest.config.js');\nconst package = require('./package');\n\nmodule.exports = {\n  ...baseConfig,\n  collectCoverage: false,\n  displayName: package.name,\n  rootDir: '.',\n  testEnvironment: 'node',\n};\n"
  },
  {
    "path": "packages/analytics-node-test/package.json",
    "content": "{\n  \"name\": \"@amplitude/analytics-node-test\",\n  \"version\": \"1.0.13\",\n  \"private\": true,\n  \"description\": \"\",\n  \"author\": \"Amplitude Inc\",\n  \"homepage\": \"https://github.com/amplitude/Amplitude-TypeScript\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/amplitude/Amplitude-TypeScript.git\"\n  },\n  \"scripts\": {\n    \"test\": \"jest -i\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/amplitude/Amplitude-TypeScript/issues\"\n  },\n  \"dependencies\": {\n    \"@amplitude/analytics-node\": \"workspace:*\"\n  },\n  \"devDependencies\": {\n    \"@amplitude/analytics-core\": \"workspace:*\",\n    \"nock\": \"^13.2.4\"\n  }\n}\n"
  },
  {
    "path": "packages/analytics-node-test/test/constants.ts",
    "content": "export const uuidPattern = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/;\nexport const url = 'https://api2.amplitude.com';\nexport const path = '/2/httpapi';\nexport const SUCCESS_MESSAGE = 'Event tracked successfully';\n"
  },
  {
    "path": "packages/analytics-node-test/test/index.test.ts",
    "content": "import * as amplitude from '@amplitude/analytics-node';\nimport { default as nock } from 'nock';\nimport { success } from './responses';\nimport { path, SUCCESS_MESSAGE, url, uuidPattern } from './constants';\nimport { LogLevel } from '@amplitude/analytics-core';\n\ndescribe('integration', () => {\n  const uuid: string = expect.stringMatching(uuidPattern) as string;\n  const library = expect.stringMatching(/^amplitude-node-ts\\/.+/) as string;\n  const number = expect.any(Number) as number;\n  const opts = {\n    flushIntervalMillis: 1000,\n  };\n\n  describe('track', () => {\n    test('should track event', async () => {\n      const scope = nock(url).post(path).reply(200, success);\n\n      amplitude.init('API_KEY', opts);\n      const response = await amplitude.track('test event', {\n        mode: 'test',\n      }).promise;\n      expect(response.event).toEqual({\n        time: number,\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event',\n        event_id: 0,\n        event_properties: {\n          mode: 'test',\n        },\n        library: library,\n      });\n      expect(response.code).toBe(200);\n      expect(response.message).toBe(SUCCESS_MESSAGE);\n      scope.done();\n    });\n\n    test('should track event with event options', async () => {\n      const scope = nock(url).post(path).reply(200, success);\n\n      amplitude.init('API_KEY', opts);\n      const response = await amplitude.track('test event', undefined, {\n        user_id: 'sdk.dev@amplitude.com',\n        device_id: 'deviceId',\n      }).promise;\n      expect(response.event).toEqual({\n        user_id: 'sdk.dev@amplitude.com',\n        device_id: 'deviceId',\n        time: number,\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event',\n        event_id: 0,\n        library: library,\n      });\n      expect(response.code).toBe(200);\n      expect(response.message).toBe(SUCCESS_MESSAGE);\n      scope.done();\n    });\n\n    test('should track event when init is called after', async () => {\n      const scope = nock(url).post(path).reply(200, success);\n\n      const pendingResponse = amplitude.track('test event', undefined, {\n        user_id: 'sdk.dev@amplitude.com',\n        device_id: 'deviceId',\n      }).promise;\n      await amplitude.init('API_KEY', opts).promise;\n      const response = await pendingResponse;\n      expect(response.event).toEqual({\n        user_id: 'sdk.dev@amplitude.com',\n        device_id: 'deviceId',\n        time: number,\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event',\n        event_id: 0,\n        library: library,\n      });\n      expect(response.code).toBe(200);\n      expect(response.message).toBe(SUCCESS_MESSAGE);\n      scope.done();\n    });\n\n    test('should track event with base event', async () => {\n      const scope = nock(url).post(path).reply(200, success);\n\n      amplitude.init('API_KEY', opts);\n      const response = await amplitude.track(\n        {\n          event_type: 'test event',\n          groups: {\n            org: '15',\n          },\n        },\n        undefined,\n        {\n          user_id: 'sdk.dev@amplitude.com',\n          device_id: 'deviceId',\n        },\n      ).promise;\n      expect(response.event).toEqual({\n        user_id: 'sdk.dev@amplitude.com',\n        device_id: 'deviceId',\n        time: number,\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event',\n        event_id: 0,\n        library: library,\n        groups: {\n          org: '15',\n        },\n      });\n      expect(response.code).toBe(200);\n      expect(response.message).toBe(SUCCESS_MESSAGE);\n      scope.done();\n    });\n\n    test('should handle 400 error', async () => {\n      const first = nock(url)\n        .post(path)\n        .reply(400, {\n          code: 400,\n          error: 'Invalid field values on some events',\n          events_with_invalid_fields: {\n            device_id: [1],\n          },\n        });\n      const second = nock(url).post(path).reply(200, success);\n\n      amplitude.init('API_KEY', {\n        ...opts,\n        logLevel: 0,\n      });\n      const response = await Promise.all([\n        amplitude.track('test event 1').promise,\n        amplitude.track('test event 2', undefined, {\n          device_id: undefined,\n        }).promise,\n      ]);\n      expect(response[0].event).toEqual({\n        time: number,\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event 1',\n        event_id: 0,\n        library: library,\n      });\n      expect(response[0].code).toBe(200);\n      expect(response[0].message).toBe(SUCCESS_MESSAGE);\n      expect(response[1].event).toEqual({\n        user_id: undefined,\n        device_id: undefined,\n        time: number,\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event 2',\n        event_id: 1,\n        library: library,\n      });\n      expect(response[1].code).toBe(400);\n      expect(response[1].message).toBe('Invalid field values on some events');\n      first.done();\n      second.done();\n    });\n\n    test('should handle 413 error', async () => {\n      const first = nock(url).post(path).reply(413, {\n        code: 413,\n        error: 'Payload too large',\n      });\n      const second = nock(url).post(path).times(2).reply(200, success);\n\n      amplitude.init('API_KEY', {\n        ...opts,\n        logLevel: 0,\n        flushQueueSize: 2,\n      });\n      const response = await Promise.all([\n        amplitude.track('test event 1').promise,\n        amplitude.track('test event 2').promise,\n      ]);\n      expect(response[0].event).toEqual({\n        time: number,\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event 1',\n        event_id: 0,\n        library: library,\n      });\n      expect(response[0].code).toBe(200);\n      expect(response[0].message).toBe(SUCCESS_MESSAGE);\n      expect(response[1].event).toEqual({\n        time: number,\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event 2',\n        event_id: 1,\n        library: library,\n      });\n      expect(response[1].code).toBe(200);\n      expect(response[1].message).toBe(SUCCESS_MESSAGE);\n      first.done();\n      second.done();\n    });\n\n    test('should handle 429 error', async () => {\n      const first = nock(url)\n        .post(path)\n        .reply(429, {\n          code: 429,\n          error: 'Too many requests for some devices and users',\n          exceeded_daily_quota_devices: {\n            throttled_device_id: 1,\n          },\n        });\n      const second = nock(url).post(path).reply(200, success);\n\n      amplitude.init('API_KEY', {\n        ...opts,\n        logLevel: 0,\n      });\n      const response = await Promise.all([\n        amplitude.track('test event 1').promise,\n        amplitude.track('test event 2', undefined, {\n          device_id: 'throttled_device_id',\n        }).promise,\n      ]);\n      expect(response[0].event).toEqual({\n        time: number,\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event 1',\n        event_id: 0,\n        library: library,\n      });\n      expect(response[0].code).toBe(200);\n      expect(response[0].message).toBe(SUCCESS_MESSAGE);\n      expect(response[1].event).toEqual({\n        device_id: 'throttled_device_id',\n        time: number,\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event 2',\n        event_id: 1,\n        library: library,\n      });\n      expect(response[1].code).toBe(429);\n      expect(response[1].message).toBe('Too many requests for some devices and users');\n      first.done();\n      second.done();\n    });\n\n    test('should handle 500 error', async () => {\n      const first = nock(url).post(path).reply(500, {\n        code: 500,\n      });\n      const second = nock(url).post(path).reply(200, success);\n\n      amplitude.init('API_KEY', {\n        ...opts,\n        logLevel: 0,\n      });\n      const response = await Promise.all([\n        amplitude.track('test event 1').promise,\n        amplitude.track('test event 2').promise,\n      ]);\n      expect(response[0].event).toEqual({\n        time: number,\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event 1',\n        event_id: 0,\n        library: library,\n      });\n      expect(response[0].code).toBe(200);\n      expect(response[0].message).toBe(SUCCESS_MESSAGE);\n      expect(response[1].event).toEqual({\n        time: number,\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event 2',\n        event_id: 1,\n        library: library,\n      });\n      expect(response[0].code).toBe(200);\n      expect(response[0].message).toBe(SUCCESS_MESSAGE);\n      first.done();\n      second.done();\n    });\n\n    test('should exhaust max retries', async () => {\n      const scope = nock(url).post(path).times(3).reply(500, {\n        code: 500,\n      });\n\n      amplitude.init('API_KEY', {\n        ...opts,\n        logLevel: 0,\n        flushMaxRetries: 3,\n      });\n      const response = await amplitude.track('test event').promise;\n      expect(response.event).toEqual({\n        time: number,\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: 'test event',\n        event_id: 0,\n        library: library,\n      });\n      expect(response.code).toBe(500);\n      expect(response.message).toBe('Event rejected due to exceeded retry count');\n      scope.done();\n    }, 10000);\n\n    test('should handle missing api key', async () => {\n      amplitude.init('', {\n        ...opts,\n        logLevel: 0,\n      });\n      const response = await amplitude.track('test event').promise;\n      expect(response.code).toBe(400);\n      expect(response.message).toBe('Event rejected due to missing API key');\n    });\n\n    test('should handle client opt out', async () => {\n      amplitude.init('API_KEY', {\n        ...opts,\n        logLevel: 0,\n      });\n      amplitude.setOptOut(true);\n      const response = await amplitude.track('test event').promise;\n      expect(response.code).toBe(0);\n      expect(response.message).toBe('Event skipped due to optOut config');\n    });\n  });\n\n  describe('identify', () => {\n    test('should track event', async () => {\n      const scope = nock(url).post(path).reply(200, success);\n\n      amplitude.init('API_KEY', opts);\n      const id = new amplitude.Identify();\n      id.set('org', 'amp');\n      id.setOnce('initial_org', 'amp');\n      id.append('locations_1', 'ca');\n      id.prepend('locations_2', 'ny');\n      id.postInsert('tasks_1', 'a');\n      id.preInsert('tasks_2', 'b');\n      id.remove('company', 'x');\n      id.add('employees', 1);\n      const response = await amplitude.identify(id).promise;\n      expect(response.event).toEqual({\n        time: number,\n        insert_id: uuid,\n        partner_id: undefined,\n        event_type: '$identify',\n        event_id: 0,\n        library: library,\n        user_properties: {\n          $add: {\n            employees: 1,\n          },\n          $append: {\n            locations_1: 'ca',\n          },\n          $postInsert: {\n            tasks_1: 'a',\n          },\n          $preInsert: {\n            tasks_2: 'b',\n          },\n          $prepend: {\n            locations_2: 'ny',\n          },\n          $remove: {\n            company: 'x',\n          },\n          $set: {\n            org: 'amp',\n          },\n          $setOnce: {\n            initial_org: 'amp',\n          },\n        },\n      });\n      expect(response.code).toBe(200);\n      expect(response.message).toBe(SUCCESS_MESSAGE);\n      scope.done();\n    });\n  });\n\n  describe('revenue', () => {\n    test('should track event', async () => {\n      const scope = nock(url).post(path).reply(200, success);\n\n      amplitude.init('API_KEY', opts);\n      const rev = new amplitude.Revenue();\n      rev.setProductId('1');\n      rev.setQuantity(1);\n      rev.setPrice(100);\n      rev.setRevenueType('t');\n      rev.setRevenue(200);\n      const response = await amplitude.revenue(rev).promise;\n      expect(response.event).toEqual({\n        event_id: 0,\n        event_properties: {\n          $price: 100,\n          $productId: '1',\n          $quantity: 1,\n          $revenue: 200,\n          $revenueType: 't',\n        },\n        event_type: 'revenue_amount',\n        insert_id: uuid,\n        library: library,\n        partner_id: undefined,\n        time: number,\n      });\n      expect(response.code).toBe(200);\n      expect(response.message).toBe(SUCCESS_MESSAGE);\n      scope.done();\n    });\n  });\n\n  describe('setGroup', () => {\n    test('should track event', async () => {\n      const scope = nock(url).post(path).reply(200, success);\n\n      amplitude.init('API_KEY', opts);\n      const response = await amplitude.setGroup('org', 'engineering').promise;\n      expect(response.event).toEqual({\n        event_id: 0,\n        event_type: '$identify',\n        groups: {\n          org: 'engineering',\n        },\n        insert_id: uuid,\n        library: library,\n        partner_id: undefined,\n        time: number,\n        user_properties: {\n          $set: {\n            org: 'engineering',\n          },\n        },\n      });\n      expect(response.code).toBe(200);\n      expect(response.message).toBe(SUCCESS_MESSAGE);\n      scope.done();\n    });\n  });\n\n  describe('custom config', () => {\n    describe('serverUrl', () => {\n      test('should track event to custom serverUrl', async () => {\n        const serverUrl = 'https://domain.com';\n        const scope = nock(serverUrl).post(path).reply(200, success);\n\n        amplitude.init('API_KEY', {\n          ...opts,\n          serverUrl: serverUrl + path,\n        });\n        const response = await amplitude.track('test event').promise;\n        expect(response.event).toEqual({\n          time: number,\n          insert_id: uuid,\n          partner_id: undefined,\n          event_type: 'test event',\n          event_id: 0,\n          library: library,\n        });\n        expect(response.code).toBe(200);\n        expect(response.message).toBe(SUCCESS_MESSAGE);\n        scope.done();\n      });\n    });\n\n    describe('debug mode', () => {\n      test('should enable debug mode for track', async () => {\n        const scope = nock(url).post(path).reply(200, success);\n\n        const logger = {\n          disable: jest.fn(),\n          enable: jest.fn(),\n          debug: jest.fn(),\n          log: jest.fn(),\n          warn: jest.fn(),\n          error: jest.fn(),\n        };\n        amplitude.init('API_KEY', { ...opts, loggerProvider: logger, logLevel: LogLevel.Debug });\n\n        const response = await amplitude.track('test event', {\n          mode: 'test',\n        }).promise;\n        expect(response.event).toEqual({\n          time: number,\n          insert_id: uuid,\n          partner_id: undefined,\n          event_type: 'test event',\n          event_id: 0,\n          event_properties: {\n            mode: 'test',\n          },\n          library: library,\n        });\n        expect(response.code).toBe(200);\n        expect(response.message).toBe(SUCCESS_MESSAGE);\n        scope.done();\n\n        expect(logger.debug).toHaveBeenCalledTimes(1);\n        /* eslint-disable */\n        const debugContext = JSON.parse(logger.debug.mock.calls[0]);\n        expect(debugContext.type).toBeDefined();\n        expect(debugContext.name).toEqual('track');\n        expect(debugContext.args).toBeDefined();\n        expect(debugContext.stacktrace).toBeDefined();\n        expect(debugContext.time).toBeDefined();\n        expect(debugContext.states).toBeDefined();\n        /* eslint-enable */\n      });\n\n      test('should enable debug mode for setOptOut', async () => {\n        const logger = {\n          disable: jest.fn(),\n          enable: jest.fn(),\n          debug: jest.fn(),\n          log: jest.fn(),\n          warn: jest.fn(),\n          error: jest.fn(),\n        };\n        amplitude.init('API_KEY', { ...opts, loggerProvider: logger, logLevel: LogLevel.Debug });\n        amplitude.setOptOut(true);\n\n        expect(logger.debug).toHaveBeenCalledTimes(1);\n        /* eslint-disable */\n        const debugContext = JSON.parse(logger.debug.mock.calls[0]);\n        expect(debugContext.type).toBeDefined();\n        expect(debugContext.name).toEqual('setOptOut');\n        expect(debugContext.args).toBeDefined();\n        expect(debugContext.stacktrace).toBeDefined();\n        expect(debugContext.time).toBeDefined();\n        expect(debugContext.states).toBeDefined();\n        /* eslint-enable */\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-node-test/test/responses.ts",
    "content": "export const success = {\n  code: 200,\n  events_ingested: 1,\n  payload_size_bytes: 50,\n  server_upload_time: 1396381378123,\n};\n"
  },
  {
    "path": "packages/analytics-node-test/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"test/**/*\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"esModuleInterop\": true,\n    \"noEmit\": true,\n    \"rootDir\": \".\",\n  }\n}\n"
  },
  {
    "path": "packages/analytics-react-native/.gitattributes",
    "content": "*.pbxproj -text\n# specific for windows script files\n*.bat text eol=crlf"
  },
  {
    "path": "packages/analytics-react-native/.gitignore",
    "content": "# OSX\n#\n.DS_Store\n\n# XDE\n.expo/\n\n# VSCode\n.vscode/\njsconfig.json\n\n# Xcode\n#\nbuild/\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\nxcuserdata\n*.xccheckout\n*.moved-aside\nDerivedData\n*.hmap\n*.ipa\n*.xcuserstate\nproject.xcworkspace\n\n# Android/IJ\n#\n.idea\n.gradle\nlocal.properties\nandroid.iml\n**/*/.project\n\n# Cocoapods\n#\nios/Pods\n\n# node.js\n#\nnode_modules/\nnpm-debug.log\nyarn-debug.log\nyarn-error.log\n\n# BUCK\nbuck-out/\n\\.buckd/\nandroid/app/libs\nandroid/keystores/debug.keystore\n\n# Expo\n.expo/*\n\n# generated by bob\nlib/\n"
  },
  {
    "path": "packages/analytics-react-native/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.5.53](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.52...@amplitude/analytics-react-native@1.5.53) (2026-05-13)\n\n\n### Bug Fixes\n\n* **analytics-react-native:** use node test environment for mobile and bump analytics-core to 2.48.1 ([#1747](https://github.com/amplitude/Amplitude-TypeScript/issues/1747)) ([27d4ddd](https://github.com/amplitude/Amplitude-TypeScript/commit/27d4ddd1ae1d089779b9a7afc5e3ba46814611ac))\n\n\n\n\n\n## [1.5.52](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.51...@amplitude/analytics-react-native@1.5.52) (2026-03-26)\n\n\n### Bug Fixes\n\n* **react-native:** remove buildscript block to prevent AGP conflicts with host app ([#1631](https://github.com/amplitude/Amplitude-TypeScript/issues/1631)) ([2f2319e](https://github.com/amplitude/Amplitude-TypeScript/commit/2f2319eff97c4bb4e1d4ff29c1732f0244c1cab6))\n\n\n\n\n\n## [1.5.51](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.50...@amplitude/analytics-react-native@1.5.51) (2026-03-19)\n\n\n### Bug Fixes\n\n* **analytics-react-native:** pin analytics-core to avoid upgrades ([#1596](https://github.com/amplitude/Amplitude-TypeScript/issues/1596)) ([474d508](https://github.com/amplitude/Amplitude-TypeScript/commit/474d508dcd4ceb240b1e38b4417be3d680171638))\n\n\n\n\n\n## [1.5.50](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.49...@amplitude/analytics-react-native@1.5.50) (2026-03-17)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.49](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.48...@amplitude/analytics-react-native@1.5.49) (2026-03-16)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.48](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.47...@amplitude/analytics-react-native@1.5.48) (2026-03-13)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.47](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.46...@amplitude/analytics-react-native@1.5.47) (2026-03-12)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.46](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.45...@amplitude/analytics-react-native@1.5.46) (2026-03-09)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.45](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.44...@amplitude/analytics-react-native@1.5.45) (2026-03-05)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.44](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.43...@amplitude/analytics-react-native@1.5.44) (2026-03-03)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.43](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.42...@amplitude/analytics-react-native@1.5.43) (2026-03-03)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.42](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.41...@amplitude/analytics-react-native@1.5.42) (2026-02-26)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.41](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.40...@amplitude/analytics-react-native@1.5.41) (2026-02-24)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.40](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.39...@amplitude/analytics-react-native@1.5.40) (2026-02-19)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.39](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.38...@amplitude/analytics-react-native@1.5.39) (2026-02-17)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.38](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.37...@amplitude/analytics-react-native@1.5.38) (2026-02-10)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.37](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.36...@amplitude/analytics-react-native@1.5.37) (2026-01-26)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.36](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.35...@amplitude/analytics-react-native@1.5.36) (2026-01-21)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.35](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.34...@amplitude/analytics-react-native@1.5.35) (2026-01-15)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.34](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.33...@amplitude/analytics-react-native@1.5.34) (2026-01-14)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.33](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.32...@amplitude/analytics-react-native@1.5.33) (2026-01-14)\n\n\n### Bug Fixes\n\n* **analytics-browser:** two cookie problem resolution ([#1490](https://github.com/amplitude/Amplitude-TypeScript/issues/1490)) ([506638a](https://github.com/amplitude/Amplitude-TypeScript/commit/506638a2a412dc3843b0da9450325f70ff465422))\n\n\n\n\n\n## [1.5.32](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.31...@amplitude/analytics-react-native@1.5.32) (2025-12-24)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.31](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.30...@amplitude/analytics-react-native@1.5.31) (2025-12-23)\n\n\n### Bug Fixes\n\n* dummy patch for react-native ([#1442](https://github.com/amplitude/Amplitude-TypeScript/issues/1442)) ([6b58b38](https://github.com/amplitude/Amplitude-TypeScript/commit/6b58b382af8af62f0b9add72972074ea498236bf))\n\n\n\n\n\n## [1.5.30](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.29...@amplitude/analytics-react-native@1.5.30) (2025-12-22)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.29](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.28...@amplitude/analytics-react-native@1.5.29) (2025-12-16)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.28](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.27...@amplitude/analytics-react-native@1.5.28) (2025-12-09)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.27](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.26...@amplitude/analytics-react-native@1.5.27) (2025-11-21)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.26](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.25...@amplitude/analytics-react-native@1.5.26) (2025-11-20)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.25](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.24...@amplitude/analytics-react-native@1.5.25) (2025-11-17)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.24](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.23...@amplitude/analytics-react-native@1.5.24) (2025-11-17)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.23](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.22...@amplitude/analytics-react-native@1.5.23) (2025-11-05)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.22](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.21...@amplitude/analytics-react-native@1.5.22) (2025-10-29)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.21](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.20...@amplitude/analytics-react-native@1.5.21) (2025-10-23)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.20](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.19...@amplitude/analytics-react-native@1.5.20) (2025-10-23)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.19](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.18...@amplitude/analytics-react-native@1.5.19) (2025-10-17)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.18](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.17...@amplitude/analytics-react-native@1.5.18) (2025-10-15)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.17](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.16...@amplitude/analytics-react-native@1.5.17) (2025-10-14)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.16](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.15...@amplitude/analytics-react-native@1.5.16) (2025-10-14)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.15](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.14...@amplitude/analytics-react-native@1.5.15) (2025-10-03)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.14](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.13...@amplitude/analytics-react-native@1.5.14) (2025-10-01)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.12...@amplitude/analytics-react-native@1.5.13) (2025-09-25)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.11...@amplitude/analytics-react-native@1.5.12) (2025-09-23)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.10...@amplitude/analytics-react-native@1.5.11) (2025-09-18)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.9...@amplitude/analytics-react-native@1.5.10) (2025-09-12)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.8...@amplitude/analytics-react-native@1.5.9) (2025-09-05)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.7...@amplitude/analytics-react-native@1.5.8) (2025-08-28)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.6...@amplitude/analytics-react-native@1.5.7) (2025-08-26)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.5...@amplitude/analytics-react-native@1.5.6) (2025-08-25)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.4...@amplitude/analytics-react-native@1.5.5) (2025-08-22)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.3...@amplitude/analytics-react-native@1.5.4) (2025-08-21)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.2...@amplitude/analytics-react-native@1.5.3) (2025-08-13)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n## [1.5.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.1...@amplitude/analytics-react-native@1.5.2) (2025-08-08)\n\n\n### Bug Fixes\n\n* **analytics-react-native:** fix Types export ([#1242](https://github.com/amplitude/Amplitude-TypeScript/issues/1242)) ([06c5a98](https://github.com/amplitude/Amplitude-TypeScript/commit/06c5a988fd94a0f26ce023e78ab4d278c090472a))\n\n\n\n\n\n## [1.5.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.5.0...@amplitude/analytics-react-native@1.5.1) (2025-08-05)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n\n\n\n\n# [1.5.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.1.7...@amplitude/analytics-react-native@1.5.0) (2025-07-29)\n\n\n### Bug Fixes\n\n* add app_set_id, idfa and idfv support ([#458](https://github.com/amplitude/Amplitude-TypeScript/issues/458)) ([00c6cac](https://github.com/amplitude/Amplitude-TypeScript/commit/00c6cac1e30dc73a5c9813f1f44a44ca341ec55b)), closes [#424](https://github.com/amplitude/Amplitude-TypeScript/issues/424)\n* **analytics-react-native:** migrate to analytics-core v2 ([#1216](https://github.com/amplitude/Amplitude-TypeScript/issues/1216)) ([76e85a1](https://github.com/amplitude/Amplitude-TypeScript/commit/76e85a1daa704a1c4c44d0176a56c8dd8d4ad3f1))\n* **analytics-react-native:** support RN 0.73 ([#871](https://github.com/amplitude/Amplitude-TypeScript/issues/871)) ([d0ae4d6](https://github.com/amplitude/Amplitude-TypeScript/commit/d0ae4d6d77b55d9621a4616e0cb8521ae2c9a61b))\n* location is polyfilled to an empty object ([#738](https://github.com/amplitude/Amplitude-TypeScript/issues/738)) ([130add9](https://github.com/amplitude/Amplitude-TypeScript/commit/130add99485c0d33e6a8ce32168212a2453025e4))\n* simplify plugins and eliminate enums ([#407](https://github.com/amplitude/Amplitude-TypeScript/issues/407)) ([890ec66](https://github.com/amplitude/Amplitude-TypeScript/commit/890ec6695a8b25cd6988e9f7ae584d4ba2835f67))\n\n\n### Features\n\n* add offline mode ([#644](https://github.com/amplitude/Amplitude-TypeScript/issues/644)) ([f2cd717](https://github.com/amplitude/Amplitude-TypeScript/commit/f2cd717316eef66b101153cb8eedf37fadc6de0c))\n* add option for instance name ([#428](https://github.com/amplitude/Amplitude-TypeScript/issues/428)) ([1a8ff7d](https://github.com/amplitude/Amplitude-TypeScript/commit/1a8ff7d665d2a936db7cb42f4cde5350379b7cae))\n* added extendSession() method to Browser Client ([#425](https://github.com/amplitude/Amplitude-TypeScript/issues/425)) ([#433](https://github.com/amplitude/Amplitude-TypeScript/issues/433)) ([0f5fccc](https://github.com/amplitude/Amplitude-TypeScript/commit/0f5fccc83d3f7f0a80adc4a0807fbd7e71c72e4a))\n* allow cross subdomain excluded referrer ([#391](https://github.com/amplitude/Amplitude-TypeScript/issues/391)) ([f34f64b](https://github.com/amplitude/Amplitude-TypeScript/commit/f34f64b68bbd328da354afae61ca416d7055a734))\n* **analytics-browser:** autocapture network errors ([#1050](https://github.com/amplitude/Amplitude-TypeScript/issues/1050)) ([104350f](https://github.com/amplitude/Amplitude-TypeScript/commit/104350ffe8b1bd1a7090482ac3bf24d85672bd43))\n* **analytics-core:** expose unified AmplitudeContext and AnalyticsClient ([#1222](https://github.com/amplitude/Amplitude-TypeScript/issues/1222)) ([7e32712](https://github.com/amplitude/Amplitude-TypeScript/commit/7e327128b4032592897dc6bb50dedda053ad8eda))\n* make default event tracking enabled by default ([#386](https://github.com/amplitude/Amplitude-TypeScript/issues/386)) ([242f42d](https://github.com/amplitude/Amplitude-TypeScript/commit/242f42dd2e46eaec95c827795e04f74fba39c35f))\n* simplify browser SDK options and plugin options interface ([#384](https://github.com/amplitude/Amplitude-TypeScript/issues/384)) ([b464cfb](https://github.com/amplitude/Amplitude-TypeScript/commit/b464cfb8e09d722bf06ed3c11955f77465a23daf))\n* simplify user identity storage options/configuration ([#390](https://github.com/amplitude/Amplitude-TypeScript/issues/390)) ([f8cf0cc](https://github.com/amplitude/Amplitude-TypeScript/commit/f8cf0cca8c2a17738f13878642fa5b37c0070f77))\n\n\n### Reverts\n\n* Revert \"ci: remove noImplicitUseStrict as it's deprecated in ts 5.5 (#974)\" ([29df7ea](https://github.com/amplitude/Amplitude-TypeScript/commit/29df7ea187a414ddbd1894f89f996a67a3c5c36c)), closes [#974](https://github.com/amplitude/Amplitude-TypeScript/issues/974)\n* Revert \"chore(release): publish\" ([d392f62](https://github.com/amplitude/Amplitude-TypeScript/commit/d392f6290b8bb4dd955d6e6f20b00191679489c4))\n* PR 1058 ([#1077](https://github.com/amplitude/Amplitude-TypeScript/issues/1077)) ([e72835e](https://github.com/amplitude/Amplitude-TypeScript/commit/e72835e07ec0318d564439a7ddd47f37b156c6c3))\n\n\n\n\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.4.14](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.4.13...@amplitude/analytics-react-native@1.4.14) (2025-07-08)\n\n### Bug Fixes\n\n- **analytics-react-native:** country uppercase with existing Kotlin version\n  ([#1198](https://github.com/amplitude/Amplitude-TypeScript/issues/1198))\n  ([9e7ed0e](https://github.com/amplitude/Amplitude-TypeScript/commit/9e7ed0e345e5c5de28a8c76ced512c7343d204ea))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.4.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.4.12...@amplitude/analytics-react-native@1.4.13) (2025-03-03)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.4.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.4.11...@amplitude/analytics-react-native@1.4.12) (2025-02-28)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.4.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.4.10...@amplitude/analytics-react-native@1.4.11) (2024-11-04)\n\n### Bug Fixes\n\n- make table non nullable\n  ([0dbd936](https://github.com/amplitude/Amplitude-TypeScript/commit/0dbd93636e404f1b8cb090661ff43da11e51ede2))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.4.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.4.9...@amplitude/analytics-react-native@1.4.10) (2024-09-23)\n\n### Bug Fixes\n\n- **analytics-react-native:** should export extendSession in client\n  ([#884](https://github.com/amplitude/Amplitude-TypeScript/issues/884))\n  ([ff2e9b5](https://github.com/amplitude/Amplitude-TypeScript/commit/ff2e9b56c71636fec79d56e5a6d2fd3f567a29b3))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.4.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.4.8...@amplitude/analytics-react-native@1.4.9) (2024-05-28)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.4.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.4.7...@amplitude/analytics-react-native@1.4.8) (2024-05-07)\n\n### Bug Fixes\n\n- location is polyfilled to an empty object ([#739](https://github.com/amplitude/Amplitude-TypeScript/issues/739))\n  ([25dfbdf](https://github.com/amplitude/Amplitude-TypeScript/commit/25dfbdf6f72d12dbb6c4d8f932e7ba7f34bb5dc3))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.4.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.4.6...@amplitude/analytics-react-native@1.4.7) (2023-12-21)\n\n### Bug Fixes\n\n- update default not tracking country value ([#641](https://github.com/amplitude/Amplitude-TypeScript/issues/641))\n  ([3262f4e](https://github.com/amplitude/Amplitude-TypeScript/commit/3262f4eed25561fdb98f0140308c5e91405bf175))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.4.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.4.5...@amplitude/analytics-react-native@1.4.6) (2023-12-19)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.4.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.4.4...@amplitude/analytics-react-native@1.4.5) (2023-10-26)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.4.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.4.3...@amplitude/analytics-react-native@1.4.4) (2023-09-08)\n\n### Bug Fixes\n\n- config values should take precedence over nativemodule in Context plugin\n  ([#575](https://github.com/amplitude/Amplitude-TypeScript/issues/575))\n  ([13dbb29](https://github.com/amplitude/Amplitude-TypeScript/commit/13dbb29be5916f57b58703ecae3f4deb7f45359e))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.4.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.4.2...@amplitude/analytics-react-native@1.4.3) (2023-08-22)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.4.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.4.1...@amplitude/analytics-react-native@1.4.2) (2023-08-22)\n\n### Bug Fixes\n\n- collect 'country' data in react-native ([#547](https://github.com/amplitude/Amplitude-TypeScript/issues/547))\n  ([2e1e8dd](https://github.com/amplitude/Amplitude-TypeScript/commit/2e1e8ddd6366da1eabbd731e2818bf2ce5fef3bb))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.4.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.4.0...@amplitude/analytics-react-native@1.4.1) (2023-08-17)\n\n### Bug Fixes\n\n- collect 'carrier' data in react-native iOS ([#545](https://github.com/amplitude/Amplitude-TypeScript/issues/545))\n  ([057e4d9](https://github.com/amplitude/Amplitude-TypeScript/commit/057e4d9a4856755ab9dd7340c705dc3118482971))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.4.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.3.6...@amplitude/analytics-react-native@1.4.0) (2023-08-15)\n\n### Features\n\n- update Android files to support recent React Native versions\n  ([#533](https://github.com/amplitude/Amplitude-TypeScript/issues/533))\n  ([c06209a](https://github.com/amplitude/Amplitude-TypeScript/commit/c06209a77c375facad60676aefb0fa314af865a8))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.3.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.3.5...@amplitude/analytics-react-native@1.3.6) (2023-08-15)\n\n### Bug Fixes\n\n- add example react-native plugin to get location, remove unused location-related logic from react-native\n  ([#536](https://github.com/amplitude/Amplitude-TypeScript/issues/536))\n  ([3fdfc53](https://github.com/amplitude/Amplitude-TypeScript/commit/3fdfc53aeded5c87b280a77038a73e5c2849e629))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.3.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.3.4...@amplitude/analytics-react-native@1.3.5) (2023-08-11)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.3.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.3.3...@amplitude/analytics-react-native@1.3.4) (2023-08-10)\n\n### Bug Fixes\n\n- migrate legacy data ([#486](https://github.com/amplitude/Amplitude-TypeScript/issues/486))\n  ([586cbc5](https://github.com/amplitude/Amplitude-TypeScript/commit/586cbc59dca0da88dd1564b93cb8cc5c8ac7796d))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.3.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.3.2...@amplitude/analytics-react-native@1.3.3) (2023-07-27)\n\n### Bug Fixes\n\n- updated session logic and tests ([#447](https://github.com/amplitude/Amplitude-TypeScript/issues/447))\n  ([ed03435](https://github.com/amplitude/Amplitude-TypeScript/commit/ed034358065d8f3dc6da4be9a880de5af001d6c2))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.3.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.3.1...@amplitude/analytics-react-native@1.3.2) (2023-07-26)\n\n### Bug Fixes\n\n- react-native fix context plugin to include app version on mobile\n  ([#507](https://github.com/amplitude/Amplitude-TypeScript/issues/507))\n  ([cf93eaf](https://github.com/amplitude/Amplitude-TypeScript/commit/cf93eaf295645232e839e4625cfbbeaa933bfefc))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.3.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.3.0...@amplitude/analytics-react-native@1.3.1) (2023-07-05)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.3.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.2.2...@amplitude/analytics-react-native@1.3.0) (2023-06-26)\n\n### Bug Fixes\n\n- add app_set_id, idfa and idfv support ([#456](https://github.com/amplitude/Amplitude-TypeScript/issues/456))\n  ([83ce837](https://github.com/amplitude/Amplitude-TypeScript/commit/83ce8371f8edea800ff6ac11c6184d8cc1bb17c7))\n\n### Features\n\n- add option for instance name ([#428](https://github.com/amplitude/Amplitude-TypeScript/issues/428))\n  ([#442](https://github.com/amplitude/Amplitude-TypeScript/issues/442))\n  ([569464c](https://github.com/amplitude/Amplitude-TypeScript/commit/569464c698eb54b3da05e203ac90cf1a399d96ed))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.2.1...@amplitude/analytics-react-native@1.2.2) (2023-06-14)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.2.0...@amplitude/analytics-react-native@1.2.1) (2023-06-13)\n\n### Bug Fixes\n\n- do not fetch advertising Id if adid tracking is disabled\n  ([#424](https://github.com/amplitude/Amplitude-TypeScript/issues/424))\n  ([52f7b08](https://github.com/amplitude/Amplitude-TypeScript/commit/52f7b08cc9501e41a8e421c7f84458dea78db972))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.2.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.1.9...@amplitude/analytics-react-native@1.2.0) (2023-06-13)\n\n### Features\n\n- added extendSession() method to Browser Client ([#425](https://github.com/amplitude/Amplitude-TypeScript/issues/425))\n  ([c6c82ba](https://github.com/amplitude/Amplitude-TypeScript/commit/c6c82bae762493a07922e08baca5db1bd91e483e))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.1.8...@amplitude/analytics-react-native@1.1.9) (2023-06-08)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.1.8-beta.0...@amplitude/analytics-react-native@1.1.8) (2023-06-06)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.8-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.1.7...@amplitude/analytics-react-native@1.1.8-beta.0) (2023-06-06)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.1.6...@amplitude/analytics-react-native@1.1.7) (2023-05-04)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.1.5...@amplitude/analytics-react-native@1.1.6) (2023-04-27)\n\n### Bug Fixes\n\n- add connector event listener after plugins and queued functions\n  ([#378](https://github.com/amplitude/Amplitude-TypeScript/issues/378))\n  ([a2fc8b6](https://github.com/amplitude/Amplitude-TypeScript/commit/a2fc8b6a7ec87dd8eab6538c1e9929c57804b899))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.1.4...@amplitude/analytics-react-native@1.1.5) (2023-04-27)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.1.3...@amplitude/analytics-react-native@1.1.4) (2023-04-25)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.1.2...@amplitude/analytics-react-native@1.1.3) (2023-04-06)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.1.1...@amplitude/analytics-react-native@1.1.2) (2023-03-31)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.1.1-beta.0...@amplitude/analytics-react-native@1.1.1) (2023-03-03)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.1-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.1.0...@amplitude/analytics-react-native@1.1.1-beta.0) (2023-03-03)\n\n### Bug Fixes\n\n- push user id and device id changes to analytics connector\n  ([#342](https://github.com/amplitude/Amplitude-TypeScript/issues/342))\n  ([3214b08](https://github.com/amplitude/Amplitude-TypeScript/commit/3214b0836eb03e39b5753b1e6be30e1c2f5770ca))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.1.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.1.0-beta.1...@amplitude/analytics-react-native@1.1.0) (2023-02-27)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.1.0-beta.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.1.0-beta.0...@amplitude/analytics-react-native@1.1.0-beta.1) (2023-02-24)\n\n### Bug Fixes\n\n- improper cookie usage ([#330](https://github.com/amplitude/Amplitude-TypeScript/issues/330))\n  ([e670091](https://github.com/amplitude/Amplitude-TypeScript/commit/e670091e59014bb35bd9b3ec2a7192f259393575))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.1.0-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.0.1...@amplitude/analytics-react-native@1.1.0-beta.0) (2023-02-24)\n\n### Features\n\n- pass amplitude instance to plugin.setup for enhanced plugin capabilities\n  ([#328](https://github.com/amplitude/Amplitude-TypeScript/issues/328))\n  ([91eeaa0](https://github.com/amplitude/Amplitude-TypeScript/commit/91eeaa0d6bff6bde39538bb54548a938df784462))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.0.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@1.0.0...@amplitude/analytics-react-native@1.0.1) (2023-02-09)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.0.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.8.0...@amplitude/analytics-react-native@1.0.0) (2023-02-02)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.8.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.8.0-beta.0...@amplitude/analytics-react-native@0.8.0) (2023-01-31)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.8.0-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.7.2...@amplitude/analytics-react-native@0.8.0-beta.0) (2023-01-26)\n\n### Bug Fixes\n\n- updates required kotlin version for react native SDK\n  ([9184714](https://github.com/amplitude/Amplitude-TypeScript/commit/9184714ed0173a468fda86429b734d9ef26d6f16))\n\n### Features\n\n- allow opt out of deleting legacy sdk cookies\n  ([c6a82fb](https://github.com/amplitude/Amplitude-TypeScript/commit/c6a82fb52e1301e427116891d1f31208bcfc6548))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.7.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.7.1...@amplitude/analytics-react-native@0.7.2) (2023-01-11)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.7.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.7.0...@amplitude/analytics-react-native@0.7.1) (2022-12-21)\n\n### Bug Fixes\n\n- upgrade dependencies to resolve dependabot vulnerability alerts\n  ([#299](https://github.com/amplitude/Amplitude-TypeScript/issues/299))\n  ([7dd1cd1](https://github.com/amplitude/Amplitude-TypeScript/commit/7dd1cd1b23a71981a4ad90b4b30cc9b7d28c4412))\n\n### Reverts\n\n- Revert \"Updated dependencies\"\n  ([7ca9964](https://github.com/amplitude/Amplitude-TypeScript/commit/7ca9964781e4b900c6c027bdddf2ae1e7428ba18))\n\n# [0.7.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.6.1...@amplitude/analytics-react-native@0.7.0) (2022-11-28)\n\n### Features\n\n- persisted event identifiers (React Native) ([#280](https://github.com/amplitude/Amplitude-TypeScript/issues/280))\n  ([bd35e73](https://github.com/amplitude/Amplitude-TypeScript/commit/bd35e73a0a08db6609938d27f00f54cbf77ff6c1))\n\n## [0.6.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.6.0...@amplitude/analytics-react-native@0.6.1) (2022-11-16)\n\n### Bug Fixes\n\n- exclude '**mocks**' from typescript declarations\n  ([#277](https://github.com/amplitude/Amplitude-TypeScript/issues/277))\n  ([b6ed565](https://github.com/amplitude/Amplitude-TypeScript/commit/b6ed565928943e3c25fb584b7cd71a0f6d734603))\n- set React Native default session timeout to 5 minutes (same for other mobile devices)\n  ([#278](https://github.com/amplitude/Amplitude-TypeScript/issues/278))\n  ([a456471](https://github.com/amplitude/Amplitude-TypeScript/commit/a4564719ccd0628690427f198a8ca83d60ceb1ac))\n\n# [0.6.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.5.1...@amplitude/analytics-react-native@0.6.0) (2022-11-15)\n\n### Features\n\n- auto-tracking session events ([#263](https://github.com/amplitude/Amplitude-TypeScript/issues/263))\n  ([75347c6](https://github.com/amplitude/Amplitude-TypeScript/commit/75347c61984832a6ade3ca9e6abe1bbd0faa6cde))\n\n## [0.5.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.5.0...@amplitude/analytics-react-native@0.5.1) (2022-11-01)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n# [0.5.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.4.11...@amplitude/analytics-react-native@0.5.0) (2022-11-01)\n\n### Features\n\n- enhance logger with debug information ([#254](https://github.com/amplitude/Amplitude-TypeScript/issues/254))\n  ([5c6175e](https://github.com/amplitude/Amplitude-TypeScript/commit/5c6175e9372cbeea264ddb34c6cc68148063d4f7))\n\n## [0.4.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.4.10...@amplitude/analytics-react-native@0.4.11) (2022-10-26)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n## [0.4.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.4.10-beta.1...@amplitude/analytics-react-native@0.4.10) (2022-10-25)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n## [0.4.10-beta.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.4.10-beta.0...@amplitude/analytics-react-native@0.4.10-beta.1) (2022-10-25)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n## [0.4.10-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.4.9...@amplitude/analytics-react-native@0.4.10-beta.0) (2022-10-25)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n## [0.4.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.4.8...@amplitude/analytics-react-native@0.4.9) (2022-10-25)\n\n### Bug Fixes\n\n- add safe check for global scope before loading SDK\n  ([#252](https://github.com/amplitude/Amplitude-TypeScript/issues/252))\n  ([a3f4f6f](https://github.com/amplitude/Amplitude-TypeScript/commit/a3f4f6f7b11abd9cdbdf064e31e32d5fc3e92031))\n- invoke pre-init track fns after attribution ([#253](https://github.com/amplitude/Amplitude-TypeScript/issues/253))\n  ([b8996d7](https://github.com/amplitude/Amplitude-TypeScript/commit/b8996d793f74d388c1a96e0cde5c0ac060c1e565))\n\n## [0.4.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.4.7...@amplitude/analytics-react-native@0.4.8) (2022-10-14)\n\n### Bug Fixes\n\n- update userId/deviceId in identify call if eventOptions contains userId/deviceId\n  ([#244](https://github.com/amplitude/Amplitude-TypeScript/issues/244))\n  ([578cbe2](https://github.com/amplitude/Amplitude-TypeScript/commit/578cbe218de84d7fdd4930f75820beda6f85ce6d))\n\n## [0.4.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.4.6...@amplitude/analytics-react-native@0.4.7) (2022-10-04)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n## [0.4.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.4.5...@amplitude/analytics-react-native@0.4.6) (2022-09-30)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n## [0.4.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.4.4...@amplitude/analytics-react-native@0.4.5) (2022-09-30)\n\n### Bug Fixes\n\n- cover the case when apiKey is missing in the runtime\n  ([#240](https://github.com/amplitude/Amplitude-TypeScript/issues/240))\n  ([308bbe8](https://github.com/amplitude/Amplitude-TypeScript/commit/308bbe8337cbab366a0ca255f2d665101f4781a0))\n\n## [0.4.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.4.4-beta.1...@amplitude/analytics-react-native@0.4.4) (2022-09-28)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n## [0.4.4-beta.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.4.4-beta.0...@amplitude/analytics-react-native@0.4.4-beta.1) (2022-09-27)\n\n### Bug Fixes\n\n- define correct dependencies for @amplitude/analytics-connector\n  ([#234](https://github.com/amplitude/Amplitude-TypeScript/issues/234))\n  ([41c1351](https://github.com/amplitude/Amplitude-TypeScript/commit/41c1351e441b890b016ba123c4ed5747a4c33adb))\n\n## [0.4.4-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.4.3...@amplitude/analytics-react-native@0.4.4-beta.0) (2022-09-26)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n## [0.4.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.4.2...@amplitude/analytics-react-native@0.4.3) (2022-09-26)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n## [0.4.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.4.1...@amplitude/analytics-react-native@0.4.2) (2022-09-22)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n## [0.4.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.4.0...@amplitude/analytics-react-native@0.4.1) (2022-09-16)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n# [0.4.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.3.3...@amplitude/analytics-react-native@0.4.0) (2022-09-08)\n\n### Features\n\n- add ingestion_metadata field ([#212](https://github.com/amplitude/Amplitude-TypeScript/issues/212))\n  ([ebe8448](https://github.com/amplitude/Amplitude-TypeScript/commit/ebe8448b23609134f846e18da2e769158ca30bf1))\n\n## [0.3.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.3.2...@amplitude/analytics-react-native@0.3.3) (2022-08-31)\n\n**Note:** Version bump only for package @amplitude/analytics-react-native\n\n## [0.3.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.3.1...@amplitude/analytics-react-native@0.3.2) (2022-08-29)\n\n### Bug Fixes\n\n- add conditional check for window.location.search\n  ([#198](https://github.com/amplitude/Amplitude-TypeScript/issues/198))\n  ([e61b4db](https://github.com/amplitude/Amplitude-TypeScript/commit/e61b4db25e2e7677a3dcb2c8e71f26bcac9a9fd5))\n\n## [0.3.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.3.0...@amplitude/analytics-react-native@0.3.1) (2022-08-23)\n\n### Bug Fixes\n\n- pass options to testStorage ([#201](https://github.com/amplitude/Amplitude-TypeScript/issues/201))\n  ([6e22eb0](https://github.com/amplitude/Amplitude-TypeScript/commit/6e22eb0c101c743b15bb49d9491082fd1fe1d90e))\n\n# [0.3.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.2.4...@amplitude/analytics-react-native@0.3.0) (2022-08-18)\n\n### Bug Fixes\n\n- handle parsing malformed urls for web attribution\n  ([#192](https://github.com/amplitude/Amplitude-TypeScript/issues/192))\n  ([cd254d6](https://github.com/amplitude/Amplitude-TypeScript/commit/cd254d6319d8bc7d92affc263ec12c9c39f82fb2))\n- prevent concurrent init calls ([#191](https://github.com/amplitude/Amplitude-TypeScript/issues/191))\n  ([efda076](https://github.com/amplitude/Amplitude-TypeScript/commit/efda0760f4f1e92e47a3150985e18efcc3b108d9))\n- removes unused tracking options ([#193](https://github.com/amplitude/Amplitude-TypeScript/issues/193))\n  ([2b57a8e](https://github.com/amplitude/Amplitude-TypeScript/commit/2b57a8e07971312b40c8287e2daddcfb2b55a832))\n\n### Features\n\n- adds create instance api ([#188](https://github.com/amplitude/Amplitude-TypeScript/issues/188))\n  ([050c1d9](https://github.com/amplitude/Amplitude-TypeScript/commit/050c1d96cedbc9e68aedf6fd55e85d2d3dc2fee4))\n\n## [0.2.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.2.3...@amplitude/analytics-react-native@0.2.4) (2022-08-16)\n\n### Bug Fixes\n\n- enable adid by default\n  ([a24dfe0](https://github.com/amplitude/Amplitude-TypeScript/commit/a24dfe05291fd51da50f531990f68ed27dcca7c8))\n\n## [0.2.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.2.2...@amplitude/analytics-react-native@0.2.3) (2022-08-13)\n\n### Bug Fixes\n\n- correct platform and add adid ([#184](https://github.com/amplitude/Amplitude-TypeScript/issues/184))\n  ([7134a43](https://github.com/amplitude/Amplitude-TypeScript/commit/7134a4398844516f3d868daf82df9cf2e19d3c39))\n\n## [0.2.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.2.1...@amplitude/analytics-react-native@0.2.2) (2022-08-12)\n\n### Bug Fixes\n\n- add callable queue when init is pending ([#181](https://github.com/amplitude/Amplitude-TypeScript/issues/181))\n  ([d8fc361](https://github.com/amplitude/Amplitude-TypeScript/commit/d8fc36195b96e2c10ccc5106027beaa7e970e0c0))\n\n## [0.2.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.2.0...@amplitude/analytics-react-native@0.2.1) (2022-08-02)\n\n### Bug Fixes\n\n- implement integration with experiment sdk for browser\n  ([#156](https://github.com/amplitude/Amplitude-TypeScript/issues/156))\n  ([075ba84](https://github.com/amplitude/Amplitude-TypeScript/commit/075ba84bb4d05fb6a256272d19c03cb692cb0c28))\n\n# [0.2.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.1.1...@amplitude/analytics-react-native@0.2.0) (2022-07-29)\n\n### Features\n\n- add reset method for resetting userId and deviceId\n  ([#157](https://github.com/amplitude/Amplitude-TypeScript/issues/157))\n  ([8bfc864](https://github.com/amplitude/Amplitude-TypeScript/commit/8bfc864b15dd7e427556a50bc3de6b43b2485189))\n\n## [0.1.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-react-native@0.1.0...@amplitude/analytics-react-native@0.1.1) (2022-07-22)\n\n### Bug Fixes\n\n- missing tracked events before init issue ([#144](https://github.com/amplitude/Amplitude-TypeScript/issues/144))\n  ([60d0f68](https://github.com/amplitude/Amplitude-TypeScript/commit/60d0f6848087f7b8fc3c870d55489a238e841b26))\n- removes saveEvents config ([#147](https://github.com/amplitude/Amplitude-TypeScript/issues/147))\n  ([6fde736](https://github.com/amplitude/Amplitude-TypeScript/commit/6fde736ca8a865462522082a8085673756dbcc7d))\n- update default flush config for node ([#152](https://github.com/amplitude/Amplitude-TypeScript/issues/152))\n  ([2445dff](https://github.com/amplitude/Amplitude-TypeScript/commit/2445dff0842e7e0a2b7ee767ab926b5a93348214))\n\n# 0.1.0 (2022-07-15)\n\n### Features\n\n- react-native with web support ([#126](https://github.com/amplitude/Amplitude-TypeScript/issues/126))\n  ([5384130](https://github.com/amplitude/Amplitude-TypeScript/commit/5384130904d19b4b6cf4b43826efa2b373b47b85))\n"
  },
  {
    "path": "packages/analytics-react-native/README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://amplitude.com\" target=\"_blank\" align=\"center\">\n    <img src=\"https://static.amplitude.com/lightning/46c85bfd91905de8047f1ee65c7c93d6fa9ee6ea/static/media/amplitude-logo-with-text.4fb9e463.svg\" width=\"280\">\n  </a>\n  <br />\n</p>\n\n# @amplitude/analytics-react-native\n\nOfficial Amplitude SDK for React Native\n\n# Installation and Quick Start\n\nPlease visit our :100:[Developer Center](https://www.docs.developers.amplitude.com/data/sdks/typescript-react-native/) for instructions on installing and using our the SDK.\n\n## Installation\n\nTo get started with using Amplitude React Native SDK, install the package to your project via NPM. In addition, this package relies on `@react-native-async-storage/async-storage`, which must also be installed.\n\n```sh\n# npm\nnpm install @amplitude/analytics-react-native\nnpm install @react-native-async-storage/async-storage\n\n# yarn\nyarn add @amplitude/analytics-react-native\nyarn add @react-native-async-storage/async-storage\n```\n\n## Usage\n\n### Initializing SDK\n\nInitialization is necessary before any instrumentation is done. The API key for your Amplitude project is required.\n\n```typescript\namplitude.init(API_KEY);\n```\n\n### Set UserId\n\nSets an `userId` (usually called after user logs in).\n```typescript\nimport { setUserId } from '@amplitude/analytics-react-native';\n\nsetUserId('xxxxx');\n```\n\n\n### Tracking an Event\n\nEvents represent how users interact with your application. For example, “Button Clicked” may be an action you want to note.\n\n```typescript\nimport { track } from '@amplitude/analytics-react-native';\n\n// Track a basic event\ntrack('Button Clicked');\n\n// Track events with additional properties\nconst eventProperties = {\n  selectedColors: ['red', 'blue'],\n};\ntrack('Button Clicked', eventProperties);\n```\n\n### User Properties\n\nUser properties help you understand your users at the time they performed some action within your app such as their device details, their preferences, or language.\n\n```typescript\nimport { Identify, identify } from '@amplitude/analytics-react-native';\n\nconst event = new Identify();\n\n// sets the value of a user property\nevent.set('key1', 'value1');\n\n// sets the value of a user property only once\nevent.setOnce('key1', 'value1');\n\n// increments a user property by some numerical value.\nevent.add('value1', 10);\n\n// pre inserts a value or values to a user property\nevent.preInsert('ab-tests', 'new-user-test');\n\n// post inserts a value or values to a user property\nevent.postInsert('ab-tests', 'new-user-test');\n\n// removes a value or values to a user property\nevent.remove('ab-tests', 'new-user-test')\n\n// sends identify event\nidentify(event);\n```\n\n### prepend/append\n\n* append will append a value or values to a user property array.\n* prepend will prepend a value or values to a user property.\n\n### User Groups\n\n```typescript\nimport { setGroup } from '@amplitude/analytics-react-native';\n\n// set group with single group name\nsetGroup('orgId', '15');\n\n// set group with multiple group names\nsetGroup('sport', ['soccer', 'tennis']);\n```\n\n### Group Identify\n\nThis feature is only available to Growth and Enterprise customers who have purchased the [Accounts add-on](https://amplitude.zendesk.com/hc/en-us/articles/115001765532).\n\nUse the Group Identify API to set or update properties of particular groups. However, these updates will only affect events going forward.\n\n```typescript\nimport { Identify, groupIdentify } from '@amplitude/analytics-react-native';\n\nconst groupType = 'plan';\nconst groupName = 'enterprise';\nconst identity = new Identify()\nidentity.set('key1', 'value1');\n\ngroupIdentify(groupType, groupName, identity);\n```\n\n### Track Revenue\n\nRevenue instances will store each revenue transaction and allow you to define several special revenue properties (such as 'revenueType', 'productIdentifier', etc.) that are used in Amplitude's Event Segmentation and Revenue LTV charts. These Revenue instance objects are then passed into `revenue` to send as revenue events to Amplitude. This allows us to automatically display data relevant to revenue in the platform. You can use this to track both in-app and non-in-app purchases.\n\n```typescript\nimport { Revenue, revenue } from '@amplitude/analytics-react-native';\n\nconst event = new Revenue()\n  .setProductId('com.company.productId')\n  .setPrice(3.99)\n  .setQuantity(3);\n\nrevenue(event);\n```\n\n### Callback\n\nAll asynchronous API are optionally awaitable through a specific Promise interface. This also serves as callback interface.\n\n```typescript\n// Using async/await\nconst results = await track('Button Clicked').promise;\nresult.event; // {...} (The final event object sent to Amplitude)\nresult.code; // 200 (The HTTP response status code of the request.\nresult.message; // \"Event tracked successfully\" (The response message)\n\n// Using promises\ntrack('Button Clicked').promise.then((result) => {\n  result.event; // {...} (The final event object sent to Amplitude)\n  result.code; // 200 (The HTTP response status code of the request.\n  result.message; // \"Event tracked successfully\" (The response message)\n});\n```\n\n### User Log out\n\nThis updates user ID and device ID. After calling `reset()` the succeeding events now belong to a new user identity.\n\n```typescript\nimport { reset } from '@amplitude/analytics-react-native';\n\nreset();\n```\n"
  },
  {
    "path": "packages/analytics-react-native/__mocks__/@react-native-async-storage/async-storage.ts",
    "content": "import AsyncStorage from '@react-native-async-storage/async-storage/jest/async-storage-mock';\nexport default AsyncStorage;\n"
  },
  {
    "path": "packages/analytics-react-native/amplitude-react-native.podspec",
    "content": "require \"json\"\n\npackage = JSON.parse(File.read(File.join(__dir__, \"package.json\")))\n\nPod::Spec.new do |s|\n  s.name = \"amplitude-react-native\"\n  s.version = package[\"version\"]\n  s.summary = package[\"description\"]\n  s.homepage = package[\"homepage\"]\n  s.license = package[\"license\"]\n  s.authors = package[\"author\"]\n\n  s.swift_version = \"5.0\"\n\n  s.platforms = { :ios => \"10.0\", :tvos => \"10.0\" }\n  s.source = { :git => \"https://github.com/amplitude/Amplitude-TypeScript.git\", :tag => \"#{s.version}\" }\n\n  s.source_files = \"ios/**/*.{h,m,mm,swift}\"\n\n  s.dependency \"React-Core\"\nend\n"
  },
  {
    "path": "packages/analytics-react-native/android/build.gradle",
    "content": "def isNewArchitectureEnabled() {\n  return rootProject.hasProperty(\"newArchEnabled\") && rootProject.getProperty(\"newArchEnabled\") == \"true\"\n}\n\napply plugin: \"com.android.library\"\napply plugin: \"kotlin-android\"\n\n\ndef appProject = rootProject.allprojects.find { it.plugins.hasPlugin('com.android.application') }\n\nif (isNewArchitectureEnabled()) {\n  apply plugin: \"com.facebook.react\"\n}\n\ndef getExtOrDefault(name) {\n  return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties[\"AmplitudeReactNative_\" + name]\n}\n\ndef getExtOrIntegerDefault(name) {\n  return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties[\"AmplitudeReactNative_\" + name]).toInteger()\n}\n\ndef supportsNamespace() {\n  def parsed = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')\n  def major = parsed[0].toInteger()\n  def minor = parsed[1].toInteger()\n\n  // Namespace support was added in 7.3.0\n  if (major == 7 && minor >= 3) {\n    return true\n  }\n\n  return major >= 8\n}\n\nandroid {\n  if (supportsNamespace()) {\n    namespace \"com.amplitude.reactnative\"\n\n    sourceSets {\n      main {\n        manifest.srcFile \"src/main/AndroidManifestNew.xml\"\n      }\n    }\n  }\n\n  compileSdkVersion getExtOrIntegerDefault(\"compileSdkVersion\")\n\n  defaultConfig {\n    minSdkVersion getExtOrIntegerDefault(\"minSdkVersion\")\n    targetSdkVersion getExtOrIntegerDefault(\"targetSdkVersion\")\n    buildConfigField \"boolean\", \"IS_NEW_ARCHITECTURE_ENABLED\", isNewArchitectureEnabled().toString()\n  }\n  buildTypes {\n    release {\n      minifyEnabled false\n    }\n  }\n\n  lintOptions {\n    disable \"GradleCompatible\"\n  }\n\n  compileOptions {\n    sourceCompatibility JavaVersion.VERSION_1_8\n    targetCompatibility JavaVersion.VERSION_1_8\n  }\n\n}\n\nrepositories {\n  mavenCentral()\n  google()\n}\n\ndef kotlin_version = getExtOrDefault(\"kotlinVersion\")\n\ndependencies {\n  // For < 0.71, this will be from the local maven repo\n  // For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin\n  //noinspection GradleDynamicVersion\n  implementation \"com.facebook.react:react-native:+\"\n  implementation \"org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version\"\n}\n\nif (isNewArchitectureEnabled()) {\n  react {\n    jsRootDir = file(\"../src/\")\n    libraryName = \"AmplitudeReactNative\"\n    codegenJavaPackageName = \"com.amplitude.reactnative\"\n  }\n}\n"
  },
  {
    "path": "packages/analytics-react-native/android/gradle.properties",
    "content": "AmplitudeReactNative_kotlinVersion=1.7.0\nAmplitudeReactNative_minSdkVersion=21\nAmplitudeReactNative_targetSdkVersion=31\nAmplitudeReactNative_compileSdkVersion=31\nAmplitudeReactNative_ndkversion=21.4.7075529\n"
  },
  {
    "path": "packages/analytics-react-native/android/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n          package=\"com.amplitude.reactnative\">\n</manifest>\n"
  },
  {
    "path": "packages/analytics-react-native/android/src/main/AndroidManifestNew.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n</manifest>\n"
  },
  {
    "path": "packages/analytics-react-native/android/src/main/java/com/amplitude/reactnative/AmplitudeReactNativeModule.kt",
    "content": "package com.amplitude.reactnative\n\nimport com.facebook.react.bridge.Promise\nimport com.facebook.react.module.annotations.ReactModule\nimport com.facebook.react.bridge.ReactApplicationContext\nimport com.facebook.react.bridge.ReactContextBaseJavaModule\nimport com.facebook.react.bridge.ReactMethod\nimport com.facebook.react.bridge.ReadableMap\nimport com.facebook.react.bridge.WritableNativeArray\nimport com.facebook.react.bridge.WritableNativeMap\n\nconst val MODULE_NAME = \"AmplitudeReactNative\"\n\n@ReactModule(name = MODULE_NAME)\nclass AmplitudeReactNativeModule(private val reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {\n    companion object {\n        const val DEVICE_ID_KEY = \"device_id\"\n        const val USER_ID_KEY = \"user_id\"\n        const val LAST_EVENT_TIME_KEY = \"last_event_time\"\n        const val LAST_EVENT_ID_KEY = \"last_event_id\"\n        const val PREVIOUS_SESSION_ID_KEY = \"previous_session_id\"\n    }\n\n    private var androidContextProvider: AndroidContextProvider? = null\n\n    override fun getName(): String {\n        return MODULE_NAME\n    }\n\n    @ReactMethod\n    private fun getApplicationContext(options: ReadableMap, promise: Promise) {\n        val trackAdid = if (options.hasKey(\"adid\")) options.getBoolean(\"adid\") else false\n        if (androidContextProvider == null) {\n            androidContextProvider = AndroidContextProvider(reactContext.applicationContext, trackAdid)\n        }\n\n        promise.resolve(WritableNativeMap().apply {\n            putString(\"version\", androidContextProvider!!.versionName)\n            putString(\"platform\", androidContextProvider!!.platform)\n            putString(\"language\", androidContextProvider!!.language)\n            putString(\"country\", androidContextProvider!!.country)\n            putString(\"osName\", androidContextProvider!!.osName)\n            putString(\"osVersion\", androidContextProvider!!.osVersion)\n            putString(\"deviceBrand\", androidContextProvider!!.brand)\n            putString(\"deviceManufacturer\", androidContextProvider!!.manufacturer)\n            putString(\"deviceModel\", androidContextProvider!!.model)\n            putString(\"carrier\", androidContextProvider!!.carrier)\n            if (trackAdid) {\n                putString(\"adid\", androidContextProvider!!.advertisingId)\n            }\n            putString(\"appSetId\", androidContextProvider!!.appSetId)\n        })\n    }\n\n    @ReactMethod\n    private fun getLegacySessionData(instanceName: String?, promise: Promise) {\n        try {\n            val storage = LegacyDatabaseStorageProvider.getStorage(reactContext.applicationContext, instanceName)\n            val deviceId = getLegacyValue(storage, DEVICE_ID_KEY)\n            val userId = getLegacyValue(storage, USER_ID_KEY)\n            val previousSessionId = getLegacyLongValue(storage, PREVIOUS_SESSION_ID_KEY)\n            val lastEventTime = getLegacyLongValue(storage, LAST_EVENT_TIME_KEY)\n            val lastEventId = getLegacyLongValue(storage, LAST_EVENT_ID_KEY)\n            promise.resolve(WritableNativeMap().apply {\n                if (deviceId != null) {\n                    putString(\"deviceId\", deviceId)\n                }\n                if (userId != null) {\n                    putString(\"userId\", userId)\n                }\n                if (previousSessionId != null) {\n                    putDouble(\"sessionId\", previousSessionId.toDouble())\n                }\n                if (lastEventTime != null) {\n                    putDouble(\"lastEventTime\", lastEventTime.toDouble())\n                }\n                if (lastEventId != null) {\n                    putDouble(\"lastEventId\", lastEventId.toDouble())\n                }\n            })\n        } catch (e: Exception) {\n            LogcatLogger.logger.error(\n                \"can't get legacy session data: $e\"\n            )\n        }\n    }\n\n    private fun getLegacyValue(storage: LegacyDatabaseStorage, key: String): String? {\n        try {\n            return storage.getValue(key)\n        } catch (e: Exception) {\n            LogcatLogger.logger.error(\n                \"can't get legacy $key: $e\"\n            )\n            return null\n        }\n    }\n\n    private fun getLegacyLongValue(storage: LegacyDatabaseStorage, key: String): Long? {\n        try {\n            return storage.getLongValue(key)\n        } catch (e: Exception) {\n            LogcatLogger.logger.error(\n                \"can't get legacy $key: $e\"\n            )\n            return null\n        }\n    }\n\n    @ReactMethod\n    private fun getLegacyEvents(instanceName: String?, eventKind: String, promise: Promise) {\n        try {\n            val storage = LegacyDatabaseStorageProvider.getStorage(reactContext.applicationContext, instanceName)\n            val jsonEvents = when (eventKind) {\n                \"event\" -> storage.readEvents()\n                \"identify\" -> storage.readIdentifies()\n                \"interceptedIdentify\" -> storage.readInterceptedIdentifies()\n                else -> listOf()\n            }\n\n            val events = WritableNativeArray()\n            jsonEvents.forEach { event -> events.pushString(event.toString()) }\n            promise.resolve(events)\n        } catch (e: Exception) {\n            LogcatLogger.logger.error(\n                \"can't get legacy ${eventKind}s: $e\"\n            )\n            promise.resolve(WritableNativeArray())\n        }\n    }\n\n    @ReactMethod\n    private fun removeLegacyEvent(instanceName: String?, eventKind: String, eventId: Int) {\n        try {\n            val storage = LegacyDatabaseStorageProvider.getStorage(reactContext.applicationContext, instanceName)\n            when (eventKind) {\n                \"event\" -> storage.removeEvent(eventId)\n                \"identify\" -> storage.removeIdentify(eventId)\n                \"interceptedIdentify\" -> storage.removeInterceptedIdentify(eventId)\n            }\n        } catch (e: Exception) {\n            LogcatLogger.logger.error(\n                \"can't remove legacy $eventKind with id=$eventId: $e\"\n            )\n        }\n    }\n}\n"
  },
  {
    "path": "packages/analytics-react-native/android/src/main/java/com/amplitude/reactnative/AmplitudeReactNativePackage.java",
    "content": "package com.amplitude.reactnative;\n\nimport androidx.annotation.NonNull;\n\nimport com.facebook.react.ReactPackage;\nimport com.facebook.react.bridge.NativeModule;\nimport com.facebook.react.bridge.ReactApplicationContext;\nimport com.facebook.react.uimanager.ViewManager;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class AmplitudeReactNativePackage implements ReactPackage {\n    @NonNull\n    @Override\n    public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {\n        List<NativeModule> modules = new ArrayList<>();\n        modules.add(new AmplitudeReactNativeModule(reactContext));\n        return modules;\n    }\n\n    @NonNull\n    @Override\n    public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {\n        return Collections.emptyList();\n    }\n}\n"
  },
  {
    "path": "packages/analytics-react-native/android/src/main/java/com/amplitude/reactnative/AndroidContextProvider.kt",
    "content": "package com.amplitude.reactnative\n\nimport android.content.Context\nimport android.content.pm.PackageInfo\nimport android.content.pm.PackageManager\nimport android.content.res.Resources\nimport android.os.Build\nimport android.provider.Settings.Secure\nimport android.telephony.TelephonyManager\nimport java.lang.Exception\nimport java.lang.reflect.InvocationTargetException\nimport java.util.Locale\nimport java.util.UUID\n\nclass AndroidContextProvider(private val context: Context, shouldTrackAdid: Boolean) {\n  var shouldTrackAdid = true\n  private var cachedInfo: CachedInfo? = null\n    get() {\n      if (field == null) {\n        field = CachedInfo()\n      }\n      return field\n    }\n\n  /**\n   * Internal class serves as a cache\n   */\n  inner class CachedInfo {\n    var advertisingId: String?\n    val country: String?\n    val versionName: String?\n    val osName: String\n    val platform: String\n    val osVersion: String\n    val brand: String\n    val manufacturer: String\n    val model: String\n    val carrier: String?\n    val language: String\n    var limitAdTrackingEnabled: Boolean = true\n    val gpsEnabled: Boolean\n    var appSetId: String\n\n    init {\n      advertisingId = fetchAdvertisingId()\n      versionName = fetchVersionName()\n      osName = OS_NAME\n      platform = PLATFORM\n      osVersion = fetchOsVersion()\n      brand = fetchBrand()\n      manufacturer = fetchManufacturer()\n      model = fetchModel()\n      carrier = fetchCarrier()\n      country = fetchCountry()\n      language = fetchLanguage()\n      gpsEnabled = checkGPSEnabled()\n      appSetId = fetchAppSetId()\n    }\n\n    /**\n     * Internal methods for getting raw information\n     */\n    private fun fetchVersionName(): String? {\n      val packageInfo: PackageInfo\n      try {\n        packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)\n        return packageInfo.versionName\n      } catch (e: PackageManager.NameNotFoundException) {\n      } catch (e: Exception) {\n      }\n      return null\n    }\n\n    private fun fetchOsVersion(): String {\n      return Build.VERSION.RELEASE\n    }\n\n    private fun fetchBrand(): String {\n      return Build.BRAND\n    }\n\n    private fun fetchManufacturer(): String {\n      return Build.MANUFACTURER\n    }\n\n    private fun fetchModel(): String {\n      return Build.MODEL\n    }\n\n    private fun fetchCarrier(): String? {\n      try {\n        val manager = context\n          .getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager\n        return manager.networkOperatorName\n      } catch (e: Exception) {\n        // Failed to get network operator name from network\n      }\n      return null\n    }\n\n    private fun fetchCountry(): String? {\n      // This should not be called on the main thread.\n\n      var country = countryFromNetwork\n      return if (!country.isNullOrEmpty()) {\n        country\n      } else countryFromLocale\n    }\n\n    private val countryFromNetwork: String?\n      get() {\n        try {\n          val manager = context\n            .getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager\n          if (manager.phoneType != TelephonyManager.PHONE_TYPE_CDMA) {\n            val country = manager.networkCountryIso\n            if (country != null) {\n              return country.uppercase(Locale.US)\n            }\n          }\n        } catch (e: Exception) {\n          // Failed to get country from network\n        }\n        return null\n      }\n\n    private val locale: Locale\n      get() {\n        val configuration = Resources.getSystem().configuration\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n          val localeList = configuration.locales\n          if (localeList.isEmpty) {\n            return Locale.getDefault()\n          } else {\n            return localeList.get(0)\n          }\n        } else {\n          return configuration.locale\n        }\n      }\n\n    private val countryFromLocale: String\n      get() = locale.country\n\n    private fun fetchLanguage(): String {\n      return locale.language\n    }\n\n    private fun fetchAdvertisingId(): String? {\n      if (!shouldTrackAdid) {\n        return null\n      }\n\n      // This should not be called on the main thread.\n      return if (\"Amazon\" == fetchManufacturer()) {\n        fetchAndCacheAmazonAdvertisingId\n      } else {\n        fetchAndCacheGoogleAdvertisingId\n      }\n    }\n\n    private fun fetchAppSetId(): String {\n      try {\n        val AppSet = Class\n          .forName(\"com.google.android.gms.appset.AppSet\")\n        val getClient = AppSet.getMethod(\"getClient\", Context::class.java)\n        val appSetIdClient = getClient.invoke(null, context)\n        val getAppSetIdInfo = appSetIdClient.javaClass.getMethod(\"getAppSetIdInfo\")\n        val taskWithAppSetInfo = getAppSetIdInfo.invoke(appSetIdClient)\n        val Tasks = Class.forName(\"com.google.android.gms.tasks.Tasks\")\n        val await =\n          Tasks.getMethod(\"await\", Class.forName(\"com.google.android.gms.tasks.Task\"))\n        val appSetInfo = await.invoke(null, taskWithAppSetInfo)\n        val getId = appSetInfo.javaClass.getMethod(\"getId\")\n        appSetId = getId.invoke(appSetInfo) as String\n      } catch (e: ClassNotFoundException) {\n        LogcatLogger.logger\n          .warn(\"Google Play Services SDK not found for app set id!\")\n      } catch (e: InvocationTargetException) {\n        LogcatLogger.logger.warn(\"Google Play Services not available for app set id\")\n      } catch (e: Exception) {\n        LogcatLogger.logger.error(\n          \"Encountered an error connecting to Google Play Services for app set id\"\n        )\n      }\n      return appSetId\n    }\n\n    private val fetchAndCacheAmazonAdvertisingId: String?\n      get() {\n        val cr = context.contentResolver\n        limitAdTrackingEnabled = Secure.getInt(cr, SETTING_LIMIT_AD_TRACKING, 0) == 1\n        advertisingId = Secure.getString(cr, SETTING_ADVERTISING_ID)\n        return advertisingId\n      }\n    private val fetchAndCacheGoogleAdvertisingId: String?\n      get() {\n        try {\n          val AdvertisingIdClient = Class\n            .forName(\"com.google.android.gms.ads.identifier.AdvertisingIdClient\")\n          val getAdvertisingInfo = AdvertisingIdClient.getMethod(\n            \"getAdvertisingIdInfo\",\n            Context::class.java\n          )\n          val advertisingInfo = getAdvertisingInfo.invoke(null, context)\n          val isLimitAdTrackingEnabled = advertisingInfo.javaClass.getMethod(\n            \"isLimitAdTrackingEnabled\"\n          )\n          val limitAdTrackingEnabled = isLimitAdTrackingEnabled\n            .invoke(advertisingInfo) as Boolean\n          this.limitAdTrackingEnabled =\n            limitAdTrackingEnabled != null && limitAdTrackingEnabled\n          val getId = advertisingInfo.javaClass.getMethod(\"getId\")\n          advertisingId = getId.invoke(advertisingInfo) as String\n        } catch (e: ClassNotFoundException) {\n          LogcatLogger.logger\n            .warn(\"Google Play Services SDK not found for advertising id!\")\n        } catch (e: InvocationTargetException) {\n          LogcatLogger.logger\n            .warn(\"Google Play Services not available for advertising id\")\n        } catch (e: Exception) {\n          LogcatLogger.logger.error(\n            \"Encountered an error connecting to Google Play Services for advertising id\"\n          )\n        }\n        return advertisingId\n      }\n\n    private fun checkGPSEnabled(): Boolean {\n      // This should not be called on the main thread.\n      try {\n        val GPSUtil = Class\n          .forName(\"com.google.android.gms.common.GooglePlayServicesUtil\")\n        val getGPSAvailable = GPSUtil.getMethod(\n          \"isGooglePlayServicesAvailable\",\n          Context::class.java\n        )\n        val status = getGPSAvailable.invoke(null, context) as Int\n        // status 0 corresponds to com.google.android.gms.common.ConnectionResult.SUCCESS;\n        return status != null && status == 0\n      } catch (e: NoClassDefFoundError) {\n        LogcatLogger.logger.warn(\"Google Play Services Util not found!\")\n      } catch (e: ClassNotFoundException) {\n        LogcatLogger.logger.warn(\"Google Play Services Util not found!\")\n      } catch (e: NoSuchMethodException) {\n        LogcatLogger.logger.warn(\"Google Play Services not available\")\n      } catch (e: InvocationTargetException) {\n        LogcatLogger.logger.warn(\"Google Play Services not available\")\n      } catch (e: IllegalAccessException) {\n        LogcatLogger.logger.warn(\"Google Play Services not available\")\n      } catch (e: Exception) {\n        LogcatLogger.logger.warn(\n          \"Error when checking for Google Play Services: $e\"\n        )\n      }\n      return false\n    }\n  }\n\n  fun prefetch() {\n    cachedInfo\n  }\n\n  fun isGooglePlayServicesEnabled(): Boolean {\n    return cachedInfo!!.gpsEnabled\n  }\n\n  fun isLimitAdTrackingEnabled(): Boolean {\n    return cachedInfo!!.limitAdTrackingEnabled\n  }\n\n  val versionName: String?\n    get() = cachedInfo!!.versionName\n  val osName: String\n    get() = cachedInfo!!.osName\n  val platform: String\n    get() = cachedInfo!!.platform\n  val osVersion: String\n    get() = cachedInfo!!.osVersion\n  val brand: String\n    get() = cachedInfo!!.brand\n  val manufacturer: String\n    get() = cachedInfo!!.manufacturer\n  val model: String\n    get() = cachedInfo!!.model\n  val carrier: String?\n    get() = cachedInfo!!.carrier\n  val country: String?\n    get() = cachedInfo!!.country\n  val language: String\n    get() = cachedInfo!!.language\n  val advertisingId: String?\n    get() = cachedInfo!!.advertisingId\n  val appSetId: String\n    get() = cachedInfo!!.appSetId\n\n  companion object {\n    const val OS_NAME = \"android\"\n    const val PLATFORM = \"Android\"\n    const val SETTING_LIMIT_AD_TRACKING = \"limit_ad_tracking\"\n    const val SETTING_ADVERTISING_ID = \"advertising_id\"\n    fun generateUUID(): String {\n      return UUID.randomUUID().toString()\n    }\n  }\n\n  init {\n    this.shouldTrackAdid = shouldTrackAdid\n  }\n}\n"
  },
  {
    "path": "packages/analytics-react-native/android/src/main/java/com/amplitude/reactnative/AndroidLogger.kt",
    "content": "package com.amplitude.reactnative\n\nimport android.util.Log\n\ninterface Logger {\n  enum class LogMode(i: Int) {\n    DEBUG(1),\n    INFO(2),\n    WARN(3),\n    ERROR(4),\n    OFF(5)\n  }\n\n  var logMode: LogMode\n\n  fun debug(message: String)\n\n  fun error(message: String)\n\n  fun info(message: String)\n\n  fun warn(message: String)\n}\n\nclass LogcatLogger() : Logger {\n  override var logMode: Logger.LogMode = Logger.LogMode.INFO\n  private val tag = \"Amplitude\"\n\n  override fun debug(message: String) {\n    if (logMode <= Logger.LogMode.DEBUG) {\n      Log.d(tag, message)\n    }\n  }\n\n  override fun error(message: String) {\n    if (logMode <= Logger.LogMode.ERROR) {\n      Log.e(tag, message)\n    }\n  }\n\n  override fun info(message: String) {\n    if (logMode <= Logger.LogMode.INFO) {\n      Log.i(tag, message)\n    }\n  }\n\n  override fun warn(message: String) {\n    if (logMode <= Logger.LogMode.WARN) {\n      Log.w(tag, message)\n    }\n  }\n\n  companion object {\n    val logger = LogcatLogger()\n  }\n}\n"
  },
  {
    "path": "packages/analytics-react-native/android/src/main/java/com/amplitude/reactnative/LegacyDatabaseStorage.kt",
    "content": "package com.amplitude.reactnative\n\nimport android.content.Context\nimport android.database.Cursor\nimport android.database.sqlite.SQLiteDatabase\nimport android.database.sqlite.SQLiteException\nimport android.database.sqlite.SQLiteOpenHelper\nimport org.json.JSONObject\nimport java.io.File\nimport java.util.LinkedList\nimport java.util.Locale\n\n/**\n * Store the database related constants.\n * Align with com/amplitude/api/DatabaseHelper.java in previous SDK.\n */\nobject DatabaseConstants {\n    const val DEFAULT_INSTANCE = \"\\$default_instance\"\n    const val DATABASE_NAME = \"com.amplitude.api\"\n    const val DATABASE_VERSION = 4\n\n    const val EVENT_TABLE_NAME = \"events\"\n    const val IDENTIFY_TABLE_NAME = \"identifys\"\n    const val IDENTIFY_INTERCEPTOR_TABLE_NAME = \"identify_interceptor\"\n    const val ID_FIELD = \"id\"\n    const val EVENT_FIELD = \"event\"\n\n    const val LONG_STORE_TABLE_NAME = \"long_store\"\n    const val STORE_TABLE_NAME = \"store\"\n    const val KEY_FIELD = \"key\"\n    const val VALUE_FIELD = \"value\"\n}\n\n/**\n * The SDK doesn't need to write/read from local sqlite database.\n * This storage class is used for migrating events only.\n */\nclass LegacyDatabaseStorage(context: Context, databaseName: String) : SQLiteOpenHelper(\n    context,\n    databaseName,\n    null,\n    DatabaseConstants.DATABASE_VERSION\n) {\n    private var file: File = context.getDatabasePath(databaseName)\n    var currentDbVersion: Int = DatabaseConstants.DATABASE_VERSION\n        private set\n\n    override fun onCreate(db: SQLiteDatabase) {\n        throw NotImplementedError()\n    }\n\n    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {\n        currentDbVersion = oldVersion\n    }\n\n    private fun queryDb(\n        db: SQLiteDatabase,\n        table: String,\n        columns: Array<String?>?,\n        selection: String?,\n        selectionArgs: Array<String?>?,\n        orderBy: String?,\n    ): Cursor? {\n        return db.query(table, columns, selection, selectionArgs, null, null, orderBy, null)\n    }\n\n    private fun handleIfCursorRowTooLargeException(e: java.lang.IllegalStateException) {\n        val message = e.message\n        if (!message.isNullOrEmpty() && message.contains(\"Couldn't read\") && message.contains(\"CursorWindow\")) {\n            closeDb()\n        } else {\n            throw e\n        }\n    }\n\n    private fun convertIfCursorWindowException(e: java.lang.RuntimeException) {\n        val message = e.message\n        if (!message.isNullOrEmpty() && (message.startsWith(\"Cursor window allocation of\") || message.startsWith(\"Could not allocate CursorWindow\"))) {\n            throw CursorWindowAllocationException(message)\n        } else {\n            throw e\n        }\n    }\n\n    private fun closeDb() {\n        try {\n            close()\n        } catch (e: Exception) {\n            LogcatLogger.logger.error(\"close failed: ${e.message}\")\n        }\n    }\n\n    @Synchronized\n    fun readEvents(): List<JSONObject> {\n        return readEventsFromTable(DatabaseConstants.EVENT_TABLE_NAME)\n    }\n\n    @Synchronized\n    fun readIdentifies(): List<JSONObject> {\n        return readEventsFromTable(DatabaseConstants.IDENTIFY_TABLE_NAME)\n    }\n\n    @Synchronized\n    fun readInterceptedIdentifies(): List<JSONObject> {\n        if (currentDbVersion < 4) {\n            return listOf()\n        }\n        return readEventsFromTable(DatabaseConstants.IDENTIFY_INTERCEPTOR_TABLE_NAME)\n    }\n\n    private fun readEventsFromTable(table: String): List<JSONObject> {\n        if (!file.exists()) {\n            return arrayListOf()\n        }\n\n        val events: MutableList<JSONObject> = LinkedList()\n        var cursor: Cursor? = null\n        try {\n            val db = readableDatabase\n            cursor = queryDb(\n                db,\n                table,\n                arrayOf(DatabaseConstants.ID_FIELD, DatabaseConstants.EVENT_FIELD),\n                null,\n                null,\n                DatabaseConstants.ID_FIELD + \" ASC\",\n            )\n            while (cursor!!.moveToNext()) {\n                val eventId = cursor.getLong(0)\n                val event = cursor.getString(1)\n                if (event.isNullOrEmpty()) {\n                    continue\n                }\n                val obj = JSONObject(event)\n                obj.put(\"event_id\", eventId)\n                events.add(obj)\n            }\n        } catch (e: SQLiteException) {\n            LogcatLogger.logger.error(\n                \"read events from $table failed: ${e.message}\"\n            )\n            closeDb()\n        } catch (e: StackOverflowError) {\n            LogcatLogger.logger.error(\n                \"read events from $table failed: ${e.message}\"\n            )\n            closeDb()\n        } catch (e: IllegalStateException) { // put before Runtime since IllegalState extends\n            handleIfCursorRowTooLargeException(e)\n        } catch (e: RuntimeException) {\n            convertIfCursorWindowException(e)\n        } finally {\n            cursor?.close()\n            close()\n        }\n        return events\n    }\n\n    @Synchronized\n    fun removeEvent(eventId: Int) {\n        removeEventFromTable(DatabaseConstants.EVENT_TABLE_NAME, eventId)\n    }\n\n    @Synchronized\n    fun removeIdentify(eventId: Int) {\n        removeEventFromTable(DatabaseConstants.IDENTIFY_TABLE_NAME, eventId)\n    }\n\n    @Synchronized\n    fun removeInterceptedIdentify(eventId: Int) {\n        if (currentDbVersion < 4) {\n            return\n        }\n        removeEventFromTable(DatabaseConstants.IDENTIFY_INTERCEPTOR_TABLE_NAME, eventId)\n    }\n\n    private fun removeEventFromTable(table: String, eventId: Int) {\n        try {\n            val db = writableDatabase\n            db.delete(\n                table,\n                \"${DatabaseConstants.ID_FIELD} = ?\",\n                arrayOf(eventId.toString())\n            )\n        } catch (e: SQLiteException) {\n            LogcatLogger.logger.error(\n                \"remove events from $table failed: ${e.message}\"\n            )\n            closeDb()\n        } catch (e: StackOverflowError) {\n            LogcatLogger.logger.error(\n                \"remove events from $table failed: ${e.message}\"\n            )\n            closeDb()\n        } finally {\n            close()\n        }\n    }\n\n    @Synchronized\n    fun getValue(key: String): String? {\n        return getValueFromTable(DatabaseConstants.STORE_TABLE_NAME, key) as String?\n    }\n\n    @Synchronized\n    fun getLongValue(key: String): Long? {\n        return getValueFromTable(DatabaseConstants.LONG_STORE_TABLE_NAME, key) as Long?\n    }\n\n    private fun getValueFromTable(table: String, key: String): Any? {\n        if (!file.exists()) {\n            return null\n        }\n\n        var value: Any? = null\n        var cursor: Cursor? = null\n        try {\n            val db = readableDatabase\n            cursor = queryDb(\n                db,\n                table,\n                arrayOf<String?>(\n                    DatabaseConstants.KEY_FIELD,\n                    DatabaseConstants.VALUE_FIELD\n                ),\n                DatabaseConstants.KEY_FIELD + \" = ?\",\n                arrayOf(key),\n                null,\n            )\n            if (cursor!!.moveToFirst()) {\n                value = if (table == DatabaseConstants.STORE_TABLE_NAME) cursor.getString(1) else cursor.getLong(1)\n            }\n        } catch (e: SQLiteException) {\n            LogcatLogger.logger.error(\n                \"getValue from $table failed: ${e.message}\"\n            )\n            // Hard to recover from SQLiteExceptions, just start fresh\n            closeDb()\n        } catch (e: StackOverflowError) {\n            LogcatLogger.logger.error(\n                \"getValue from $table failed: ${e.message}\"\n            )\n            // potential stack overflow error when getting database on custom Android versions\n            closeDb()\n        } catch (e: IllegalStateException) { // put before Runtime since IllegalState extends\n            // cursor window row too big exception\n            handleIfCursorRowTooLargeException(e)\n        } catch (e: RuntimeException) {\n            // cursor window allocation exception\n            convertIfCursorWindowException(e)\n        } finally {\n            cursor?.close()\n            close()\n        }\n        return value\n    }\n\n    @Synchronized\n    fun removeValue(key: String) {\n        removeValueFromTable(DatabaseConstants.STORE_TABLE_NAME, key)\n    }\n\n    @Synchronized\n    fun removeLongValue(key: String) {\n        removeValueFromTable(DatabaseConstants.LONG_STORE_TABLE_NAME, key)\n    }\n\n    private fun removeValueFromTable(table: String, key: String) {\n        try {\n            val db = writableDatabase\n            db.delete(\n                table,\n                \"${DatabaseConstants.KEY_FIELD} = ?\",\n                arrayOf(key)\n            )\n        } catch (e: SQLiteException) {\n            LogcatLogger.logger.error(\n                \"remove value from $table failed: ${e.message}\"\n            )\n            closeDb()\n        } catch (e: StackOverflowError) {\n            LogcatLogger.logger.error(\n                \"remove value from $table failed: ${e.message}\"\n            )\n            closeDb()\n        } finally {\n            close()\n        }\n    }\n}\n\nclass CursorWindowAllocationException(description: String?) :\n    java.lang.RuntimeException(description)\n\nobject LegacyDatabaseStorageProvider {\n    private val instances: MutableMap<String, LegacyDatabaseStorage> = mutableMapOf()\n\n    fun getStorage(context: Context, instanceName: String?): LegacyDatabaseStorage {\n        val databaseName = getDatabaseName(instanceName)\n        var storage = instances[databaseName]\n        if (storage == null) {\n            storage = LegacyDatabaseStorage(context, databaseName)\n            instances[databaseName] = storage\n        }\n\n        return storage\n    }\n\n    private fun getDatabaseName(instanceName: String?): String {\n        val normalizedInstanceName = instanceName?.lowercase(Locale.getDefault())\n        return if (normalizedInstanceName.isNullOrEmpty() || normalizedInstanceName == DatabaseConstants.DEFAULT_INSTANCE) DatabaseConstants.DATABASE_NAME else \"${DatabaseConstants.DATABASE_NAME}_$normalizedInstanceName\"\n    }\n}\n"
  },
  {
    "path": "packages/analytics-react-native/babel.config.js",
    "content": "module.exports = {\n  presets: ['module:metro-react-native-babel-preset'],\n};\n"
  },
  {
    "path": "packages/analytics-react-native/ios/AmplitudeReactNative-Bridging-Header.h",
    "content": "#import <React/RCTBridgeModule.h>\n"
  },
  {
    "path": "packages/analytics-react-native/ios/AmplitudeReactNative.m",
    "content": "#import <React/RCTBridgeModule.h>\n\n@interface RCT_EXTERN_MODULE(AmplitudeReactNative, NSObject)\n\nRCT_EXTERN_METHOD(getApplicationContext: (NSDictionary*)options resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)\nRCT_EXTERN_METHOD(getLegacySessionData: (NSString*)instanceName resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)\nRCT_EXTERN_METHOD(getLegacyEvents: (NSString*)instanceName eventKind:(NSString*)eventKind resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)\nRCT_EXTERN_METHOD(removeLegacyEvent: (NSString*)instanceName eventKind:(NSString*)eventKind eventId:(double)eventId)\n\n@end\n"
  },
  {
    "path": "packages/analytics-react-native/ios/AmplitudeReactNative.swift",
    "content": "import Foundation\nimport React\n\n@objc(AmplitudeReactNative)\nclass ReactNative: NSObject {\n\n    @objc\n    static func requiresMainQueueSetup() -> Bool {\n        return false\n    }\n\n    @objc\n    func getApplicationContext(\n        _ options: NSDictionary,\n        resolver resolve: RCTPromiseResolveBlock,\n        rejecter reject: RCTPromiseRejectBlock\n    ) -> Void {\n        let trackingOptions = options as! [String: Bool]\n        let trackIdfv = trackingOptions[\"idfv\"] ?? false\n        let trackCarrier = trackingOptions[\"carrier\"] ?? false\n        let appleContextProvider = AppleContextProvider(trackIdfv: trackIdfv, trackCarrier: trackCarrier)\n\n        var applicationContext: [String: String?] = [\n            \"version\": appleContextProvider.version,\n            \"platform\": appleContextProvider.platform,\n            \"language\": appleContextProvider.language,\n            \"country\": appleContextProvider.country,\n            \"osName\": appleContextProvider.osName,\n            \"osVersion\": appleContextProvider.osVersion,\n            \"deviceManufacturer\": appleContextProvider.deviceManufacturer,\n            \"deviceModel\": appleContextProvider.deviceModel,\n        ]\n        if (trackIdfv) {\n            applicationContext[\"idfv\"] = appleContextProvider.idfv\n        }\n        if (trackCarrier) {\n            applicationContext[\"carrier\"] = appleContextProvider.carrier\n        }\n        resolve(applicationContext)\n    }\n\n    @objc\n    func getLegacySessionData(\n        _ instanceName: String?,\n        resolver resolve: RCTPromiseResolveBlock,\n        rejecter reject: RCTPromiseRejectBlock\n    ) -> Void {\n        let storage = LegacyDatabaseStorage.getStorage(instanceName)\n        var sessionData: [String: Any?] = [:]\n\n        if let deviceId = storage.getValue(\"device_id\") {\n            sessionData[\"deviceId\"] = deviceId\n        }\n        if let userId = storage.getValue(\"user_id\") {\n            sessionData[\"userId\"] = userId\n        }\n        if let previousSessionId = storage.getLongValue(\"previous_session_id\") {\n            sessionData[\"sessionId\"] = previousSessionId\n        }\n        if let lastEventTime = storage.getLongValue(\"previous_session_time\") {\n            sessionData[\"lastEventTime\"] = lastEventTime\n        }\n        if let lastEventId = storage.getLastEventId() {\n            sessionData[\"lastEventId\"] = lastEventId\n        }\n        resolve(sessionData)\n    }\n\n    @objc\n    func getLegacyEvents(\n        _ instanceName: String?,\n        eventKind: String,\n        resolver resolve: RCTPromiseResolveBlock,\n        rejecter reject: RCTPromiseRejectBlock\n    ) -> Void {\n        let storage = LegacyDatabaseStorage.getStorage(instanceName)\n        var events: [[String: Any]] = []\n        switch eventKind {\n        case \"event\":\n            events = storage.readEvents()\n        case \"identify\":\n            events = storage.readIdentifies()\n        case \"interceptedIdentify\":\n            events = storage.readInterceptedIdentifies()\n        default:\n            break\n        }\n        var jsonEvents: [String] = []\n        events.forEach { event in\n            if let jsonEvent = try? JSONSerialization.data(withJSONObject: event) {\n                jsonEvents.append(String(decoding: jsonEvent, as: UTF8.self))\n            }\n        }\n        resolve(jsonEvents)\n    }\n\n    @objc\n    func removeLegacyEvent(\n        _ instanceName: String?,\n        eventKind: String,\n        eventId: Double\n    ) -> Void {\n        let storage = LegacyDatabaseStorage.getStorage(instanceName)\n        switch eventKind {\n        case \"event\":\n            storage.removeEvent(Int64(eventId))\n        case \"identify\":\n            storage.removeIdentify(Int64(eventId))\n        case \"interceptedIdentify\":\n            storage.removeInterceptedIdentify(Int64(eventId))\n        default:\n            break\n        }\n    }\n}\n"
  },
  {
    "path": "packages/analytics-react-native/ios/AmplitudeReactNative.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t5E555C0D2413F4C50049A1A2 /* PBXBuildFile */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* AmplitudeReactNative.m */; };\n\t\t8EDEC1ED2DCD14B370FA86F1 /* LegacyDatabaseStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EDECE6C52794FD9D46192E2 /* LegacyDatabaseStorage.swift */; };\n\t\tF4FF95D7245B92E800C19C63 /* AmplitudeReactNative.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4FF95D6245B92E800C19C63 /* AmplitudeReactNative.swift */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXCopyFilesBuildPhase section */\n\t\t58B511D91A9E6C8500147676 /* CopyFiles */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = \"include/$(PRODUCT_NAME)\";\n\t\t\tdstSubfolderSpec = 16;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXCopyFilesBuildPhase section */\n\n/* Begin PBXFileReference section */\n\t\t134814201AA4EA6300B7C361 /* libAmplitudeReactNative.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libAmplitudeReactNative.a; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t8EDECE6C52794FD9D46192E2 /* LegacyDatabaseStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LegacyDatabaseStorage.swift; sourceTree = \"<group>\"; };\n\t\tB3E7B5891CC2AC0600A0062D /* AmplitudeReactNative.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AmplitudeReactNative.m; sourceTree = \"<group>\"; };\n\t\tF4FF95D5245B92E700C19C63 /* AmplitudeReactNative-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = \"AmplitudeReactNative-Bridging-Header.h\"; sourceTree = \"<group>\"; };\n\t\tF4FF95D6245B92E800C19C63 /* AmplitudeReactNative.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AmplitudeReactNative.swift; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t58B511D81A9E6C8500147676 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t134814211AA4EA7D00B7C361 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t134814201AA4EA6300B7C361 /* libAmplitudeReactNative.a */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t58B511D21A9E6C8500147676 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF4FF95D6245B92E800C19C63 /* AmplitudeReactNative.swift */,\n\t\t\t\tB3E7B5891CC2AC0600A0062D /* AmplitudeReactNative.m */,\n\t\t\t\tF4FF95D5245B92E700C19C63 /* AmplitudeReactNative-Bridging-Header.h */,\n\t\t\t\t134814211AA4EA7D00B7C361 /* Products */,\n\t\t\t\t8EDECE6C52794FD9D46192E2 /* LegacyDatabaseStorage.swift */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t58B511DA1A9E6C8500147676 /* ReactNative */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget \"ReactNative\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t58B511D71A9E6C8500147676 /* Sources */,\n\t\t\t\t58B511D81A9E6C8500147676 /* Frameworks */,\n\t\t\t\t58B511D91A9E6C8500147676 /* CopyFiles */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = ReactNative;\n\t\t\tproductName = RCTDataManager;\n\t\t\tproductReference = 134814201AA4EA6300B7C361 /* libAmplitudeReactNative.a */;\n\t\t\tproductType = \"com.apple.product-type.library.static\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t58B511D31A9E6C8500147676 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastUpgradeCheck = 0920;\n\t\t\t\tORGANIZATIONNAME = Facebook;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t58B511DA1A9E6C8500147676 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 6.1.1;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject \"AmplitudeReactNative\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = English;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\tEnglish,\n\t\t\t\ten,\n\t\t\t);\n\t\t\tmainGroup = 58B511D21A9E6C8500147676;\n\t\t\tproductRefGroup = 58B511D21A9E6C8500147676;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t58B511DA1A9E6C8500147676 /* ReactNative */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t58B511D71A9E6C8500147676 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tF4FF95D7245B92E800C19C63 /* AmplitudeReactNative.swift in Sources */,\n\t\t\t\tB3E7B58A1CC2AC0600A0062D,\n\t\t\t\t8EDEC1ED2DCD14B370FA86F1 /* LegacyDatabaseStorage.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\t58B511ED1A9E6C8500147676 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_SYMBOLS_PRIVATE_EXTERN = NO;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t58B511EE1A9E6C8500147676 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCOPY_PHASE_STRIP = YES;\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t58B511F01A9E6C8500147676 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tHEADER_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,\n\t\t\t\t\t\"$(SRCROOT)/../../../React/**\",\n\t\t\t\t\t\"$(SRCROOT)/../../react-native/React/**\",\n\t\t\t\t);\n\t\t\t\tLIBRARY_SEARCH_PATHS = \"$(inherited)\";\n\t\t\t\tOTHER_LDFLAGS = \"-ObjC\";\n\t\t\t\tPRODUCT_NAME = ReactNative;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"AmplitudeReactNative-Bridging-Header.h\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t58B511F11A9E6C8500147676 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tHEADER_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,\n\t\t\t\t\t\"$(SRCROOT)/../../../React/**\",\n\t\t\t\t\t\"$(SRCROOT)/../../react-native/React/**\",\n\t\t\t\t);\n\t\t\t\tLIBRARY_SEARCH_PATHS = \"$(inherited)\";\n\t\t\t\tOTHER_LDFLAGS = \"-ObjC\";\n\t\t\t\tPRODUCT_NAME = ReactNative;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"AmplitudeReactNative-Bridging-Header.h\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t58B511D61A9E6C8500147676 /* Build configuration list for PBXProject \"AmplitudeReactNative\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t58B511ED1A9E6C8500147676 /* Debug */,\n\t\t\t\t58B511EE1A9E6C8500147676 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget \"ReactNative\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t58B511F01A9E6C8500147676 /* Debug */,\n\t\t\t\t58B511F11A9E6C8500147676 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 58B511D31A9E6C8500147676 /* Project object */;\n}\n"
  },
  {
    "path": "packages/analytics-react-native/ios/AppleContextProvider.swift",
    "content": "#if os(iOS) && !targetEnvironment(simulator)\nimport CoreTelephony\n#endif\nimport Foundation\n\n@objc public class AppleContextProvider : NSObject {\n\n    public let version: String? = AppleContextProvider.getVersion()\n    public let language: String? = AppleContextProvider.getLanguage()\n    public let country: String? = AppleContextProvider.getCountry()\n    public let platform: String = AppleContextProvider.getPlatform()\n    public let osName: String = AppleContextProvider.getOsName()\n    public let osVersion: String = AppleContextProvider.getOsVersion()\n    public let deviceManufacturer: String = AppleContextProvider.getDeviceManufacturer()\n    public let deviceModel: String = AppleContextProvider.getDeviceModel()\n    public var idfv: String? = nil\n    public var carrier: String? = nil\n\n    init(trackIdfv: Bool, trackCarrier: Bool) {\n      super.init()\n      if (trackIdfv) {\n        fetchIdfv()\n      }\n      if (trackCarrier) {\n        fetchCarrier()\n      }\n    }\n\n    private static func getVersion() -> String? {\n        return Bundle.main.infoDictionary?[\"CFBundleShortVersionString\"] as? String\n    }\n\n    private static func getLanguage() -> String? {\n        return Locale(identifier: \"en_US\").localizedString(forLanguageCode: Locale.preferredLanguages[0])\n    }\n\n    private static func getCountry() -> String? {\n        return Locale.current.regionCode\n    }\n\n    private static func getPlatform() -> String {\n        return \"iOS\"\n    }\n\n    private static func getOsName() -> String {\n        return \"ios\"\n    }\n\n    private static func getOsVersion() -> String {\n        let systemVersion = ProcessInfo.processInfo.operatingSystemVersion\n        return \"\\(systemVersion.majorVersion).\\(systemVersion.minorVersion).\\(systemVersion.patchVersion)\"\n    }\n\n    private static func getDeviceManufacturer() -> String {\n        return \"Apple\"\n    }\n\n    private static func getPlatformString() -> String {\n        var sysinfo = utsname()\n        uname(&sysinfo) // ignore return value\n        return String(bytes: Data(bytes: &sysinfo.machine, count: Int(_SYS_NAMELEN)), encoding: .ascii)!.trimmingCharacters(in: .controlCharacters)\n    }\n\n    private func fetchIdfv() {\n        self.idfv = UIDevice.current.identifierForVendor?.uuidString\n    }\n\n    private func fetchCarrier() {\n        self.carrier = \"Unknown\"\n        #if os(iOS) && !targetEnvironment(simulator)\n        if #available(iOS 12.0, *) {\n            let networkInfo = CTTelephonyNetworkInfo()\n            if let providers = networkInfo.serviceSubscriberCellularProviders {\n                for (_, provider) in providers where provider.mobileNetworkCode != nil {\n                    self.carrier = provider.carrierName ?? carrier\n                    // As long as we get one carrier information, we break.\n                    break\n                }\n            }\n        }\n        #endif\n    }\n\n    private static func getDeviceModel() -> String {\n        let platform = getPlatformString()\n        // == iPhone ==\n        // iPhone 1\n        if (platform == \"iPhone1,1\") { return \"iPhone 1\" }\n        // iPhone 3\n        if (platform == \"iPhone1,2\") { return \"iPhone 3G\" }\n        if (platform == \"iPhone2,1\") { return \"iPhone 3GS\" }\n        // iPhone 4\n        if (platform == \"iPhone3,1\") { return \"iPhone 4\" }\n        if (platform == \"iPhone3,2\") { return \"iPhone 4\" }\n        if (platform == \"iPhone3,3\") { return \"iPhone 4\" }\n        if (platform == \"iPhone4,1\") { return \"iPhone 4S\" }\n        // iPhone 5\n        if (platform == \"iPhone5,1\") { return \"iPhone 5\" }\n        if (platform == \"iPhone5,2\") { return \"iPhone 5\" }\n        if (platform == \"iPhone5,3\") { return \"iPhone 5c\" }\n        if (platform == \"iPhone5,4\") { return \"iPhone 5c\" }\n        if (platform == \"iPhone6,1\") { return \"iPhone 5s\" }\n        if (platform == \"iPhone6,2\") { return \"iPhone 5s\" }\n        // iPhone 6\n        if (platform == \"iPhone7,1\") { return \"iPhone 6 Plus\" }\n        if (platform == \"iPhone7,2\") { return \"iPhone 6\" }\n        if (platform == \"iPhone8,1\") { return \"iPhone 6s\" }\n        if (platform == \"iPhone8,2\") { return \"iPhone 6s Plus\" }\n\n        // iPhone 7\n        if (platform == \"iPhone9,1\") { return \"iPhone 7\" }\n        if (platform == \"iPhone9,2\") { return \"iPhone 7 Plus\" }\n        if (platform == \"iPhone9,3\") { return \"iPhone 7\" }\n        if (platform == \"iPhone9,4\") { return \"iPhone 7 Plus\" }\n        // iPhone 8\n        if (platform == \"iPhone10,1\") { return \"iPhone 8\" }\n        if (platform == \"iPhone10,4\") { return \"iPhone 8\" }\n        if (platform == \"iPhone10,2\") { return \"iPhone 8 Plus\" }\n        if (platform == \"iPhone10,5\") { return \"iPhone 8 Plus\" }\n\n        // iPhone X\n        if (platform == \"iPhone10,3\") { return \"iPhone X\" }\n        if (platform == \"iPhone10,6\") { return \"iPhone X\" }\n\n        // iPhone XS\n        if (platform == \"iPhone11,2\") { return \"iPhone XS\" }\n        if (platform == \"iPhone11,6\") { return \"iPhone XS Max\" }\n\n        // iPhone XR\n        if (platform == \"iPhone11,8\") { return \"iPhone XR\" }\n\n        // iPhone 11\n        if (platform == \"iPhone12,1\") { return \"iPhone 11\" }\n        if (platform == \"iPhone12,3\") { return \"iPhone 11 Pro\" }\n        if (platform == \"iPhone12,5\") { return \"iPhone 11 Pro Max\" }\n\n        // iPhone SE\n        if (platform == \"iPhone8,4\") { return \"iPhone SE\" }\n        if (platform == \"iPhone12,8\") { return \"iPhone SE 2\" }\n\n        // == iPod ==\n        if (platform == \"iPod1,1\") { return \"iPod Touch 1G\" }\n        if (platform == \"iPod2,1\") { return \"iPod Touch 2G\" }\n        if (platform == \"iPod3,1\") { return \"iPod Touch 3G\" }\n        if (platform == \"iPod4,1\") { return \"iPod Touch 4G\" }\n        if (platform == \"iPod5,1\") { return \"iPod Touch 5G\" }\n        if (platform == \"iPod7,1\") { return \"iPod Touch 6G\" }\n        if (platform == \"iPod9,1\") { return \"iPod Touch 7G\" }\n\n        // == iPad ==\n        // iPad 1\n        if (platform == \"iPad1,1\") { return \"iPad 1\" }\n        // iPad 2\n        if (platform == \"iPad2,1\") { return \"iPad 2\" }\n        if (platform == \"iPad2,2\") { return \"iPad 2\" }\n        if (platform == \"iPad2,3\") { return \"iPad 2\" }\n        if (platform == \"iPad2,4\") { return \"iPad 2\" }\n        // iPad 3\n        if (platform == \"iPad3,1\") { return \"iPad 3\" }\n        if (platform == \"iPad3,2\") { return \"iPad 3\" }\n        if (platform == \"iPad3,3\") { return \"iPad 3\" }\n        // iPad 4\n        if (platform == \"iPad3,4\") { return \"iPad 4\" }\n        if (platform == \"iPad3,5\") { return \"iPad 4\" }\n        if (platform == \"iPad3,6\") { return \"iPad 4\" }\n        // iPad Air\n        if (platform == \"iPad4,1\") { return \"iPad Air\" }\n        if (platform == \"iPad4,2\") { return \"iPad Air\" }\n        if (platform == \"iPad4,3\") { return \"iPad Air\" }\n        // iPad Air 2\n        if (platform == \"iPad5,3\") { return \"iPad Air 2\" }\n        if (platform == \"iPad5,4\") { return \"iPad Air 2\" }\n        // iPad 5\n        if (platform == \"iPad6,11\") { return \"iPad 5\" }\n        if (platform == \"iPad6,12\") { return \"iPad 5\" }\n        // iPad 6\n        if (platform == \"iPad7,5\") { return \"iPad 6\" }\n        if (platform == \"iPad7,6\") { return \"iPad 6\" }\n        // iPad Air 3\n        if (platform == \"iPad11,3\") { return \"iPad Air 3\" }\n        if (platform == \"iPad11,4\") { return \"iPad Air 3\" }\n        // iPad 7\n        if (platform == \"iPad7,11\") { return \"iPad 6\" }\n        if (platform == \"iPad7,12\") { return \"iPad 6\" }\n\n        // iPad Pro\n        if (platform == \"iPad6,7\") { return \"iPad Pro\" }\n        if (platform == \"iPad6,8\") { return \"iPad Pro\" }\n        if (platform == \"iPad6,3\") { return \"iPad Pro\" }\n        if (platform == \"iPad6,4\") { return \"iPad Pro\" }\n        if (platform == \"iPad7,1\") { return \"iPad Pro\" }\n        if (platform == \"iPad7,2\") { return \"iPad Pro\" }\n        if (platform == \"iPad7,3\") { return \"iPad Pro\" }\n        if (platform == \"iPad7,4\") { return \"iPad Pro\" }\n        if (platform == \"iPad8,1\") { return \"iPad Pro\" }\n        if (platform == \"iPad8,2\") { return \"iPad Pro\" }\n        if (platform == \"iPad8,3\") { return \"iPad Pro\" }\n        if (platform == \"iPad8,4\") { return \"iPad Pro\" }\n        if (platform == \"iPad8,5\") { return \"iPad Pro\" }\n        if (platform == \"iPad8,6\") { return \"iPad Pro\" }\n        if (platform == \"iPad8,7\") { return \"iPad Pro\" }\n        if (platform == \"iPad8,8\") { return \"iPad Pro\" }\n\n        // iPad Mini\n        if (platform == \"iPad2,5\") { return \"iPad Mini\" }\n        if (platform == \"iPad2,6\") { return \"iPad Mini\" }\n        if (platform == \"iPad2,7\") { return \"iPad Mini\" }\n        // iPad Mini 2\n        if (platform == \"iPad4,4\") { return \"iPad Mini 2\" }\n        if (platform == \"iPad4,5\") { return \"iPad Mini 2\" }\n        if (platform == \"iPad4,6\") { return \"iPad Mini 2\" }\n        // iPad Mini 3\n        if (platform == \"iPad4,7\") { return \"iPad Mini 3\" }\n        if (platform == \"iPad4,8\") { return \"iPad Mini 3\" }\n        if (platform == \"iPad4,9\") { return \"iPad Mini 3\" }\n        // iPad Mini 4\n        if (platform == \"iPad5,1\") { return \"iPad Mini 4\" }\n        if (platform == \"iPad5,2\") { return \"iPad Mini 4\" }\n        // iPad Mini 5\n        if (platform == \"iPad11,1\") { return \"iPad Mini 5\" }\n        if (platform == \"iPad11,2\") { return \"iPad Mini 5\" }\n\n        // == Apple Watch ==\n        if (platform == \"Watch1,1\") { return \"Apple Watch 38mm\" }\n        if (platform == \"Watch1,2\") { return \"Apple Watch 42mm\" }\n        if (platform == \"Watch2,3\") { return \"Apple Watch Series 2 38mm\" }\n        if (platform == \"Watch2,4\") { return \"Apple Watch Series 2 42mm\" }\n        if (platform == \"Watch2,6\") { return \"Apple Watch Series 1 38mm\" }\n        if (platform == \"Watch2,7\") { return \"Apple Watch Series 1 42mm\" }\n        if (platform == \"Watch3,1\") { return \"Apple Watch Series 3 38mm Cellular\" }\n        if (platform == \"Watch3,2\") { return \"Apple Watch Series 3 42mm Cellular\" }\n        if (platform == \"Watch3,3\") { return \"Apple Watch Series 3 38mm\" }\n        if (platform == \"Watch3,4\") { return \"Apple Watch Series 3 42mm\" }\n        if (platform == \"Watch4,1\") { return \"Apple Watch Series 4 40mm\" }\n        if (platform == \"Watch4,2\") { return \"Apple Watch Series 4 44mm\" }\n        if (platform == \"Watch4,3\") { return \"Apple Watch Series 4 40mm Cellular\" }\n        if (platform == \"Watch4,4\") { return \"Apple Watch Series 4 44mm Cellular\" }\n        if (platform == \"Watch5,1\") { return \"Apple Watch Series 5 40mm\" }\n        if (platform == \"Watch5,2\") { return \"Apple Watch Series 5 44mm\" }\n        if (platform == \"Watch5,3\") { return \"Apple Watch Series 5 40mm Cellular\" }\n        if (platform == \"Watch5,4\") { return \"Apple Watch Series 5 44mm Cellular\" }\n        if (platform == \"Watch6,1\") { return \"Apple Watch Series 6 40mm\" }\n        if (platform == \"Watch6,2\") { return \"Apple Watch Series 6 44mm\" }\n        if (platform == \"Watch6,3\") { return \"Apple Watch Series 6 40mm Cellular\" }\n        if (platform == \"Watch6,4\") { return \"Apple Watch Series 6 44mm Cellular\" }\n\n        // == Others ==\n        if (platform == \"i386\") { return \"Simulator\" }\n        if (platform == \"x86_64\") { return \"Simulator\" }\n        if (platform.hasPrefix(\"MacBookAir\")) { return \"MacBook Air\" }\n        if (platform.hasPrefix(\"MacBookPro\")) { return \"MacBook Pro\" }\n        if (platform.hasPrefix(\"MacBook\")) { return \"MacBook\" }\n        if (platform.hasPrefix(\"MacPro\")) { return \"Mac Pro\" }\n        if (platform.hasPrefix(\"Macmini\")) { return \"Mac Mini\" }\n        if (platform.hasPrefix(\"iMac\")) { return \"iMac\" }\n        if (platform.hasPrefix(\"Xserve\")) { return \"Xserve\" }\n        return platform\n    }\n}\n"
  },
  {
    "path": "packages/analytics-react-native/ios/LegacyDatabaseStorage.swift",
    "content": "import Foundation\nimport SQLite3\n\nclass LegacyDatabaseStorage {\n    private static let DATABASE_NAME = \"com.amplitude.database\"\n    private static let EVENT_TABLE_NAME = \"events\"\n    private static let IDENTIFY_TABLE_NAME = \"identifys\"\n    private static let INTERCEPTED_IDENTIFY_TABLE_NAME = \"intercepted_identifys\"\n    private static let STORE_TABLE_NAME = \"store\"\n    private static let LONG_STORE_TABLE_NAME = \"long_store\"\n    private static let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self)\n\n    private static var instances: [String: LegacyDatabaseStorage] = [:]\n    private static let instanceQueue = DispatchQueue(label: \"legacyDatabaseStorage.amplitude.com\")\n\n    let databasePath: String\n\n    public static func getStorage(_ instanceName: String?) -> LegacyDatabaseStorage {\n        instanceQueue.sync {\n            var normalizedInstanceName = instanceName?.lowercased() ?? \"\"\n            if normalizedInstanceName == \"default_instance\" {\n                normalizedInstanceName = \"\"\n            }\n            if let storage = instances[normalizedInstanceName] {\n                return storage\n            }\n            let storage = LegacyDatabaseStorage(getDatabasePath(normalizedInstanceName).path)\n            instances[normalizedInstanceName] = storage\n            return storage\n        }\n    }\n\n    static func getDatabasePath(_ instanceName: String) -> URL {\n        #if os(tvOS)\n        let searchPathDirectory = FileManager.SearchPathDirectory.cachesDirectory\n        #else\n        let searchPathDirectory = FileManager.SearchPathDirectory.libraryDirectory\n        #endif\n\n        let urls = FileManager.default.urls(for: searchPathDirectory, in: .userDomainMask)\n        var databaseUrl = urls[0]\n\n        var databaseName = DATABASE_NAME\n        if instanceName != \"\" {\n            databaseName += \"_\\(instanceName)\"\n        }\n        databaseUrl.appendPathComponent(databaseName)\n        return databaseUrl\n    }\n\n    public init(_ databasePath: String) {\n        self.databasePath = databasePath\n    }\n\n    func getValue(_ key: String) -> String? {\n        getValueFromTable(LegacyDatabaseStorage.STORE_TABLE_NAME, key) as? String\n    }\n\n    func getLongValue(_ key: String) -> Int64? {\n        getValueFromTable(LegacyDatabaseStorage.LONG_STORE_TABLE_NAME, key) as? Int64\n    }\n\n    private func getValueFromTable(_ table: String, _ key: String) -> Any? {\n        let query = \"SELECT key, value FROM \\(table) WHERE key = ?;\"\n        return executeQuery(query) { stmt in\n            let bindResult = sqlite3_bind_text(stmt, 1, key, -1, LegacyDatabaseStorage.SQLITE_TRANSIENT)\n            if bindResult != SQLITE_OK {\n                print(\"bind query parameter failed with result: \\(bindResult)\")\n                return\n            }\n\n            let stepResult = sqlite3_step(stmt)\n            if stepResult != SQLITE_ROW {\n                print(\"execute query '\\(query)' failed with result: \\(stepResult)\")\n                return\n            }\n\n            if sqlite3_column_type(stmt, 1) != SQLITE_NULL {\n                if table == LegacyDatabaseStorage.STORE_TABLE_NAME {\n                    guard let rawValue = sqlite3_column_text(stmt, 1) else {\n                        return\n                    }\n                    return String(cString: rawValue)\n                } else {\n                    return sqlite3_column_int64(stmt, 1)\n                }\n            } else {\n                return\n            }\n        }\n    }\n\n    func getLastEventId() -> Int64? {\n        let query = \"select coalesce(max(seq), -1) from sqlite_sequence where name = 'events';\"\n        let lastId = executeQuery(query) { stmt in\n            let stepResult = sqlite3_step(stmt)\n            if stepResult != SQLITE_ROW {\n                print(\"execute query '\\(query)' failed with result: \\(stepResult)\")\n                return -1 as Int64\n            }\n\n            if sqlite3_column_type(stmt, 0) != SQLITE_NULL {\n                let value = sqlite3_column_int64(stmt, 0)\n                return value\n            } else {\n                return -1 as Int64\n            }\n        }\n        return lastId != nil && lastId! >= 0 ? lastId : nil\n    }\n\n    func removeValue(_ key: String) {\n        removeValueFromTable(LegacyDatabaseStorage.STORE_TABLE_NAME, key)\n    }\n\n    func removeLongValue(_ key: String) {\n        removeValueFromTable(LegacyDatabaseStorage.LONG_STORE_TABLE_NAME, key)\n    }\n\n    private func removeValueFromTable(_ table: String, _ key: String) {\n        let query = \"DELETE FROM \\(table) WHERE key = ?;\"\n        _ = executeQuery(query) { stmt in\n            let bindResult = sqlite3_bind_text(stmt, 1, key, -1, LegacyDatabaseStorage.SQLITE_TRANSIENT)\n            if bindResult != SQLITE_OK {\n                print(\"bind query parameter failed with result: \\(bindResult)\")\n                return\n            }\n\n            let stepResult = sqlite3_step(stmt)\n            if stepResult != SQLITE_DONE {\n                print(\"execute query '\\(query)' failed with result: \\(stepResult)\")\n                return\n            }\n        }\n    }\n\n    func removeEvent(_ eventId: Int64) {\n        removeEventFromTable(LegacyDatabaseStorage.EVENT_TABLE_NAME, eventId)\n    }\n\n    func removeIdentify(_ eventId: Int64) {\n        removeEventFromTable(LegacyDatabaseStorage.IDENTIFY_TABLE_NAME, eventId)\n    }\n\n    func removeInterceptedIdentify(_ eventId: Int64) {\n        removeEventFromTable(LegacyDatabaseStorage.INTERCEPTED_IDENTIFY_TABLE_NAME, eventId)\n    }\n\n    private func removeEventFromTable(_ table: String, _ eventId: Int64) {\n        let query = \"DELETE FROM \\(table) WHERE id = ?;\"\n        _ = executeQuery(query) { stmt in\n            let bindResult = sqlite3_bind_int64(stmt, 1, eventId)\n            if bindResult != SQLITE_OK {\n                print(\"bind query parameter failed with result: \\(bindResult)\")\n                return\n            }\n\n            let stepResult = sqlite3_step(stmt)\n            if stepResult != SQLITE_DONE {\n                print(\"execute query '\\(query)' failed with result: \\(stepResult)\")\n                return\n            }\n        }\n    }\n\n    func readEvents() -> [[String: Any]] {\n        readEventsFromTable(LegacyDatabaseStorage.EVENT_TABLE_NAME)\n    }\n\n    func readIdentifies() -> [[String: Any]] {\n        readEventsFromTable(LegacyDatabaseStorage.IDENTIFY_TABLE_NAME)\n    }\n\n    func readInterceptedIdentifies() -> [[String: Any]] {\n        readEventsFromTable(LegacyDatabaseStorage.INTERCEPTED_IDENTIFY_TABLE_NAME)\n    }\n\n    private func readEventsFromTable(_ table: String) -> [[String: Any]] {\n        let query = \"SELECT id, event FROM \\(table) ORDER BY id;\"\n        return executeQuery(query) { stmt in\n            var events: [[String: Any]] = []\n            while sqlite3_step(stmt) == SQLITE_ROW {\n                let eventId = sqlite3_column_int64(stmt, 0)\n                let rawEventData = sqlite3_column_text(stmt, 1)\n                if rawEventData != nil {\n                    let eventData = String(cString: rawEventData!).data(using: .utf8)\n                    if eventData != nil && eventData!.count > 0 {\n                        let event = try? JSONSerialization.jsonObject(with: eventData!, options: []) as? [String: Any]\n                        if var event {\n                            event[\"event_id\"] = eventId\n                            events.append(event)\n                        }\n                    }\n                }\n            }\n            return events\n        } ?? []\n    }\n\n    private func executeQuery<T>(_ query: String, _ block: (_ stmt: OpaquePointer) -> T) -> T? {\n        if !FileManager.default.fileExists(atPath: databasePath) {\n            return nil\n        }\n\n        var db: OpaquePointer?\n        let openResult = sqlite3_open(databasePath, &db)\n        if openResult != SQLITE_OK {\n            print(\"open database failed with result: \\(openResult)\")\n            sqlite3_close(db)\n            return nil\n        }\n\n        var stmt: OpaquePointer?\n        let prepareResult = sqlite3_prepare(db, query, -1, &stmt, nil)\n        if prepareResult != SQLITE_OK {\n            print(\"prepare query failed with result: \\(prepareResult)\")\n            return nil\n        }\n        let value = block(stmt!)\n        sqlite3_finalize(stmt)\n        sqlite3_close(db)\n        return value\n    }\n}\n"
  },
  {
    "path": "packages/analytics-react-native/jest.config.js",
    "content": "const baseConfig = require('../../jest.config.js');\nconst package = require('./package');\n\nmodule.exports = {\n  ...baseConfig,\n  displayName: package.name,\n  rootDir: '.',\n  preset: 'react-native',\n  // testEnvironment is set per-script in package.json:\n  //   test:mobile → node   (matches the RN preset default; faithful to the RN runtime)\n  //   test:web    → jsdom  (so test cases exercising RN-Web behavior have document/window)\n  // Leaving it unset here lets the preset's default (node) apply when neither\n  // setup file is provided (e.g. running `jest` directly).\n  modulePathIgnorePatterns: [\n    \"<rootDir>/lib/\"\n  ],\n  transformIgnorePatterns: [\n    'node_modules/(?!(.pnpm|@react-native|react-native|@segment)/)',\n  ],\n  // TODO: get full coverage\n  coverageThreshold: {\n    global: {\n      // The branches threshold is 84 (not 85) because a few branches in\n      // `getTopLevelDomain` are inherently web-only (they depend on\n      // `window.location` and `document.cookie`). Those tests are gated to\n      // run only under `test:web`, so `test:mobile` doesn't cover them.\n      // `test:web` still comfortably exceeds 85% on every metric.\n      branches: 84,\n      functions: 85,\n      lines: 85,\n      statements: 85,\n    }\n  },\n};\n"
  },
  {
    "path": "packages/analytics-react-native/package.json",
    "content": "{\n  \"name\": \"@amplitude/analytics-react-native\",\n  \"version\": \"1.5.53\",\n  \"description\": \"Official React Native SDK\",\n  \"keywords\": [\n    \"analytics\",\n    \"amplitude\",\n    \"react-native\",\n    \"ios\",\n    \"android\"\n  ],\n  \"author\": \"Amplitude Inc\",\n  \"homepage\": \"https://github.com/amplitude/Amplitude-TypeScript\",\n  \"license\": \"MIT\",\n  \"main\": \"lib/commonjs/index\",\n  \"module\": \"lib/module/index\",\n  \"types\": \"lib/typescript/index.d.ts\",\n  \"react-native\": \"src/index\",\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"tag\": \"latest\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/amplitude/Amplitude-TypeScript.git\"\n  },\n  \"scripts\": {\n    \"build\": \"bob build\",\n    \"clean\": \"rimraf node_modules lib coverage\",\n    \"fix\": \"pnpm fix:eslint & pnpm fix:prettier\",\n    \"fix:eslint\": \"eslint '{src,test}/**/*.ts' --fix\",\n    \"fix:prettier\": \"prettier --write \\\"{src,test}/**/*.ts\\\"\",\n    \"lint\": \"pnpm lint:eslint & pnpm lint:prettier\",\n    \"lint:eslint\": \"eslint '{src,test}/**/*.ts'\",\n    \"lint:prettier\": \"prettier --check \\\"{src,test}/**/*.ts\\\"\",\n    \"test\": \"pnpm test:web && pnpm test:mobile\",\n    \"test:web\": \"jest --setupFiles './test/mock/setup-web.ts' --testEnvironment jsdom\",\n    \"test:mobile\": \"jest --setupFiles './test/mock/setup-mobile.ts' --testEnvironment node\",\n    \"typecheck\": \"tsc --noEmit -p ./tsconfig.json\",\n    \"version\": \"pnpm version-file && pnpm build\",\n    \"version-file\": \"node -p \\\"'export const VERSION = \\\\'' + require('./package.json').version + '\\\\';'\\\" > src/version.ts\",\n    \"typescript\": \"tsc --noEmit\",\n    \"example\": \"yarn --cwd example\",\n    \"pods\": \"cd example && pod-install --quiet\"\n  },\n  \"source\": \"src/index\",\n  \"files\": [\n    \"src\",\n    \"lib\",\n    \"android\",\n    \"ios\",\n    \"amplitude-react-native.podspec\",\n    \"!android/build\",\n    \"!ios/build\",\n    \"!**/test\"\n  ],\n  \"bugs\": {\n    \"url\": \"https://github.com/amplitude/Amplitude-TypeScript/issues\"\n  },\n  \"dependencies\": {\n    \"@amplitude/analytics-core\": \"2.48.1\",\n    \"@amplitude/ua-parser-js\": \"^0.7.31\",\n    \"@react-native-async-storage/async-storage\": \"^1.17.11\",\n    \"tslib\": \"^2.4.1\"\n  },\n  \"devDependencies\": {\n    \"@types/react\": \"^18.0.26\",\n    \"@types/react-native\": \"0.70.8\",\n    \"@types/ua-parser-js\": \"^0.7.39\",\n    \"react\": \"18.2.0\",\n    \"react-native\": \"0.70.6\",\n    \"react-native-builder-bob\": \"^0.20.3\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"*\",\n    \"react-native\": \"*\"\n  },\n  \"react-native-builder-bob\": {\n    \"source\": \"src\",\n    \"output\": \"lib\",\n    \"targets\": [\n      \"commonjs\",\n      \"module\",\n      [\n        \"typescript\",\n        {\n          \"project\": \"tsconfig.build.json\"\n        }\n      ]\n    ]\n  }\n}\n"
  },
  {
    "path": "packages/analytics-react-native/src/campaign/campaign-tracker.ts",
    "content": "import {\n  createIdentifyEvent,\n  Identify,\n  Storage,\n  Campaign,\n  CampaignParser as ICampaignParser,\n  BaseEvent,\n  getCookieName as getStorageKey,\n  BASE_CAMPAIGN,\n  EMPTY_VALUE,\n  MKTG,\n  CampaignParser,\n} from '@amplitude/analytics-core';\nimport { CampaignTracker as ICampaignTracker, CampaignTrackFunction, CampaignTrackerOptions } from './types';\n\n/**\n * @deprecated\n * Campaign tracker has mixed logic from built-in and plugin web attribution\n * features. Do not add more features here. The plan moving foward is to consolidate logic\n * in @amplitude/plugin-web-attribution-browser with backward compatibility.\n */\nexport class CampaignTracker implements ICampaignTracker {\n  storage: Storage<Campaign>;\n  storageKey: string;\n  parser: ICampaignParser;\n  track: CampaignTrackFunction;\n  onNewCampaign: (campaign: Campaign) => unknown;\n\n  disabled: boolean;\n  trackNewCampaigns: boolean;\n  trackPageViews: boolean;\n  excludeReferrers: string[];\n  initialEmptyValue: string;\n\n  constructor(apiKey: string, options: CampaignTrackerOptions) {\n    this.storage = options.storage;\n    this.storageKey = getStorageKey(apiKey, MKTG);\n    this.parser = new CampaignParser();\n    this.track = options.track;\n    this.onNewCampaign = options.onNewCampaign;\n\n    this.disabled = Boolean(options.disabled);\n    this.trackNewCampaigns = Boolean(options.trackNewCampaigns);\n    this.trackPageViews = Boolean(options.trackPageViews);\n    this.excludeReferrers = options.excludeReferrers ?? [];\n    if (typeof location !== 'undefined') {\n      this.excludeReferrers.unshift(location.hostname);\n    }\n    this.initialEmptyValue = options.initialEmptyValue ?? EMPTY_VALUE;\n  }\n\n  isNewCampaign(current: Campaign, previous: Campaign | undefined, ignoreSubdomainInReferrer = false) {\n    const { referrer, referring_domain, ...currentCampaign } = current;\n    const { referrer: _previous_referrer, referring_domain: prevReferringDomain, ...previousCampaign } = previous || {};\n\n    if (current.referring_domain && this.excludeReferrers.includes(current.referring_domain)) {\n      return false;\n    }\n\n    const hasNewCampaign = JSON.stringify(currentCampaign) !== JSON.stringify(previousCampaign);\n    const hasNewDomain = ignoreSubdomainInReferrer\n      ? domainWithoutSubdomain(referring_domain || '') !== domainWithoutSubdomain(prevReferringDomain || '')\n      : referring_domain !== prevReferringDomain;\n\n    return !previous || hasNewCampaign || hasNewDomain;\n  }\n\n  async saveCampaignToStorage(campaign: Campaign): Promise<void> {\n    await this.storage.set(this.storageKey, campaign);\n  }\n\n  async getCampaignFromStorage(): Promise<Campaign | undefined> {\n    return await this.storage.get(this.storageKey);\n  }\n\n  createCampaignEvent(campaign: Campaign) {\n    const campaignParameters: Campaign = {\n      // This object definition allows undefined keys to be iterated on\n      // in .reduce() to build indentify object\n      ...BASE_CAMPAIGN,\n      ...campaign,\n    };\n    const identifyEvent = Object.entries(campaignParameters).reduce((identify, [key, value]) => {\n      identify.setOnce(`initial_${key}`, value || this.initialEmptyValue);\n      if (value) {\n        return identify.set(key, value);\n      }\n      return identify.unset(key);\n    }, new Identify());\n\n    const pageViewEvent: BaseEvent = {\n      event_type: 'Page View',\n      event_properties: {\n        page_title: /* istanbul ignore next */ (typeof document !== 'undefined' && document.title) || '',\n        page_location: /* istanbul ignore next */ (typeof location !== 'undefined' && location.href) || '',\n        page_path: /* istanbul ignore next */ (typeof location !== 'undefined' && location.pathname) || '',\n      },\n    };\n    return {\n      ...createIdentifyEvent(identifyEvent),\n      ...(this.trackPageViews && pageViewEvent),\n    };\n  }\n\n  async send(isNewSession: boolean) {\n    if (this.disabled) {\n      return;\n    }\n    const currentCampaign = await this.parser.parse();\n    const previousCampaign = await this.getCampaignFromStorage();\n    if (!isNewSession) {\n      if (!this.trackNewCampaigns || !this.isNewCampaign(currentCampaign, previousCampaign)) {\n        return;\n      }\n      this.onNewCampaign(currentCampaign);\n    }\n    await this.track(this.createCampaignEvent(currentCampaign));\n    await this.saveCampaignToStorage(currentCampaign);\n  }\n}\n\nconst domainWithoutSubdomain = (domain: string) => {\n  const parts = domain.split('.');\n\n  if (parts.length <= 2) {\n    return domain;\n  }\n\n  return parts.slice(parts.length - 2, parts.length).join('.');\n};\n"
  },
  {
    "path": "packages/analytics-react-native/src/campaign/types.ts",
    "content": "import { Campaign, ReactNativeAttributionOptions, Storage, BaseEvent } from '@amplitude/analytics-core';\n\nexport interface CampaignTrackerOptions extends ReactNativeAttributionOptions {\n  storage: Storage<Campaign>;\n  track: CampaignTrackFunction;\n  onNewCampaign: (campaign: Campaign) => unknown;\n}\n\nexport interface CampaignTracker extends CampaignTrackerOptions {\n  send(force: boolean): Promise<void>;\n}\n\nexport type CampaignTrackFunction = (event: BaseEvent) => Promise<unknown>;\n"
  },
  {
    "path": "packages/analytics-react-native/src/config.ts",
    "content": "import {\n  Config,\n  MemoryStorage,\n  UUID,\n  ReactNativeConfig as IReactNativeConfig,\n  ReactNativeTrackingOptions,\n  Event,\n  ReactNativeOptions,\n  Storage,\n  UserSession,\n  CookieStorage,\n  getCookieName,\n  getQueryParams,\n  FetchTransport,\n} from '@amplitude/analytics-core';\n\nimport { LocalStorage } from './storage/local-storage';\nimport RemnantDataMigration from './migration/remnant-data-migration';\n\nexport const getDefaultConfig = () => {\n  const cookieStorage = new MemoryStorage<UserSession>();\n  const trackingOptions: Required<ReactNativeTrackingOptions> = {\n    adid: true,\n    carrier: true,\n    deviceManufacturer: true,\n    deviceModel: true,\n    ipAddress: true,\n    language: true,\n    osName: true,\n    osVersion: true,\n    platform: true,\n    appSetId: true,\n    idfv: true,\n    country: false, // NOTE: tracking country information would disable server-side IP address lookup to fill other information like region, city, dma, etc.\n  };\n  return {\n    cookieExpiration: 365,\n    cookieSameSite: 'Lax',\n    cookieSecure: false,\n    cookieStorage,\n    cookieUpgrade: true,\n    disableCookies: false,\n    domain: '',\n    sessionTimeout: 5 * 60 * 1000,\n    storageProvider: new MemoryStorage<Event[]>(),\n    trackingSessionEvents: false,\n    trackingOptions,\n    transportProvider: new FetchTransport(),\n  };\n};\n\nexport class ReactNativeConfig extends Config implements IReactNativeConfig {\n  appVersion?: string;\n  cookieExpiration: number;\n  cookieSameSite: string;\n  cookieSecure: boolean;\n  cookieStorage: Storage<UserSession>;\n  cookieUpgrade: boolean;\n  disableCookies: boolean;\n  domain: string;\n  partnerId?: string;\n  sessionTimeout: number;\n  trackingSessionEvents: boolean;\n  trackingOptions: ReactNativeTrackingOptions;\n\n  // NOTE: These protected properties are used to cache values from async storage\n  protected _deviceId?: string;\n  protected _lastEventId?: number;\n  protected _lastEventTime?: number;\n  protected _optOut = false;\n  protected _sessionId?: number;\n  protected _userId?: string;\n\n  constructor(apiKey: string, options?: ReactNativeOptions) {\n    const defaultConfig = getDefaultConfig();\n    super({\n      flushIntervalMillis: 1000,\n      flushMaxRetries: 5,\n      flushQueueSize: 30,\n      transportProvider: defaultConfig.transportProvider,\n      ...options,\n      apiKey,\n    });\n\n    // NOTE: Define `cookieStorage` first to persist user session\n    // user session properties expect `cookieStorage` to be defined\n    this.cookieStorage = options?.cookieStorage ?? defaultConfig.cookieStorage;\n    this.deviceId = options?.deviceId;\n    this.lastEventTime = options?.lastEventTime;\n    this.optOut = Boolean(options?.optOut);\n    this.sessionId = options?.sessionId;\n    this.userId = options?.userId;\n\n    this.appVersion = options?.appVersion;\n    this.cookieExpiration = options?.cookieExpiration ?? defaultConfig.cookieExpiration;\n    this.cookieSameSite = options?.cookieSameSite ?? defaultConfig.cookieSameSite;\n    this.cookieSecure = options?.cookieSecure ?? defaultConfig.cookieSecure;\n    this.cookieUpgrade = options?.cookieUpgrade ?? defaultConfig.cookieUpgrade;\n    this.disableCookies = options?.disableCookies ?? defaultConfig.disableCookies;\n    this.domain = options?.domain ?? defaultConfig.domain;\n    this.partnerId = options?.partnerId;\n    this.sessionTimeout = options?.sessionTimeout ?? defaultConfig.sessionTimeout;\n    this.trackingOptions = options?.trackingOptions ?? defaultConfig.trackingOptions;\n    this.trackingSessionEvents = options?.trackingSessionEvents ?? defaultConfig.trackingSessionEvents;\n  }\n\n  get deviceId() {\n    return this._deviceId;\n  }\n\n  set deviceId(deviceId: string | undefined) {\n    if (this._deviceId !== deviceId) {\n      this._deviceId = deviceId;\n      this.updateStorage();\n    }\n  }\n\n  get userId() {\n    return this._userId;\n  }\n\n  set userId(userId: string | undefined) {\n    if (this._userId !== userId) {\n      this._userId = userId;\n      this.updateStorage();\n    }\n  }\n\n  get sessionId() {\n    return this._sessionId;\n  }\n\n  set sessionId(sessionId: number | undefined) {\n    if (this._sessionId !== sessionId) {\n      this._sessionId = sessionId;\n      this.updateStorage();\n    }\n  }\n\n  get optOut() {\n    return this._optOut;\n  }\n\n  set optOut(optOut: boolean) {\n    if (this._optOut !== optOut) {\n      this._optOut = optOut;\n      this.updateStorage();\n    }\n  }\n\n  get lastEventTime() {\n    return this._lastEventTime;\n  }\n\n  set lastEventTime(lastEventTime: number | undefined) {\n    if (this._lastEventTime !== lastEventTime) {\n      this._lastEventTime = lastEventTime;\n      this.updateStorage();\n    }\n  }\n\n  get lastEventId() {\n    return this._lastEventId;\n  }\n\n  set lastEventId(lastEventId: number | undefined) {\n    if (this._lastEventId !== lastEventId) {\n      this._lastEventId = lastEventId;\n      this.updateStorage();\n    }\n  }\n\n  private updateStorage() {\n    const cache = {\n      deviceId: this._deviceId,\n      userId: this._userId,\n      sessionId: this._sessionId,\n      optOut: this._optOut,\n      lastEventTime: this._lastEventTime,\n      lastEventId: this._lastEventId,\n    };\n    void this.cookieStorage?.set(getCookieName(this.apiKey), cache);\n  }\n}\n\nexport const useReactNativeConfig = async (\n  apiKey: string,\n  options?: ReactNativeOptions,\n): Promise<IReactNativeConfig> => {\n  const defaultConfig = getDefaultConfig();\n\n  // create cookie storage\n  const domain = options?.disableCookies ? '' : options?.domain ?? (await getTopLevelDomain());\n  const cookieStorage = await createCookieStorage<UserSession>({ ...options, domain });\n  const previousCookies = await cookieStorage.get(getCookieName(apiKey));\n  const queryParams = getQueryParams();\n\n  // reconcile user session\n  let deviceId = options?.deviceId ?? queryParams.deviceId ?? previousCookies?.deviceId;\n  let lastEventTime = options?.lastEventTime ?? previousCookies?.lastEventTime;\n  const optOut = options?.optOut ?? Boolean(previousCookies?.optOut);\n  let sessionId = options?.sessionId ?? previousCookies?.sessionId;\n  let userId = options?.userId ?? previousCookies?.userId;\n  let lastEventId = previousCookies?.lastEventId;\n\n  const storageProvider = options?.storageProvider ?? (await createEventsStorage(options));\n\n  if (options?.migrateLegacyData !== false) {\n    const legacySessionData = await new RemnantDataMigration(\n      apiKey,\n      options?.instanceName,\n      storageProvider,\n      previousCookies?.lastEventTime === undefined,\n      options?.loggerProvider,\n    ).execute();\n    deviceId = deviceId ?? legacySessionData.deviceId;\n    userId = userId ?? legacySessionData.userId;\n    sessionId = sessionId ?? legacySessionData.sessionId;\n    lastEventTime = lastEventTime ?? legacySessionData.lastEventTime;\n    lastEventId = lastEventId ?? legacySessionData.lastEventId;\n  }\n\n  const config = new ReactNativeConfig(apiKey, {\n    ...options,\n    cookieStorage,\n    deviceId: deviceId ?? UUID(),\n    domain,\n    lastEventTime,\n    optOut,\n    sessionId,\n    storageProvider,\n    trackingOptions: {\n      ...defaultConfig.trackingOptions,\n      ...options?.trackingOptions,\n    },\n    transportProvider: options?.transportProvider ?? new FetchTransport(),\n    userId,\n  });\n\n  config.lastEventId = lastEventId;\n\n  config.loggerProvider?.log(\n    `Init: storage=${cookieStorage.constructor.name} restoredSessionId = ${\n      previousCookies?.sessionId ?? 'undefined'\n    }, optionsSessionId = ${options?.sessionId ?? 'undefined'}`,\n  );\n\n  return config;\n};\n\nexport const createCookieStorage = async <T>(\n  overrides?: ReactNativeOptions,\n  baseConfig = getDefaultConfig(),\n): Promise<Storage<T>> => {\n  const options = { ...baseConfig, ...overrides };\n  const cookieStorage = overrides?.cookieStorage as Storage<T>;\n  if (!cookieStorage || !(await cookieStorage.isEnabled())) {\n    return createFlexibleStorage<T>(options);\n  }\n  return cookieStorage;\n};\n\nconst createFlexibleStorage = async <T>(options: ReactNativeOptions): Promise<Storage<T>> => {\n  let storage: Storage<T> = new CookieStorage({\n    domain: options.domain,\n    expirationDays: options.cookieExpiration,\n    sameSite: options.cookieSameSite,\n    secure: options.cookieSecure,\n  });\n  if (options.disableCookies || !(await storage.isEnabled())) {\n    storage = new LocalStorage();\n    if (!(await storage.isEnabled())) {\n      storage = new MemoryStorage();\n    }\n  }\n  return storage;\n};\n\nexport const createEventsStorage = async (overrides?: ReactNativeOptions): Promise<Storage<Event[]> | undefined> => {\n  const hasStorageProviderProperty = overrides && Object.prototype.hasOwnProperty.call(overrides, 'storageProvider');\n  // If storageProperty is explicitly undefined like `{ storageProperty: undefined }`\n  // then storageProvider is undefined\n  // If storageProvider is implicitly undefined like `{ }`\n  // then storageProvider is LocalStorage\n  // Otherwise storageProvider is overriden\n  if (!hasStorageProviderProperty || overrides.storageProvider) {\n    for (const storage of [overrides?.storageProvider, new LocalStorage<Event[]>()]) {\n      if (storage && (await storage.isEnabled())) {\n        return storage;\n      }\n    }\n  }\n  return undefined;\n};\n\nexport const getTopLevelDomain = async (url?: string) => {\n  if (\n    !(await new CookieStorage<number>().isEnabled()) ||\n    (!url && (typeof location === 'undefined' || !location.hostname))\n  ) {\n    return '';\n  }\n\n  const host = url ?? location.hostname;\n  const parts = host.split('.');\n  const levels = [];\n  const storageKey = 'AMP_TLDTEST';\n\n  for (let i = parts.length - 2; i >= 0; --i) {\n    levels.push(parts.slice(i).join('.'));\n  }\n  for (let i = 0; i < levels.length; i++) {\n    const domain = levels[i];\n    const options = { domain: '.' + domain };\n    const storage = new CookieStorage<number>(options);\n    await storage.set(storageKey, 1);\n    const value = await storage.get(storageKey);\n    if (value) {\n      await storage.remove(storageKey);\n      return '.' + domain;\n    }\n  }\n\n  return '';\n};\n"
  },
  {
    "path": "packages/analytics-react-native/src/cookie-migration/index.ts",
    "content": "import { UserSession, ReactNativeOptions, getOldCookieName } from '@amplitude/analytics-core';\nimport { createCookieStorage, getDefaultConfig, getTopLevelDomain } from '../config';\n\nexport const parseOldCookies = async (apiKey: string, options?: ReactNativeOptions): Promise<UserSession> => {\n  const storage = await createCookieStorage<string>({\n    ...options,\n    domain: options?.disableCookies ? '' : options?.domain ?? (await getTopLevelDomain()),\n  });\n  const oldCookieName = getOldCookieName(apiKey);\n  const cookies = await storage.getRaw(oldCookieName);\n\n  if (!cookies) {\n    return {\n      optOut: false,\n    };\n  }\n\n  if (options?.cookieUpgrade ?? getDefaultConfig().cookieUpgrade) {\n    await storage.remove(oldCookieName);\n  }\n  const [deviceId, userId, optOut, sessionId, lastEventTime] = cookies.split('.');\n  return {\n    deviceId,\n    userId: decode(userId),\n    sessionId: parseTime(sessionId),\n    lastEventTime: parseTime(lastEventTime),\n    optOut: Boolean(optOut),\n  };\n};\n\nexport const parseTime = (num: string) => {\n  const integer = parseInt(num, 32);\n  if (isNaN(integer)) {\n    return undefined;\n  }\n  return integer;\n};\n\nexport const decode = (value?: string): string | undefined => {\n  if (!atob || !escape || !value) {\n    return undefined;\n  }\n  try {\n    return decodeURIComponent(escape(atob(value)));\n  } catch {\n    return undefined;\n  }\n};\n"
  },
  {
    "path": "packages/analytics-react-native/src/index.ts",
    "content": "/* eslint-disable @typescript-eslint/unbound-method */\nimport client from './react-native-client';\nexport { createInstance } from './react-native-client';\nexport const {\n  add,\n  flush,\n  getDeviceId,\n  getSessionId,\n  getUserId,\n  groupIdentify,\n  identify,\n  init,\n  logEvent,\n  remove,\n  reset,\n  revenue,\n  setDeviceId,\n  setGroup,\n  setOptOut,\n  setSessionId,\n  setUserId,\n  track,\n  extendSession,\n} = client;\n\nexport { Revenue, Identify } from '@amplitude/analytics-core';\n\n// Export types to maintain backward compatibility with `analytics-types`.\n// In the next major version, only export customer-facing types to reduce the public API surface.\nimport * as Types from './types';\nexport { Types };\n"
  },
  {
    "path": "packages/analytics-react-native/src/migration/remnant-data-migration.ts",
    "content": "import { NativeModules } from 'react-native';\nimport { Event, ILogger, Storage, UserSession } from '@amplitude/analytics-core';\nimport { STORAGE_PREFIX } from '@amplitude/analytics-core';\n\ntype LegacyEventKind = 'event' | 'identify' | 'interceptedIdentify';\n\ninterface AmplitudeReactNative {\n  getLegacySessionData(instanceName: string | undefined): Promise<Omit<UserSession, 'optOut'>>;\n  getLegacyEvents(instanceName: string | undefined, eventKind: LegacyEventKind): Promise<string[]>;\n  removeLegacyEvent(instanceName: string | undefined, eventKind: LegacyEventKind, eventId: number): void;\n}\n\nexport default class RemnantDataMigration {\n  eventsStorageKey: string;\n  private readonly nativeModule: AmplitudeReactNative;\n\n  constructor(\n    private apiKey: string,\n    private instanceName: string | undefined,\n    private storage: Storage<Event[]> | undefined,\n    private firstRunSinceUpgrade: boolean,\n    private logger: ILogger | undefined,\n  ) {\n    // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n    this.eventsStorageKey = `${STORAGE_PREFIX}_${this.apiKey.substring(0, 10)}`;\n    this.nativeModule = NativeModules.AmplitudeReactNative as AmplitudeReactNative;\n  }\n\n  async execute(): Promise<Omit<UserSession, 'optOut'>> {\n    if (!this.nativeModule) {\n      return {};\n    }\n\n    if (this.firstRunSinceUpgrade) {\n      await this.moveIdentifies();\n      await this.moveInterceptedIdentifies();\n    }\n    await this.moveEvents();\n\n    const sessionData = await this.callNativeFunction(() => this.nativeModule.getLegacySessionData(this.instanceName));\n    return sessionData ?? {};\n  }\n\n  private async moveEvents() {\n    await this.moveLegacyEvents('event');\n  }\n\n  private async moveIdentifies() {\n    await this.moveLegacyEvents('identify');\n  }\n\n  private async moveInterceptedIdentifies() {\n    await this.moveLegacyEvents('interceptedIdentify');\n  }\n\n  private async callNativeFunction<T>(action: () => Promise<T>): Promise<T | undefined> {\n    try {\n      return await action();\n    } catch (e) {\n      this.logger?.error(`can't call native function: ${String(e)}`);\n      return undefined;\n    }\n  }\n\n  private callNativeAction(action: () => void) {\n    try {\n      action();\n    } catch (e) {\n      this.logger?.error(`can't call native function: ${String(e)}`);\n    }\n  }\n\n  private async moveLegacyEvents(eventKind: LegacyEventKind) {\n    const legacyJsonEvents = await this.callNativeFunction(() =>\n      this.nativeModule.getLegacyEvents(this.instanceName, eventKind),\n    );\n    if (!this.storage || !legacyJsonEvents || legacyJsonEvents.length === 0) {\n      return;\n    }\n\n    const events = (await this.storage.get(this.eventsStorageKey)) ?? [];\n    const eventIds: number[] = [];\n\n    legacyJsonEvents.forEach((jsonEvent) => {\n      const event = this.convertLegacyEvent(jsonEvent);\n      if (event) {\n        events.push(event);\n        if (event.event_id !== undefined) {\n          eventIds.push(event.event_id);\n        }\n      }\n    });\n\n    await this.storage.set(this.eventsStorageKey, events);\n    eventIds.forEach((eventId) =>\n      this.callNativeAction(() => this.nativeModule.removeLegacyEvent(this.instanceName, eventKind, eventId)),\n    );\n  }\n\n  /* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access */\n  private convertLegacyEvent(legacyJsonEvent: string): Event | null {\n    try {\n      const event = JSON.parse(legacyJsonEvent) as Event;\n\n      const { library, timestamp, uuid, api_properties } = event as any;\n      if (library !== undefined) {\n        // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n        event.library = `${library.name}/${library.version}`;\n      }\n      if (timestamp !== undefined) {\n        event.time = timestamp;\n      }\n      if (uuid !== undefined) {\n        event.insert_id = uuid;\n      }\n\n      if (api_properties) {\n        const { androidADID, android_app_set_id, ios_idfa, ios_idfv, productId, quantity, price, location } =\n          api_properties;\n        if (androidADID !== undefined) {\n          event.adid = androidADID;\n        }\n        if (android_app_set_id !== undefined) {\n          event.android_app_set_id = android_app_set_id;\n        }\n        if (ios_idfa !== undefined) {\n          event.idfa = ios_idfa;\n        }\n        if (ios_idfv !== undefined) {\n          event.idfv = ios_idfv;\n        }\n        if (productId !== undefined) {\n          event.productId = productId;\n        }\n        if (quantity !== undefined) {\n          event.quantity = quantity;\n        }\n        if (price !== undefined) {\n          event.price = price;\n        }\n        if (location !== undefined) {\n          const { lat, lng } = location;\n          event.location_lat = lat;\n          event.location_lng = lng;\n        }\n      }\n\n      const { $productId: productId, $quantity: quantity, $price: price, $revenueType: revenueType } = event as any;\n      if (productId !== undefined) {\n        event.productId = productId;\n      }\n      if (quantity !== undefined) {\n        event.quantity = quantity;\n      }\n      if (price !== undefined) {\n        event.price = price;\n      }\n      if (revenueType !== undefined) {\n        event.revenueType = revenueType;\n      }\n\n      return event;\n    } catch {\n      // skip invalid events\n      return null;\n    }\n  }\n  // eslint-enable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n}\n"
  },
  {
    "path": "packages/analytics-react-native/src/plugins/context.ts",
    "content": "import {\n  BeforePlugin,\n  ReactNativeConfig,\n  Event,\n  ReactNativeTrackingOptions,\n  UUID,\n  getLanguage,\n} from '@amplitude/analytics-core';\nimport UAParser from '@amplitude/ua-parser-js';\nimport { VERSION } from '../version';\nimport { NativeModules } from 'react-native';\n\nconst BROWSER_PLATFORM = 'Web';\nconst IP_ADDRESS = '$remote';\n\ntype NativeContext = {\n  version: string;\n  platform: string;\n  language: string;\n  country: string;\n  osName: string;\n  osVersion: string;\n  deviceBrand: string;\n  deviceManufacturer: string;\n  deviceModel: string;\n  carrier: string;\n  adid: string;\n  appSetId: string;\n  idfv: string;\n};\n\nexport interface AmplitudeReactNative {\n  getApplicationContext(options: ReactNativeTrackingOptions): Promise<NativeContext>;\n}\n\nexport class Context implements BeforePlugin {\n  name = '@amplitude/plugin-context-react-native';\n  type = 'before' as const;\n\n  // this.config is defined in setup() which will always be called first\n  // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n  // @ts-ignore\n  config: ReactNativeConfig;\n  uaResult: UAParser.IResult;\n  nativeModule: AmplitudeReactNative | undefined = NativeModules.AmplitudeReactNative as\n    | AmplitudeReactNative\n    | undefined;\n  library = `amplitude-react-native-ts/${VERSION}`;\n\n  constructor() {\n    let agent: string | undefined;\n    /* istanbul ignore else */\n    if (typeof navigator !== 'undefined') {\n      agent = navigator.userAgent;\n    }\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n    this.uaResult = new UAParser(agent).getResult();\n  }\n\n  setup(config: ReactNativeConfig): Promise<undefined> {\n    this.config = config;\n    return Promise.resolve(undefined);\n  }\n\n  async execute(context: Event): Promise<Event> {\n    const time = new Date().getTime();\n    const nativeContext = await this.nativeModule?.getApplicationContext(this.config.trackingOptions);\n    const appVersion = this.config.appVersion || nativeContext?.version;\n    const platform = nativeContext?.platform || BROWSER_PLATFORM;\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment\n    const osName = nativeContext?.osName || this.uaResult.browser.name;\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment\n    const osVersion = nativeContext?.osVersion || this.uaResult.browser.version;\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment\n    const deviceVendor = nativeContext?.deviceManufacturer || this.uaResult.device.vendor;\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment\n    const deviceModel = nativeContext?.deviceModel || this.uaResult.device.model || this.uaResult.os.name;\n    const language = nativeContext?.language || getLanguage();\n    const country = nativeContext?.country;\n    const carrier = nativeContext?.carrier;\n    const adid = nativeContext?.adid;\n    const appSetId = nativeContext?.appSetId;\n    const idfv = nativeContext?.idfv;\n\n    const event: Event = {\n      user_id: this.config.userId,\n      device_id: this.config.deviceId,\n      session_id: this.config.sessionId,\n      time,\n      ...(appVersion && { app_version: appVersion }),\n      ...(this.config.trackingOptions.platform && { platform: platform }),\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n      ...(this.config.trackingOptions.osName && { os_name: osName }),\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n      ...(this.config.trackingOptions.osVersion && { os_version: osVersion }),\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n      ...(this.config.trackingOptions.deviceManufacturer && { device_manufacturer: deviceVendor }),\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n      ...(this.config.trackingOptions.deviceModel && { device_model: deviceModel }),\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n      ...(this.config.trackingOptions.language && { language: language }),\n      ...(this.config.trackingOptions.country && { country: country }),\n      ...(this.config.trackingOptions.carrier && { carrier: carrier }),\n      ...(this.config.trackingOptions.ipAddress && { ip: IP_ADDRESS }),\n      ...(this.config.trackingOptions.adid && { adid: adid }),\n      ...(this.config.trackingOptions.appSetId && { android_app_set_id: appSetId }),\n      ...(this.config.trackingOptions.idfv && { idfv: idfv }),\n      insert_id: UUID(),\n      partner_id: this.config.partnerId,\n      plan: this.config.plan,\n      ...(this.config.ingestionMetadata && {\n        ingestion_metadata: {\n          source_name: this.config.ingestionMetadata.sourceName,\n          source_version: this.config.ingestionMetadata.sourceVersion,\n        },\n      }),\n      ...context,\n      library: this.library,\n    };\n    return event;\n  }\n}\n"
  },
  {
    "path": "packages/analytics-react-native/src/react-native-client.ts",
    "content": "import { AppState, AppStateStatus, NativeEventSubscription } from 'react-native';\nimport {\n  AmplitudeCore,\n  Destination,\n  UUID,\n  returnWrapper,\n  debugWrapper,\n  getClientLogConfig,\n  getClientStates,\n  ReactNativeConfig,\n  ReactNativeOptions,\n  ReactNativeAttributionOptions as AttributionOptions,\n  IIdentify,\n  EventOptions,\n  Event,\n  Result,\n  ReactNativeClient,\n  Campaign,\n  IdentityEventSender,\n  getAnalyticsConnector,\n  setConnectorDeviceId,\n  setConnectorUserId,\n  SpecialEventType,\n  AnalyticsClient,\n} from '@amplitude/analytics-core';\nimport { CampaignTracker } from './campaign/campaign-tracker';\nimport { Context } from './plugins/context';\nimport { useReactNativeConfig, createCookieStorage } from './config';\nimport { parseOldCookies } from './cookie-migration';\nimport { isNative } from './utils/platform';\n\nconst START_SESSION_EVENT = 'session_start';\nconst END_SESSION_EVENT = 'session_end';\n\nexport class AmplitudeReactNative extends AmplitudeCore implements ReactNativeClient, AnalyticsClient {\n  appState: AppStateStatus = 'background';\n  private appStateChangeHandler: NativeEventSubscription | undefined;\n  explicitSessionId: number | undefined;\n  // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n  // @ts-ignore\n  config: ReactNativeConfig;\n  userProperties: { [key: string]: any } | undefined;\n\n  init(apiKey = '', userId?: string, options?: ReactNativeOptions) {\n    return returnWrapper(this._init({ ...options, userId, apiKey }));\n  }\n  protected async _init(options: ReactNativeOptions & { apiKey: string }) {\n    // Step 0: Block concurrent initialization\n    if (this.initializing) {\n      return;\n    }\n    this.initializing = true;\n    this.explicitSessionId = options.sessionId;\n\n    // Step 1: Read cookies stored by old SDK\n    const oldCookies = await parseOldCookies(options.apiKey, options);\n\n    // Step 2: Create react native config\n    const reactNativeOptions = await useReactNativeConfig(options.apiKey, {\n      ...options,\n      deviceId: options.deviceId ?? oldCookies.deviceId,\n      sessionId: oldCookies.sessionId,\n      optOut: options.optOut ?? oldCookies.optOut,\n      lastEventTime: oldCookies.lastEventTime,\n      userId: options.userId ?? oldCookies.userId,\n    });\n    await super._init(reactNativeOptions);\n\n    // Set up the analytics connector to integrate with the experiment SDK.\n    // Send events from the experiment SDK and forward identifies to the\n    // identity store.\n    const connector = getAnalyticsConnector();\n    connector.identityStore.setIdentity({\n      userId: this.config.userId,\n      deviceId: this.config.deviceId,\n    });\n\n    // Step 3: Install plugins\n    // Do not track any events before this\n    await this.add(new Destination()).promise;\n    await this.add(new Context()).promise;\n    await this.add(new IdentityEventSender()).promise;\n\n    // Step 4: Manage session\n    this.appState = AppState.currentState;\n    const isNewSession = this.startNewSessionIfNeeded(this.currentTimeMillis());\n    this.config.loggerProvider?.log(\n      `Init: startNewSessionIfNeeded = ${isNewSession ? 'yes' : 'no'}, sessionId = ${\n        this.getSessionId() ?? 'undefined'\n      }`,\n    );\n    this.appStateChangeHandler = AppState.addEventListener('change', this.handleAppStateChange);\n\n    this.initializing = false;\n\n    // Step 5: Track attributions\n    await this.runAttributionStrategy(options.attribution, isNewSession);\n\n    // Step 6: Run queued functions\n    await this.runQueuedFunctions('dispatchQ');\n\n    // Step 7: Add the event receiver after running remaining queued functions.\n    connector.eventBridge.setEventReceiver((event) => {\n      void this.track(event.eventType, event.eventProperties);\n    });\n  }\n\n  shutdown() {\n    this.appStateChangeHandler?.remove();\n  }\n\n  async runAttributionStrategy(attributionConfig?: AttributionOptions, isNewSession = false) {\n    if (isNative()) {\n      return;\n    }\n    const track = (...args: Parameters<typeof this.track>) => this.track(...args).promise;\n    const onNewCampaign = this.setSessionId.bind(this, this.currentTimeMillis());\n\n    const storage = await createCookieStorage<Campaign>(this.config);\n    const campaignTracker = new CampaignTracker(this.config.apiKey, {\n      ...attributionConfig,\n      storage,\n      track,\n      onNewCampaign,\n    });\n\n    await campaignTracker.send(isNewSession);\n  }\n\n  getUserId() {\n    return this.config?.userId;\n  }\n\n  setUserId(userId: string | undefined) {\n    if (!this.config) {\n      this.q.push(this.setUserId.bind(this, userId));\n      return;\n    }\n    this.config.userId = userId;\n    setConnectorUserId(userId);\n  }\n\n  getDeviceId() {\n    return this.config?.deviceId;\n  }\n\n  setDeviceId(deviceId: string) {\n    if (!this.config) {\n      this.q.push(this.setDeviceId.bind(this, deviceId));\n      return;\n    }\n    this.config.deviceId = deviceId;\n    setConnectorDeviceId(deviceId);\n  }\n\n  identify(identify: IIdentify, eventOptions?: EventOptions) {\n    if (eventOptions?.user_id) {\n      this.setUserId(eventOptions.user_id);\n    }\n    if (eventOptions?.device_id) {\n      this.setDeviceId(eventOptions.device_id);\n    }\n    return super.identify(identify, eventOptions);\n  }\n\n  reset() {\n    this.setUserId(undefined);\n    this.setDeviceId(UUID());\n  }\n\n  getSessionId() {\n    return this.config?.sessionId;\n  }\n\n  getIdentity() {\n    return {\n      userId: this.getUserId(),\n      deviceId: this.getDeviceId(),\n      userProperties: this.userProperties,\n    };\n  }\n\n  getOptOut() {\n    return this.config?.optOut;\n  }\n\n  setSessionId(sessionId: number) {\n    if (!this.config) {\n      this.q.push(this.setSessionId.bind(this, sessionId));\n      return;\n    }\n\n    this.explicitSessionId = sessionId;\n    void this.setSessionIdInternal(sessionId, this.currentTimeMillis());\n  }\n\n  extendSession() {\n    if (!this.config) {\n      this.q.push(this.extendSession.bind(this));\n      return;\n    }\n    this.config.lastEventTime = this.currentTimeMillis();\n  }\n\n  private setSessionIdInternal(sessionId: number, eventTime: number) {\n    const previousSessionId = this.config.sessionId;\n    if (previousSessionId === sessionId) {\n      return;\n    }\n\n    this.config.sessionId = sessionId;\n\n    if (this.config.trackingSessionEvents) {\n      this.config.loggerProvider?.log(`SESSION_END event: previousSessionId = ${previousSessionId ?? 'undefined'}`);\n\n      if (previousSessionId !== undefined) {\n        const sessionEndEvent: Event = {\n          event_type: END_SESSION_EVENT,\n          time: this.config.lastEventTime !== undefined ? this.config.lastEventTime + 1 : sessionId, // increment lastEventTime to sort events properly in UI - session_end should be the last event in a session\n          session_id: previousSessionId,\n        };\n        void this.track(sessionEndEvent);\n      }\n\n      this.config.loggerProvider?.log(`SESSION_START event: sessionId = ${sessionId}`);\n      const sessionStartEvent: Event = {\n        event_type: START_SESSION_EVENT,\n        time: eventTime,\n        session_id: sessionId,\n      };\n      void this.track(sessionStartEvent);\n    }\n\n    this.config.lastEventTime = eventTime;\n  }\n\n  async process(event: Event): Promise<Result> {\n    if (!this.config.optOut) {\n      const eventTime = event.time ?? this.currentTimeMillis();\n      if (event.time === undefined) {\n        event = { ...event, time: eventTime };\n      }\n\n      const isSessionEvent = event.event_type === START_SESSION_EVENT || event.event_type === END_SESSION_EVENT;\n      const isCustomEventSessionId =\n        !isSessionEvent && event.session_id != undefined && event.session_id !== this.getSessionId();\n      if (!isCustomEventSessionId) {\n        if (!isSessionEvent) {\n          if (this.appState !== 'active') {\n            this.startNewSessionIfNeeded(eventTime);\n          }\n        }\n        this.config.lastEventTime = eventTime;\n      }\n\n      if (event.session_id == undefined) {\n        event.session_id = this.getSessionId();\n      }\n\n      if (event.event_id === undefined) {\n        const eventId = (this.config.lastEventId ?? 0) + 1;\n        event = { ...event, event_id: eventId };\n        this.config.lastEventId = eventId;\n      }\n    }\n\n    // Set user properties\n    if (event.event_type === SpecialEventType.IDENTIFY && event.user_properties) {\n      this.userProperties = this.getOperationAppliedUserProperties(event.user_properties);\n    }\n\n    return super.process(event);\n  }\n\n  currentTimeMillis() {\n    return Date.now();\n  }\n\n  private startNewSessionIfNeeded(timestamp: number): boolean {\n    const sessionId = this.explicitSessionId ?? timestamp;\n\n    const shouldStartNewSession = this.shouldStartNewSession(timestamp);\n    if (shouldStartNewSession) {\n      this.setSessionIdInternal(sessionId, timestamp);\n    } else {\n      this.config.lastEventTime = timestamp;\n    }\n\n    return shouldStartNewSession;\n  }\n\n  private shouldStartNewSession(timestamp: number): boolean {\n    const sessionId = this.explicitSessionId ?? timestamp;\n\n    return (\n      !this.inSession() ||\n      (this.explicitSessionId !== this.config.sessionId &&\n        (this.explicitSessionId !== undefined || !this.isWithinMinTimeBetweenSessions(sessionId)))\n    );\n  }\n\n  private isWithinMinTimeBetweenSessions(timestamp: number) {\n    return timestamp - (this.config.lastEventTime ?? 0) < this.config.sessionTimeout;\n  }\n\n  private inSession() {\n    return this.config.sessionId != undefined;\n  }\n\n  private readonly handleAppStateChange = (nextAppState: AppStateStatus) => {\n    const currentAppState = this.appState;\n    this.appState = nextAppState;\n    if (currentAppState !== nextAppState) {\n      const timestamp = this.currentTimeMillis();\n      if (nextAppState == 'active') {\n        this.enterForeground(timestamp);\n      } else {\n        this.exitForeground(timestamp);\n      }\n    }\n  };\n\n  private enterForeground(timestamp: number) {\n    this.config.loggerProvider?.log('App Activated');\n    return this.startNewSessionIfNeeded(timestamp);\n  }\n\n  private exitForeground(timestamp: number) {\n    this.config.lastEventTime = timestamp;\n  }\n}\n\nexport const createInstance = (): ReactNativeClient => {\n  const client = new AmplitudeReactNative();\n  return {\n    init: debugWrapper(\n      client.init.bind(client),\n      'init',\n      getClientLogConfig(client),\n      getClientStates(client, ['config']),\n    ),\n    add: debugWrapper(\n      client.add.bind(client),\n      'add',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.plugins']),\n    ),\n    remove: debugWrapper(\n      client.remove.bind(client),\n      'remove',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.plugins']),\n    ),\n    track: debugWrapper(\n      client.track.bind(client),\n      'track',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.queue.length']),\n    ),\n    logEvent: debugWrapper(\n      client.logEvent.bind(client),\n      'logEvent',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.queue.length']),\n    ),\n    identify: debugWrapper(\n      client.identify.bind(client),\n      'identify',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.queue.length']),\n    ),\n    groupIdentify: debugWrapper(\n      client.groupIdentify.bind(client),\n      'groupIdentify',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.queue.length']),\n    ),\n    setGroup: debugWrapper(\n      client.setGroup.bind(client),\n      'setGroup',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.queue.length']),\n    ),\n    revenue: debugWrapper(\n      client.revenue.bind(client),\n      'revenue',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.queue.length']),\n    ),\n    flush: debugWrapper(\n      client.flush.bind(client),\n      'flush',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.queue.length']),\n    ),\n    getUserId: debugWrapper(\n      client.getUserId.bind(client),\n      'getUserId',\n      getClientLogConfig(client),\n      getClientStates(client, ['config', 'config.userId']),\n    ),\n    setUserId: debugWrapper(\n      client.setUserId.bind(client),\n      'setUserId',\n      getClientLogConfig(client),\n      getClientStates(client, ['config', 'config.userId']),\n    ),\n    getDeviceId: debugWrapper(\n      client.getDeviceId.bind(client),\n      'getDeviceId',\n      getClientLogConfig(client),\n      getClientStates(client, ['config', 'config.deviceId']),\n    ),\n    setDeviceId: debugWrapper(\n      client.setDeviceId.bind(client),\n      'setDeviceId',\n      getClientLogConfig(client),\n      getClientStates(client, ['config', 'config.deviceId']),\n    ),\n    reset: debugWrapper(\n      client.reset.bind(client),\n      'reset',\n      getClientLogConfig(client),\n      getClientStates(client, ['config', 'config.userId', 'config.deviceId']),\n    ),\n    getSessionId: debugWrapper(\n      client.getSessionId.bind(client),\n      'getSessionId',\n      getClientLogConfig(client),\n      getClientStates(client, ['config']),\n    ),\n    setSessionId: debugWrapper(\n      client.setSessionId.bind(client),\n      'setSessionId',\n      getClientLogConfig(client),\n      getClientStates(client, ['config']),\n    ),\n    extendSession: debugWrapper(\n      client.extendSession.bind(client),\n      'extendSession',\n      getClientLogConfig(client),\n      getClientStates(client, ['config']),\n    ),\n    setOptOut: debugWrapper(\n      client.setOptOut.bind(client),\n      'setOptOut',\n      getClientLogConfig(client),\n      getClientStates(client, ['config']),\n    ),\n  };\n};\n\nexport default createInstance();\n"
  },
  {
    "path": "packages/analytics-react-native/src/storage/local-storage.ts",
    "content": "import { Storage, getGlobalScope } from '@amplitude/analytics-core';\nimport AsyncStorage from '@react-native-async-storage/async-storage';\n\nexport class LocalStorage<T> implements Storage<T> {\n  async isEnabled(): Promise<boolean> {\n    /* istanbul ignore if */\n    if (!getGlobalScope()) {\n      return false;\n    }\n\n    const random = String(Date.now());\n    const testStorage = new LocalStorage<string>();\n    const testKey = 'AMP_TEST';\n    try {\n      await testStorage.set(testKey, random);\n      const value = await testStorage.get(testKey);\n      return value === random;\n    } catch {\n      /* istanbul ignore next */\n      return false;\n    } finally {\n      await testStorage.remove(testKey);\n    }\n  }\n\n  async get(key: string): Promise<T | undefined> {\n    try {\n      const value = await this.getRaw(key);\n      if (!value) {\n        return undefined;\n      }\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n      return JSON.parse(value);\n    } catch {\n      /* istanbul ignore next */\n      return undefined;\n    }\n  }\n\n  async getRaw(key: string): Promise<string | undefined> {\n    return (await AsyncStorage.getItem(key)) || undefined;\n  }\n\n  async set(key: string, value: T): Promise<void> {\n    try {\n      await AsyncStorage.setItem(key, JSON.stringify(value));\n    } catch {\n      //\n    }\n  }\n\n  async remove(key: string): Promise<void> {\n    try {\n      await AsyncStorage.removeItem(key);\n    } catch {\n      //\n    }\n  }\n\n  async reset(): Promise<void> {\n    try {\n      await AsyncStorage.clear();\n    } catch {\n      //\n    }\n  }\n}\n"
  },
  {
    "path": "packages/analytics-react-native/src/types.ts",
    "content": "/* eslint-disable @typescript-eslint/unbound-method */\nexport {\n  AmplitudeReturn,\n  BaseEvent,\n  EventOptions,\n  ReactNativeClient,\n  ReactNativeAttributionOptions,\n  ReactNativeOptions,\n  ReactNativeConfig,\n  ReactNativeTrackingOptions,\n  Event,\n  IdentifyEvent,\n  GroupIdentifyEvent,\n  IdentifyOperation,\n  SpecialEventType,\n  IIdentify,\n  IRevenue,\n  RevenueProperty,\n  ILogger,\n  LogLevel,\n  Plugin,\n  BeforePlugin,\n  EnrichmentPlugin,\n  DestinationPlugin,\n  Result,\n  ServerZoneType,\n  ServerZone,\n  IdentityStorageType,\n  Storage,\n  TransportType,\n} from '@amplitude/analytics-core';\n"
  },
  {
    "path": "packages/analytics-react-native/src/utils/platform.ts",
    "content": "import { Platform } from 'react-native';\n\nexport const isWeb = (): boolean => {\n  return Platform.OS === 'web';\n};\n\nexport const isNative = (): boolean => {\n  return !isWeb();\n};\n"
  },
  {
    "path": "packages/analytics-react-native/src/version.ts",
    "content": "export const VERSION = '1.5.53';\n"
  },
  {
    "path": "packages/analytics-react-native/test/config.test.ts",
    "content": "import * as Config from '../src/config';\nimport * as LocalStorageModule from '../src/storage/local-storage';\nimport * as core from '@amplitude/analytics-core';\nimport { LogLevel, Storage, UserSession, getCookieName, FetchTransport } from '@amplitude/analytics-core';\nimport * as BrowserUtils from '@amplitude/analytics-core';\nimport { isWeb } from '../src/utils/platform';\nimport { uuidPattern } from './helpers/constants';\n\ndescribe('config', () => {\n  const someUUID: string = expect.stringMatching(uuidPattern) as string;\n  const someStorage: core.MemoryStorage<UserSession> = expect.any(\n    core.MemoryStorage,\n  ) as core.MemoryStorage<UserSession>;\n\n  const API_KEY = 'apiKey';\n\n  describe('BrowserConfig', () => {\n    test('should create overwrite config', async () => {\n      const cookieStorage = new core.MemoryStorage<UserSession>();\n      const logger = new core.Logger();\n      logger.enable(LogLevel.Warn);\n      const config = new Config.ReactNativeConfig('');\n      expect(config).toEqual({\n        apiKey: '',\n        appVersion: undefined,\n        cookieStorage,\n        cookieExpiration: 365,\n        cookieSameSite: 'Lax',\n        cookieSecure: false,\n        cookieUpgrade: true,\n        disableCookies: false,\n        domain: '',\n        flushIntervalMillis: 1000,\n        flushMaxRetries: 5,\n        flushQueueSize: 30,\n        instanceName: '$default_instance',\n        loggerProvider: logger,\n        logLevel: LogLevel.Warn,\n        minIdLength: undefined,\n        _optOut: false,\n        partnerId: undefined,\n        plan: undefined,\n        ingestionMetadata: undefined,\n        serverUrl: 'https://api2.amplitude.com/2/httpapi',\n        serverZone: 'US',\n        sessionTimeout: 300000,\n        trackingOptions: {\n          adid: true,\n          carrier: true,\n          deviceManufacturer: true,\n          deviceModel: true,\n          ipAddress: true,\n          language: true,\n          osName: true,\n          osVersion: true,\n          platform: true,\n          appSetId: true,\n          idfv: true,\n          country: false,\n        },\n        transportProvider: new FetchTransport(),\n        useBatch: false,\n        trackingSessionEvents: false,\n        offline: false,\n        storageProvider: undefined,\n      });\n    });\n  });\n\n  describe('useBrowserConfig', () => {\n    test('should create default config', async () => {\n      jest.spyOn(Config, 'createCookieStorage').mockResolvedValueOnce(new core.MemoryStorage());\n      jest.spyOn(Config, 'createEventsStorage').mockResolvedValueOnce(new core.MemoryStorage());\n      const logger = new core.Logger();\n      logger.enable(LogLevel.Warn);\n      const config = await Config.useReactNativeConfig(API_KEY, undefined);\n      expect(config).toEqual({\n        apiKey: API_KEY,\n        appVersion: undefined,\n        cookieStorage: someStorage,\n        cookieExpiration: 365,\n        cookieSameSite: 'Lax',\n        cookieSecure: false,\n        cookieUpgrade: true,\n        _deviceId: someUUID,\n        disableCookies: false,\n        domain: '',\n        flushIntervalMillis: 1000,\n        flushMaxRetries: 5,\n        flushQueueSize: 30,\n        instanceName: '$default_instance',\n        loggerProvider: logger,\n        logLevel: LogLevel.Warn,\n        minIdLength: undefined,\n        _optOut: false,\n        partnerId: undefined,\n        plan: undefined,\n        ingestionMetadata: undefined,\n        serverUrl: 'https://api2.amplitude.com/2/httpapi',\n        serverZone: 'US',\n        sessionTimeout: 300000,\n        storageProvider: new core.MemoryStorage(),\n        trackingOptions: {\n          adid: true,\n          carrier: true,\n          deviceManufacturer: true,\n          deviceModel: true,\n          ipAddress: true,\n          language: true,\n          osName: true,\n          osVersion: true,\n          platform: true,\n          appSetId: true,\n          idfv: true,\n          country: false,\n        },\n        transportProvider: new FetchTransport(),\n        useBatch: false,\n        trackingSessionEvents: false,\n        offline: false,\n      });\n    });\n\n    test('should create using cookies/overwrite', async () => {\n      const cookieStorage = new core.MemoryStorage<UserSession>();\n      await cookieStorage.set(getCookieName(API_KEY), {\n        deviceId: 'deviceIdFromCookies',\n        lastEventTime: 1,\n        sessionId: -1,\n        userId: 'userIdFromCookies',\n        optOut: false,\n        lastEventId: 2,\n      });\n      jest.spyOn(Config, 'createCookieStorage').mockResolvedValueOnce(cookieStorage);\n      jest.spyOn(Config, 'createEventsStorage').mockResolvedValueOnce(new core.MemoryStorage());\n      const logger = new core.Logger();\n      logger.enable(LogLevel.Warn);\n      const config = await Config.useReactNativeConfig(API_KEY, {\n        partnerId: 'partnerId',\n        plan: {\n          version: '0',\n        },\n        ingestionMetadata: {\n          sourceName: 'ampli',\n          sourceVersion: '2.0.0',\n        },\n        sessionTimeout: 1,\n        cookieUpgrade: false,\n        disableCookies: true,\n      });\n      expect(config).toEqual({\n        apiKey: API_KEY,\n        appVersion: undefined,\n        cookieStorage,\n        cookieExpiration: 365,\n        cookieSameSite: 'Lax',\n        cookieSecure: false,\n        cookieUpgrade: false,\n        _deviceId: 'deviceIdFromCookies',\n        disableCookies: true,\n        domain: '',\n        flushIntervalMillis: 1000,\n        flushMaxRetries: 5,\n        flushQueueSize: 30,\n        instanceName: '$default_instance',\n        _lastEventId: 2,\n        _lastEventTime: 1,\n        loggerProvider: logger,\n        logLevel: LogLevel.Warn,\n        minIdLength: undefined,\n        _optOut: false,\n        partnerId: 'partnerId',\n        plan: {\n          version: '0',\n        },\n        ingestionMetadata: {\n          sourceName: 'ampli',\n          sourceVersion: '2.0.0',\n        },\n        serverUrl: 'https://api2.amplitude.com/2/httpapi',\n        serverZone: 'US',\n        _sessionId: -1,\n        sessionTimeout: 1,\n        storageProvider: new core.MemoryStorage(),\n        trackingSessionEvents: false,\n        trackingOptions: {\n          adid: true,\n          carrier: true,\n          deviceManufacturer: true,\n          deviceModel: true,\n          ipAddress: true,\n          language: true,\n          osName: true,\n          osVersion: true,\n          platform: true,\n          appSetId: true,\n          idfv: true,\n          country: false,\n        },\n        transportProvider: new FetchTransport(),\n        useBatch: false,\n        _userId: 'userIdFromCookies',\n        offline: false,\n      });\n    });\n  });\n\n  describe('createCookieStorage', () => {\n    test('should return custom', async () => {\n      const cookieStorage = {\n        options: {},\n        config: {},\n        isEnabled: async () => true,\n        get: async () => ({\n          optOut: false,\n        }),\n        set: async () => undefined,\n        remove: async () => undefined,\n        reset: async () => undefined,\n        getRaw: async () => undefined,\n      };\n      const storage = await Config.createCookieStorage({\n        cookieStorage,\n      });\n      expect(storage).toBe(cookieStorage);\n    });\n\n    /*\n     * Tested function is only available on web.\n     */\n    if (isWeb()) {\n      test('should return cookies', async () => {\n        const storage = await Config.createCookieStorage();\n        expect(storage).toBeInstanceOf(BrowserUtils.CookieStorage);\n      });\n    }\n\n    test('should use return storage', async () => {\n      const storage = await Config.createCookieStorage({ disableCookies: true });\n      expect(storage).toBeInstanceOf(LocalStorageModule.LocalStorage);\n    });\n\n    test('should use memory', async () => {\n      const cookiesConstructor = jest.spyOn(BrowserUtils, 'CookieStorage').mockReturnValueOnce({\n        options: {},\n        config: {},\n        isEnabled: async () => false,\n        get: async () => '',\n        getRaw: async () => '',\n        set: async () => undefined,\n        remove: async () => undefined,\n        reset: async () => undefined,\n      } as unknown as BrowserUtils.CookieStorage<unknown>);\n      const localStorageConstructor = jest.spyOn(LocalStorageModule, 'LocalStorage').mockReturnValueOnce({\n        isEnabled: async () => false,\n        get: async () => '',\n        set: async () => undefined,\n        remove: async () => undefined,\n        reset: async () => undefined,\n        getRaw: async () => undefined,\n      });\n      const storage = await Config.createCookieStorage();\n      expect(storage).toBeInstanceOf(core.MemoryStorage);\n      expect(cookiesConstructor).toHaveBeenCalledTimes(1);\n      expect(localStorageConstructor).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('createEventsStorage', () => {\n    test('should return custom', async () => {\n      const storageProvider = {\n        isEnabled: async () => true,\n        get: async () => [],\n        set: async () => undefined,\n        remove: async () => undefined,\n        reset: async () => undefined,\n        getRaw: async () => undefined,\n      };\n      const storage = await Config.createEventsStorage({\n        storageProvider,\n      });\n      expect(storage).toBe(storageProvider);\n    });\n\n    test('should use return storage', async () => {\n      const storage = await Config.createEventsStorage();\n      expect(storage).toBeInstanceOf(LocalStorageModule.LocalStorage);\n    });\n\n    test('should return undefined storage', async () => {\n      const storage = await Config.createEventsStorage({\n        storageProvider: undefined,\n      });\n      expect(storage).toBe(undefined);\n    });\n  });\n\n  describe('getTopLevelDomain', () => {\n    test('should return empty string for localhost', async () => {\n      // jest env hostname is localhost\n      const domain = await Config.getTopLevelDomain();\n      expect(domain).toBe('');\n    });\n\n    test('should return empty string if no access to cookies', async () => {\n      const testCookieStorage: Storage<number> = {\n        isEnabled: () => Promise.resolve(false),\n        get: jest.fn().mockResolvedValueOnce(Promise.resolve(1)),\n        getRaw: jest.fn().mockResolvedValueOnce(Promise.resolve(1)),\n        set: jest.fn().mockResolvedValueOnce(Promise.resolve(undefined)),\n        remove: jest.fn().mockResolvedValueOnce(Promise.resolve(undefined)),\n        reset: jest.fn().mockResolvedValueOnce(Promise.resolve(undefined)),\n      };\n      jest.spyOn(BrowserUtils, 'CookieStorage').mockReturnValueOnce({\n        ...testCookieStorage,\n        options: {},\n        config: {},\n      } as unknown as BrowserUtils.CookieStorage<unknown>);\n      const domain = await Config.getTopLevelDomain();\n      expect(domain).toBe('');\n    });\n\n    test('should return top level domain', async () => {\n      const testCookieStorage: Storage<number> = {\n        isEnabled: () => Promise.resolve(true),\n        get: jest.fn().mockResolvedValueOnce(Promise.resolve(1)),\n        getRaw: jest.fn().mockResolvedValueOnce(Promise.resolve(1)),\n        set: jest.fn().mockResolvedValueOnce(Promise.resolve(undefined)),\n        remove: jest.fn().mockResolvedValueOnce(Promise.resolve(undefined)),\n        reset: jest.fn().mockResolvedValueOnce(Promise.resolve(undefined)),\n      };\n      const actualCookieStorage: Storage<number> = {\n        isEnabled: () => Promise.resolve(true),\n        get: jest.fn().mockResolvedValueOnce(Promise.resolve(undefined)).mockResolvedValueOnce(Promise.resolve(1)),\n        getRaw: jest.fn().mockResolvedValueOnce(Promise.resolve(undefined)).mockResolvedValueOnce(Promise.resolve(1)),\n        set: jest.fn().mockResolvedValue(Promise.resolve(undefined)),\n        remove: jest.fn().mockResolvedValue(Promise.resolve(undefined)),\n        reset: jest.fn().mockResolvedValue(Promise.resolve(undefined)),\n      };\n      jest\n        .spyOn(BrowserUtils, 'CookieStorage')\n        .mockReturnValueOnce({\n          ...testCookieStorage,\n          options: {},\n          config: {},\n        } as unknown as BrowserUtils.CookieStorage<unknown>)\n        .mockReturnValue({\n          ...actualCookieStorage,\n          options: {},\n          config: {},\n        } as unknown as BrowserUtils.CookieStorage<unknown>);\n      expect(await Config.getTopLevelDomain('www.legislation.gov.uk')).toBe('.legislation.gov.uk');\n    });\n\n    // `window.location` is web-only; these cases don't apply on RN.\n    if (isWeb()) {\n      test('should not throw an error when location is an empty object', async () => {\n        const originalLocation = window.location;\n\n        Object.defineProperty(window, 'location', {\n          value: {} as Location,\n          configurable: true,\n        });\n\n        expect(await Config.getTopLevelDomain()).toBe('');\n\n        Object.defineProperty(window, 'location', {\n          value: originalLocation,\n          configurable: true,\n        });\n      });\n\n      test('should return empty string when location is undefined', async () => {\n        const originalLocation = window.location;\n\n        Object.defineProperty(window, 'location', {\n          value: undefined,\n          configurable: true,\n        });\n\n        expect(await Config.getTopLevelDomain()).toBe('');\n\n        Object.defineProperty(window, 'location', {\n          value: originalLocation,\n          configurable: true,\n        });\n      });\n    }\n  });\n});\n"
  },
  {
    "path": "packages/analytics-react-native/test/cookie-migration/index.test.ts",
    "content": "import { Storage, getOldCookieName, CookieStorage } from '@amplitude/analytics-core';\nimport { decode, parseOldCookies, parseTime } from '../../src/cookie-migration';\nimport * as LocalStorageModule from '../../src/storage/local-storage';\nimport { isWeb } from '../../src/utils/platform';\n\ndescribe('cookie-migration', () => {\n  const API_KEY = 'asdfasdf';\n  afterEach(() => {\n    // clean up cookies (web-only — RN has no `document`)\n    if (typeof document !== 'undefined') {\n      document.cookie = `${getOldCookieName(API_KEY)}=null; expires=-1`;\n    }\n  });\n\n  describe('parseOldCookies', () => {\n    test('should return default values', async () => {\n      const cookies = await parseOldCookies(API_KEY, { disableCookies: true });\n      expect(cookies).toEqual({\n        optOut: false,\n      });\n    });\n\n    test('should handle non-persistent storage', async () => {\n      jest.spyOn(LocalStorageModule, 'LocalStorage').mockReturnValueOnce({\n        isEnabled: async () => false,\n        get: async () => ({}),\n        getRaw: async () => '',\n        set: async () => undefined,\n        remove: async () => undefined,\n        reset: async () => undefined,\n      });\n      const cookies = await parseOldCookies(API_KEY, { disableCookies: true });\n      expect(cookies).toEqual({\n        optOut: false,\n      });\n    });\n\n    /*\n     * Tested function is only available on web.\n     */\n    if (isWeb()) {\n      test('should remove old cookies', async () => {\n        const timestamp = 1650949309508;\n        const time = timestamp.toString(32);\n        const userId = 'userId';\n        const encodedUserId = btoa(unescape(encodeURIComponent(userId)));\n        const oldCookieName = getOldCookieName(API_KEY);\n        document.cookie = `${oldCookieName}=deviceId.${encodedUserId}..${time}.${time}`;\n        const cookies = await parseOldCookies(API_KEY, {\n          cookieUpgrade: true,\n        });\n        expect(cookies).toEqual({\n          deviceId: 'deviceId',\n          userId: 'userId',\n          sessionId: timestamp,\n          lastEventTime: timestamp,\n          optOut: false,\n        });\n\n        const storage: Storage<string> = new CookieStorage<string>();\n        const cookies2 = await storage.getRaw(oldCookieName);\n        expect(cookies2).toBeUndefined();\n      });\n\n      test('should keep old cookies', async () => {\n        const timestamp = 1650949309508;\n        const time = timestamp.toString(32);\n        const userId = 'userId';\n        const encodedUserId = btoa(unescape(encodeURIComponent(userId)));\n        const oldCookieName = getOldCookieName(API_KEY);\n        document.cookie = `${oldCookieName}=deviceId.${encodedUserId}..${time}.${time}`;\n        const cookies = await parseOldCookies(API_KEY, {\n          cookieUpgrade: false,\n        });\n        expect(cookies).toEqual({\n          deviceId: 'deviceId',\n          userId: 'userId',\n          sessionId: timestamp,\n          lastEventTime: timestamp,\n          optOut: false,\n        });\n\n        const storage: Storage<string> = new CookieStorage<string>();\n        const cookies2 = await storage.getRaw(oldCookieName);\n        expect(cookies2).toBe(`deviceId.${encodedUserId}..${time}.${time}`);\n      });\n    }\n  });\n\n  describe('parseTime', () => {\n    test('should parse time', () => {\n      const timestamp = Date.now();\n      const base32 = timestamp.toString(32);\n      expect(parseTime(base32)).toBe(timestamp);\n    });\n\n    test('should handle invalid values', () => {\n      expect(parseTime('')).toBe(undefined);\n    });\n  });\n\n  describe('decode', () => {\n    test('should decode value', () => {\n      expect(decode('YXNkZg==')).toBe('asdf');\n    });\n\n    test('should handle incorrecty encoded value', () => {\n      expect(decode('asdf')).toBe(undefined);\n    });\n\n    test('should handle undefined input', () => {\n      expect(decode(undefined)).toBe(undefined);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-react-native/test/helpers/constants.ts",
    "content": "export const uuidPattern = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/;\n"
  },
  {
    "path": "packages/analytics-react-native/test/helpers/default.ts",
    "content": "import { MemoryStorage } from '@amplitude/analytics-core';\nimport { ReactNativeConfig as IReactNativeConfig, ReactNativeOptions, UserSession } from '@amplitude/analytics-core';\n\nimport { ReactNativeConfig } from '../../src/config';\n\nexport const useDefaultConfig = (overrides?: ReactNativeOptions) =>\n  new ReactNativeConfig(API_KEY, { ...DEFAULT_OPTIONS, ...overrides });\n\nexport const API_KEY = 'apiKey';\n\nexport const USER_ID = 'userId';\n\nconst cookieStorage = new MemoryStorage<UserSession>();\n\nexport const DEFAULT_OPTIONS: Partial<IReactNativeConfig> = {\n  apiKey: API_KEY,\n  cookieStorage,\n  cookieExpiration: 365,\n  cookieSameSite: 'Lax',\n  cookieSecure: false,\n  disableCookies: false,\n  domain: '',\n  storageProvider: {\n    isEnabled: async () => true,\n    get: async () => undefined,\n    set: async () => undefined,\n    remove: async () => undefined,\n    reset: async () => undefined,\n    getRaw: async () => undefined,\n  },\n  trackingOptions: {\n    adid: true,\n    carrier: true,\n    deviceManufacturer: true,\n    deviceModel: true,\n    ipAddress: true,\n    language: true,\n    osName: true,\n    osVersion: true,\n    platform: true,\n    appSetId: true,\n    idfv: true,\n    country: true,\n  },\n  transportProvider: {\n    send: () => Promise.resolve(null),\n  },\n  sessionTimeout: 5 * 60 * 1000,\n};\n"
  },
  {
    "path": "packages/analytics-react-native/test/index.test.ts",
    "content": "import {\n  add,\n  createInstance,\n  flush,\n  getDeviceId,\n  getSessionId,\n  getUserId,\n  groupIdentify,\n  Identify,\n  identify,\n  init,\n  logEvent,\n  remove,\n  reset,\n  Revenue,\n  revenue,\n  setDeviceId,\n  setGroup,\n  setOptOut,\n  setSessionId,\n  setUserId,\n  track,\n} from '../src/index';\n\ndescribe('index', () => {\n  test('should expose apis', () => {\n    expect(typeof add).toBe('function');\n    expect(typeof createInstance).toBe('function');\n    expect(typeof flush).toBe('function');\n    expect(typeof groupIdentify).toBe('function');\n    expect(typeof getDeviceId).toBe('function');\n    expect(typeof getSessionId).toBe('function');\n    expect(typeof getUserId).toBe('function');\n    expect(typeof Identify).toBe('function');\n    expect(typeof identify).toBe('function');\n    expect(typeof init).toBe('function');\n    expect(typeof logEvent).toBe('function');\n    expect(typeof remove).toBe('function');\n    expect(typeof reset).toBe('function');\n    expect(typeof Revenue).toBe('function');\n    expect(typeof revenue).toBe('function');\n    expect(typeof setDeviceId).toBe('function');\n    expect(typeof setGroup).toBe('function');\n    expect(typeof setOptOut).toBe('function');\n    expect(typeof setSessionId).toBe('function');\n    expect(typeof setUserId).toBe('function');\n    expect(typeof track).toBe('function');\n  });\n});\n"
  },
  {
    "path": "packages/analytics-react-native/test/migration/remnant-data-migration.test.ts",
    "content": "import { NativeModules } from 'react-native';\nimport { AmplitudeReactNative } from '../../src/react-native-client';\nimport { Logger, MemoryStorage } from '@amplitude/analytics-core';\nimport {\n  Event,\n  LogLevel,\n  UserSession,\n  STORAGE_PREFIX,\n  getCookieName as getStorageKey,\n} from '@amplitude/analytics-core';\n\ndescribe('migration', () => {\n  const deviceId = '22833898-c487-4536-b213-40f207abdce0R';\n  const userId = 'android-kotlin-sample-user-legacy';\n  let sessionId: number | undefined;\n  let lastEventTime: number | undefined;\n  const removeLegacyEvent = jest.fn();\n\n  beforeAll(() => {\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n    NativeModules.AmplitudeReactNative = {\n      getApplicationContext: () => {\n        return {\n          version: '1.0.0',\n          platform: 'iOS',\n          os: 'react-native-tests',\n          language: 'react-native-tests',\n          device_brand: 'react-native-tests',\n          device_manufacturer: 'react-native-tests',\n          device_model: 'react-native-tests',\n          carrier: 'react-native-tests',\n        };\n      },\n      ...NativeModules.AmplitudeReactNative,\n      getLegacySessionData: () => ({\n        deviceId: deviceId,\n        userId: userId,\n        sessionId,\n        lastEventTime: lastEventTime,\n        lastEventId: 12345,\n      }),\n      getLegacyEvents: (instanceName: string | undefined, eventKind: string) => {\n        if (instanceName !== 'test-instance') {\n          return [];\n        }\n\n        if (eventKind == 'event') {\n          return [\n            '{\"event_id\":1,\"event_type\":\"legacy event 1\",\"timestamp\":1684219150354,\"user_id\":\"android-kotlin-sample-user-legacy\",\"device_id\":\"22833898-c487-4536-b213-40f207abdce0R\",\"session_id\":1684219150343,\"uuid\":\"d6eff10b-9cd4-45d7-85cb-c81cb6cb8b2e\",\"sequence_number\":3,\"version_name\":\"1.0\",\"os_name\":\"android\",\"os_version\":\"13\",\"api_level\":33,\"device_brand\":\"google\",\"device_manufacturer\":\"Google\",\"device_model\":\"sdk_gphone64_x86_64\",\"carrier\":\"T-Mobile\",\"country\":\"US\",\"language\":\"en\",\"platform\":\"Android\",\"library\":{\"name\":\"amplitude-android\",\"version\":\"2.39.3-SNAPSHOT\"},\"api_properties\":{\"androidADID\":\"63e67f64-ba80-4683-90e2-6d5d78801df9\",\"android_app_set_id\":\"31ac0887-8b0d-e858-3d66-2e36f043a3ce\",\"limit_ad_tracking\":false,\"gps_enabled\":true,\"ios_idfa\":\"idfa-1\",\"location\":{\"lat\":123,\"lng\":456},\"productId\":\"product-1\",\"quantity\":12,\"price\":23},\"event_properties\":{\"test1\":\"value1\",\"test2\":\"value2\"},\"user_properties\":{},\"groups\":{},\"group_properties\":{}}',\n            '{\"event_id\":7,\"event_type\":\"legacy event 2\",\"timestamp\":1684219150355,\"user_id\":\"android-kotlin-sample-user-legacy\",\"device_id\":\"22833898-c487-4536-b213-40f207abdce0R\",\"session_id\":1684219150343,\"uuid\":\"7b4c5c13-6fdc-4931-9ba1-e4efdf346ee0\",\"sequence_number\":4,\"version_name\":\"1.0\",\"os_name\":\"android\",\"os_version\":\"13\",\"api_level\":33,\"device_brand\":\"google\",\"device_manufacturer\":\"Google\",\"device_model\":\"sdk_gphone64_x86_64\",\"carrier\":\"T-Mobile\",\"country\":\"US\",\"language\":\"en\",\"platform\":\"Android\",\"library\":{\"name\":\"amplitude-android\",\"version\":\"2.39.3-SNAPSHOT\"},\"api_properties\":{\"androidADID\":\"63e67f64-ba80-4683-90e2-6d5d78801df9\",\"android_app_set_id\":\"31ac0887-8b0d-e858-3d66-2e36f043a3ce\",\"limit_ad_tracking\":false,\"gps_enabled\":true,\"ios_idfv\":\"idfv-1\",\"location\":{\"lat\":789,\"lng\":234}}, \"$productId\":\"product-2\",\"$quantity\":34,\"$price\":45,\"event_properties\":{\"data1\":\"value1\",\"data2\":\"value2\"},\"user_properties\":{},\"groups\":{},\"group_properties\":{}}',\n          ];\n        }\n        if (eventKind == 'identify') {\n          return [\n            '{\"event_id\":4,\"event_type\":\"$identify\",\"timestamp\":1684219150343,\"user_id\":\"android-kotlin-sample-user-legacy\",\"device_id\":\"22833898-c487-4536-b213-40f207abdce0R\",\"session_id\":1684219150343,\"uuid\":\"be09ecba-83f7-444a-aba0-fe1f529a3716\",\"sequence_number\":1,\"version_name\":\"1.0\",\"os_name\":\"android\",\"os_version\":\"13\",\"api_level\":33,\"device_brand\":\"google\",\"device_manufacturer\":\"Google\",\"device_model\":\"sdk_gphone64_x86_64\",\"carrier\":\"T-Mobile\",\"country\":\"US\",\"language\":\"en\",\"platform\":\"Android\",\"library\":{\"name\":\"amplitude-android\",\"version\":\"2.39.3-SNAPSHOT\"},\"api_properties\":{\"androidADID\":\"63e67f64-ba80-4683-90e2-6d5d78801df9\",\"android_app_set_id\":\"31ac0887-8b0d-e858-3d66-2e36f043a3ce\",\"limit_ad_tracking\":false,\"gps_enabled\":true},\"event_properties\":{},\"user_properties\":{\"$add\":{\"ident1\":\"value1\",\"ident2\":\"value2\"}},\"groups\":{},\"group_properties\":{}}',\n            '{\"event_id\":5,\"event_type\":\"$identify\",\"timestamp\":1684219150344,\"user_id\":\"android-kotlin-sample-user-legacy\",\"device_id\":\"22833898-c487-4536-b213-40f207abdce0R\",\"session_id\":1684219150343,\"uuid\":\"0894387e-e923-423b-9feb-086ba8cb2cfa\",\"sequence_number\":2,\"version_name\":\"1.0\",\"os_name\":\"android\",\"os_version\":\"13\",\"api_level\":33,\"device_brand\":\"google\",\"device_manufacturer\":\"Google\",\"device_model\":\"sdk_gphone64_x86_64\",\"carrier\":\"T-Mobile\",\"country\":\"US\",\"language\":\"en\",\"platform\":\"Android\",\"library\":{\"name\":\"amplitude-android\",\"version\":\"2.39.3-SNAPSHOT\"},\"api_properties\":{\"androidADID\":\"63e67f64-ba80-4683-90e2-6d5d78801df9\",\"android_app_set_id\":\"31ac0887-8b0d-e858-3d66-2e36f043a3ce\",\"limit_ad_tracking\":false,\"gps_enabled\":true},\"event_properties\":{},\"user_properties\":{\"$setOnce\":{\"once1\":\"value1\"}},\"groups\":{},\"group_properties\":{}}',\n          ];\n        }\n        if (eventKind == 'interceptedIdentify') {\n          return [\n            '{\"event_id\":2,\"event_type\":\"$identify\",\"timestamp\":1684219150358,\"user_id\":\"android-kotlin-sample-user-legacy\",\"device_id\":\"22833898-c487-4536-b213-40f207abdce0R\",\"session_id\":1684219150343,\"uuid\":\"1a14d057-8a12-40bb-8217-2d62dd08a525\",\"sequence_number\":5,\"version_name\":\"1.0\",\"os_name\":\"android\",\"os_version\":\"13\",\"api_level\":33,\"device_brand\":\"google\",\"device_manufacturer\":\"Google\",\"device_model\":\"sdk_gphone64_x86_64\",\"carrier\":\"T-Mobile\",\"country\":\"US\",\"language\":\"en\",\"platform\":\"Android\",\"library\":{\"name\":\"amplitude-android\",\"version\":\"2.39.3-SNAPSHOT\"},\"api_properties\":{\"androidADID\":\"63e67f64-ba80-4683-90e2-6d5d78801df9\",\"android_app_set_id\":\"31ac0887-8b0d-e858-3d66-2e36f043a3ce\",\"limit_ad_tracking\":false,\"gps_enabled\":true},\"event_properties\":{},\"user_properties\":{\"$set\":{\"user1\":\"value1\",\"user2\":\"value2\"}},\"groups\":{},\"group_properties\":{}}',\n            '{\"event_id\":6,\"event_type\":\"$identify\",\"timestamp\":1684219150359,\"user_id\":\"android-kotlin-sample-user-legacy\",\"device_id\":\"22833898-c487-4536-b213-40f207abdce0R\",\"session_id\":1684219150343,\"uuid\":\"b115a299-4cc6-495b-8e4e-c2ce6f244be9\",\"sequence_number\":6,\"version_name\":\"1.0\",\"os_name\":\"android\",\"os_version\":\"13\",\"api_level\":33,\"device_brand\":\"google\",\"device_manufacturer\":\"Google\",\"device_model\":\"sdk_gphone64_x86_64\",\"carrier\":\"T-Mobile\",\"country\":\"US\",\"language\":\"en\",\"platform\":\"Android\",\"library\":{\"name\":\"amplitude-android\",\"version\":\"2.39.3-SNAPSHOT\"},\"api_properties\":{\"androidADID\":\"63e67f64-ba80-4683-90e2-6d5d78801df9\",\"android_app_set_id\":\"31ac0887-8b0d-e858-3d66-2e36f043a3ce\",\"limit_ad_tracking\":false,\"gps_enabled\":true},\"event_properties\":{},\"user_properties\":{\"$set\":{\"user1\":\"value1\",\"user4\":\"value2\"}},\"groups\":{},\"group_properties\":{}}',\n          ];\n        }\n        return [];\n      },\n      removeLegacyEvent,\n    };\n  });\n\n  beforeEach(() => {\n    sessionId = Date.now() - 3000;\n    lastEventTime = Date.now() - 1000;\n    removeLegacyEvent.mockReset();\n  });\n\n  test('should migrate legacy data', async () => {\n    const client = new AmplitudeReactNative();\n    const storageProvider = new MemoryStorage<Event[]>();\n    const loggerProvider = new Logger();\n    loggerProvider.enable(LogLevel.Warn);\n    await client.init('TEST_API_KEY', undefined, {\n      disableCookies: true,\n      cookieStorage: new MemoryStorage(),\n      storageProvider,\n      loggerProvider,\n      instanceName: 'test-instance',\n    }).promise;\n    expect(client.getDeviceId()).toEqual(deviceId);\n    expect(client.getUserId()).toEqual(userId);\n    expect(client.getSessionId()).toEqual(sessionId);\n    expect(client.config.lastEventTime).toBeGreaterThanOrEqual(lastEventTime ?? 0);\n    expect(client.config.lastEventId).toEqual(12345);\n\n    const eventsKey = `${STORAGE_PREFIX}_${client.config.apiKey.substring(0, 10)}`;\n    const events = await storageProvider.get(eventsKey);\n    expect(events?.length).toEqual(6);\n    const event1 = events?.[0];\n    expect(event1?.event_type).toEqual('$identify');\n    expect(event1?.event_id).toEqual(4);\n    expect(event1?.time).toEqual(1684219150343);\n    expect(event1?.insert_id).toEqual('be09ecba-83f7-444a-aba0-fe1f529a3716');\n    expect(event1?.library).toEqual('amplitude-android/2.39.3-SNAPSHOT');\n    expect(event1?.device_id).toEqual(deviceId);\n    expect(event1?.user_id).toEqual(userId);\n    const event2 = events?.[1];\n    expect(event2?.event_type).toEqual('$identify');\n    expect(event2?.event_id).toEqual(5);\n    expect(event2?.time).toEqual(1684219150344);\n    expect(event2?.insert_id).toEqual('0894387e-e923-423b-9feb-086ba8cb2cfa');\n    expect(event2?.library).toEqual('amplitude-android/2.39.3-SNAPSHOT');\n    expect(event2?.device_id).toEqual(deviceId);\n    expect(event2?.user_id).toEqual(userId);\n    const event3 = events?.[2];\n    expect(event3?.event_type).toEqual('$identify');\n    expect(event3?.event_id).toEqual(2);\n    expect(event3?.time).toEqual(1684219150358);\n    expect(event3?.insert_id).toEqual('1a14d057-8a12-40bb-8217-2d62dd08a525');\n    expect(event3?.library).toEqual('amplitude-android/2.39.3-SNAPSHOT');\n    expect(event3?.device_id).toEqual(deviceId);\n    expect(event3?.user_id).toEqual(userId);\n    const event4 = events?.[3];\n    expect(event4?.event_type).toEqual('$identify');\n    expect(event4?.event_id).toEqual(6);\n    expect(event4?.time).toEqual(1684219150359);\n    expect(event4?.insert_id).toEqual('b115a299-4cc6-495b-8e4e-c2ce6f244be9');\n    expect(event4?.library).toEqual('amplitude-android/2.39.3-SNAPSHOT');\n    expect(event4?.device_id).toEqual(deviceId);\n    expect(event4?.user_id).toEqual(userId);\n    const event5 = events?.[4];\n    expect(event5?.event_type).toEqual('legacy event 1');\n    expect(event5?.event_id).toEqual(1);\n    expect(event5?.time).toEqual(1684219150354);\n    expect(event5?.insert_id).toEqual('d6eff10b-9cd4-45d7-85cb-c81cb6cb8b2e');\n    expect(event5?.library).toEqual('amplitude-android/2.39.3-SNAPSHOT');\n    expect(event5?.device_id).toEqual(deviceId);\n    expect(event5?.user_id).toEqual(userId);\n    expect(event5?.location_lat).toEqual(123);\n    expect(event5?.location_lng).toEqual(456);\n    expect(event5?.productId).toEqual('product-1');\n    expect(event5?.quantity).toEqual(12);\n    expect(event5?.price).toEqual(23);\n    const event6 = events?.[5];\n    expect(event6?.event_type).toEqual('legacy event 2');\n    expect(event6?.event_id).toEqual(7);\n    expect(event6?.time).toEqual(1684219150355);\n    expect(event6?.insert_id).toEqual('7b4c5c13-6fdc-4931-9ba1-e4efdf346ee0');\n    expect(event6?.library).toEqual('amplitude-android/2.39.3-SNAPSHOT');\n    expect(event6?.device_id).toEqual(deviceId);\n    expect(event6?.user_id).toEqual(userId);\n    expect(event6?.location_lat).toEqual(789);\n    expect(event6?.location_lng).toEqual(234);\n    expect(event6?.productId).toEqual('product-2');\n    expect(event6?.quantity).toEqual(34);\n    expect(event6?.price).toEqual(45);\n\n    expect(removeLegacyEvent.mock.calls).toEqual([\n      ['test-instance', 'identify', 4],\n      ['test-instance', 'identify', 5],\n      ['test-instance', 'interceptedIdentify', 2],\n      ['test-instance', 'interceptedIdentify', 6],\n      ['test-instance', 'event', 1],\n      ['test-instance', 'event', 7],\n    ]);\n  });\n\n  test('should not migrate legacy identifies if not first run since upgrade', async () => {\n    const apiKey = 'TEST_API_KEY';\n    const client = new AmplitudeReactNative();\n    const storageProvider = new MemoryStorage<Event[]>();\n    const loggerProvider = new Logger();\n    loggerProvider.enable(LogLevel.Warn);\n    const cookieStorage = new MemoryStorage<UserSession>();\n    await cookieStorage.set(getStorageKey(apiKey), {\n      deviceId: 'custom-device-id',\n      lastEventId: 1000,\n      lastEventTime: Date.now(),\n      optOut: false,\n    });\n\n    await client.init(apiKey, undefined, {\n      disableCookies: true,\n      cookieStorage,\n      storageProvider,\n      loggerProvider,\n      instanceName: 'test-instance',\n    }).promise;\n    expect(client.getDeviceId()).toEqual('custom-device-id');\n    expect(client.getUserId()).toEqual(userId);\n    expect(client.getSessionId()).toEqual(sessionId);\n    expect(client.config.lastEventTime).toBeGreaterThanOrEqual(lastEventTime ?? 0);\n    expect(client.config.lastEventId).toEqual(1000);\n\n    const eventsKey = `${STORAGE_PREFIX}_${client.config.apiKey.substring(0, 10)}`;\n    const events = await storageProvider.get(eventsKey);\n    expect(events?.length).toEqual(2);\n    const event1 = events?.[0];\n    expect(event1?.event_type).toEqual('legacy event 1');\n    expect(event1?.event_id).toEqual(1);\n    expect(event1?.time).toEqual(1684219150354);\n    expect(event1?.insert_id).toEqual('d6eff10b-9cd4-45d7-85cb-c81cb6cb8b2e');\n    expect(event1?.library).toEqual('amplitude-android/2.39.3-SNAPSHOT');\n    expect(event1?.device_id).toEqual(deviceId);\n    expect(event1?.user_id).toEqual(userId);\n    const event2 = events?.[1];\n    expect(event2?.event_type).toEqual('legacy event 2');\n    expect(event2?.event_id).toEqual(7);\n    expect(event2?.time).toEqual(1684219150355);\n    expect(event2?.insert_id).toEqual('7b4c5c13-6fdc-4931-9ba1-e4efdf346ee0');\n    expect(event2?.library).toEqual('amplitude-android/2.39.3-SNAPSHOT');\n    expect(event2?.device_id).toEqual(deviceId);\n    expect(event2?.user_id).toEqual(userId);\n\n    expect(removeLegacyEvent.mock.calls).toEqual([\n      ['test-instance', 'event', 1],\n      ['test-instance', 'event', 7],\n    ]);\n  });\n\n  test('should not migrate legacy data if migrateLegacyData is false', async () => {\n    const client = new AmplitudeReactNative();\n    const storageProvider = new MemoryStorage<Event[]>();\n    const loggerProvider = new Logger();\n    loggerProvider.enable(LogLevel.Warn);\n    await client.init('TEST_API_KEY', undefined, {\n      disableCookies: true,\n      cookieStorage: new MemoryStorage(),\n      storageProvider: storageProvider,\n      migrateLegacyData: false,\n      loggerProvider,\n      instanceName: 'test-instance',\n    }).promise;\n    expect(client.getDeviceId()).not.toEqual(deviceId);\n    expect(client.getUserId()).not.toEqual(userId);\n    expect(client.getSessionId()).not.toEqual(sessionId);\n    expect(client.config.lastEventId).not.toEqual(12345);\n\n    const eventsKey = `${STORAGE_PREFIX}_${client.config.apiKey.substring(0, 10)}`;\n    const events = await storageProvider.get(eventsKey);\n    expect(events?.length || 0).toEqual(0);\n\n    expect(removeLegacyEvent.mock.calls).toEqual([]);\n  }, 10000);\n});\n"
  },
  {
    "path": "packages/analytics-react-native/test/mock/@react-native-async-storage/async-storage.js",
    "content": "export default from '@react-native-community/async-storage/jest/async-storage-mock';\n"
  },
  {
    "path": "packages/analytics-react-native/test/mock/setup-mobile.ts",
    "content": "import mockAsyncStorage from '@react-native-async-storage/async-storage/jest/async-storage-mock';\nimport { NativeModules, Platform } from 'react-native';\n\n/*\n * Set the platform OS to mobile.\n */\nPlatform.OS = 'ios';\n\n/*\n * Mock AsyncStorage\n */\njest.mock('@react-native-async-storage/async-storage', () => mockAsyncStorage);\n\n/*\n * Mock navigator. This is what the navigator looks like on mobile.\n *\n * Use `Object.defineProperty` rather than direct assignment because Node 21+\n * defines `globalThis.navigator` as a non-writable getter. A plain assignment\n * (`globalThis.navigator = …`) throws `TypeError: Cannot set property …` in\n * strict-mode ES modules. The built-in descriptor is `configurable: true`, so\n * `defineProperty` overrides it cleanly on Node 22 / 24 while still working\n * on Node 18/20 (where the property doesn't exist yet) and under jsdom\n * (where `window.navigator` and `globalThis.navigator` alias).\n */\n// eslint-disable-next-line no-restricted-globals\nObject.defineProperty(globalThis, 'navigator', {\n  value: { product: 'ReactNative' },\n  configurable: true,\n  writable: true,\n});\n\n/*\n * Mock Native Module\n */\nNativeModules.AmplitudeReactNative = {\n  getApplicationContext: async (): Promise<Record<string, string>> => {\n    // Keys here must match the NativeContext type declared in\n    // src/plugins/context.ts. Previously this mock used snake_case keys\n    // (`os`, `device_brand`, …) which silently fell through to the\n    // navigator.userAgent fallback path. That path only worked under jsdom\n    // (which provides a default userAgent); in pure-node it returned\n    // `undefined` and broke the os_name assertion.\n    return {\n      version: '1.0.0',\n      platform: 'iOS',\n      osName: 'react-native-tests',\n      osVersion: 'react-native-tests',\n      language: 'react-native-tests',\n      country: 'react-native-tests',\n      deviceBrand: 'react-native-tests',\n      deviceManufacturer: 'react-native-tests',\n      deviceModel: 'react-native-tests',\n      carrier: 'react-native-tests',\n      adid: 'react-native-tests',\n      appSetId: 'react-native-tests',\n      idfv: 'react-native-tests',\n    };\n  },\n  getLegacySessionData: () => ({}),\n  getLegacyEvents: () => [],\n  removeLegacyEvent: () => ({}),\n};\n"
  },
  {
    "path": "packages/analytics-react-native/test/mock/setup-web.ts",
    "content": "import mockAsyncStorage from '@react-native-async-storage/async-storage/jest/async-storage-mock';\nimport { Platform } from 'react-native';\n\n/*\n * Set the platform OS to mobile.\n */\nPlatform.OS = 'web';\n\n/*\n * Mock AsyncStorage\n */\njest.mock('@react-native-async-storage/async-storage', () => mockAsyncStorage);\n\n/*\n * Mock navigator. This is what the navigator looks like on mobile\n */\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\n// window['navigator'] = { product: \"ReactNative\" }\n"
  },
  {
    "path": "packages/analytics-react-native/test/plugins/context.test.ts",
    "content": "import { Context } from '../../src/plugins/context';\nimport { useDefaultConfig } from '../helpers/default';\nimport { isWeb } from '../../src/utils/platform';\n\ndescribe('context', () => {\n  describe('setup', () => {\n    test('should setup plugin', async () => {\n      const context = new Context();\n      const config = useDefaultConfig();\n      config.appVersion = '1.0.0';\n      await context.setup(config);\n      expect(context.config.appVersion).toEqual('1.0.0');\n      expect(context.uaResult).toBeDefined();\n    });\n\n    test('should setup plugin without app version', async () => {\n      const context = new Context();\n      const config = useDefaultConfig();\n      await context.setup(config);\n      expect(context.config.appVersion).toBeUndefined();\n      expect(context.uaResult).toBeDefined();\n    });\n  });\n\n  describe('execute', () => {\n    test('should execute plugin', async () => {\n      const context = new Context();\n      const config = useDefaultConfig({\n        deviceId: 'deviceId',\n        sessionId: 1,\n        userId: 'user@amplitude.com',\n      });\n      config.appVersion = '1.0.0';\n      await context.setup(config);\n\n      const event = {\n        event_type: 'event_type',\n      };\n      const firstContextEvent = await context.execute(event);\n      expect(firstContextEvent.app_version).toEqual('1.0.0');\n      expect(firstContextEvent.event_type).toEqual('event_type');\n      expect(firstContextEvent.insert_id).toBeDefined();\n      /*\n       * Platform dependent on mobile/web\n       */\n      expect(firstContextEvent.platform).toEqual(isWeb() ? 'Web' : 'iOS');\n      expect(firstContextEvent.os_name).toBeDefined();\n      expect(firstContextEvent.os_version).toBeDefined();\n      expect(firstContextEvent.language).toBeDefined();\n      expect(firstContextEvent.ip).toEqual('$remote');\n      expect(firstContextEvent.device_id).toEqual('deviceId');\n      expect(firstContextEvent.session_id).toEqual(1);\n      expect(firstContextEvent.user_id).toEqual('user@amplitude.com');\n\n      const secondContextEvent = await context.execute(event);\n      expect(secondContextEvent.insert_id).toBeDefined();\n      expect(secondContextEvent.insert_id).not.toEqual(firstContextEvent.insert_id);\n    });\n\n    test('should not return the properties when the tracking options are false', async () => {\n      const context = new Context();\n      const config = useDefaultConfig({\n        deviceId: 'deviceId',\n        sessionId: 1,\n        trackingOptions: {\n          adid: false,\n          carrier: false,\n          deviceManufacturer: false,\n          deviceModel: false,\n          ipAddress: false,\n          language: false,\n          osName: false,\n          osVersion: false,\n          platform: false,\n          appSetId: false,\n          idfv: false,\n          country: false,\n        },\n        userId: 'user@amplitude.com',\n      });\n      config.appVersion = '1.0.0';\n      await context.setup(config);\n\n      const event = {\n        event_type: 'event_type',\n      };\n      const firstContextEvent = await context.execute(event);\n      expect(firstContextEvent.app_version).toEqual('1.0.0');\n      expect(firstContextEvent.event_type).toEqual('event_type');\n      expect(firstContextEvent.insert_id).toBeDefined();\n\n      // tracking options should not be included\n      expect(firstContextEvent.platform).toBeUndefined();\n      expect(firstContextEvent.os_name).toBeUndefined();\n      expect(firstContextEvent.os_version).toBeUndefined();\n      expect(firstContextEvent.language).toBeUndefined();\n      expect(firstContextEvent.ip).toBeUndefined();\n      expect(firstContextEvent.adid).toBeUndefined();\n      expect(firstContextEvent.android_app_set_id).toBeUndefined();\n      expect(firstContextEvent.idfv).toBeUndefined();\n      expect(firstContextEvent.country).toBeUndefined();\n      expect(firstContextEvent.device_id).toEqual('deviceId');\n      expect(firstContextEvent.session_id).toEqual(1);\n      expect(firstContextEvent.user_id).toEqual('user@amplitude.com');\n\n      const secondContextEvent = await context.execute(event);\n      expect(secondContextEvent.insert_id).toBeDefined();\n      expect(secondContextEvent.insert_id).not.toEqual(firstContextEvent.insert_id);\n    });\n\n    test('should be overwritten by the context', async () => {\n      const context = new Context();\n      const config = useDefaultConfig({\n        deviceId: 'deviceId',\n        sessionId: 1,\n        userId: 'user@amplitude.com',\n      });\n      config.appVersion = '1.0.0';\n      await context.setup(config);\n\n      const event = {\n        event_type: 'event_type',\n        device_id: 'new deviceId',\n      };\n      const firstContextEvent = await context.execute(event);\n      expect(firstContextEvent.app_version).toEqual('1.0.0');\n      expect(firstContextEvent.event_type).toEqual('event_type');\n      expect(firstContextEvent.insert_id).toBeDefined();\n      expect(firstContextEvent.device_id).toEqual('new deviceId');\n\n      const secondContextEvent = await context.execute(event);\n      expect(secondContextEvent.insert_id).toBeDefined();\n      expect(secondContextEvent.insert_id).not.toEqual(firstContextEvent.insert_id);\n    });\n\n    test('should contain app version from native module', async () => {\n      const context = new Context();\n      const config = useDefaultConfig({\n        deviceId: 'deviceId',\n        sessionId: 1,\n        userId: 'user@amplitude.com',\n      });\n      await context.setup(config);\n\n      const event = {\n        event_type: 'event_type',\n      };\n      const firstContextEvent = await context.execute(event);\n\n      expect(firstContextEvent.app_version).toEqual(isWeb() ? undefined : '1.0.0');\n    });\n\n    describe('ingestionMetadata config', () => {\n      test('should include ingestion metadata', async () => {\n        const sourceName = 'ampli';\n        const sourceVersion = '2.0.0';\n        const context = new Context();\n        const config = useDefaultConfig({\n          ingestionMetadata: {\n            sourceName,\n            sourceVersion,\n          },\n          userId: 'user@amplitude.com',\n        });\n        await context.setup(config);\n\n        const event = {\n          event_type: 'event_type',\n        };\n        const firstContextEvent = await context.execute(event);\n        expect(firstContextEvent.event_type).toEqual('event_type');\n        expect(firstContextEvent.ingestion_metadata?.source_name).toEqual(sourceName);\n        expect(firstContextEvent.ingestion_metadata?.source_version).toEqual(sourceVersion);\n      });\n\n      test('sourceName should be optional', async () => {\n        const sourceVersion = '2.0.0';\n        const context = new Context();\n        const config = useDefaultConfig({\n          ingestionMetadata: {\n            sourceVersion,\n          },\n          userId: 'user@amplitude.com',\n        });\n        await context.setup(config);\n\n        const event = {\n          event_type: 'event_type',\n        };\n        const firstContextEvent = await context.execute(event);\n        expect(firstContextEvent.ingestion_metadata?.source_name).toBeUndefined();\n        expect(firstContextEvent.ingestion_metadata?.source_version).toEqual(sourceVersion);\n      });\n\n      test('sourceVersion should be optional', async () => {\n        const sourceName = 'ampli';\n        const context = new Context();\n        const config = useDefaultConfig({\n          ingestionMetadata: {\n            sourceName,\n          },\n          userId: 'user@amplitude.com',\n        });\n        await context.setup(config);\n\n        const event = {\n          event_type: 'event_type',\n        };\n        const firstContextEvent = await context.execute(event);\n        expect(firstContextEvent.ingestion_metadata?.source_name).toEqual(sourceName);\n        expect(firstContextEvent.ingestion_metadata?.source_version).toBeUndefined();\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-react-native/test/react-native-client.test.ts",
    "content": "import { AmplitudeReactNative } from '../src/react-native-client';\nimport * as core from '@amplitude/analytics-core';\nimport * as CookieMigration from '../src/cookie-migration';\nimport {\n  Status,\n  UserSession,\n  Event,\n  getAnalyticsConnector,\n  getCookieName as getStorageKey,\n} from '@amplitude/analytics-core';\nimport { isWeb } from '../src/utils/platform';\nimport AsyncStorage from '@react-native-async-storage/async-storage';\nimport * as Config from '../src/config';\n\ndescribe('react-native-client', () => {\n  const API_KEY = 'API_KEY';\n  const USER_ID = 'USER_ID';\n  const DEVICE_ID = 'DEVICE_ID';\n  const attributionConfig = {\n    attribution: {\n      disabled: true,\n    },\n  };\n\n  afterEach(async () => {\n    // clean up cookies (web-only — RN has no `document`)\n    if (typeof document !== 'undefined') {\n      document.cookie = 'AMP_API_KEY=null; expires=-1';\n    }\n    if (!isWeb()) {\n      await AsyncStorage.clear();\n    }\n  });\n\n  describe('init', () => {\n    test('should initialize client', async () => {\n      const parseOldCookies = jest.spyOn(CookieMigration, 'parseOldCookies').mockResolvedValueOnce({\n        optOut: false,\n      });\n      const client = new AmplitudeReactNative();\n      await client.init(API_KEY, USER_ID, {\n        ...attributionConfig,\n      }).promise;\n      expect(parseOldCookies).toHaveBeenCalledTimes(1);\n    });\n\n    test('should initialize without error when apiKey is undefined', async () => {\n      const parseOldCookies = jest.spyOn(CookieMigration, 'parseOldCookies').mockResolvedValueOnce({\n        optOut: false,\n      });\n      const client = new AmplitudeReactNative();\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n      await client.init(undefined as any, USER_ID, {\n        ...attributionConfig,\n      }).promise;\n      expect(parseOldCookies).toHaveBeenCalledTimes(1);\n    });\n\n    test('should read from old cookies config', async () => {\n      const parseOldCookies = jest.spyOn(CookieMigration, 'parseOldCookies').mockResolvedValueOnce({\n        optOut: false,\n        deviceId: DEVICE_ID,\n        sessionId: 1,\n        lastEventTime: Date.now() - 1000,\n      });\n      const cookieStorage = new core.MemoryStorage<UserSession>();\n      const client = new AmplitudeReactNative();\n      await client.init(API_KEY, USER_ID, {\n        optOut: false,\n        cookieStorage,\n        ...attributionConfig,\n      }).promise;\n      expect(client.getDeviceId()).toBe(DEVICE_ID);\n      expect(client.getSessionId()).toBe(1);\n      expect(parseOldCookies).toHaveBeenCalledTimes(1);\n    });\n\n    test('should call prevent concurrent init executions', async () => {\n      const parseOldCookies = jest.spyOn(CookieMigration, 'parseOldCookies').mockResolvedValueOnce({\n        optOut: false,\n      });\n      const useNodeConfig = jest.spyOn(Config, 'useReactNativeConfig');\n      const client = new AmplitudeReactNative();\n      await Promise.all([\n        client.init(API_KEY, USER_ID, {\n          ...attributionConfig,\n        }).promise,\n        client.init(API_KEY, USER_ID, {\n          ...attributionConfig,\n        }).promise,\n        client.init(API_KEY, USER_ID, {\n          ...attributionConfig,\n        }).promise,\n      ]);\n      // NOTE: `parseOldCookies` and `useNodeConfig` are only called once despite multiple init calls\n      expect(parseOldCookies).toHaveBeenCalledTimes(1);\n      expect(useNodeConfig).toHaveBeenCalledTimes(1);\n    });\n\n    test('should read from new cookies config', async () => {\n      const parseOldCookies = jest.spyOn(CookieMigration, 'parseOldCookies').mockResolvedValueOnce({\n        optOut: false,\n      });\n      const cookieStorage = new core.MemoryStorage<UserSession>();\n      jest.spyOn(cookieStorage, 'set').mockResolvedValue();\n      jest.spyOn(cookieStorage, 'get').mockResolvedValue({\n        sessionId: 1,\n        deviceId: DEVICE_ID,\n        optOut: false,\n      });\n      const client = new AmplitudeReactNative();\n      await client.init(API_KEY, USER_ID, {\n        optOut: true,\n        cookieStorage,\n        ...attributionConfig,\n      }).promise;\n      expect(client.getDeviceId()).toBe(DEVICE_ID);\n      expect(client.getSessionId()).not.toBe(1);\n      expect(parseOldCookies).toHaveBeenCalledTimes(1);\n    });\n\n    test('should track attributions', async () => {\n      const parseOldCookies = jest.spyOn(CookieMigration, 'parseOldCookies').mockResolvedValueOnce({\n        optOut: false,\n      });\n      const client = new AmplitudeReactNative();\n      const runAttributionStrategy = jest\n        .spyOn(client, 'runAttributionStrategy')\n        .mockReturnValueOnce(Promise.resolve(undefined));\n      await client.init(API_KEY, USER_ID).promise;\n      expect(parseOldCookies).toHaveBeenCalledTimes(1);\n      expect(runAttributionStrategy).toHaveBeenCalledTimes(1);\n    });\n\n    test('should track attributions with config', async () => {\n      const parseOldCookies = jest.spyOn(CookieMigration, 'parseOldCookies').mockResolvedValueOnce({\n        optOut: false,\n      });\n      const client = new AmplitudeReactNative();\n      const runAttributionStrategy = jest\n        .spyOn(client, 'runAttributionStrategy')\n        .mockReturnValueOnce(Promise.resolve(undefined));\n      await client.init(API_KEY, USER_ID, {\n        attribution: {\n          excludeReferrers: [],\n          initialEmptyValue: '',\n        },\n      }).promise;\n      expect(parseOldCookies).toHaveBeenCalledTimes(1);\n      expect(runAttributionStrategy).toHaveBeenCalledTimes(1);\n    });\n\n    test('should set user id and device id in analytics connector', async () => {\n      const cookieStorage = new core.MemoryStorage<UserSession>();\n      jest.spyOn(cookieStorage, 'set').mockResolvedValue();\n      jest.spyOn(cookieStorage, 'get').mockResolvedValueOnce(undefined).mockResolvedValue({\n        sessionId: 1,\n        deviceId: DEVICE_ID,\n        optOut: false,\n      });\n      const client = new AmplitudeReactNative();\n      await client.init(API_KEY, USER_ID, {\n        optOut: true,\n        cookieStorage,\n        ...attributionConfig,\n      }).promise;\n      expect(client.getDeviceId()).toBe(DEVICE_ID);\n      expect(client.getUserId()).toBe(USER_ID);\n      const identity = getAnalyticsConnector().identityStore.getIdentity();\n      expect(identity.deviceId).toBe(DEVICE_ID);\n      expect(identity.userId).toBe(USER_ID);\n    });\n\n    test('should set up event bridge and track events', async () => {\n      const client = new AmplitudeReactNative();\n      await client.init(API_KEY, USER_ID, {\n        optOut: false,\n        ...attributionConfig,\n      }).promise;\n      const track = jest.spyOn(client, 'track').mockReturnValueOnce({\n        promise: Promise.resolve({\n          code: 200,\n          message: '',\n          event: {\n            event_type: 'event_type',\n          },\n        }),\n      });\n      getAnalyticsConnector().eventBridge.logEvent({\n        eventType: 'event_type',\n        eventProperties: {\n          k: 'v',\n        },\n      });\n      expect(track).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  if (isWeb()) {\n    describe('trackCampaign', () => {\n      test('should track campaign', async () => {\n        const client = new AmplitudeReactNative();\n        const track = jest.spyOn(client, 'track').mockReturnValueOnce({\n          promise: Promise.resolve({\n            code: 200,\n            message: '',\n            event: {\n              event_type: 'event_type',\n            },\n          }),\n        });\n        await client.init(API_KEY, USER_ID, {\n          attribution: {\n            disabled: false,\n          },\n        }).promise;\n        const result = await client.runAttributionStrategy();\n        expect(result).toBe(undefined);\n        expect(track).toHaveBeenCalledTimes(1);\n      });\n    });\n  }\n\n  describe('getUserId', () => {\n    test('should get user id', async () => {\n      const client = new AmplitudeReactNative();\n      await client.init(API_KEY, USER_ID, {\n        ...attributionConfig,\n      }).promise;\n      expect(client.getUserId()).toBe(USER_ID);\n    });\n\n    test('should handle undefined config', async () => {\n      const client = new AmplitudeReactNative();\n      expect(client.getUserId()).toBe(undefined);\n    });\n  });\n\n  describe('setUserId', () => {\n    test('should set user id', async () => {\n      const client = new AmplitudeReactNative();\n      await client.init(API_KEY, undefined, {\n        ...attributionConfig,\n      }).promise;\n      expect(client.getUserId()).toBe(undefined);\n      client.setUserId(USER_ID);\n      expect(client.getUserId()).toBe(USER_ID);\n    });\n\n    test('should defer set user id', () => {\n      return new Promise<void>((resolve) => {\n        const client = new AmplitudeReactNative();\n        void client\n          .init(API_KEY, undefined, {\n            ...attributionConfig,\n          })\n          .promise.then(() => {\n            expect(client.getUserId()).toBe('user@amplitude.com');\n            resolve();\n          });\n        client.setUserId('user@amplitude.com');\n      });\n    });\n  });\n\n  describe('getDeviceId', () => {\n    test('should get device id', async () => {\n      const client = new AmplitudeReactNative();\n      await client.init(API_KEY, undefined, {\n        deviceId: DEVICE_ID,\n        ...attributionConfig,\n      }).promise;\n      expect(client.getDeviceId()).toBe(DEVICE_ID);\n    });\n\n    test('should handle undefined config', async () => {\n      const client = new AmplitudeReactNative();\n      expect(client.getDeviceId()).toBe(undefined);\n    });\n  });\n\n  describe('setDeviceId', () => {\n    test('should set device id config', async () => {\n      const client = new AmplitudeReactNative();\n      await client.init(API_KEY, undefined, {\n        ...attributionConfig,\n      }).promise;\n      client.setDeviceId(DEVICE_ID);\n      expect(client.getDeviceId()).toBe(DEVICE_ID);\n    });\n\n    test('should defer set device id', () => {\n      return new Promise<void>((resolve) => {\n        const client = new AmplitudeReactNative();\n        void client\n          .init(API_KEY, undefined, {\n            ...attributionConfig,\n          })\n          .promise.then(() => {\n            expect(client.getDeviceId()).toBe('asdfg');\n            resolve();\n          });\n        client.setDeviceId('asdfg');\n      });\n    });\n  });\n\n  describe('reset', () => {\n    test('should reset user id and generate new device id config', async () => {\n      const client = new AmplitudeReactNative();\n      await client.init(API_KEY).promise;\n      client.setUserId(USER_ID);\n      client.setDeviceId(DEVICE_ID);\n      expect(client.getUserId()).toBe(USER_ID);\n      expect(client.getDeviceId()).toBe(DEVICE_ID);\n      client.reset();\n      expect(client.getUserId()).toBe(undefined);\n      expect(client.getDeviceId()).not.toBe(DEVICE_ID);\n    }, 10000);\n  });\n\n  describe('getSessionId', () => {\n    test('should get session id', async () => {\n      const client = new AmplitudeReactNative();\n      await client.init(API_KEY, undefined, {\n        sessionId: 1,\n        ...attributionConfig,\n      }).promise;\n      expect(client.getSessionId()).toBe(1);\n    });\n\n    test('should handle undefined config', async () => {\n      const client = new AmplitudeReactNative();\n      expect(client.getSessionId()).toBe(undefined);\n    });\n  });\n\n  describe('setSessionId', () => {\n    test('should set session id', async () => {\n      const client = new AmplitudeReactNative();\n      await client.init(API_KEY, undefined, {\n        ...attributionConfig,\n      }).promise;\n      client.setSessionId(1);\n      expect(client.getSessionId()).toBe(1);\n    });\n\n    test('should defer set session id', () => {\n      return new Promise<void>((resolve) => {\n        const client = new AmplitudeReactNative();\n        void client\n          .init(API_KEY, undefined, {\n            ...attributionConfig,\n          })\n          .promise.then(() => {\n            expect(client.getSessionId()).toBe(1);\n            resolve();\n          });\n        client.setSessionId(1);\n      });\n    });\n  });\n\n  describe('setOptOut', () => {\n    test('should set opt out', async () => {\n      const client = new AmplitudeReactNative();\n      await client.init(API_KEY, undefined, {\n        ...attributionConfig,\n      }).promise;\n      client.setOptOut(true);\n      expect(client.config.optOut).toBe(true);\n    });\n  });\n\n  describe('identify', () => {\n    test('should track identify', async () => {\n      const send = jest.fn().mockReturnValueOnce({\n        status: Status.Success,\n        statusCode: 200,\n        body: {\n          eventsIngested: 1,\n          payloadSizeBytes: 1,\n          serverUploadTime: 1,\n        },\n      });\n      const client = new AmplitudeReactNative();\n      await client.init(API_KEY, undefined, {\n        transportProvider: {\n          send,\n        },\n        ...attributionConfig,\n      }).promise;\n      const identifyObject = new core.Identify();\n      const result = await client.identify(identifyObject, { user_id: '123', device_id: '123' }).promise;\n      expect(result.code).toEqual(200);\n      expect(send).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('groupIdentify', () => {\n    test('should track group identify', async () => {\n      const send = jest.fn().mockReturnValueOnce({\n        status: Status.Success,\n        statusCode: 200,\n        body: {\n          eventsIngested: 1,\n          payloadSizeBytes: 1,\n          serverUploadTime: 1,\n        },\n      });\n      const client = new AmplitudeReactNative();\n      await client.init(API_KEY, undefined, {\n        transportProvider: {\n          send,\n        },\n        ...attributionConfig,\n      }).promise;\n      const identifyObject = new core.Identify();\n      const result = await client.groupIdentify('g', '1', identifyObject).promise;\n      expect(result.code).toEqual(200);\n      expect(send).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('revenue', () => {\n    test('should track revenue', async () => {\n      const send = jest.fn().mockReturnValueOnce({\n        status: Status.Success,\n        statusCode: 200,\n        body: {\n          eventsIngested: 1,\n          payloadSizeBytes: 1,\n          serverUploadTime: 1,\n        },\n      });\n      const client = new AmplitudeReactNative();\n      await client.init(API_KEY, undefined, {\n        transportProvider: {\n          send,\n        },\n        ...attributionConfig,\n      }).promise;\n      const revenueObject = new core.Revenue();\n      const result = await client.revenue(revenueObject).promise;\n      expect(result.code).toEqual(200);\n      expect(send).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('session management', () => {\n    class AmplitudeReactNativeTest extends AmplitudeReactNative {\n      currentTime: number;\n\n      constructor(currentTime: number) {\n        super();\n        this.currentTime = currentTime;\n      }\n\n      currentTimeMillis(): number {\n        return this.currentTime;\n      }\n\n      setActive(currentTime: number) {\n        this.currentTime = currentTime;\n        // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n        // @ts-ignore\n        this.handleAppStateChange('active');\n      }\n\n      setBackground(timestamp: number) {\n        this.currentTime = timestamp;\n        // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n        // @ts-ignore\n        this.handleAppStateChange('background');\n      }\n    }\n\n    const sendResponse = {\n      status: Status.Success,\n      statusCode: 200,\n      body: {\n        eventsIngested: 1,\n        payloadSizeBytes: 1,\n        serverUploadTime: 1,\n      },\n    };\n\n    const clientOptions = (\n      send: any,\n      cookieStorage: core.MemoryStorage<UserSession>,\n      trackingSessionEvents: boolean,\n      sessionId?: number,\n    ) => ({\n      transportProvider: {\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n        send,\n      },\n      cookieStorage,\n      sessionTimeout: 100,\n      sessionId,\n      trackingSessionEvents,\n      ...attributionConfig,\n    });\n\n    test('session restore', async () => {\n      const send = jest.fn().mockReturnValue(sendResponse);\n      const cookieStorage = new core.MemoryStorage<UserSession>();\n\n      const client1 = new AmplitudeReactNativeTest(950);\n      await client1.init(API_KEY, undefined, clientOptions(send, cookieStorage, true)).promise;\n\n      client1.setActive(1000);\n\n      expect(client1.config.sessionId).toEqual(950);\n      expect(client1.config.lastEventTime).toEqual(1000);\n      expect(client1.config.lastEventId).toEqual(1);\n\n      void client1.track({ event_type: 'event-1', time: 1200 });\n\n      expect(client1.config.sessionId).toEqual(950);\n      expect(client1.config.lastEventTime).toEqual(1200);\n      expect(client1.config.lastEventId).toEqual(2);\n\n      const client2 = new AmplitudeReactNativeTest(1250);\n      await client2.init(API_KEY, undefined, clientOptions(send, cookieStorage, true)).promise;\n\n      expect(client2.config.sessionId).toEqual(950);\n      expect(client2.config.lastEventTime).toEqual(1250);\n      expect(client2.config.lastEventId).toEqual(2);\n\n      void client2.track({ event_type: 'event-2', time: 1270 });\n\n      expect(client2.config.sessionId).toEqual(950);\n      expect(client2.config.lastEventTime).toEqual(1270);\n      expect(client2.config.lastEventId).toEqual(3);\n\n      const client3 = new AmplitudeReactNativeTest(1300);\n      await client3.init(API_KEY, undefined, clientOptions(send, cookieStorage, true)).promise;\n\n      expect(client3.config.sessionId).toEqual(950);\n      expect(client3.config.lastEventTime).toEqual(1300);\n      expect(client3.config.lastEventId).toEqual(3);\n\n      client3.setActive(1500);\n\n      expect(client3.config.sessionId).toEqual(1500);\n      expect(client3.config.lastEventTime).toEqual(1500);\n      expect(client3.config.lastEventId).toEqual(5);\n    });\n\n    describe('track session events', () => {\n      test('should assign session ids and track session_start/session_end events', async () => {\n        const send = jest.fn().mockReturnValue(sendResponse);\n        const client = new AmplitudeReactNativeTest(950);\n        const cookieStorage = new core.MemoryStorage<UserSession>();\n        await cookieStorage.set(getStorageKey(API_KEY), { sessionId: 500, lastEventTime: 850, optOut: false });\n\n        await client.init(API_KEY, undefined, clientOptions(send, cookieStorage, true)).promise;\n\n        void client.track({ event_type: 'event-1', time: 1000 });\n        void client.track({ event_type: 'event-2', time: 1050 });\n        void client.track({ event_type: 'event-3', time: 1200 });\n        void client.track({ event_type: 'event-4', time: 1350 });\n\n        client.setActive(1500);\n\n        void client.track({ event_type: 'event-5', time: 1700 });\n\n        client.setBackground(1730);\n\n        void client.track({ event_type: 'event-6', time: 1750 });\n        void client.track({ event_type: 'event-7', time: 2000 });\n\n        client.setActive(2050);\n\n        await client.track({ event_type: 'event-8', time: 2200 }).promise;\n\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n        const events = send.mock.calls.flatMap((call) => call[1].events as Event[]);\n        expect(events.length).toEqual(18);\n        events.forEach((event, i) => expect(event.event_id).toEqual(i + 1));\n\n        expect(events[0].event_type).toEqual('session_end');\n        expect(events[0].session_id).toEqual(500);\n        expect(events[0].time).toEqual(851);\n\n        expect(events[1].event_type).toEqual('session_start');\n        expect(events[1].session_id).toEqual(950);\n        expect(events[1].time).toEqual(950);\n\n        expect(events[2].event_type).toEqual('event-1');\n        expect(events[2].session_id).toEqual(950);\n        expect(events[2].time).toEqual(1000);\n\n        expect(events[3].event_type).toEqual('event-2');\n        expect(events[3].session_id).toEqual(950);\n        expect(events[3].time).toEqual(1050);\n\n        expect(events[4].event_type).toEqual('session_end');\n        expect(events[4].session_id).toEqual(950);\n        expect(events[4].time).toEqual(1051);\n\n        expect(events[5].event_type).toEqual('session_start');\n        expect(events[5].session_id).toEqual(1200);\n        expect(events[5].time).toEqual(1200);\n\n        expect(events[6].event_type).toEqual('event-3');\n        expect(events[6].session_id).toEqual(1200);\n        expect(events[6].time).toEqual(1200);\n\n        expect(events[7].event_type).toEqual('session_end');\n        expect(events[7].session_id).toEqual(1200);\n        expect(events[7].time).toEqual(1201);\n\n        expect(events[8].event_type).toEqual('session_start');\n        expect(events[8].session_id).toEqual(1350);\n        expect(events[8].time).toEqual(1350);\n\n        expect(events[9].event_type).toEqual('event-4');\n        expect(events[9].session_id).toEqual(1350);\n        expect(events[9].time).toEqual(1350);\n\n        expect(events[10].event_type).toEqual('session_end');\n        expect(events[10].session_id).toEqual(1350);\n        expect(events[10].time).toEqual(1351);\n\n        expect(events[11].event_type).toEqual('session_start');\n        expect(events[11].session_id).toEqual(1500);\n        expect(events[11].time).toEqual(1500);\n\n        expect(events[12].event_type).toEqual('event-5');\n        expect(events[12].session_id).toEqual(1500);\n        expect(events[12].time).toEqual(1700);\n\n        expect(events[13].event_type).toEqual('event-6');\n        expect(events[13].session_id).toEqual(1500);\n        expect(events[13].time).toEqual(1750);\n\n        expect(events[14].event_type).toEqual('session_end');\n        expect(events[14].session_id).toEqual(1500);\n        expect(events[14].time).toEqual(1751);\n\n        expect(events[15].event_type).toEqual('session_start');\n        expect(events[15].session_id).toEqual(2000);\n        expect(events[15].time).toEqual(2000);\n\n        expect(events[16].event_type).toEqual('event-7');\n        expect(events[16].session_id).toEqual(2000);\n        expect(events[16].time).toEqual(2000);\n\n        expect(events[17].event_type).toEqual('event-8');\n        expect(events[17].session_id).toEqual(2000);\n        expect(events[17].time).toEqual(2200);\n      });\n\n      test('should use explicit session ids and track session_start/session_end events', async () => {\n        const send = jest.fn().mockReturnValue(sendResponse);\n        const client = new AmplitudeReactNativeTest(950);\n        const cookieStorage = new core.MemoryStorage<UserSession>();\n        await cookieStorage.set(getStorageKey(API_KEY), { sessionId: 500, lastEventTime: 850, optOut: false });\n\n        await client.init(API_KEY, undefined, clientOptions(send, cookieStorage, true, 1000)).promise;\n\n        void client.track({ event_type: 'event-1', time: 1000 });\n        void client.track({ event_type: 'event-2', time: 1050 });\n\n        client.currentTime = 1100;\n        client.setSessionId(5000);\n\n        void client.track({ event_type: 'event-3', time: 1200 });\n        void client.track({ event_type: 'event-4', time: 1350 });\n\n        client.setActive(1500);\n\n        void client.track({ event_type: 'event-5', time: 1700 });\n\n        client.currentTime = 1720;\n        client.setSessionId(5050);\n\n        client.setBackground(1730);\n\n        void client.track({ event_type: 'event-6', time: 1750 });\n        void client.track({ event_type: 'event-7', time: 2000 });\n\n        client.setActive(2050);\n\n        await client.track({ event_type: 'event-8', time: 2200 }).promise;\n\n        client.setSessionId(6000);\n\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n        const events = send.mock.calls.flatMap((call) => call[1].events as Event[]);\n        expect(events.length).toEqual(14);\n        events.forEach((event, i) => expect(event.event_id).toEqual(i + 1));\n\n        expect(events[0].event_type).toEqual('session_end');\n        expect(events[0].session_id).toEqual(500);\n        expect(events[0].time).toEqual(851);\n\n        expect(events[1].event_type).toEqual('session_start');\n        expect(events[1].session_id).toEqual(1000);\n        expect(events[1].time).toEqual(950);\n\n        expect(events[2].event_type).toEqual('event-1');\n        expect(events[2].session_id).toEqual(1000);\n        expect(events[2].time).toEqual(1000);\n\n        expect(events[3].event_type).toEqual('event-2');\n        expect(events[3].session_id).toEqual(1000);\n        expect(events[3].time).toEqual(1050);\n\n        expect(events[4].event_type).toEqual('session_end');\n        expect(events[4].session_id).toEqual(1000);\n        expect(events[4].time).toEqual(1051);\n\n        expect(events[5].event_type).toEqual('session_start');\n        expect(events[5].session_id).toEqual(5000);\n        expect(events[5].time).toEqual(1100);\n\n        expect(events[6].event_type).toEqual('event-3');\n        expect(events[6].session_id).toEqual(5000);\n        expect(events[6].time).toEqual(1200);\n\n        expect(events[7].event_type).toEqual('event-4');\n        expect(events[7].session_id).toEqual(5000);\n        expect(events[7].time).toEqual(1350);\n\n        expect(events[8].event_type).toEqual('event-5');\n        expect(events[8].session_id).toEqual(5000);\n        expect(events[8].time).toEqual(1700);\n\n        expect(events[9].event_type).toEqual('session_end');\n        expect(events[9].session_id).toEqual(5000);\n        expect(events[9].time).toEqual(1701);\n\n        expect(events[10].event_type).toEqual('session_start');\n        expect(events[10].session_id).toEqual(5050);\n        expect(events[10].time).toEqual(1720);\n\n        expect(events[11].event_type).toEqual('event-6');\n        expect(events[11].session_id).toEqual(5050);\n        expect(events[11].time).toEqual(1750);\n\n        expect(events[12].event_type).toEqual('event-7');\n        expect(events[12].session_id).toEqual(5050);\n        expect(events[12].time).toEqual(2000);\n\n        expect(events[13].event_type).toEqual('event-8');\n        expect(events[13].session_id).toEqual(5050);\n        expect(events[13].time).toEqual(2200);\n      });\n    });\n\n    describe('do not track session events', () => {\n      test('should assign session ids and do not track session_start/session_end events', async () => {\n        const send = jest.fn().mockReturnValue(sendResponse);\n        const client = new AmplitudeReactNativeTest(950);\n        const cookieStorage = new core.MemoryStorage<UserSession>();\n        await cookieStorage.set(getStorageKey(API_KEY), { sessionId: 500, lastEventTime: 850, optOut: false });\n\n        await client.init(API_KEY, undefined, clientOptions(send, cookieStorage, false)).promise;\n\n        void client.track({ event_type: 'event-1', time: 1000 });\n        void client.track({ event_type: 'event-2', time: 1050 });\n        void client.track({ event_type: 'event-3', time: 1200 });\n        void client.track({ event_type: 'event-4', time: 1350 });\n\n        client.setActive(1500);\n\n        void client.track({ event_type: 'event-5', time: 1700 });\n\n        client.setBackground(1730);\n\n        void client.track({ event_type: 'event-6', time: 1750 });\n        void client.track({ event_type: 'event-7', time: 2000 });\n\n        client.setActive(2050);\n\n        await client.track({ event_type: 'event-8', time: 2200 }).promise;\n\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n        const events = send.mock.calls.flatMap((call) => call[1].events as Event[]);\n        expect(events.length).toEqual(8);\n        events.forEach((event, i) => expect(event.event_id).toEqual(i + 1));\n\n        expect(events[0].event_type).toEqual('event-1');\n        expect(events[0].session_id).toEqual(950);\n        expect(events[0].time).toEqual(1000);\n\n        expect(events[1].event_type).toEqual('event-2');\n        expect(events[1].session_id).toEqual(950);\n        expect(events[1].time).toEqual(1050);\n\n        expect(events[2].event_type).toEqual('event-3');\n        expect(events[2].session_id).toEqual(1200);\n        expect(events[2].time).toEqual(1200);\n\n        expect(events[3].event_type).toEqual('event-4');\n        expect(events[3].session_id).toEqual(1350);\n        expect(events[3].time).toEqual(1350);\n\n        expect(events[4].event_type).toEqual('event-5');\n        expect(events[4].session_id).toEqual(1500);\n        expect(events[4].time).toEqual(1700);\n\n        expect(events[5].event_type).toEqual('event-6');\n        expect(events[5].session_id).toEqual(1500);\n        expect(events[5].time).toEqual(1750);\n\n        expect(events[6].event_type).toEqual('event-7');\n        expect(events[6].session_id).toEqual(2000);\n        expect(events[6].time).toEqual(2000);\n\n        expect(events[7].event_type).toEqual('event-8');\n        expect(events[7].session_id).toEqual(2000);\n        expect(events[7].time).toEqual(2200);\n      });\n\n      test('should use explicit session ids and do not track session_start/session_end events', async () => {\n        const send = jest.fn().mockReturnValue(sendResponse);\n        const client = new AmplitudeReactNativeTest(950);\n        const cookieStorage = new core.MemoryStorage<UserSession>();\n        await cookieStorage.set(getStorageKey(API_KEY), { sessionId: 500, lastEventTime: 850, optOut: false });\n\n        await client.init(API_KEY, undefined, clientOptions(send, cookieStorage, false, 1000)).promise;\n\n        void client.track({ event_type: 'event-1', time: 1000 });\n        void client.track({ event_type: 'event-2', time: 1050 });\n\n        client.currentTime = 1100;\n        client.setSessionId(5000);\n\n        void client.track({ event_type: 'event-3', time: 1200 });\n        void client.track({ event_type: 'event-4', time: 1350 });\n\n        client.setActive(1500);\n\n        void client.track({ event_type: 'event-5', time: 1700 });\n\n        client.currentTime = 1720;\n        client.setSessionId(5050);\n\n        client.setBackground(1730);\n\n        void client.track({ event_type: 'event-6', time: 1750 });\n        void client.track({ event_type: 'event-7', time: 2000 });\n\n        client.setActive(2050);\n\n        await client.track({ event_type: 'event-8', time: 2200 }).promise;\n\n        client.setSessionId(6000);\n\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n        const events = send.mock.calls.flatMap((call) => call[1].events as Event[]);\n        expect(events.length).toEqual(8);\n        events.forEach((event, i) => expect(event.event_id).toEqual(i + 1));\n\n        expect(events[0].event_type).toEqual('event-1');\n        expect(events[0].session_id).toEqual(1000);\n        expect(events[0].time).toEqual(1000);\n\n        expect(events[1].event_type).toEqual('event-2');\n        expect(events[1].session_id).toEqual(1000);\n        expect(events[1].time).toEqual(1050);\n\n        expect(events[2].event_type).toEqual('event-3');\n        expect(events[2].session_id).toEqual(5000);\n        expect(events[2].time).toEqual(1200);\n\n        expect(events[3].event_type).toEqual('event-4');\n        expect(events[3].session_id).toEqual(5000);\n        expect(events[3].time).toEqual(1350);\n\n        expect(events[4].event_type).toEqual('event-5');\n        expect(events[4].session_id).toEqual(5000);\n        expect(events[4].time).toEqual(1700);\n\n        expect(events[5].event_type).toEqual('event-6');\n        expect(events[5].session_id).toEqual(5050);\n        expect(events[5].time).toEqual(1750);\n\n        expect(events[6].event_type).toEqual('event-7');\n        expect(events[6].session_id).toEqual(5050);\n        expect(events[6].time).toEqual(2000);\n\n        expect(events[7].event_type).toEqual('event-8');\n        expect(events[7].session_id).toEqual(5050);\n        expect(events[7].time).toEqual(2200);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-react-native/test/react-native-sessions.test.ts",
    "content": "import { AmplitudeReactNative } from '../src/react-native-client';\nimport * as core from '@amplitude/analytics-core';\nimport { Status, UserSession, Event } from '@amplitude/analytics-core';\nimport { isWeb } from '../src/utils/platform';\nimport AsyncStorage from '@react-native-async-storage/async-storage';\n\ndescribe('react-native-session', () => {\n  const API_KEY = 'API_KEY';\n  const attributionConfig = {\n    attribution: {\n      disabled: true,\n    },\n  };\n\n  afterEach(async () => {\n    // clean up cookies (web-only — RN has no `document`)\n    if (typeof document !== 'undefined') {\n      document.cookie = 'AMP_API_KEY=null; expires=-1';\n    }\n    if (!isWeb()) {\n      await AsyncStorage.clear();\n    }\n  });\n\n  class AmplitudeReactNativeTest extends AmplitudeReactNative {\n    currentTime: number;\n\n    constructor(currentTime: number) {\n      super();\n      this.currentTime = currentTime;\n    }\n\n    currentTimeMillis(): number {\n      return this.currentTime;\n    }\n\n    setForeground(timestamp: number) {\n      this.currentTime = timestamp;\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore\n      this.handleAppStateChange('active');\n    }\n\n    setBackground(timestamp: number) {\n      this.currentTime = timestamp;\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore\n      this.handleAppStateChange('background');\n    }\n  }\n\n  const sendResponse = {\n    status: Status.Success,\n    statusCode: 200,\n    body: {\n      eventsIngested: 1,\n      payloadSizeBytes: 1,\n      serverUploadTime: 1,\n    },\n  };\n\n  const clientOptions = (\n    send: any,\n    cookieStorage: core.MemoryStorage<UserSession>,\n    trackingSessionEvents: boolean,\n    sessionId?: number,\n  ) => ({\n    transportProvider: {\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n      send,\n    },\n    cookieStorage,\n    sessionTimeout: 100,\n    sessionId,\n    trackingSessionEvents,\n    ...attributionConfig,\n  });\n\n  const createEvent = (time: number, eventType: string, sessionId?: number): Event => {\n    return {\n      event_type: eventType,\n      time: time,\n      session_id: sessionId,\n      user_id: 'user',\n    };\n  };\n\n  test('close background events should not start new session', async () => {\n    const send = jest.fn().mockReturnValue(sendResponse);\n    const cookieStorage = new core.MemoryStorage<UserSession>();\n\n    const client = new AmplitudeReactNativeTest(950);\n    await client.init(API_KEY, undefined, clientOptions(send, cookieStorage, true)).promise;\n\n    client.track(createEvent(1000, 'event-1'));\n    client.track(createEvent(1050, 'event-2'));\n    await client.flush().promise;\n\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n    const events = send.mock.calls.flatMap((call) => call[1].events as Event[]);\n    expect(events.length).toEqual(3);\n\n    expect(events[0].event_type).toEqual('session_start');\n    expect(events[0].session_id).toEqual(950);\n    expect(events[0].time).toEqual(950);\n\n    expect(events[1].event_type).toEqual('event-1');\n    expect(events[1].session_id).toEqual(950);\n    expect(events[1].time).toEqual(1000);\n\n    expect(events[2].event_type).toEqual('event-2');\n    expect(events[2].session_id).toEqual(950);\n    expect(events[2].time).toEqual(1050);\n  });\n\n  test('distant background events should start new session', async () => {\n    const send = jest.fn().mockReturnValue(sendResponse);\n    const cookieStorage = new core.MemoryStorage<UserSession>();\n\n    const client = new AmplitudeReactNativeTest(950);\n    await client.init(API_KEY, undefined, clientOptions(send, cookieStorage, true)).promise;\n\n    client.track(createEvent(1000, 'event-1'));\n    client.track(createEvent(2000, 'event-2'));\n    await client.flush().promise;\n\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n    const events = send.mock.calls.flatMap((call) => call[1].events as Event[]);\n    expect(events.length).toEqual(5);\n\n    expect(events[0].event_type).toEqual('session_start');\n    expect(events[0].session_id).toEqual(950);\n    expect(events[0].time).toEqual(950);\n\n    expect(events[1].event_type).toEqual('event-1');\n    expect(events[1].session_id).toEqual(950);\n    expect(events[1].time).toEqual(1000);\n\n    expect(events[2].event_type).toEqual('session_end');\n    expect(events[2].session_id).toEqual(950);\n    expect(events[2].time).toEqual(1001);\n\n    expect(events[3].event_type).toEqual('session_start');\n    expect(events[3].session_id).toEqual(2000);\n    expect(events[3].time).toEqual(2000);\n\n    expect(events[4].event_type).toEqual('event-2');\n    expect(events[4].session_id).toEqual(2000);\n    expect(events[4].time).toEqual(2000);\n  });\n\n  test('foreground events should not start new session', async () => {\n    const send = jest.fn().mockReturnValue(sendResponse);\n    const cookieStorage = new core.MemoryStorage<UserSession>();\n\n    const client = new AmplitudeReactNativeTest(950);\n    await client.init(API_KEY, undefined, clientOptions(send, cookieStorage, true)).promise;\n\n    client.setForeground(1000);\n    client.track(createEvent(1050, 'event-1'));\n    client.track(createEvent(2000, 'event-2'));\n    await client.flush().promise;\n\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n    const events = send.mock.calls.flatMap((call) => call[1].events as Event[]);\n    expect(events.length).toEqual(3);\n\n    expect(events[0].event_type).toEqual('session_start');\n    expect(events[0].session_id).toEqual(950);\n    expect(events[0].time).toEqual(950);\n\n    expect(events[1].event_type).toEqual('event-1');\n    expect(events[1].session_id).toEqual(950);\n    expect(events[1].time).toEqual(1050);\n\n    expect(events[2].event_type).toEqual('event-2');\n    expect(events[2].session_id).toEqual(950);\n    expect(events[2].time).toEqual(2000);\n  });\n\n  test('close background and foreground events should not start new session', async () => {\n    const send = jest.fn().mockReturnValue(sendResponse);\n    const cookieStorage = new core.MemoryStorage<UserSession>();\n\n    const client = new AmplitudeReactNativeTest(950);\n    await client.init(API_KEY, undefined, clientOptions(send, cookieStorage, true)).promise;\n\n    client.track(createEvent(1000, 'event-1'));\n    client.setForeground(1050);\n    client.track(createEvent(2000, 'event-2'));\n    await client.flush().promise;\n\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n    const events = send.mock.calls.flatMap((call) => call[1].events as Event[]);\n    expect(events.length).toEqual(3);\n\n    expect(events[0].event_type).toEqual('session_start');\n    expect(events[0].session_id).toEqual(950);\n    expect(events[0].time).toEqual(950);\n\n    expect(events[1].event_type).toEqual('event-1');\n    expect(events[1].session_id).toEqual(950);\n    expect(events[1].time).toEqual(1000);\n\n    expect(events[2].event_type).toEqual('event-2');\n    expect(events[2].session_id).toEqual(950);\n    expect(events[2].time).toEqual(2000);\n  });\n\n  test('distant background and foreground events should start new session', async () => {\n    const send = jest.fn().mockReturnValue(sendResponse);\n    const cookieStorage = new core.MemoryStorage<UserSession>();\n\n    const client = new AmplitudeReactNativeTest(950);\n    await client.init(API_KEY, undefined, clientOptions(send, cookieStorage, true)).promise;\n\n    client.track(createEvent(1000, 'event-1'));\n    client.setForeground(2000);\n    client.track(createEvent(3000, 'event-2'));\n    await client.flush().promise;\n\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n    const events = send.mock.calls.flatMap((call) => call[1].events as Event[]);\n    expect(events.length).toEqual(5);\n\n    expect(events[0].event_type).toEqual('session_start');\n    expect(events[0].session_id).toEqual(950);\n    expect(events[0].time).toEqual(950);\n\n    expect(events[1].event_type).toEqual('event-1');\n    expect(events[1].session_id).toEqual(950);\n    expect(events[1].time).toEqual(1000);\n\n    expect(events[2].event_type).toEqual('session_end');\n    expect(events[2].session_id).toEqual(950);\n    expect(events[2].time).toEqual(1001);\n\n    expect(events[3].event_type).toEqual('session_start');\n    expect(events[3].session_id).toEqual(2000);\n    expect(events[3].time).toEqual(2000);\n\n    expect(events[4].event_type).toEqual('event-2');\n    expect(events[4].session_id).toEqual(2000);\n    expect(events[4].time).toEqual(3000);\n  });\n\n  test('close foreground and background events should not start new session', async () => {\n    const send = jest.fn().mockReturnValue(sendResponse);\n    const cookieStorage = new core.MemoryStorage<UserSession>();\n\n    const client = new AmplitudeReactNativeTest(950);\n    await client.init(API_KEY, undefined, clientOptions(send, cookieStorage, true)).promise;\n\n    client.setForeground(1000);\n    client.track(createEvent(1500, 'event-1'));\n    client.setBackground(2000);\n    client.track(createEvent(2050, 'event-2'));\n    await client.flush().promise;\n\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n    const events = send.mock.calls.flatMap((call) => call[1].events as Event[]);\n    expect(events.length).toEqual(3);\n\n    expect(events[0].event_type).toEqual('session_start');\n    expect(events[0].session_id).toEqual(950);\n    expect(events[0].time).toEqual(950);\n\n    expect(events[1].event_type).toEqual('event-1');\n    expect(events[1].session_id).toEqual(950);\n    expect(events[1].time).toEqual(1500);\n\n    expect(events[2].event_type).toEqual('event-2');\n    expect(events[2].session_id).toEqual(950);\n    expect(events[2].time).toEqual(2050);\n  });\n\n  test('distant foreground and background events should start new session', async () => {\n    const send = jest.fn().mockReturnValue(sendResponse);\n    const cookieStorage = new core.MemoryStorage<UserSession>();\n\n    const client = new AmplitudeReactNativeTest(950);\n    await client.init(API_KEY, undefined, clientOptions(send, cookieStorage, true)).promise;\n\n    client.setForeground(1000);\n    client.track(createEvent(1500, 'event-1'));\n    client.setBackground(2000);\n    client.track(createEvent(3000, 'event-2'));\n    await client.flush().promise;\n\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n    const events = send.mock.calls.flatMap((call) => call[1].events as Event[]);\n    expect(events.length).toEqual(5);\n\n    expect(events[0].event_type).toEqual('session_start');\n    expect(events[0].session_id).toEqual(950);\n    expect(events[0].time).toEqual(950);\n\n    expect(events[1].event_type).toEqual('event-1');\n    expect(events[1].session_id).toEqual(950);\n    expect(events[1].time).toEqual(1500);\n\n    expect(events[2].event_type).toEqual('session_end');\n    expect(events[2].session_id).toEqual(950);\n    expect(events[2].time).toEqual(2001);\n\n    expect(events[3].event_type).toEqual('session_start');\n    expect(events[3].session_id).toEqual(3000);\n    expect(events[3].time).toEqual(3000);\n\n    expect(events[4].event_type).toEqual('event-2');\n    expect(events[4].session_id).toEqual(3000);\n    expect(events[4].time).toEqual(3000);\n  });\n\n  test('session data should be persisted', async () => {\n    const send = jest.fn().mockReturnValue(sendResponse);\n    const cookieStorage = new core.MemoryStorage<UserSession>();\n\n    const client1 = new AmplitudeReactNativeTest(950);\n    await client1.init(API_KEY, undefined, clientOptions(send, cookieStorage, true)).promise;\n\n    client1.setForeground(1000);\n\n    expect(client1.getSessionId()).toEqual(950);\n    expect(client1.config.sessionId).toEqual(950);\n    expect(client1.config.lastEventTime).toEqual(1000);\n    expect(client1.config.lastEventId).toEqual(1);\n\n    client1.track(createEvent(1200, 'event-1'));\n\n    expect(client1.getSessionId()).toEqual(950);\n    expect(client1.config.sessionId).toEqual(950);\n    expect(client1.config.lastEventTime).toEqual(1200);\n    expect(client1.config.lastEventId).toEqual(2);\n\n    const client2 = new AmplitudeReactNativeTest(1250);\n    await client2.init(API_KEY, undefined, clientOptions(send, cookieStorage, true)).promise;\n\n    expect(client2.getSessionId()).toEqual(950);\n    expect(client2.config.sessionId).toEqual(950);\n    expect(client2.config.lastEventTime).toEqual(1250);\n    expect(client1.config.lastEventId).toEqual(2);\n  });\n\n  test('explicit session for event should be preserved and do not update config.lastEventTime', async () => {\n    const send = jest.fn().mockReturnValue(sendResponse);\n    const cookieStorage = new core.MemoryStorage<UserSession>();\n\n    const client = new AmplitudeReactNativeTest(950);\n    await client.init(API_KEY, undefined, clientOptions(send, cookieStorage, true)).promise;\n\n    expect(client.config.lastEventTime).toEqual(950);\n    client.track(createEvent(1000, 'event-1'));\n    expect(client.config.lastEventTime).toEqual(1000);\n    client.track(createEvent(1050, 'event-2', 3000));\n    expect(client.config.lastEventTime).toEqual(1000);\n    client.track(createEvent(1100, 'event-3'));\n    expect(client.config.lastEventTime).toEqual(1100);\n    await client.flush().promise;\n\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n    const events = send.mock.calls.flatMap((call) => call[1].events as Event[]);\n    expect(events.length).toEqual(6);\n\n    expect(events[0].event_type).toEqual('session_start');\n    expect(events[0].session_id).toEqual(950);\n    expect(events[0].time).toEqual(950);\n\n    expect(events[1].event_type).toEqual('event-1');\n    expect(events[1].session_id).toEqual(950);\n    expect(events[1].time).toEqual(1000);\n\n    expect(events[2].event_type).toEqual('event-2');\n    expect(events[2].session_id).toEqual(3000);\n    expect(events[2].time).toEqual(1050);\n\n    expect(events[3].event_type).toEqual('session_end');\n    expect(events[3].session_id).toEqual(950);\n    expect(events[3].time).toEqual(1001);\n\n    expect(events[4].event_type).toEqual('session_start');\n    expect(events[4].session_id).toEqual(1100);\n    expect(events[4].time).toEqual(1100);\n\n    expect(events[5].event_type).toEqual('event-3');\n    expect(events[5].session_id).toEqual(1100);\n    expect(events[5].time).toEqual(1100);\n  });\n\n  test('explicit no session for event should be preserved and do not update config.lastEventTime', async () => {\n    const send = jest.fn().mockReturnValue(sendResponse);\n    const cookieStorage = new core.MemoryStorage<UserSession>();\n\n    const client = new AmplitudeReactNativeTest(950);\n    await client.init(API_KEY, undefined, clientOptions(send, cookieStorage, true)).promise;\n\n    expect(client.config.lastEventTime).toEqual(950);\n    client.track(createEvent(1000, 'event-1'));\n    expect(client.config.lastEventTime).toEqual(1000);\n    client.track(createEvent(1050, 'event-2', -1));\n    expect(client.config.lastEventTime).toEqual(1000);\n    client.track(createEvent(1100, 'event-3'));\n    expect(client.config.lastEventTime).toEqual(1100);\n    await client.flush().promise;\n\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n    const events = send.mock.calls.flatMap((call) => call[1].events as Event[]);\n    expect(events.length).toEqual(6);\n\n    expect(events[0].event_type).toEqual('session_start');\n    expect(events[0].session_id).toEqual(950);\n    expect(events[0].time).toEqual(950);\n\n    expect(events[1].event_type).toEqual('event-1');\n    expect(events[1].session_id).toEqual(950);\n    expect(events[1].time).toEqual(1000);\n\n    expect(events[2].event_type).toEqual('event-2');\n    expect(events[2].session_id).toEqual(-1);\n    expect(events[2].time).toEqual(1050);\n\n    expect(events[3].event_type).toEqual('session_end');\n    expect(events[3].session_id).toEqual(950);\n    expect(events[3].time).toEqual(1001);\n\n    expect(events[4].event_type).toEqual('session_start');\n    expect(events[4].session_id).toEqual(1100);\n    expect(events[4].time).toEqual(1100);\n\n    expect(events[5].event_type).toEqual('event-3');\n    expect(events[5].session_id).toEqual(1100);\n    expect(events[5].time).toEqual(1100);\n  });\n\n  test('explicit session for event (equal to current session) should be preserved and update config.lastEventTime', async () => {\n    const send = jest.fn().mockReturnValue(sendResponse);\n    const cookieStorage = new core.MemoryStorage<UserSession>();\n\n    const client = new AmplitudeReactNativeTest(950);\n    await client.init(API_KEY, undefined, clientOptions(send, cookieStorage, true)).promise;\n\n    expect(client.config.lastEventTime).toEqual(950);\n    client.track(createEvent(1000, 'event-1'));\n    expect(client.config.lastEventTime).toEqual(1000);\n    client.track(createEvent(1050, 'event-2', 950));\n    expect(client.config.lastEventTime).toEqual(1050);\n    client.track(createEvent(1100, 'event-3'));\n    expect(client.config.lastEventTime).toEqual(1100);\n    await client.flush().promise;\n\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n    const events = send.mock.calls.flatMap((call) => call[1].events as Event[]);\n    expect(events.length).toEqual(4);\n\n    expect(events[0].event_type).toEqual('session_start');\n    expect(events[0].session_id).toEqual(950);\n    expect(events[0].time).toEqual(950);\n\n    expect(events[1].event_type).toEqual('event-1');\n    expect(events[1].session_id).toEqual(950);\n    expect(events[1].time).toEqual(1000);\n\n    expect(events[2].event_type).toEqual('event-2');\n    expect(events[2].session_id).toEqual(950);\n    expect(events[2].time).toEqual(1050);\n\n    expect(events[3].event_type).toEqual('event-3');\n    expect(events[3].session_id).toEqual(950);\n    expect(events[3].time).toEqual(1100);\n  });\n\n  describe('explicit global session', () => {\n    test('explicit session should be used', async () => {\n      const send = jest.fn().mockReturnValue(sendResponse);\n      const cookieStorage = new core.MemoryStorage<UserSession>();\n\n      const client = new AmplitudeReactNativeTest(5000);\n      await client.init(API_KEY, undefined, clientOptions(send, cookieStorage, true)).promise;\n\n      client.setSessionId(5000);\n      client.track(createEvent(1000, 'event-1'));\n      client.track(createEvent(1050, 'event-2'));\n      client.currentTime = 1070;\n      client.setSessionId(6000);\n      client.track(createEvent(1100, 'event-3'));\n      await client.flush().promise;\n\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n      const events = send.mock.calls.flatMap((call) => call[1].events as Event[]);\n      expect(events.length).toEqual(6);\n\n      expect(events[0].event_type).toEqual('session_start');\n      expect(events[0].session_id).toEqual(5000);\n      expect(events[0].time).toEqual(5000);\n\n      expect(events[1].event_type).toEqual('event-1');\n      expect(events[1].session_id).toEqual(5000);\n      expect(events[1].time).toEqual(1000);\n\n      expect(events[2].event_type).toEqual('event-2');\n      expect(events[2].session_id).toEqual(5000);\n      expect(events[2].time).toEqual(1050);\n\n      expect(events[3].event_type).toEqual('session_end');\n      expect(events[3].session_id).toEqual(5000);\n      expect(events[3].time).toEqual(1051);\n\n      expect(events[4].event_type).toEqual('session_start');\n      expect(events[4].session_id).toEqual(6000);\n      expect(events[4].time).toEqual(1070);\n\n      expect(events[5].event_type).toEqual('event-3');\n      expect(events[5].session_id).toEqual(6000);\n      expect(events[5].time).toEqual(1100);\n    });\n\n    test('explicit session for event should be preserved', async () => {\n      const send = jest.fn().mockReturnValue(sendResponse);\n      const cookieStorage = new core.MemoryStorage<UserSession>();\n\n      const client = new AmplitudeReactNativeTest(950);\n      await client.init(API_KEY, undefined, clientOptions(send, cookieStorage, true)).promise;\n\n      client.setSessionId(5000);\n      expect(client.config.lastEventTime).toEqual(950);\n      client.track(createEvent(1000, 'event-1'));\n      expect(client.config.lastEventTime).toEqual(1000);\n      client.track(createEvent(1050, 'event-2', 3000));\n      expect(client.config.lastEventTime).toEqual(1000);\n      client.track(createEvent(1100, 'event-3'));\n      expect(client.config.lastEventTime).toEqual(1100);\n      await client.flush().promise;\n\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n      const events = send.mock.calls.flatMap((call) => call[1].events as Event[]);\n      expect(events.length).toEqual(6);\n\n      expect(events[0].event_type).toEqual('session_start');\n      expect(events[0].session_id).toEqual(950);\n      expect(events[0].time).toEqual(950);\n\n      expect(events[1].event_type).toEqual('session_end');\n      expect(events[1].session_id).toEqual(950);\n      expect(events[1].time).toEqual(951);\n\n      expect(events[2].event_type).toEqual('session_start');\n      expect(events[2].session_id).toEqual(5000);\n      expect(events[2].time).toEqual(950);\n\n      expect(events[3].event_type).toEqual('event-1');\n      expect(events[3].session_id).toEqual(5000);\n      expect(events[3].time).toEqual(1000);\n\n      expect(events[4].event_type).toEqual('event-2');\n      expect(events[4].session_id).toEqual(3000);\n      expect(events[4].time).toEqual(1050);\n\n      expect(events[5].event_type).toEqual('event-3');\n      expect(events[5].session_id).toEqual(5000);\n      expect(events[5].time).toEqual(1100);\n    });\n\n    test('explicit no session for event should be preserved', async () => {\n      const send = jest.fn().mockReturnValue(sendResponse);\n      const cookieStorage = new core.MemoryStorage<UserSession>();\n\n      const client = new AmplitudeReactNativeTest(950);\n      await client.init(API_KEY, undefined, clientOptions(send, cookieStorage, true)).promise;\n\n      client.setSessionId(5000);\n      expect(client.config.lastEventTime).toEqual(950);\n      client.track(createEvent(1000, 'event-1'));\n      expect(client.config.lastEventTime).toEqual(1000);\n      client.track(createEvent(1050, 'event-2', -1));\n      expect(client.config.lastEventTime).toEqual(1000);\n      client.track(createEvent(1100, 'event-3'));\n      expect(client.config.lastEventTime).toEqual(1100);\n      await client.flush().promise;\n\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n      const events = send.mock.calls.flatMap((call) => call[1].events as Event[]);\n      expect(events.length).toEqual(6);\n\n      expect(events[0].event_type).toEqual('session_start');\n      expect(events[0].session_id).toEqual(950);\n      expect(events[0].time).toEqual(950);\n\n      expect(events[1].event_type).toEqual('session_end');\n      expect(events[1].session_id).toEqual(950);\n      expect(events[1].time).toEqual(951);\n\n      expect(events[2].event_type).toEqual('session_start');\n      expect(events[2].session_id).toEqual(5000);\n      expect(events[2].time).toEqual(950);\n\n      expect(events[3].event_type).toEqual('event-1');\n      expect(events[3].session_id).toEqual(5000);\n      expect(events[3].time).toEqual(1000);\n\n      expect(events[4].event_type).toEqual('event-2');\n      expect(events[4].session_id).toEqual(-1);\n      expect(events[4].time).toEqual(1050);\n\n      expect(events[5].event_type).toEqual('event-3');\n      expect(events[5].session_id).toEqual(5000);\n      expect(events[5].time).toEqual(1100);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-react-native/test/storage/local-storage.test.ts",
    "content": "import { LocalStorage } from '../../src/storage/local-storage';\n\ndescribe('local-storage', () => {\n  describe('isEnabled', () => {\n    test('should return true', async () => {\n      const localStorage = new LocalStorage();\n      expect(await localStorage.isEnabled()).toBe(true);\n    });\n  });\n\n  describe('get', () => {\n    test('should return undefined if not set', async () => {\n      const localStorage = new LocalStorage();\n      expect(await localStorage.get('1')).toBe(undefined);\n    });\n\n    test('should return object', async () => {\n      const localStorage = new LocalStorage<Record<string, number>>();\n      await localStorage.set('1', { a: 1 });\n      expect(await localStorage.get('1')).toEqual({ a: 1 });\n    });\n\n    test('should return array', async () => {\n      const localStorage = new LocalStorage<number[]>();\n      await localStorage.set('1', [1]);\n      expect(await localStorage.get('1')).toEqual([1]);\n    });\n  });\n\n  describe('set', () => {\n    test('should set value', async () => {\n      const localStorage = new LocalStorage();\n      await localStorage.set('1', 'a');\n      expect(await localStorage.get('1')).toBe('a');\n    });\n  });\n\n  describe('remove', () => {\n    test('should remove value of key', async () => {\n      const localStorage = new LocalStorage();\n      await localStorage.set('1', 'a');\n      await localStorage.set('2', 'b');\n      expect(await localStorage.get('1')).toBe('a');\n      expect(await localStorage.get('2')).toBe('b');\n      await localStorage.remove('1');\n      expect(await localStorage.get('1')).toBe(undefined);\n      expect(await localStorage.get('2')).toBe('b');\n    });\n  });\n\n  describe('reset', () => {\n    test('should remove all values', async () => {\n      const localStorage = new LocalStorage();\n      await localStorage.set('1', 'a');\n      await localStorage.set('2', 'b');\n      expect(await localStorage.get('1')).toBe('a');\n      expect(await localStorage.get('2')).toBe('b');\n      await localStorage.reset();\n      expect(await localStorage.get('1')).toBe(undefined);\n      expect(await localStorage.get('2')).toBe(undefined);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-react-native/test/tsconfig.json",
    "content": "{\n  \"extends\": \"../tsconfig.json\",\n  \"compilerOptions\": {\n    \"types\": [\"jest\", \"node\"]\n  }\n}\n\n"
  },
  {
    "path": "packages/analytics-react-native/test/types.test.ts",
    "content": "import * as amplitude from '../src/index';\n\ndescribe('Type Exports', () => {\n  test('IdentifyOperation should be an enum', () => {\n    expect(amplitude.Types.IdentifyOperation.ADD).toBe('$add');\n  });\n\n  test('SpecialEventType should be an enum', () => {\n    expect(amplitude.Types.SpecialEventType.IDENTIFY).toBe('$identify');\n  });\n\n  test('exported enums are proper enums', () => {\n    const enumTypes = ['RevenueProperty', 'LogLevel', 'ServerZone'];\n    enumTypes.forEach((enumType) => {\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n      expect((amplitude.Types as any)[enumType]).toBeDefined();\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n      expect(typeof (amplitude.Types as any)[enumType]).toBe('object');\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument\n      expect(Object.keys((amplitude.Types as any)[enumType]).length).toBeGreaterThan(0);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/analytics-react-native/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig\",\n  \"exclude\": [\"test\", \"__mocks__\"]\n}\n"
  },
  {
    "path": "packages/analytics-react-native/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"paths\": {\n      \"@amplitude/analytics-react-native\": [\"./src/index\"]\n    },\n    \"allowUnreachableCode\": false,\n    \"allowUnusedLabels\": false,\n    \"esModuleInterop\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"jsx\": \"react\",\n    \"lib\": [\"esnext\", \"dom\"],\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"noImplicitUseStrict\": false,\n    \"noStrictGenericChecks\": false,\n    \"skipLibCheck\": true,\n    \"target\": \"es6\"\n  }\n}\n"
  },
  {
    "path": "packages/analytics-types/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.11.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.11.0...@amplitude/analytics-types@2.11.1) (2026-01-14)\n\n**Note:** Version bump only for package @amplitude/analytics-types\n\n\n\n\n\n# [2.11.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.10.0...@amplitude/analytics-types@2.11.0) (2025-10-23)\n\n\n### Features\n\n* **analytics-browser:** add remote config server url to proxy remote config requests ([#1348](https://github.com/amplitude/Amplitude-TypeScript/issues/1348)) ([461b598](https://github.com/amplitude/Amplitude-TypeScript/commit/461b59876a75af0d97fd639c35ce08f6b0f4c24b))\n\n\n\n\n\n# [2.10.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.9.2...@amplitude/analytics-types@2.10.0) (2025-08-22)\n\n\n### Bug Fixes\n\n* **analtyics-browser): Revert \"feat(analytics-browser:** add page-url-previous-page plugin\" ([#1237](https://github.com/amplitude/Amplitude-TypeScript/issues/1237)) ([dfd7340](https://github.com/amplitude/Amplitude-TypeScript/commit/dfd7340f6519e647a814b3c66913b0c96b0567cf))\n* **analytics-core:** fix typo in Reddit click-id ([#1267](https://github.com/amplitude/Amplitude-TypeScript/issues/1267)) ([43e581d](https://github.com/amplitude/Amplitude-TypeScript/commit/43e581d6465546a38373f758f179eee103172755))\n\n\n### Features\n\n* **analytics-browser:** add page-url-previous-page plugin ([#1110](https://github.com/amplitude/Amplitude-TypeScript/issues/1110)) ([dc053ed](https://github.com/amplitude/Amplitude-TypeScript/commit/dc053ed9f0b6378fce6a49f6a6e4196f3622bd25))\n\n\n\n\n\n## [2.9.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.9.1...@amplitude/analytics-types@2.9.2) (2025-05-02)\n\n**Note:** Version bump only for package @amplitude/analytics-types\n\n\n\n\n\n## [2.9.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.9.0...@amplitude/analytics-types@2.9.1) (2025-03-24)\n\n\n### Bug Fixes\n\n* typo in a docblock ([#954](https://github.com/amplitude/Amplitude-TypeScript/issues/954)) ([71e9f9a](https://github.com/amplitude/Amplitude-TypeScript/commit/71e9f9ac464d9bfa10d47fe052a902cff782888b))\n\n\n\n\n\n# [2.9.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.8.4...@amplitude/analytics-types@2.9.0) (2025-02-28)\n\n\n### Bug Fixes\n\n* ability to send revenue currency to amplitude ([d4f52e7](https://github.com/amplitude/Amplitude-TypeScript/commit/d4f52e74e9840a3361784dfc37ef21125375d02e))\n\n\n### Features\n\n* moves groups to eventoptions type [#970](https://github.com/amplitude/Amplitude-TypeScript/issues/970) ([#972](https://github.com/amplitude/Amplitude-TypeScript/issues/972)) ([f60f71c](https://github.com/amplitude/Amplitude-TypeScript/commit/f60f71c694f6cccccd9d8276a1e04fcc839aa54b))\n\n\n### Reverts\n\n* Revert \"chore(release): publish\" ([d392f62](https://github.com/amplitude/Amplitude-TypeScript/commit/d392f6290b8bb4dd955d6e6f20b00191679489c4))\n\n\n\n\n\n## [2.8.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.8.3...@amplitude/analytics-types@2.8.4) (2024-11-05)\n\n\n### Bug Fixes\n\n* **analytics-types:** allow an array of objects as identity value type ([#914](https://github.com/amplitude/Amplitude-TypeScript/issues/914)) ([a6ddf9f](https://github.com/amplitude/Amplitude-TypeScript/commit/a6ddf9f369fb0240f7fe9ca7040ef36a48a65d41))\n\n\n\n\n\n## [2.8.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.8.2...@amplitude/analytics-types@2.8.3) (2024-10-21)\n\n\n### Bug Fixes\n\n* **analytics-types:** build in next.js ([#900](https://github.com/amplitude/Amplitude-TypeScript/issues/900)) ([63be8c3](https://github.com/amplitude/Amplitude-TypeScript/commit/63be8c3e6b20e772cdca86207c4618423aa547d8))\n\n\n\n\n\n## [2.8.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.8.1...@amplitude/analytics-types@2.8.2) (2024-09-17)\n\n\n### Bug Fixes\n\n* **analytics-types:** update Element in element interactions ([#877](https://github.com/amplitude/Amplitude-TypeScript/issues/877)) ([d501ef6](https://github.com/amplitude/Amplitude-TypeScript/commit/d501ef639b915d5a19adb12c63a0ef55d0263e74))\n\n\n\n\n\n## [2.8.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.8.0...@amplitude/analytics-types@2.8.1) (2024-09-10)\n\n\n### Bug Fixes\n\n* **analytics-types:** update element interactions options ([#862](https://github.com/amplitude/Amplitude-TypeScript/issues/862)) ([fbce96b](https://github.com/amplitude/Amplitude-TypeScript/commit/fbce96b36c68fe7d9543b54c4fd2b9c086bac66a))\n\n\n\n\n\n# [2.8.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.7.0...@amplitude/analytics-types@2.8.0) (2024-08-13)\n\n\n### Features\n\n* support remote config for each autocapture field ([#848](https://github.com/amplitude/Amplitude-TypeScript/issues/848)) ([939d49f](https://github.com/amplitude/Amplitude-TypeScript/commit/939d49f488bda8bbe4fa57cd2a2ab23f75540fc5))\n\n\n\n\n\n# [2.7.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.6.0...@amplitude/analytics-types@2.7.0) (2024-08-02)\n\n\n### Features\n\n* remote config ([#832](https://github.com/amplitude/Amplitude-TypeScript/issues/832)) ([c415f79](https://github.com/amplitude/Amplitude-TypeScript/commit/c415f792a98253ac60885eb1dc7e53b78ca47dcb)), closes [#769](https://github.com/amplitude/Amplitude-TypeScript/issues/769) [#772](https://github.com/amplitude/Amplitude-TypeScript/issues/772) [#780](https://github.com/amplitude/Amplitude-TypeScript/issues/780) [#782](https://github.com/amplitude/Amplitude-TypeScript/issues/782) [#811](https://github.com/amplitude/Amplitude-TypeScript/issues/811) [#828](https://github.com/amplitude/Amplitude-TypeScript/issues/828)\n\n\n\n\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.6.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.5.1...@amplitude/analytics-types@2.6.0) (2024-06-17)\n\n### Bug Fixes\n\n- adding ability to enable debug logs using cookies\n  ([bc36f08](https://github.com/amplitude/Amplitude-TypeScript/commit/bc36f0893b27d96a676120dadd50dd756921de46))\n\n### Features\n\n- **analytics-browser:** consume remote config ([#769](https://github.com/amplitude/Amplitude-TypeScript/issues/769))\n  ([9c4e03c](https://github.com/amplitude/Amplitude-TypeScript/commit/9c4e03c3b3989213ac04410c8b9bf5e78ed393cf))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.5.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.5.0...@amplitude/analytics-types@2.5.1) (2024-05-21)\n\n**Note:** Version bump only for package @amplitude/analytics-types\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.5.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.4.0...@amplitude/analytics-types@2.5.0) (2024-02-23)\n\n### Features\n\n- landing page improvement ([#667](https://github.com/amplitude/Amplitude-TypeScript/issues/667))\n  ([5f365f0](https://github.com/amplitude/Amplitude-TypeScript/commit/5f365f0b933ee890aee1d9ac083576f09b0defc3))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.4.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.3.1...@amplitude/analytics-types@2.4.0) (2024-01-24)\n\n### Features\n\n- add offline mode ([#644](https://github.com/amplitude/Amplitude-TypeScript/issues/644))\n  ([f2cd717](https://github.com/amplitude/Amplitude-TypeScript/commit/f2cd717316eef66b101153cb8eedf37fadc6de0c))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.3.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.3.0...@amplitude/analytics-types@2.3.1) (2023-11-16)\n\n### Bug Fixes\n\n- npm latest tags ([#624](https://github.com/amplitude/Amplitude-TypeScript/issues/624))\n  ([76bf7a4](https://github.com/amplitude/Amplitude-TypeScript/commit/76bf7a4c871375649fac45d549b711ac52c16b0d))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.3.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.2.0...@amplitude/analytics-types@2.3.0) (2023-10-18)\n\n### Features\n\n- add client upload time ([#601](https://github.com/amplitude/Amplitude-TypeScript/issues/601))\n  ([b80d090](https://github.com/amplitude/Amplitude-TypeScript/commit/b80d090c5a70f75b4d3cb653efa1af48ff2fcd34))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.2.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.1.2...@amplitude/analytics-types@2.2.0) (2023-09-18)\n\n### Bug Fixes\n\n- dont modify types in analytics-types\n  ([488832f](https://github.com/amplitude/Amplitude-TypeScript/commit/488832f618c77b81f7ed318aa0af2a92caacae1a))\n- **global user properties:** test, and fix filename\n  ([84bdbef](https://github.com/amplitude/Amplitude-TypeScript/commit/84bdbef3697aba4838ac5cfdddefa85f50420dd7))\n- refactor event.ts\n  ([1a28e0b](https://github.com/amplitude/Amplitude-TypeScript/commit/1a28e0b8a24dc5d2e214cb64d66ce5c2fd6358ba))\n\n### Features\n\n- **global user properties:** add global properties plugin base code without tests\n  ([b539c5e](https://github.com/amplitude/Amplitude-TypeScript/commit/b539c5e3c0cf33de474cda4b31a399308abebbaa))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.1.1...@amplitude/analytics-types@2.1.2) (2023-08-24)\n\n### Bug Fixes\n\n- apply 'core' changes fom 1.x/migrate-legacy-data\n  ([#531](https://github.com/amplitude/Amplitude-TypeScript/issues/531))\n  ([502a080](https://github.com/amplitude/Amplitude-TypeScript/commit/502a080b6eca2bc390b5d8076f24b9137d213f89))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.1.0...@amplitude/analytics-types@2.1.1) (2023-06-30)\n\n### Bug Fixes\n\n- add app_set_id, idfa and idfv support ([#458](https://github.com/amplitude/Amplitude-TypeScript/issues/458))\n  ([00c6cac](https://github.com/amplitude/Amplitude-TypeScript/commit/00c6cac1e30dc73a5c9813f1f44a44ca341ec55b)), closes\n  [#424](https://github.com/amplitude/Amplitude-TypeScript/issues/424)\n- allow plugins to teardown to remove listeners ([#460](https://github.com/amplitude/Amplitude-TypeScript/issues/460))\n  ([c337363](https://github.com/amplitude/Amplitude-TypeScript/commit/c337363c25b0a1285e8df455511516fc0a9bec7e))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.1.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.0.1...@amplitude/analytics-types@2.1.0) (2023-06-22)\n\n### Features\n\n- **storage:** add support for sessionStorage as identityStorage\n  ([#435](https://github.com/amplitude/Amplitude-TypeScript/issues/435))\n  ([8596f6a](https://github.com/amplitude/Amplitude-TypeScript/commit/8596f6a340a32b08a3f55a337723c39c6c57cbf1)), closes\n  [#434](https://github.com/amplitude/Amplitude-TypeScript/issues/434)\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.0.0...@amplitude/analytics-types@2.0.1) (2023-06-21)\n\n### Bug Fixes\n\n- types for plugins to be env specific ([#440](https://github.com/amplitude/Amplitude-TypeScript/issues/440))\n  ([46b297c](https://github.com/amplitude/Amplitude-TypeScript/commit/46b297c11b5d2a83678824b119191fb955df6096))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.0.0-beta.8...@amplitude/analytics-types@2.0.0) (2023-06-14)\n\n**Note:** Version bump only for package @amplitude/analytics-types\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.0.0-beta.7...@amplitude/analytics-types@2.0.0-beta.8) (2023-06-14)\n\n**Note:** Version bump only for package @amplitude/analytics-types\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.0.0-beta.6...@amplitude/analytics-types@2.0.0-beta.7) (2023-06-14)\n\n### Features\n\n- added extendSession() method to Browser Client ([#425](https://github.com/amplitude/Amplitude-TypeScript/issues/425))\n  ([#433](https://github.com/amplitude/Amplitude-TypeScript/issues/433))\n  ([0f5fccc](https://github.com/amplitude/Amplitude-TypeScript/commit/0f5fccc83d3f7f0a80adc4a0807fbd7e71c72e4a))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.0.0-beta.5...@amplitude/analytics-types@2.0.0-beta.6) (2023-06-13)\n\n### Features\n\n- add option for instance name ([#428](https://github.com/amplitude/Amplitude-TypeScript/issues/428))\n  ([1a8ff7d](https://github.com/amplitude/Amplitude-TypeScript/commit/1a8ff7d665d2a936db7cb42f4cde5350379b7cae))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.0.0-beta.4...@amplitude/analytics-types@2.0.0-beta.5) (2023-06-13)\n\n### Features\n\n- log response body from API to logger ([#415](https://github.com/amplitude/Amplitude-TypeScript/issues/415))\n  ([#422](https://github.com/amplitude/Amplitude-TypeScript/issues/422))\n  ([d14b5c0](https://github.com/amplitude/Amplitude-TypeScript/commit/d14b5c00a88f1a61149a61128bb4c4d07ed35836))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.0.0-beta.3...@amplitude/analytics-types@2.0.0-beta.4) (2023-06-08)\n\n### Bug Fixes\n\n- expose server zone enum ([#414](https://github.com/amplitude/Amplitude-TypeScript/issues/414))\n  ([386ebdf](https://github.com/amplitude/Amplitude-TypeScript/commit/386ebdf8658ff4de8fe5f1d30626eb61f3f776e3))\n\n### Features\n\n- simplify init interface ([#416](https://github.com/amplitude/Amplitude-TypeScript/issues/416))\n  ([93752da](https://github.com/amplitude/Amplitude-TypeScript/commit/93752da1e6ed521263c6d5295a37fc5dc7f3de86))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.0.0-beta.2...@amplitude/analytics-types@2.0.0-beta.3) (2023-06-07)\n\n**Note:** Version bump only for package @amplitude/analytics-types\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@2.0.0-beta.1...@amplitude/analytics-types@2.0.0-beta.2) (2023-06-06)\n\n### Bug Fixes\n\n- simplify plugins and eliminate enums ([#407](https://github.com/amplitude/Amplitude-TypeScript/issues/407))\n  ([890ec66](https://github.com/amplitude/Amplitude-TypeScript/commit/890ec6695a8b25cd6988e9f7ae584d4ba2835f67))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.20.0...@amplitude/analytics-types@2.0.0-beta.1) (2023-06-06)\n\n### Features\n\n- allow cross subdomain excluded referrer ([#391](https://github.com/amplitude/Amplitude-TypeScript/issues/391))\n  ([f34f64b](https://github.com/amplitude/Amplitude-TypeScript/commit/f34f64b68bbd328da354afae61ca416d7055a734))\n- simplify browser SDK options and plugin options interface\n  ([#384](https://github.com/amplitude/Amplitude-TypeScript/issues/384))\n  ([b464cfb](https://github.com/amplitude/Amplitude-TypeScript/commit/b464cfb8e09d722bf06ed3c11955f77465a23daf))\n- simplify user identity storage options/configuration\n  ([#390](https://github.com/amplitude/Amplitude-TypeScript/issues/390))\n  ([f8cf0cc](https://github.com/amplitude/Amplitude-TypeScript/commit/f8cf0cca8c2a17738f13878642fa5b37c0070f77))\n- use server side user agent parser ([#382](https://github.com/amplitude/Amplitude-TypeScript/issues/382))\n  ([69bd255](https://github.com/amplitude/Amplitude-TypeScript/commit/69bd2558cb37d027064b6459cc2887c219196973))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.20.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.19.0...@amplitude/analytics-types@0.20.0) (2023-05-04)\n\n### Features\n\n- add attribution tracking for linkedin click id li_fat_id\n  ([ca81f3d](https://github.com/amplitude/Amplitude-TypeScript/commit/ca81f3d75ece7e0e23a1bc1b6889107d53a60a86))\n- add rtd_cid for Reddit campaign tracking/attribution\n  ([784e080](https://github.com/amplitude/Amplitude-TypeScript/commit/784e080aa129c37e850d7f34115beb9770044e4e))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.19.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.18.0...@amplitude/analytics-types@0.19.0) (2023-04-25)\n\n### Features\n\n- persist last event id - to be used on next initialization\n  ([#374](https://github.com/amplitude/Amplitude-TypeScript/issues/374))\n  ([4fd7691](https://github.com/amplitude/Amplitude-TypeScript/commit/4fd76911142969bbc76d6d6e2cb986331201af37))\n- send user_agent with events ([#375](https://github.com/amplitude/Amplitude-TypeScript/issues/375))\n  ([26086b5](https://github.com/amplitude/Amplitude-TypeScript/commit/26086b543d7f0ee2d35e09b43199b5c26ed24e36))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.18.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.17.1...@amplitude/analytics-types@0.18.0) (2023-04-06)\n\n### Features\n\n- update Plugin implementation to allow for dropping events\n  ([#361](https://github.com/amplitude/Amplitude-TypeScript/issues/361))\n  ([3db4d13](https://github.com/amplitude/Amplitude-TypeScript/commit/3db4d1327e87ebcf7a2a8c1d50a62e5c8bc2b418))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.17.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.17.0...@amplitude/analytics-types@0.17.1) (2023-03-31)\n\n### Bug Fixes\n\n- add support for exactOptionalPropertyTypes TypeScript compiler option to BaseEvent\n  ([#362](https://github.com/amplitude/Amplitude-TypeScript/issues/362))\n  ([de6073c](https://github.com/amplitude/Amplitude-TypeScript/commit/de6073c07037bae845d88a4e61a0c739cd55e8c9))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.17.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.17.0-beta.0...@amplitude/analytics-types@0.17.0) (2023-02-27)\n\n**Note:** Version bump only for package @amplitude/analytics-types\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.17.0-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.16.0...@amplitude/analytics-types@0.17.0-beta.0) (2023-02-24)\n\n### Bug Fixes\n\n- consolidate web attribution and page view tracking plugins for marketing analytics use case\n  ([c268997](https://github.com/amplitude/Amplitude-TypeScript/commit/c26899787611daeda7fca288e260bbc42a831130))\n\n### Features\n\n- allow custom page view event type ([#335](https://github.com/amplitude/Amplitude-TypeScript/issues/335))\n  ([0a4f8ed](https://github.com/amplitude/Amplitude-TypeScript/commit/0a4f8ede6e30ec3450ac0a468cf22b9266b0b23c))\n- pass amplitude instance to plugin.setup for enhanced plugin capabilities\n  ([#328](https://github.com/amplitude/Amplitude-TypeScript/issues/328))\n  ([91eeaa0](https://github.com/amplitude/Amplitude-TypeScript/commit/91eeaa0d6bff6bde39538bb54548a938df784462))\n- retrofit web attribution and page view plugins to browser SDK\n  ([#331](https://github.com/amplitude/Amplitude-TypeScript/issues/331))\n  ([ba845d3](https://github.com/amplitude/Amplitude-TypeScript/commit/ba845d3329bd6bebe3b89f24f4f316088c2d62b9))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.16.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.15.0...@amplitude/analytics-types@0.16.0) (2023-02-09)\n\n### Features\n\n- add file download tracker plugin ([#322](https://github.com/amplitude/Amplitude-TypeScript/issues/322))\n  ([1604409](https://github.com/amplitude/Amplitude-TypeScript/commit/16044091135b0983f2edb3931ddf5d2c213be3fc))\n- add named instances for google tag manager use case\n  ([#326](https://github.com/amplitude/Amplitude-TypeScript/issues/326))\n  ([327ef9a](https://github.com/amplitude/Amplitude-TypeScript/commit/327ef9a3d097f892e41814cb02b90453e2d39ed5))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.15.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.15.0-beta.0...@amplitude/analytics-types@0.15.0) (2023-01-31)\n\n**Note:** Version bump only for package @amplitude/analytics-types\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.15.0-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.14.0...@amplitude/analytics-types@0.15.0-beta.0) (2023-01-26)\n\n### Features\n\n- allow opt out of deleting legacy sdk cookies\n  ([c6a82fb](https://github.com/amplitude/Amplitude-TypeScript/commit/c6a82fb52e1301e427116891d1f31208bcfc6548))\n\n# [0.14.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.13.0...@amplitude/analytics-types@0.14.0) (2022-11-28)\n\n### Features\n\n- add utm_id tracking ([#284](https://github.com/amplitude/Amplitude-TypeScript/issues/284))\n  ([f72dcf1](https://github.com/amplitude/Amplitude-TypeScript/commit/f72dcf1788ebc84544aaee1dc41b1d1ba6e4c06e))\n- persisted event identifiers (React Native) ([#280](https://github.com/amplitude/Amplitude-TypeScript/issues/280))\n  ([bd35e73](https://github.com/amplitude/Amplitude-TypeScript/commit/bd35e73a0a08db6609938d27f00f54cbf77ff6c1))\n\n# [0.13.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.12.0...@amplitude/analytics-types@0.13.0) (2022-11-15)\n\n### Features\n\n- auto-tracking session events ([#263](https://github.com/amplitude/Amplitude-TypeScript/issues/263))\n  ([75347c6](https://github.com/amplitude/Amplitude-TypeScript/commit/75347c61984832a6ade3ca9e6abe1bbd0faa6cde))\n\n# [0.12.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.11.0...@amplitude/analytics-types@0.12.0) (2022-11-01)\n\n### Features\n\n- enhance logger with debug information ([#254](https://github.com/amplitude/Amplitude-TypeScript/issues/254))\n  ([5c6175e](https://github.com/amplitude/Amplitude-TypeScript/commit/5c6175e9372cbeea264ddb34c6cc68148063d4f7))\n\n# [0.11.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.10.3...@amplitude/analytics-types@0.11.0) (2022-10-04)\n\n### Features\n\n- add gbraid and wbraid as campaign parameters ([#242](https://github.com/amplitude/Amplitude-TypeScript/issues/242))\n  ([514b7cd](https://github.com/amplitude/Amplitude-TypeScript/commit/514b7cdea9fee0c4e61479b087f7acdfea889350))\n\n## [0.10.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.10.3-beta.0...@amplitude/analytics-types@0.10.3) (2022-09-28)\n\n**Note:** Version bump only for package @amplitude/analytics-types\n\n## [0.10.3-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.10.2...@amplitude/analytics-types@0.10.3-beta.0) (2022-09-26)\n\n**Note:** Version bump only for package @amplitude/analytics-types\n\n## [0.10.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.10.1...@amplitude/analytics-types@0.10.2) (2022-09-26)\n\n### Bug Fixes\n\n- update base config to include additional click ids\n  ([#229](https://github.com/amplitude/Amplitude-TypeScript/issues/229))\n  ([5596931](https://github.com/amplitude/Amplitude-TypeScript/commit/55969310714c43f138e1702ba285fd4dadcdcb44))\n\n## [0.10.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.10.0...@amplitude/analytics-types@0.10.1) (2022-09-22)\n\n**Note:** Version bump only for package @amplitude/analytics-types\n\n# [0.10.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.9.0...@amplitude/analytics-types@0.10.0) (2022-09-16)\n\n### Features\n\n- new marketing analytics plugin ([#213](https://github.com/amplitude/Amplitude-TypeScript/issues/213))\n  ([02ff174](https://github.com/amplitude/Amplitude-TypeScript/commit/02ff174e3361173dbf15ed3acf72e950810e174f))\n\n# [0.9.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.8.1...@amplitude/analytics-types@0.9.0) (2022-09-08)\n\n### Bug Fixes\n\n- allow implicit undefined return for Plugin.setup interface\n  ([#211](https://github.com/amplitude/Amplitude-TypeScript/issues/211))\n  ([e88642e](https://github.com/amplitude/Amplitude-TypeScript/commit/e88642e15adf400387dd8383f1f9751d76d33575))\n\n### Features\n\n- add ingestion_metadata field ([#212](https://github.com/amplitude/Amplitude-TypeScript/issues/212))\n  ([ebe8448](https://github.com/amplitude/Amplitude-TypeScript/commit/ebe8448b23609134f846e18da2e769158ca30bf1))\n\n## [0.8.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.8.0...@amplitude/analytics-types@0.8.1) (2022-08-31)\n\n### Bug Fixes\n\n- removes @types/node from analytics-types package\n  ([#209](https://github.com/amplitude/Amplitude-TypeScript/issues/209))\n  ([a294b73](https://github.com/amplitude/Amplitude-TypeScript/commit/a294b734eb1671568c65e0a4524c46256ab2bdd4))\n- update create instance init interface ([#205](https://github.com/amplitude/Amplitude-TypeScript/issues/205))\n  ([5eb6d5f](https://github.com/amplitude/Amplitude-TypeScript/commit/5eb6d5ffc3877c7241e9c03bb1e782a60531d153))\n\n# [0.8.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.7.0...@amplitude/analytics-types@0.8.0) (2022-08-18)\n\n### Bug Fixes\n\n- removes unused tracking options ([#193](https://github.com/amplitude/Amplitude-TypeScript/issues/193))\n  ([2b57a8e](https://github.com/amplitude/Amplitude-TypeScript/commit/2b57a8e07971312b40c8287e2daddcfb2b55a832))\n\n### Features\n\n- adds create instance api ([#188](https://github.com/amplitude/Amplitude-TypeScript/issues/188))\n  ([050c1d9](https://github.com/amplitude/Amplitude-TypeScript/commit/050c1d96cedbc9e68aedf6fd55e85d2d3dc2fee4))\n\n# [0.7.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.6.2...@amplitude/analytics-types@0.7.0) (2022-08-16)\n\n### Features\n\n- add 'extra' to eventOptions ([#186](https://github.com/amplitude/Amplitude-TypeScript/issues/186))\n  ([32266f4](https://github.com/amplitude/Amplitude-TypeScript/commit/32266f459c180b75236d036bac66c3e7ecd33920))\n\n## [0.6.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.6.1...@amplitude/analytics-types@0.6.2) (2022-08-13)\n\n### Bug Fixes\n\n- correct platform and add adid ([#184](https://github.com/amplitude/Amplitude-TypeScript/issues/184))\n  ([7134a43](https://github.com/amplitude/Amplitude-TypeScript/commit/7134a4398844516f3d868daf82df9cf2e19d3c39))\n\n## [0.6.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.6.0...@amplitude/analytics-types@0.6.1) (2022-07-22)\n\n### Bug Fixes\n\n- allow undefined storage provider ([#146](https://github.com/amplitude/Amplitude-TypeScript/issues/146))\n  ([e704342](https://github.com/amplitude/Amplitude-TypeScript/commit/e704342761c8ad7de3921ba21901ef8d3a768188))\n- removes deprecated uuid from event options ([#154](https://github.com/amplitude/Amplitude-TypeScript/issues/154))\n  ([d940dea](https://github.com/amplitude/Amplitude-TypeScript/commit/d940dea139d022712a9766c1f7f8096c6dc44832))\n- removes saveEvents config ([#147](https://github.com/amplitude/Amplitude-TypeScript/issues/147))\n  ([6fde736](https://github.com/amplitude/Amplitude-TypeScript/commit/6fde736ca8a865462522082a8085673756dbcc7d))\n\n# [0.6.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.5.1...@amplitude/analytics-types@0.6.0) (2022-07-15)\n\n### Features\n\n- react-native with web support ([#126](https://github.com/amplitude/Amplitude-TypeScript/issues/126))\n  ([5384130](https://github.com/amplitude/Amplitude-TypeScript/commit/5384130904d19b4b6cf4b43826efa2b373b47b85))\n\n## [0.5.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.5.0...@amplitude/analytics-types@0.5.1) (2022-06-29)\n\n### Bug Fixes\n\n- remove Awaited type to support older versions of typescript\n  ([#121](https://github.com/amplitude/Amplitude-TypeScript/issues/121))\n  ([23d36f8](https://github.com/amplitude/Amplitude-TypeScript/commit/23d36f8aade258b995132dafd725ada00e400916))\n\n# [0.5.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.4.0...@amplitude/analytics-types@0.5.0) (2022-06-29)\n\n### Features\n\n- add flush() api to send all events immediately ([#125](https://github.com/amplitude/Amplitude-TypeScript/issues/125))\n  ([b5dbcbb](https://github.com/amplitude/Amplitude-TypeScript/commit/b5dbcbb803c76ee5ade7ea85f76fbea50d8bab49))\n- make storage interface async to enable react-native\n  ([#122](https://github.com/amplitude/Amplitude-TypeScript/issues/122))\n  ([42bb39c](https://github.com/amplitude/Amplitude-TypeScript/commit/42bb39c967db015d5899487618d066f3540c9f18))\n\n# [0.4.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.3.0...@amplitude/analytics-types@0.4.0) (2022-06-24)\n\n### Features\n\n- add marketing campaign tracking ([#112](https://github.com/amplitude/Amplitude-TypeScript/issues/112))\n  ([bca73ed](https://github.com/amplitude/Amplitude-TypeScript/commit/bca73ede308ecb1663986a99600657732969d60c))\n\n# [0.3.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.2.1...@amplitude/analytics-types@0.3.0) (2022-06-17)\n\n### Features\n\n- add event bridge components ([#93](https://github.com/amplitude/Amplitude-TypeScript/issues/93))\n  ([64452fc](https://github.com/amplitude/Amplitude-TypeScript/commit/64452fcfeee66e10367220da023137232b2ea112))\n- add Plan option to config ([#117](https://github.com/amplitude/Amplitude-TypeScript/issues/117))\n  ([194d7e6](https://github.com/amplitude/Amplitude-TypeScript/commit/194d7e66af0209cb8155cf6aa0b05a5dcb170f9d))\n- introduce NodeJS package ([#92](https://github.com/amplitude/Amplitude-TypeScript/issues/92))\n  ([476fb44](https://github.com/amplitude/Amplitude-TypeScript/commit/476fb44efcf2dfcd84af6f0ef45e141ad87dac43))\n\n## [0.2.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.2.0...@amplitude/analytics-types@0.2.1) (2022-05-17)\n\n### Bug Fixes\n\n- allow min_id_length option in http payload ([#99](https://github.com/amplitude/Amplitude-TypeScript/issues/99))\n  ([85ec965](https://github.com/amplitude/Amplitude-TypeScript/commit/85ec965d1202f8ee68ca15fbc46015fba76ba3c9))\n- allow option.serverUrl to be used in destination plugin\n  ([#104](https://github.com/amplitude/Amplitude-TypeScript/issues/104))\n  ([f353367](https://github.com/amplitude/Amplitude-TypeScript/commit/f353367b8b264f86b6ea15b15f30385f8d5b8ad5))\n\n# [0.2.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.1.3...@amplitude/analytics-types@0.2.0) (2022-05-12)\n\n### Bug Fixes\n\n- handle 400 error with invalid id lengths ([#81](https://github.com/amplitude/Amplitude-TypeScript/issues/81))\n  ([fd1686f](https://github.com/amplitude/Amplitude-TypeScript/commit/fd1686fa427588d1dcb6d2125cb4d53647c699e8))\n- update plan type to include version id ([#83](https://github.com/amplitude/Amplitude-TypeScript/issues/83))\n  ([e6f05a5](https://github.com/amplitude/Amplitude-TypeScript/commit/e6f05a56ff9fc4810af8d73b6a0940c2900aa35e))\n\n### Features\n\n- parse old cookies and convert to new format ([#85](https://github.com/amplitude/Amplitude-TypeScript/issues/85))\n  ([bda78be](https://github.com/amplitude/Amplitude-TypeScript/commit/bda78be5d2de335e7b1ff6da413b20d3dc751aca))\n\n## [0.1.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.1.2...@amplitude/analytics-types@0.1.3) (2022-04-02)\n\n### Bug Fixes\n\n- move types to analytics-types ([#70](https://github.com/amplitude/Amplitude-TypeScript/issues/70))\n  ([0cb4155](https://github.com/amplitude/Amplitude-TypeScript/commit/0cb41556f2f6be41a7b4838d33ce517289d4d880))\n\n## [0.1.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.1.1...@amplitude/analytics-types@0.1.2) (2022-04-01)\n\n**Note:** Version bump only for package @amplitude/analytics-types\n\n## [0.1.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/analytics-types@0.1.0...@amplitude/analytics-types@0.1.1) (2022-04-01)\n\n### Bug Fixes\n\n- context plugin library version\n  ([8d29c6f](https://github.com/amplitude/Amplitude-TypeScript/commit/8d29c6f4a612510188d920ac243c0bdb116fe02c))\n\n# 0.1.0 (2022-03-31)\n\n### Bug Fixes\n\n- add log message ([#44](https://github.com/amplitude/Amplitude-TypeScript/issues/44))\n  ([92325bc](https://github.com/amplitude/Amplitude-TypeScript/commit/92325bc34cf0143f5f33ec4b0afd3e2d148c3d38))\n- couple plugins with config instance ([#43](https://github.com/amplitude/Amplitude-TypeScript/issues/43))\n  ([abf687a](https://github.com/amplitude/Amplitude-TypeScript/commit/abf687a5d7a395638d8154f65ececc9b5464c366))\n- deserialize json stored in cookies and local storage\n  ([#11](https://github.com/amplitude/Amplitude-TypeScript/issues/11))\n  ([e4346f7](https://github.com/amplitude/Amplitude-TypeScript/commit/e4346f73e020f59ea8fce1af968b7aedd4a73ba0))\n- max retry limit ([#53](https://github.com/amplitude/Amplitude-TypeScript/issues/53))\n  ([fdc0391](https://github.com/amplitude/Amplitude-TypeScript/commit/fdc0391885ac9822f42324d2fd66a8aace001afe))\n- update event results callback parameter ([#29](https://github.com/amplitude/Amplitude-TypeScript/issues/29))\n  ([1acd3c0](https://github.com/amplitude/Amplitude-TypeScript/commit/1acd3c02310e5e9a2b7ab19140f7d6249e9a8452))\n- update logger config to logger provider ([#19](https://github.com/amplitude/Amplitude-TypeScript/issues/19))\n  ([ef89d9f](https://github.com/amplitude/Amplitude-TypeScript/commit/ef89d9f5ffdc9dd88c3652ac36705c79741f53d1))\n\n### Features\n\n- add context plugin ([#13](https://github.com/amplitude/Amplitude-TypeScript/issues/13))\n  ([3d63991](https://github.com/amplitude/Amplitude-TypeScript/commit/3d639917905b25cab0bb012286b8ba487d0f63fb))\n- add EU and batch endpoint support ([#50](https://github.com/amplitude/Amplitude-TypeScript/issues/50))\n  ([af6be60](https://github.com/amplitude/Amplitude-TypeScript/commit/af6be606a0e049657129ddbcbbf83c3dff844443))\n- add identify class and handle identify logging ([#10](https://github.com/amplitude/Amplitude-TypeScript/issues/10))\n  ([9075b1f](https://github.com/amplitude/Amplitude-TypeScript/commit/9075b1f0cf4270dacc05b1b7f4bad36c50e2500b))\n- add partner_id in event options ([#38](https://github.com/amplitude/Amplitude-TypeScript/issues/38))\n  ([880fe57](https://github.com/amplitude/Amplitude-TypeScript/commit/880fe57e5813d8bbe05c2a2a9428bd8a0a1e7d08))\n- add serverZone check while calling getApiHost ([#51](https://github.com/amplitude/Amplitude-TypeScript/issues/51))\n  ([fa3014d](https://github.com/amplitude/Amplitude-TypeScript/commit/fa3014dd730e624b6320769edbdf35350d0edc3d))\n- adds default logger provider ([#14](https://github.com/amplitude/Amplitude-TypeScript/issues/14))\n  ([c5c3d62](https://github.com/amplitude/Amplitude-TypeScript/commit/c5c3d62cf505e3df949a4225e3fa3ae2b56d5a0a))\n- adds session management ([#15](https://github.com/amplitude/Amplitude-TypeScript/issues/15))\n  ([e23a563](https://github.com/amplitude/Amplitude-TypeScript/commit/e23a563c27befa5a3dc31ee55c559359e0159de3))\n- attribution tracking ([#24](https://github.com/amplitude/Amplitude-TypeScript/issues/24))\n  ([c12678e](https://github.com/amplitude/Amplitude-TypeScript/commit/c12678e2aad98d333982ddb1ea4afb67a050bb1d))\n- core timeline implementation ([#3](https://github.com/amplitude/Amplitude-TypeScript/issues/3))\n  ([ac8bc3a](https://github.com/amplitude/Amplitude-TypeScript/commit/ac8bc3a7212c4e13240fca0da1fbca2cdf7d68c2))\n- create browser folder structure ([#5](https://github.com/amplitude/Amplitude-TypeScript/issues/5))\n  ([b1b279d](https://github.com/amplitude/Amplitude-TypeScript/commit/b1b279da067af7a5ca0c797b4f45fc154e3c2ae4))\n- create cookie/events storage providers ([#7](https://github.com/amplitude/Amplitude-TypeScript/issues/7))\n  ([b3d6fab](https://github.com/amplitude/Amplitude-TypeScript/commit/b3d6fab5239d0d14854af9aa8a0c31826447ac48))\n- create transport providers (fetch/xhr/sendBeacon) ([#8](https://github.com/amplitude/Amplitude-TypeScript/issues/8))\n  ([5ad3477](https://github.com/amplitude/Amplitude-TypeScript/commit/5ad3477974c779d696088922f56cae38a89f911c))\n- implement revenue ([#12](https://github.com/amplitude/Amplitude-TypeScript/issues/12))\n  ([dafd10e](https://github.com/amplitude/Amplitude-TypeScript/commit/dafd10e9feb84513bdcd415a965e3216b044206a))\n- implement save events to storage on destination plugin\n  ([#26](https://github.com/amplitude/Amplitude-TypeScript/issues/26))\n  ([5f47677](https://github.com/amplitude/Amplitude-TypeScript/commit/5f476773f0a546db15de45fc40725a138a037c97))\n- implemented destination plugin with retry ([#4](https://github.com/amplitude/Amplitude-TypeScript/issues/4))\n  ([f4f085e](https://github.com/amplitude/Amplitude-TypeScript/commit/f4f085ed343ea3a0571c778f2d40d637573817d7))\n- implements optOut config ([#30](https://github.com/amplitude/Amplitude-TypeScript/issues/30))\n  ([bdf1eb0](https://github.com/amplitude/Amplitude-TypeScript/commit/bdf1eb0c46f535947f66162639dd0b23f154ce28))\n- improve browser config logic ([#56](https://github.com/amplitude/Amplitude-TypeScript/issues/56))\n  ([3054c68](https://github.com/amplitude/Amplitude-TypeScript/commit/3054c6856dd8f8ed49c9326f25c14b672890915b))\n- introduce amplitude sdk promises ([#52](https://github.com/amplitude/Amplitude-TypeScript/issues/52))\n  ([75f79c0](https://github.com/amplitude/Amplitude-TypeScript/commit/75f79c023b136b9148b79514f65515342e9b3d37))\n- set transport api ([#58](https://github.com/amplitude/Amplitude-TypeScript/issues/58))\n  ([addd2dd](https://github.com/amplitude/Amplitude-TypeScript/commit/addd2dd70d25b6977ad7faa044da518bf7b9295b))\n"
  },
  {
    "path": "packages/analytics-types/README.md",
    "content": "# @amplitude/analytics-types\n\nShared types used for Ampilitude Analytics Typescript packages\n"
  },
  {
    "path": "packages/analytics-types/package.json",
    "content": "{\n  \"name\": \"@amplitude/analytics-types\",\n  \"version\": \"2.11.1\",\n  \"description\": \"\",\n  \"author\": \"Amplitude Inc\",\n  \"homepage\": \"https://github.com/amplitude/Amplitude-TypeScript\",\n  \"license\": \"MIT\",\n  \"main\": \"lib/cjs/index.js\",\n  \"module\": \"lib/esm/index.js\",\n  \"types\": \"lib/esm/index.d.ts\",\n  \"sideEffects\": false,\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"tag\": \"latest\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/amplitude/Amplitude-TypeScript.git\"\n  },\n  \"scripts\": {\n    \"build\": \"pnpm build:es5 & pnpm build:esm\",\n    \"build:es5\": \"tsc -p ./tsconfig.es5.json\",\n    \"build:esm\": \"tsc -p ./tsconfig.esm.json\",\n    \"watch\": \"tsc -p ./tsconfig.esm.json --watch\",\n    \"clean\": \"rimraf lib\",\n    \"fix\": \"pnpm fix:eslint & pnpm fix:prettier\",\n    \"fix:eslint\": \"eslint '{src,test}/**/*.ts' --fix\",\n    \"fix:prettier\": \"prettier --write \\\"{src,test}/**/*.ts\\\"\",\n    \"lint\": \"pnpm lint:eslint & pnpm lint:prettier\",\n    \"lint:eslint\": \"eslint '{src,test}/**/*.ts'\",\n    \"lint:prettier\": \"prettier --check \\\"{src,test}/**/*.ts\\\"\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/amplitude/Amplitude-TypeScript/issues\"\n  },\n  \"files\": [\n    \"lib\"\n  ]\n}\n"
  },
  {
    "path": "packages/analytics-types/src/amplitude-promise.ts",
    "content": "export interface AmplitudeReturn<T> {\n  promise: Promise<T>;\n}\n"
  },
  {
    "path": "packages/analytics-types/src/base-event.ts",
    "content": "import { Plan } from './plan';\nimport { IngestionMetadataEventProperty } from './ingestion-metadata';\n\nexport interface BaseEvent extends EventOptions {\n  event_type: string;\n  event_properties?: { [key: string]: any } | undefined;\n  user_properties?: { [key: string]: any } | undefined;\n  group_properties?: { [key: string]: any } | undefined;\n}\n\nexport interface EventOptions {\n  user_id?: string;\n  device_id?: string;\n  time?: number;\n  location_lat?: number;\n  location_lng?: number;\n  app_version?: string;\n  version_name?: string;\n  library?: string;\n  platform?: string;\n  os_name?: string;\n  os_version?: string;\n  device_brand?: string;\n  device_manufacturer?: string;\n  device_model?: string;\n  carrier?: string;\n  country?: string;\n  region?: string;\n  city?: string;\n  dma?: string;\n  idfa?: string;\n  idfv?: string;\n  adid?: string;\n  android_id?: string;\n  language?: string;\n  ip?: string;\n  price?: number;\n  quantity?: number;\n  revenue?: number;\n  productId?: string;\n  revenueType?: string;\n  currency?: string;\n  event_id?: number;\n  session_id?: number;\n  insert_id?: string;\n  plan?: Plan;\n  ingestion_metadata?: IngestionMetadataEventProperty;\n  partner_id?: string;\n  user_agent?: string;\n  android_app_set_id?: string;\n  extra?: { [key: string]: any };\n  groups?: { [key: string]: any } | undefined;\n}\n"
  },
  {
    "path": "packages/analytics-types/src/campaign.ts",
    "content": "import { BaseEvent } from './base-event';\nimport { ReactNativeAttributionOptions } from './config';\nimport { Storage } from './storage';\n\nexport interface UTMParameters {\n  utm_campaign: string | undefined;\n  utm_content: string | undefined;\n  utm_id: string | undefined;\n  utm_medium: string | undefined;\n  utm_source: string | undefined;\n  utm_term: string | undefined;\n}\n\nexport interface ReferrerParameters {\n  referrer: string | undefined;\n  referring_domain: string | undefined;\n}\n\nexport interface ClickIdParameters {\n  dclid: string | undefined;\n  fbclid: string | undefined;\n  gbraid: string | undefined;\n  gclid: string | undefined;\n  ko_click_id: string | undefined;\n  li_fat_id: string | undefined;\n  msclkid: string | undefined;\n  rdt_cid: string | undefined;\n  ttclid: string | undefined;\n  twclid: string | undefined;\n  wbraid: string | undefined;\n}\n\nexport interface Campaign\n  extends Record<string, string | undefined>,\n    UTMParameters,\n    ReferrerParameters,\n    ClickIdParameters {}\n\nexport interface CampaignParser {\n  parse(): Promise<Campaign>;\n}\n\nexport interface CampaignTrackerOptions extends ReactNativeAttributionOptions {\n  storage: Storage<Campaign>;\n  track: CampaignTrackFunction;\n  onNewCampaign: (campaign: Campaign) => unknown;\n}\n\nexport interface CampaignTracker extends CampaignTrackerOptions {\n  send(force: boolean): Promise<void>;\n}\n\nexport type CampaignTrackFunction = (event: BaseEvent) => Promise<unknown>;\n"
  },
  {
    "path": "packages/analytics-types/src/client/core-client.ts",
    "content": "// import { Config } from '../config';\nimport { AmplitudeReturn } from '../amplitude-promise';\nimport { BaseEvent, EventOptions } from '../base-event';\nimport { Identify, Revenue } from '../event';\nimport { Plugin } from '../plugin';\nimport { Result } from '../result';\n\nexport interface CoreClient {\n  /**\n   * Adds a new plugin.\n   *\n   * ```typescript\n   * const plugin = {\n   *   name: 'myPlugin',\n   *   type: 'enrichment',\n   *   setup(config: Config) {\n   *     return;\n   *   },\n   *   execute(context: Event) {\n   *     return context;\n   *   },\n   * };\n   * amplitude.add(plugin);\n   * ```\n   */\n  add(plugin: Plugin): AmplitudeReturn<void>;\n\n  /**\n   * Removes a plugin.\n   *\n   * ```typescript\n   * amplitude.remove('myPlugin');\n   * ```\n   */\n  remove(pluginName: string): AmplitudeReturn<void>;\n\n  /**\n   * Tracks user-defined event, with specified type, optional event properties and optional overwrites.\n   *\n   * ```typescript\n   * // event tracking with event type only\n   * track('Page Load');\n   *\n   * // event tracking with event type and additional event properties\n   * track('Page Load', { loadTime: 1000 });\n   *\n   * // event tracking with event type, additional event properties, and overwritten event options\n   * track('Page Load', { loadTime: 1000 }, { sessionId: -1 });\n   *\n   * // alternatively, this tracking method is awaitable\n   * const result = await track('Page Load').promise;\n   * console.log(result.event); // {...}\n   * console.log(result.code); // 200\n   * console.log(result.message); // \"Event tracked successfully\"\n   * ```\n   */\n  track(\n    eventInput: BaseEvent | string,\n    eventProperties?: Record<string, any>,\n    eventOptions?: EventOptions,\n  ): AmplitudeReturn<Result>;\n\n  /**\n   * Alias for track()\n   */\n  logEvent(\n    eventInput: BaseEvent | string,\n    eventProperties?: Record<string, any>,\n    eventOptions?: EventOptions,\n  ): AmplitudeReturn<Result>;\n\n  /**\n   * Sends an identify event containing user property operations\n   *\n   * ```typescript\n   * const id = new Identify();\n   * id.set('colors', ['rose', 'gold']);\n   * identify(id);\n   *\n   * // alternatively, this tracking method is awaitable\n   * const result = await identify(id).promise;\n   * console.log(result.event); // {...}\n   * console.log(result.code); // 200\n   * console.log(result.message); // \"Event tracked successfully\"\n   * ```\n   */\n  identify(identify: Identify, eventOptions?: EventOptions): AmplitudeReturn<Result>;\n\n  /**\n   * Sends a group identify event containing group property operations.\n   *\n   * ```typescript\n   * const id = new Identify();\n   * id.set('skills', ['js', 'ts']);\n   * const groupType = 'org';\n   * const groupName = 'engineering';\n   * groupIdentify(groupType, groupName, id);\n   *\n   * // alternatively, this tracking method is awaitable\n   * const result = await groupIdentify(groupType, groupName, id).promise;\n   * console.log(result.event); // {...}\n   * console.log(result.code); // 200\n   * console.log(result.message); // \"Event tracked successfully\"\n   * ```\n   */\n  groupIdentify(\n    groupType: string,\n    groupName: string | string[],\n    identify: Identify,\n    eventOptions?: EventOptions,\n  ): AmplitudeReturn<Result>;\n\n  /**\n   * Assigns a user to group\n   *\n   * ```typescript\n   * const groupType = 'orgId';\n   * const groupName = '15';\n   * setGroup(groupType, groupName, { user_id: '12345' })\n   * ```\n   */\n  setGroup(groupType: string, groupName: string | string[], eventOptions?: EventOptions): AmplitudeReturn<Result>;\n\n  /**\n   * Sends a revenue event containing revenue property operations.\n   *\n   * ```typescript\n   * const rev = new Revenue();\n   * rev.setRevenue(100);\n   * revenue(rev);\n   *\n   * // alternatively, this tracking method is awaitable\n   * const result = await revenue(rev).promise;\n   * console.log(result.event); // {...}\n   * console.log(result.code); // 200\n   * console.log(result.message); // \"Event tracked successfully\"\n   * ```\n   */\n  revenue(revenue: Revenue, eventOptions?: EventOptions): AmplitudeReturn<Result>;\n\n  /**\n   * Sets a new optOut config value. This toggles event tracking on/off.\n   *\n   *```typescript\n   * // Stops tracking\n   * setOptOut(true);\n   *\n   * // Starts/resumes tracking\n   * setOptOut(false);\n   * ```\n   */\n  setOptOut(optOut: boolean): void;\n\n  /**\n   * Flush all unsent events.\n   *\n   *```typescript\n   * flush();\n   * ```\n   */\n  flush(): AmplitudeReturn<void>;\n}\n"
  },
  {
    "path": "packages/analytics-types/src/client/index.ts",
    "content": "export { BrowserClient, ReactNativeClient } from './web-client';\nexport { NodeClient } from './node-client';\nexport { CoreClient } from './core-client';\n"
  },
  {
    "path": "packages/analytics-types/src/client/node-client.ts",
    "content": "import { AmplitudeReturn } from '../amplitude-promise';\nimport { NodeConfig, NodeOptions } from '../config';\nimport { CoreClient } from './core-client';\nimport { Plugin } from '../plugin';\n\nexport interface NodeClient extends CoreClient {\n  /**\n   * Initializes the Amplitude SDK with your apiKey, optional configurations.\n   * This method must be called before any other operations.\n   *\n   * ```typescript\n   * await init(API_KEY, options).promise;\n   * ```\n   */\n  init(apiKey: string, options?: NodeOptions): AmplitudeReturn<void>;\n\n  /**\n   * Adds a new plugin.\n   *\n   * ```typescript\n   * const plugin = {\n   *   name: 'my-plugin',\n   *   type: 'enrichment',\n   *   async setup(config: NodeConfig, amplitude: NodeClient) {\n   *     return;\n   *   },\n   *   async execute(event: Event) {\n   *     return event;\n   *   },\n   * };\n   * amplitude.add(plugin);\n   * ```\n   */\n  add(plugin: Plugin<NodeClient, NodeConfig>): AmplitudeReturn<void>;\n}\n"
  },
  {
    "path": "packages/analytics-types/src/client/web-client.ts",
    "content": "import { AmplitudeReturn } from '../amplitude-promise';\nimport { BrowserConfig, BrowserOptions, ReactNativeConfig, ReactNativeOptions } from '../config';\nimport { TransportType } from '../transport';\nimport { CoreClient } from './core-client';\nimport { Plugin } from '../plugin';\n\ninterface Client extends CoreClient {\n  /**\n   * Returns current user ID.\n   *\n   * ```typescript\n   * const userId = getUserId();\n   * ```\n   */\n  getUserId(): string | undefined;\n\n  /**\n   * Sets a new user ID.\n   *\n   * ```typescript\n   * setUserId('userId');\n   * ```\n   */\n  setUserId(userId: string | undefined): void;\n\n  /**\n   * Returns current device ID.\n   *\n   * ```typescript\n   * const deviceId = getDeviceId();\n   * ```\n   */\n  getDeviceId(): string | undefined;\n\n  /**\n   * Sets a new device ID.\n   * When setting a custom device ID, make sure the value is sufficiently unique.\n   * A uuid is recommended.\n   *\n   * ```typescript\n   * setDeviceId('deviceId');\n   * ```\n   */\n  setDeviceId(deviceId: string): void;\n\n  /**\n   * Returns current session ID.\n   *\n   * ```typescript\n   * const sessionId = getSessionId();\n   * ```\n   */\n  getSessionId(): number | undefined;\n\n  /**\n   * Sets a new session ID.\n   * When setting a custom session ID, make sure the value is in milliseconds since epoch (Unix Timestamp).\n   *\n   * ```typescript\n   * setSessionId(Date.now());\n   * ```\n   */\n  setSessionId(sessionId: number): void;\n\n  /**\n   * Extends the current session (advanced)\n   *\n   * Normally sessions are extended automatically by track()'ing events. If you want to extend the session without\n   * tracking and event, this will set the last user interaction to the current time.\n   *\n   * ```typescript\n   * extendSession();\n   * ```\n   */\n  extendSession(): void;\n\n  /**\n   * Anonymizes users after they log out, by:\n   *\n   * * setting userId to undefined\n   * * setting deviceId to a new uuid value\n   *\n   * With an undefined userId and a completely new deviceId, the current user would appear as a brand new user in dashboard.\n   *\n   * ```typescript\n   * import { reset } from '@amplitude/analytics-browser';\n   *\n   * reset();\n   * ```\n   */\n  reset(): void;\n}\n\nexport interface BrowserClient extends Client {\n  /**\n   * Initializes the Amplitude SDK with your apiKey, optional configurations.\n   * This method must be called before any other operations.\n   *\n   * ```typescript\n   * await init(API_KEY, options).promise;\n   * ```\n   */\n  init(apiKey: string, options?: BrowserOptions): AmplitudeReturn<void>;\n  init(apiKey: string, userId?: string, options?: BrowserOptions): AmplitudeReturn<void>;\n\n  /**\n   * Sets the network transport type for events.\n   *\n   * ```typescript\n   * // Use Fetch API\n   * setTransport('fetch');\n   *\n   * // Use XMLHttpRequest API\n   * setTransport('xhr');\n   *\n   * // Use navigator.sendBeacon API\n   * setTransport('beacon');\n   * ```\n   */\n  setTransport(transport: TransportType): void;\n\n  /**\n   * Adds a new plugin.\n   *\n   * ```typescript\n   * const plugin = {\n   *   name: 'my-plugin',\n   *   type: 'enrichment',\n   *   async setup(config: BrowserConfig, amplitude: BrowserClient) {\n   *     return;\n   *   },\n   *   async execute(event: Event) {\n   *     return event;\n   *   },\n   * };\n   * amplitude.add(plugin);\n   * ```\n   */\n  add(plugin: Plugin<BrowserClient, BrowserConfig>): AmplitudeReturn<void>;\n}\n\nexport interface ReactNativeClient extends Client {\n  /**\n   * Initializes the Amplitude SDK with your apiKey, optional configurations.\n   * This method must be called before any other operations.\n   *\n   * ```typescript\n   * await init(API_KEY, options).promise;\n   * ```\n   */\n  init(apiKey: string, userId?: string, options?: ReactNativeOptions): AmplitudeReturn<void>;\n\n  /**\n   * Adds a new plugin.\n   *\n   * ```typescript\n   * const plugin = {\n   *   name: 'my-plugin',\n   *   type: 'enrichment',\n   *   async setup(config: ReactNativeConfig, amplitude: ReactNativeClient) {\n   *     return;\n   *   },\n   *   async execute(event: Event) {\n   *     return event;\n   *   },\n   * };\n   * amplitude.add(plugin);\n   * ```\n   */\n  add(plugin: Plugin<ReactNativeClient, ReactNativeConfig>): AmplitudeReturn<void>;\n}\n"
  },
  {
    "path": "packages/analytics-types/src/config/browser.ts",
    "content": "import { UserSession } from '../user-session';\nimport { IdentityStorageType, Storage } from '../storage';\nimport { Transport } from '../transport';\nimport { Config } from './core';\nimport { PageTrackingOptions } from '../page-view-tracking';\nimport { ElementInteractionsOptions } from '../element-interactions';\n\nexport interface BrowserConfig extends ExternalBrowserConfig, InternalBrowserConfig {}\n\nexport interface ExternalBrowserConfig extends Config {\n  /**\n   * An app version for events tracked. This can be the version of your application.\n   * @defaultValue `undefined`\n   */\n  appVersion?: string;\n  /**\n   * @deprecated This property is deprecated and will be removed in future versions. Please migrate to using `autocapture` instead.\n   * The default event tracking configuration.\n   * See {@link https://www.docs.developers.amplitude.com/data/sdks/browser-2/#tracking-default-events}.\n   * @defaultValue `true`\n   */\n  defaultTracking?: boolean | DefaultTrackingOptions;\n  /**\n   * The configurations for auto-captured events.\n   * See {@link https://www.docs.developers.amplitude.com/data/sdks/browser-2/autocapture/}.\n   */\n  autocapture?: boolean | AutocaptureOptions;\n  /**\n   * The identifier for the device running your application.\n   * @defaultValue `UUID()`\n   */\n  deviceId?: string;\n  /**\n   * Configuration for cookie.\n   */\n  cookieOptions?: CookieOptions;\n  /**\n   * The storage for user identify.\n   * @defaultValue `\"cookie\"`\n   */\n  identityStorage?: IdentityStorageType;\n  /**\n   * The partner identifier.\n   * Amplitude requires the customer who built an event ingestion integration to add the partner identifier to partner_id.\n   * @defaultValue `undefined`\n   */\n  partnerId?: string;\n  /**\n   * The custom Session ID for the current session.\n   * @defaultValue `timestamp`\n   */\n  sessionId?: number;\n  /**\n   * The period of inactivity from the last tracked event before a session expires in milliseconds.\n   * @defaultValue `1,800,000` (30 minutes)\n   */\n  sessionTimeout: number;\n  /**\n   * The configurations for tracking additional properties.\n   * See {@link https://www.docs.developers.amplitude.com/data/sdks/browser-2/#optional-tracking}.\n   */\n  trackingOptions: TrackingOptions;\n  /**\n   * Network transport mechanism used to send events.\n   * @defaultValue `\"fetch\"`\n   */\n  transport?: 'fetch' | 'xhr' | 'beacon';\n  /**\n   * The identifier for the user being tracked.\n   * @defaultValue `undefined`\n   */\n  userId?: string;\n  /**\n   * User's Nth instance of performing a default Page Viewed event within a session.\n   * Used for landing page analysis.\n   */\n  pageCounter?: number;\n  /**\n   * Whether to fetch remote configuration.\n   * @defaultValue `false`\n   */\n  fetchRemoteConfig?: boolean;\n  /**\n   * Custom server URL for remote configuration requests. If not provided, defaults to the standard\n   * Amplitude remote config endpoint based on serverZone (US or EU).\n   * Use this to proxy remote config requests through your own server.\n   * @defaultValue `undefined` (uses standard Amplitude remote config endpoint)\n   */\n  remoteConfigServerUrl?: string;\n}\n\ninterface InternalBrowserConfig {\n  cookieStorage: Storage<UserSession>;\n  lastEventTime?: number;\n  lastEventId?: number;\n  transportProvider: Transport;\n}\n\n/**\n * @deprecated This interface is deprecated and will be removed in future versions. Please migrate to using `AutocaptureOptions` instead.\n */\nexport interface DefaultTrackingOptions {\n  /**\n   * Enables/disables marketing attribution tracking or config with detailed attribution options.\n   * @defaultValue `true`\n   */\n  attribution?: boolean | AttributionOptions;\n  /**\n   * Enables/disables form downloads tracking.\n   * @defaultValue `true`\n   */\n  fileDownloads?: boolean;\n  /**\n   * Enables/disables form interaction tracking.\n   * @defaultValue `true`\n   */\n  formInteractions?: boolean;\n  /**\n   * Enables/disables default page view tracking.\n   * @defaultValue `true`\n   */\n  pageViews?: boolean | PageTrackingOptions;\n  /**\n   * Enables/disables session tracking.\n   * @defaultValue `true`\n   */\n  sessions?: boolean;\n}\n\nexport interface AutocaptureOptions {\n  /**\n   * Enables/disables marketing attribution tracking or config with detailed attribution options.\n   * @defaultValue `true`\n   */\n  attribution?: boolean | AttributionOptions;\n  /**\n   * Enables/disables form downloads tracking.\n   * @defaultValue `true`\n   */\n  fileDownloads?: boolean;\n  /**\n   * Enables/disables form interaction tracking.\n   * @defaultValue `true`\n   */\n  formInteractions?: boolean;\n  /**\n   * Enables/disables default page view tracking.\n   * @defaultValue `true`\n   */\n  pageViews?: boolean | PageTrackingOptions;\n  /**\n   * Enables/disables session tracking.\n   * @defaultValue `true`\n   */\n  sessions?: boolean;\n  /**\n   * Enables/disables user interactions tracking.\n   * @defaultValue `false`\n   */\n  elementInteractions?: boolean | ElementInteractionsOptions;\n}\n\nexport interface TrackingOptions {\n  /**\n   * Enables/disables ip address tracking.\n   * @defaultValue `true`\n   */\n  ipAddress?: boolean;\n  /**\n   * Enables/disables language tracking.\n   * @defaultValue `true`\n   */\n  language?: boolean;\n  /**\n   * Enables/disables platform tracking.\n   * @defaultValue `true`\n   */\n  platform?: boolean;\n}\n\nexport interface AttributionOptions {\n  /**\n   * The rules to determine which referrers are excluded from being tracked as traffic source.\n   * @defaultValue `[/your-domain\\.com$/]`\n   */\n  excludeReferrers?: (string | RegExp)[];\n  /**\n   * The value to represent undefined/no initial campaign parameter for first-touch attribution.\n   * @defaultValue `\"EMPTY\"`\n   */\n  initialEmptyValue?: string;\n  /**\n   * The flag of if Amplitude to start a new session if any campaign parameter changes.\n   * @defaultValue `false`\n   */\n  resetSessionOnNewCampaign?: boolean;\n}\n\nexport interface CookieOptions {\n  /**\n   * The domain property of cookies created.\n   * @defaultValue `Your top level domain`\n   */\n  domain?: string;\n  /**\n   * The expiration of cookies created in days.\n   * @defaultValue `365`\n   */\n  expiration?: number;\n  /**\n   * How cookies are sent with cross-site requests.\n   * @defaultValue `\"Lax\"`\n   */\n  sameSite?: 'Strict' | 'Lax' | 'None';\n  /**\n   * The flag of if send cookies over secure protocols.\n   * @defaultValue `false`\n   */\n  secure?: boolean;\n  /**\n   * The flag of if upgrade the cookies created by maintenance Browser SDK.\n   * @defaultValue `true`\n   */\n  upgrade?: boolean;\n}\n\ntype HiddenOptions = 'apiKey' | 'transportProvider' | 'requestMetadata';\n\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface BrowserOptions extends Omit<Partial<ExternalBrowserConfig>, HiddenOptions> {}\n\nexport type BrowserRemoteConfig = {\n  browserSDK: {\n    autocapture?: AutocaptureOptions | boolean;\n  };\n};\n"
  },
  {
    "path": "packages/analytics-types/src/config/core.ts",
    "content": "import { Event } from '../event';\nimport { IngestionMetadata } from '../ingestion-metadata';\nimport { Plan } from '../plan';\nimport { ServerZoneType } from '../server-zone';\nimport { Storage } from '../storage';\nimport { Transport } from '../transport';\nimport { Logger, LogLevel } from '../logger';\nimport { OfflineDisabled } from '../offline';\n\nexport interface Config {\n  /**\n   * Your Amplitude Project API key.\n   */\n  apiKey: string;\n  /**\n   * The interval of uploading events to Amplitude in milliseconds.\n   */\n  flushIntervalMillis: number;\n  /**\n   * The maximum number of retries for failed upload attempts. This is only applicable to retryable errors.\n   */\n  flushMaxRetries: number;\n  /**\n   * The maximum number of events that are batched in a single upload attempt.\n   */\n  flushQueueSize: number;\n  /**\n   * The instance name. For tracking events to multiple Amplitude projects in your application.\n   */\n  instanceName?: string;\n  /**\n   * Level of logs to be printed in the developer console.\n   * Valid values are `LogLevel.None`, `LogLevel.Error`, `LogLevel.Warn`, `LogLevel.Verbose`,  `LogLevel.Debug`\n   */\n  logLevel: LogLevel;\n  /**\n   * A custom Logger class to emit log messages to desired destination.\n   */\n  loggerProvider: Logger;\n  /**\n   * The minimum length for the value of userId and deviceId properties.\n   */\n  minIdLength?: number;\n  /**\n   * Whether the SDK is connected to network.\n   */\n  offline?: boolean | typeof OfflineDisabled;\n  /**\n   *  The flag to opt this device out of Amplitude tracking.\n   *  If this flag is set, no additional information will be stored for the user.\n   */\n  optOut: boolean;\n  /**\n   * Tracking plan properties.\n   * Amplitude internal use.\n   */\n  plan?: Plan;\n  /**\n   * Ingestion metadata.\n   * Amplitude internal use.\n   */\n  ingestionMetadata?: IngestionMetadata;\n  /**\n   * The URL where events are upload to.\n   */\n  serverUrl?: string;\n  /**\n   * The Amplitude server zone.\n   * Set this to EU for Amplitude projects created in EU data center.\n   */\n  serverZone?: ServerZoneType;\n  /**\n   *  The storage provider to persist unsent events.\n   */\n  storageProvider?: Storage<Event[]>;\n  /**\n   * A customer Transport Class for sending data to a server.\n   */\n  transportProvider: Transport;\n  /**\n   * The flag of whether to upload events to Batch API instead of the default HTTP V2 API.\n   */\n  useBatch: boolean;\n  /**\n   * Metrics of the SDK.\n   */\n  requestMetadata?: RequestMetadata;\n}\n\nexport interface RequestMetadata {\n  sdk: {\n    metrics: {\n      histogram: HistogramOptions;\n    };\n  };\n\n  recordHistogram<T extends HistogramKey>(key: T, value: HistogramOptions[T]): void;\n}\n\nexport interface HistogramOptions {\n  remote_config_fetch_time_IDB?: number;\n  remote_config_fetch_time_API_success?: number;\n  remote_config_fetch_time_API_fail?: number;\n}\n\nexport type HistogramKey = keyof HistogramOptions;\n\nexport interface Options extends Partial<Config> {\n  apiKey: string;\n  transportProvider: Transport;\n}\n"
  },
  {
    "path": "packages/analytics-types/src/config/index.ts",
    "content": "export { Config, Options, RequestMetadata, HistogramOptions, HistogramKey } from './core';\nexport {\n  BrowserConfig,\n  DefaultTrackingOptions,\n  TrackingOptions,\n  AttributionOptions,\n  BrowserOptions,\n  AutocaptureOptions,\n  BrowserRemoteConfig,\n} from './browser';\nexport { NodeConfig, NodeOptions } from './node';\nexport {\n  ReactNativeAttributionOptions,\n  ReactNativeConfig,\n  ReactNativeTrackingOptions,\n  ReactNativeOptions,\n} from './react-native';\n"
  },
  {
    "path": "packages/analytics-types/src/config/node.ts",
    "content": "import { Config } from './core';\n\nexport type NodeConfig = Config;\n\nexport type NodeOptions = Omit<Partial<NodeConfig>, 'apiKey'>;\n"
  },
  {
    "path": "packages/analytics-types/src/config/react-native.ts",
    "content": "import { UserSession } from '../user-session';\nimport { Storage } from '../storage';\nimport { TransportType } from '../transport';\nimport { Config } from './core';\n\nexport interface ReactNativeConfig extends Config {\n  attribution?: ReactNativeAttributionOptions;\n  appVersion?: string;\n  deviceId?: string;\n  cookieExpiration: number;\n  cookieSameSite: string;\n  cookieSecure: boolean;\n  cookieStorage: Storage<UserSession>;\n  cookieUpgrade: boolean;\n  disableCookies: boolean;\n  domain: string;\n  lastEventTime?: number;\n  lastEventId?: number;\n  partnerId?: string;\n  sessionId?: number;\n  sessionTimeout: number;\n  trackingOptions: ReactNativeTrackingOptions;\n  userId?: string;\n  trackingSessionEvents?: boolean;\n  migrateLegacyData?: boolean;\n}\n\nexport interface ReactNativeTrackingOptions {\n  adid?: boolean;\n  carrier?: boolean;\n  deviceManufacturer?: boolean;\n  deviceModel?: boolean;\n  ipAddress?: boolean;\n  language?: boolean;\n  osName?: boolean;\n  osVersion?: boolean;\n  platform?: boolean;\n  appSetId?: boolean;\n  idfv?: boolean;\n}\n\nexport interface ReactNativeAttributionOptions {\n  disabled?: boolean;\n  excludeReferrers?: string[];\n  initialEmptyValue?: string;\n  trackNewCampaigns?: boolean;\n  trackPageViews?: boolean;\n}\n\ntype HiddenOptions = 'apiKey' | 'lastEventId';\n\nexport interface ReactNativeOptions extends Omit<Partial<ReactNativeConfig>, HiddenOptions> {\n  transport?: TransportType;\n}\n"
  },
  {
    "path": "packages/analytics-types/src/destination-context.ts",
    "content": "import { Event } from './event';\nimport { EventCallback } from './event-callback';\n\nexport interface DestinationContext {\n  event: Event;\n  attempts: number;\n  callback: EventCallback;\n  timeout: number;\n}\n"
  },
  {
    "path": "packages/analytics-types/src/element-interactions.ts",
    "content": "import { Logger } from './logger';\n\nexport type ActionType = 'click' | 'change';\n\n/**\n * Default CSS selectors to define which elements on the page to track.\n * Extend this list to include additional elements to track. For example:\n * ```\n * autocapturePlugin({\n *    cssSelectorAllowlist: [...DEFAULT_CSS_SELECTOR_ALLOWLIST, \".my-class\"],\n * })\n * ```\n */\nexport const DEFAULT_CSS_SELECTOR_ALLOWLIST = [\n  'a',\n  'button',\n  'input',\n  'select',\n  'textarea',\n  'label',\n  'video',\n  'audio',\n  '[contenteditable=\"true\" i]',\n  '[data-amp-default-track]',\n  '.amp-default-track',\n];\n\n/**\n * Default prefix to allow the plugin to capture data attributes as an event property.\n */\nexport const DEFAULT_DATA_ATTRIBUTE_PREFIX = 'data-amp-track-';\n\n/**\n * Default list of elements on the page should be tracked when the page changes.\n */\nexport const DEFAULT_ACTION_CLICK_ALLOWLIST = ['div', 'span', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'];\n\nexport interface ElementInteractionsOptions {\n  /**\n   * List of CSS selectors to allow auto tracking on.\n   * When provided, allow elements matching any selector to be tracked.\n   * Default is ['a', 'button', 'input', 'select', 'textarea', 'label', '[data-amp-default-track]', '.amp-default-track'].\n   */\n  cssSelectorAllowlist?: string[];\n\n  /**\n   * List of page URLs to allow auto tracking on.\n   * When provided, only allow tracking on these URLs.\n   * Both full URLs and regex are supported.\n   */\n  pageUrlAllowlist?: (string | RegExp)[];\n\n  /**\n   * Function to determine whether an event should be tracked.\n   * When provided, this function overwrites all other allowlists and configurations.\n   * If the function returns true, the event will be tracked.\n   * If the function returns false, the event will not be tracked.\n   * @param actionType - The type of action that triggered the event.\n   * @param element - The [Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) that triggered the event.\n   */\n  shouldTrackEventResolver?: (actionType: ActionType, element: DomElement) => boolean;\n\n  /**\n   * Prefix for data attributes to allow auto collecting.\n   * Default is 'data-amp-track-'.\n   */\n  dataAttributePrefix?: string;\n\n  /**\n   * Options for integrating visual tagging selector.\n   */\n  visualTaggingOptions?: {\n    enabled?: boolean;\n    messenger?: Messenger;\n  };\n\n  /**\n   * Debounce time in milliseconds for tracking events.\n   * This is used to detect rage clicks.\n   */\n  debounceTime?: number;\n\n  /**\n   * CSS selector allowlist for tracking clicks that result in a DOM change/navigation on elements not already allowed by the cssSelectorAllowlist\n   */\n  actionClickAllowlist?: string[];\n}\n\nexport interface Messenger {\n  logger?: Logger;\n  setup: () => void;\n}\n\n// DomElement is [Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) if the dom library is included in tsconfig.json\n// and never if it is not included\n// eslint-disable-next-line no-restricted-globals\ntype DomElement = typeof globalThis extends {\n  Element: new (...args: any) => infer T;\n}\n  ? T\n  : never;\n"
  },
  {
    "path": "packages/analytics-types/src/event-bridge.ts",
    "content": "import { Event } from './event';\n\nexport interface EventBridge {\n  sendEvent(channel: string, event: Event): void;\n  setReceiver(channel: string, receiver: EventBridgeReceiver): void;\n}\n\nexport interface EventBridgeChannel {\n  sendEvent(event: Event): void;\n  setReceiver(receiver: EventBridgeReceiver): void;\n}\n\nexport interface EventBridgeContainer {\n  getInstance(instanceName: string): EventBridge;\n}\n\nexport interface EventBridgeReceiver {\n  receive(channel: string, event: Event): void;\n}\n"
  },
  {
    "path": "packages/analytics-types/src/event-callback.ts",
    "content": "import { Result } from './result';\n\nexport type EventCallback = (result: Result) => void;\n"
  },
  {
    "path": "packages/analytics-types/src/event.ts",
    "content": "import { BaseEvent } from './base-event';\n\nexport interface Identify {\n  getUserProperties(): IdentifyUserProperties;\n  set(property: string, value: ValidPropertyType): Identify;\n  setOnce(property: string, value: ValidPropertyType): Identify;\n  append(property: string, value: ValidPropertyType): Identify;\n  prepend(property: string, value: ValidPropertyType): Identify;\n  postInsert(property: string, value: ValidPropertyType): Identify;\n  preInsert(property: string, value: ValidPropertyType): Identify;\n  remove(property: string, value: ValidPropertyType): Identify;\n  add(property: string, value: number): Identify;\n  unset(property: string): Identify;\n  clearAll(): Identify;\n}\n\nexport enum IdentifyOperation {\n  // Base Operations to set values\n  SET = '$set',\n  SET_ONCE = '$setOnce',\n\n  // Operations around modifying existing values\n  ADD = '$add',\n  APPEND = '$append',\n  PREPEND = '$prepend',\n  REMOVE = '$remove',\n\n  // Operations around appending values *if* they aren't present\n  PREINSERT = '$preInsert',\n  POSTINSERT = '$postInsert',\n\n  // Operations around removing properties/values\n  UNSET = '$unset',\n  CLEAR_ALL = '$clearAll',\n}\n\nexport type ValidPropertyType =\n  | number\n  | string\n  | boolean\n  | Array<string | number>\n  | { [key: string]: ValidPropertyType }\n  | Array<{ [key: string]: ValidPropertyType }>;\n\ninterface BaseOperationConfig {\n  [key: string]: ValidPropertyType;\n}\n\nexport interface IdentifyUserProperties {\n  // Add operations can only take numbers\n  [IdentifyOperation.ADD]?: { [key: string]: number };\n\n  // This reads the keys of the passed object, but the values are not used\n  [IdentifyOperation.UNSET]?: BaseOperationConfig;\n  // This option does not read the key as it unsets all user properties\n  [IdentifyOperation.CLEAR_ALL]?: any;\n\n  // These operations can take numbers, strings, or arrays of both.\n  [IdentifyOperation.SET]?: BaseOperationConfig;\n  [IdentifyOperation.SET_ONCE]?: BaseOperationConfig;\n  [IdentifyOperation.APPEND]?: BaseOperationConfig;\n  [IdentifyOperation.PREPEND]?: BaseOperationConfig;\n  [IdentifyOperation.POSTINSERT]?: BaseOperationConfig;\n  [IdentifyOperation.PREINSERT]?: BaseOperationConfig;\n  [IdentifyOperation.REMOVE]?: BaseOperationConfig;\n}\n\nexport type UserProperties =\n  | IdentifyUserProperties\n  | {\n      [key in Exclude<string, IdentifyOperation>]: any;\n    };\n\nexport interface Revenue {\n  getEventProperties(): RevenueEventProperties;\n  setProductId(productId: string): Revenue;\n  setQuantity(quantity: number): Revenue;\n  setPrice(price: number): Revenue;\n  setRevenueType(revenueType: string): Revenue;\n  setCurrency(currency: string): Revenue;\n  setEventProperties(properties: { [key: string]: any }): Revenue;\n  setRevenue(revenue: number): Revenue;\n}\n\nexport enum RevenueProperty {\n  REVENUE_PRODUCT_ID = '$productId',\n  REVENUE_QUANTITY = '$quantity',\n  REVENUE_PRICE = '$price',\n  REVENUE_TYPE = '$revenueType',\n  REVENUE_CURRENCY = '$currency',\n  REVENUE = '$revenue',\n}\n\nexport interface RevenueEventProperties {\n  [RevenueProperty.REVENUE_PRODUCT_ID]?: string;\n  [RevenueProperty.REVENUE_QUANTITY]?: number;\n  [RevenueProperty.REVENUE_PRICE]?: number;\n  [RevenueProperty.REVENUE_TYPE]?: string;\n  [RevenueProperty.REVENUE_CURRENCY]?: string;\n  [RevenueProperty.REVENUE]?: number;\n}\n\n/**\n * Strings that have special meaning when used as an event's type\n * and have different specifications.\n */\nexport enum SpecialEventType {\n  IDENTIFY = '$identify',\n  GROUP_IDENTIFY = '$groupidentify',\n  REVENUE = 'revenue_amount',\n}\n\nexport interface TrackEvent extends BaseEvent {\n  event_type: Exclude<string, SpecialEventType>;\n}\n\nexport interface IdentifyEvent extends BaseEvent {\n  event_type: SpecialEventType.IDENTIFY;\n  user_properties: UserProperties;\n}\n\nexport interface GroupIdentifyEvent extends BaseEvent {\n  event_type: SpecialEventType.GROUP_IDENTIFY;\n  group_properties: UserProperties;\n}\n\nexport interface RevenueEvent extends BaseEvent {\n  event_type: SpecialEventType.REVENUE;\n  event_properties:\n    | RevenueEventProperties\n    | {\n        [key: string]: any;\n      };\n}\n\nexport type Event = TrackEvent | IdentifyEvent | GroupIdentifyEvent | RevenueEvent;\n"
  },
  {
    "path": "packages/analytics-types/src/index.ts",
    "content": "export { AmplitudeReturn } from './amplitude-promise';\nexport { BaseEvent, EventOptions } from './base-event';\nexport {\n  Campaign,\n  CampaignParser,\n  CampaignTracker,\n  CampaignTrackerOptions,\n  CampaignTrackFunction,\n  ClickIdParameters,\n  ReferrerParameters,\n  UTMParameters,\n} from './campaign';\nexport { BrowserClient, ReactNativeClient, NodeClient } from './client';\nexport {\n  AttributionOptions,\n  AutocaptureOptions,\n  BrowserConfig,\n  BrowserOptions,\n  Config,\n  DefaultTrackingOptions,\n  Options,\n  NodeConfig,\n  NodeOptions,\n  ReactNativeConfig,\n  ReactNativeOptions,\n  ReactNativeTrackingOptions,\n  TrackingOptions,\n  RequestMetadata,\n  HistogramOptions,\n  HistogramKey,\n  BrowserRemoteConfig,\n} from './config';\nexport { CoreClient } from './client/core-client';\nexport { DestinationContext } from './destination-context';\nexport {\n  Event,\n  TrackEvent,\n  IdentifyEvent,\n  GroupIdentifyEvent,\n  SpecialEventType,\n  IdentifyOperation,\n  IdentifyUserProperties,\n  ValidPropertyType,\n  Identify,\n  Revenue,\n  RevenueEvent,\n  RevenueProperty,\n  RevenueEventProperties,\n} from './event';\nexport { EventCallback } from './event-callback';\nexport { EventBridge, EventBridgeChannel, EventBridgeContainer, EventBridgeReceiver } from './event-bridge';\nexport { Logger, LogLevel, LogConfig, DebugContext } from './logger';\nexport { Payload } from './payload';\nexport { Plan } from './plan';\nexport { IngestionMetadata } from './ingestion-metadata';\nexport { Plugin, BeforePlugin, EnrichmentPlugin, DestinationPlugin, PluginType } from './plugin';\nexport { Result } from './result';\nexport { Response, SuccessResponse, InvalidResponse, PayloadTooLargeResponse, RateLimitResponse } from './response';\nexport { QueueProxy, InstanceProxy } from './proxy';\nexport { ServerZone, ServerZoneType } from './server-zone';\nexport { Status } from './status';\nexport { CookieStorageOptions, IdentityStorageType, Storage } from './storage';\nexport { Transport, TransportType } from './transport';\nexport { UserSession } from './user-session';\nexport { UTMData } from './utm';\nexport { PageTrackingOptions, PageTrackingTrackOn, PageTrackingHistoryChanges } from './page-view-tracking';\nexport { OfflineDisabled } from './offline';\nexport {\n  Messenger,\n  ElementInteractionsOptions,\n  ActionType,\n  DEFAULT_CSS_SELECTOR_ALLOWLIST,\n  DEFAULT_DATA_ATTRIBUTE_PREFIX,\n  DEFAULT_ACTION_CLICK_ALLOWLIST,\n} from './element-interactions';\n"
  },
  {
    "path": "packages/analytics-types/src/ingestion-metadata.ts",
    "content": "/**\n * Ingestion metadata\n */\nexport interface IngestionMetadata {\n  /** The source name of ingestion metadata e.g. \"ampli\" */\n  sourceName?: string;\n  /** The source version of ingestion metadata e.g. \"2.0.0\" */\n  sourceVersion?: string;\n}\n\n/**\n * Ingestion metadata event property, snake-case\n */\nexport interface IngestionMetadataEventProperty {\n  /** The source name of ingestion metadata e.g. \"ampli\" */\n  source_name?: string;\n  /** The source version of ingestion metadata e.g. \"2.0.0\" */\n  source_version?: string;\n}\n"
  },
  {
    "path": "packages/analytics-types/src/logger.ts",
    "content": "export interface Logger {\n  disable(): void;\n  enable(logLevel: LogLevel): void;\n  log(...args: any[]): void;\n  warn(...args: any[]): void;\n  error(...args: any[]): void;\n  debug(...args: any[]): void;\n}\n\nexport enum LogLevel {\n  None = 0,\n  Error = 1,\n  Warn = 2,\n  Verbose = 3,\n  Debug = 4,\n}\n\nexport interface LogConfig {\n  logger: Logger;\n  logLevel: LogLevel;\n}\n\ntype TimeKey = 'start' | 'end';\n\nexport interface DebugContext {\n  type: string;\n  name: string;\n  args: string[] | string;\n  stacktrace?: string[] | string;\n  time?: { [key in TimeKey]?: string };\n  states?: { [key: string]: any };\n}\n"
  },
  {
    "path": "packages/analytics-types/src/offline.ts",
    "content": "export const OfflineDisabled = null;\n"
  },
  {
    "path": "packages/analytics-types/src/page-view-tracking.ts",
    "content": "export interface PageTrackingOptions {\n  trackOn?: PageTrackingTrackOn;\n  trackHistoryChanges?: PageTrackingHistoryChanges;\n  eventType?: string;\n  pageCounter?: number;\n}\n\nexport type PageTrackingTrackOn = 'attribution' | (() => boolean);\n\nexport type PageTrackingHistoryChanges = 'all' | 'pathOnly';\n"
  },
  {
    "path": "packages/analytics-types/src/payload.ts",
    "content": "import { Event } from './event';\nimport { RequestMetadata } from './config';\n\nexport interface PayloadOptions {\n  min_id_length?: number;\n}\n\nexport interface Payload {\n  api_key: string;\n  events: readonly Event[];\n  options?: PayloadOptions;\n  client_upload_time?: string;\n  request_metadata?: RequestMetadata;\n}\n"
  },
  {
    "path": "packages/analytics-types/src/plan.ts",
    "content": "/**\n * Tracking plan\n */\nexport interface Plan {\n  /** The tracking plan branch name e.g. \"main\" */\n  branch?: string;\n  /** The tracking plan source e.g. \"web\" */\n  source?: string;\n  /** The tracking plan version e.g. \"1\", \"15\" */\n  version?: string;\n  /** The tracking plan version Id e.g. \"9ec23ba0-275f-468f-80d1-66b88bff9529\" */\n  versionId?: string;\n}\n"
  },
  {
    "path": "packages/analytics-types/src/plugin.ts",
    "content": "import { Event } from './event';\nimport { Config } from './config';\nimport { Result } from './result';\nimport { CoreClient } from './client/core-client';\n\ntype PluginTypeBefore = 'before';\ntype PluginTypeEnrichment = 'enrichment';\ntype PluginTypeDestination = 'destination';\nexport type PluginType = PluginTypeBefore | PluginTypeEnrichment | PluginTypeDestination;\n\ninterface PluginBase<T = CoreClient, U = Config> {\n  name?: string;\n  type?: PluginType;\n  setup?(config: U, client: T): Promise<void>;\n  teardown?(): Promise<void>;\n}\n\nexport interface BeforePlugin<T = CoreClient, U = Config> extends PluginBase<T, U> {\n  type: PluginTypeBefore;\n  execute?(context: Event): Promise<Event | null>;\n}\n\nexport interface EnrichmentPlugin<T = CoreClient, U = Config> extends PluginBase<T, U> {\n  type?: PluginTypeEnrichment;\n  execute?(context: Event): Promise<Event | null>;\n}\n\nexport interface DestinationPlugin<T = CoreClient, U = Config> extends PluginBase<T, U> {\n  type: PluginTypeDestination;\n  execute(context: Event): Promise<Result>;\n  flush?(): Promise<void>;\n}\n\nexport type Plugin<T = CoreClient, U = Config> = BeforePlugin<T, U> | EnrichmentPlugin<T, U> | DestinationPlugin<T, U>;\n"
  },
  {
    "path": "packages/analytics-types/src/proxy.ts",
    "content": "import { Result } from './result';\n\ninterface ProxyItem {\n  name: string;\n  args: any[];\n  resolve?: (promise: Promise<Result>) => void;\n}\n\nexport type QueueProxy = Array<ProxyItem>;\n\nexport interface InstanceProxy {\n  _q: QueueProxy;\n  _iq: Record<string, InstanceProxy>;\n}\n"
  },
  {
    "path": "packages/analytics-types/src/response.ts",
    "content": "import { Status } from './status';\n\nexport interface SuccessBody {\n  eventsIngested: number;\n  payloadSizeBytes: number;\n  serverUploadTime: number;\n}\n\nexport interface InvalidRequestBody {\n  error: string;\n  missingField: string;\n  eventsWithInvalidFields: { [eventField: string]: number[] };\n  eventsWithMissingFields: { [eventField: string]: number[] };\n  eventsWithInvalidIdLengths: { [eventField: string]: number[] };\n  epsThreshold: 0;\n  exceededDailyQuotaDevices: { [deviceId: string]: number };\n  silencedDevices: string[];\n  silencedEvents: number[];\n  throttledDevices: { [deviceId: string]: number };\n  throttledEvents: number[];\n}\nexport interface PayloadTooLargeBody {\n  error: string;\n}\nexport interface RateLimitBody {\n  error: string;\n  epsThreshold: number;\n  throttledDevices: { [deviceId: string]: number };\n  throttledUsers: { [userId: string]: number };\n  exceededDailyQuotaDevices: { [deviceId: string]: number };\n  exceededDailyQuotaUsers: { [userId: string]: number };\n  throttledEvents: number[];\n}\n\nexport type StatusWithResponseBody = Status.Invalid | Status.PayloadTooLarge | Status.RateLimit | Status.Success;\n\nexport type ResponseBody = SuccessBody | InvalidRequestBody | PayloadTooLargeBody | RateLimitBody;\n\nexport interface SuccessResponse {\n  status: Status.Success;\n  statusCode: number;\n  body: SuccessBody;\n}\n\nexport interface InvalidResponse {\n  status: Status.Invalid;\n  statusCode: number;\n  body: InvalidRequestBody;\n}\n\nexport interface PayloadTooLargeResponse {\n  status: Status.PayloadTooLarge;\n  statusCode: number;\n  body: PayloadTooLargeBody;\n}\n\nexport interface RateLimitResponse {\n  status: Status.RateLimit;\n  statusCode: number;\n  body: RateLimitBody;\n}\n\nexport interface TimeoutResponse {\n  status: Status.Timeout;\n  statusCode: number;\n}\n\nexport interface OtherResponse {\n  status: Exclude<Status, StatusWithResponseBody>;\n  statusCode: number;\n}\n\nexport type Response =\n  | SuccessResponse\n  | InvalidResponse\n  | PayloadTooLargeResponse\n  | RateLimitResponse\n  | TimeoutResponse\n  | OtherResponse;\n"
  },
  {
    "path": "packages/analytics-types/src/result.ts",
    "content": "import { Event } from './event';\n\nexport interface Result {\n  event: Event;\n  code: number;\n  message: string;\n}\n"
  },
  {
    "path": "packages/analytics-types/src/server-zone.ts",
    "content": "/**\n * @deprecated use ServerZoneType instead\n */\nexport enum ServerZone {\n  US = 'US',\n  EU = 'EU',\n}\n\nexport type ServerZoneType = 'US' | 'EU';\n"
  },
  {
    "path": "packages/analytics-types/src/status.ts",
    "content": "/** The status of an event. */\nexport enum Status {\n  /** The status could not be determined. */\n  Unknown = 'unknown',\n  /** The event was skipped due to configuration or callbacks. */\n  Skipped = 'skipped',\n  /** The event was sent successfully. */\n  Success = 'success',\n  /** A user or device in the payload is currently rate limited and should try again later. */\n  RateLimit = 'rate_limit',\n  /** The sent payload was too large to be processed. */\n  PayloadTooLarge = 'payload_too_large',\n  /** The event could not be processed. */\n  Invalid = 'invalid',\n  /** A server-side error ocurred during submission. */\n  Failed = 'failed',\n  /** a server or client side error occuring when a request takes too long and is cancelled */\n  Timeout = 'Timeout',\n  /** NodeJS runtime environment error.. E.g. disconnected from network */\n  SystemError = 'SystemError',\n}\n"
  },
  {
    "path": "packages/analytics-types/src/storage.ts",
    "content": "export interface Storage<T> {\n  isEnabled(): Promise<boolean>;\n  get(key: string): Promise<T | undefined>;\n  getRaw(key: string): Promise<string | undefined>;\n  set(key: string, value: T): Promise<void>;\n  remove(key: string): Promise<void>;\n  reset(): Promise<void>;\n}\n\nexport interface CookieStorageOptions {\n  domain?: string;\n  expirationDays?: number;\n  sameSite?: string;\n  secure?: boolean;\n}\n\nexport type IdentityStorageType = 'cookie' | 'localStorage' | 'sessionStorage' | 'none';\n"
  },
  {
    "path": "packages/analytics-types/src/transport.ts",
    "content": "import { Payload } from './payload';\nimport { Response } from './response';\n\nexport interface Transport {\n  send(serverUrl: string, payload: Payload): Promise<Response | null>;\n}\n\nexport type TransportType = 'xhr' | 'beacon' | 'fetch';\n"
  },
  {
    "path": "packages/analytics-types/src/user-session.ts",
    "content": "export interface UserSession {\n  userId?: string;\n  deviceId?: string;\n  sessionId?: number;\n  lastEventTime?: number;\n  optOut: boolean;\n  lastEventId?: number;\n  pageCounter?: number;\n  debugLogsEnabled?: boolean;\n}\n"
  },
  {
    "path": "packages/analytics-types/src/utm.ts",
    "content": "export interface UTMData {\n  utm_source?: string;\n  utm_medium?: string;\n  utm_campaign?: string;\n  utm_term?: string;\n  utm_content?: string;\n}\n"
  },
  {
    "path": "packages/analytics-types/tsconfig.es5.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/cjs\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/analytics-types/tsconfig.esm.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"module\": \"es6\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/esm\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/analytics-types/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"noEmit\": true,\n    \"rootDir\": \".\",\n    \"types\": [],\n    \"lib\": [\"dom\", \"es6\"],\n  }\n}\n"
  },
  {
    "path": "packages/e2e-remote-config/README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://amplitude.com\" target=\"_blank\" align=\"center\">\n    <img src=\"https://static.amplitude.com/lightning/46c85bfd91905de8047f1ee65c7c93d6fa9ee6ea/static/media/amplitude-logo-with-text.4fb9e463.svg\" width=\"280\">\n  </a>\n  <br />\n</p>\n\n# E2E Remote Config\n\nA place for E2E tests that test the Remote Config functionality. Tests against a matrix of SDK versions and API Keys."
  },
  {
    "path": "packages/e2e-remote-config/remote-config-test-staging.sh",
    "content": "# STAGING\nAPI_KEY=\"52fbe5356dc7490756a9c26591f2bb37\"\nAMPLITUDE_VERSION=\"2.22.2\"\nSERVER_ZONE=\"STAGING\"\nSERVER_ZONE=$SERVER_ZONE API_KEY=$API_KEY AMPLITUDE_VERSION=$AMPLITUDE_VERSION npx playwright test --reporter=list packages/e2e-remote-config/test/e2e/fetch-remote-config.spec.ts\n"
  },
  {
    "path": "packages/e2e-remote-config/remote-config-test.sh",
    "content": "# API_KEY empty\nAPI_KEY=\"657954c4c37e22e8dc2af0413ac01e2b\"\nSERVER_ZONE=\"US\"\nAPI_KEY=$API_KEY AMPLITUDE_VERSION=$AMPLITUDE_VERSION npx playwright test --reporter=list packages/e2e-remote-config/test/e2e/fetch-remote-config.spec.ts\n\n# 2.11.0 -- first mionor version to support remote config for autocapture\nAMPLITUDE_VERSION=\"2.11.13\"\nAPI_KEY=$API_KEY AMPLITUDE_VERSION=$AMPLITUDE_VERSION npx playwright test --reporter=list packages/e2e-remote-config/test/e2e/fetch-remote-config.spec.ts\n\n# 2.13.3 -- first minor version to set remote config fetch default=true\nAMPLITUDE_VERSION=\"2.13.3\"\nAPI_KEY=$API_KEY AMPLITUDE_VERSION=$AMPLITUDE_VERSION npx playwright test --reporter=list packages/e2e-remote-config/test/e2e/fetch-remote-config.spec.ts\n\n# 2.17.12 -- first minor version to use the new Remote Config client\nAMPLITUDE_VERSION=\"2.22.2\"\nAPI_KEY=$API_KEY AMPLITUDE_VERSION=$AMPLITUDE_VERSION npx playwright test --reporter=list packages/e2e-remote-config/test/e2e/fetch-remote-config.spec.ts\n\n# API_KEY nested\nAPI_KEY=\"77de0b7de6157d5e7ca409c81778f28e\"\nAMPLITUDE_VERSION=\"2.11.13\"\nAPI_KEY=$API_KEY AMPLITUDE_VERSION=$AMPLITUDE_VERSION npx playwright test --reporter=list packages/e2e-remote-config/test/e2e/fetch-remote-config.spec.ts\n\nAMPLITUDE_VERSION=\"2.13.3\"\nAPI_KEY=$API_KEY AMPLITUDE_VERSION=$AMPLITUDE_VERSION npx playwright test --reporter=list packages/e2e-remote-config/test/e2e/fetch-remote-config.spec.ts\n\nAMPLITUDE_VERSION=\"2.22.2\"\nAPI_KEY=$API_KEY AMPLITUDE_VERSION=$AMPLITUDE_VERSION npx playwright test --reporter=list packages/e2e-remote-config/test/e2e/fetch-remote-config.spec.ts\n\n# API_KEY default\nAPI_KEY=\"aafc4dd16b5bf88b1cf21693d97665d3\"\nAMPLITUDE_VERSION=\"2.11.13\"\nAPI_KEY=$API_KEY AMPLITUDE_VERSION=$AMPLITUDE_VERSION npx playwright test --reporter=list packages/e2e-remote-config/test/e2e/fetch-remote-config.spec.ts\n\nAMPLITUDE_VERSION=\"2.13.3\"\nAPI_KEY=$API_KEY AMPLITUDE_VERSION=$AMPLITUDE_VERSION npx playwright test --reporter=list packages/e2e-remote-config/test/e2e/fetch-remote-config.spec.ts\n\nAMPLITUDE_VERSION=\"2.22.2\"\nAPI_KEY=$API_KEY AMPLITUDE_VERSION=$AMPLITUDE_VERSION npx playwright test --reporter=list packages/e2e-remote-config/test/e2e/fetch-remote-config.spec.ts"
  },
  {
    "path": "packages/e2e-remote-config/test/e2e/fetch-remote-config.spec.ts",
    "content": "import { test, expect } from '@playwright/test';\n\n/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-return, no-restricted-globals */\n\n// parse query params\nconst remoteConfigUrl = 'https://sr-client-cfg.amplitude.com/';\nconst amplitudeVersion = process.env.AMPLITUDE_VERSION;\nconst apiKey = process.env.API_KEY;\nconst serverZone = process.env.SERVER_ZONE || 'US';\n\nlet redirectedServerUrl = null;\nif (serverZone === 'STAGING') {\n  redirectedServerUrl = 'https://sr-client-cfg.stag2.amplitude.com/';\n} else if (serverZone === 'EU') {\n  redirectedServerUrl = 'https://sr-client-cfg.eu.amplitude.com/';\n}\n\nif (redirectedServerUrl && !redirectedServerUrl?.endsWith('/')) {\n  redirectedServerUrl += '/';\n}\n\nconst LOCAL_SITE = 'http://localhost:5173';\n\ntest.describe(`Fetch remote config: remoteConfigUrl=${redirectedServerUrl} sdkVersion=${amplitudeVersion || 'latest'} apiKey=${apiKey || 'default'}`, () => {\n  test('should fetch remote config', async ({ page }) => {\n    // intercept the fetch request to the remote config\n    let fullRemoteConfigUrl = remoteConfigUrl;\n    await page.route(`${remoteConfigUrl}**`, async (route) => {\n      if (redirectedServerUrl) {\n        // edit the request to redirect to the redirectedServerUrl\n        const request = route.request();\n        const newUrl = request.url().replace(remoteConfigUrl, redirectedServerUrl);\n        fullRemoteConfigUrl = newUrl;\n        await route.continue({ url: newUrl });\n      } else {\n        fullRemoteConfigUrl = route.request().url();\n        await route.continue();\n      }\n    });\n    const responsePattern = redirectedServerUrl ? `${redirectedServerUrl}**` : `${remoteConfigUrl}**`;\n    const fetchRemoteConfigPromise = page.waitForResponse(responsePattern);\n\n    // open the page with parameters to define version, api key and server zone\n    let queryParams: Record<string, string> = {};\n    if (amplitudeVersion) {\n      queryParams.amplitudeVersion = amplitudeVersion;\n    }\n    if (apiKey) {\n      queryParams.apiKey = apiKey;\n    }\n    queryParams.serverZone = serverZone;\n    await page.goto(`${LOCAL_SITE}/remote-config-test.html?${new URLSearchParams(queryParams).toString()}`);\n    const response = await fetchRemoteConfigPromise;\n    const body = await response.json();\n    expect(body.configs.analyticsSDK).toBeDefined();\n\n    // perform an interaction on the page to confirm it's still interactable\n    const interactiveButton = page.locator('#interactive-button');\n    const interactiveContent = page.locator('#interactive-content');\n    await expect(interactiveContent).toHaveText('This is the interactive section.');\n    await interactiveButton.click();\n  });\n});\n"
  },
  {
    "path": "packages/gtm-snippet/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.41.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.39.1...@amplitude/gtm-snippet@2.41.0) (2026-04-21)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n# [2.40.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.39.1...@amplitude/gtm-snippet@2.40.0) (2026-04-16)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n# [2.40.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.39.0...@amplitude/gtm-snippet@2.40.0) (2026-04-14)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n# [2.39.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.38.1...@amplitude/gtm-snippet@2.39.0) (2026-04-09)\n\n\n### Features\n\n* **session-replay-browser:** improve replay data delivery (SR-3115) ([#1637](https://github.com/amplitude/Amplitude-TypeScript/issues/1637)) ([21bd1c8](https://github.com/amplitude/Amplitude-TypeScript/commit/21bd1c870eea801878aea0fc4e952fe2b8908675))\n\n\n\n\n\n## [2.38.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.37.3...@amplitude/gtm-snippet@2.38.1) (2026-04-01)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n# [2.38.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.37.2...@amplitude/gtm-snippet@2.38.0) (2026-03-26)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.37.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.37.2...@amplitude/gtm-snippet@2.37.2) (2026-03-24)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.37.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.37.1...@amplitude/gtm-snippet@2.37.2) (2026-03-24)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.37.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.36.9...@amplitude/gtm-snippet@2.37.1) (2026-03-23)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n# [2.37.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.36.8...@amplitude/gtm-snippet@2.37.0) (2026-03-20)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.36.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.36.7...@amplitude/gtm-snippet@2.36.8) (2026-03-19)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.36.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.36.6...@amplitude/gtm-snippet@2.36.7) (2026-03-17)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.36.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.36.5...@amplitude/gtm-snippet@2.36.6) (2026-03-16)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.36.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.36.4...@amplitude/gtm-snippet@2.36.5) (2026-03-13)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.36.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.36.3...@amplitude/gtm-snippet@2.36.4) (2026-03-12)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.36.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.36.3...@amplitude/gtm-snippet@2.36.3) (2026-03-11)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.36.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.36.2...@amplitude/gtm-snippet@2.36.3) (2026-03-09)\n\n\n### Bug Fixes\n\n* **session-replay:** guarantee in-order batch delivery including retries ([#1576](https://github.com/amplitude/Amplitude-TypeScript/issues/1576)) ([0afcac6](https://github.com/amplitude/Amplitude-TypeScript/commit/0afcac6cd42b999b74ba797717f7cf0d447029ef))\n\n\n\n\n\n## [2.36.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.36.2...@amplitude/gtm-snippet@2.36.2) (2026-03-06)\n\n\n### Bug Fixes\n\n* **session-replay:** guarantee in-order batch delivery including retries ([#1576](https://github.com/amplitude/Amplitude-TypeScript/issues/1576)) ([0afcac6](https://github.com/amplitude/Amplitude-TypeScript/commit/0afcac6cd42b999b74ba797717f7cf0d447029ef))\n\n\n\n\n\n## [2.36.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.36.2...@amplitude/gtm-snippet@2.36.2) (2026-03-06)\n\n\n### Bug Fixes\n\n* **session-replay:** guarantee in-order batch delivery including retries ([#1576](https://github.com/amplitude/Amplitude-TypeScript/issues/1576)) ([0afcac6](https://github.com/amplitude/Amplitude-TypeScript/commit/0afcac6cd42b999b74ba797717f7cf0d447029ef))\n\n\n\n\n\n## [2.36.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.36.2...@amplitude/gtm-snippet@2.36.2) (2026-03-06)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.36.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.36.1...@amplitude/gtm-snippet@2.36.2) (2026-03-05)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.36.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.35.5...@amplitude/gtm-snippet@2.36.1) (2026-03-03)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n# [2.36.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.35.4...@amplitude/gtm-snippet@2.36.0) (2026-03-03)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.35.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.35.3...@amplitude/gtm-snippet@2.35.4) (2026-02-26)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.35.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.35.2...@amplitude/gtm-snippet@2.35.3) (2026-02-24)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.35.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.35.1...@amplitude/gtm-snippet@2.35.2) (2026-02-20)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.35.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.34.2...@amplitude/gtm-snippet@2.35.1) (2026-02-19)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n# [2.35.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.35.0...@amplitude/gtm-snippet@2.35.0) (2026-02-17)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.34.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.34.1...@amplitude/gtm-snippet@2.34.1) (2026-02-11)\n\n\n### Features\n\n* **gtm-snippet:** update GTM package's engagement sdk snippet to support split bun… ([#1528](https://github.com/amplitude/Amplitude-TypeScript/issues/1528)) ([ce5da08](https://github.com/amplitude/Amplitude-TypeScript/commit/ce5da08398a9cbaa468217d36e73a5f9eefcdb32))\n\n\n\n\n\n## [2.34.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.33.6...@amplitude/gtm-snippet@2.34.1) (2026-02-10)\n\n\n### Bug Fixes\n\n* **analytics-browser:** defer session_start and attribution when optOut is \"true\" ([#1509](https://github.com/amplitude/Amplitude-TypeScript/issues/1509)) ([3a3818d](https://github.com/amplitude/Amplitude-TypeScript/commit/3a3818d19bd84e4aa8405e10f8538886dd647f38))\n\n\n\n\n\n# [2.34.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.33.5...@amplitude/gtm-snippet@2.34.0) (2026-01-26)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.33.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.33.4...@amplitude/gtm-snippet@2.33.5) (2026-01-21)\n\n\n### Bug Fixes\n\n* **analytics-browser:** ignore right clicks when tracking dead clicks ([#1496](https://github.com/amplitude/Amplitude-TypeScript/issues/1496)) ([752b4c0](https://github.com/amplitude/Amplitude-TypeScript/commit/752b4c0d9f22fcaa4b920b6fff09455a58f92da2))\n\n\n\n\n\n## [2.33.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.33.3...@amplitude/gtm-snippet@2.33.4) (2026-01-15)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.33.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.33.2...@amplitude/gtm-snippet@2.33.3) (2026-01-14)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.33.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.33.1...@amplitude/gtm-snippet@2.33.2) (2026-01-14)\n\n\n### Bug Fixes\n\n* **deps:** bump node-forge from 1.3.1 to 1.3.3 in /packages/analytics-browser/playground/react-spa ([#1438](https://github.com/amplitude/Amplitude-TypeScript/issues/1438)) ([ffacc88](https://github.com/amplitude/Amplitude-TypeScript/commit/ffacc8888217249e6c8084ef7327872e1fa375ca))\n\n\n\n\n\n## [2.33.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.32.3...@amplitude/gtm-snippet@2.33.1) (2025-12-30)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n# [2.33.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.32.3...@amplitude/gtm-snippet@2.33.0) (2025-12-30)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n# [2.33.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.32.2...@amplitude/gtm-snippet@2.33.0) (2025-12-24)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.32.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.32.2...@amplitude/gtm-snippet@2.32.2) (2025-12-22)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.32.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.32.1...@amplitude/gtm-snippet@2.32.2) (2025-12-16)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.32.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.31.5...@amplitude/gtm-snippet@2.32.1) (2025-12-12)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n# [2.32.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.31.4...@amplitude/gtm-snippet@2.32.0) (2025-12-09)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.31.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.31.3...@amplitude/gtm-snippet@2.31.4) (2025-12-08)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.31.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.31.3...@amplitude/gtm-snippet@2.31.3) (2025-12-05)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.31.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.31.2...@amplitude/gtm-snippet@2.31.3) (2025-11-21)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.31.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.31.1...@amplitude/gtm-snippet@2.31.2) (2025-11-20)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.31.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.30.2...@amplitude/gtm-snippet@2.31.1) (2025-11-17)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n# [2.31.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.30.1...@amplitude/gtm-snippet@2.31.0) (2025-11-17)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.30.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.29.1...@amplitude/gtm-snippet@2.30.1) (2025-11-05)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n# [2.30.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.28.1...@amplitude/gtm-snippet@2.30.0) (2025-10-29)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n# [2.29.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.27.2...@amplitude/gtm-snippet@2.29.0) (2025-10-23)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n# [2.28.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.27.1...@amplitude/gtm-snippet@2.28.0) (2025-10-23)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.27.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.26.3...@amplitude/gtm-snippet@2.27.1) (2025-10-21)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n# [2.27.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.26.2...@amplitude/gtm-snippet@2.27.0) (2025-10-17)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.26.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.26.1...@amplitude/gtm-snippet@2.26.2) (2025-10-15)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.26.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.25.5...@amplitude/gtm-snippet@2.26.1) (2025-10-14)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n# [2.26.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.25.4...@amplitude/gtm-snippet@2.26.0) (2025-10-14)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## [2.25.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/gtm-snippet@2.25.3...@amplitude/gtm-snippet@2.25.4) (2025-10-07)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n\n\n\n\n\n## 2.25.3 (2025-10-06)\n\n**Note:** Version bump only for package @amplitude/gtm-snippet\n"
  },
  {
    "path": "packages/gtm-snippet/amplitude-wrapper.js.ejs",
    "content": "import { version } from '../../analytics-browser/package.json';\n\n/* Amplitude Browser 2.0 SDK begin */\n<%- analyticsBrowserSnippet %>\n\n/* Amplitude Browser 2.0 SDK end */\n\n/* Amplitude Page View V1 Enrichment Plugin begin */\nvar amplitudePageViewV1EnrichmentPlugin=function(e){\"use strict\";var t=function(){return t=Object.assign||function(e){for(var t,n=1,r=arguments.length;n<r;n++)for(var i in t=arguments[n])Object.prototype.hasOwnProperty.call(t,i)&&(e[i]=t[i]);return e},t.apply(this,arguments)};function n(e,t,n,r){return new(n||(n=Promise))((function(i,o){function u(e){try{l(r.next(e))}catch(e){o(e)}}function a(e){try{l(r.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?i(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(u,a)}l((r=r.apply(e,t||[])).next())}))}function r(e,t){var n,r,i,o,u={label:0,sent:function(){if(1&i[0])throw i[1];return i[1]},trys:[],ops:[]};return o={next:a(0),throw:a(1),return:a(2)},\"function\"==typeof Symbol&&(o[Symbol.iterator]=function(){return this}),o;function a(a){return function(l){return function(a){if(n)throw new TypeError(\"Generator is already executing.\");for(;o&&(o=0,a[0]&&(u=0)),u;)try{if(n=1,r&&(i=2&a[0]?r.return:a[0]?r.throw||((i=r.return)&&i.call(r),0):r.next)&&!(i=i.call(r,a[1])).done)return i;switch(r=0,i&&(a=[2&a[0],i.value]),a[0]){case 0:case 1:i=a;break;case 4:return u.label++,{value:a[1],done:!1};case 5:u.label++,r=a[1],a=[0];continue;case 7:a=u.ops.pop(),u.trys.pop();continue;default:if(!(i=u.trys,(i=i.length>0&&i[i.length-1])||6!==a[0]&&2!==a[0])){u=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]<i[3])){u.label=a[1];break}if(6===a[0]&&u.label<i[1]){u.label=i[1],i=a;break}if(i&&u.label<i[2]){u.label=i[2],u.ops.push(a);break}i[2]&&u.ops.pop(),u.trys.pop();continue}a=t.call(e,u)}catch(e){a=[6,e],r=0}finally{n=i=0}if(5&a[0])throw a[1];return{value:a[0]?a[1]:void 0,done:!0}}([a,l])}}}var i=function(){var e=this;return{name:\"@amplitude/plugin-page-view-v1-enrichment-browser\",type:\"enrichment\",setup:function(e){return n(this,void 0,void 0,(function(){return r(this,(function(t){return e.loggerProvider.log(\"Installing @amplitude/plugin-page-view-v1-enrichment-browser.\"),[2]}))}))},execute:function(i){return n(e,void 0,void 0,(function(){var e,n,o,u,a,l;return r(this,(function(r){return\"[Amplitude] Page Viewed\"==i.event_type&&(e=i.event_properties||{},n=e[\"[Amplitude] Page Domain\"],o=e[\"[Amplitude] Page Location\"],u=e[\"[Amplitude] Page Path\"],a=e[\"[Amplitude] Page Title\"],l=e[\"[Amplitude] Page URL\"],(i=t(t({},i),{event_type:\"Page View\",event_properties:t(t({},i.event_properties),{page_domain:null!=n?n:\"\",page_location:null!=o?o:\"\",page_path:null!=u?u:\"\",page_title:null!=a?a:\"\",page_url:null!=l?l:\"\"})})).event_properties&&(delete i.event_properties[\"[Amplitude] Page Domain\"],delete i.event_properties[\"[Amplitude] Page Location\"],delete i.event_properties[\"[Amplitude] Page Path\"],delete i.event_properties[\"[Amplitude] Page Title\"],delete i.event_properties[\"[Amplitude] Page URL\"])),[2,i]}))}))}}};return e.pageViewV1EnrichmentPlugin=i,e.plugin=i,Object.defineProperty(e,\"__esModule\",{value:!0}),e}({});\n/* Amplitude Page View V1 Enrichment Plugin end */\n\n/* Amplitude User Agent Enrichment Plugin begin */\nvar amplitudeUserAgentEnrichmentPlugin=function(i){\"use strict\";var e=function(){return e=Object.assign||function(i){for(var e,o=1,r=arguments.length;o<r;o++)for(var n in e=arguments[o])Object.prototype.hasOwnProperty.call(e,n)&&(i[n]=e[n]);return i},e.apply(this,arguments)};function o(i,e,o,r){return new(o||(o=Promise))((function(n,a){function t(i){try{b(r.next(i))}catch(i){a(i)}}function s(i){try{b(r.throw(i))}catch(i){a(i)}}function b(i){var e;i.done?n(i.value):(e=i.value,e instanceof o?e:new o((function(i){i(e)}))).then(t,s)}b((r=r.apply(i,e||[])).next())}))}function r(i,e){var o,r,n,a,t={label:0,sent:function(){if(1&n[0])throw n[1];return n[1]},trys:[],ops:[]};return a={next:s(0),throw:s(1),return:s(2)},\"function\"==typeof Symbol&&(a[Symbol.iterator]=function(){return this}),a;function s(s){return function(b){return function(s){if(o)throw new TypeError(\"Generator is already executing.\");for(;a&&(a=0,s[0]&&(t=0)),t;)try{if(o=1,r&&(n=2&s[0]?r.return:s[0]?r.throw||((n=r.return)&&n.call(r),0):r.next)&&!(n=n.call(r,s[1])).done)return n;switch(r=0,n&&(s=[2&s[0],n.value]),s[0]){case 0:case 1:n=s;break;case 4:return t.label++,{value:s[1],done:!1};case 5:t.label++,r=s[1],s=[0];continue;case 7:s=t.ops.pop(),t.trys.pop();continue;default:if(!(n=t.trys,(n=n.length>0&&n[n.length-1])||6!==s[0]&&2!==s[0])){t=0;continue}if(3===s[0]&&(!n||s[1]>n[0]&&s[1]<n[3])){t.label=s[1];break}if(6===s[0]&&t.label<n[1]){t.label=n[1],n=s;break}if(n&&t.label<n[2]){t.label=n[2],t.ops.push(s);break}n[2]&&t.ops.pop(),t.trys.pop();continue}s=e.call(i,t)}catch(i){s=[6,i],r=0}finally{o=n=0}if(5&s[0])throw s[1];return{value:s[0]?s[1]:void 0,done:!0}}([s,b])}}}var n=\"undefined\"!=typeof globalThis?globalThis:\"undefined\"!=typeof window?window:\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:{},a={exports:{}};!function(i,e){!function(o,r){var n=\"function\",a=\"undefined\",t=\"object\",s=\"string\",b=\"model\",l=\"name\",w=\"type\",u=\"vendor\",d=\"version\",c=\"architecture\",p=\"console\",m=\"mobile\",f=\"tablet\",h=\"smarttv\",v=\"wearable\",g=\"embedded\",x=\"Amazon\",k=\"Apple\",y=\"ASUS\",_=\"BlackBerry\",T=\"Browser\",S=\"Chrome\",q=\"Firefox\",N=\"Google\",z=\"Huawei\",A=\"LG\",E=\"Microsoft\",O=\"Motorola\",j=\"Opera\",C=\"Samsung\",P=\"Sharp\",U=\"Sony\",M=\"Xiaomi\",R=\"Zebra\",V=\"Facebook\",B=function(i){for(var e={},o=0;o<i.length;o++)e[i[o].toUpperCase()]=i[o];return e},I=function(i,e){return typeof i===s&&-1!==D(e).indexOf(D(i))},D=function(i){return i.toLowerCase()},G=function(i,e){if(typeof i===s)return i=i.replace(/^\\s\\s*/,\"\"),typeof e===a?i:i.substring(0,350)},W=function(i,e){for(var o,a,s,b,l,w,u=0;u<e.length&&!l;){var d=e[u],c=e[u+1];for(o=a=0;o<d.length&&!l;)if(l=d[o++].exec(i))for(s=0;s<c.length;s++)w=l[++a],typeof(b=c[s])===t&&b.length>0?2===b.length?typeof b[1]==n?this[b[0]]=b[1].call(this,w):this[b[0]]=b[1]:3===b.length?typeof b[1]!==n||b[1].exec&&b[1].test?this[b[0]]=w?w.replace(b[1],b[2]):r:this[b[0]]=w?b[1].call(this,w,b[2]):r:4===b.length&&(this[b[0]]=w?b[3].call(this,w.replace(b[1],b[2])):r):this[b]=w||r;u+=2}},F=function(i,e){for(var o in e)if(typeof e[o]===t&&e[o].length>0){for(var n=0;n<e[o].length;n++)if(I(e[o][n],i))return\"?\"===o?r:o}else if(I(e[o],i))return\"?\"===o?r:o;return i},L={ME:\"4.90\",\"NT 3.11\":\"NT3.51\",\"NT 4.0\":\"NT4.0\",2e3:\"NT 5.0\",XP:[\"NT 5.1\",\"NT 5.2\"],Vista:\"NT 6.0\",7:\"NT 6.1\",8:\"NT 6.2\",8.1:\"NT 6.3\",10:[\"NT 6.4\",\"NT 10.0\"],RT:\"ARM\"},Z={browser:[[/\\b(?:crmo|crios)\\/([\\w\\.]+)/i],[d,[l,\"Chrome\"]],[/edg(?:e|ios|a)?\\/([\\w\\.]+)/i],[d,[l,\"Edge\"]],[/(opera mini)\\/([-\\w\\.]+)/i,/(opera [mobiletab]{3,6})\\b.+version\\/([-\\w\\.]+)/i,/(opera)(?:.+version\\/|[\\/ ]+)([\\w\\.]+)/i],[l,d],[/opios[\\/ ]+([\\w\\.]+)/i],[d,[l,j+\" Mini\"]],[/\\bopr\\/([\\w\\.]+)/i],[d,[l,j]],[/(kindle)\\/([\\w\\.]+)/i,/(lunascape|maxthon|netfront|jasmine|blazer)[\\/ ]?([\\w\\.]*)/i,/(avant |iemobile|slim)(?:browser)?[\\/ ]?([\\w\\.]*)/i,/(ba?idubrowser)[\\/ ]?([\\w\\.]+)/i,/(?:ms|\\()(ie) ([\\w\\.]+)/i,/(flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs|bowser|quark|qupzilla|falkon|rekonq|puffin|brave|whale|qqbrowserlite|qq|duckduckgo)\\/([-\\w\\.]+)/i,/(weibo)__([\\d\\.]+)/i],[l,d],[/(?:\\buc? ?browser|(?:juc.+)ucweb)[\\/ ]?([\\w\\.]+)/i],[d,[l,\"UC\"+T]],[/microm.+\\bqbcore\\/([\\w\\.]+)/i,/\\bqbcore\\/([\\w\\.]+).+microm/i],[d,[l,\"WeChat(Win) Desktop\"]],[/micromessenger\\/([\\w\\.]+)/i],[d,[l,\"WeChat\"]],[/konqueror\\/([\\w\\.]+)/i],[d,[l,\"Konqueror\"]],[/trident.+rv[: ]([\\w\\.]{1,9})\\b.+like gecko/i],[d,[l,\"IE\"]],[/yabrowser\\/([\\w\\.]+)/i],[d,[l,\"Yandex\"]],[/(avast|avg)\\/([\\w\\.]+)/i],[[l,/(.+)/,\"$1 Secure \"+T],d],[/\\bfocus\\/([\\w\\.]+)/i],[d,[l,q+\" Focus\"]],[/\\bopt\\/([\\w\\.]+)/i],[d,[l,j+\" Touch\"]],[/coc_coc\\w+\\/([\\w\\.]+)/i],[d,[l,\"Coc Coc\"]],[/dolfin\\/([\\w\\.]+)/i],[d,[l,\"Dolphin\"]],[/coast\\/([\\w\\.]+)/i],[d,[l,j+\" Coast\"]],[/miuibrowser\\/([\\w\\.]+)/i],[d,[l,\"MIUI \"+T]],[/fxios\\/([-\\w\\.]+)/i],[d,[l,q]],[/\\bqihu|(qi?ho?o?|360)browser/i],[[l,\"360 \"+T]],[/(oculus|samsung|sailfish|huawei)browser\\/([\\w\\.]+)/i],[[l,/(.+)/,\"$1 \"+T],d],[/(comodo_dragon)\\/([\\w\\.]+)/i],[[l,/_/g,\" \"],d],[/(electron)\\/([\\w\\.]+) safari/i,/(tesla)(?: qtcarbrowser|\\/(20\\d\\d\\.[-\\w\\.]+))/i,/m?(qqbrowser|baiduboxapp|2345Explorer)[\\/ ]?([\\w\\.]+)/i],[l,d],[/(metasr)[\\/ ]?([\\w\\.]+)/i,/(lbbrowser)/i,/\\[(linkedin)app\\]/i],[l],[/((?:fban\\/fbios|fb_iab\\/fb4a)(?!.+fbav)|;fbav\\/([\\w\\.]+);)/i],[[l,V],d],[/safari (line)\\/([\\w\\.]+)/i,/\\b(line)\\/([\\w\\.]+)\\/iab/i,/(chromium|instagram)[\\/ ]([-\\w\\.]+)/i],[l,d],[/\\bgsa\\/([\\w\\.]+) .*safari\\//i],[d,[l,\"GSA\"]],[/headlesschrome(?:\\/([\\w\\.]+)| )/i],[d,[l,S+\" Headless\"]],[/ wv\\).+(chrome)\\/([\\w\\.]+)/i],[[l,S+\" WebView\"],d],[/droid.+ version\\/([\\w\\.]+)\\b.+(?:mobile safari|safari)/i],[d,[l,\"Android \"+T]],[/(chrome|omniweb|arora|[tizenoka]{5} ?browser)\\/v?([\\w\\.]+)/i],[l,d],[/version\\/([\\w\\.\\,]+) .*mobile\\/\\w+ (safari)/i],[d,[l,\"Mobile Safari\"]],[/version\\/([\\w(\\.|\\,)]+) .*(mobile ?safari|safari)/i],[d,l],[/webkit.+?(mobile ?safari|safari)(\\/[\\w\\.]+)/i],[l,[d,F,{\"1.0\":\"/8\",1.2:\"/1\",1.3:\"/3\",\"2.0\":\"/412\",\"2.0.2\":\"/416\",\"2.0.3\":\"/417\",\"2.0.4\":\"/419\",\"?\":\"/\"}]],[/(webkit|khtml)\\/([\\w\\.]+)/i],[l,d],[/(navigator|netscape\\d?)\\/([-\\w\\.]+)/i],[[l,\"Netscape\"],d],[/mobile vr; rv:([\\w\\.]+)\\).+firefox/i],[d,[l,q+\" Reality\"]],[/ekiohf.+(flow)\\/([\\w\\.]+)/i,/(swiftfox)/i,/(icedragon|iceweasel|camino|chimera|fennec|maemo browser|minimo|conkeror|klar)[\\/ ]?([\\w\\.\\+]+)/i,/(seamonkey|k-meleon|icecat|iceape|firebird|phoenix|palemoon|basilisk|waterfox)\\/([-\\w\\.]+)$/i,/(firefox)\\/([\\w\\.]+)/i,/(mozilla)\\/([\\w\\.]+) .+rv\\:.+gecko\\/\\d+/i,/(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|sleipnir|obigo|mosaic|(?:go|ice|up)[\\. ]?browser)[-\\/ ]?v?([\\w\\.]+)/i,/(links) \\(([\\w\\.]+)/i],[l,d],[/(cobalt)\\/([\\w\\.]+)/i],[l,[d,/master.|lts./,\"\"]]],cpu:[[/(?:(amd|x(?:(?:86|64)[-_])?|wow|win)64)[;\\)]/i],[[c,\"amd64\"]],[/(ia32(?=;))/i],[[c,D]],[/((?:i[346]|x)86)[;\\)]/i],[[c,\"ia32\"]],[/\\b(aarch64|arm(v?8e?l?|_?64))\\b/i],[[c,\"arm64\"]],[/\\b(arm(?:v[67])?ht?n?[fl]p?)\\b/i],[[c,\"armhf\"]],[/windows (ce|mobile); ppc;/i],[[c,\"arm\"]],[/((?:ppc|powerpc)(?:64)?)(?: mac|;|\\))/i],[[c,/ower/,\"\",D]],[/(sun4\\w)[;\\)]/i],[[c,\"sparc\"]],[/((?:avr32|ia64(?=;))|68k(?=\\))|\\barm(?=v(?:[1-7]|[5-7]1)l?|;|eabi)|(?=atmel )avr|(?:irix|mips|sparc)(?:64)?\\b|pa-risc)/i],[[c,D]]],device:[[/\\b(sch-i[89]0\\d|shw-m380s|sm-[ptx]\\w{2,4}|gt-[pn]\\d{2,4}|sgh-t8[56]9|nexus 10)/i],[b,[u,C],[w,f]],[/\\b((?:s[cgp]h|gt|sm)-\\w+|galaxy nexus)/i,/samsung[- ]([-\\w]+)/i,/sec-(sgh\\w+)/i],[b,[u,C],[w,m]],[/((ipod|iphone)\\d+,\\d+)/i],[b,[u,k],[w,m]],[/(ipad\\d+,\\d+)/i],[b,[u,k],[w,f]],[/\\((ip(?:hone|od)[\\w ]*);/i],[b,[u,k],[w,m]],[/\\((ipad);[-\\w\\),; ]+apple/i,/applecoremedia\\/[\\w\\.]+ \\((ipad)/i,/\\b(ipad)\\d\\d?,\\d\\d?[;\\]].+ios/i],[b,[u,k],[w,f]],[/(macintosh);/i],[b,[u,k]],[/\\b((?:ag[rs][23]?|bah2?|sht?|btv)-a?[lw]\\d{2})\\b(?!.+d\\/s)/i],[b,[u,z],[w,f]],[/(?:huawei|honor)([-\\w ]+)[;\\)]/i,/\\b(nexus 6p|\\w{2,4}e?-[atu]?[ln][\\dx][012359c][adn]?)\\b(?!.+d\\/s)/i],[b,[u,z],[w,m]],[/\\b(poco[\\w ]+)(?: bui|\\))/i,/\\b; (\\w+) build\\/hm\\1/i,/\\b(hm[-_ ]?note?[_ ]?(?:\\d\\w)?) bui/i,/\\b(redmi[\\-_ ]?(?:note|k)?[\\w_ ]+)(?: bui|\\))/i,/\\b(mi[-_ ]?(?:a\\d|one|one[_ ]plus|note lte|max|cc)?[_ ]?(?:\\d?\\w?)[_ ]?(?:plus|se|lite)?)(?: bui|\\))/i],[[b,/_/g,\" \"],[u,M],[w,m]],[/\\b(mi[-_ ]?(?:pad)(?:[\\w_ ]+))(?: bui|\\))/i],[[b,/_/g,\" \"],[u,M],[w,f]],[/; (\\w+) bui.+ oppo/i,/\\b(cph[12]\\d{3}|p(?:af|c[al]|d\\w|e[ar])[mt]\\d0|x9007|a101op)\\b/i],[b,[u,\"OPPO\"],[w,m]],[/vivo (\\w+)(?: bui|\\))/i,/\\b(v[12]\\d{3}\\w?[at])(?: bui|;)/i],[b,[u,\"Vivo\"],[w,m]],[/\\b(rmx[12]\\d{3})(?: bui|;|\\))/i],[b,[u,\"Realme\"],[w,m]],[/\\b(milestone|droid(?:[2-4x]| (?:bionic|x2|pro|razr))?:?( 4g)?)\\b[\\w ]+build\\//i,/\\bmot(?:orola)?[- ](\\w*)/i,/((?:moto[\\w\\(\\) ]+|xt\\d{3,4}|nexus 6)(?= bui|\\)))/i],[b,[u,O],[w,m]],[/\\b(mz60\\d|xoom[2 ]{0,2}) build\\//i],[b,[u,O],[w,f]],[/((?=lg)?[vl]k\\-?\\d{3}) bui| 3\\.[-\\w; ]{10}lg?-([06cv9]{3,4})/i],[b,[u,A],[w,f]],[/(lm(?:-?f100[nv]?|-[\\w\\.]+)(?= bui|\\))|nexus [45])/i,/\\blg[-e;\\/ ]+((?!browser|netcast|android tv)\\w+)/i,/\\blg-?([\\d\\w]+) bui/i],[b,[u,A],[w,m]],[/(ideatab[-\\w ]+)/i,/lenovo ?(s[56]000[-\\w]+|tab(?:[\\w ]+)|yt[-\\d\\w]{6}|tb[-\\d\\w]{6})/i],[b,[u,\"Lenovo\"],[w,f]],[/(?:maemo|nokia).*(n900|lumia \\d+)/i,/nokia[-_ ]?([-\\w\\.]*)/i],[[b,/_/g,\" \"],[u,\"Nokia\"],[w,m]],[/(pixel c)\\b/i],[b,[u,N],[w,f]],[/droid.+; (pixel[\\daxl ]{0,6})(?: bui|\\))/i],[b,[u,N],[w,m]],[/droid.+ (a?\\d[0-2]{2}so|[c-g]\\d{4}|so[-gl]\\w+|xq-a\\w[4-7][12])(?= bui|\\).+chrome\\/(?![1-6]{0,1}\\d\\.))/i],[b,[u,U],[w,m]],[/sony tablet [ps]/i,/\\b(?:sony)?sgp\\w+(?: bui|\\))/i],[[b,\"Xperia Tablet\"],[u,U],[w,f]],[/ (kb2005|in20[12]5|be20[12][59])\\b/i,/(?:one)?(?:plus)? (a\\d0\\d\\d)(?: b|\\))/i],[b,[u,\"OnePlus\"],[w,m]],[/(alexa)webm/i,/(kf[a-z]{2}wi)( bui|\\))/i,/(kf[a-z]+)( bui|\\)).+silk\\//i],[b,[u,x],[w,f]],[/((?:sd|kf)[0349hijorstuw]+)( bui|\\)).+silk\\//i],[[b,/(.+)/g,\"Fire Phone $1\"],[u,x],[w,m]],[/(playbook);[-\\w\\),; ]+(rim)/i],[b,u,[w,f]],[/\\b((?:bb[a-f]|st[hv])100-\\d)/i,/\\(bb10; (\\w+)/i],[b,[u,_],[w,m]],[/(?:\\b|asus_)(transfo[prime ]{4,10} \\w+|eeepc|slider \\w+|nexus 7|padfone|p00[cj])/i],[b,[u,y],[w,f]],[/ (z[bes]6[027][012][km][ls]|zenfone \\d\\w?)\\b/i],[b,[u,y],[w,m]],[/(nexus 9)/i],[b,[u,\"HTC\"],[w,f]],[/(htc)[-;_ ]{1,2}([\\w ]+(?=\\)| bui)|\\w+)/i,/(zte)[- ]([\\w ]+?)(?: bui|\\/|\\))/i,/(alcatel|geeksphone|nexian|panasonic|sony(?!-bra))[-_ ]?([-\\w]*)/i],[u,[b,/_/g,\" \"],[w,m]],[/droid.+; ([ab][1-7]-?[0178a]\\d\\d?)/i],[b,[u,\"Acer\"],[w,f]],[/droid.+; (m[1-5] note) bui/i,/\\bmz-([-\\w]{2,})/i],[b,[u,\"Meizu\"],[w,m]],[/\\b(sh-?[altvz]?\\d\\d[a-ekm]?)/i],[b,[u,P],[w,m]],[/(blackberry|benq|palm(?=\\-)|sonyericsson|acer|asus|dell|meizu|motorola|polytron)[-_ ]?([-\\w]*)/i,/(hp) ([\\w ]+\\w)/i,/(asus)-?(\\w+)/i,/(microsoft); (lumia[\\w ]+)/i,/(lenovo)[-_ ]?([-\\w]+)/i,/(jolla)/i,/(oppo) ?([\\w ]+) bui/i],[u,b,[w,m]],[/(archos) (gamepad2?)/i,/(hp).+(touchpad(?!.+tablet)|tablet)/i,/(kindle)\\/([\\w\\.]+)/i,/(nook)[\\w ]+build\\/(\\w+)/i,/(dell) (strea[kpr\\d ]*[\\dko])/i,/(le[- ]+pan)[- ]+(\\w{1,9}) bui/i,/(trinity)[- ]*(t\\d{3}) bui/i,/(gigaset)[- ]+(q\\w{1,9}) bui/i,/(vodafone) ([\\w ]+)(?:\\)| bui)/i],[u,b,[w,f]],[/(surface duo)/i],[b,[u,E],[w,f]],[/droid [\\d\\.]+; (fp\\du?)(?: b|\\))/i],[b,[u,\"Fairphone\"],[w,m]],[/(u304aa)/i],[b,[u,\"AT&T\"],[w,m]],[/\\bsie-(\\w*)/i],[b,[u,\"Siemens\"],[w,m]],[/\\b(rct\\w+) b/i],[b,[u,\"RCA\"],[w,f]],[/\\b(venue[\\d ]{2,7}) b/i],[b,[u,\"Dell\"],[w,f]],[/\\b(q(?:mv|ta)\\w+) b/i],[b,[u,\"Verizon\"],[w,f]],[/\\b(?:barnes[& ]+noble |bn[rt])([\\w\\+ ]*) b/i],[b,[u,\"Barnes & Noble\"],[w,f]],[/\\b(tm\\d{3}\\w+) b/i],[b,[u,\"NuVision\"],[w,f]],[/\\b(k88) b/i],[b,[u,\"ZTE\"],[w,f]],[/\\b(nx\\d{3}j) b/i],[b,[u,\"ZTE\"],[w,m]],[/\\b(gen\\d{3}) b.+49h/i],[b,[u,\"Swiss\"],[w,m]],[/\\b(zur\\d{3}) b/i],[b,[u,\"Swiss\"],[w,f]],[/\\b((zeki)?tb.*\\b) b/i],[b,[u,\"Zeki\"],[w,f]],[/\\b([yr]\\d{2}) b/i,/\\b(dragon[- ]+touch |dt)(\\w{5}) b/i],[[u,\"Dragon Touch\"],b,[w,f]],[/\\b(ns-?\\w{0,9}) b/i],[b,[u,\"Insignia\"],[w,f]],[/\\b((nxa|next)-?\\w{0,9}) b/i],[b,[u,\"NextBook\"],[w,f]],[/\\b(xtreme\\_)?(v(1[045]|2[015]|[3469]0|7[05])) b/i],[[u,\"Voice\"],b,[w,m]],[/\\b(lvtel\\-)?(v1[12]) b/i],[[u,\"LvTel\"],b,[w,m]],[/\\b(ph-1) /i],[b,[u,\"Essential\"],[w,m]],[/\\b(v(100md|700na|7011|917g).*\\b) b/i],[b,[u,\"Envizen\"],[w,f]],[/\\b(trio[-\\w\\. ]+) b/i],[b,[u,\"MachSpeed\"],[w,f]],[/\\btu_(1491) b/i],[b,[u,\"Rotor\"],[w,f]],[/(shield[\\w ]+) b/i],[b,[u,\"Nvidia\"],[w,f]],[/(sprint) (\\w+)/i],[u,b,[w,m]],[/(kin\\.[onetw]{3})/i],[[b,/\\./g,\" \"],[u,E],[w,m]],[/droid.+; (cc6666?|et5[16]|mc[239][23]x?|vc8[03]x?)\\)/i],[b,[u,R],[w,f]],[/droid.+; (ec30|ps20|tc[2-8]\\d[kx])\\)/i],[b,[u,R],[w,m]],[/(ouya)/i,/(nintendo) ([wids3utch]+)/i],[u,b,[w,p]],[/droid.+; (shield) bui/i],[b,[u,\"Nvidia\"],[w,p]],[/(playstation [345portablevi]+)/i],[b,[u,U],[w,p]],[/\\b(xbox(?: one)?(?!; xbox))[\\); ]/i],[b,[u,E],[w,p]],[/smart-tv.+(samsung)/i],[u,[w,h]],[/hbbtv.+maple;(\\d+)/i],[[b,/^/,\"SmartTV\"],[u,C],[w,h]],[/(nux; netcast.+smarttv|lg (netcast\\.tv-201\\d|android tv))/i],[[u,A],[w,h]],[/(apple) ?tv/i],[u,[b,k+\" TV\"],[w,h]],[/crkey/i],[[b,S+\"cast\"],[u,N],[w,h]],[/droid.+aft(\\w)( bui|\\))/i],[b,[u,x],[w,h]],[/\\(dtv[\\);].+(aquos)/i,/(aquos-tv[\\w ]+)\\)/i],[b,[u,P],[w,h]],[/(bravia[\\w ]+)( bui|\\))/i],[b,[u,U],[w,h]],[/(mitv-\\w{5}) bui/i],[b,[u,M],[w,h]],[/\\b(roku)[\\dx]*[\\)\\/]((?:dvp-)?[\\d\\.]*)/i,/hbbtv\\/\\d+\\.\\d+\\.\\d+ +\\([\\w ]*; *(\\w[^;]*);([^;]*)/i],[[u,G],[b,G],[w,h]],[/\\b(android tv|smart[- ]?tv|opera tv|tv; rv:)\\b/i],[[w,h]],[/((pebble))app/i],[u,b,[w,v]],[/droid.+; (glass) \\d/i],[b,[u,N],[w,v]],[/droid.+; (wt63?0{2,3})\\)/i],[b,[u,R],[w,v]],[/(quest( 2)?)/i],[b,[u,V],[w,v]],[/(tesla)(?: qtcarbrowser|\\/[-\\w\\.]+)/i],[u,[w,g]],[/droid .+?; ([^;]+?)(?: bui|\\) applew).+? mobile safari/i],[b,[w,m]],[/droid .+?; ([^;]+?)(?: bui|\\) applew).+?(?! mobile) safari/i],[b,[w,f]],[/\\b((tablet|tab)[;\\/]|focus\\/\\d(?!.+mobile))/i],[[w,f]],[/(phone|mobile(?:[;\\/]| [ \\w\\/\\.]*safari)|pda(?=.+windows ce))/i],[[w,m]],[/(android[-\\w\\. ]{0,9});.+buil/i],[b,[u,\"Generic\"]]],engine:[[/windows.+ edge\\/([\\w\\.]+)/i],[d,[l,\"EdgeHTML\"]],[/webkit\\/537\\.36.+chrome\\/(?!27)([\\w\\.]+)/i],[d,[l,\"Blink\"]],[/(presto)\\/([\\w\\.]+)/i,/(webkit|trident|netfront|netsurf|amaya|lynx|w3m|goanna)\\/([\\w\\.]+)/i,/ekioh(flow)\\/([\\w\\.]+)/i,/(khtml|tasman|links)[\\/ ]\\(?([\\w\\.]+)/i,/(icab)[\\/ ]([23]\\.[\\d\\.]+)/i],[l,d],[/rv\\:([\\w\\.]{1,9})\\b.+(gecko)/i],[d,l]],os:[[/microsoft (windows) (vista|xp)/i],[l,d],[/(windows) nt 6\\.2; (arm)/i,/(windows (?:phone(?: os)?|mobile))[\\/ ]?([\\d\\.\\w ]*)/i,/(windows)[\\/ ]?([ntce\\d\\. ]+\\w)(?!.+xbox)/i],[l,[d,F,L]],[/(win(?=3|9|n)|win 9x )([nt\\d\\.]+)/i],[[l,\"Windows\"],[d,F,L]],[/ip[honead]{2,4}\\b(?:.*os ([\\w]+) like mac|; opera)/i,/cfnetwork\\/.+darwin/i],[[d,/_/g,\".\"],[l,\"iOS\"]],[/(mac os x) ?([\\w\\. ]*)/i,/(macintosh|mac_powerpc\\b)(?!.+haiku)/i],[[l,\"Mac OS\"],[d,/_/g,\".\"]],[/droid ([\\w\\.]+)\\b.+(android[- ]x86|harmonyos)/i],[d,l],[/(android|webos|qnx|bada|rim tablet os|maemo|meego|sailfish)[-\\/ ]?([\\w\\.]*)/i,/(blackberry)\\w*\\/([\\w\\.]*)/i,/(tizen|kaios)[\\/ ]([\\w\\.]+)/i,/\\((series40);/i],[l,d],[/\\(bb(10);/i],[d,[l,_]],[/(?:symbian ?os|symbos|s60(?=;)|series60)[-\\/ ]?([\\w\\.]*)/i],[d,[l,\"Symbian\"]],[/mozilla\\/[\\d\\.]+ \\((?:mobile|tablet|tv|mobile; [\\w ]+); rv:.+ gecko\\/([\\w\\.]+)/i],[d,[l,q+\" OS\"]],[/web0s;.+rt(tv)/i,/\\b(?:hp)?wos(?:browser)?\\/([\\w\\.]+)/i],[d,[l,\"webOS\"]],[/crkey\\/([\\d\\.]+)/i],[d,[l,S+\"cast\"]],[/(cros) [\\w]+ ([\\w\\.]+\\w)/i],[[l,\"Chromium OS\"],d],[/(nintendo|playstation) ([wids345portablevuch]+)/i,/(xbox); +xbox ([^\\);]+)/i,/\\b(joli|palm)\\b ?(?:os)?\\/?([\\w\\.]*)/i,/(mint)[\\/\\(\\) ]?(\\w*)/i,/(mageia|vectorlinux)[; ]/i,/([kxln]?ubuntu|debian|suse|opensuse|gentoo|arch(?= linux)|slackware|fedora|mandriva|centos|pclinuxos|red ?hat|zenwalk|linpus|raspbian|plan 9|minix|risc os|contiki|deepin|manjaro|elementary os|sabayon|linspire)(?: gnu\\/linux)?(?: enterprise)?(?:[- ]linux)?(?:-gnu)?[-\\/ ]?(?!chrom|package)([-\\w\\.]*)/i,/(hurd|linux) ?([\\w\\.]*)/i,/(gnu) ?([\\w\\.]*)/i,/\\b([-frentopcghs]{0,5}bsd|dragonfly)[\\/ ]?(?!amd|[ix346]{1,2}86)([\\w\\.]*)/i,/(haiku) (\\w+)/i],[l,d],[/(sunos) ?([\\w\\.\\d]*)/i],[[l,\"Solaris\"],d],[/((?:open)?solaris)[-\\/ ]?([\\w\\.]*)/i,/(aix) ((\\d)(?=\\.|\\)| )[\\w\\.])*/i,/\\b(beos|os\\/2|amigaos|morphos|openvms|fuchsia|hp-ux)/i,/(unix) ?([\\w\\.]*)/i],[l,d]]},H=function(i,e){if(typeof i===t&&(e=i,i=r),!(this instanceof H))return new H(i,e).getResult();var n=i||(typeof o!==a&&o.navigator&&o.navigator.userAgent?o.navigator.userAgent:\"\"),p=e?function(i,e){var o={};for(var r in i)e[r]&&e[r].length%2==0?o[r]=e[r].concat(i[r]):o[r]=i[r];return o}(Z,e):Z;return this.getBrowser=function(){var i,e={};return e[l]=r,e[d]=r,W.call(e,n,p.browser),e.major=typeof(i=e.version)===s?i.replace(/[^\\d\\.]/g,\"\").split(\".\")[0]:r,e},this.getCPU=function(){var i={};return i[c]=r,W.call(i,n,p.cpu),i},this.getDevice=function(){var i={};return i[u]=r,i[b]=r,i[w]=r,W.call(i,n,p.device),i},this.getEngine=function(){var i={};return i[l]=r,i[d]=r,W.call(i,n,p.engine),i},this.getOS=function(){var i={};return i[l]=r,i[d]=r,W.call(i,n,p.os),i},this.getResult=function(){return{ua:this.getUA(),browser:this.getBrowser(),engine:this.getEngine(),os:this.getOS(),device:this.getDevice(),cpu:this.getCPU()}},this.getUA=function(){return n},this.setUA=function(i){return n=typeof i===s&&i.length>350?G(i,350):i,this},this.setUA(n),this};H.VERSION=\"0.7.33\",H.BROWSER=B([l,d,\"major\"]),H.CPU=B([c]),H.DEVICE=B([b,u,w,p,m,h,f,v,g]),H.ENGINE=H.OS=B([l,d]),i.exports&&(e=i.exports=H),e.UAParser=H;var $=typeof o!==a&&(o.jQuery||o.Zepto);if($&&!$.ua){var X=new H;$.ua=X.getResult(),$.ua.get=function(){return X.getUA()},$.ua.set=function(i){X.setUA(i);var e=X.getResult();for(var o in e)$.ua[o]=e[o]}}}(\"object\"==typeof window?window:n)}(a,a.exports);var t=a.exports,s=function(i){var n=this;void 0===i&&(i={});var a,s=i.osName,b=void 0===s||s,l=i.osVersion,w=void 0===l||l,u=i.deviceManufacturer,d=void 0===u||u,c=i.deviceModel,p=void 0===c||c;return{name:\"@amplitude/plugin-user-agent-enrichment-browser\",type:\"enrichment\",setup:function(i){return o(this,void 0,void 0,(function(){var e;return r(this,(function(o){return\"undefined\"!=typeof navigator&&(e=navigator.userAgent),a=new t(e).getResult(),i.loggerProvider.log(\"Installing @amplitude/plugin-user-agent-enrichment-browser.\"),[2]}))}))},execute:function(i){return o(n,void 0,void 0,(function(){var o,n,t,s;return r(this,(function(r){return o=a.browser.name,n=a.browser.version,t=a.device.model||a.os.name,s=a.device.vendor,[2,e(e(e(e(e({},i),b&&{os_name:o}),w&&{os_version:n}),d&&{device_manufacturer:s}),p&&{device_model:t})]}))}))}}};return i.plugin=s,i.userAgentEnrichmentPlugin=s,Object.defineProperty(i,\"__esModule\",{value:!0}),i}({});\n/* Amplitude User Agent Enrichment Plugin end */\n\n/* Session Replay Plugin start */\n// plugin-session-replay-browser version: 1.30.2\n<%- pluginSessionReplaySnippet %>\nvar sessionReplayPlugin = sessionReplay;\n/* Session Replay Plugin end */\n\n/* Guides and Surveys Plugin (engagement) start */\nvar engagementSnippet=function(){\"use strict\";(()=>{var Z=function(){function n(){}return n.prototype.getApplicationContext=function(){return{versionName:this.versionName,language:F(),platform:\"Web\",os:void 0,deviceModel:void 0}},n}(),F=function(){return typeof navigator<\"u\"&&(navigator.languages&&navigator.languages[0]||navigator.language)||\"\"},z=function(){function n(){this.queue=[]}return n.prototype.logEvent=function(e){this.receiver?this.receiver(e):this.queue.length<512&&this.queue.push(e)},n.prototype.setEventReceiver=function(e){this.receiver=e,this.queue.length>0&&(this.queue.forEach(function(t){e(t)}),this.queue=[])},n}(),A=function(){return A=Object.assign||function(e){for(var t,r=1,i=arguments.length;r<i;r++){t=arguments[r];for(var u in t)Object.prototype.hasOwnProperty.call(t,u)&&(e[u]=t[u])}return e},A.apply(this,arguments)};function b(n){var e=typeof Symbol==\"function\"&&Symbol.iterator,t=e&&n[e],r=0;if(t)return t.call(n);if(n&&typeof n.length==\"number\")return{next:function(){return n&&r>=n.length&&(n=void 0),{value:n&&n[r++],done:!n}}};throw new TypeError(e?\"Object is not iterable.\":\"Symbol.iterator is not defined.\")}function C(n,e){var t=typeof Symbol==\"function\"&&n[Symbol.iterator];if(!t)return n;var r=t.call(n),i,u=[],m;try{for(;(e===void 0||e-- >0)&&!(i=r.next()).done;)u.push(i.value)}catch(d){m={error:d}}finally{try{i&&!i.done&&(t=r.return)&&t.call(r)}finally{if(m)throw m.error}}return u}var L=function(n,e){var t,r,i=[\"string\",\"number\",\"boolean\",\"undefined\"],u=typeof n,m=typeof e;if(u!==m)return!1;try{for(var d=b(i),v=d.next();!v.done;v=d.next()){var I=v.value;if(I===u)return n===e}}catch(a){t={error:a}}finally{try{v&&!v.done&&(r=d.return)&&r.call(d)}finally{if(t)throw t.error}}if(n==null&&e==null)return!0;if(n==null||e==null||n.length!==e.length)return!1;var S=Array.isArray(n),E=Array.isArray(e);if(S!==E)return!1;if(S&&E){for(var p=0;p<n.length;p++)if(!L(n[p],e[p]))return!1}else{var c=Object.keys(n).sort(),o=Object.keys(e).sort();if(!L(c,o))return!1;var s=!0;return Object.keys(n).forEach(function(a){L(n[a],e[a])||(s=!1)}),s}return!0},V=\"$set\",Y=\"$unset\",H=\"$clearAll\";Object.entries||(Object.entries=function(n){for(var e=Object.keys(n),t=e.length,r=new Array(t);t--;)r[t]=[e[t],n[e[t]]];return r});var W=function(){function n(){this.identity={userProperties:{}},this.listeners=new Set}return n.prototype.editIdentity=function(){var e=this,t=A({},this.identity.userProperties),r=A(A({},this.identity),{userProperties:t});return{setUserId:function(i){return r.userId=i,this},setDeviceId:function(i){return r.deviceId=i,this},setUserProperties:function(i){return r.userProperties=i,this},setOptOut:function(i){return r.optOut=i,this},updateUserProperties:function(i){var u,m,d,v,I,S,E=r.userProperties||{};try{for(var p=b(Object.entries(i)),c=p.next();!c.done;c=p.next()){var o=C(c.value,2),s=o[0],a=o[1];switch(s){case V:try{for(var g=(d=void 0,b(Object.entries(a))),f=g.next();!f.done;f=g.next()){var P=C(f.value,2),_=P[0],h=P[1];E[_]=h}}catch(w){d={error:w}}finally{try{f&&!f.done&&(v=g.return)&&v.call(g)}finally{if(d)throw d.error}}break;case Y:try{for(var l=(I=void 0,b(Object.keys(a))),y=l.next();!y.done;y=l.next()){var _=y.value;delete E[_]}}catch(w){I={error:w}}finally{try{y&&!y.done&&(S=l.return)&&S.call(l)}finally{if(I)throw I.error}}break;case H:E={};break}}}catch(w){u={error:w}}finally{try{c&&!c.done&&(m=p.return)&&m.call(p)}finally{if(u)throw u.error}}return r.userProperties=E,this},commit:function(){return e.setIdentity(r),this}}},n.prototype.getIdentity=function(){return A({},this.identity)},n.prototype.setIdentity=function(e){var t=A({},this.identity);this.identity=A({},e),L(t,this.identity)||this.listeners.forEach(function(r){r(e)})},n.prototype.addIdentityListener=function(e){this.listeners.add(e)},n.prototype.removeIdentityListener=function(e){this.listeners.delete(e)},n}(),D=typeof globalThis<\"u\"?globalThis:typeof window<\"u\"?window:self,N=function(){function n(){this.identityStore=new W,this.eventBridge=new z,this.applicationContextProvider=new Z}return n.getInstance=function(e){return D.analyticsConnectorInstances||(D.analyticsConnectorInstances={}),D.analyticsConnectorInstances[e]||(D.analyticsConnectorInstances[e]=new n),D.analyticsConnectorInstances[e]},n}();var K=[\"boot\"];var Q=\"$default_instance\";function O(n){var i,u,m,d,v,I,S,E,p;let e=typeof window<\"u\"?window.engagement:void 0,t={_q:(i=e==null?void 0:e._q)!=null?i:[],_configuration:{apiKey:(m=(u=e==null?void 0:e._configuration)==null?void 0:u.apiKey)!=null?m:\"\",serverUrl:(d=e==null?void 0:e._configuration)==null?void 0:d.serverUrl,chatUrl:(v=e==null?void 0:e._configuration)==null?void 0:v.chatUrl,mediaUrl:(I=e==null?void 0:e._configuration)==null?void 0:I.mediaUrl,serverZone:(E=(S=e==null?void 0:e._configuration)==null?void 0:S.serverZone)!=null?E:\"US\",options:{...(p=e==null?void 0:e._configuration)==null?void 0:p.options}},init(c,o){var P,_,h;if(t._configuration.apiKey){console.log(\"Engagement SDK has already been initialized. Ignoring additional init call.\");return}t._configuration={...t._configuration,...o,apiKey:c,options:{splitting:!0,...t._configuration.options,...o==null?void 0:o.options}},(_=(P=t._configuration)==null?void 0:P.options)!=null&&_.logger&&t._configuration.options.logger.enable((h=t._configuration.options.logLevel)!=null?h:2);let s;if(o!=null&&o.cdnUrl)t._configuration.options.splitting?s=`${o.cdnUrl}/engagement-browser/prod/split/index.js`:s=o.cdnUrl+\"/engagement-browser/prod/index.min.js.gz\";else{let l=t._configuration.serverZone===\"EU\"?\"https://cdn.eu.amplitude.com\":\"https://cdn.amplitude.com\";t._configuration.options.splitting?s=`${l}/engagement-browser/prod/split/index.js`:s=`${l}/engagement-browser/prod/index.min.js.gz`}let a=null,g=()=>{if(a&&(clearTimeout(a),a=null),t._q&&t._q.length>0)for(console.warn(`Engagement SDK failed to load within ${f}ms. Resolving pending calls gracefully.`);t._q.length>0;){let l=t._q.shift();if(!l)continue;let y=l[0],w=K.includes(y);if(console.warn(`Engagement SDK method '${y}' still in queue (isAsyncMethod=${w}); attempting to resolve as no-op.`),w&&l[1]instanceof Function&&l[2]instanceof Function){let U=l[1];console.warn(`Engagement SDK method '${y}' resolved as no-op due to script loading failure`),U(void 0)}}};n(s,t._configuration.options.splitting?\"module\":void 0,o==null?void 0:o.nonce,g);let f=1e4;a=setTimeout(()=>{g()},f)},plugin(c){let o=t.init;return{name:\"@amplitude/engagement-browser\",type:\"enrichment\",async setup(s,a){var _;let g=(_=s.instanceName)!=null?_:Q,f=N.getInstance(g).identityStore;o(s.apiKey,{serverZone:s.serverZone,...c,options:{logLevel:s.logLevel,logger:s.loggerProvider,...c==null?void 0:c.options}});let P=[{track:h=>{a.track(h)}}];await window.engagement.boot({user:()=>{let h=f.getIdentity();return{user_id:a.getUserId(),device_id:a.getDeviceId(),user_properties:h.userProperties,getSessionId:a.getSessionId}},integrations:P}),f.addIdentityListener(h=>{var l,y,w,U;if(!((l=window.engagement)!=null&&l._.user)||!((y=window.engagement)!=null&&y._analytics.hasBooted)){console.warn(\"Engagement SDK not booted. Ignoring identity change.\");return}((U=(w=window.engagement)==null?void 0:w._.user)==null?void 0:U.user_id)!==h.userId?(window.engagement.shutdown(),window.engagement.boot({user:()=>{let G=f.getIdentity();return{user_id:a.getUserId(),device_id:a.getDeviceId(),user_properties:G.userProperties,getSessionId:a.getSessionId}},integrations:P})):window.engagement._setUserProperties(h.userProperties)})},async execute(s){return window.engagement.forwardEvent(s),s}}}},r=t;return new Proxy(t,{get:function(c,o){if(o in r)return r[o];if(o!==\"then\")return o===\"gs\"||o===\"rc\"?new Proxy({},{get:function(s,a){return function(){let g=Array.from(arguments),f=`${o}.${a}`;g.unshift(f),t._q.push(g)}}}):K.includes(o)?function(){let s=Array.prototype.slice.call(arguments);return new Promise((a,g)=>{s.unshift(o,a,g),t._q.push(s)})}:function(){let s=Array.prototype.slice.call(arguments);s.unshift(o),t._q.push(s)}}})}var k=(i=>(i.Local=\"https://local.amplitude.com:3010/\",i.Staging=\"https://apps.stag2.amplitude.com/\",i.Production=\"https://app.amplitude.com/\",i.ProductionEU=\"https://app.eu.amplitude.com/\",i))(k||{}),q=n=>{if(typeof window<\"u\"&&window.opener)for(let e of Object.values(k))window.opener.postMessage({message:n},e)};function J(n,e,t,r){for(let i of n){let u=document.createElement(\"script\");u.src=i,u.id=\"engagement-sdk-bundle\",t&&u.setAttribute(\"nonce\",t),e&&u.setAttribute(\"type\",e),r&&(u.onerror=r),document.getElementsByTagName(\"head\")[0].appendChild(u)}}var x=()=>(q(\"ENGAGEMENT_SNIPPET\"),O((n,e,t,r)=>J([n||\"https://cdn.amplitude.com/engagement-browser/prod/index.min.js.gz\"],e,t,r)));var B=\"{{SERVER_ZONE}}\",R=\"{{SERVER_URL}}\",X=\"{{INSTALL_PLUGIN}}\",j=\"{{HELP_CENTER_ENABLED}}\",ee=\"{{AUTO_INIT}}\";window.engagement=x();var M=B!==\"\"?B:void 0,$=R!==\"\"?R:void 0,T={options:{helpCenterEnabled:j===\"true\"}};$&&(T.serverUrl=$);M&&(T.serverZone=M);setTimeout(()=>{var n,e;(e=(n=window.engagement)==null?void 0:n._configuration)!=null&&e.apiKey||(X===\"true\"&&window.amplitude?window.amplitude.add(window.engagement.plugin(T)):ee===\"true\"&&window.engagement.init(\"{{YOUR_API_KEY}}\",T))},500);})();};\n/* Guides and Surveys Plugin (engagement) end */\n\n/* Amplitude Wrapper begin */\nconst LOG_PREFIX = '[Amplitude / GTM]';\n\n(function(a,p) {\n  // If window.amplitudeGTM doesn't exist, return\n  const globalAmplitude = a.amplitudeGTM;\n  if (!globalAmplitude || typeof globalAmplitude.init !== 'function') return;\n\n  // Enumerate available events\n  var eventEnum = [\n      'init',\n      'track',\n      'identify',\n      'setGroup',\n      'groupIdentify',\n      'revenue',\n      'flush',\n      'getUserId',\n      'setUserId',\n      'getSessionId',\n      'setSessionId',\n      'setDeviceId',\n      'getDeviceId',\n      'reset',\n      'setOptOut',\n      'setTransport'\n  ];\n\n  var identifyEnum = [\n      'add',\n      'append',\n      'clearAll',\n      'prepend',\n      'set',\n      'setOnce',\n      'remove',\n      'preInsert',\n      'postInsert',\n      'unset'\n  ];\n\n  /* To work with the identify API, pass an array of identify operations (each an array in itself)\n   * with the command and parameters included.\n   *\n   * window._amplitude('identify', [\n   *     ['add', 'someUserProp', 1],\n   *     ['add', 'someOtherUserProp', 2],\n   *     ['prepend', 'anotherUserProp', 'someValue']\n   *     ['unset', 'unsetUserProp', 'value is ignored']\n   *     ['clearAll', 'key is ignored', 'value is ignored']\n   * ]);\n   *\n   */\n  var identify = function(client, args, group) {\n      args = args.shift();\n\n      // Validate identify args\n      if (!Array.isArray(args) || args.length === 0) return;\n\n      var identifyInstance = new globalAmplitude.Identify();\n\n      // Loop through the commands array and execute each\n      args.forEach(function(identifyParams) {\n          // If the operation is not in array format, return\n          if (!Array.isArray(identifyParams)) return;\n\n          var cmd = identifyParams.shift();\n\n          // If not a valid \"identify\" command, return\n          if (identifyEnum.indexOf(cmd) === -1) return;\n\n          if (cmd === 'unset') {\n            identifyInstance.unset(identifyParams[0]);\n          }\n\n          if (cmd === 'clearAll') {\n            identifyInstance.clearAll();\n          }\n\n          identifyInstance[cmd].apply(identifyInstance, identifyParams);\n      });\n\n      // If this API is used with groupIdentify, return the Identify object\n      if (group === true) return identifyInstance;\n\n      client.identify(identifyInstance);\n  };\n\n  /* The groupIdentify API is similar to identify, except you also need to collect\n   * the group name and type in addition to the Identify array.\n   *\n   * window._amplitude(\n   *   'groupIdentify',\n   *   'groupType',\n   *   'groupName',\n   *   [\n   *     ['add', 'someGroupUserProp', 1],\n   *     ['prepend', 'someOtherGroupUserProp', 'someValue']\n   *   ]\n   * );\n   *\n   */\n  var groupIdentify = function(client, args) {\n      // Validate the arguments\n      if (args.length < 3) return;\n      if (typeof args[0] !== 'string' || typeof args[1] !== 'string') return;\n      if (!Array.isArray(args[2]) || args[2].length === 0) return;\n\n      // Get the Identify instance object\n      var groupIdentifyInstance = identify(client, [args[2]], true);\n\n      client.groupIdentify(args[0], args[1], groupIdentifyInstance);\n  };\n\n  /* To send revenue, you need to pass an object to the command:\n   *\n   * {\n   *   productId: 'product_id', // required\n   *   price: 10.88, // required\n   *   quantity: 1,\n   *   revenueType: 'purchase',\n   *   eventProperties: {'someKey': 'someValue}\n   * }\n   *\n   */\n  var revenue = function(client, args) {\n      args = args.shift();\n      // Validate revenue args\n      if (!args.price || !args.productId)  return;\n\n      var revenue = new globalAmplitude.Revenue()\n          .setProductId(args.productId)\n          .setQuantity(args.quantity || 1)\n          .setPrice(args.price)\n          .setRevenue(args.revenue || (args.price * (args.quantity || 1)));\n          if (args.revenueType) {\n            revenue.setRevenueType(args.revenueType)\n          }\n          if (args.eventProperties) {\n            revenue.setEventProperties(args.eventProperties)\n          }\n          if (args.currency) {\n            revenue.setCurrency(args.currency);\n          }\n          if (args.receipt) {\n            revenue.setReceipt(args.receipt);\n          }\n          if (args.receiptSig) {\n            revenue.setReceiptSig(args.receiptSig);\n          }\n      client.revenue(revenue);\n  };\n\n  var gtmLibraryPlugin = () => {\n      return {\n          name: 'gtm-library-enrichment',\n          type: 'enrichment',\n          setup: async () => undefined,\n          execute: async (event) => {\n              event['library'] = `amplitude-ts-gtm-snippet/${version}`;\n              return event;\n          },\n      };\n  };\n\n  var getRegExp = function(expression) {\n    try {\n      return new RegExp(expression);\n    } catch (e) {\n      console.error(`${LOG_PREFIX} - ${e}`);\n      return null;\n    }\n  };\n\n  var getValidExp = function (expArray) {\n    return expArray?.reduce((acc, item) => {\n      var regExp = getRegExp(item);\n      if (regExp !== null) {\n        acc.push(regExp);\n      }\n      return acc;\n    }, []);\n  };\n\n\n  var init = function(client, args) {\n      const argsLength = args.length;\n      const configuration = args[argsLength - 1];\n\n      if (configuration.autocapture.attribution) {\n        const excludeReferrers = [\n          ...(configuration.autocapture.attribution.excludeReferrersText || []),\n          ...(getValidExp(configuration.autocapture.attribution.excludeReferrersRegex) || [])\n        ];\n        delete configuration.autocapture.attribution.excludeReferrersText;\n        delete configuration.autocapture.attribution.excludeReferrersRegex;\n        // if excludeReferrers is empty, use default\n        if (excludeReferrers.length !== 0) {\n          configuration.autocapture.attribution.excludeReferrers = excludeReferrers;\n        }\n      }\n\n      if (configuration.autocapture.elementInteractions) {\n        const pageUrlAllowlist = [\n          ...(configuration.autocapture.elementInteractions.pageUrlAllowlistString || []),\n          ...(getValidExp(configuration.autocapture.elementInteractions.pageUrlAllowlistRegex) || [])\n        ];\n        delete configuration.autocapture.elementInteractions.pageUrlAllowlistString;\n        delete configuration.autocapture.elementInteractions.pageUrlAllowlistRegex;\n        // if pageUrlAllowlist is empty, use default\n        if (pageUrlAllowlist.length !== 0) {\n          configuration.autocapture.elementInteractions.pageUrlAllowlist = pageUrlAllowlist;\n        }\n\n\n        const dataAttributePrefix = [\n          ...(configuration.autocapture.elementInteractions.dataAttributePrefixString || []),\n          ...(getValidExp(configuration.autocapture.elementInteractions.dataAttributePrefixRegex) || [])\n        ]\n        delete configuration.autocapture.elementInteractions.dataAttributePrefixString;\n        delete configuration.autocapture.elementInteractions.dataAttributePrefixRegex;\n        // if dataAttributePrefix is empty, use default\n        if (dataAttributePrefix.length !== 0) {\n          configuration.autocapture.elementInteractions.dataAttributePrefix = dataAttributePrefix;\n        }\n      }\n\n      if (configuration.autocapture.networkTracking) {\n        const networkTracking = configuration.autocapture.networkTracking;\n        const captureRules = networkTracking.captureRules || [];\n        captureRules.forEach((rule) => {\n          rule.urls = [\n            ...(rule.urls || []),\n            ...(getValidExp(rule.urlsRegex) || [])\n          ];\n          if (rule.urls.length === 0) {\n            delete rule.urls;\n          }\n          delete rule.urlsRegex;\n        });\n      }\n\n      const userAgentEnrichmentOptions = configuration['userAgentEnrichmentOptions'];\n      const pageViewLegacy = configuration['pageViewLegacy'];\n      const sessionReplay = configuration['sessionReplay'];\n      const guidesSurveys = configuration['guidesSurveys'];\n\n      if (userAgentEnrichmentOptions) {\n        client.add(amplitudeUserAgentEnrichmentPlugin.userAgentEnrichmentPlugin(userAgentEnrichmentOptions));\n      }\n\n      if (pageViewLegacy) {\n        client.add(amplitudePageViewV1EnrichmentPlugin.pageViewV1EnrichmentPlugin())\n      }\n\n      if(sessionReplay) {\n        client.add(sessionReplayPlugin.plugin());\n      }\n\n      if (guidesSurveys) {\n        // Only initiate G/S here, otherwise, we'll auto-install the proxy for users who don't need it\n        engagementSnippet();\n        client.add(window.engagement.plugin());\n      }\n\n      // as plugin order cannot be adjusted, init first then add library plugin to overwrite the library value\n      let promise = client.init(...args).promise;\n      promise.then(\n          () => client.add(gtmLibraryPlugin())\n      );\n      return promise;\n  };\n\n\n  // Build the command wrapper logic\n  a[p] = a[p] || function() {\n      // Build array out of arguments\n      var args = [].slice.call(arguments, 0);\n\n      // Pick the first argument as the instance name\n      var name = args.shift();\n      var client = !name ? globalAmplitude : globalAmplitude._iq[name];\n      if (!client) {\n        client = globalAmplitude.createInstance(name);\n      }\n\n      // Pick the first argument as the command\n      var cmd = args.shift();\n\n      // If cmd is not one of the available ones, return\n      if (eventEnum.indexOf(cmd) === -1) return;\n\n      // Handle Revenue separately\n      if (cmd === 'revenue') return revenue(client, args);\n\n      // Handle Identify separately\n      if (cmd === 'identify') return identify(client, args);\n\n      // Handle GroupIdentify separately\n      if (cmd === 'groupIdentify') return groupIdentify(client, args);\n\n      if (cmd === 'init') return init(client, args);\n\n      // Otherwise call the method and pass the arguments\n      return client[cmd].apply(this, args);\n  };\n})(window, '_amplitude')\n/* Amplitude wrapper end */\n"
  },
  {
    "path": "packages/gtm-snippet/e2e/gtm-snippet.spec.ts",
    "content": "import { test, expect } from '@playwright/test';\nimport { parseRequestBody } from './helpers';\n\ntest.describe('GTM Snippet Page', () => {\n  let requests: any[] = [];\n\n  test.beforeEach(async ({ page }) => {\n    requests = [];\n    // Intercept Amplitude API calls\n    await page.route('https://api2.amplitude.com/2/httpapi', async (route) => {\n      const request = route.request();\n      const data = parseRequestBody(request);\n      if (data) {\n        requests.push(data);\n      }\n      await route.continue();\n    });\n  });\n\n  test('should load GTM snippet page and track event', async ({ page }) => {\n    // Navigate to the GTM snippet page\n    const response = await page.goto('/gtm-snippet/gtm-snippet.html', {\n      waitUntil: 'networkidle',\n      timeout: 30000,\n    });\n\n    // Check if the response was successful\n    expect(response?.status()).toBe(200);\n\n    // Wait for the Amplitude SDK to be available\n    await page.waitForFunction(\n      () => {\n        return typeof (window as any).amplitude !== 'undefined';\n      },\n      { timeout: 10000 },\n    );\n\n    // Verify amplitude is defined\n    const amplitudeDefined = await page.evaluate(() => {\n      return typeof (window as any).amplitude !== 'undefined';\n    });\n    expect(amplitudeDefined).toBe(true);\n\n    // track an event and immediately flush to avoid batching delay\n    await page.evaluate(async () => {\n      (window as any).amplitude.track('GTM Snippet Test');\n      await (window as any).amplitude.flush();\n    });\n\n    // Wait for network requests to complete\n    await page.waitForLoadState('networkidle');\n    // wait up to 10 seconds for the request to be made\n    for (let i = 0; i < 20; i++) {\n      if (requests.length > 0) break;\n      await page.waitForTimeout(500);\n    }\n\n    // Verify the GTM Snippet Test event was tracked\n    const events = requests[0].events;\n    expect(events).toBeDefined();\n    expect(events.length).toBeGreaterThan(0);\n    const gtmSnippetEvent = events.find((event: any) => event.event_type === 'GTM Snippet Test');\n    expect(gtmSnippetEvent).toBeDefined();\n    expect(gtmSnippetEvent.event_type).toBe('GTM Snippet Test');\n  });\n});\n"
  },
  {
    "path": "packages/gtm-snippet/e2e/helpers.ts",
    "content": "import { gunzipSync } from 'zlib';\nimport type { Request } from '@playwright/test';\n\n/**\n * Parse request body as JSON. Decompresses gzip when Content-Encoding: gzip is set.\n * Uses postDataBuffer() for gzip so we get raw bytes; uses postData() for plain JSON.\n */\nexport function parseRequestBody(request: Request): Record<string, unknown> | undefined {\n  const contentEncoding = request.headers()['content-encoding'];\n\n  if (contentEncoding === 'gzip') {\n    const buffer = request.postDataBuffer();\n    if (!buffer || buffer.length === 0) return undefined;\n    const bodyStr = gunzipSync(buffer).toString('utf8');\n    return JSON.parse(bodyStr) as Record<string, unknown>;\n  }\n\n  const postData = request.postData();\n  if (!postData) return undefined;\n  return JSON.parse(postData) as Record<string, unknown>;\n}\n"
  },
  {
    "path": "packages/gtm-snippet/package.json",
    "content": "{\n  \"private\": true,\n  \"name\": \"@amplitude/gtm-snippet\",\n  \"description\": \"Amplitude JS SDK Wrapper for use with Google Tag Manager\",\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"tag\": \"latest\"\n  },\n  \"scripts\": {\n    \"build\": \"pnpm build:template && pnpm build:bundle\",\n    \"build:bundle\": \"rollup --config rollup.config.js\",\n    \"build:template\": \"node ./scripts/build-snippet.js\",\n    \"prepublishOnly\": \"pnpm build\",\n    \"publish:s3\": \"node ./scripts/upload-to-s3.js\",\n    \"version\": \"node ./scripts/version.js\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/amplitude/Amplitude-TypeScript.git\"\n  },\n  \"author\": \"Amplitude <support@amplitude.com>\",\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"@amplitude/analytics-browser\": \"workspace:*\",\n    \"@amplitude/plugin-session-replay-browser\": \"workspace:*\"\n  },\n  \"devDependencies\": {\n    \"@amplitude/eslint-plugin-amplitude\": \"^1.0.1\",\n    \"@aws-sdk/client-s3\": \"^3.229.0\",\n    \"@rollup/plugin-json\": \"5.0.0\",\n    \"compression-webpack-plugin\": \"^11.1.0\",\n    \"ejs\": \"^3.1.9\",\n    \"eslint\": \"^8.2.0\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-prettier\": \"^4.0.0\",\n    \"prettier\": \"^2.4.1\",\n    \"rollup\": \"^2.79.1\",\n    \"rollup-plugin-gzip\": \"^3.1.0\",\n    \"rollup-plugin-terser\": \"^7.0.2\"\n  }\n}\n"
  },
  {
    "path": "packages/gtm-snippet/playwright.config.ts",
    "content": "import { defineConfig } from '@playwright/test';\nimport baseConfig from '../../playwright.config';\n\nexport default defineConfig({\n  ...baseConfig,\n});\n\n"
  },
  {
    "path": "packages/gtm-snippet/rollup.config.js",
    "content": "import { gtmSnippetBundle } from '../../scripts/build/rollup.config';\n\nexport default [gtmSnippetBundle];\n"
  },
  {
    "path": "packages/gtm-snippet/scripts/build-snippet.js",
    "content": "const fs = require('fs');\nconst path = require('path');\nconst ejs = require('ejs');\n\n\nconst templatePath = path.join(__dirname, '..', 'amplitude-wrapper.js.ejs');\nconst outputPath = path.join(__dirname, '..', 'lib', 'amplitude-wrapper.js');\nfs.mkdirSync(path.join(__dirname, '..', 'lib'), { recursive: true });\n\n// Read the analytics browser snippet\nconst analyticsSnippetPath = path.join(__dirname, '..', '..', 'analytics-browser', 'lib', 'scripts','amplitude-gtm-snippet-min.js');\nconsole.log('Reading analytics browser snippet...');\nconst analyticsBrowserSnippet = fs.readFileSync(analyticsSnippetPath, 'utf8');\n\n// Read the plugin snippet\nconst pluginSnippetPath = path.join(__dirname, '..', '..', 'plugin-session-replay-browser', 'lib', 'scripts','plugin-session-replay-browser-min.js');\nconsole.log('Reading plugin snippet...');\nconst pluginSessionReplaySnippet = fs.readFileSync(pluginSnippetPath, 'utf8');\n\n// Read and process the EJS template\nconsole.log('Processing EJS template...');\nconst template = fs.readFileSync(templatePath, 'utf8');\n\n// Render the template with the snippet\nconst rendered = ejs.render(template, {\n  analyticsBrowserSnippet,\n  pluginSessionReplaySnippet,\n});\n\n// Write the output file\nconsole.log('Writing output file...');\nfs.writeFileSync(outputPath, rendered);\n\nconsole.log('✅ Successfully built amplitude-wrapper.js from template');\n"
  },
  {
    "path": "packages/gtm-snippet/scripts/upload-to-s3.js",
    "content": "const fs = require('fs');\nconst path = require('path');\nconst analyticsBrowserPkg = require(path.join(process.cwd(), '..', 'analytics-browser', 'package.json'));\nconst { S3Client, PutObjectCommand, HeadObjectCommand } = require('@aws-sdk/client-s3');\nconst bucket = process.env.S3_BUCKET_NAME;\n\nconst extension = 'min.js.br';\nconst filename = 'analytics-browser-gtm-wrapper';\nconst gtmWrapper = `./lib/scripts/${filename}.${extension}`;\n\nconst getVersion = () => analyticsBrowserPkg.version;\nlet deployed = false;\nconst body = fs.readFileSync(path.join(process.cwd(), gtmWrapper));\nconst key = `libs/${filename}-${getVersion()}.${extension}`;\n\nif (process.env.DRY_RUN) {\n  console.log(`[Publish to AWS S3] Dry run. Skipping upload job.`);\n  console.log(`Publishing ${key} to ${bucket}...`);\n  return;\n}\n\nconst client = new S3Client();\nconst headObject = new HeadObjectCommand({\n  Bucket: bucket,\n  Key: key,\n});\n\n\nconsole.log('[Publish to AWS S3] START');\nconst promise = client\n    .send(headObject)\n    .then(() => {\n      console.log(`[Publish to AWS S3] ${key} exists in target bucket. Skipping upload job.`);\n    })\n    .catch(() => {\n      console.log(`[Publish to AWS S3] ${key} does not exist in target bucket. Uploading to S3...`);\n      const putObject = new PutObjectCommand({\n        ACL: 'public-read',\n        Body: body,\n        Bucket: bucket,\n        CacheControl: 'max-age=31536000',\n        ContentType: 'application/javascript',\n        ContentEncoding: 'br',\n        Key: key,\n      });\n      return client\n        .send(putObject)\n        .then(() => {\n          console.log(`[Publish to AWS S3] Upload success for ${key}.`);\n          deployed = true;\n        })\n        .catch(console.error);\n    });\n\n  promise\n  .then(() => {\n    if (deployed) {\n      console.log(`[Publish to AWS S3] Success! Deployed.`);\n    } else {\n      console.log(`[Publish to AWS S3] Complete! Nothing to deploy.`);\n    }\n    console.log('[Publish to AWS S3] END');\n  })\n  .catch(console.log);"
  },
  {
    "path": "packages/gtm-snippet/scripts/version.js",
    "content": "const fs = require('fs');\nconst path = require('path');\n\nconsole.log('[GTM Snippet Version Sync] START');\n\ntry {\n  // Read current package.json\n  const currentPkgPath = path.join(__dirname, '..', 'package.json');\n  const currentPkg = JSON.parse(fs.readFileSync(currentPkgPath, 'utf8'));\n  \n  // Read analytics-browser package.json\n  const analyticsPkgPath = path.join(__dirname, '..', '..', 'analytics-browser', 'package.json');\n  const analyticsPkg = JSON.parse(fs.readFileSync(analyticsPkgPath, 'utf8'));\n  \n  console.log(`[GTM Snippet Version Sync] Current version: ${currentPkg.version}`);\n  console.log(`[GTM Snippet Version Sync] Analytics browser version: ${analyticsPkg.version}`);\n  \n  // Update version to match analytics-browser\n  currentPkg.version = analyticsPkg.version;\n  \n  // Write updated package.json\n  fs.writeFileSync(currentPkgPath, JSON.stringify(currentPkg, null, 2) + '\\n');\n  \n  console.log(`[GTM Snippet Version Sync] Updated gtm-snippet version to: ${analyticsPkg.version}`);\n  console.log('[GTM Snippet Version Sync] SUCCESS');\n} catch (error) {\n  console.error('[GTM Snippet Version Sync] ERROR:', error.message);\n  process.exit(1);\n}\n"
  },
  {
    "path": "packages/gtm-snippet/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"e2e/**/*\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"esModuleInterop\": true,\n    \"lib\": [\"dom\"],\n    \"noEmit\": true,\n    \"rootDir\": \".\"\n  }\n}\n\n\n\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.27.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.27.0...@amplitude/plugin-autocapture-browser@1.27.1) (2026-05-05)\n\n\n### Bug Fixes\n\n* **autocapture:** add code lines to event properties for long task ([#1701](https://github.com/amplitude/Amplitude-TypeScript/issues/1701)) ([dbca5c0](https://github.com/amplitude/Amplitude-TypeScript/commit/dbca5c000447907d7ae5570ef9fa03f7ad4d5a81))\n* **plugin-autocapture-browser:** strip URL params from Page URL in Viewport Content Updated ([#1713](https://github.com/amplitude/Amplitude-TypeScript/issues/1713)) ([9797cd7](https://github.com/amplitude/Amplitude-TypeScript/commit/9797cd74790efa89fc7ef218a919993898d0dbee))\n\n\n\n\n\n# [1.27.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.26.1...@amplitude/plugin-autocapture-browser@1.27.0) (2026-04-28)\n\n\n### Features\n\n* remove experimental request body compression backdoor ([#1699](https://github.com/amplitude/Amplitude-TypeScript/issues/1699)) ([98ecb9d](https://github.com/amplitude/Amplitude-TypeScript/commit/98ecb9dc1f3658cf6d0dfae1e9784335c9d33b5e))\n\n\n\n\n\n## [1.26.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.26.0...@amplitude/plugin-autocapture-browser@1.26.1) (2026-04-22)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n# [1.26.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.25.3...@amplitude/plugin-autocapture-browser@1.26.0) (2026-04-21)\n\n\n### Features\n\n* add long task tracking ([#1622](https://github.com/amplitude/Amplitude-TypeScript/issues/1622)) ([d995e1f](https://github.com/amplitude/Amplitude-TypeScript/commit/d995e1f2c098441808d65f6c171e171587e37ac2))\n\n\n\n\n\n## [1.25.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.25.2...@amplitude/plugin-autocapture-browser@1.25.3) (2026-04-14)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.25.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.25.1...@amplitude/plugin-autocapture-browser@1.25.2) (2026-04-09)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.25.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.25.0...@amplitude/plugin-autocapture-browser@1.25.1) (2026-04-01)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n# [1.25.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.24.2...@amplitude/plugin-autocapture-browser@1.25.0) (2026-03-26)\n\n\n### Features\n\n* **autocapture:** add viewportContentUpdated support to remote config ([#1621](https://github.com/amplitude/Amplitude-TypeScript/issues/1621)) ([f40b150](https://github.com/amplitude/Amplitude-TypeScript/commit/f40b150ddb44da9c69bc97da69f9ba003d1eb7d6))\n\n\n\n\n\n## [1.24.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.24.1...@amplitude/plugin-autocapture-browser@1.24.2) (2026-03-23)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.24.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.24.0...@amplitude/plugin-autocapture-browser@1.24.1) (2026-03-20)\n\n\n### Bug Fixes\n\n* **analytics-browser:** double thrashed cursor threshold ([#1604](https://github.com/amplitude/Amplitude-TypeScript/issues/1604)) ([32cb4b6](https://github.com/amplitude/Amplitude-TypeScript/commit/32cb4b63ddce39dc6b68d3ae3b3798b0ae73ccd4))\n\n\n\n\n\n# [1.24.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.23.7...@amplitude/plugin-autocapture-browser@1.24.0) (2026-03-19)\n\n\n### Features\n\n* **autocapture:** zoning beta  ([#1589](https://github.com/amplitude/Amplitude-TypeScript/issues/1589)) ([2bb3608](https://github.com/amplitude/Amplitude-TypeScript/commit/2bb36088dc1342512ba0289fb1108ed8a61361f6))\n\n\n\n\n\n## [1.23.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.23.6...@amplitude/plugin-autocapture-browser@1.23.7) (2026-03-17)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.23.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.23.5...@amplitude/plugin-autocapture-browser@1.23.6) (2026-03-16)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.23.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.23.4...@amplitude/plugin-autocapture-browser@1.23.5) (2026-03-13)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.23.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.23.3...@amplitude/plugin-autocapture-browser@1.23.4) (2026-03-12)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.23.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.23.2...@amplitude/plugin-autocapture-browser@1.23.3) (2026-03-09)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.23.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.23.1...@amplitude/plugin-autocapture-browser@1.23.2) (2026-03-05)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.23.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.23.0...@amplitude/plugin-autocapture-browser@1.23.1) (2026-03-03)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n# [1.23.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.22.3...@amplitude/plugin-autocapture-browser@1.23.0) (2026-03-03)\n\n\n### Features\n\n* manual opt in gzip ([#1568](https://github.com/amplitude/Amplitude-TypeScript/issues/1568)) ([303c130](https://github.com/amplitude/Amplitude-TypeScript/commit/303c130429c51b0913f3903db4ace5263e1c78e7))\n\n\n\n\n\n## [1.22.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.22.2...@amplitude/plugin-autocapture-browser@1.22.3) (2026-02-26)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.22.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.22.1...@amplitude/plugin-autocapture-browser@1.22.2) (2026-02-24)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.22.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.22.0...@amplitude/plugin-autocapture-browser@1.22.1) (2026-02-20)\n\n\n### Bug Fixes\n\n* **autocapture:** remove cloneNode in getText can cause duplicate network requests ([#1546](https://github.com/amplitude/Amplitude-TypeScript/issues/1546)) ([b75f696](https://github.com/amplitude/Amplitude-TypeScript/commit/b75f6969e5cc1baf7f6fc6bd585bd8f976b87620))\n\n\n\n\n\n# [1.22.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.21.0...@amplitude/plugin-autocapture-browser@1.22.0) (2026-02-19)\n\n\n### Features\n\n* screenshot capture messenger ([#1535](https://github.com/amplitude/Amplitude-TypeScript/issues/1535)) ([93ef551](https://github.com/amplitude/Amplitude-TypeScript/commit/93ef551ff0ab7dc48014aa5fa25841437d641993))\n\n\n\n\n\n# [1.21.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.20.0...@amplitude/plugin-autocapture-browser@1.21.0) (2026-02-17)\n\n\n### Features\n\n* **analytics-browser:** add setIdentity() ([#1517](https://github.com/amplitude/Amplitude-TypeScript/issues/1517)) ([314b3c1](https://github.com/amplitude/Amplitude-TypeScript/commit/314b3c1b7ee5b0ef135848a66156eb2874daec5f))\n\n\n\n\n\n# [1.20.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.19.0...@amplitude/plugin-autocapture-browser@1.20.0) (2026-02-10)\n\n\n### Bug Fixes\n\n* ignore errors that are not ErrorEvent ([#1512](https://github.com/amplitude/Amplitude-TypeScript/issues/1512)) ([366d7eb](https://github.com/amplitude/Amplitude-TypeScript/commit/366d7ebed2e10d46cf46e301650f0c52d82047ed))\n\n\n### Features\n\n* **analytics-browser:** [@experimental](https://github.com/experimental) add Thrashed Cursor frustration signal ([#1523](https://github.com/amplitude/Amplitude-TypeScript/issues/1523)) ([376b034](https://github.com/amplitude/Amplitude-TypeScript/commit/376b0342716057c82430ab72c0fc5bab55bc0dba))\n\n\n\n\n\n# [1.19.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.18.7...@amplitude/plugin-autocapture-browser@1.19.0) (2026-01-26)\n\n\n### Features\n\n* **analytics-browser:** support Error Clicks in frustration interactions ([#1491](https://github.com/amplitude/Amplitude-TypeScript/issues/1491)) ([d6f4c59](https://github.com/amplitude/Amplitude-TypeScript/commit/d6f4c59b4d71f8fe1e0e906221f2c6469a643cf9))\n\n\n\n\n\n## [1.18.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.18.6...@amplitude/plugin-autocapture-browser@1.18.7) (2026-01-21)\n\n\n### Bug Fixes\n\n* **analytics-browser:** ignore right clicks when tracking dead clicks ([#1496](https://github.com/amplitude/Amplitude-TypeScript/issues/1496)) ([752b4c0](https://github.com/amplitude/Amplitude-TypeScript/commit/752b4c0d9f22fcaa4b920b6fff09455a58f92da2))\n* **autocapture:** fix config key for page actions ([#1488](https://github.com/amplitude/Amplitude-TypeScript/issues/1488)) ([267b73d](https://github.com/amplitude/Amplitude-TypeScript/commit/267b73d8e857e170fbff615b75ddf6887093a25a))\n\n\n\n\n\n## [1.18.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.18.5...@amplitude/plugin-autocapture-browser@1.18.6) (2026-01-15)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.18.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.18.4...@amplitude/plugin-autocapture-browser@1.18.5) (2026-01-14)\n\n\n### Bug Fixes\n\n* **plugin-autocapture-browser:** allow selective configuration of frustration interactions ([#1489](https://github.com/amplitude/Amplitude-TypeScript/issues/1489)) ([5350f5b](https://github.com/amplitude/Amplitude-TypeScript/commit/5350f5b53d134b516f1e0e0cd202090015751ce0))\n\n\n\n\n\n## [1.18.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.18.3...@amplitude/plugin-autocapture-browser@1.18.4) (2026-01-14)\n\n\n### Bug Fixes\n\n* **plugin-autocapture-browser:** apply rage clicks to window over viewport ([#1459](https://github.com/amplitude/Amplitude-TypeScript/issues/1459)) ([ee71e48](https://github.com/amplitude/Amplitude-TypeScript/commit/ee71e48b81a5c22f236df67ad6aa23c25ce0bffc))\n* **plugin-autocapture-browser:** do not trigger rage click when text being highlighted ([#1471](https://github.com/amplitude/Amplitude-TypeScript/issues/1471)) ([7564033](https://github.com/amplitude/Amplitude-TypeScript/commit/7564033a7a4759c49015738fe3ea49ec1475dbe8))\n* **plugin-autocapture-browser:** Remove unused rxjs dependency in plugin-autocapture-browser ([#1484](https://github.com/amplitude/Amplitude-TypeScript/issues/1484)) ([dcbce97](https://github.com/amplitude/Amplitude-TypeScript/commit/dcbce97c86f2907bfae9cc421821f21d193feb06))\n\n\n\n\n\n## [1.18.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.18.2...@amplitude/plugin-autocapture-browser@1.18.3) (2025-12-24)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.18.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.18.1...@amplitude/plugin-autocapture-browser@1.18.2) (2025-12-16)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.18.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.18.0...@amplitude/plugin-autocapture-browser@1.18.1) (2025-12-09)\n\n\n### Bug Fixes\n\n* truncate large href ([#1427](https://github.com/amplitude/Amplitude-TypeScript/issues/1427)) ([a4b626b](https://github.com/amplitude/Amplitude-TypeScript/commit/a4b626be02c4d3805bd8378bbdc0bad1eeb21089))\n\n\n\n\n\n# [1.18.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.17.4...@amplitude/plugin-autocapture-browser@1.18.0) (2025-11-21)\n\n\n### Features\n\n* **analytics-browser:** reduce bundle size via refactoring out rxjs ([#1391](https://github.com/amplitude/Amplitude-TypeScript/issues/1391)) ([09ade0b](https://github.com/amplitude/Amplitude-TypeScript/commit/09ade0b37cfdbaacb0e328cb812168d60dc25124))\n\n\n\n\n\n## [1.17.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.17.3...@amplitude/plugin-autocapture-browser@1.17.4) (2025-11-20)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.17.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.17.2...@amplitude/plugin-autocapture-browser@1.17.3) (2025-11-17)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.17.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.17.1...@amplitude/plugin-autocapture-browser@1.17.2) (2025-11-17)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.17.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.17.0...@amplitude/plugin-autocapture-browser@1.17.1) (2025-11-05)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n# [1.17.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.16.2...@amplitude/plugin-autocapture-browser@1.17.0) (2025-10-29)\n\n\n### Features\n\n* more diagnostics metrics ([#1371](https://github.com/amplitude/Amplitude-TypeScript/issues/1371)) ([40e255c](https://github.com/amplitude/Amplitude-TypeScript/commit/40e255c89c98f4ffffd883296d3d8a9947326aaa))\n\n\n\n\n\n## [1.16.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.16.1...@amplitude/plugin-autocapture-browser@1.16.2) (2025-10-23)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.16.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.16.0...@amplitude/plugin-autocapture-browser@1.16.1) (2025-10-23)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n# [1.16.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.15.3...@amplitude/plugin-autocapture-browser@1.16.0) (2025-10-21)\n\n\n### Features\n\n* **session-replay-browser:** migrate to new remote config client ([#1351](https://github.com/amplitude/Amplitude-TypeScript/issues/1351)) ([d9e0c2c](https://github.com/amplitude/Amplitude-TypeScript/commit/d9e0c2c5df47147bd89c6bfd5e5d2fe3254c8b27))\n\n\n\n\n\n## [1.15.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.15.2...@amplitude/plugin-autocapture-browser@1.15.3) (2025-10-17)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.15.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.15.1...@amplitude/plugin-autocapture-browser@1.15.2) (2025-10-15)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.15.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.15.0...@amplitude/plugin-autocapture-browser@1.15.1) (2025-10-14)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n# [1.15.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.14.4...@amplitude/plugin-autocapture-browser@1.15.0) (2025-10-14)\n\n\n### Features\n\n* **autocapture:** refactor getPageTitle from autocapture to make it reusable ([#1331](https://github.com/amplitude/Amplitude-TypeScript/issues/1331)) ([44eabd1](https://github.com/amplitude/Amplitude-TypeScript/commit/44eabd1139252ed71845d29a86ceccd2ef119d15))\n* **plugin-network-capture-browser:** make networkTracking headers + body capturing GA ([#1334](https://github.com/amplitude/Amplitude-TypeScript/issues/1334)) ([8b57656](https://github.com/amplitude/Amplitude-TypeScript/commit/8b576569d28f323b21f6c82d708867d91c641063))\n\n\n\n\n\n## [1.14.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.14.3...@amplitude/plugin-autocapture-browser@1.14.4) (2025-10-07)\n\n\n### Bug Fixes\n\n* Revert \"feat(analytics-client-common): refactor getPageTitle from aut… ([#1328](https://github.com/amplitude/Amplitude-TypeScript/issues/1328)) ([3976910](https://github.com/amplitude/Amplitude-TypeScript/commit/3976910d2e17a61f9f8e588a006cd44012f2f250))\n\n\n\n\n\n## [1.14.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.14.2...@amplitude/plugin-autocapture-browser@1.14.3) (2025-10-03)\n\n\n### Bug Fixes\n\n* add diagnostics to client and track autocapture getHierachy block time ([#1312](https://github.com/amplitude/Amplitude-TypeScript/issues/1312)) ([a919e22](https://github.com/amplitude/Amplitude-TypeScript/commit/a919e223428083a87954cffa50bc765baa5360b0))\n\n\n\n\n\n## [1.14.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.14.1...@amplitude/plugin-autocapture-browser@1.14.2) (2025-10-01)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.14.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.14.0...@amplitude/plugin-autocapture-browser@1.14.1) (2025-09-25)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n# [1.14.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.13.0...@amplitude/plugin-autocapture-browser@1.14.0) (2025-09-23)\n\n\n### Features\n\n* **analytics-client-common:** refactor getPageTitle from autocapture to make it reusable ([#1298](https://github.com/amplitude/Amplitude-TypeScript/issues/1298)) ([3c931ee](https://github.com/amplitude/Amplitude-TypeScript/commit/3c931eeb7bb4d2482523c48cf796113187d9b078))\n\n\n\n\n\n# [1.13.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.12.2...@amplitude/plugin-autocapture-browser@1.13.0) (2025-09-18)\n\n\n### Bug Fixes\n\n* **analytics-browser:** add URI decoding to Element Clicked event attribute ([#1297](https://github.com/amplitude/Amplitude-TypeScript/issues/1297)) ([ebb2120](https://github.com/amplitude/Amplitude-TypeScript/commit/ebb212080948e8acbaeadbdc410580e04202f818))\n\n\n### Features\n\n* **autocapture:** add data masking in title ([#1289](https://github.com/amplitude/Amplitude-TypeScript/issues/1289)) ([6b8d1eb](https://github.com/amplitude/Amplitude-TypeScript/commit/6b8d1eb3c72d0b49f86153c9b7a5b25efd2b771b))\n\n\n\n\n\n## [1.12.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.12.1...@amplitude/plugin-autocapture-browser@1.12.2) (2025-09-12)\n\n\n### Bug Fixes\n\n* **plugin-autocapture-browser:** no dead click on target=_blank ([#1285](https://github.com/amplitude/Amplitude-TypeScript/issues/1285)) ([f2758a1](https://github.com/amplitude/Amplitude-TypeScript/commit/f2758a173e53a09781ae7ad4687e8a8f9e16f243))\n\n\n\n\n\n## [1.12.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.12.0...@amplitude/plugin-autocapture-browser@1.12.1) (2025-09-09)\n\n\n### Bug Fixes\n\n* **autocapture:** make the default for patterns in mask-text-regex to be case insensitive ([#1282](https://github.com/amplitude/Amplitude-TypeScript/issues/1282)) ([e4995ac](https://github.com/amplitude/Amplitude-TypeScript/commit/e4995acbeda81d3bcf11f2d97743aa844b0240d2))\n\n\n\n\n\n# [1.12.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.11.1...@amplitude/plugin-autocapture-browser@1.12.0) (2025-09-05)\n\n\n### Features\n\n* **autocapture:** attribute value mask ([#1263](https://github.com/amplitude/Amplitude-TypeScript/issues/1263)) ([54916ef](https://github.com/amplitude/Amplitude-TypeScript/commit/54916ef1ae39c2d476b256e387238c252cf2509c))\n* **autocapture:** exclude text with data-amp-mask element attribute ([#1260](https://github.com/amplitude/Amplitude-TypeScript/issues/1260)) ([07da789](https://github.com/amplitude/Amplitude-TypeScript/commit/07da78921a8cde931b9f2aae207b65263c066392))\n* **autocapture:** include pageUrlExcludelist ([#1264](https://github.com/amplitude/Amplitude-TypeScript/issues/1264)) ([dd2aa7f](https://github.com/amplitude/Amplitude-TypeScript/commit/dd2aa7fbb476ead45831f2dc39a94db224131699))\n\n\n\n\n\n## [1.11.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.11.0...@amplitude/plugin-autocapture-browser@1.11.1) (2025-08-28)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n# [1.11.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.10.2...@amplitude/plugin-autocapture-browser@1.11.0) (2025-08-26)\n\n\n### Features\n\n* **autocapture:** add maskTextRegex option to autocapture ([#1259](https://github.com/amplitude/Amplitude-TypeScript/issues/1259)) ([2f1cf07](https://github.com/amplitude/Amplitude-TypeScript/commit/2f1cf075b3e0728f4124bb5c30c8a7e7c21d5a12))\n\n\n\n\n\n## [1.10.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.10.1...@amplitude/plugin-autocapture-browser@1.10.2) (2025-08-25)\n\n\n### Bug Fixes\n\n* **plugin-autocapture-browser:** make rage click less noisy ([#1265](https://github.com/amplitude/Amplitude-TypeScript/issues/1265)) ([a31acd3](https://github.com/amplitude/Amplitude-TypeScript/commit/a31acd34f2389d12427daba776ce22a262db7874))\n\n\n\n\n\n## [1.10.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.10.0...@amplitude/plugin-autocapture-browser@1.10.1) (2025-08-22)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n# [1.10.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.9.0...@amplitude/plugin-autocapture-browser@1.10.0) (2025-08-21)\n\n\n### Features\n\n* **autocapture:** add filtering for email in isNonSensitiveString ([#1257](https://github.com/amplitude/Amplitude-TypeScript/issues/1257)) ([9cdd425](https://github.com/amplitude/Amplitude-TypeScript/commit/9cdd425f039d94bb0db6f9f82cbcaa97eeb8e39d))\n\n\n\n\n\n# [1.9.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.8.3...@amplitude/plugin-autocapture-browser@1.9.0) (2025-08-13)\n\n\n### Features\n\n* **autocapture:** pass autocapture version to Visual Labeling ([#1247](https://github.com/amplitude/Amplitude-TypeScript/issues/1247)) ([f13f795](https://github.com/amplitude/Amplitude-TypeScript/commit/f13f795ba0795278d88d795a395dd9e05d9512ba))\n\n\n\n\n\n## [1.8.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.8.2...@amplitude/plugin-autocapture-browser@1.8.3) (2025-08-08)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.8.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.8.1...@amplitude/plugin-autocapture-browser@1.8.2) (2025-08-05)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.8.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.8.0...@amplitude/plugin-autocapture-browser@1.8.1) (2025-07-30)\n\n\n### Bug Fixes\n\n* **analytics-browser:** use pointerdown instead of click for rage clicks ([#1210](https://github.com/amplitude/Amplitude-TypeScript/issues/1210)) ([321bb0f](https://github.com/amplitude/Amplitude-TypeScript/commit/321bb0fe345b0da2e5d0101b6de5c1e5209df6c1))\n\n\n\n\n\n# [1.8.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.7.1...@amplitude/plugin-autocapture-browser@1.8.0) (2025-07-29)\n\n\n### Features\n\n* **autocapture:** fetch page actions from remote config ([#1168](https://github.com/amplitude/Amplitude-TypeScript/issues/1168)) ([da213cc](https://github.com/amplitude/Amplitude-TypeScript/commit/da213cc33c4986bcebff2b4264b2c17314f5f310))\n\n\n\n\n\n## [1.7.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.7.0...@amplitude/plugin-autocapture-browser@1.7.1) (2025-07-17)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n# [1.7.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.6.1...@amplitude/plugin-autocapture-browser@1.7.0) (2025-07-15)\n\n\n### Features\n\n* **analytics-browser:** add experimental frustrationInteractions ([#1209](https://github.com/amplitude/Amplitude-TypeScript/issues/1209)) ([e321744](https://github.com/amplitude/Amplitude-TypeScript/commit/e3217444c58be15e779ff1fd54a55027c93f5db0))\n\n\n\n\n\n## [1.6.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.6.0...@amplitude/plugin-autocapture-browser@1.6.1) (2025-07-11)\n\n\n### Bug Fixes\n\n* use sliding window to capture rage clicks ([#1202](https://github.com/amplitude/Amplitude-TypeScript/issues/1202)) ([b80f09e](https://github.com/amplitude/Amplitude-TypeScript/commit/b80f09e5ed9a92a7f7d26bd6761c0cd11f306ec3))\n\n\n\n\n\n# [1.6.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.5.0...@amplitude/plugin-autocapture-browser@1.6.0) (2025-07-08)\n\n\n### Bug Fixes\n\n* **plugin-autocapture-browser:** remove cursor pointer ([#1187](https://github.com/amplitude/Amplitude-TypeScript/issues/1187)) ([6894b93](https://github.com/amplitude/Amplitude-TypeScript/commit/6894b93b713c6a2dbdb453155e6261ff7e8ddeb4))\n\n\n### Features\n\n* **analytics-browser:** change definition of rage click ([#1183](https://github.com/amplitude/Amplitude-TypeScript/issues/1183)) ([108f930](https://github.com/amplitude/Amplitude-TypeScript/commit/108f930114629fdb3d600532a2c6b8b4f6cafd01))\n\n\n\n\n\n# [1.5.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.4.0...@amplitude/plugin-autocapture-browser@1.5.0) (2025-06-30)\n\n\n### Features\n\n* add getOptOut() and getIdentity() ([#1174](https://github.com/amplitude/Amplitude-TypeScript/issues/1174)) ([72017c8](https://github.com/amplitude/Amplitude-TypeScript/commit/72017c8a1a54d929542e883e61d61168f214a780))\n\n\n\n\n\n# [1.4.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.3.0...@amplitude/plugin-autocapture-browser@1.4.0) (2025-06-26)\n\n\n### Features\n\n* **plugin-autocapture-browser:** add rage+dead clicks to autocapture plugin ([#1146](https://github.com/amplitude/Amplitude-TypeScript/issues/1146)) ([c850f02](https://github.com/amplitude/Amplitude-TypeScript/commit/c850f020a6b56bbd8d64e0f946acaf0eac15ccf7))\n\n\n\n\n\n# [1.3.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.2.9...@amplitude/plugin-autocapture-browser@1.3.0) (2025-06-25)\n\n\n### Features\n\n* **autocapture:** Added config to capture event properties ([#1111](https://github.com/amplitude/Amplitude-TypeScript/issues/1111)) ([109c3e2](https://github.com/amplitude/Amplitude-TypeScript/commit/109c3e220293fff92f870f8efe1a6cb4a20bebf4))\n\n\n\n\n\n## [1.2.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.2.8...@amplitude/plugin-autocapture-browser@1.2.9) (2025-06-11)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.2.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.2.7...@amplitude/plugin-autocapture-browser@1.2.8) (2025-06-03)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.2.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.2.7-main.0...@amplitude/plugin-autocapture-browser@1.2.7) (2025-05-27)\n\n\n### Reverts\n\n* \"chore(release): publish\" ([#1094](https://github.com/amplitude/Amplitude-TypeScript/issues/1094)) ([f6db1ee](https://github.com/amplitude/Amplitude-TypeScript/commit/f6db1eed32ed77c7ce626624dc55972971f3b27d))\n\n\n\n\n\n## [1.2.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.2.5...@amplitude/plugin-autocapture-browser@1.2.6) (2025-05-14)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.2.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.2.4...@amplitude/plugin-autocapture-browser@1.2.5) (2025-05-13)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.2.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.2.3...@amplitude/plugin-autocapture-browser@1.2.4) (2025-05-07)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.2.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.2.2...@amplitude/plugin-autocapture-browser@1.2.3) (2025-05-05)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.2.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.2.1...@amplitude/plugin-autocapture-browser@1.2.2) (2025-05-02)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.2.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.2.0...@amplitude/plugin-autocapture-browser@1.2.1) (2025-05-02)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n# [1.2.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.1.10...@amplitude/plugin-autocapture-browser@1.2.0) (2025-05-02)\n\n\n### Features\n\n* **analytics-browser:** autocapture network errors ([#1050](https://github.com/amplitude/Amplitude-TypeScript/issues/1050)) ([104350f](https://github.com/amplitude/Amplitude-TypeScript/commit/104350ffe8b1bd1a7090482ac3bf24d85672bd43))\n\n\n\n\n\n## [1.1.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.1.9...@amplitude/plugin-autocapture-browser@1.1.10) (2025-04-30)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.1.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.1.8...@amplitude/plugin-autocapture-browser@1.1.9) (2025-04-22)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.1.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.1.7...@amplitude/plugin-autocapture-browser@1.1.8) (2025-04-17)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.1.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.1.6...@amplitude/plugin-autocapture-browser@1.1.7) (2025-04-15)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.1.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.1.5...@amplitude/plugin-autocapture-browser@1.1.6) (2025-04-10)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.1.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.1.4...@amplitude/plugin-autocapture-browser@1.1.5) (2025-04-07)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.1.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.1.3...@amplitude/plugin-autocapture-browser@1.1.4) (2025-04-07)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.1.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.1.2...@amplitude/plugin-autocapture-browser@1.1.3) (2025-04-02)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.1.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.1.1...@amplitude/plugin-autocapture-browser@1.1.2) (2025-03-24)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n\n\n\n\n## [1.1.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.1.0...@amplitude/plugin-autocapture-browser@1.1.1) (2025-03-21)\n\n\n### Bug Fixes\n\n* **autocapture:** removed deprecated Element Selector event property … ([#1001](https://github.com/amplitude/Amplitude-TypeScript/issues/1001)) ([590d3f4](https://github.com/amplitude/Amplitude-TypeScript/commit/590d3f4c38c336fd490786babdfde292f9350101))\n\n\n\n\n\n# [1.1.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.0.5...@amplitude/plugin-autocapture-browser@1.1.0) (2025-03-14)\n\n\n### Bug Fixes\n\n* **autocapture:** remove time assignment for element interactions tracking ([#981](https://github.com/amplitude/Amplitude-TypeScript/issues/981)) ([c837a07](https://github.com/amplitude/Amplitude-TypeScript/commit/c837a07e62285a7e033014f5ea9d38cf246f4f89))\n\n\n### Features\n\n* **analytics-core:** merge analytics-types ([#989](https://github.com/amplitude/Amplitude-TypeScript/issues/989)) ([9f7ed68](https://github.com/amplitude/Amplitude-TypeScript/commit/9f7ed68e8ec468f5c597ce427c70ffd855dde629))\n\n\n\n\n\n## 1.0.5 (2025-02-28)\n\n\n### Reverts\n\n* Revert \"chore(release): publish\" ([d392f62](https://github.com/amplitude/Amplitude-TypeScript/commit/d392f6290b8bb4dd955d6e6f20b00191679489c4))\n\n\n\n\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.0.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.0.3...@amplitude/plugin-autocapture-browser@1.0.4) (2024-11-25)\n\n### Bug Fixes\n\n- missing body for fetch intercepts in ga events forwarder\n  ([#922](https://github.com/amplitude/Amplitude-TypeScript/issues/922))\n  ([3257610](https://github.com/amplitude/Amplitude-TypeScript/commit/3257610eedaef7f694859fb432fe62faca769331))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.0.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.0.2...@amplitude/plugin-autocapture-browser@1.0.3) (2024-09-23)\n\n### Bug Fixes\n\n- **analytics-react-native:** should export extendSession in client\n  ([#884](https://github.com/amplitude/Amplitude-TypeScript/issues/884))\n  ([ff2e9b5](https://github.com/amplitude/Amplitude-TypeScript/commit/ff2e9b56c71636fec79d56e5a6d2fd3f567a29b3))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.0.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.0.1...@amplitude/plugin-autocapture-browser@1.0.2) (2024-09-18)\n\n### Bug Fixes\n\n- **autocapture:** use getAttribute to more safely access attributes and cast properties to string\n  ([#875](https://github.com/amplitude/Amplitude-TypeScript/issues/875))\n  ([9bef4b7](https://github.com/amplitude/Amplitude-TypeScript/commit/9bef4b7aadee113dea870d12ee3cd1ff351eee57))\n- **plugin-autocapture-browser:** import types from analytics-types\n  ([#879](https://github.com/amplitude/Amplitude-TypeScript/issues/879))\n  ([9d00976](https://github.com/amplitude/Amplitude-TypeScript/commit/9d00976708f749dfbf4ad2e4627bd3981fd8fa2a))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.0.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.0.0...@amplitude/plugin-autocapture-browser@1.0.1) (2024-09-05)\n\n### Bug Fixes\n\n- **autocapture:** prevent potential memory exhaustion when generating combinations\n  ([#863](https://github.com/amplitude/Amplitude-TypeScript/issues/863))\n  ([6fd6495](https://github.com/amplitude/Amplitude-TypeScript/commit/6fd6495d4fa889882b45af844e38cba488c6bc31))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.0.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.0.0-beta.5...@amplitude/plugin-autocapture-browser@1.0.0) (2024-08-01)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.0.0-beta.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.0.0-beta.4...@amplitude/plugin-autocapture-browser@1.0.0-beta.5) (2024-08-01)\n\n### Features\n\n- **autocapture:** add more elements to the default cssSelectorAllowlist\n  ([#833](https://github.com/amplitude/Amplitude-TypeScript/issues/833))\n  ([cf4070a](https://github.com/amplitude/Amplitude-TypeScript/commit/cf4070a30286be04aa050100f6fac202533e1d7e))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.0.0-beta.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.0.0-beta.3...@amplitude/plugin-autocapture-browser@1.0.0-beta.4) (2024-07-30)\n\n### Bug Fixes\n\n- **autocapture:** Remove click tracking buffer and duplicate action clicks\n  ([#830](https://github.com/amplitude/Amplitude-TypeScript/issues/830))\n  ([e1fefd4](https://github.com/amplitude/Amplitude-TypeScript/commit/e1fefd4a529dcec92a929a6003f384f05b6084c3))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.0.0-beta.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.0.0-beta.2...@amplitude/plugin-autocapture-browser@1.0.0-beta.3) (2024-07-23)\n\n### Features\n\n- **autocapture:** track DOM mutations and navigation events to capture action clicks\n  ([#813](https://github.com/amplitude/Amplitude-TypeScript/issues/813))\n  ([52947a3](https://github.com/amplitude/Amplitude-TypeScript/commit/52947a30b452f51a5bcf74009bacd0beb3a6fdaa))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.0.0-beta.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.0.0-beta.1...@amplitude/plugin-autocapture-browser@1.0.0-beta.2) (2024-07-23)\n\n### Bug Fixes\n\n- **autocapture:** reverse hierarchy order and use more accurate property size calculation\n  ([#807](https://github.com/amplitude/Amplitude-TypeScript/issues/807))\n  ([24afd6a](https://github.com/amplitude/Amplitude-TypeScript/commit/24afd6a6a87cc12d8766df92156ee8e2ef785d9b))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.0.0-beta.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@1.0.0-beta.0...@amplitude/plugin-autocapture-browser@1.0.0-beta.1) (2024-07-06)\n\n### Features\n\n- **plugin-autocapture-browser:** update visual labeling to latest 1.0.0 alpha\n  ([#803](https://github.com/amplitude/Amplitude-TypeScript/issues/803))\n  ([7ac6b0e](https://github.com/amplitude/Amplitude-TypeScript/commit/7ac6b0e2a97d78fde3bb1ec26701ba63831d99ef))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.0.0-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@0.11.0...@amplitude/plugin-autocapture-browser@1.0.0-beta.0) (2024-07-06)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.11.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@0.10.0...@amplitude/plugin-autocapture-browser@0.11.0) (2024-07-01)\n\n### Features\n\n- **autocapture:** Add element hierarchy tracking and improve attribute filtering\n  ([#786](https://github.com/amplitude/Amplitude-TypeScript/issues/786))\n  ([03e3f9d](https://github.com/amplitude/Amplitude-TypeScript/commit/03e3f9d8e56355d3af1e1335d9a099b58d16e1a6))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.10.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@0.9.2...@amplitude/plugin-autocapture-browser@0.10.0) (2024-06-24)\n\n### Features\n\n- **autocapture-browser:** Adding async request/response pattern to Autocapture messenger\n  ([#781](https://github.com/amplitude/Amplitude-TypeScript/issues/781))\n  ([f7e26fc](https://github.com/amplitude/Amplitude-TypeScript/commit/f7e26fc1ffed3589934935cede4432ff915c424c))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.9.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@0.9.1...@amplitude/plugin-autocapture-browser@0.9.2) (2024-06-07)\n\n### Bug Fixes\n\n- **plugin-autocapture-browser:** export AutocaptureOptions\n  ([#766](https://github.com/amplitude/Amplitude-TypeScript/issues/766))\n  ([a2558c8](https://github.com/amplitude/Amplitude-TypeScript/commit/a2558c83d3373aabeaf26b9196883f52028b5f67))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.9.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-autocapture-browser@0.9.0...@amplitude/plugin-autocapture-browser@0.9.1) (2024-05-28)\n\n**Note:** Version bump only for package @amplitude/plugin-autocapture-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# 0.9.0 (2024-04-23)\n\n### Features\n\n- rename deta to autocapture ([#725](https://github.com/amplitude/Amplitude-TypeScript/issues/725))\n  ([28a71ac](https://github.com/amplitude/Amplitude-TypeScript/commit/28a71ac398eb47e5a01fd6c893521180ff01aa7e))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.8.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-default-event-tracking-advanced-browser@0.7.2...@amplitude/plugin-default-event-tracking-advanced-browser@0.8.0) (2024-03-20)\n\n### Features\n\n- pass iselementselectable to visual selector ([#684](https://github.com/amplitude/Amplitude-TypeScript/issues/684))\n  ([4ca7f9c](https://github.com/amplitude/Amplitude-TypeScript/commit/4ca7f9c2ea546eb79415f2b9ba3336df8f9352ff))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.7.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-default-event-tracking-advanced-browser@0.7.1...@amplitude/plugin-default-event-tracking-advanced-browser@0.7.2) (2024-03-08)\n\n**Note:** Version bump only for package @amplitude/plugin-default-event-tracking-advanced-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.7.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-default-event-tracking-advanced-browser@0.7.0...@amplitude/plugin-default-event-tracking-advanced-browser@0.7.1) (2024-03-02)\n\n**Note:** Version bump only for package @amplitude/plugin-default-event-tracking-advanced-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.7.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-default-event-tracking-advanced-browser@0.6.0...@amplitude/plugin-default-event-tracking-advanced-browser@0.7.0) (2024-03-01)\n\n### Features\n\n- **deta:** support eu and staging origins ([#671](https://github.com/amplitude/Amplitude-TypeScript/issues/671))\n  ([9d6144f](https://github.com/amplitude/Amplitude-TypeScript/commit/9d6144fa2f4cba70458c499e0e04255330c57386))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.6.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-default-event-tracking-advanced-browser@0.5.1...@amplitude/plugin-default-event-tracking-advanced-browser@0.6.0) (2024-02-13)\n\n### Features\n\n- **deta:** pass the on track message for instrumentations\n  ([#661](https://github.com/amplitude/Amplitude-TypeScript/issues/661))\n  ([c87a63b](https://github.com/amplitude/Amplitude-TypeScript/commit/c87a63b42e8f314c9dbe6cc634847cb195563913))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.5.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-default-event-tracking-advanced-browser@0.5.0...@amplitude/plugin-default-event-tracking-advanced-browser@0.5.1) (2024-02-10)\n\n### Bug Fixes\n\n- **deta plugin:** type and error issues ([#660](https://github.com/amplitude/Amplitude-TypeScript/issues/660))\n  ([276ad85](https://github.com/amplitude/Amplitude-TypeScript/commit/276ad85bf61f24ccabe13bfc4a60194c1a5db42e))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.5.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-default-event-tracking-advanced-browser@0.4.2...@amplitude/plugin-default-event-tracking-advanced-browser@0.5.0) (2024-01-31)\n\n### Features\n\n- bump selector version to 0.1.1 ([#656](https://github.com/amplitude/Amplitude-TypeScript/issues/656))\n  ([f6e7ef7](https://github.com/amplitude/Amplitude-TypeScript/commit/f6e7ef7bfc6f1ac6697cc3f005fb702636df2d55))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.4.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-default-event-tracking-advanced-browser@0.4.1...@amplitude/plugin-default-event-tracking-advanced-browser@0.4.2) (2024-01-16)\n\n**Note:** Version bump only for package @amplitude/plugin-default-event-tracking-advanced-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.4.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-default-event-tracking-advanced-browser@0.4.0...@amplitude/plugin-default-event-tracking-advanced-browser@0.4.1) (2024-01-10)\n\n**Note:** Version bump only for package @amplitude/plugin-default-event-tracking-advanced-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.4.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-default-event-tracking-advanced-browser@0.3.1...@amplitude/plugin-default-event-tracking-advanced-browser@0.4.0) (2024-01-05)\n\n### Features\n\n- **deta:** use same method for element properties\n  ([#643](https://github.com/amplitude/Amplitude-TypeScript/issues/643))\n  ([69efb79](https://github.com/amplitude/Amplitude-TypeScript/commit/69efb79c3953ec981f909553d1ac62eb3d549562))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.3.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-default-event-tracking-advanced-browser@0.3.0...@amplitude/plugin-default-event-tracking-advanced-browser@0.3.1) (2023-12-19)\n\n**Note:** Version bump only for package @amplitude/plugin-default-event-tracking-advanced-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.3.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-default-event-tracking-advanced-browser@0.2.1...@amplitude/plugin-default-event-tracking-advanced-browser@0.3.0) (2023-11-16)\n\n### Features\n\n- integrate with selector ([#620](https://github.com/amplitude/Amplitude-TypeScript/issues/620))\n  ([7afb5c7](https://github.com/amplitude/Amplitude-TypeScript/commit/7afb5c72aba497b7feba980fdf49f061a1009de2))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.2.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-default-event-tracking-advanced-browser@0.2.0...@amplitude/plugin-default-event-tracking-advanced-browser@0.2.1) (2023-11-03)\n\n### Bug Fixes\n\n- skip parent element event when it is not target ([#613](https://github.com/amplitude/Amplitude-TypeScript/issues/613))\n  ([cd378b3](https://github.com/amplitude/Amplitude-TypeScript/commit/cd378b36200345721bc69a95c5d6daf7cf8b52cd))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.2.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-default-event-tracking-advanced-browser@0.1.3...@amplitude/plugin-default-event-tracking-advanced-browser@0.2.0) (2023-11-01)\n\n### Features\n\n- add default data attr selector ([#612](https://github.com/amplitude/Amplitude-TypeScript/issues/612))\n  ([c0f0c2d](https://github.com/amplitude/Amplitude-TypeScript/commit/c0f0c2dcbcb43959992380fe26b0df961a4ea9f4))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.1.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-default-event-tracking-advanced-browser@0.1.2...@amplitude/plugin-default-event-tracking-advanced-browser@0.1.3) (2023-10-27)\n\n### Bug Fixes\n\n- handle text node throw error issue ([#610](https://github.com/amplitude/Amplitude-TypeScript/issues/610))\n  ([b425d44](https://github.com/amplitude/Amplitude-TypeScript/commit/b425d441753b298cc3a6717b00e38230612f19a3))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.1.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-default-event-tracking-advanced-browser@0.1.1...@amplitude/plugin-default-event-tracking-advanced-browser@0.1.2) (2023-10-27)\n\n### Bug Fixes\n\n- add filter back to handle current node ([#609](https://github.com/amplitude/Amplitude-TypeScript/issues/609))\n  ([92c412b](https://github.com/amplitude/Amplitude-TypeScript/commit/92c412b106158e57d57d526c05df0ec23977b388))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.1.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-default-event-tracking-advanced-browser@0.1.0...@amplitude/plugin-default-event-tracking-advanced-browser@0.1.1) (2023-10-27)\n\n### Bug Fixes\n\n- remove event stopPropagation ([#608](https://github.com/amplitude/Amplitude-TypeScript/issues/608))\n  ([afe1cc2](https://github.com/amplitude/Amplitude-TypeScript/commit/afe1cc2567b2bcc50a3416299b16f4721a50866a))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.1.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-default-event-tracking-advanced-browser@0.0.2...@amplitude/plugin-default-event-tracking-advanced-browser@0.1.0) (2023-10-27)\n\n### Features\n\n- make auto-tracking solely use css selector allowlist\n  ([#606](https://github.com/amplitude/Amplitude-TypeScript/issues/606))\n  ([404d09e](https://github.com/amplitude/Amplitude-TypeScript/commit/404d09ecc7a7923d7016fc2de3df26af442e123d))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.0.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-default-event-tracking-advanced-browser@0.0.1...@amplitude/plugin-default-event-tracking-advanced-browser@0.0.2) (2023-10-26)\n\n**Note:** Version bump only for package @amplitude/plugin-default-event-tracking-advanced-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## 0.0.1 (2023-10-11)\n\n**Note:** Version bump only for package @amplitude/plugin-default-event-tracking-advanced-browser\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://amplitude.com\" target=\"_blank\" align=\"center\">\n    <img src=\"https://static.amplitude.com/lightning/46c85bfd91905de8047f1ee65c7c93d6fa9ee6ea/static/media/amplitude-logo-with-text.4fb9e463.svg\" width=\"280\">\n  </a>\n  <br />\n</p>\n\n# @amplitude/plugin-autocapture-browser (beta)\n**This plugin is in beta at the moment, naming and interface might change in the future.**\n\nBrowser SDK plugin for autocapture.\n\n## Installation\n\nThis package is published on NPM registry and is available to be installed using npm and yarn.\n\n```sh\n# npm\nnpm install @amplitude/plugin-autocapture-browser@beta\n\n# yarn\nyarn add @amplitude/plugin-autocapture-browser@beta\n```\n\n## Usage\n\nThis plugin works on top of the Amplitude Browser SDK, generating auto-tracked events and sending to Amplitude.\n\nTo use this plugin, you need to install `@amplitude/analytics-browser` version `v1.9.1` or later.\n\n### 1. Import Amplitude packages\n\n* `@amplitude/analytics-browser`\n* `@amplitude/plugin-autocapture-browser`\n\n```typescript\nimport * as amplitude from '@amplitude/analytics-browser';\nimport { autocapturePlugin } from '@amplitude/plugin-autocapture-browser';\n```\n\n### 2. Instantiate the plugin\n\nThe plugin accepts 1 optional parameter, which is an `Object` to configure the allowed tracking options.\n\n```typescript\nconst plugin = autocapturePlugin({\n  cssSelectorAllowlist: [\n    '.amp-tracking',\n    '[amp-tracking]'\n  ],\n  pageUrlAllowlist: [\n    'https://amplitude.com',\n    new RegExp('https://amplitude.com/blog/*')\n  ],\n  pageUrlExcludelist: [\n    'https://amplitude.com/admin',\n    new RegExp('^https:\\\\/\\\\/amplitude\\\\.com\\\\/private\\\\/.*$')\n  ],\n});\n```\n\nExamples:\n- The above `cssSelectorAllowlist` will only allow tracking elements like:\n    - `<button amp-tracking>Click</button>`\n    - `<a class=\"amp-tracking\">Link</a>`\n- The above `pageUrlAllowlist` will only allow the elements on URL \"https://amplitude.com\" or any URL matching the \"https://amplitude.com/blog/*\" to be tracked\n- The above `pageUrlExcludelist` will block tracking on URL \"https://amplitude.com/admin\" or any URL matching the \"^https:\\\\/\\\\/amplitude\\\\.com\\\\/private\\\\/.*$\" pattern, even if they match the allowlist\n\n#### Options\n\n|Name|Type|Default|Description|\n|-|-|-|-|\n|`cssSelectorAllowlist`|`string[]`|`['a', 'button', 'input', 'select', 'textarea', 'label', '[data-amp-default-track]', '.amp-default-track']`| When provided, only allow elements matching any selector to be tracked. |\n|`pageUrlAllowlist`|`(string\\|RegExp)[]`|`undefined`| When provided, only allow elements matching URLs to be tracked. |\n|`pageUrlExcludelist`|`(string\\|RegExp)[]`|`undefined`| When provided, block tracking on elements matching URLs. Takes precedence over allowlist. |\n|`shouldTrackEventResolver`|`(actionType: ActionType, element: Element) => boolean`|`undefined`| When provided, overwrite all other allowlists and configurations. |\n|`dataAttributePrefix`|`string`|`'data-amp-track-'`| Allow data attributes to be collected in event property. |\n\n### 3. Install plugin to Amplitude SDK\n\n```typescript\namplitude.add(plugin);\n```\n\n### 4. Initialize Amplitude SDK\n\n```typescript\namplitude.init('API_KEY');\n```\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/e2e/autocapture.spec.ts",
    "content": "import { test, expect, Page, BrowserContext } from '@playwright/test';\n\nconst TBT_DIFF_THRESHOLD = 1000;\n\nasync function runFormTest(page: Page, context: BrowserContext, browserName: string, skipAutocapture = false) {\n  // Enable CPU throttling through CDP only for Chromium\n  if (browserName === 'chromium') {\n    const client = await context.newCDPSession(page);\n    await client.send('Emulation.setCPUThrottlingRate', { rate: 20 });\n  }\n\n  // Navigate to the form test page\n  const url = skipAutocapture ? '/form-test.html?skipAutocapture=true' : '/form-test.html';\n  await page.goto(url);\n\n  // Wait for the page to be fully loaded\n  await page.waitForLoadState('networkidle');\n\n  await page.fill('#text', 'Test Text Input');\n  await page.fill('#email', 'test@example.com');\n  await page.fill('#number', '42');\n  await page.fill('#date', '2024-03-20');\n  await page.fill('#color', '#ff0000');\n  await page.fill('#range', '75');\n  await page.selectOption('#select', '2');\n  await page.fill('#textarea', 'This is a test textarea input with multiple lines.\\nLine 2\\nLine 3');\n  await page.check('#checkbox1');\n  await page.check('#checkbox2');\n  await page.check('#radio1');\n\n  // Submit the form\n  await page.click('button[type=\"submit\"]');\n\n  // Verify form submission was successful\n  const resultDiv = page.locator('#result');\n  await expect(resultDiv).toBeVisible();\n  await expect(resultDiv).toContainText('Form Submitted Successfully');\n\n  // Get Total Blocking Time from the element\n  const tbtElement = page.locator('#tbt');\n  const tbt = await tbtElement.textContent();\n  return Number(tbt);\n}\n\ntest('should not significantly impact performance when autocapture is enabled', async ({ browser, browserName }) => {\n  // Create two separate contexts\n  const context1 = await browser.newContext();\n  const context2 = await browser.newContext();\n\n  // Create pages in each context\n  const page1 = await context1.newPage();\n  const page2 = await context2.newPage();\n\n  try {\n    await runFormTest(page2, context2, browserName);\n    const tbtNoAutocapture = await runFormTest(page2, context2, browserName, true);\n    const tbtWithAutocapture = await runFormTest(page1, context1, browserName);\n    const performanceDiff = tbtWithAutocapture - tbtNoAutocapture;\n    expect(performanceDiff).toBeLessThan(TBT_DIFF_THRESHOLD);\n  } finally {\n    // Clean up contexts\n    await context1.close();\n    await context2.close();\n  }\n});\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/jest.config.js",
    "content": "const baseConfig = require('../../jest.config.js');\nconst package = require('./package');\n\nmodule.exports = {\n  ...baseConfig,\n  displayName: package.name,\n  rootDir: '.',\n  testEnvironment: 'jsdom',\n  coveragePathIgnorePatterns: ['index.ts'],\n  setupFiles: ['./test/setup.ts'],\n};\n\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/package.json",
    "content": "{\n  \"name\": \"@amplitude/plugin-autocapture-browser\",\n  \"version\": \"1.27.1\",\n  \"description\": \"\",\n  \"author\": \"Amplitude Inc\",\n  \"homepage\": \"https://github.com/amplitude/Amplitude-TypeScript\",\n  \"license\": \"MIT\",\n  \"main\": \"lib/cjs/index.js\",\n  \"module\": \"lib/esm/index.js\",\n  \"types\": \"lib/esm/index.d.ts\",\n  \"sideEffects\": false,\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"tag\": \"beta\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/amplitude/Amplitude-TypeScript.git\"\n  },\n  \"scripts\": {\n    \"build\": \"pnpm bundle && pnpm build:es5 && pnpm build:esm\",\n    \"bundle\": \"rollup --config rollup.config.js\",\n    \"build:es5\": \"tsc -p ./tsconfig.es5.json\",\n    \"build:esm\": \"tsc -p ./tsconfig.esm.json\",\n    \"watch\": \"tsc -p ./tsconfig.esm.json --watch\",\n    \"watch-bundle\": \"NODE_ENV=development pnpm bundle --watch\",\n    \"clean\": \"rimraf node_modules lib coverage\",\n    \"fix\": \"pnpm fix:eslint & pnpm fix:prettier\",\n    \"fix:eslint\": \"eslint '{src,test}/**/*.ts' --fix\",\n    \"fix:prettier\": \"prettier --write \\\"{src,test}/**/*.ts\\\"\",\n    \"lint\": \"pnpm lint:eslint & pnpm lint:prettier\",\n    \"lint:eslint\": \"eslint '{src,test}/**/*.ts'\",\n    \"lint:prettier\": \"prettier --check \\\"{src,test}/**/*.ts\\\"\",\n    \"publish\": \"node ../../scripts/publish/upload-to-s3.js\",\n    \"test\": \"jest\",\n    \"typecheck\": \"tsc -p ./tsconfig.json\",\n    \"version\": \"pnpm version-file && pnpm build\",\n    \"version-file\": \"node -p \\\"'export const VERSION = \\\\'' + require('./package.json').version + '\\\\';'\\\" > src/version.ts\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/amplitude/Amplitude-TypeScript/issues\"\n  },\n  \"dependencies\": {\n    \"@amplitude/analytics-core\": \"workspace:*\",\n    \"tslib\": \"^2.4.1\"\n  },\n  \"devDependencies\": {\n    \"@aws-sdk/client-s3\": \"^3.229.0\",\n    \"@rollup/plugin-commonjs\": \"^23.0.4\",\n    \"@rollup/plugin-node-resolve\": \"^15.0.1\",\n    \"@rollup/plugin-typescript\": \"^10.0.1\",\n    \"css.escape\": \"^1.5.1\",\n    \"rollup\": \"^2.79.1\",\n    \"rollup-plugin-execute\": \"^1.1.1\",\n    \"rollup-plugin-gzip\": \"^3.1.0\",\n    \"rollup-plugin-sourcemaps\": \"^0.6.3\",\n    \"rollup-plugin-terser\": \"^7.0.2\"\n  },\n  \"files\": [\n    \"lib\"\n  ]\n}\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/playwright.config.ts",
    "content": "import { defineConfig } from '@playwright/test';\nimport baseConfig from '../../playwright.config';\n\nexport default defineConfig({\n  ...baseConfig,\n}); "
  },
  {
    "path": "packages/plugin-autocapture-browser/rollup.config.js",
    "content": "import { iife, umd } from '../../scripts/build/rollup.config';\n\niife.input = umd.input;\niife.output.name = 'amplitudeAutocapturePlugin';\n\n\nif (process.env.NODE_ENV === 'development') {\n  iife.output.sourcemap = 'inline';\n}\nexport default [umd, iife];"
  },
  {
    "path": "packages/plugin-autocapture-browser/src/autocapture/track-action-click.ts",
    "content": "import { AllWindowObservables, AutoCaptureOptionsWithDefaults } from '../autocapture-plugin';\nimport { BrowserClient, ActionType, merge, asyncMap } from '@amplitude/analytics-core';\nimport {\n  ElementBasedTimestampedEvent,\n  filterOutNonTrackableEvents,\n  getClosestElement,\n  shouldTrackEvent,\n  TimestampedEvent,\n} from '../helpers';\nimport { AMPLITUDE_ELEMENT_CLICKED_EVENT } from '../constants';\n\nexport function trackActionClick({\n  amplitude,\n  allObservables,\n  options,\n  getEventProperties,\n  shouldTrackEvent,\n  shouldTrackActionClick,\n}: {\n  amplitude: BrowserClient;\n  allObservables: AllWindowObservables;\n  options: AutoCaptureOptionsWithDefaults;\n  getEventProperties: (actionType: ActionType, element: Element) => Record<string, any>;\n  shouldTrackActionClick: shouldTrackEvent;\n  shouldTrackEvent: shouldTrackEvent;\n}) {\n  const { clickObservable, mutationObservable, navigateObservable } = allObservables;\n\n  const filteredClickObservable = clickObservable\n    .filter((click) => {\n      return !shouldTrackEvent('click', click.closestTrackedAncestor);\n    })\n    .map((click) => {\n      // overwrite the closestTrackedAncestor with the closest element that is on the actionClickAllowlist\n      const closestActionClickEl = getClosestElement(click.event.target as Element, options.actionClickAllowlist);\n      click.closestTrackedAncestor = closestActionClickEl as Element;\n\n      // overwrite the targetElementProperties with the properties of the closestActionClickEl\n      if (click.closestTrackedAncestor !== null) {\n        click.targetElementProperties = getEventProperties(click.type, click.closestTrackedAncestor);\n      }\n      return click;\n    })\n    .filter(filterOutNonTrackableEvents)\n    .filter((clickEvent) => {\n      // Only track change on elements that should be tracked\n      return shouldTrackActionClick('click', clickEvent.closestTrackedAncestor);\n    });\n\n  const mutationOrNavigate = navigateObservable ? merge(mutationObservable, navigateObservable) : mutationObservable;\n\n  const clickMutationNavigateObservable = merge(filteredClickObservable, mutationOrNavigate);\n\n  let actionClickTimer: ReturnType<typeof setTimeout> | null = null;\n  let lastClickEvent: TimestampedEvent<any> | null = null;\n\n  const actionClickObservable = asyncMap(clickMutationNavigateObservable, (event) => {\n    // clear any previous timer\n    if (actionClickTimer) {\n      clearTimeout(actionClickTimer);\n      actionClickTimer = null;\n    }\n    if (event.type === 'click') {\n      // mark the 'last click event'\n      lastClickEvent = event;\n\n      // set a timer to clear last click event if no mutation event between now and 500ms\n      actionClickTimer = setTimeout(() => {\n        actionClickTimer = null;\n        lastClickEvent = null;\n      }, 500);\n      return Promise.resolve(null);\n    } else {\n      // if mutation/navigation + last click event, then it's an action click\n      if (lastClickEvent) {\n        const event = lastClickEvent;\n        lastClickEvent = null;\n        return Promise.resolve(event);\n      }\n    }\n    return Promise.resolve(null);\n  });\n\n  return actionClickObservable.subscribe((actionClick) => {\n    if (!actionClick) return;\n    /* istanbul ignore next */\n    amplitude?.track(\n      AMPLITUDE_ELEMENT_CLICKED_EVENT,\n      getEventProperties('click', (actionClick as ElementBasedTimestampedEvent<MouseEvent>).closestTrackedAncestor),\n    );\n  });\n}\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/src/autocapture/track-change.ts",
    "content": "import { AllWindowObservables } from '../autocapture-plugin';\nimport {\n  filterOutNonTrackableEvents,\n  shouldTrackEvent,\n  ElementBasedTimestampedEvent,\n  type evaluateTriggersFn,\n} from '../helpers';\nimport { BrowserClient, ActionType } from '@amplitude/analytics-core';\nimport { AMPLITUDE_ELEMENT_CHANGED_EVENT } from '../constants';\n\nexport function trackChange({\n  amplitude,\n  allObservables,\n  getEventProperties,\n  shouldTrackEvent,\n  evaluateTriggers,\n}: {\n  amplitude: BrowserClient;\n  allObservables: AllWindowObservables;\n  getEventProperties: (actionType: ActionType, element: Element) => Record<string, any>;\n  shouldTrackEvent: shouldTrackEvent;\n  evaluateTriggers: evaluateTriggersFn;\n}) {\n  const { changeObservable } = allObservables;\n\n  const filteredChangeObservable = changeObservable\n    .filter(filterOutNonTrackableEvents)\n    .filter((changeEvent: ElementBasedTimestampedEvent<Event>) => {\n      // Only track change on elements that should be tracked,\n      return shouldTrackEvent('change', changeEvent.closestTrackedAncestor);\n    })\n    .map((changeEvent) => evaluateTriggers(changeEvent));\n\n  return filteredChangeObservable.subscribe((changeEvent) => {\n    /* istanbul ignore next */\n    amplitude?.track(AMPLITUDE_ELEMENT_CHANGED_EVENT, getEventProperties('change', changeEvent.closestTrackedAncestor));\n  });\n}\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/src/autocapture/track-click.ts",
    "content": "import { AllWindowObservables } from '../autocapture-plugin';\nimport { ElementBasedEvent, type ElementBasedTimestampedEvent, type evaluateTriggersFn } from '../helpers';\nimport { Observable, BrowserClient } from '@amplitude/analytics-core';\nimport { filterOutNonTrackableEvents, shouldTrackEvent } from '../helpers';\nimport { AMPLITUDE_ELEMENT_CLICKED_EVENT } from '../constants';\n\nexport function trackClicks({\n  amplitude,\n  allObservables,\n  shouldTrackEvent,\n  evaluateTriggers,\n}: {\n  amplitude: BrowserClient;\n  allObservables: AllWindowObservables;\n  shouldTrackEvent: shouldTrackEvent;\n  evaluateTriggers: evaluateTriggersFn;\n}) {\n  const { clickObservable } = allObservables;\n\n  const clickObservableFiltered = clickObservable\n    .filter(filterOutNonTrackableEvents)\n    .filter((click: ElementBasedTimestampedEvent<MouseEvent>) => {\n      // Only track clicks on elements that should be tracked,\n      return shouldTrackEvent('click', click.closestTrackedAncestor);\n    })\n    .map((click: ElementBasedTimestampedEvent<MouseEvent>) => evaluateTriggers(click));\n\n  const clicks: Observable<typeof clickObservableFiltered extends Observable<infer U> ? U : never> =\n    clickObservableFiltered;\n\n  return clicks.subscribe((click: ElementBasedTimestampedEvent<ElementBasedEvent>) => {\n    /* istanbul ignore next */\n    amplitude?.track(AMPLITUDE_ELEMENT_CLICKED_EVENT, click.targetElementProperties);\n  });\n}\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/src/autocapture/track-dead-click.ts",
    "content": "import { AllWindowObservables } from '../frustration-plugin';\nimport { BrowserClient, ActionType, merge, asyncMap } from '@amplitude/analytics-core';\nimport { ElementBasedTimestampedEvent, filterOutNonTrackableEvents, MouseButton, shouldTrackEvent } from '../helpers';\nimport { AMPLITUDE_ELEMENT_DEAD_CLICKED_EVENT } from '../constants';\nconst DEAD_CLICK_TIMEOUT = 3000; // 3 seconds to wait for an activity to happen\n\ntype EventDeadClick = {\n  '[Amplitude] X': number;\n  '[Amplitude] Y': number;\n};\n\nconst CHANGE_EVENTS = ['mutation', 'navigate'];\n\nexport function trackDeadClick({\n  amplitude,\n  allObservables,\n  getEventProperties,\n  shouldTrackDeadClick,\n}: {\n  amplitude: BrowserClient;\n  allObservables: AllWindowObservables;\n  getEventProperties: (actionType: ActionType, element: Element) => Record<string, any>;\n  shouldTrackDeadClick: shouldTrackEvent;\n}) {\n  const { clickObservable, mutationObservable, navigateObservable }: AllWindowObservables = allObservables;\n\n  const filteredClickObservable = clickObservable.filter((click) => {\n    return (\n      filterOutNonTrackableEvents(click) &&\n      shouldTrackDeadClick('click', click.closestTrackedAncestor) &&\n      click.event.target instanceof Element &&\n      click.event.target.closest('a[target=\"_blank\"]') === null &&\n      click.event.button === MouseButton.LEFT_OR_TOUCH_CONTACT\n    );\n  });\n\n  /* istanbul ignore next */\n  const changeObservables = navigateObservable ? merge(mutationObservable, navigateObservable) : mutationObservable;\n\n  const clicksAndChangeObservable = merge(filteredClickObservable, changeObservables);\n\n  let deadClickTimer: ReturnType<typeof setTimeout> | null = null;\n\n  const deadClickObservable = asyncMap(\n    clicksAndChangeObservable,\n    (event): Promise<ElementBasedTimestampedEvent<MouseEvent> | null> => {\n      if (deadClickTimer && CHANGE_EVENTS.includes(event.type)) {\n        // a mutation or navigation means it's not a dead click, so clear the timer\n        clearTimeout(deadClickTimer);\n        deadClickTimer = null;\n        return Promise.resolve(null);\n      } else if (event.type === 'click') {\n        // if a dead click is already on-deck, return null.\n        // this throttles dead clicks events so no more than one dead click event\n        // is tracked per every DEAD_CLICK_TIMEOUT ms.\n        if (deadClickTimer) {\n          return Promise.resolve(null);\n        }\n        return new Promise((resolve) => {\n          deadClickTimer = setTimeout(() => {\n            resolve(event as ElementBasedTimestampedEvent<MouseEvent>);\n            deadClickTimer = null;\n          }, DEAD_CLICK_TIMEOUT);\n        });\n      }\n      // unreachable code, but needed to satisfy the type checker\n      return Promise.resolve(null);\n    },\n  );\n\n  return deadClickObservable.subscribe((actionClick) => {\n    if (!actionClick) return;\n    const deadClickEvent: EventDeadClick = {\n      '[Amplitude] X': (actionClick.event as MouseEvent).clientX,\n      '[Amplitude] Y': (actionClick.event as MouseEvent).clientY,\n    };\n    amplitude.track(\n      AMPLITUDE_ELEMENT_DEAD_CLICKED_EVENT,\n      {\n        ...getEventProperties('click', actionClick.closestTrackedAncestor),\n        ...deadClickEvent,\n      },\n      { time: actionClick.timestamp },\n    );\n  });\n}\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/src/autocapture/track-error-click.ts",
    "content": "import { BrowserErrorEvent } from '../observables';\nimport { AllWindowObservables } from '../frustration-plugin';\nimport {\n  ElementBasedTimestampedEvent,\n  filterOutNonTrackableEvents,\n  MouseButton,\n  shouldTrackEvent,\n  TimestampedEvent,\n} from '../helpers';\nimport { BrowserClient, merge } from '@amplitude/analytics-core';\nimport { AMPLITUDE_ELEMENT_ERROR_CLICKED_EVENT } from '../constants';\n\ntype ClickOrErrorEvent = ElementBasedTimestampedEvent<MouseEvent> | TimestampedEvent<BrowserErrorEvent>;\n\nconst ERROR_CLICK_TIMEOUT = 2_000; // 2 seconds to wait for an error to happen\n\nexport function trackErrorClicks({\n  amplitude,\n  allObservables,\n  shouldTrackErrorClick,\n}: {\n  amplitude: BrowserClient;\n  allObservables: AllWindowObservables;\n  shouldTrackErrorClick: shouldTrackEvent;\n}) {\n  const { clickObservable, browserErrorObservable } = allObservables;\n\n  const filteredClickObservable = clickObservable.filter((click) => {\n    return (\n      filterOutNonTrackableEvents(click) &&\n      shouldTrackErrorClick('click', click.closestTrackedAncestor) &&\n      click.event.target instanceof Element &&\n      click.event.target.closest('a[target=\"_blank\"]') === null &&\n      click.event.button === MouseButton.LEFT_OR_TOUCH_CONTACT\n    );\n  });\n\n  let errorClickTimer: ReturnType<typeof setTimeout> | null = null;\n  let latestClickEvent: ElementBasedTimestampedEvent<MouseEvent> | null = null;\n\n  const clearClickTimer = () => {\n    if (errorClickTimer !== null) {\n      clearTimeout(errorClickTimer);\n      errorClickTimer = null;\n    }\n    latestClickEvent = null;\n  };\n\n  return merge(filteredClickObservable, browserErrorObservable).subscribe((event: ClickOrErrorEvent) => {\n    if (event.type === 'click') {\n      clearClickTimer();\n      latestClickEvent = event as ElementBasedTimestampedEvent<MouseEvent>;\n      errorClickTimer = setTimeout(clearClickTimer, ERROR_CLICK_TIMEOUT);\n      return;\n    }\n\n    if (event.type === 'error' && latestClickEvent) {\n      amplitude.track(AMPLITUDE_ELEMENT_ERROR_CLICKED_EVENT, {\n        ['[Amplitude] Kind']: event.event.kind,\n        ['[Amplitude] Message']: event.event.message,\n        ['[Amplitude] Stack']: event.event.stack,\n        ['[Amplitude] Filename']: event.event.filename,\n        ['[Amplitude] Line Number']: event.event.lineNumber,\n        ['[Amplitude] Column Number']: event.event.columnNumber,\n        ...latestClickEvent.targetElementProperties,\n      });\n      clearClickTimer();\n    }\n  });\n}\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/src/autocapture/track-exposure.ts",
    "content": "/* eslint-disable no-restricted-globals */\nimport { DEFAULT_EXPOSURE_DURATION } from '@amplitude/analytics-core';\nimport { AllWindowObservables } from '../autocapture-plugin';\nimport { DataExtractor } from '../data-extractor';\n\nexport function trackExposure({\n  allObservables,\n  onExposure,\n  dataExtractor,\n  exposureDuration = DEFAULT_EXPOSURE_DURATION,\n}: {\n  allObservables: AllWindowObservables;\n  onExposure: (elementPath: string) => void;\n  dataExtractor: DataExtractor;\n  exposureDuration?: number;\n}) {\n  // Track which elements have been marked as exposed (per-element state)\n  const exposureMap = new Map<Element, boolean>();\n\n  // Track active timers for elements that are currently visible but not yet exposed\n  const exposureTimerMap = new Map<Element, ReturnType<typeof setTimeout> | null | undefined>();\n\n  const { exposureObservable } = allObservables;\n\n  const exposureSubscription = exposureObservable.subscribe((event) => {\n    const entry = event as unknown as IntersectionObserverEntry;\n    const element = entry.target;\n\n    if (entry.isIntersecting) {\n      // Element became visible - start exposure timer if not already exposed\n      if (!exposureMap.get(element)) {\n        const timer = setTimeout(() => {\n          // Element has been visible for exposureDuration - mark as exposed\n          exposureMap.set(element, true);\n\n          // Record the CSS selector path in the shared exposure state\n          const elementPath = dataExtractor.getElementPath(element);\n          onExposure(elementPath);\n\n          // Clear the timer reference\n          exposureTimerMap.set(element, null);\n        }, exposureDuration);\n\n        exposureTimerMap.set(element, timer);\n      }\n    } else if (!entry.isIntersecting && entry.intersectionRatio < 1.0) {\n      // Element left viewport - cancel exposure timer if one exists\n      const timer = exposureTimerMap.get(element);\n      if (timer) {\n        clearTimeout(timer);\n        exposureTimerMap.set(element, null);\n      }\n    }\n  });\n\n  return {\n    unsubscribe: () => {\n      exposureSubscription.unsubscribe();\n    },\n    reset: () => {\n      exposureTimerMap.forEach((timer) => {\n        if (timer) {\n          clearTimeout(timer);\n        }\n      });\n      exposureTimerMap.clear();\n      exposureMap.clear();\n    },\n  };\n}\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/src/autocapture/track-long-task.ts",
    "content": "import { BrowserClient, ElementInteractionsOptions, PerformanceTrackingOptions } from '@amplitude/analytics-core';\nimport { AMPLITUDE_MAIN_THREAD_BLOCK_EVENT } from '../constants';\nimport { isUrlAllowed } from '../helpers';\n\nconst DEFAULT_DURATION_THRESHOLD = 100; // ms\nconst MEASURE_BUFFER_WINDOW_MS = 10_000;\n\n// LoAF and Long Task types are not yet in TypeScript's built-in DOM types\ninterface PerformanceScriptTiming extends PerformanceEntry {\n  sourceURL: string;\n  sourceFunctionName: string;\n  // Character offset into the source URL's script where the function was defined.\n  // Used downstream for sourcemap resolution. Optional because coverage varies\n  // across browsers and entry origins (inline handlers, new Function, etc.).\n  sourceCharPosition?: number;\n  invokerType: string;\n  invoker: string;\n}\n\ninterface PerformanceLongAnimationFrameTiming extends PerformanceEntry {\n  renderStart: number;\n  styleAndLayoutStart: number;\n  blockingDuration: number;\n  scripts: PerformanceScriptTiming[];\n}\n\ninterface TaskAttributionTiming extends PerformanceEntry {\n  name: string;\n}\n\ninterface PerformanceLongTaskTiming extends PerformanceEntry {\n  attribution: TaskAttributionTiming[];\n}\n\nfunction getOverlappingMeasures(entry: PerformanceEntry, measures: PerformanceEntry[]): string[] {\n  const taskEnd = entry.startTime + entry.duration;\n  return measures\n    .filter((measure) => measure.startTime < taskEnd && measure.startTime + measure.duration > entry.startTime)\n    .map((measure) => measure.name);\n}\n\nfunction buildLoAFProperties(entry: PerformanceLongAnimationFrameTiming, measures: PerformanceEntry[]) {\n  const overlappingMeasures = getOverlappingMeasures(entry, measures);\n  const scripts = entry.scripts ?? [];\n\n  const scriptURLs = scripts.map((s) => s.sourceURL).filter(Boolean);\n  const scriptFunctions = scripts.map((s) => s.sourceFunctionName).filter(Boolean);\n  const scriptPositions = scripts\n    .map((s) => s.sourceCharPosition)\n    .filter((p): p is number => typeof p === 'number' && p >= 0);\n  const invokerTypes = scripts.map((s) => s.invokerType).filter(Boolean);\n  const invokers = scripts.map((s) => s.invoker).filter(Boolean);\n\n  return {\n    '[Amplitude] Main Thread Block Source': 'long-animation-frame',\n    '[Amplitude] Main Thread Block Duration': entry.duration,\n    '[Amplitude] Main Thread Block Blocking Duration': entry.blockingDuration,\n    '[Amplitude] Main Thread Block Start Time': entry.startTime,\n    ...(overlappingMeasures.length > 0 && { '[Amplitude] Main Thread Block Measures': overlappingMeasures }),\n    '[Amplitude] Main Thread Block Render Start': entry.renderStart,\n    '[Amplitude] Main Thread Block Style And Layout Start': entry.styleAndLayoutStart,\n    '[Amplitude] Main Thread Block Script Count': scripts.length,\n    ...(scriptURLs.length > 0 && { '[Amplitude] Main Thread Block Script URLs': scriptURLs }),\n    ...(scriptFunctions.length > 0 && { '[Amplitude] Main Thread Block Script Functions': scriptFunctions }),\n    ...(scriptPositions.length > 0 && { '[Amplitude] Main Thread Block Script Positions': scriptPositions }),\n    ...(invokerTypes.length > 0 && { '[Amplitude] Main Thread Block Invoker Types': invokerTypes }),\n    ...(invokers.length > 0 && { '[Amplitude] Main Thread Block Invokers': invokers }),\n  };\n}\n\nfunction buildLongTaskProperties(entry: PerformanceLongTaskTiming, measures: PerformanceEntry[]) {\n  const overlappingMeasures = getOverlappingMeasures(entry, measures);\n  const attribution = entry.attribution ?? [];\n\n  return {\n    '[Amplitude] Main Thread Block Source': 'long-task',\n    '[Amplitude] Main Thread Block Duration': entry.duration,\n    '[Amplitude] Main Thread Block Blocking Duration': entry.duration,\n    '[Amplitude] Main Thread Block Start Time': entry.startTime,\n    ...(overlappingMeasures.length > 0 && { '[Amplitude] Main Thread Block Measures': overlappingMeasures }),\n    ...(attribution.length > 0 && {\n      '[Amplitude] Main Thread Block Attribution': attribution.map((a: TaskAttributionTiming) => a.name),\n    }),\n  };\n}\n\nfunction getSupportedEntryType(): 'long-animation-frame' | 'longtask' | null {\n  /* istanbul ignore next */\n  if (typeof PerformanceObserver === 'undefined') return null;\n  try {\n    const supported = PerformanceObserver.supportedEntryTypes;\n    if (supported.includes('long-animation-frame')) return 'long-animation-frame';\n    if (supported.includes('longtask')) return 'longtask';\n  } catch {\n    // ignore\n  }\n  return null;\n}\n\nexport function trackMainThreadBlock({\n  amplitude,\n  options,\n  durationThreshold = DEFAULT_DURATION_THRESHOLD,\n}: {\n  amplitude: BrowserClient;\n  options: PerformanceTrackingOptions;\n  durationThreshold?: number;\n}) {\n  const entryType = getSupportedEntryType();\n\n  /* istanbul ignore next */\n  if (!entryType) {\n    return { unsubscribe: () => void 0 };\n  }\n\n  const measures: PerformanceEntry[] = [];\n\n  const measureObserver = new PerformanceObserver((list) => {\n    const now = performance.now();\n    for (const entry of list.getEntries()) {\n      measures.push(entry);\n    }\n    const cutoff = now - MEASURE_BUFFER_WINDOW_MS;\n    while (measures.length > 0 && measures[0].startTime < cutoff) {\n      measures.shift();\n    }\n  });\n\n  try {\n    measureObserver.observe({ entryTypes: ['measure'] });\n  } catch {\n    // measure not supported — continue without it\n  }\n\n  const blockObserver = new PerformanceObserver((list) => {\n    for (const entry of list.getEntries()) {\n      if (!isUrlAllowed(options as ElementInteractionsOptions)) {\n        return;\n      }\n      if (entry.duration < durationThreshold) {\n        continue;\n      }\n      const properties =\n        entryType === 'long-animation-frame'\n          ? buildLoAFProperties(entry as PerformanceLongAnimationFrameTiming, measures)\n          : buildLongTaskProperties(entry as PerformanceLongTaskTiming, measures);\n\n      amplitude.track(AMPLITUDE_MAIN_THREAD_BLOCK_EVENT, properties);\n    }\n  });\n\n  try {\n    blockObserver.observe({ entryTypes: [entryType] });\n  } catch {\n    measureObserver.disconnect();\n    return { unsubscribe: () => void 0 };\n  }\n\n  return {\n    unsubscribe: () => {\n      blockObserver.disconnect();\n      measureObserver.disconnect();\n    },\n  };\n}\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/src/autocapture/track-rage-click.ts",
    "content": "import { AllWindowObservables } from '../frustration-plugin';\nimport {\n  BrowserClient,\n  asyncMap,\n  DEFAULT_RAGE_CLICK_THRESHOLD,\n  DEFAULT_RAGE_CLICK_WINDOW_MS,\n  DEFAULT_RAGE_CLICK_OUT_OF_BOUNDS_THRESHOLD,\n} from '@amplitude/analytics-core';\nimport { shouldTrackEvent } from '../helpers';\nimport { AMPLITUDE_ELEMENT_RAGE_CLICKED_EVENT } from '../constants';\n\nconst RAGE_CLICK_THRESHOLD = DEFAULT_RAGE_CLICK_THRESHOLD;\nconst RAGE_CLICK_WINDOW_MS = DEFAULT_RAGE_CLICK_WINDOW_MS;\nconst RAGE_CLICK_OUT_OF_BOUNDS_THRESHOLD = DEFAULT_RAGE_CLICK_OUT_OF_BOUNDS_THRESHOLD;\n\ntype Click = {\n  X: number;\n  Y: number;\n  Time: number;\n};\n\ntype EventRageClick = {\n  '[Amplitude] Begin Time': string; // ISO-8601\n  '[Amplitude] End Time': string; // ISO-8601\n  '[Amplitude] Duration': number;\n  '[Amplitude] Clicks': Array<Click>;\n  '[Amplitude] Click Count': number;\n};\n\ntype ClickEvent = {\n  event: MouseEvent | Event;\n  timestamp: number;\n  targetElementProperties: Record<string, any>;\n  closestTrackedAncestor: Element | null;\n};\n\ntype ClickRegionBoundingBox = {\n  yMin?: number;\n  yMax?: number;\n  xMin?: number;\n  xMax?: number;\n  isOutOfBounds?: boolean;\n};\n\ntype RageClickEvent = {\n  rageClickEvent: EventRageClick;\n  time: number;\n};\n\nfunction addCoordinates(regionBox: ClickRegionBoundingBox, click: ClickEvent) {\n  const { pageX, pageY } = click.event as MouseEvent;\n  regionBox.yMin = Math.min(regionBox.yMin ?? pageY, pageY);\n  regionBox.yMax = Math.max(regionBox.yMax ?? pageY, pageY);\n  regionBox.xMin = Math.min(regionBox.xMin ?? pageX, pageX);\n  regionBox.xMax = Math.max(regionBox.xMax ?? pageX, pageX);\n  regionBox.isOutOfBounds =\n    regionBox.yMax - regionBox.yMin > RAGE_CLICK_OUT_OF_BOUNDS_THRESHOLD ||\n    regionBox.xMax - regionBox.xMin > RAGE_CLICK_OUT_OF_BOUNDS_THRESHOLD;\n}\n\nfunction getRageClickAnalyticsEvent(clickWindow: ClickEvent[]) {\n  /* istanbul ignore if */\n  if (clickWindow.length === 0) {\n    return null;\n  }\n  const firstClick = clickWindow[0];\n  const lastClick = clickWindow[clickWindow.length - 1];\n\n  const rageClickEvent: EventRageClick = {\n    '[Amplitude] Begin Time': new Date(firstClick.timestamp).toISOString(),\n    '[Amplitude] End Time': new Date(lastClick.timestamp).toISOString(),\n    '[Amplitude] Duration': lastClick.timestamp - firstClick.timestamp,\n    '[Amplitude] Clicks': clickWindow.map((click) => ({\n      X: (click.event as MouseEvent).pageX,\n      Y: (click.event as MouseEvent).pageY,\n      Time: click.timestamp,\n    })),\n    '[Amplitude] Click Count': clickWindow.length,\n    ...firstClick.targetElementProperties,\n  };\n\n  return { rageClickEvent, time: firstClick.timestamp };\n}\n\nfunction isClickOutsideRageClickWindow(clickWindow: ClickEvent[], click: ClickEvent) {\n  const firstIndex = Math.max(0, clickWindow.length - RAGE_CLICK_THRESHOLD + 1);\n  const firstClick = clickWindow[firstIndex];\n  return click.timestamp - firstClick.timestamp >= RAGE_CLICK_WINDOW_MS;\n}\n\nfunction isNewElement(clickWindow: ClickEvent[], click: ClickEvent) {\n  return (\n    clickWindow.length > 0 &&\n    clickWindow[clickWindow.length - 1].closestTrackedAncestor !== click.closestTrackedAncestor\n  );\n}\n\nexport function trackRageClicks({\n  amplitude,\n  allObservables,\n  shouldTrackRageClick,\n}: {\n  amplitude: BrowserClient;\n  allObservables: AllWindowObservables;\n  shouldTrackRageClick: shouldTrackEvent;\n}) {\n  const { clickObservable, selectionObservable }: AllWindowObservables = allObservables;\n\n  // Keep track of all clicks within the sliding window\n  let clickWindow: ClickEvent[] = [];\n\n  // Keep track of the region box for all clicks, to determine when a rage click is out of bounds\n  let clickBoundingBox: ClickRegionBoundingBox = {};\n\n  let pendingRageClick: {\n    resolve: (rageClickEvent: RageClickEvent | null) => void;\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    timerId: any;\n  } | null = null;\n\n  // helper function to reset the click window and region box\n  function resetClickWindow(click?: ClickEvent) {\n    clickWindow = [];\n    clickBoundingBox = {};\n    if (click) {\n      addCoordinates(clickBoundingBox, click);\n      clickWindow.push(click);\n    }\n  }\n\n  const rageClickObservable = asyncMap(\n    clickObservable.filter((click) => shouldTrackRageClick('click', click.closestTrackedAncestor)),\n    async (click: ClickEvent): Promise<RageClickEvent | null> => {\n      // add this click's coordinates to the bounding box\n      addCoordinates(clickBoundingBox, click);\n\n      let resolutionValue: RageClickEvent | null = null;\n\n      // if current click is:\n      //  1. first click in the window\n      //  2. on a new element\n      //  3. outside the rage click time window\n      //  4. out of bounds\n      // then start a new click window\n      if (\n        clickWindow.length === 0 ||\n        isNewElement(clickWindow, click) ||\n        isClickOutsideRageClickWindow(clickWindow, click) ||\n        clickBoundingBox.isOutOfBounds\n      ) {\n        // if there was a previous Rage Click Event on deck, then send it\n        if (pendingRageClick) {\n          resolutionValue = getRageClickAnalyticsEvent(clickWindow);\n        }\n        resetClickWindow(click);\n      } else {\n        clickWindow.push(click);\n      }\n\n      // if there was a previous Rage Click Event on deck, then resolve it\n      if (pendingRageClick) {\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n        clearTimeout(pendingRageClick.timerId);\n        pendingRageClick.resolve(resolutionValue);\n        pendingRageClick = null;\n      }\n\n      // if we have enough clicks to be a rage click, set a timout to trigger the rage\n      // click event after the time threshold is reached.\n      // This will be cancelled if a new click is tracked within the time threshold.\n      if (clickWindow.length >= RAGE_CLICK_THRESHOLD) {\n        return new Promise((resolve) => {\n          pendingRageClick = {\n            resolve,\n            timerId: setTimeout(() => {\n              resolve(getRageClickAnalyticsEvent(clickWindow));\n            }, RAGE_CLICK_WINDOW_MS),\n          };\n        });\n      }\n\n      return null;\n    },\n  );\n\n  // reset the click window when a selection change occurs\n  /* istanbul ignore next */\n  const selectionSubscription = selectionObservable?.subscribe(() => {\n    resetClickWindow();\n  });\n\n  const rageClickSubscription = rageClickObservable.subscribe((data: RageClickEvent | null) => {\n    /* istanbul ignore if */\n    if (data === null) {\n      return;\n    }\n    amplitude.track(AMPLITUDE_ELEMENT_RAGE_CLICKED_EVENT, data.rageClickEvent, { time: data.time });\n  });\n\n  return {\n    unsubscribe: () => {\n      rageClickSubscription.unsubscribe();\n      /* istanbul ignore next */\n      selectionSubscription?.unsubscribe();\n    },\n  };\n}\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/src/autocapture/track-scroll.ts",
    "content": "import { AllWindowObservables } from '../autocapture-plugin';\nimport { BrowserClient, getGlobalScope } from '@amplitude/analytics-core';\n\nexport interface ScrollState {\n  maxX: number;\n  maxY: number;\n}\n\nexport function trackScroll({\n  amplitude,\n  allObservables,\n}: {\n  amplitude: BrowserClient;\n  allObservables: AllWindowObservables;\n}) {\n  // amplitude is reserved for future periodic scroll event tracking\n  void amplitude;\n\n  const { scrollObservable } = allObservables;\n  const state: ScrollState = { maxX: 0, maxY: 0 };\n\n  const scrollSubscription = scrollObservable.subscribe(() => {\n    const globalScope = getGlobalScope();\n    /* istanbul ignore next */\n    const currentX = Math.floor(globalScope?.scrollX ?? globalScope?.pageXOffset ?? 0);\n    /* istanbul ignore next */\n    const currentY = Math.floor(globalScope?.scrollY ?? globalScope?.pageYOffset ?? 0);\n\n    // Update page-level max positions for Page View End event (never resets during page lifetime)\n    state.maxX = Math.max(state.maxX, currentX);\n    state.maxY = Math.max(state.maxY, currentY);\n  });\n\n  return {\n    unsubscribe: () => {\n      scrollSubscription.unsubscribe();\n    },\n    getState: () => state,\n    reset: () => {\n      state.maxX = 0;\n      state.maxY = 0;\n    },\n  };\n}\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/src/autocapture/track-thrashed-cursor.ts",
    "content": "import { BrowserClient, ElementInteractionsOptions, Observable } from '@amplitude/analytics-core';\nimport { AllWindowObservables } from '../frustration-plugin';\nimport { AMPLITUDE_THRASHED_CURSOR_EVENT } from '../constants';\nimport { isUrlAllowed } from '../helpers';\n\ntype Position = {\n  x: number;\n  y: number;\n};\n\nenum Direction {\n  INCREASING = 'increasing',\n  DECREASING = 'decreasing',\n}\n\nenum Axis {\n  X = 'x',\n  Y = 'y',\n}\n\nexport const createMouseDirectionChangeObservable = ({\n  allWindowObservables,\n}: {\n  allWindowObservables: AllWindowObservables;\n}): Observable<Axis> => {\n  const { mouseMoveObservable } = allWindowObservables;\n  return new Observable<Axis>((observer) => {\n    let lastPosition: Position | null = null;\n    let xDirection: Direction | null = null;\n    let yDirection: Direction | null = null;\n    return mouseMoveObservable.subscribe((event) => {\n      const currentPosition = { x: event.clientX, y: event.clientY };\n      if (lastPosition === null) {\n        lastPosition = currentPosition;\n        return;\n      }\n      if (currentPosition.x > lastPosition.x) {\n        if (xDirection === Direction.DECREASING) {\n          observer.next(Axis.X);\n        }\n        xDirection = Direction.INCREASING;\n      } else if (currentPosition.x < lastPosition.x) {\n        if (xDirection === Direction.INCREASING) {\n          observer.next(Axis.X);\n        }\n        xDirection = Direction.DECREASING;\n      }\n\n      if (currentPosition.y > lastPosition.y) {\n        if (yDirection === Direction.DECREASING) {\n          observer.next(Axis.Y);\n        }\n        yDirection = Direction.INCREASING;\n      } else if (currentPosition.y < lastPosition.y) {\n        if (yDirection === Direction.INCREASING) {\n          observer.next(Axis.Y);\n        }\n        yDirection = Direction.DECREASING;\n      }\n      lastPosition = currentPosition;\n    });\n  });\n};\n\ntype DirectionChangeSeries = {\n  // number of direction changes to be considered a thrashed cursor\n  changesThreshold: number;\n  // timestamps of direction changes (limited to \"changesThreshold\" to avoid memory leaks)\n  changes: number[];\n  // window duration in milliseconds\n  thresholdMs: number;\n  // when the series of direction   changes started\n  startTime?: number;\n};\n\nfunction addDirectionChange(directionChangeSeries: DirectionChangeSeries) {\n  const now = +Date.now();\n\n  directionChangeSeries.startTime = directionChangeSeries.startTime || now;\n\n  // add this direction change to the series (fixed length array to avoid memory leaks)\n  const { changes, changesThreshold } = directionChangeSeries;\n  changes.push(now);\n  if (changes.length > changesThreshold) changes.shift();\n}\n\n// checks if there are enough direction changes within window + threshold\n// for it to be considered a thrashed cursor\nfunction isThrashedCursor(directionChanges: DirectionChangeSeries): boolean {\n  const { changes, changesThreshold, thresholdMs } = directionChanges;\n  if (changes.length < changesThreshold) return false;\n  const delta = changes[changes.length - 1] - changes[0];\n  return delta < thresholdMs;\n}\n\nfunction resetDirectionChangeSeries(directionChangeSeries: DirectionChangeSeries) {\n  directionChangeSeries.changes = [];\n  directionChangeSeries.startTime = undefined;\n}\n\n// if the time between first and last change is greater than the threshold,\n// shift the window to the right until it is below the threshold\nfunction adjustWindow(directionChanges: DirectionChangeSeries) {\n  const { changes, thresholdMs } = directionChanges;\n\n  // find the first change that is within the threshold\n  let leftPtr = 0;\n  const lastChange = changes[changes.length - 1];\n  for (; leftPtr < changes.length; leftPtr++) {\n    const delta = lastChange - changes[leftPtr];\n    if (delta < thresholdMs) {\n      break;\n    }\n  }\n  if (leftPtr === 0) return;\n\n  directionChanges.startTime = changes[leftPtr];\n  directionChanges.changes.splice(0, leftPtr);\n}\n\nfunction getPendingThrashedCursor(\n  directionChangesX: DirectionChangeSeries,\n  directionChangesY: DirectionChangeSeries,\n): number | undefined {\n  let startTime = undefined;\n  if (isThrashedCursor(directionChangesX)) {\n    startTime = directionChangesX.startTime;\n  }\n  if (isThrashedCursor(directionChangesY)) {\n    const startTimeY = directionChangesY.startTime;\n    if (startTimeY && (!startTime || startTimeY < startTime)) {\n      startTime = startTimeY;\n    }\n  }\n  return startTime;\n}\n\nconst DEFAULT_THRESHOLD = 20;\nconst DEFAULT_WINDOW_MS = 2_000;\n\nexport const createThrashedCursorObservable = ({\n  mouseDirectionChangeObservable,\n  directionChanges = DEFAULT_THRESHOLD,\n  thresholdMs = DEFAULT_WINDOW_MS,\n}: {\n  mouseDirectionChangeObservable: Observable<Axis>;\n  directionChanges?: number;\n  thresholdMs?: number;\n}): Observable<number> => {\n  return new Observable<number>((observer) => {\n    const xDirectionChanges: DirectionChangeSeries = { changes: [], changesThreshold: directionChanges, thresholdMs };\n    const yDirectionChanges: DirectionChangeSeries = { changes: [], changesThreshold: directionChanges, thresholdMs };\n    let pendingThrashedCursor: number | undefined = undefined;\n    let timer: ReturnType<typeof setTimeout> | null = null;\n\n    function emitPendingThrashedCursor() {\n      if (pendingThrashedCursor !== undefined) {\n        observer.next(pendingThrashedCursor);\n        pendingThrashedCursor = undefined;\n\n        // reset window\n        if (timer !== null) clearTimeout(timer);\n        resetDirectionChangeSeries(xDirectionChanges);\n        resetDirectionChangeSeries(yDirectionChanges);\n      }\n    }\n\n    return mouseDirectionChangeObservable.subscribe((axis) => {\n      if (timer !== null) clearTimeout(timer);\n      addDirectionChange(axis === Axis.X ? xDirectionChanges : yDirectionChanges);\n\n      const nextPendingThrashedCursor = getPendingThrashedCursor(xDirectionChanges, yDirectionChanges);\n      if (nextPendingThrashedCursor) {\n        // if we're in a thrashed cursor window, debounce it for \"thresholdMs\" duration\n        // this is so that we do not restart the window if more direction changes are\n        // detected in this series\n        pendingThrashedCursor = pendingThrashedCursor || nextPendingThrashedCursor;\n        timer = setTimeout(() => {\n          emitPendingThrashedCursor();\n          timer = null;\n        }, thresholdMs);\n      } else {\n        emitPendingThrashedCursor();\n      }\n\n      adjustWindow(xDirectionChanges);\n      adjustWindow(yDirectionChanges);\n\n      /* istanbul ignore next */\n      return () => {\n        /* istanbul ignore if */\n        if (timer !== null) {\n          clearTimeout(timer);\n          timer = null;\n        }\n      };\n    });\n  });\n};\n\nexport const trackThrashedCursor = ({\n  amplitude,\n  options,\n  allObservables,\n  directionChanges = DEFAULT_THRESHOLD,\n  thresholdMs = DEFAULT_WINDOW_MS,\n}: {\n  amplitude: BrowserClient;\n  options: ElementInteractionsOptions;\n  allObservables: AllWindowObservables;\n  directionChanges?: number;\n  thresholdMs?: number;\n}) => {\n  const mouseDirectionChangeObservable = createMouseDirectionChangeObservable({ allWindowObservables: allObservables });\n  const thrashedCursorObservable = createThrashedCursorObservable({\n    mouseDirectionChangeObservable,\n    directionChanges,\n    thresholdMs,\n  });\n  return thrashedCursorObservable.subscribe((time) => {\n    if (!isUrlAllowed(options)) {\n      return;\n    }\n    amplitude.track(AMPLITUDE_THRASHED_CURSOR_EVENT, undefined, { time });\n  });\n};\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/src/autocapture/track-viewport-content-updated.ts",
    "content": "import { BrowserClient, getDecodeURI, getGlobalScope } from '@amplitude/analytics-core';\nimport * as constants from '../constants';\nimport { getCurrentPageViewId } from '../helpers';\n\nexport interface ScrollTracker {\n  getState: () => { maxX: number; maxY: number };\n  reset: () => void;\n}\n\nexport interface ExposureTracker {\n  reset: () => void;\n}\n\nexport function fireViewportContentUpdated({\n  amplitude,\n  scrollTracker,\n  currentElementExposed,\n  elementExposedForPage,\n  exposureTracker,\n  isPageEnd,\n  lastScroll,\n}: {\n  amplitude: BrowserClient;\n  scrollTracker: ScrollTracker;\n  currentElementExposed: Set<string>;\n  elementExposedForPage: Set<string>;\n  exposureTracker: ExposureTracker | undefined;\n  isPageEnd: boolean;\n  lastScroll: { maxX: undefined | number; maxY: undefined | number };\n}): void {\n  const pageScrollMaxState = scrollTracker.getState();\n  const globalScope = getGlobalScope();\n\n  /* istanbul ignore next */\n  const viewportWidth = globalScope?.innerWidth ?? 0;\n  /* istanbul ignore next */\n  const viewportHeight = globalScope?.innerHeight ?? 0;\n\n  const eventProperties: Record<string, unknown> = {\n    [constants.AMPLITUDE_EVENT_PROP_PAGE_URL]: getDecodeURI(\n      /* istanbul ignore next */\n      globalScope?.location?.href?.split('?')[0] ?? '',\n    ),\n    [constants.AMPLITUDE_EVENT_PROP_MAX_PAGE_X]: pageScrollMaxState.maxX + viewportWidth,\n    [constants.AMPLITUDE_EVENT_PROP_MAX_PAGE_Y]: pageScrollMaxState.maxY + viewportHeight,\n    [constants.AMPLITUDE_EVENT_PROP_VIEWPORT_HEIGHT]: viewportHeight,\n    [constants.AMPLITUDE_EVENT_PROP_VIEWPORT_WIDTH]: viewportWidth,\n    '[Amplitude] Element Exposed': Array.from(currentElementExposed),\n  };\n\n  const pageViewId = getCurrentPageViewId();\n  if (pageViewId) {\n    eventProperties[constants.AMPLITUDE_EVENT_PROP_PAGE_VIEW_ID] = pageViewId;\n  }\n\n  // If elements exposed is empty and max scroll is same as last event, don't track\n  if (\n    currentElementExposed.size === 0 &&\n    pageScrollMaxState.maxX === lastScroll.maxX &&\n    pageScrollMaxState.maxY === lastScroll.maxY\n  ) {\n    if (isPageEnd) {\n      scrollTracker.reset();\n      elementExposedForPage.clear();\n      exposureTracker?.reset();\n    }\n    return;\n  }\n\n  /* istanbul ignore next */\n  amplitude?.track('[Amplitude] Viewport Content Updated', eventProperties);\n  lastScroll.maxX = pageScrollMaxState.maxX;\n  lastScroll.maxY = pageScrollMaxState.maxY;\n\n  // Clear current batch\n  currentElementExposed.clear();\n\n  if (isPageEnd) {\n    // Reset state for next page view\n    scrollTracker.reset();\n    elementExposedForPage.clear();\n    exposureTracker?.reset();\n  }\n}\n\nexport function onExposure(\n  elementPath: string,\n  elementExposedForPage: Set<string>,\n  currentElementExposed: Set<string>,\n  fireViewportContentUpdatedCallback: (isPageEnd: boolean) => void,\n) {\n  if (elementExposedForPage.has(elementPath)) {\n    return;\n  }\n  elementExposedForPage.add(elementPath);\n  currentElementExposed.add(elementPath);\n\n  // Check if current set size exceeds 18k chars\n  const exposedArray = Array.from(currentElementExposed);\n  const exposedString = JSON.stringify(exposedArray);\n\n  if (exposedString.length >= constants.MAX_ELEMENT_EXPOSED_STR_LENGTH) {\n    fireViewportContentUpdatedCallback(false);\n  }\n}\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/src/autocapture-plugin.ts",
    "content": "/* eslint-disable no-restricted-globals */\nimport {\n  type BrowserClient,\n  type BrowserConfig,\n  type EnrichmentPlugin,\n  type ElementInteractionsOptions,\n  DEFAULT_EXPOSURE_DURATION,\n  DEFAULT_CSS_SELECTOR_ALLOWLIST,\n  DEFAULT_ACTION_CLICK_ALLOWLIST,\n  DEFAULT_DATA_ATTRIBUTE_PREFIX,\n  IDiagnosticsClient,\n  getGlobalScope,\n  getOrCreateWindowMessenger,\n  enableBackgroundCapture,\n  multicast,\n} from '@amplitude/analytics-core';\nimport { VERSION } from './version';\nimport * as constants from './constants';\nimport {\n  createShouldTrackEvent,\n  type ElementBasedTimestampedEvent,\n  type TimestampedEvent,\n  type NavigateEvent,\n} from './helpers';\nimport { enableVisualTagging } from './libs/messenger';\nimport { trackClicks } from './autocapture/track-click';\nimport { trackChange } from './autocapture/track-change';\nimport { trackActionClick } from './autocapture/track-action-click';\nimport { trackScroll } from './autocapture/track-scroll';\n\nimport {\n  createClickObservable,\n  createScrollObservable,\n  createExposureObservable,\n  createMutationObservable,\n} from './observables';\n\nimport {\n  createLabeledEventToTriggerMap,\n  createTriggerEvaluator,\n  groupLabeledEventIdsByEventType,\n} from './pageActions/triggers';\nimport { DataExtractor } from './data-extractor';\nimport { Observable, Unsubscribable } from '@amplitude/analytics-core';\nimport { trackExposure } from './autocapture/track-exposure';\nimport { fireViewportContentUpdated, onExposure, ExposureTracker } from './autocapture/track-viewport-content-updated';\n\ntype NavigationType = {\n  addEventListener: (type: string, listener: EventListenerOrEventListenerObject) => void;\n  removeEventListener: (type: string, listener: EventListenerOrEventListenerObject) => void;\n};\n\ndeclare global {\n  interface Window {\n    navigation: NavigationType;\n  }\n}\n\ntype BrowserEnrichmentPlugin = EnrichmentPlugin<BrowserClient, BrowserConfig>;\n\nexport type AutoCaptureOptionsWithDefaults = Required<\n  Pick<ElementInteractionsOptions, 'debounceTime' | 'cssSelectorAllowlist' | 'actionClickAllowlist'>\n> &\n  ElementInteractionsOptions;\n\nexport enum ObservablesEnum {\n  ClickObservable = 'clickObservable',\n  ChangeObservable = 'changeObservable',\n  NavigateObservable = 'navigateObservable',\n  MutationObservable = 'mutationObservable',\n  ScrollObservable = 'scrollObservable',\n  ExposureObservable = 'exposureObservable',\n  BrowserErrorObservable = 'browserErrorObservable',\n  SelectionObservable = 'selectionObservable',\n  MouseMoveObservable = 'mouseMoveObservable',\n}\n\nexport interface AllWindowObservables {\n  [ObservablesEnum.ChangeObservable]: Observable<ElementBasedTimestampedEvent<Event>>;\n  // [ObservablesEnum.ErrorObservable]: Observable<TimestampedEvent<ErrorEvent>>;\n  [ObservablesEnum.ClickObservable]: Observable<ElementBasedTimestampedEvent<MouseEvent>>;\n  [ObservablesEnum.MutationObservable]: Observable<TimestampedEvent<MutationRecord[]>>;\n  [ObservablesEnum.NavigateObservable]?: Observable<TimestampedEvent<NavigateEvent>>;\n  [ObservablesEnum.ScrollObservable]: Observable<Event>; // TODO: add type for scroll event\n  [ObservablesEnum.ExposureObservable]: Observable<Event>;\n  [ObservablesEnum.SelectionObservable]?: Observable<void>;\n}\n\nexport const autocapturePlugin = (\n  options: ElementInteractionsOptions = {},\n  context?: { diagnosticsClient: IDiagnosticsClient },\n): BrowserEnrichmentPlugin => {\n  // Set the plugin version tag\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n  context?.diagnosticsClient.setTag('plugin.autocapture.version', VERSION);\n\n  const {\n    dataAttributePrefix = DEFAULT_DATA_ATTRIBUTE_PREFIX,\n    visualTaggingOptions = {\n      enabled: true,\n    },\n  } = options;\n\n  options.cssSelectorAllowlist = options.cssSelectorAllowlist ?? DEFAULT_CSS_SELECTOR_ALLOWLIST;\n  options.actionClickAllowlist = options.actionClickAllowlist ?? DEFAULT_ACTION_CLICK_ALLOWLIST;\n  options.debounceTime = options.debounceTime ?? 0;\n  const isViewportContentUpdatedEnabled = options.viewportContentUpdated?.enabled !== false;\n  const resolvedExposureDuration =\n    options.viewportContentUpdated?.exposureDuration ?? options.exposureDuration ?? DEFAULT_EXPOSURE_DURATION;\n  options.viewportContentUpdated = {\n    ...options.viewportContentUpdated,\n    exposureDuration: resolvedExposureDuration,\n  };\n\n  options.pageUrlExcludelist = options.pageUrlExcludelist?.reduce(\n    (acc: (string | RegExp | { pattern: string })[], excludePattern) => {\n      if (typeof excludePattern === 'string') {\n        acc.push(excludePattern);\n      }\n      if (excludePattern instanceof RegExp) {\n        acc.push(excludePattern);\n      }\n      if (typeof excludePattern === 'object' && excludePattern !== null && 'pattern' in excludePattern) {\n        try {\n          acc.push(new RegExp(excludePattern.pattern));\n        } catch (regexError) {\n          console.warn(`Invalid regex pattern: ${excludePattern.pattern}`, regexError);\n          return acc;\n        }\n      }\n      return acc;\n    },\n    [],\n  );\n\n  const name = constants.PLUGIN_NAME;\n  const type = 'enrichment';\n\n  const subscriptions: Unsubscribable[] = [];\n\n  const dataExtractor = new DataExtractor(options, context);\n\n  // Page-level state shared across trackers, emitted in a single Page View End event on beforeunload\n  // elementExposedForPage holds the total set of elements seen during the entire page view lifetime\n  const elementExposedForPage = new Set<string>();\n  // currentElementExposed only holds the set of elements that will be flushed during the next [Amplitude] Viewport Content Updated event\n  const currentElementExposed = new Set<string>();\n\n  let beforeUnloadCleanup: () => void;\n\n  const createObservables = (): AllWindowObservables => {\n    const clickObservable = multicast(\n      createClickObservable().map(\n        (click) =>\n          dataExtractor.addAdditionalEventProperties(\n            click,\n            'click',\n            (options as AutoCaptureOptionsWithDefaults).cssSelectorAllowlist,\n            dataAttributePrefix,\n          ) as ElementBasedTimestampedEvent<MouseEvent>,\n      ),\n    );\n\n    const changeObservable = multicast(\n      new Observable<ElementBasedTimestampedEvent<Event>>((observer) => {\n        const handler = (changeEvent: Event) => {\n          const enrichedChangeEvent = dataExtractor.addAdditionalEventProperties(\n            changeEvent,\n            'change',\n            (options as AutoCaptureOptionsWithDefaults).cssSelectorAllowlist,\n            dataAttributePrefix,\n          ) as ElementBasedTimestampedEvent<Event>;\n          observer.next(enrichedChangeEvent);\n        };\n        /* istanbul ignore next */\n        getGlobalScope()?.document.addEventListener('change', handler, { capture: true });\n        /* istanbul ignore next */\n        return () => getGlobalScope()?.document.removeEventListener('change', handler);\n      }),\n    );\n\n    // Create observable for URL changes\n    let navigateObservable: Observable<TimestampedEvent<NavigateEvent>> | undefined;\n\n    /* istanbul ignore next */\n    if (window.navigation) {\n      navigateObservable = multicast(\n        new Observable<TimestampedEvent<NavigateEvent>>((observer) => {\n          const handler = (navigateEvent: NavigateEvent) => {\n            const enrichedNavigateEvent = dataExtractor.addAdditionalEventProperties(\n              navigateEvent,\n              'navigate',\n              (options as AutoCaptureOptionsWithDefaults).cssSelectorAllowlist,\n              dataAttributePrefix,\n            );\n            observer.next(enrichedNavigateEvent);\n          };\n          window.navigation.addEventListener('navigate', handler as EventListener);\n          return () => {\n            window.navigation.removeEventListener('navigate', handler as EventListener);\n          };\n        }),\n      );\n    }\n\n    const mutationObservable = multicast(\n      createMutationObservable().map((mutation) =>\n        dataExtractor.addAdditionalEventProperties(\n          mutation,\n          'mutation',\n          (options as AutoCaptureOptionsWithDefaults).cssSelectorAllowlist,\n          dataAttributePrefix,\n        ),\n      ),\n    );\n\n    const scrollObservable = createScrollObservable();\n\n    const exposureObservable = createExposureObservable(\n      mutationObservable,\n      (options as AutoCaptureOptionsWithDefaults).cssSelectorAllowlist,\n    );\n\n    return {\n      [ObservablesEnum.ChangeObservable]: changeObservable,\n      // [ObservablesEnum.ErrorObservable]: errorObservable,\n      [ObservablesEnum.ClickObservable]: clickObservable,\n      [ObservablesEnum.MutationObservable]: mutationObservable,\n      [ObservablesEnum.NavigateObservable]: navigateObservable,\n      [ObservablesEnum.ScrollObservable]: scrollObservable,\n      [ObservablesEnum.ExposureObservable]: exposureObservable,\n    };\n  };\n\n  // Group labeled events by event type (eg. click, change)\n  let groupedLabeledEvents = groupLabeledEventIdsByEventType(Object.values(options.pageActions?.labeledEvents ?? {}));\n\n  let labeledEventToTriggerMap = createLabeledEventToTriggerMap(options.pageActions?.triggers ?? []);\n\n  // Evaluate triggers for the given event by running the actions associated with the matching triggers\n  const evaluateTriggers = createTriggerEvaluator(\n    groupedLabeledEvents,\n    labeledEventToTriggerMap,\n    dataExtractor,\n    options,\n  );\n\n  // Function to recalculate internal variables when remote config is updated\n  const recomputePageActionsData = (remotePageActions: ElementInteractionsOptions['pageActions']) => {\n    if (remotePageActions) {\n      // Merge remote config with local options\n      options.pageActions = {\n        ...options.pageActions,\n        ...remotePageActions,\n      };\n\n      // Recalculate internal variables\n      groupedLabeledEvents = groupLabeledEventIdsByEventType(Object.values(options.pageActions.labeledEvents ?? {}));\n      labeledEventToTriggerMap = createLabeledEventToTriggerMap(options.pageActions.triggers ?? []);\n\n      // Update evaluateTriggers function\n      evaluateTriggers.update(groupedLabeledEvents, labeledEventToTriggerMap, options);\n    }\n  };\n\n  const setup: BrowserEnrichmentPlugin['setup'] = async (config, amplitude) => {\n    /* istanbul ignore if */\n    if (typeof document === 'undefined') {\n      return;\n    }\n\n    let pageViewEndFired = false;\n    const lastScroll: { maxX: undefined | number; maxY: undefined | number } = { maxX: undefined, maxY: undefined };\n\n    // Fetch remote config for pageActions in a non-blocking manner\n    if (config.fetchRemoteConfig) {\n      if (!config.remoteConfigClient) {\n        // TODO(xinyi): Diagnostics.recordEvent\n        config.loggerProvider.debug('Remote config client is not provided, skipping remote config fetch');\n      } else {\n        config.remoteConfigClient.subscribe('configs.analyticsSDK.pageActions', 'all', (remoteConfig) => {\n          recomputePageActionsData(remoteConfig as ElementInteractionsOptions['pageActions']);\n        });\n      }\n    }\n\n    // Create should track event functions the different allowlists\n    const shouldTrackEvent = createShouldTrackEvent(\n      options,\n      (options as AutoCaptureOptionsWithDefaults).cssSelectorAllowlist,\n    );\n    const shouldTrackActionClick = createShouldTrackEvent(\n      options,\n      (options as AutoCaptureOptionsWithDefaults).actionClickAllowlist,\n    );\n\n    // Create observables for events on the window\n    const allObservables = createObservables();\n\n    // Create subscriptions\n    const clickTrackingSubscription = trackClicks({\n      allObservables,\n      amplitude,\n      shouldTrackEvent: shouldTrackEvent,\n      evaluateTriggers: evaluateTriggers.evaluate.bind(evaluateTriggers),\n    });\n\n    subscriptions.push(clickTrackingSubscription);\n\n    const changeSubscription = trackChange({\n      allObservables,\n      getEventProperties: (...args) => dataExtractor.getEventProperties(...args, dataAttributePrefix),\n      amplitude,\n      shouldTrackEvent: shouldTrackEvent,\n      evaluateTriggers: evaluateTriggers.evaluate.bind(evaluateTriggers),\n    });\n    subscriptions.push(changeSubscription);\n\n    const actionClickSubscription = trackActionClick({\n      allObservables,\n      options: options as AutoCaptureOptionsWithDefaults,\n      getEventProperties: (...args) => dataExtractor.getEventProperties(...args, dataAttributePrefix),\n      amplitude,\n      shouldTrackEvent,\n      shouldTrackActionClick: shouldTrackActionClick,\n    });\n    if (actionClickSubscription) {\n      subscriptions.push(actionClickSubscription);\n    }\n\n    const scrollTracker = trackScroll({\n      allObservables,\n      amplitude,\n    });\n    subscriptions.push(scrollTracker);\n\n    const trackers: { exposure?: ExposureTracker & Unsubscribable } = {};\n\n    const globalScope = getGlobalScope();\n\n    const handleViewportContentUpdated = (isPageEnd: boolean) => {\n      if (isPageEnd && pageViewEndFired) {\n        return;\n      }\n      setTimeout(() => {\n        pageViewEndFired = false;\n      }, 100);\n\n      pageViewEndFired = true;\n      fireViewportContentUpdated({\n        amplitude,\n        scrollTracker,\n        currentElementExposed,\n        elementExposedForPage,\n        exposureTracker: trackers.exposure,\n        isPageEnd,\n        lastScroll,\n      });\n    };\n\n    const handleExposure = (elementPath: string) => {\n      onExposure(elementPath, elementExposedForPage, currentElementExposed, handleViewportContentUpdated);\n    };\n\n    if (isViewportContentUpdatedEnabled) {\n      trackers.exposure = trackExposure({\n        allObservables,\n        onExposure: handleExposure,\n        dataExtractor,\n        exposureDuration: resolvedExposureDuration,\n      });\n      if (trackers.exposure) {\n        subscriptions.push(trackers.exposure);\n      }\n\n      const beforeUnloadHandler = () => {\n        handleViewportContentUpdated(true);\n      };\n      /* istanbul ignore next */\n      globalScope?.addEventListener('beforeunload', beforeUnloadHandler);\n      beforeUnloadCleanup = () => {\n        /* istanbul ignore next */\n        globalScope?.removeEventListener('beforeunload', beforeUnloadHandler);\n      };\n      // Ensure cleanup on teardown as well\n      subscriptions.push({ unsubscribe: () => beforeUnloadCleanup() });\n\n      // Also track on navigation (SPA)\n      const navigateObservable = allObservables[ObservablesEnum.NavigateObservable];\n      if (navigateObservable) {\n        subscriptions.push(\n          navigateObservable.subscribe(() => {\n            handleViewportContentUpdated(true);\n          }),\n        );\n      } else if (globalScope) {\n        const popstateHandler = () => {\n          handleViewportContentUpdated(true);\n        };\n        /* istanbul ignore next */\n        // Fallback for SPA tracking when Navigation API is not available\n        globalScope.addEventListener('popstate', popstateHandler);\n\n        /* istanbul ignore next */\n        // There is no global browser listener for changes to history, so we have\n        // to modify pushState directly.\n        // https://stackoverflow.com/a/64927639\n        // eslint-disable-next-line @typescript-eslint/unbound-method\n        const originalPushState = globalScope.history.pushState;\n        if (globalScope.history && originalPushState) {\n          // eslint-disable-next-line @typescript-eslint/unbound-method\n          globalScope.history.pushState = new Proxy(originalPushState, {\n            apply: (target, thisArg, [state, unused, url]) => {\n              target.apply(thisArg, [state, unused, url]);\n              handleViewportContentUpdated(true);\n            },\n          });\n        }\n\n        subscriptions.push({\n          unsubscribe: () => {\n            /* istanbul ignore next */\n            globalScope.removeEventListener('popstate', popstateHandler);\n            /* istanbul ignore next */\n            if (globalScope.history && originalPushState) {\n              globalScope.history.pushState = originalPushState;\n            }\n          },\n        });\n      }\n    }\n\n    /* istanbul ignore next */\n    config?.loggerProvider?.log(`${name} has been successfully added.`);\n\n    // Setup visual tagging and background capture on the shared messenger singleton.\n    // Using the singleton ensures a single message listener per page, even when\n    // session-replay is also loaded.\n    if (window.opener && visualTaggingOptions.enabled) {\n      const allowlist = (options as AutoCaptureOptionsWithDefaults).cssSelectorAllowlist;\n      const actionClickAllowlist = (options as AutoCaptureOptionsWithDefaults).actionClickAllowlist;\n\n      const messenger = getOrCreateWindowMessenger();\n      enableVisualTagging(messenger, {\n        dataExtractor,\n        isElementSelectable: createShouldTrackEvent(options, [...allowlist, ...actionClickAllowlist]),\n        cssSelectorAllowlist: allowlist,\n        actionClickAllowlist,\n      });\n      enableBackgroundCapture(messenger);\n      /* istanbul ignore next */\n      messenger.setup({\n        logger: config?.loggerProvider,\n        ...(config?.serverZone && { endpoint: constants.AMPLITUDE_ORIGINS_MAP[config.serverZone] }),\n      });\n    }\n  };\n\n  const execute: BrowserEnrichmentPlugin['execute'] = async (event) => {\n    return event;\n  };\n\n  const teardown = async () => {\n    for (const subscription of subscriptions) {\n      subscription.unsubscribe();\n    }\n  };\n\n  return {\n    name,\n    type,\n    setup,\n    execute,\n    teardown,\n  };\n};\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/src/constants.ts",
    "content": "export const PLUGIN_NAME = '@amplitude/plugin-autocapture-browser';\nexport const FRUSTRATION_PLUGIN_NAME = '@amplitude/plugin-frustration-browser';\nexport const PERFORMANCE_PLUGIN_NAME = '@amplitude/plugin-performance-browser';\n\nexport const AMPLITUDE_ELEMENT_CLICKED_EVENT = '[Amplitude] Element Clicked';\nexport const AMPLITUDE_ELEMENT_DEAD_CLICKED_EVENT = '[Amplitude] Dead Click';\nexport const AMPLITUDE_ELEMENT_RAGE_CLICKED_EVENT = '[Amplitude] Rage Click';\nexport const AMPLITUDE_ELEMENT_ERROR_CLICKED_EVENT = '[Amplitude] Error Click';\nexport const AMPLITUDE_ELEMENT_CHANGED_EVENT = '[Amplitude] Element Changed';\nexport const AMPLITUDE_PAGE_SCROLLED_EVENT = '[Amplitude] Page Scrolled';\nexport const AMPLITUDE_THRASHED_CURSOR_EVENT = '[Amplitude] Thrashed Cursor';\nexport const AMPLITUDE_MAIN_THREAD_BLOCK_EVENT = '[Amplitude] Main Thread Block';\n\nexport const AMPLITUDE_EVENT_PROP_ELEMENT_ID = '[Amplitude] Element ID';\nexport const AMPLITUDE_EVENT_PROP_ELEMENT_CLASS = '[Amplitude] Element Class';\nexport const AMPLITUDE_EVENT_PROP_ELEMENT_TAG = '[Amplitude] Element Tag';\nexport const AMPLITUDE_EVENT_PROP_ELEMENT_TEXT = '[Amplitude] Element Text';\nexport const AMPLITUDE_EVENT_PROP_ELEMENT_HIERARCHY = '[Amplitude] Element Hierarchy';\nexport const AMPLITUDE_EVENT_PROP_ELEMENT_HREF = '[Amplitude] Element Href';\nexport const AMPLITUDE_EVENT_PROP_ELEMENT_POSITION_LEFT = '[Amplitude] Element Position Left';\nexport const AMPLITUDE_EVENT_PROP_ELEMENT_POSITION_TOP = '[Amplitude] Element Position Top';\nexport const AMPLITUDE_EVENT_PROP_ELEMENT_ARIA_LABEL = '[Amplitude] Element Aria Label';\nexport const AMPLITUDE_EVENT_PROP_ELEMENT_ATTRIBUTES = '[Amplitude] Element Attributes';\nexport const AMPLITUDE_EVENT_PROP_ELEMENT_PATH = '[Amplitude] Element Path';\n\nexport const AMPLITUDE_EVENT_PROP_ELEMENT_PARENT_LABEL = '[Amplitude] Element Parent Label';\nexport const AMPLITUDE_EVENT_PROP_PAGE_URL = '[Amplitude] Page URL';\nexport const AMPLITUDE_EVENT_PROP_PAGE_TITLE = '[Amplitude] Page Title';\nexport const AMPLITUDE_EVENT_PROP_VIEWPORT_HEIGHT = '[Amplitude] Viewport Height';\nexport const AMPLITUDE_EVENT_PROP_VIEWPORT_WIDTH = '[Amplitude] Viewport Width';\nexport const AMPLITUDE_EVENT_PROP_MAX_PAGE_X = '[Amplitude] Max Page X';\nexport const AMPLITUDE_EVENT_PROP_MAX_PAGE_Y = '[Amplitude] Max Page Y';\n\nexport const AMPLITUDE_EVENT_PROP_PAGE_VIEW_ID = '[Amplitude] Page View ID';\n\n// Origin constants are now shared via analytics-core; re-export for backwards compatibility\nexport {\n  AMPLITUDE_ORIGIN,\n  AMPLITUDE_ORIGIN_EU,\n  AMPLITUDE_ORIGIN_STAGING,\n  AMPLITUDE_ORIGINS_MAP,\n  AMPLITUDE_BACKGROUND_CAPTURE_SCRIPT_URL,\n} from '@amplitude/analytics-core';\n\nexport const AMPLITUDE_VISUAL_TAGGING_SELECTOR_SCRIPT_URL =\n  'https://cdn.amplitude.com/libs/visual-tagging-selector-1.0.0-alpha.js.gz';\n// This is the class name used by the visual tagging selector to highlight the selected element.\n// Should not use this class in the selector.\nexport const AMPLITUDE_VISUAL_TAGGING_HIGHLIGHT_CLASS = 'amp-visual-tagging-selector-highlight';\n\n// Data attribute for specifying which attributes should be redacted from autocapture\nexport const DATA_AMP_MASK_ATTRIBUTES = 'data-amp-mask-attributes';\n\nexport const MAX_MASK_TEXT_PATTERNS = 25;\n\nexport const MAX_ATTRIBUTE_LENGTH = 128;\n\n// The key for the page view object in sessionStorage\nexport const PAGE_VIEW_SESSION_STORAGE_KEY = 'AMP_PAGE_VIEW';\n\nexport const MAX_ELEMENT_EXPOSED_STR_LENGTH = 18_000;\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/src/data-extractor.ts",
    "content": "/* eslint-disable no-restricted-globals */\nimport {\n  ElementInteractionsOptions,\n  ActionType,\n  getDecodeURI,\n  IDiagnosticsClient,\n  MASKED_TEXT_VALUE,\n  TEXT_MASK_ATTRIBUTE,\n  getPageTitle,\n  replaceSensitiveString,\n} from '@amplitude/analytics-core';\nimport type { DataSource } from '@amplitude/analytics-core/lib/esm/types/element-interactions';\nimport * as constants from './constants';\nimport {\n  removeEmptyProperties,\n  extractPrefixedAttributes,\n  isElementPointerCursor,\n  getClosestElement,\n  isElementBasedEvent,\n  parseAttributesToMask,\n  getCurrentPageViewId,\n} from './helpers';\nimport type { BaseTimestampedEvent, ElementBasedTimestampedEvent, TimestampedEvent, JSONValue } from './helpers';\nimport { getAncestors, getElementProperties } from './hierarchy';\nimport { getDataSource } from './pageActions/actions';\nimport { Hierarchy } from './typings/autocapture';\nimport { cssPath } from './libs/element-path';\n\nexport class DataExtractor {\n  private readonly additionalMaskTextPatterns: RegExp[];\n  diagnosticsClient?: IDiagnosticsClient;\n\n  constructor(options: ElementInteractionsOptions, context?: { diagnosticsClient: IDiagnosticsClient }) {\n    this.diagnosticsClient = context?.diagnosticsClient;\n\n    const rawPatterns = options.maskTextRegex ?? [];\n\n    const compiled: RegExp[] = [];\n    for (const entry of rawPatterns) {\n      if (compiled.length >= constants.MAX_MASK_TEXT_PATTERNS) {\n        break;\n      }\n      if (entry instanceof RegExp) {\n        compiled.push(entry);\n      } else if ('pattern' in entry && typeof entry.pattern === 'string') {\n        try {\n          compiled.push(new RegExp(entry.pattern, 'i'));\n        } catch {\n          // ignore invalid pattern strings\n        }\n      }\n    }\n    this.additionalMaskTextPatterns = compiled;\n  }\n\n  /**\n   * Wrapper method to replace sensitive strings using the helper function\n   * @param text - The text to search for sensitive data\n   * @returns The text with sensitive data replaced by masked text\n   */\n  replaceSensitiveString = (text: string | null): string => {\n    return replaceSensitiveString(text, this.additionalMaskTextPatterns);\n  };\n\n  // Get the DOM hierarchy of the element, starting from the target element to the root element.\n  getHierarchy = (element: Element | null): Hierarchy => {\n    const startTime = performance.now();\n\n    let hierarchy: Hierarchy = [];\n    if (!element) {\n      return [];\n    }\n\n    // Get list of ancestors including itself and get properties at each level in the hierarchy\n    const ancestors = getAncestors(element);\n\n    // Build attributes to mask map\n    const elementToAttributesToMaskMap = new Map<Element, Set<string>>();\n\n    for (let i = ancestors.length - 1; i >= 0; i--) {\n      const node = ancestors[i];\n      if (node) {\n        const attributesToMask = parseAttributesToMask(node.getAttribute(constants.DATA_AMP_MASK_ATTRIBUTES));\n        const ancestorAttributesToMask =\n          i === ancestors.length - 1 ? [] : elementToAttributesToMaskMap.get(ancestors[i + 1]) ?? new Set<string>();\n        const combinedAttributesToMask = new Set([...ancestorAttributesToMask, ...attributesToMask]);\n        elementToAttributesToMaskMap.set(node, combinedAttributesToMask);\n      }\n    }\n\n    hierarchy = ancestors.map((el) =>\n      getElementProperties(el, elementToAttributesToMaskMap.get(el) ?? new Set<string>()),\n    );\n\n    // Search for and mask any sensitive attribute values\n    for (const hierarchyNode of hierarchy) {\n      if (hierarchyNode?.attrs) {\n        Object.entries(hierarchyNode.attrs).forEach(([key, value]) => {\n          if (hierarchyNode.attrs) {\n            hierarchyNode.attrs[key] = this.replaceSensitiveString(value);\n          }\n        });\n      }\n    }\n\n    const endTime = performance.now();\n    this.diagnosticsClient?.recordHistogram('autocapturePlugin.getHierarchy', endTime - startTime);\n\n    return hierarchy;\n  };\n\n  getNearestLabel = (element: Element): string => {\n    const parent = element.parentElement;\n    if (!parent) {\n      return '';\n    }\n    let labelElement: Element | null;\n    try {\n      labelElement = parent.querySelector(':scope>span,h1,h2,h3,h4,h5,h6');\n    } catch {\n      /* istanbul ignore next */\n      labelElement = null;\n    }\n    if (labelElement) {\n      /* istanbul ignore next */\n      return this.getText(labelElement);\n    }\n    return this.getNearestLabel(parent);\n  };\n\n  getElementPath = (element: Element | null): string => {\n    if (!element) {\n      return '';\n    }\n    const startTime = performance.now();\n\n    const elementPath = cssPath(element);\n\n    const endTime = performance.now();\n    this.diagnosticsClient?.recordHistogram('autocapturePlugin.getElementPath', endTime - startTime);\n\n    return elementPath;\n  };\n\n  // Returns the Amplitude event properties for the given element.\n  getEventProperties = (actionType: ActionType, element: Element, dataAttributePrefix: string) => {\n    /* istanbul ignore next */\n    const tag = element?.tagName?.toLowerCase?.();\n    /* istanbul ignore next */\n    const rect =\n      typeof element.getBoundingClientRect === 'function' ? element.getBoundingClientRect() : { left: null, top: null };\n\n    const hierarchy = this.getHierarchy(element);\n    const currentElementAttributes = hierarchy[0]?.attrs;\n    const nearestLabel = this.getNearestLabel(element);\n    const attributes = extractPrefixedAttributes(currentElementAttributes ?? {}, dataAttributePrefix);\n\n    /* istanbul ignore next */\n    const properties: Record<string, any> = {\n      [constants.AMPLITUDE_EVENT_PROP_ELEMENT_HIERARCHY]: hierarchy,\n      [constants.AMPLITUDE_EVENT_PROP_ELEMENT_TAG]: tag,\n      [constants.AMPLITUDE_EVENT_PROP_ELEMENT_TEXT]: this.getText(element),\n      [constants.AMPLITUDE_EVENT_PROP_ELEMENT_POSITION_LEFT]: rect.left == null ? null : Math.round(rect.left),\n      [constants.AMPLITUDE_EVENT_PROP_ELEMENT_POSITION_TOP]: rect.top == null ? null : Math.round(rect.top),\n      [constants.AMPLITUDE_EVENT_PROP_ELEMENT_ATTRIBUTES]: attributes,\n      [constants.AMPLITUDE_EVENT_PROP_ELEMENT_PATH]: this.getElementPath(element),\n      [constants.AMPLITUDE_EVENT_PROP_ELEMENT_PARENT_LABEL]: nearestLabel,\n      [constants.AMPLITUDE_EVENT_PROP_PAGE_URL]: getDecodeURI(window.location.href.split('?')[0]),\n      [constants.AMPLITUDE_EVENT_PROP_PAGE_TITLE]: (\n        getPageTitle as (parseTitleFunction: (title: string) => string) => string\n      )(this.replaceSensitiveString),\n      [constants.AMPLITUDE_EVENT_PROP_VIEWPORT_HEIGHT]: window.innerHeight,\n      [constants.AMPLITUDE_EVENT_PROP_VIEWPORT_WIDTH]: window.innerWidth,\n    };\n\n    const pageViewId = getCurrentPageViewId();\n    /* istanbul ignore next */\n    if (pageViewId) {\n      /* istanbul ignore next */\n      properties[constants.AMPLITUDE_EVENT_PROP_PAGE_VIEW_ID] = pageViewId;\n    }\n\n    // id is never masked, so always include it\n    properties[constants.AMPLITUDE_EVENT_PROP_ELEMENT_ID] = element.getAttribute('id') || '';\n\n    // class is never masked, so always include it\n    properties[constants.AMPLITUDE_EVENT_PROP_ELEMENT_CLASS] = element.getAttribute('class');\n\n    properties[constants.AMPLITUDE_EVENT_PROP_ELEMENT_ARIA_LABEL] = currentElementAttributes?.['aria-label'];\n\n    if (tag === 'a' && actionType === 'click' && element instanceof HTMLAnchorElement) {\n      const href = element.href.substring(0, constants.MAX_ATTRIBUTE_LENGTH);\n      properties[constants.AMPLITUDE_EVENT_PROP_ELEMENT_HREF] = this.replaceSensitiveString(href); // we don't use hierarchy here because we don't want href value to be changed\n    }\n\n    return removeEmptyProperties(properties);\n  };\n\n  addTypeAndTimestamp = <T>(\n    event: T,\n    type: BaseTimestampedEvent<T>['type'] | ElementBasedTimestampedEvent<T>['type'],\n  ): BaseTimestampedEvent<T> | ElementBasedTimestampedEvent<T> => {\n    return {\n      event,\n      timestamp: Date.now(),\n      type,\n    };\n  };\n\n  addAdditionalEventProperties = <T>(\n    event: T,\n    type: TimestampedEvent<T>['type'],\n    selectorAllowlist: string[],\n    dataAttributePrefix: string,\n    // capture the event if the cursor is a \"pointer\" when this element is clicked on\n    // reason: a \"pointer\" cursor indicates that an element should be interactable\n    //         regardless of the element's tag name\n    isCapturingCursorPointer = false,\n  ): TimestampedEvent<T> | ElementBasedTimestampedEvent<T> => {\n    const baseEvent = this.addTypeAndTimestamp(event, type);\n\n    if (isElementBasedEvent(baseEvent) && baseEvent.event.target !== null) {\n      if (isCapturingCursorPointer) {\n        const isCursorPointer = isElementPointerCursor(baseEvent.event.target as Element, baseEvent.type);\n        if (isCursorPointer) {\n          baseEvent.closestTrackedAncestor = baseEvent.event.target as HTMLElement;\n          baseEvent.targetElementProperties = this.getEventProperties(\n            baseEvent.type,\n            baseEvent.closestTrackedAncestor,\n            dataAttributePrefix,\n          );\n          return baseEvent;\n        }\n      }\n      // Retrieve additional event properties from the target element\n      const closestTrackedAncestor = getClosestElement(baseEvent.event.target as HTMLElement, selectorAllowlist);\n      if (closestTrackedAncestor) {\n        baseEvent.closestTrackedAncestor = closestTrackedAncestor;\n        baseEvent.targetElementProperties = this.getEventProperties(\n          baseEvent.type,\n          closestTrackedAncestor,\n          dataAttributePrefix,\n        );\n      }\n      return baseEvent;\n    }\n\n    return baseEvent;\n  };\n\n  extractDataFromDataSource = (dataSource: DataSource, contextElement: HTMLElement) => {\n    // Extract from DOM Element\n    if (dataSource.sourceType === 'DOM_ELEMENT') {\n      const sourceElement = getDataSource(dataSource, contextElement);\n      if (!sourceElement) {\n        return undefined;\n      }\n\n      if (dataSource.elementExtractType === 'TEXT') {\n        return this.getText(sourceElement);\n      } else if (dataSource.elementExtractType === 'ATTRIBUTE' && dataSource.attribute) {\n        return sourceElement.getAttribute(dataSource.attribute);\n      }\n      return undefined;\n    }\n\n    // TODO: Extract from other source types\n    return undefined;\n  };\n\n  // Traverse text content without cloning DOM nodes, which avoids media/network side effects\n  // from recreating nested elements such as <video>, <audio>, or <img>.\n  private getTextWithMaskedDescendants = (element: Element): string => {\n    const maskedSelector = `[${TEXT_MASK_ATTRIBUTE}], [contenteditable]`;\n    // Fast path: if no masked descendants exist, rely on native text extraction.\n    if (!element.querySelector(maskedSelector)) {\n      return (element as HTMLElement).innerText;\n    }\n\n    let output = '';\n    const childNodes = Array.from(element.childNodes);\n    for (const childNode of childNodes) {\n      if (childNode.nodeType === Node.TEXT_NODE) {\n        output += childNode.textContent || '';\n        continue;\n      }\n\n      if (!(childNode instanceof Element)) {\n        continue;\n      }\n\n      // Replace entire masked/contenteditable subtrees with the mask token.\n      if (childNode.hasAttribute(TEXT_MASK_ATTRIBUTE) || childNode.hasAttribute('contenteditable')) {\n        output += MASKED_TEXT_VALUE;\n        continue;\n      }\n      output += this.getTextWithMaskedDescendants(childNode);\n    }\n    return output;\n  };\n\n  getText = (element: Element): string => {\n    // Check if element or any parent has data-amp-mask attribute\n    const hasMaskAttribute = element.closest(`[${TEXT_MASK_ATTRIBUTE}]`) !== null;\n    if (hasMaskAttribute) {\n      return MASKED_TEXT_VALUE;\n    }\n    let output = '';\n    if (!element.querySelector(`[${TEXT_MASK_ATTRIBUTE}], [contenteditable]`)) {\n      output = (element as HTMLElement).innerText || '';\n    } else {\n      output = this.getTextWithMaskedDescendants(element);\n    }\n    return this.replaceSensitiveString(output.substring(0, 255)).replace(/\\s+/g, ' ').trim();\n  };\n\n  // Returns the element properties for the given element in Visual Labeling.\n  getEventTagProps = (element: Element): Record<string, JSONValue> => {\n    if (!element) {\n      return {};\n    }\n    /* istanbul ignore next */\n    const tag = element?.tagName?.toLowerCase?.();\n\n    const properties = {\n      [constants.AMPLITUDE_EVENT_PROP_ELEMENT_TAG]: tag,\n      [constants.AMPLITUDE_EVENT_PROP_ELEMENT_TEXT]: this.getText(element),\n      [constants.AMPLITUDE_EVENT_PROP_PAGE_URL]: window.location.href.split('?')[0],\n    };\n    return removeEmptyProperties(properties) as Record<string, JSONValue>;\n  };\n}\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/src/frustration-plugin.ts",
    "content": "/* eslint-disable no-restricted-globals */\nimport {\n  BrowserClient,\n  BrowserConfig,\n  EnrichmentPlugin,\n  FrustrationInteractionsOptions,\n  DEFAULT_DATA_ATTRIBUTE_PREFIX,\n  multicast,\n  Observable,\n  Unsubscribable,\n  DEFAULT_RAGE_CLICK_ALLOWLIST,\n  DEFAULT_DEAD_CLICK_ALLOWLIST,\n  DEFAULT_ERROR_CLICK_ALLOWLIST,\n} from '@amplitude/analytics-core';\nimport * as constants from './constants';\nimport { createShouldTrackEvent, ElementBasedTimestampedEvent, NavigateEvent, TimestampedEvent } from './helpers';\nimport { trackDeadClick } from './autocapture/track-dead-click';\nimport { trackRageClicks } from './autocapture/track-rage-click';\nimport { ObservablesEnum } from './autocapture-plugin';\nimport {\n  BrowserErrorEvent,\n  createClickObservable,\n  createErrorObservable,\n  createMutationObservable,\n  createMouseMoveObservable,\n} from './observables';\nimport { DataExtractor } from './data-extractor';\nimport { trackErrorClicks } from './autocapture/track-error-click';\nimport { trackThrashedCursor } from './autocapture/track-thrashed-cursor';\n\nexport interface AllWindowObservables {\n  [ObservablesEnum.ClickObservable]: Observable<ElementBasedTimestampedEvent<MouseEvent>>;\n  [ObservablesEnum.MutationObservable]: Observable<TimestampedEvent<MutationRecord[]>>;\n  [ObservablesEnum.BrowserErrorObservable]: Observable<TimestampedEvent<BrowserErrorEvent>>;\n  [ObservablesEnum.NavigateObservable]?: Observable<TimestampedEvent<NavigateEvent>>;\n  [ObservablesEnum.SelectionObservable]?: Observable<void>;\n  [ObservablesEnum.MouseMoveObservable]: Observable<MouseEvent>;\n}\n\ntype BrowserEnrichmentPlugin = EnrichmentPlugin<BrowserClient, BrowserConfig>;\n\n/**\n * Helper function to extract the css selector allowlist\n * from the frustration interactions options for a specific\n * autocapture feature.\n */\nfunction getCssSelectorAllowlist(\n  options: FrustrationInteractionsOptions,\n  attribute: keyof FrustrationInteractionsOptions,\n  defaultAllowlist: string[],\n  enabled: boolean,\n): string[] {\n  if (!enabled) {\n    return [];\n  }\n  const config = options[attribute];\n  if (\n    typeof config === 'object' &&\n    config !== null &&\n    'cssSelectorAllowlist' in config &&\n    Array.isArray(config.cssSelectorAllowlist)\n  ) {\n    return config.cssSelectorAllowlist;\n  }\n  return defaultAllowlist;\n}\n\nconst MINIMUM_THRASHED_CURSOR_DIRECTION_CHANGES = 5;\nconst MAXIMUM_THRASHED_CURSOR_THRESHOLD = 4000;\n\nexport const frustrationPlugin = (options: FrustrationInteractionsOptions = {}): BrowserEnrichmentPlugin => {\n  const name = constants.FRUSTRATION_PLUGIN_NAME;\n  const type = 'enrichment';\n\n  const subscriptions: Unsubscribable[] = [];\n\n  let isErrorClicksEnabled = options.errorClicks !== false;\n\n  // if errorClicks is not defined, disable it\n  // change this once it moves out of @experimental\n  if (!options.errorClicks) {\n    isErrorClicksEnabled = false;\n  }\n\n  // Check if each feature is enabled\n  const deadClicksEnabled = options.deadClicks !== false && options.deadClicks !== null;\n  const rageClicksEnabled = options.rageClicks !== false && options.rageClicks !== null;\n\n  let thrashedCursorEnabled = options.thrashedCursor !== false && options.thrashedCursor !== null;\n  if (!options.thrashedCursor) {\n    thrashedCursorEnabled = false;\n  }\n\n  // Get CSS selectors for enabled features\n  const rageCssSelectors = getCssSelectorAllowlist(\n    options,\n    'rageClicks',\n    DEFAULT_RAGE_CLICK_ALLOWLIST,\n    rageClicksEnabled,\n  );\n\n  const deadCssSelectors = getCssSelectorAllowlist(\n    options,\n    'deadClicks',\n    DEFAULT_DEAD_CLICK_ALLOWLIST,\n    deadClicksEnabled,\n  );\n\n  const errorCssSelectors = getCssSelectorAllowlist(\n    options,\n    'errorClicks',\n    DEFAULT_ERROR_CLICK_ALLOWLIST,\n    isErrorClicksEnabled,\n  );\n\n  const dataAttributePrefix = options.dataAttributePrefix ?? DEFAULT_DATA_ATTRIBUTE_PREFIX;\n\n  const dataExtractor = new DataExtractor(options);\n\n  // combine the selector lists from enabled features to determine which clicked elements should be filtered\n  const combinedCssSelectors = [...new Set([...rageCssSelectors, ...deadCssSelectors, ...errorCssSelectors])];\n\n  // Create observables on events on the window\n  const createObservables = (): AllWindowObservables => {\n    const clickObservable = multicast(\n      createClickObservable('pointerdown').map((click) => {\n        return dataExtractor.addAdditionalEventProperties(\n          click,\n          'click',\n          combinedCssSelectors,\n          dataAttributePrefix,\n          true, // capture when cursor is pointer\n        );\n      }),\n    );\n\n    const browserErrorObservables = multicast(\n      createErrorObservable().map((error) => {\n        return dataExtractor.addTypeAndTimestamp(error, 'error');\n      }),\n    );\n\n    const enrichedMutationObservable = multicast<TimestampedEvent<MutationRecord[]>>(\n      createMutationObservable().map((mutation) =>\n        dataExtractor.addAdditionalEventProperties(mutation, 'mutation', combinedCssSelectors, dataAttributePrefix),\n      ),\n    );\n\n    let enrichedNavigateObservable: Observable<TimestampedEvent<NavigateEvent>> | undefined;\n\n    if (window.navigation) {\n      const navigateObservable = new Observable<Event>((observer) => {\n        const handler = (event: Event): void => {\n          observer.next({\n            ...event,\n            type: 'navigate',\n          });\n        };\n        window.navigation.addEventListener('navigate', handler);\n        return () => {\n          window.navigation.removeEventListener('navigate', handler);\n        };\n      });\n      enrichedNavigateObservable = multicast<TimestampedEvent<NavigateEvent>>(\n        navigateObservable.map<TimestampedEvent<NavigateEvent>>(\n          (navigate) =>\n            dataExtractor.addAdditionalEventProperties(\n              navigate,\n              'navigate',\n              combinedCssSelectors,\n              dataAttributePrefix,\n            ) as TimestampedEvent<NavigateEvent>,\n        ),\n      );\n    }\n\n    const selectionObservable = multicast(\n      new Observable<void>((observer) => {\n        const handler = () => {\n          const el: HTMLElement | null = document.activeElement as HTMLElement;\n\n          // handle input and textarea\n\n          // if the selectionStart and selectionEnd are the same, it means\n          // nothing is selected (collapsed) and the cursor position is one point\n          if (el && (el.tagName === 'TEXTAREA' || el.tagName === 'INPUT')) {\n            let start: number | null | undefined;\n            let end: number | null | undefined;\n            try {\n              start = (el as HTMLInputElement | HTMLTextAreaElement).selectionStart;\n              end = (el as HTMLInputElement | HTMLTextAreaElement).selectionEnd;\n              if (start === end) return; // collapsed\n            } catch (error) {\n              // input that doesn't support selectionStart/selectionEnd (like checkbox)\n              // do nothing here\n              return;\n            }\n            return observer.next();\n          }\n\n          // handle non-input elements\n\n          // non-input elements have an attribute called \"isCollapsed\" which\n          // if true, indicates there \"is currently not any text selected\"\n          // (see https://developer.mozilla.org/en-US/docs/Web/API/Selection/isCollapsed)\n          const selection = window.getSelection();\n          if (!selection || selection.isCollapsed) return;\n          return observer.next();\n        };\n        window.document.addEventListener('selectionchange', handler);\n        return () => {\n          window.document.removeEventListener('selectionchange', handler);\n        };\n      }),\n    );\n\n    const mouseMoveObservable = multicast(createMouseMoveObservable());\n\n    return {\n      [ObservablesEnum.ClickObservable]: clickObservable as Observable<ElementBasedTimestampedEvent<MouseEvent>>,\n      [ObservablesEnum.MutationObservable]: enrichedMutationObservable,\n      [ObservablesEnum.NavigateObservable]: enrichedNavigateObservable,\n      [ObservablesEnum.BrowserErrorObservable]: browserErrorObservables,\n      [ObservablesEnum.SelectionObservable]: selectionObservable,\n      [ObservablesEnum.MouseMoveObservable]: mouseMoveObservable,\n    };\n  };\n\n  const setup: BrowserEnrichmentPlugin['setup'] = async (config, amplitude) => {\n    /* istanbul ignore if */\n    if (typeof document === 'undefined') {\n      return;\n    }\n\n    // Create observables for events on the window\n    const allObservables = createObservables();\n\n    // Create subscriptions only for enabled features\n    if (rageClicksEnabled) {\n      const shouldTrackRageClick = createShouldTrackEvent(options, rageCssSelectors);\n      const rageClickSubscription = trackRageClicks({\n        allObservables,\n        amplitude,\n        shouldTrackRageClick,\n      });\n      subscriptions.push(rageClickSubscription);\n    }\n\n    if (deadClicksEnabled) {\n      const shouldTrackDeadClick = createShouldTrackEvent(options, deadCssSelectors);\n      const deadClickSubscription = trackDeadClick({\n        amplitude,\n        allObservables,\n        getEventProperties: (actionType, element) =>\n          dataExtractor.getEventProperties(actionType, element, dataAttributePrefix),\n        shouldTrackDeadClick,\n      });\n      subscriptions.push(deadClickSubscription);\n    }\n\n    if (isErrorClicksEnabled) {\n      const shouldTrackErrorClick = createShouldTrackEvent(options, errorCssSelectors);\n      const errorClickSubscription = trackErrorClicks({\n        amplitude,\n        allObservables,\n        shouldTrackErrorClick,\n      });\n      subscriptions.push(errorClickSubscription);\n    }\n\n    if (thrashedCursorEnabled) {\n      let directionChanges, thresholdMs;\n      if (typeof options.thrashedCursor === 'object') {\n        directionChanges = options.thrashedCursor.directionChanges;\n        thresholdMs = options.thrashedCursor.threshold;\n\n        if (directionChanges && directionChanges < MINIMUM_THRASHED_CURSOR_DIRECTION_CHANGES) {\n          config.loggerProvider.warn(\n            `'thrashedCursor.directionChanges' of ${directionChanges} is below the minimum of ${MINIMUM_THRASHED_CURSOR_DIRECTION_CHANGES}, setting to ${MINIMUM_THRASHED_CURSOR_DIRECTION_CHANGES}`,\n          );\n          directionChanges = MINIMUM_THRASHED_CURSOR_DIRECTION_CHANGES;\n        }\n        if (thresholdMs && thresholdMs > MAXIMUM_THRASHED_CURSOR_THRESHOLD) {\n          config.loggerProvider.warn(\n            `'thrashedCursor.threshold' of ${thresholdMs} is above the maximum of ${MAXIMUM_THRASHED_CURSOR_THRESHOLD}, setting to ${MAXIMUM_THRASHED_CURSOR_THRESHOLD}`,\n          );\n          thresholdMs = MAXIMUM_THRASHED_CURSOR_THRESHOLD;\n        }\n      }\n      const thrashedCursorSubscription = trackThrashedCursor({\n        amplitude,\n        options,\n        allObservables,\n        directionChanges,\n        thresholdMs,\n      });\n      subscriptions.push(thrashedCursorSubscription);\n    }\n\n    /* istanbul ignore next */\n    config?.loggerProvider?.log(`${name} has been successfully added.`);\n  };\n\n  const execute: BrowserEnrichmentPlugin['execute'] = async (event) => {\n    return event;\n  };\n\n  const teardown = async () => {\n    for (const subscription of subscriptions) {\n      subscription.unsubscribe();\n    }\n  };\n\n  return {\n    name,\n    type,\n    setup,\n    execute,\n    teardown,\n  };\n};\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/src/helpers.ts",
    "content": "/* eslint-disable no-restricted-globals */\nimport { ElementInteractionsOptions, ActionType, isUrlMatchAllowlist, getGlobalScope } from '@amplitude/analytics-core';\nimport * as constants from './constants';\n\nexport type JSONValue = string | number | boolean | null | { [x: string]: JSONValue } | Array<JSONValue>;\n\nconst SENSITIVE_TAGS = ['input', 'select', 'textarea'];\n\nexport type shouldTrackEvent = (actionType: ActionType, element: Element) => boolean;\n\nexport const isElementPointerCursor = (element: Element, actionType: ActionType): boolean => {\n  /* istanbul ignore next */\n  const computedStyle = window?.getComputedStyle?.(element);\n  /* istanbul ignore next */\n  return computedStyle?.getPropertyValue('cursor') === 'pointer' && actionType === 'click';\n};\n\nexport const isUrlAllowed = (autocaptureOptions: ElementInteractionsOptions): boolean => {\n  const { pageUrlAllowlist, pageUrlExcludelist } = autocaptureOptions;\n\n  // check if the URL is in the excludelist\n  if (\n    pageUrlExcludelist &&\n    pageUrlExcludelist.length > 0 &&\n    isUrlMatchAllowlist(window.location.href, pageUrlExcludelist as (string | RegExp)[])\n  ) {\n    return false;\n  }\n\n  // check if the URL is in the allow list\n  if (!isUrlMatchAllowlist(window.location.href, pageUrlAllowlist)) {\n    return false;\n  }\n\n  return true;\n};\n\nexport const createShouldTrackEvent = (\n  autocaptureOptions: ElementInteractionsOptions,\n  allowlist: string[], // this can be any type of css selector allow list\n  isAlwaysCaptureCursorPointer = false,\n): shouldTrackEvent => {\n  return (actionType: ActionType, element: Element) => {\n    const { shouldTrackEventResolver } = autocaptureOptions;\n\n    /* istanbul ignore next */\n    const tag = element?.tagName?.toLowerCase?.();\n    // window, document, and Text nodes have no tag\n    if (!tag) {\n      return false;\n    }\n\n    if (shouldTrackEventResolver) {\n      return shouldTrackEventResolver(actionType, element);\n    }\n\n    if (!isUrlAllowed(autocaptureOptions)) {\n      return false;\n    }\n\n    /* istanbul ignore next */\n    const elementType = String(element?.getAttribute('type')) || '';\n    if (typeof elementType === 'string') {\n      switch (elementType.toLowerCase()) {\n        case 'hidden':\n          return false;\n        case 'password':\n          return false;\n      }\n    }\n\n    const isCursorPointer = isElementPointerCursor(element, actionType);\n\n    if (isAlwaysCaptureCursorPointer && isCursorPointer) {\n      return true;\n    }\n\n    /* istanbul ignore if */\n    if (allowlist) {\n      const hasMatchAnyAllowedSelector = allowlist.some((selector) => !!element?.matches?.(selector));\n      if (!hasMatchAnyAllowedSelector) {\n        return false;\n      }\n    }\n\n    switch (tag) {\n      case 'input':\n      case 'select':\n      case 'textarea':\n        return actionType === 'change' || actionType === 'click';\n      default: {\n        /* istanbul ignore next */\n        /* istanbul ignore next */\n        if (isCursorPointer) {\n          return true;\n        }\n        return actionType === 'click';\n      }\n    }\n  };\n};\n\nexport const isTextNode = (node: Node) => {\n  return !!node && node.nodeType === 3;\n};\n\nexport const isNonSensitiveElement = (element: Element) => {\n  /* istanbul ignore next */\n  const tag = element?.tagName?.toLowerCase?.();\n  const isContentEditable =\n    element instanceof HTMLElement ? element.getAttribute('contenteditable')?.toLowerCase() === 'true' : false;\n\n  return !SENSITIVE_TAGS.includes(tag) && !isContentEditable;\n};\n\n/**\n * Collects redacted attribute names from element and ancestor elements with data-amp-mask-attributes\n * The 'id' and 'class' attributes cannot be redacted as they're critical for element identification\n * @param element - The target element to check for redaction attributes\n * @returns Set of attribute names that should be redacted\n */\n/**\n * Parses a comma-separated string of attribute names and filters out protected attributes\n * @param attributeString - Comma-separated string of attribute names\n * @returns Array of valid attribute names, excluding 'id' and 'class'\n */\nexport const parseAttributesToMask = (attributeString: string | null): string[] => {\n  return attributeString\n    ? attributeString\n        .split(',')\n        .map((attr) => attr.trim())\n        .filter((attr) => attr.length > 0 && attr !== 'id' && attr !== 'class') // Prevent 'id' and 'class' from being redacted as they're critical for element identification\n    : [];\n};\n\nexport const extractPrefixedAttributes = (\n  attrs: { [key: string]: string },\n  prefix: string,\n): { [key: string]: string } => {\n  return Object.entries(attrs).reduce((attributes: { [key: string]: string }, [attributeName, attributeValue]) => {\n    if (attributeName.startsWith(prefix)) {\n      const attributeKey = attributeName.replace(prefix, '');\n\n      if (attributeKey) {\n        attributes[attributeKey] = attributeValue || '';\n      }\n    }\n    return attributes;\n  }, {});\n};\n\nexport const isEmpty = (value: unknown) => {\n  return (\n    value === undefined ||\n    value === null ||\n    (typeof value === 'object' && Object.keys(value).length === 0) ||\n    (typeof value === 'string' && value.trim().length === 0)\n  );\n};\n\nexport const removeEmptyProperties = (properties: { [key: string]: unknown }): { [key: string]: unknown } => {\n  return Object.keys(properties).reduce((filteredProperties: { [key: string]: unknown }, key) => {\n    const value = properties[key];\n    if (!isEmpty(value)) {\n      filteredProperties[key] = value;\n    }\n    return filteredProperties;\n  }, {});\n};\n\nexport const getCurrentPageViewId = (): string | undefined => {\n  try {\n    const globalScope = getGlobalScope();\n    /* istanbul ignore next */\n    const raw = globalScope?.sessionStorage?.getItem(constants.PAGE_VIEW_SESSION_STORAGE_KEY);\n    if (!raw) {\n      return undefined;\n    }\n    const parsed = JSON.parse(raw) as { pageViewId?: unknown };\n    if (typeof parsed.pageViewId === 'string') {\n      return parsed.pageViewId;\n    }\n  } catch {\n    // ignore storage access or JSON errors\n  }\n  return undefined;\n};\n\nexport const querySelectUniqueElements = (root: Element | Document, selectors: string[]): Element[] => {\n  if (root && 'querySelectorAll' in root && typeof root.querySelectorAll === 'function') {\n    const elementSet = selectors.reduce((elements: Set<Element>, selector) => {\n      if (selector) {\n        const selectedElements = Array.from(root.querySelectorAll(selector));\n        selectedElements.forEach((element) => {\n          elements.add(element);\n        });\n      }\n      return elements;\n    }, new Set<Element>());\n    return Array.from(elementSet);\n  }\n  return [];\n};\n\n// Similar as element.closest, but works with multiple selectors\nexport const getClosestElement = (element: Element | null, selectors: string[]): Element | null => {\n  if (!element) {\n    return null;\n  }\n  /* istanbul ignore next */\n  if (selectors.some((selector) => element?.matches?.(selector))) {\n    return element;\n  }\n  /* istanbul ignore next */\n  return getClosestElement(element?.parentElement, selectors);\n};\n\nexport const asyncLoadScript = (url: string) => {\n  return new Promise((resolve, reject) => {\n    try {\n      const scriptElement = document.createElement('script');\n      scriptElement.type = 'text/javascript';\n      scriptElement.async = true;\n      scriptElement.src = url;\n      scriptElement.addEventListener(\n        'load',\n        () => {\n          resolve({ status: true });\n        },\n        { once: true },\n      );\n      scriptElement.addEventListener('error', () => {\n        reject({\n          status: false,\n          message: `Failed to load the script ${url}`,\n        });\n      });\n      /* istanbul ignore next */\n      document.head?.appendChild(scriptElement);\n    } catch (error) {\n      /* istanbul ignore next */\n      reject(error);\n    }\n  });\n};\n\nexport function generateUniqueId(): string {\n  return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n}\n\nexport const filterOutNonTrackableEvents = (event: ElementBasedTimestampedEvent<ElementBasedEvent>): boolean => {\n  // Filter out changeEvent events with no target\n  // This could happen when change events are triggered programmatically\n  if (event.event.target === null || !event.closestTrackedAncestor) {\n    return false;\n  }\n\n  return true;\n};\n\nexport type AutoCaptureOptionsWithDefaults = Required<\n  Pick<ElementInteractionsOptions, 'debounceTime' | 'cssSelectorAllowlist' | 'actionClickAllowlist'>\n> &\n  ElementInteractionsOptions;\n\n// Base TimestampedEvent type\nexport type BaseTimestampedEvent<T> = {\n  event: T;\n  timestamp: number;\n  type: 'rage' | 'click' | 'change' | 'error' | 'navigate' | 'mutation';\n};\n\n// Specific types for events with targetElementProperties\nexport type ElementBasedEvent = MouseEvent | Event;\nexport type ElementBasedTimestampedEvent<T> = BaseTimestampedEvent<T> & {\n  event: MouseEvent | Event;\n  type: 'click' | 'change';\n  closestTrackedAncestor: Element;\n  targetElementProperties: Record<string, any>;\n};\n\nexport type evaluateTriggersFn = (\n  event: ElementBasedTimestampedEvent<ElementBasedEvent>,\n) => ElementBasedTimestampedEvent<ElementBasedEvent>;\n\n// Union type for all possible TimestampedEvents\nexport type TimestampedEvent<T> = BaseTimestampedEvent<T> | ElementBasedTimestampedEvent<T>;\n\n// Type predicate\nexport function isElementBasedEvent<T>(event: BaseTimestampedEvent<T>): event is ElementBasedTimestampedEvent<T> {\n  return event.type === 'click' || event.type === 'change';\n}\n\nexport interface NavigateEvent extends Event {\n  readonly navigationType: 'reload' | 'push' | 'replace' | 'traverse';\n  readonly destination: {\n    readonly url: string;\n    readonly key: string | null;\n    readonly id: string | null;\n    readonly index: number;\n    readonly sameDocument: boolean;\n\n    getState(): any;\n  };\n  readonly canIntercept: boolean;\n  readonly userInitiated: boolean;\n  readonly hashChange: boolean;\n  readonly signal: AbortSignal;\n  readonly formData: FormData | null;\n  readonly downloadRequest: string | null;\n  readonly info: any;\n  readonly hasUAVisualTransition: boolean;\n  /** @see https://github.com/WICG/navigation-api/pull/264 */\n  readonly sourceElement: Element | null;\n\n  scroll(): void;\n}\n\nexport enum MouseButton {\n  LEFT_OR_TOUCH_CONTACT = 0,\n  MIDDLE = 1,\n  RIGHT = 2,\n}\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/src/hierarchy.ts",
    "content": "import { isNonSensitiveElement } from './helpers';\nimport { DATA_AMP_MASK_ATTRIBUTES } from './constants';\nimport type { HierarchyNode } from './typings/autocapture';\nimport * as constants from './constants';\nimport { MASKED_TEXT_VALUE, TEXT_MASK_ATTRIBUTE } from '@amplitude/analytics-core';\n\nconst BLOCKED_ATTRIBUTES = new Set([\n  // Already captured elsewhere in the hierarchy object\n  'id',\n  'class',\n\n  // non-useful and potentially large attribute\n  'style',\n\n  // sensitive as prefilled form data may populate this attribute\n  'value',\n\n  // DOM events\n  'onclick',\n  'onchange',\n  'oninput',\n  'onblur',\n  'onsubmit',\n  'onfocus',\n  'onkeydown',\n  'onkeyup',\n  'onkeypress',\n\n  // React specific\n  'data-reactid',\n  'data-react-checksum',\n  'data-reactroot',\n\n  // Amplitude specific - used for redaction but should not be included in getElementProperties\n  DATA_AMP_MASK_ATTRIBUTES,\n  TEXT_MASK_ATTRIBUTE,\n]);\nconst SENSITIVE_ELEMENT_ATTRIBUTE_ALLOWLIST = ['type'];\n\nconst SVG_TAGS = ['svg', 'path', 'g'];\nconst HIGHLY_SENSITIVE_INPUT_TYPES = ['password', 'hidden'];\nexport const MAX_HIERARCHY_LENGTH = 1024;\n\nexport function getElementProperties(\n  element: Element | null,\n  userMaskedAttributeNames: Set<string>,\n): HierarchyNode | null {\n  if (element === null) {\n    return null;\n  }\n\n  const tagName = String(element.tagName).toLowerCase();\n  const properties: HierarchyNode = {\n    tag: tagName,\n  };\n\n  const siblings = Array.from(element.parentElement?.children ?? []);\n  if (siblings.length) {\n    properties.index = siblings.indexOf(element);\n    properties.indexOfType = siblings.filter((el) => el.tagName === element.tagName).indexOf(element);\n  }\n\n  const prevSiblingTag = element.previousElementSibling?.tagName?.toLowerCase();\n  if (prevSiblingTag) {\n    properties.prevSib = String(prevSiblingTag);\n  }\n\n  const id = element.getAttribute('id');\n  if (id) {\n    properties.id = String(id);\n  }\n\n  const classes = Array.from(element.classList);\n  if (classes.length) {\n    properties.classes = classes;\n  }\n\n  const attributes: Record<string, string> = {};\n  const attributesArray = Array.from(element.attributes);\n  const filteredAttributes = attributesArray.filter((attr) => !BLOCKED_ATTRIBUTES.has(attr.name));\n  const isSensitiveElement = !isNonSensitiveElement(element);\n\n  // if input is hidden or password or for SVGs, skip attribute collection entirely\n  if (!HIGHLY_SENSITIVE_INPUT_TYPES.includes(String(element.getAttribute('type'))) && !SVG_TAGS.includes(tagName)) {\n    for (const attr of filteredAttributes) {\n      // If sensitive element, only allow certain attributes\n      if (isSensitiveElement && !SENSITIVE_ELEMENT_ATTRIBUTE_ALLOWLIST.includes(attr.name)) {\n        continue;\n      }\n\n      if (userMaskedAttributeNames.has(attr.name)) {\n        attributes[attr.name] = MASKED_TEXT_VALUE;\n        continue;\n      }\n\n      // Finally cast attribute value to string and limit attribute value length\n      attributes[attr.name] = String(attr.value).substring(0, constants.MAX_ATTRIBUTE_LENGTH);\n    }\n  }\n\n  if (Object.keys(attributes).length) {\n    properties.attrs = attributes;\n  }\n\n  return properties;\n}\n\nexport function getAncestors(targetEl: Element | null): Element[] {\n  const ancestors: Element[] = [];\n\n  if (!targetEl) {\n    return ancestors;\n  }\n\n  // Add self to the list of ancestors\n  ancestors.push(targetEl);\n  let current = targetEl.parentElement;\n  while (current && current.tagName !== 'HTML') {\n    ancestors.push(current);\n    current = current.parentElement;\n  }\n  return ancestors;\n}\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/src/index.ts",
    "content": "export { autocapturePlugin as plugin, autocapturePlugin } from './autocapture-plugin';\nexport { frustrationPlugin } from './frustration-plugin';\nexport { performancePlugin } from './performance-plugin';\nexport { Action, ActionData, Message, enableVisualTagging } from './libs/messenger';\nexport { DataExtractor } from './data-extractor';\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/src/libs/element-path.ts",
    "content": "/* istanbul ignore file */\n\n// Code is adapted from The Chromium Authors.\n// Source: https://github.com/ChromeDevTools/devtools-frontend/blob/main/front_end/panels/elements/DOMPath.ts#L14\n// License: BSD-style license\n//\n// Copyright 2014 The Chromium Authors\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//    * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//    * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//    * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nclass Step {\n  constructor(public value: string, public optimized: boolean) {}\n  toString() {\n    return this.value;\n  }\n}\n\nexport const cssPath = function (node: Element, optimized?: boolean): string {\n  // `node` is already an Element; this check is defensive.\n  if (node.nodeType !== Node.ELEMENT_NODE) {\n    return '';\n  }\n\n  const steps: Step[] = [];\n  let contextNode: Element | null = node;\n\n  while (contextNode) {\n    const step = cssPathStep(contextNode, Boolean(optimized), contextNode === node);\n    if (!step) {\n      break;\n    } // bail out early\n    steps.push(step);\n    if (step.optimized) {\n      break;\n    }\n    contextNode = contextNode.parentElement;\n  }\n\n  steps.reverse();\n  return steps.join(' > ');\n};\n\nconst cssPathStep = function (node: Element, optimized: boolean, isTargetNode: boolean): Step | null {\n  if (node.nodeType !== Node.ELEMENT_NODE) {\n    return null;\n  }\n\n  const id = node.getAttribute('id');\n  if (optimized) {\n    if (id) {\n      return new Step(idSelector(id), true);\n    }\n\n    const nodeNameLower = node.tagName.toLowerCase();\n    if (nodeNameLower === 'body' || nodeNameLower === 'head' || nodeNameLower === 'html') {\n      return new Step(nodeNameLower, true);\n    }\n  }\n\n  const nodeName = node.tagName.toLowerCase();\n\n  if (id) {\n    return new Step(nodeName + idSelector(id), true);\n  }\n\n  const parent = node.parentNode;\n  if (!parent || parent.nodeType === Node.DOCUMENT_NODE) {\n    return new Step(nodeName, true);\n  }\n\n  function prefixedElementClassNames(el: Element): string[] {\n    const classAttribute = el.getAttribute('class');\n    if (!classAttribute) {\n      return [];\n    }\n    return classAttribute\n      .split(/\\s+/g)\n      .filter(Boolean)\n      .map(function (name) {\n        // The prefix is required to store \"__proto__\" in a object-based map.\n        return '$' + name;\n      });\n  }\n\n  function idSelector(id: string): string {\n    return '#' + CSS.escape(id);\n  }\n\n  const prefixedOwnClassNamesArray = prefixedElementClassNames(node);\n  let needsClassNames = false;\n  let needsNthChild = false;\n  let ownIndex = -1;\n  let elementIndex = -1;\n\n  const siblings: HTMLCollectionOf<Element> = parent.children;\n\n  for (let i = 0; siblings && (ownIndex === -1 || !needsNthChild) && i < siblings.length; ++i) {\n    const sibling = siblings[i];\n    if (sibling.nodeType !== Node.ELEMENT_NODE) {\n      continue;\n    }\n\n    elementIndex += 1;\n    if (sibling === node) {\n      ownIndex = elementIndex;\n      continue;\n    }\n    if (needsNthChild) {\n      continue;\n    }\n\n    if (sibling.tagName.toLowerCase() !== nodeName) {\n      continue;\n    }\n\n    needsClassNames = true;\n    const ownClassNames = new Set<string>(prefixedOwnClassNamesArray);\n    if (!ownClassNames.size) {\n      needsNthChild = true;\n      continue;\n    }\n\n    const siblingClassNamesArray = prefixedElementClassNames(sibling);\n    for (let j = 0; j < siblingClassNamesArray.length; ++j) {\n      const siblingClass = siblingClassNamesArray[j];\n      if (!ownClassNames.has(siblingClass)) {\n        continue;\n      }\n      ownClassNames.delete(siblingClass);\n      if (!ownClassNames.size) {\n        needsNthChild = true;\n        break;\n      }\n    }\n  }\n\n  let result = nodeName;\n  if (\n    isTargetNode &&\n    nodeName.toLowerCase() === 'input' &&\n    node.getAttribute('type') &&\n    !node.getAttribute('id') &&\n    !node.getAttribute('class')\n  ) {\n    result += '[type=' + CSS.escape(node.getAttribute('type') || '') + ']';\n  }\n  if (needsNthChild) {\n    result += ':nth-child(' + String(ownIndex + 1) + ')';\n  } else if (needsClassNames) {\n    for (const prefixedName of prefixedOwnClassNamesArray) {\n      result += '.' + CSS.escape(prefixedName.slice(1));\n    }\n  }\n\n  return new Step(result, false);\n};\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/src/libs/messenger.ts",
    "content": "/* istanbul ignore file */\n/* eslint-disable no-restricted-globals */\nimport { AMPLITUDE_VISUAL_TAGGING_SELECTOR_SCRIPT_URL, AMPLITUDE_VISUAL_TAGGING_HIGHLIGHT_CLASS } from '../constants';\nimport type { BaseWindowMessenger } from '@amplitude/analytics-core';\nimport { ActionType } from '@amplitude/analytics-core';\nimport { VERSION } from '../version';\nimport { DataExtractor } from '../data-extractor';\n\nexport type Action =\n  | 'ping'\n  | 'pong'\n  | 'page-loaded'\n  | 'selector-loaded'\n  | 'initialize-visual-tagging-selector'\n  | 'close-visual-tagging-selector'\n  | 'element-selected'\n  | 'track-selector-mode-changed'\n  | 'track-selector-moved'\n  | 'initialize-background-capture'\n  | 'close-background-capture'\n  | 'background-capture-loaded'\n  | 'background-capture-complete';\n\ninterface InitializeVisualTaggingSelectorData {\n  actionType: ActionType;\n}\n\ninterface ElementSelectedData {\n  '[Amplitude] Element Hierarchy'?: string;\n  '[Amplitude] Element Tag'?: string;\n  '[Amplitude] Element Text'?: string;\n  '[Amplitude] Page URL'?: string;\n  elementScreenshot?: Blob;\n}\n\ninterface TrackSelectorModeChangedData {\n  newMode: string;\n  pageUrl?: string;\n}\n\ninterface TrackSelectorMovedData {\n  newEditorLocation: string;\n  pageUrl?: string;\n}\n\nexport type ActionData = {\n  ping: null | undefined;\n  pong: null | undefined;\n  'page-loaded': null | undefined;\n  'selector-loaded': null | undefined;\n  'initialize-visual-tagging-selector': InitializeVisualTaggingSelectorData | null | undefined;\n  'close-visual-tagging-selector': null | undefined;\n  'element-selected': ElementSelectedData;\n  'track-selector-mode-changed': TrackSelectorModeChangedData;\n  'track-selector-moved': TrackSelectorMovedData;\n  'initialize-background-capture': null | undefined;\n  'close-background-capture': null | undefined;\n  'background-capture-loaded': null | undefined;\n  'background-capture-complete': { [key: string]: string | null };\n};\n\nexport interface Message<A extends Action> {\n  action: A;\n  data?: ActionData[A];\n}\n\n/**\n * Brand key to track whether visual tagging has been enabled on a messenger.\n */\nconst VISUAL_TAGGING_BRAND = '__AMPLITUDE_VISUAL_TAGGING__' as const;\n\n/**\n * Enable visual tagging on a messenger instance.\n * The first call registers the handlers; subsequent calls are no-ops.\n *\n * @param messenger - The messenger to enable visual tagging on\n * @param options - Visual tagging configuration\n */\nexport function enableVisualTagging(\n  messenger: BaseWindowMessenger,\n  options: {\n    isElementSelectable?: (action: InitializeVisualTaggingSelectorData['actionType'], element: Element) => boolean;\n    cssSelectorAllowlist?: string[];\n    actionClickAllowlist?: string[];\n    dataExtractor: DataExtractor;\n  },\n): void {\n  // Idempotency guard — works across bundle boundaries\n  const branded = messenger as unknown as Record<string, unknown>;\n  if (branded[VISUAL_TAGGING_BRAND] === true) {\n    return;\n  }\n  branded[VISUAL_TAGGING_BRAND] = true;\n\n  const { dataExtractor, isElementSelectable, cssSelectorAllowlist, actionClickAllowlist } = options;\n\n  let amplitudeVisualTaggingSelectorInstance: any = null;\n\n  const onSelect = (data: ElementSelectedData) => {\n    messenger.notify({ action: 'element-selected', data });\n  };\n\n  const onTrack = (type: string, properties: { [key: string]: string | null }) => {\n    if (type === 'selector-mode-changed') {\n      messenger.notify({ action: 'track-selector-mode-changed', data: properties });\n    } else if (type === 'selector-moved') {\n      messenger.notify({ action: 'track-selector-moved', data: properties });\n    }\n  };\n\n  messenger.registerActionHandler(\n    'initialize-visual-tagging-selector',\n    (actionData: InitializeVisualTaggingSelectorData) => {\n      messenger\n        .loadScriptOnce(AMPLITUDE_VISUAL_TAGGING_SELECTOR_SCRIPT_URL)\n        .then(() => {\n          // eslint-disable-next-line\n          amplitudeVisualTaggingSelectorInstance = (window as any)?.amplitudeVisualTaggingSelector?.({\n            getEventTagProps: dataExtractor.getEventTagProps,\n            isElementSelectable: (element: Element) => {\n              if (isElementSelectable) {\n                return isElementSelectable(actionData?.actionType || 'click', element);\n              }\n              return true;\n            },\n            onTrack,\n            onSelect,\n            visualHighlightClass: AMPLITUDE_VISUAL_TAGGING_HIGHLIGHT_CLASS,\n            messenger,\n            cssSelectorAllowlist,\n            actionClickAllowlist,\n            extractDataFromDataSource: dataExtractor.extractDataFromDataSource,\n            dataExtractor,\n            diagnostics: {\n              autocapture: {\n                version: VERSION,\n              },\n            },\n          });\n          messenger.notify({ action: 'selector-loaded' });\n        })\n        .catch(() => {\n          messenger.logger?.warn('Failed to initialize visual tagging selector');\n        });\n    },\n  );\n\n  messenger.registerActionHandler('close-visual-tagging-selector', () => {\n    // eslint-disable-next-line\n    amplitudeVisualTaggingSelectorInstance?.close?.();\n  });\n}\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/src/observables.ts",
    "content": "import { TimestampedEvent } from './helpers';\nimport { Observable, consoleObserver, getGlobalScope, merge } from '@amplitude/analytics-core';\n\n/* eslint-disable-next-line no-restricted-globals */\nconst globalScope = getGlobalScope() as typeof window;\n\nexport const createMutationObservable = (): Observable<MutationRecord[]> => {\n  return new Observable<MutationRecord[]>((observer) => {\n    const mutationObserver = new MutationObserver((mutations) => {\n      observer.next(mutations);\n    });\n    if (document.body) {\n      mutationObserver.observe(document.body, {\n        childList: true,\n        attributes: true,\n        characterData: true,\n        subtree: true,\n      });\n    }\n    return () => mutationObserver.disconnect();\n  });\n};\n\n/**\n * Creates an observable that tracks click events on the document.\n * @param clickType - The type of click event to track (click or pointerdown)\n */\nexport const createClickObservable = (\n  clickType: 'click' | 'pointerdown' = 'click',\n): Observable<MouseEvent | PointerEvent> => {\n  return new Observable<MouseEvent | PointerEvent>((observer) => {\n    const handler = (event: MouseEvent | PointerEvent) => {\n      observer.next(event);\n    };\n\n    getGlobalScope()?.document.addEventListener(clickType, handler, { capture: true });\n    return () => {\n      getGlobalScope()?.document.removeEventListener(clickType, handler, { capture: true });\n    };\n  });\n};\n\nexport const createScrollObservable = (): Observable<Event> => {\n  return new Observable<Event>((observer) => {\n    const handler = (event: Event) => {\n      observer.next(event);\n    };\n\n    getGlobalScope()?.addEventListener('scroll', handler);\n    return () => {\n      getGlobalScope()?.removeEventListener('scroll', handler);\n    };\n  });\n};\n\nconst createConsoleErrorObservable = (): Observable<BrowserErrorEvent> => {\n  return new Observable<BrowserErrorEvent>((observer) => {\n    const handler = (_: string, ...args: any[]) => {\n      /* istanbul ignore next */\n      let message: string | undefined = undefined;\n      if (Array.isArray(args[0]) && typeof args[0][0] === 'string') {\n        message = args[0][0];\n      }\n      observer.next({ kind: 'console', message });\n    };\n    consoleObserver.addListener('error', handler);\n    return () => {\n      consoleObserver.removeListener(handler);\n    };\n  });\n};\n\n// Tracks when a trackedelement is exposed to the viewport\nexport const createExposureObservable = (\n  mutationObservable: Observable<TimestampedEvent<MutationRecord[]>>,\n  selectorAllowlist: string[],\n): Observable<Event> => {\n  return new Observable<Event>((observer) => {\n    const globalScope = getGlobalScope();\n\n    if (!globalScope?.IntersectionObserver) {\n      return () => {\n        return;\n      };\n    }\n\n    const intersectionObserver = new IntersectionObserver(\n      (entries) => {\n        entries.forEach((entry) => {\n          observer.next(entry as unknown as Event);\n        });\n      },\n      {\n        root: null, // viewport\n        rootMargin: '0px', // start exactly at the viewport edge\n        threshold: 1.0, // trigger when 100% of the element is visible\n      },\n    );\n\n    // Observe initial elements\n    const selectorString = selectorAllowlist.join(',');\n    /* istanbul ignore next */\n    const initialElements = globalScope?.document.querySelectorAll(selectorString) ?? [];\n    initialElements.forEach((element) => {\n      intersectionObserver.observe(element);\n    });\n\n    // Use mutation observable to observe new elements that match the allowlist\n    const mutationSubscription = mutationObservable.subscribe(({ event }) =>\n      event.forEach(({ addedNodes }) =>\n        addedNodes.forEach((node) => {\n          if (!(node instanceof Element)) {\n            return;\n          }\n          if (node.matches(selectorString)) {\n            intersectionObserver.observe(node);\n          }\n          node.querySelectorAll(selectorString).forEach((child) => {\n            intersectionObserver.observe(child);\n          });\n        }),\n      ),\n    );\n\n    return () => {\n      mutationSubscription.unsubscribe();\n      intersectionObserver.disconnect();\n    };\n  });\n};\nconst createUnhandledErrorObservable = (): Observable<BrowserErrorEvent> => {\n  return new Observable<BrowserErrorEvent>((observer) => {\n    const handler = (event: Event) => {\n      if (!(event instanceof ErrorEvent)) {\n        return;\n      }\n      let output: BrowserErrorEvent = {\n        kind: 'error',\n      };\n\n      if (event.error instanceof Error || event.error instanceof DOMException) {\n        output = {\n          ...output,\n          message: event.error.message,\n          stack: event.error.stack,\n          filename: event.filename,\n          lineNumber: event.lineno,\n          columnNumber: event.colno,\n        };\n      } else if (typeof event.error === 'string') {\n        output.message = event.error;\n      }\n      observer.next(output);\n    };\n\n    globalScope.addEventListener('error', handler);\n    return () => {\n      globalScope.removeEventListener('error', handler);\n    };\n  });\n};\n\nconst createUnhandledRejectionObservable = (): Observable<BrowserErrorEvent> => {\n  return new Observable<BrowserErrorEvent>((observer) => {\n    const handler = (event: PromiseRejectionEvent) => {\n      const output: BrowserErrorEvent = {\n        kind: 'unhandledrejection',\n      };\n      if (event.reason instanceof Error || event.reason instanceof DOMException) {\n        output.message = event.reason.message;\n        output.stack = event.reason.stack;\n      } else if (typeof event.reason === 'string') {\n        output.message = event.reason;\n      }\n      observer.next(output);\n    };\n    globalScope.addEventListener('unhandledrejection', handler);\n    return () => {\n      globalScope.removeEventListener('unhandledrejection', handler);\n    };\n  });\n};\n\nexport type BrowserErrorEvent = {\n  kind: 'error' | 'unhandledrejection' | 'console';\n  message?: string;\n  filename?: string;\n  lineNumber?: number;\n  columnNumber?: number;\n  stack?: string;\n};\n\nexport const createErrorObservable = (): Observable<BrowserErrorEvent> => {\n  const unhandledErrorObservable = merge(createUnhandledErrorObservable(), createUnhandledRejectionObservable());\n  return merge(unhandledErrorObservable, createConsoleErrorObservable());\n};\n\nexport const createMouseMoveObservable = (): Observable<MouseEvent> => {\n  return new Observable<MouseEvent>((observer) => {\n    const handler = (event: MouseEvent) => {\n      observer.next(event);\n    };\n    const args: AddEventListenerOptions = { capture: true };\n    globalScope.document.addEventListener('mousemove', handler, args);\n    return () => {\n      globalScope.document.removeEventListener('mousemove', handler, args);\n    };\n  });\n};\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/src/pageActions/actions.ts",
    "content": "import type { DataSource, PageAction } from '@amplitude/analytics-core/lib/esm/types/element-interactions';\nimport type { DataExtractor } from '../data-extractor';\nimport type { ElementBasedTimestampedEvent, ElementBasedEvent } from '../helpers';\n\n// Get DataSource\n/**\n * Gets the DOM element specified by the data source configuration\n * @param dataSource - Configuration for finding the target element\n * @param contextElement - The element to start searching from\n * @returns The matching DOM element or undefined if not found\n */\nexport const getDataSource = (dataSource: DataSource, contextElement: HTMLElement) => {\n  // Only process DOM_ELEMENT type data sources\n  try {\n    if (dataSource.sourceType === 'DOM_ELEMENT') {\n      // If scope is specified, find the closest ancestor matching the scope rather than using documentElement (html) as the scope\n      let scopingElement: HTMLElement | null = document.documentElement;\n      if (dataSource.scope && contextElement) {\n        scopingElement = contextElement.closest(dataSource.scope);\n      }\n\n      // If we have both a scope and selector, find the matching element\n      if (scopingElement && dataSource.selector) {\n        return scopingElement.querySelector(dataSource.selector);\n      }\n\n      // Return scopingElement if no selector was specified\n      return scopingElement;\n    }\n  } catch (error) {\n    return undefined;\n  }\n\n  // Return undefined for non-DOM_ELEMENT data sources\n  return undefined;\n};\n\n// Execute actions for a condition and attach event properties to the event if needed\nexport const executeActions = (\n  actions: (string | PageAction)[],\n  ev: ElementBasedTimestampedEvent<ElementBasedEvent>,\n  dataExtractor: DataExtractor,\n) => {\n  actions.forEach((action) => {\n    // Skip if actions is string until action set is implemented\n    if (typeof action === 'string') {\n      return;\n    }\n\n    if (action.actionType === 'ATTACH_EVENT_PROPERTY') {\n      const data = dataExtractor.extractDataFromDataSource(action.dataSource, ev.closestTrackedAncestor as HTMLElement);\n\n      // Attach data to event\n      ev.targetElementProperties[action.destinationKey] = data;\n    }\n  });\n};\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/src/pageActions/matchEventToFilter.ts",
    "content": "import type { Filter } from '@amplitude/analytics-core/lib/esm/types/element-interactions';\nimport { ElementBasedTimestampedEvent, ElementBasedEvent } from '../helpers';\n\n/**\n * Matches an event to a single filter\n * @param event - The event to match\n * @param filter - The filter to match against\n * @returns boolean indicating if the event matches the filter\n */\nexport const matchEventToFilter = (event: ElementBasedTimestampedEvent<ElementBasedEvent>, filter: Filter) => {\n  try {\n    if (filter.subprop_key === '[Amplitude] Element Text') {\n      // TODO: add support for the other operators\n      return (\n        filter.subprop_op === 'is' &&\n        filter.subprop_value.includes(event.targetElementProperties['[Amplitude] Element Text'] as string)\n      );\n    } else if (filter.subprop_key === '[Amplitude] Element Hierarchy') {\n      // Check if the element ancestory matches the CSS selector, always check this last since it is the most expensive\n      return (\n        filter.subprop_op === 'autotrack css match' &&\n        !!event.closestTrackedAncestor.closest(filter.subprop_value.toString())\n      );\n    }\n  } catch (error) {\n    console.error('Error matching event to filter', error);\n    return false;\n  }\n  return false;\n};\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/src/pageActions/triggers.ts",
    "content": "import type { ElementInteractionsOptions, LabeledEvent, Trigger } from '@amplitude/analytics-core';\nimport type { ElementBasedTimestampedEvent, ElementBasedEvent } from '../helpers';\nimport { matchEventToFilter } from './matchEventToFilter';\nimport { executeActions } from './actions';\nimport type { DataExtractor } from '../data-extractor';\n\nconst eventTypeToBrowserEventMap = {\n  '[Amplitude] Element Clicked': 'click',\n  '[Amplitude] Element Changed': 'change',\n} as const;\n// groups labeled events by event type\n// skips any labeled events with malformed definitions or unexpected event_type\nexport const groupLabeledEventIdsByEventType = (labeledEvents: LabeledEvent[] | null | undefined) => {\n  // Initialize all event types with empty sets\n  const groupedLabeledEvents = Object.values(eventTypeToBrowserEventMap).reduce((acc, browserEvent) => {\n    acc[browserEvent] = new Set<string>();\n    return acc;\n  }, {} as Record<string, Set<string>>);\n\n  // If there are no labeled events, return the initialized groupedLabeledEvents\n  if (!labeledEvents) {\n    return groupedLabeledEvents;\n  }\n\n  // Group labeled events by event type\n  for (const le of labeledEvents) {\n    try {\n      for (const def of le.definition) {\n        const browserEvent = eventTypeToBrowserEventMap[def.event_type];\n        if (browserEvent) {\n          groupedLabeledEvents[browserEvent].add(le.id);\n        }\n      }\n    } catch (e) {\n      // Skip this labeled event if there is an error\n      console.warn('Skipping Labeled Event due to malformed definition', le?.id, e);\n    }\n  }\n  return groupedLabeledEvents;\n};\n\n// TODO: add tests\nexport const createLabeledEventToTriggerMap = (triggers: Trigger[]) => {\n  const labeledEventToTriggerMap = new Map<string, Trigger[]>();\n  for (const trigger of triggers) {\n    for (const condition of trigger.conditions) {\n      if (condition.type === 'LABELED_EVENT') {\n        const eventId = condition.match.eventId;\n        // Get existing triggers for this event ID or initialize empty array\n        let existingTriggers = labeledEventToTriggerMap.get(eventId);\n        if (!existingTriggers) {\n          existingTriggers = [];\n          labeledEventToTriggerMap.set(eventId, existingTriggers);\n        }\n        // Add current trigger to the list of triggers for this event ID\n        existingTriggers.push(trigger);\n      }\n    }\n  }\n  return labeledEventToTriggerMap;\n};\n\n/**\n * Matches an event to labeled events based on the event's properties.\n * The logic matches exactly what is supported by the query backend.\n * TODO: later pre-filter the labeled events based on URL first\n *\n * @param event - The event to match against labeled events\n * @param labeledEvents - Array of labeled events to match against\n * @returns Array of matching labeled events\n */\nexport const matchEventToLabeledEvents = (\n  event: ElementBasedTimestampedEvent<ElementBasedEvent>,\n  labeledEvents: LabeledEvent[],\n) => {\n  return labeledEvents.filter((le) => {\n    return le.definition.some((def) => {\n      return (\n        eventTypeToBrowserEventMap[def.event_type] === event.type &&\n        def.filters.every((filter) => matchEventToFilter(event, filter))\n      );\n    });\n  });\n};\n\nexport const matchLabeledEventsToTriggers = (labeledEvents: LabeledEvent[], leToTriggerMap: Map<string, Trigger[]>) => {\n  const matchingTriggers = new Set<Trigger>();\n  for (const le of labeledEvents) {\n    const triggers = leToTriggerMap.get(le.id);\n    if (triggers) {\n      for (const trigger of triggers) {\n        matchingTriggers.add(trigger);\n      }\n    }\n  }\n  return Array.from(matchingTriggers);\n};\n\nexport class TriggerEvaluator {\n  constructor(\n    private groupedLabeledEvents: ReturnType<typeof groupLabeledEventIdsByEventType>,\n    private labeledEventToTriggerMap: ReturnType<typeof createLabeledEventToTriggerMap>,\n    private dataExtractor: DataExtractor,\n    private options: ElementInteractionsOptions,\n  ) {}\n\n  evaluate(event: ElementBasedTimestampedEvent<ElementBasedEvent>) {\n    // If there is no pageActions, return the event as is\n    const { pageActions } = this.options;\n    if (!pageActions) {\n      return event;\n    }\n\n    // Find matching labeled events\n    const matchingLabeledEvents = matchEventToLabeledEvents(\n      event,\n      Array.from(this.groupedLabeledEvents[event.type]).map((id) => pageActions.labeledEvents[id]),\n    );\n    // Find matching conditions\n    const matchingTriggers = matchLabeledEventsToTriggers(matchingLabeledEvents, this.labeledEventToTriggerMap);\n    for (const trigger of matchingTriggers) {\n      executeActions(trigger.actions, event, this.dataExtractor);\n    }\n\n    return event;\n  }\n\n  update(\n    groupedLabeledEvents: ReturnType<typeof groupLabeledEventIdsByEventType>,\n    labeledEventToTriggerMap: ReturnType<typeof createLabeledEventToTriggerMap>,\n    options: ElementInteractionsOptions,\n  ) {\n    this.groupedLabeledEvents = groupedLabeledEvents;\n    this.labeledEventToTriggerMap = labeledEventToTriggerMap;\n    this.options = options;\n  }\n}\n\nexport const createTriggerEvaluator = (\n  groupedLabeledEvents: ReturnType<typeof groupLabeledEventIdsByEventType>,\n  labeledEventToTriggerMap: ReturnType<typeof createLabeledEventToTriggerMap>,\n  dataExtractor: DataExtractor,\n  options: ElementInteractionsOptions,\n) => {\n  return new TriggerEvaluator(groupedLabeledEvents, labeledEventToTriggerMap, dataExtractor, options);\n};\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/src/performance-plugin.ts",
    "content": "/* eslint-disable no-restricted-globals */\nimport {\n  BrowserClient,\n  BrowserConfig,\n  EnrichmentPlugin,\n  PerformanceTrackingOptions,\n  Unsubscribable,\n} from '@amplitude/analytics-core';\nimport * as constants from './constants';\nimport { trackMainThreadBlock } from './autocapture/track-long-task';\n\ntype BrowserEnrichmentPlugin = EnrichmentPlugin<BrowserClient, BrowserConfig>;\n\nconst DEFAULT_DURATION_THRESHOLD = 100; // ms\n\nexport const performancePlugin = (options: PerformanceTrackingOptions = {}): BrowserEnrichmentPlugin => {\n  const name = constants.PERFORMANCE_PLUGIN_NAME;\n  const type = 'enrichment';\n\n  const subscriptions: Unsubscribable[] = [];\n\n  const mainThreadBlockEnabled =\n    options.mainThreadBlock === true ||\n    (typeof options.mainThreadBlock === 'object' && options.mainThreadBlock !== null);\n\n  const setup: BrowserEnrichmentPlugin['setup'] = async (config, amplitude) => {\n    /* istanbul ignore if */\n    if (typeof document === 'undefined') {\n      return;\n    }\n\n    if (mainThreadBlockEnabled) {\n      let durationThreshold = DEFAULT_DURATION_THRESHOLD;\n      if (typeof options.mainThreadBlock === 'object' && options.mainThreadBlock.durationThreshold !== undefined) {\n        durationThreshold = options.mainThreadBlock.durationThreshold;\n      }\n\n      const subscription = trackMainThreadBlock({\n        amplitude,\n        options,\n        durationThreshold,\n      });\n      subscriptions.push(subscription);\n    }\n\n    /* istanbul ignore next */\n    config?.loggerProvider?.log(`${name} performance tracking has been successfully added.`);\n  };\n\n  const execute: BrowserEnrichmentPlugin['execute'] = async (event) => {\n    return event;\n  };\n\n  const teardown = async () => {\n    for (const subscription of subscriptions) {\n      subscription.unsubscribe();\n    }\n  };\n\n  return {\n    name,\n    type,\n    setup,\n    execute,\n    teardown,\n  };\n};\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/src/typings/autocapture.ts",
    "content": "export type HierarchyNode = {\n  tag: string;\n  id?: string;\n  classes?: string[];\n  attrs?: { [key: string]: string };\n  index?: number;\n  indexOfType?: number;\n  prevSib?: string;\n};\n\nexport type Hierarchy = (HierarchyNode | null)[];\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/src/version.ts",
    "content": "export const VERSION = '1.27.1';\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/test/autocapture-plugin/actions.test.ts",
    "content": "/* eslint-disable @typescript-eslint/unbound-method */\n\nimport { autocapturePlugin } from '../../src/autocapture-plugin';\nimport { type ElementBasedTimestampedEvent } from '../../src/helpers';\n\nimport {\n  ElementInteractionsOptions,\n  LabeledEvent,\n  Trigger,\n  DataSource,\n  BrowserConfig,\n  BrowserClient,\n  EnrichmentPlugin,\n  ILogger,\n  IConfig,\n} from '@amplitude/analytics-core';\nimport { createMockBrowserClient } from '../mock-browser-client';\nimport { getDataSource, executeActions } from '../../src/pageActions/actions';\nimport { DataExtractor } from '../../src/data-extractor';\n\nconst TESTING_DEBOUNCE_TIME = 4;\n\ndescribe('page actions', () => {\n  let plugin: EnrichmentPlugin | undefined;\n  let instance: jest.Mocked<BrowserClient>;\n  let loggerProvider: ILogger;\n\n  const bodyHTML = `\n    <div>\n      <div id=\"fixed-header-profile\">\n        <div id=\"fixed-header-profile-avatar\">\n          <img src=\"https://placehold.co/40x40\" alt=\"Profile Avatar\" />\n        </div>\n        <div id=\"fixed-header-profile-name\">John Doe</div>\n      </div>\n\n      <div id=\"product-card-container\">\n        <div class=\"product-card\" id=\"product-card-1\">\n          <h3 class=\"product-name\">Product 1</h3>\n          <p class=\"product-category\">Category 1</p>\n          <span class=\"price\">$10.00</span>\n          <button class=\"add-to-cart-button\">Add to Cart</button>\n        </div>\n\n        <div class=\"product-card\" id=\"product-card-2\">\n          <h3 class=\"product-name\">Product 2</h3>\n          <p class=\"product-category\">Category 2</p>\n          <span class=\"price\">$20.00</span>\n          <button class=\"add-to-cart-button\">Add to Cart</button>\n        </div>\n\n        <div class=\"product-card\" id=\"product-card-3\">\n          <h3 class=\"product-name\">Product 3</h3>\n          <p class=\"product-category\">Category 3</p>\n          <span class=\"price\">4111111111111111</span>\n          <button class=\"add-to-cart-button\">Add to Cart</button>\n        </div>\n      </div>\n    </div>\n    `;\n\n  const labeledEvents: Record<string, LabeledEvent> = {\n    '123': {\n      id: '123',\n      definition: [\n        {\n          event_type: '[Amplitude] Element Clicked',\n          filters: [\n            {\n              subprop_key: '[Amplitude] Element Text',\n              subprop_op: 'is',\n              subprop_value: ['Add to Cart'],\n            },\n            {\n              subprop_key: '[Amplitude] Element Hierarchy',\n              subprop_op: 'autotrack css match',\n              subprop_value: ['#product-card-container .add-to-cart-button'],\n            },\n          ],\n        },\n      ],\n    },\n  };\n\n  const triggers: Trigger[] = [\n    {\n      id: 'trig1',\n      name: 'Attach Event',\n      conditions: [\n        {\n          type: 'LABELED_EVENT',\n          match: {\n            eventId: '123',\n          },\n        },\n      ],\n      actions: [\n        {\n          id: 'action1',\n          actionType: 'ATTACH_EVENT_PROPERTY',\n          dataSource: {\n            sourceType: 'DOM_ELEMENT',\n            elementExtractType: 'TEXT',\n            scope: '.product-card',\n            selector: '.product-name',\n          },\n          destinationKey: 'product-name',\n        },\n        {\n          id: 'action2',\n          actionType: 'ATTACH_EVENT_PROPERTY',\n          dataSource: {\n            sourceType: 'DOM_ELEMENT',\n            elementExtractType: 'TEXT',\n            scope: '.product-card',\n            selector: '.product-category',\n          },\n          destinationKey: 'product-category',\n        },\n        {\n          id: 'action3',\n          actionType: 'ATTACH_EVENT_PROPERTY',\n          dataSource: {\n            sourceType: 'DOM_ELEMENT',\n            elementExtractType: 'TEXT',\n            scope: '.product-card',\n            selector: '.price',\n          },\n          destinationKey: 'price',\n        },\n      ],\n    },\n  ];\n\n  beforeAll(() => {\n    Object.defineProperty(window, 'location', {\n      value: {\n        hostname: '',\n        href: '',\n        pathname: '',\n        search: '',\n      },\n      writable: true,\n    });\n  });\n\n  beforeEach(() => {\n    (window.location as any) = {\n      hostname: '',\n      href: '',\n      pathname: '',\n      search: '',\n    };\n    plugin = autocapturePlugin({ debounceTime: TESTING_DEBOUNCE_TIME });\n    loggerProvider = {\n      log: jest.fn(),\n      warn: jest.fn(),\n      error: jest.fn(),\n      debug: jest.fn(),\n    } as unknown as ILogger;\n\n    plugin = autocapturePlugin({ debounceTime: TESTING_DEBOUNCE_TIME });\n    instance = createMockBrowserClient();\n  });\n\n  afterEach(() => {\n    void plugin?.teardown?.();\n    document.getElementsByTagName('body')[0].innerHTML = '';\n    jest.clearAllMocks();\n  });\n\n  describe('attach event properties', () => {\n    beforeEach(() => {\n      document.body.innerHTML = bodyHTML;\n    });\n\n    test('should attach properties from the closest matching scope', async () => {\n      const autocaptureConfig: ElementInteractionsOptions = {\n        pageActions: {\n          labeledEvents: labeledEvents,\n          triggers: triggers,\n        },\n      };\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n        autocapture: {\n          elementInteractions: autocaptureConfig,\n        },\n      };\n\n      plugin = autocapturePlugin(autocaptureConfig);\n      await plugin?.setup?.(config as IConfig, instance);\n\n      const button1 = document.querySelector('#product-card-1 .add-to-cart-button');\n\n      // trigger click event on Card 1\n      button1?.dispatchEvent(new Event('click'));\n\n      await new Promise((r) => setTimeout(r, TESTING_DEBOUNCE_TIME + 3));\n\n      expect(instance.track).toHaveBeenNthCalledWith(\n        1,\n        '[Amplitude] Element Clicked',\n        expect.objectContaining({\n          '[Amplitude] Element Class': 'add-to-cart-button',\n          'product-name': 'Product 1',\n          'product-category': 'Category 1',\n          price: '$10.00',\n        }),\n      );\n\n      const button2 = document.querySelector('#product-card-2 .add-to-cart-button');\n\n      // trigger click event on Card 2\n      button2?.dispatchEvent(new Event('click'));\n\n      await new Promise((r) => setTimeout(r, TESTING_DEBOUNCE_TIME + 3));\n\n      expect(instance.track).toHaveBeenNthCalledWith(\n        2,\n        '[Amplitude] Element Clicked',\n        expect.objectContaining({\n          '[Amplitude] Element Class': 'add-to-cart-button',\n          'product-name': 'Product 2',\n          'product-category': 'Category 2',\n          price: '$20.00',\n        }),\n      );\n    });\n\n    test('should mask credit card-like price in product-card-3', async () => {\n      const autocaptureConfig: ElementInteractionsOptions = {\n        pageActions: {\n          labeledEvents: labeledEvents,\n          triggers: triggers,\n        },\n      };\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n        autocapture: {\n          elementInteractions: autocaptureConfig,\n        },\n      };\n\n      plugin = autocapturePlugin(autocaptureConfig);\n      await plugin?.setup?.(config as IConfig, instance);\n\n      const button3 = document.querySelector('#product-card-3 .add-to-cart-button');\n\n      // trigger click event on Card 3\n      button3?.dispatchEvent(new Event('click'));\n\n      await new Promise((r) => setTimeout(r, TESTING_DEBOUNCE_TIME + 3));\n\n      expect(instance.track).toHaveBeenNthCalledWith(\n        1,\n        '[Amplitude] Element Clicked',\n        expect.objectContaining({\n          '[Amplitude] Element Class': 'add-to-cart-button',\n          'product-name': 'Product 3',\n          'product-category': 'Category 3',\n          price: '*****',\n        }),\n      );\n    });\n\n    test('should not change the event if no actions are triggered', async () => {\n      const autocaptureConfig: ElementInteractionsOptions = {};\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n        autocapture: {\n          elementInteractions: autocaptureConfig,\n        },\n      };\n\n      plugin = autocapturePlugin(autocaptureConfig);\n      await plugin?.setup?.(config as IConfig, instance);\n\n      const button1 = document.querySelector('#product-card-1 .add-to-cart-button');\n\n      // trigger click event on Card 1\n      button1?.dispatchEvent(new Event('click'));\n\n      await new Promise((r) => setTimeout(r, TESTING_DEBOUNCE_TIME + 3));\n\n      expect(instance.track).toHaveBeenNthCalledWith(\n        1,\n        '[Amplitude] Element Clicked',\n        expect.not.objectContaining({\n          'product-name': 'Product 1',\n          'product-category': 'Category 1',\n          price: '$10.00',\n        }),\n      );\n    });\n  });\n\n  describe('getDataSource', () => {\n    // Return undefined if souceType is not one of the supported types\n    test('should return undefined if sourceType is not one of the supported types', () => {\n      const data = getDataSource({ sourceType: 'UNEXPECTED_TYPE' } as unknown as DataSource, document.body);\n      expect(data).toBeUndefined();\n    });\n\n    test('should return undefined if selector and scope are invalid CSS selectors (empty strings)', () => {\n      const data = getDataSource(\n        {\n          sourceType: 'DOM_ELEMENT',\n          selector: '$$$',\n          scope: '',\n        } as unknown as DataSource,\n        document.body,\n      );\n      expect(data).toBeUndefined();\n    });\n  });\n\n  describe('extractDataFromDataSource', () => {\n    beforeEach(() => {\n      document.body.innerHTML = bodyHTML;\n    });\n\n    test('should extract data from scopingElement if no further selector is provided', () => {\n      const button1 = document.querySelector('#product-card-1 .add-to-cart-button');\n      const data = new DataExtractor({}).extractDataFromDataSource(\n        {\n          sourceType: 'DOM_ELEMENT',\n          elementExtractType: 'TEXT',\n          scope: '.product-card',\n        },\n        button1 as HTMLElement,\n      );\n      expect(data).toBe('Product 1 Category 1 $10.00 Add to Cart');\n    });\n\n    test('should return undefined if no element source is found', () => {\n      const button1 = document.querySelector('#product-card-1 .add-to-cart-button');\n      const data = new DataExtractor({}).extractDataFromDataSource(\n        {\n          sourceType: 'DOM_ELEMENT',\n          elementExtractType: 'TEXT',\n          scope: '.non-existent-scope',\n        },\n        button1 as HTMLElement,\n      );\n      expect(data).toBeUndefined();\n    });\n\n    test('should extract attribute from element', () => {\n      const avatarImage = document.querySelector('#fixed-header-profile-avatar img');\n      const data = new DataExtractor({}).extractDataFromDataSource(\n        {\n          sourceType: 'DOM_ELEMENT',\n          elementExtractType: 'ATTRIBUTE',\n          attribute: 'src',\n          selector: '#fixed-header-profile-avatar img',\n        },\n        document.body,\n      );\n      expect(data).toBe(avatarImage?.getAttribute('src'));\n    });\n\n    test('should return undefined for unsupported elementExtractType', () => {\n      const button1 = document.querySelector('#product-card-1 .add-to-cart-button');\n      const data = new DataExtractor({}).extractDataFromDataSource(\n        {\n          sourceType: 'DOM_ELEMENT',\n          elementExtractType: 'UNSUPPORTED_TYPE' as 'TEXT',\n          selector: '.add-to-cart-button',\n        },\n        button1 as HTMLElement,\n      );\n      expect(data).toBeUndefined();\n    });\n\n    test('should return undefined for non-DOM_ELEMENT sourceType', () => {\n      const button1 = document.querySelector('#product-card-1 .add-to-cart-button');\n      const data = new DataExtractor({}).extractDataFromDataSource(\n        {\n          sourceType: 'UNSUPPORTED_SOURCE_TYPE' as 'DOM_ELEMENT',\n          elementExtractType: 'TEXT',\n          selector: '.add-to-cart-button',\n        },\n        button1 as HTMLElement,\n      );\n      expect(data).toBeUndefined();\n    });\n  });\n\n  describe('executeActions', () => {\n    beforeEach(() => {\n      document.body.innerHTML = bodyHTML;\n    });\n\n    test('should skip string actions', () => {\n      const mockEvent = {\n        closestTrackedAncestor: document.querySelector('#product-card-1 .add-to-cart-button'),\n        targetElementProperties: {},\n      };\n\n      const stringActions = ['action1', 'action2'];\n\n      executeActions(\n        stringActions,\n        mockEvent as unknown as ElementBasedTimestampedEvent<MouseEvent>,\n        new DataExtractor({}),\n      );\n\n      // Should not add any properties since string actions are skipped\n      expect(mockEvent.targetElementProperties).toEqual({});\n    });\n  });\n});\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/test/autocapture-plugin/frustration-plugin.test.ts",
    "content": "import { AllWindowObservables, frustrationPlugin } from '../../src/frustration-plugin';\nimport { BrowserConfig, EnrichmentPlugin, ILogger, Observable, Unsubscribable } from '@amplitude/analytics-core';\nimport { createMockBrowserClient } from '../mock-browser-client';\nimport { trackDeadClick } from '../../src/autocapture/track-dead-click';\nimport { trackRageClicks } from '../../src/autocapture/track-rage-click';\nimport { trackErrorClicks } from '../../src/autocapture/track-error-click';\nimport { trackThrashedCursor } from '../../src/autocapture/track-thrashed-cursor';\nimport { BrowserErrorEvent, createErrorObservable } from '../../src/observables';\nimport { dispatchUnhandledRejection } from '../utils';\n\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-unsafe-argument */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-unsafe-call */\n/* eslint-disable @typescript-eslint/unbound-method */\n\n// Mock the tracking functions\njest.mock('../../src/autocapture/track-dead-click', () => ({\n  trackDeadClick: jest.fn(),\n}));\n\njest.mock('../../src/autocapture/track-rage-click', () => ({\n  trackRageClicks: jest.fn(),\n}));\n\njest.mock('../../src/autocapture/track-error-click', () => ({\n  trackErrorClicks: jest.fn(),\n}));\n\njest.mock('../../src/autocapture/track-thrashed-cursor', () => ({\n  trackThrashedCursor: jest.fn(),\n}));\n\ndescribe('frustrationPlugin', () => {\n  let plugin: EnrichmentPlugin | undefined;\n  let instance: any;\n\n  const loggerProvider: Partial<ILogger> = {\n    log: jest.fn(),\n    warn: jest.fn(),\n  };\n\n  const config: Partial<BrowserConfig> = {\n    defaultTracking: false,\n    loggerProvider: loggerProvider as ILogger,\n  };\n\n  beforeEach(() => {\n    // mock window.navigation\n    (window.navigation as any) = {\n      _handlers: [],\n      addEventListener: function (type: string, listener: () => void) {\n        if (type === 'navigate') {\n          this._handlers.push(listener);\n        }\n      },\n      removeEventListener: function (type: string, listener: () => void) {\n        if (type === 'navigate') {\n          this._handlers = this._handlers.filter((l: () => void) => l !== listener);\n        }\n      },\n      dispatchEvent: function (event: Event) {\n        if (event.type === 'navigate') {\n          this._handlers.forEach((handler: () => void) => handler());\n        }\n      },\n    };\n\n    instance = createMockBrowserClient();\n\n    // mock window.PointerEvent because it's not available in jsdom\n    function MockPointerEvent(type: string, init: PointerEventInit) {\n      return new Event(type, init);\n    }\n    (global.window as any).PointerEvent = MockPointerEvent;\n    (global.window as any).PointerEvent.prototype = Event.prototype;\n    jest.clearAllMocks();\n  });\n\n  describe('enable/disable frustration interactions', () => {\n    it('should skip tracking when set to false', async () => {\n      plugin = frustrationPlugin({\n        deadClicks: false,\n        rageClicks: false,\n      });\n\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      expect(trackDeadClick).not.toHaveBeenCalled();\n      expect(trackRageClicks).not.toHaveBeenCalled();\n    });\n\n    it('should enable tracking when set to true', async () => {\n      plugin = frustrationPlugin({\n        deadClicks: true,\n        rageClicks: true,\n      });\n\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      expect(trackDeadClick).toHaveBeenCalled();\n      expect(trackRageClicks).toHaveBeenCalled();\n    });\n\n    it('should enable tracking when not defined', async () => {\n      plugin = frustrationPlugin({});\n\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      expect(trackDeadClick).toHaveBeenCalled();\n      expect(trackRageClicks).toHaveBeenCalled();\n    });\n\n    it('should be disabled when set to null', async () => {\n      plugin = frustrationPlugin({\n        deadClicks: null as any,\n        rageClicks: null as any,\n      });\n\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      expect(trackDeadClick).not.toHaveBeenCalled();\n      expect(trackRageClicks).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('css selector allowlists', () => {\n    it('should pass custom dead click allowlist to tracking function', async () => {\n      const customDeadClickAllowlist = ['button', 'a'];\n\n      plugin = frustrationPlugin({\n        deadClicks: {\n          cssSelectorAllowlist: customDeadClickAllowlist,\n        },\n      });\n\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // Verify that trackDeadClick was called with the custom allowlist\n      expect(trackDeadClick).toHaveBeenCalledWith(\n        expect.objectContaining({\n          shouldTrackDeadClick: expect.any(Function),\n        }),\n      );\n\n      // Get the shouldTrackDeadClick function that was passed\n      const deadClickCall = (trackDeadClick as jest.Mock).mock.calls[0][0];\n      const shouldTrackDeadClick = deadClickCall.shouldTrackDeadClick;\n\n      // Create test elements\n      const button = document.createElement('button');\n      const div = document.createElement('div');\n\n      // Test that the allowlist is working\n      expect(shouldTrackDeadClick('click', button)).toBe(true); // button is in allowlist\n      expect(shouldTrackDeadClick('click', div)).toBe(false); // div is not in allowlist\n    });\n\n    it('should pass custom rage click allowlist to tracking function', async () => {\n      const customRageClickAllowlist = ['input', 'select'];\n\n      plugin = frustrationPlugin({\n        rageClicks: {\n          cssSelectorAllowlist: customRageClickAllowlist,\n        },\n      });\n\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // Verify that trackRageClicks was called with the custom allowlist\n      expect(trackRageClicks).toHaveBeenCalledWith(\n        expect.objectContaining({\n          shouldTrackRageClick: expect.any(Function),\n        }),\n      );\n\n      // Get the shouldTrackRageClick function that was passed\n      const rageClickCall = (trackRageClicks as jest.Mock).mock.calls[0][0];\n      const shouldTrackRageClick = rageClickCall.shouldTrackRageClick;\n\n      // Create test elements\n      const input = document.createElement('input');\n      const span = document.createElement('span');\n\n      // Test that the allowlist is working\n      expect(shouldTrackRageClick('click', input)).toBe(true); // input is in allowlist\n      expect(shouldTrackRageClick('click', span)).toBe(false); // span is not in allowlist\n    });\n\n    it('should pass custom error click allowlist to tracking function', async () => {\n      const customErrorClickAllowlist = ['input', 'select'];\n\n      plugin = frustrationPlugin({\n        errorClicks: {\n          cssSelectorAllowlist: customErrorClickAllowlist,\n        },\n      });\n\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // Get the shouldTrackErrorClick function that was passed\n      const errorClickCall = (trackErrorClicks as jest.Mock).mock.calls[0][0];\n      const shouldTrackErrorClick = errorClickCall.shouldTrackErrorClick;\n\n      // Create test elements\n      const input = document.createElement('input');\n      const span = document.createElement('span');\n\n      // Test that the allowlist is working\n      expect(shouldTrackErrorClick('click', input)).toBe(true); // input is in allowlist\n      expect(shouldTrackErrorClick('click', span)).toBe(false); // span is not in allowlist\n    });\n\n    it('should accept custom thrashed cursor options', async () => {\n      plugin = frustrationPlugin({\n        thrashedCursor: {\n          directionChanges: 5,\n          threshold: 100,\n        },\n      });\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      expect(trackThrashedCursor).toHaveBeenCalledWith(\n        expect.objectContaining({ thresholdMs: 100, directionChanges: 5 }),\n      );\n    });\n\n    it('should enforce minimum and maximum thrashed cursor options', async () => {\n      plugin = frustrationPlugin({\n        thrashedCursor: {\n          directionChanges: 4,\n          threshold: 4001,\n        },\n      });\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      expect(trackThrashedCursor).toHaveBeenCalledWith(\n        expect.objectContaining({ thresholdMs: 4000, directionChanges: 5 }),\n      );\n    });\n  });\n\n  describe('errorClicks', () => {\n    it('should not track error clicks if not explicitly enabled (while still @experimental)', async () => {\n      plugin = frustrationPlugin({});\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      expect(trackErrorClicks).not.toHaveBeenCalled();\n    });\n\n    it('should track error clicks if explicitly enabled', async () => {\n      plugin = frustrationPlugin({\n        errorClicks: true,\n      });\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      expect(trackErrorClicks).toHaveBeenCalled();\n    });\n  });\n\n  describe('thrashedCursor', () => {\n    it('should not track thrashed cursor if not explicitly enabled (while still @experimental)', async () => {\n      plugin = frustrationPlugin({});\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      expect(trackThrashedCursor).not.toHaveBeenCalled();\n    });\n\n    it('should track thrashed cursor if explicitly enabled', async () => {\n      plugin = frustrationPlugin({\n        thrashedCursor: true,\n      });\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      expect(trackThrashedCursor).toHaveBeenCalled();\n    });\n  });\n\n  describe('plugin lifecycle', () => {\n    it('should initialize with default options', () => {\n      plugin = frustrationPlugin();\n      expect(plugin.name).toBe('@amplitude/plugin-frustration-browser');\n      expect(plugin.type).toBe('enrichment');\n    });\n\n    it('should initialize with correct name and type', () => {\n      plugin = frustrationPlugin({});\n      expect(plugin.name).toBe('@amplitude/plugin-frustration-browser');\n      expect(plugin.type).toBe('enrichment');\n    });\n\n    it('should setup tracking functions with default options', async () => {\n      plugin = frustrationPlugin({});\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      expect(trackDeadClick).toHaveBeenCalledWith(\n        expect.objectContaining({\n          amplitude: instance,\n          allObservables: expect.any(Object),\n          getEventProperties: expect.any(Function),\n          shouldTrackDeadClick: expect.any(Function),\n        }),\n      );\n\n      // Test getEventProperties function\n      const deadClickCall = (trackDeadClick as jest.Mock).mock.calls[0][0];\n      const getEventProperties = deadClickCall.getEventProperties;\n\n      // Create test element with data attributes\n      const testElement = document.createElement('button');\n      testElement.setAttribute('data-amplitude-click', 'test-click');\n      testElement.setAttribute('data-amplitude-custom', 'custom-value');\n      testElement.setAttribute('data-other', 'ignored');\n\n      // Test getEventProperties with different action types\n      const props = getEventProperties('click', testElement);\n      expect(props).toBeDefined();\n    });\n\n    it('should use custom dataAttributePrefix when provided', async () => {\n      const customDataAttributePrefix = 'data-custom-';\n\n      plugin = frustrationPlugin({\n        dataAttributePrefix: customDataAttributePrefix,\n      });\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      expect(trackDeadClick).toHaveBeenCalledWith(\n        expect.objectContaining({\n          amplitude: instance,\n          allObservables: expect.any(Object),\n          getEventProperties: expect.any(Function),\n          shouldTrackDeadClick: expect.any(Function),\n        }),\n      );\n\n      // Test getEventProperties function with custom prefix\n      const deadClickCall = (trackDeadClick as jest.Mock).mock.calls[0][0];\n      const getEventProperties = deadClickCall.getEventProperties;\n\n      // Create test element with custom data attributes\n      const testElement = document.createElement('button');\n      testElement.setAttribute('data-custom-click', 'custom-click-value');\n      testElement.setAttribute('data-custom-user', 'custom-user-value');\n      testElement.setAttribute('data-amplitude-ignored', 'should-be-ignored');\n      testElement.setAttribute('data-other', 'also-ignored');\n\n      // Test getEventProperties with custom prefix\n      const props = getEventProperties('click', testElement);\n      expect(props).toBeDefined();\n\n      // Verify that only attributes with the custom prefix are captured\n      expect(props['[Amplitude] Element Attributes']).toEqual({\n        click: 'custom-click-value',\n        user: 'custom-user-value',\n      });\n\n      // Verify that attributes with other prefixes are not captured\n      expect(props['[Amplitude] Element Attributes']).not.toHaveProperty('amplitude-ignored');\n      expect(props['[Amplitude] Element Attributes']).not.toHaveProperty('other');\n    });\n\n    it('should unsubscribe from all subscriptions on teardown', async () => {\n      const mockSubscription = {\n        unsubscribe: jest.fn(),\n      };\n\n      // Mock the tracking functions to return subscriptions\n      (trackDeadClick as jest.Mock).mockReturnValue(mockSubscription);\n      (trackRageClicks as jest.Mock).mockReturnValue(mockSubscription);\n\n      plugin = frustrationPlugin({});\n      await plugin?.setup?.(config as BrowserConfig, instance);\n      await plugin?.teardown?.();\n\n      expect(mockSubscription.unsubscribe).toHaveBeenCalledTimes(2);\n    });\n\n    it('should execute and return the event unchanged', async () => {\n      plugin = frustrationPlugin({});\n\n      const mockEvent = {\n        event_type: 'test_event',\n        event_properties: { test: 'value' },\n        user_properties: { user: 'data' },\n      };\n\n      const result = await plugin?.execute?.(mockEvent);\n\n      expect(result).toBe(mockEvent);\n      expect(result).toEqual(mockEvent);\n    });\n  });\n\n  describe('observables', () => {\n    it('should create click + mutation observables with correct properties', async () => {\n      plugin = frustrationPlugin({});\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      const rageClickCall = (trackRageClicks as jest.Mock).mock.calls[0][0];\n      const observables = rageClickCall.allObservables;\n\n      expect(observables).toHaveProperty('clickObservable');\n      expect(observables).toHaveProperty('mutationObservable');\n      expect(observables).toHaveProperty('navigateObservable');\n\n      // Test click observable\n      const clickSpy = jest.fn();\n      const subscription = observables.clickObservable.subscribe(clickSpy);\n\n      // Create and trigger a mock click event\n      const testElement = document.createElement('button');\n      testElement.setAttribute('data-amplitude-click', 'test-click');\n      document.body.appendChild(testElement);\n\n      const mockPointerDownEvent = new PointerEvent('pointerdown', {\n        bubbles: true,\n        cancelable: true,\n        view: window,\n      });\n      testElement.dispatchEvent(mockPointerDownEvent);\n\n      // Verify click was captured\n      expect(clickSpy).toHaveBeenCalled();\n\n      // Cleanup\n      subscription.unsubscribe();\n      document.body.removeChild(testElement);\n\n      // Test mutation observable\n      const mutationSpy = jest.fn();\n      const mutationSubscription = observables.mutationObservable.subscribe(mutationSpy);\n\n      // Create and trigger a mutation\n      const container = document.createElement('div');\n      container.setAttribute('data-amplitude-mutation', 'test-mutation');\n      document.body.appendChild(container);\n\n      // Add a new element to trigger mutation\n      const newElement = document.createElement('span');\n      newElement.textContent = 'Test Mutation';\n      container.appendChild(newElement);\n\n      // Wait for the next tick to allow mutation observer to process\n      await new Promise((resolve) => setTimeout(resolve, 0));\n\n      // Verify mutation was captured\n      expect(mutationSpy).toHaveBeenCalled();\n\n      // Cleanup\n      mutationSubscription.unsubscribe();\n      document.body.removeChild(container);\n    });\n\n    it('should create navigate observable', async () => {\n      plugin = frustrationPlugin({});\n      await plugin?.setup?.(config as BrowserConfig, instance);\n      const rageClickCall = (trackRageClicks as jest.Mock).mock.calls[0][0];\n      const observables = rageClickCall.allObservables;\n\n      expect(observables).toHaveProperty('navigateObservable');\n\n      // Create and trigger a mock navigate event\n      const navigateSpy = jest.fn();\n      const subscription = observables.navigateObservable.subscribe(navigateSpy);\n\n      // Trigger a mock navigate event\n      (window.navigation as any).dispatchEvent(new Event('navigate'));\n\n      // Verify that the navigate event was captured\n      expect(navigateSpy).toHaveBeenCalled();\n\n      // Cleanup\n      subscription.unsubscribe();\n\n      // expect no event listeners left on window.navigation\n      expect((window.navigation as any)._handlers.length).toBe(0);\n    });\n\n    it('should create browser error observable with type and timestamp', async () => {\n      plugin = frustrationPlugin({\n        errorClicks: true,\n      });\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      const errorClickCall = (trackErrorClicks as jest.Mock).mock.calls[0][0];\n      const observables = errorClickCall.allObservables;\n\n      expect(observables).toHaveProperty('browserErrorObservable');\n\n      // Subscribe to the browser error observable\n      const errorSpy = jest.fn();\n      const subscription = observables.browserErrorObservable.subscribe(errorSpy);\n\n      // Trigger a console error\n      window.console.error('test browser error observable');\n\n      // Verify the error was captured and enriched with type and timestamp\n      expect(errorSpy).toHaveBeenCalled();\n      const capturedError = errorSpy.mock.calls[0][0];\n\n      // Verify the structure added by dataExtractor.addTypeAndTimestamp\n      expect(capturedError).toHaveProperty('type', 'error');\n      expect(capturedError).toHaveProperty('timestamp');\n      expect(typeof capturedError.timestamp).toBe('number');\n      expect(capturedError).toHaveProperty('event');\n      expect(capturedError.event).toEqual({\n        kind: 'console',\n        message: 'test browser error observable',\n      });\n\n      // Cleanup\n      subscription.unsubscribe();\n    });\n\n    describe('selection observable', () => {\n      let plugin: EnrichmentPlugin | undefined;\n      let rageClickCall: any;\n      let observables: AllWindowObservables;\n      let subscription: Unsubscribable | undefined;\n      let selectionSpy: jest.Mock;\n\n      beforeEach(async () => {\n        plugin = frustrationPlugin({});\n        await plugin?.setup?.(config as BrowserConfig, instance);\n        rageClickCall = (trackRageClicks as jest.Mock).mock.calls[0][0];\n        observables = rageClickCall.allObservables;\n        selectionSpy = jest.fn();\n        subscription = observables.selectionObservable?.subscribe(selectionSpy);\n        jest.clearAllMocks();\n      });\n\n      afterEach(() => {\n        subscription?.unsubscribe();\n      });\n\n      it('should trigger on selection highlighted', async () => {\n        const div = document.createElement('div');\n        div.focus();\n\n        expect(observables).toHaveProperty('selectionObservable');\n\n        jest.spyOn(window, 'getSelection').mockReturnValue({\n          isCollapsed: false,\n        } as any);\n        const mockSelectionEvent: any = new Event('selectionchange');\n        (window.document as any).dispatchEvent(mockSelectionEvent);\n\n        expect(selectionSpy).toHaveBeenCalled();\n      });\n\n      it('should not trigger on non-input element selection change if selection is collapsed', async () => {\n        // Trigger a mock selection event\n        const div = document.createElement('div');\n        div.focus();\n        (window.document as any).dispatchEvent(new Event('selectionchange'));\n        expect(selectionSpy).not.toHaveBeenCalled();\n      });\n\n      it('should trigger on input element selection change', async () => {\n        // Trigger a mock selection event\n        ['textarea', 'input'].forEach((tag) => {\n          const input = document.createElement(tag) as HTMLTextAreaElement | HTMLInputElement;\n          input.value = 'some text here'; // Add text so there's something to select\n          input.selectionStart = 0;\n          input.selectionEnd = 10;\n          document.body.appendChild(input);\n          input.focus(); // This sets document.activeElement to the input\n          (window.document as any).dispatchEvent(new Event('selectionchange'));\n          document.body.removeChild(input);\n        });\n\n        expect(selectionSpy).toHaveBeenCalledTimes(2);\n      });\n\n      it('should not trigger on input element selection change if selection is collapsed', async () => {\n        // Trigger a mock selection event on input and textarea elements\n        ['textarea', 'input'].forEach((tag) => {\n          const input = document.createElement(tag) as HTMLTextAreaElement | HTMLInputElement;\n          input.value = 'some text here'; // Add text so there's something to select\n          input.selectionStart = 0;\n          input.selectionEnd = 0;\n          document.body.appendChild(input);\n          input.focus(); // This sets document.activeElement to the input\n          (window.document as any).dispatchEvent(new Event('selectionchange'));\n          document.body.removeChild(input);\n        });\n\n        expect(selectionSpy).not.toHaveBeenCalled();\n      });\n\n      it('should not trigger on input element that does not support selectionStart/selectionEnd (like checkbox)', async () => {\n        const checkbox = document.createElement('input');\n        checkbox.type = 'checkbox';\n        // make .selectionStart and .selectionEnd throw an error\n        // simulating \"Chrome\" behavior\n        Object.defineProperty(checkbox, 'selectionStart', {\n          get: () => {\n            throw new Error('Not supported');\n          },\n        });\n        Object.defineProperty(checkbox, 'selectionEnd', {\n          get: () => {\n            throw new Error('Not supported');\n          },\n        });\n        document.body.appendChild(checkbox);\n        checkbox.focus(); // This sets document.activeElement to the checkbox\n        (window.document as any).dispatchEvent(new Event('selectionchange'));\n        document.body.removeChild(checkbox);\n        expect(selectionSpy).not.toHaveBeenCalled();\n      });\n    });\n  });\n\n  describe('createBrowserErrorObservable', () => {\n    let errorObservable: Observable<BrowserErrorEvent>;\n    let subscribePromise: Promise<BrowserErrorEvent>;\n    let subscription: Unsubscribable;\n\n    beforeEach(() => {\n      errorObservable = createErrorObservable();\n      subscribePromise = new Promise((resolve) => {\n        subscription = errorObservable.subscribe((error: BrowserErrorEvent) => {\n          resolve(error);\n        });\n      });\n    });\n\n    afterEach(() => {\n      subscription.unsubscribe();\n    });\n\n    it('should capture unhandled rejections', async () => {\n      const error = new Error('boom');\n      dispatchUnhandledRejection(window, error);\n\n      const res = await subscribePromise;\n      expect(res.kind).toBe('unhandledrejection');\n      expect(res.message).toBe('boom');\n    });\n\n    it('should capture unhandled rejections with non-object reason', async () => {\n      const error = 'Something went wrong';\n      dispatchUnhandledRejection(window, error);\n\n      const res = await subscribePromise;\n      expect(res.kind).toBe('unhandledrejection');\n      expect(res.message).toBe('Something went wrong');\n    });\n\n    it('should capture uncaught errors', async () => {\n      setTimeout(() => {\n        const error = new Error('test uncaught error');\n        error.stack = 'fake stack';\n        throw error;\n      }, 10);\n      const res = await subscribePromise;\n      expect(res.stack).toEqual('fake stack');\n      expect(res.kind).toBe('error');\n      expect(res.message).toBe('test uncaught error');\n    });\n\n    it('should capture uncaught errors with string error', async () => {\n      setTimeout(() => {\n        throw 'test uncaught error';\n      }, 10);\n      const res = await subscribePromise;\n      expect(res.kind).toBe('error');\n      expect(res.message).toBe('test uncaught error');\n      expect(res.stack).toBeUndefined();\n    });\n\n    it('should capture uncaught DOMException error', async () => {\n      setTimeout(() => {\n        // https://developer.mozilla.org/en-US/docs/Web/API/DOMException\n        throw new DOMException('test DOMException error', 'DOMException');\n      }, 10);\n      const res = await subscribePromise;\n      expect(res.kind).toBe('error');\n      expect(res.message).toBe('test DOMException error');\n      expect(res.stack).toBeDefined();\n    });\n\n    it('should not capture non-error events', async () => {\n      window.dispatchEvent(new Event('error'));\n      const timeoutPromise = new Promise((resolve) => setTimeout(() => resolve('timeout'), 100));\n      const result = await Promise.race([subscribePromise, timeoutPromise]);\n      expect(result).toBe('timeout');\n    });\n\n    it('should capture console errors', async () => {\n      window.console.error('test console error');\n      const res = await subscribePromise;\n      expect(res).toEqual({\n        kind: 'console',\n        message: 'test console error',\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/test/autocapture-plugin/performance-plugin.test.ts",
    "content": "import { BrowserConfig, EnrichmentPlugin, ILogger } from '@amplitude/analytics-core';\nimport { performancePlugin } from '../../src/performance-plugin';\nimport { PERFORMANCE_PLUGIN_NAME } from '../../src/constants';\nimport { trackMainThreadBlock } from '../../src/autocapture/track-long-task';\nimport { createMockBrowserClient } from '../mock-browser-client';\n\njest.mock('../../src/autocapture/track-long-task', () => ({\n  trackMainThreadBlock: jest.fn(),\n}));\n\ndescribe('performancePlugin', () => {\n  const loggerProvider: Partial<ILogger> = {\n    log: jest.fn(),\n    warn: jest.fn(),\n  };\n\n  const config: Partial<BrowserConfig> = {\n    defaultTracking: false,\n    loggerProvider: loggerProvider as ILogger,\n  };\n\n  let mockUnsubscribe: jest.Mock;\n\n  beforeEach(() => {\n    jest.clearAllMocks();\n    mockUnsubscribe = jest.fn();\n    (trackMainThreadBlock as jest.Mock).mockReturnValue({ unsubscribe: mockUnsubscribe });\n  });\n\n  it('should use a plugin name distinct from autocapturePlugin', () => {\n    const plugin = performancePlugin();\n    expect(plugin.name).toBe(PERFORMANCE_PLUGIN_NAME);\n  });\n\n  describe('setup', () => {\n    it('should call trackMainThreadBlock with default duration threshold when mainThreadBlock is true', async () => {\n      const plugin = performancePlugin({ mainThreadBlock: true });\n      const amplitude = createMockBrowserClient();\n      await plugin.setup!(config as BrowserConfig, amplitude);\n\n      expect(trackMainThreadBlock).toHaveBeenCalledWith({\n        amplitude,\n        options: { mainThreadBlock: true },\n        durationThreshold: 100,\n      });\n    });\n\n    it('should call trackMainThreadBlock with custom durationThreshold', async () => {\n      const plugin = performancePlugin({ mainThreadBlock: { durationThreshold: 200 } });\n      const amplitude = createMockBrowserClient();\n      await plugin.setup!(config as BrowserConfig, amplitude);\n\n      expect(trackMainThreadBlock).toHaveBeenCalledWith({\n        amplitude,\n        options: { mainThreadBlock: { durationThreshold: 200 } },\n        durationThreshold: 200,\n      });\n    });\n\n    it('should use default duration threshold when mainThreadBlock is an object without durationThreshold', async () => {\n      const plugin = performancePlugin({ mainThreadBlock: {} });\n      const amplitude = createMockBrowserClient();\n      await plugin.setup!(config as BrowserConfig, amplitude);\n\n      expect(trackMainThreadBlock).toHaveBeenCalledWith({\n        amplitude,\n        options: { mainThreadBlock: {} },\n        durationThreshold: 100,\n      });\n    });\n\n    it('should not call trackMainThreadBlock when mainThreadBlock=false', async () => {\n      const plugin = performancePlugin({ mainThreadBlock: false });\n      const amplitude = createMockBrowserClient();\n      await plugin.setup!(config as BrowserConfig, amplitude);\n\n      expect(trackMainThreadBlock).not.toHaveBeenCalled();\n    });\n\n    it('should not call trackMainThreadBlock when no options provided (mainThreadBlock defaults off)', async () => {\n      const plugin = performancePlugin();\n      const amplitude = createMockBrowserClient();\n      await plugin.setup!(config as BrowserConfig, amplitude);\n\n      expect(trackMainThreadBlock).not.toHaveBeenCalled();\n    });\n\n    it('should not call trackMainThreadBlock when options omit mainThreadBlock', async () => {\n      const plugin = performancePlugin({});\n      const amplitude = createMockBrowserClient();\n      await plugin.setup!(config as BrowserConfig, amplitude);\n\n      expect(trackMainThreadBlock).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('execute', () => {\n    it('should return the event unchanged', async () => {\n      const plugin = performancePlugin() as EnrichmentPlugin;\n      const event = { event_type: 'test' };\n      const result = await plugin.execute!(event as any);\n      expect(result).toBe(event);\n    });\n  });\n\n  describe('teardown', () => {\n    it('should call unsubscribe on all subscriptions', async () => {\n      const plugin = performancePlugin({ mainThreadBlock: true });\n      const amplitude = createMockBrowserClient();\n      await plugin.setup!(config as BrowserConfig, amplitude);\n      await plugin.teardown!();\n\n      expect(mockUnsubscribe).toHaveBeenCalledTimes(1);\n    });\n\n    it('should not throw when there are no subscriptions', async () => {\n      const plugin = performancePlugin({ mainThreadBlock: false });\n      await expect(plugin.teardown!()).resolves.toBeUndefined();\n    });\n\n    it('should not throw on teardown when mainThreadBlock was omitted (no subscriptions)', async () => {\n      const plugin = performancePlugin();\n      const amplitude = createMockBrowserClient();\n      await plugin.setup!(config as BrowserConfig, amplitude);\n      await expect(plugin.teardown!()).resolves.toBeUndefined();\n    });\n  });\n});\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/test/autocapture-plugin/track-action-clicks.test.ts",
    "content": "import { autocapturePlugin } from '../../src/autocapture-plugin';\nimport { BrowserConfig, EnrichmentPlugin, ILogger } from '@amplitude/analytics-core';\nimport { createMockBrowserClient } from '../mock-browser-client';\n\nconst TESTING_DEBOUNCE_TIME = 4;\n\ndescribe('action clicks:', () => {\n  let plugin: EnrichmentPlugin | undefined;\n\n  beforeAll(() => {\n    Object.defineProperty(window, 'location', {\n      value: {\n        hostname: '',\n        href: '',\n        pathname: '',\n        search: '',\n      },\n      writable: true,\n    });\n  });\n\n  beforeEach(() => {\n    (window.location as any) = {\n      hostname: '',\n      href: '',\n      pathname: '',\n      search: '',\n    };\n    plugin = autocapturePlugin({ debounceTime: TESTING_DEBOUNCE_TIME });\n  });\n\n  afterEach(() => {\n    void plugin?.teardown?.();\n    document.getElementsByTagName('body')[0].innerHTML = '';\n    jest.clearAllMocks();\n  });\n\n  // ********** START TESTS **********\n\n  describe('autotrack clicks that cause a change:', () => {\n    const API_KEY = 'API_KEY';\n    const USER_ID = 'USER_ID';\n\n    let instance = createMockBrowserClient();\n    let track: jest.SpyInstance;\n\n    const loggerProvider: Partial<ILogger> = {\n      log: jest.fn(),\n      warn: jest.fn(),\n      error: jest.fn(),\n    };\n    const config: Partial<BrowserConfig> = {\n      defaultTracking: false,\n      loggerProvider: loggerProvider as ILogger,\n    };\n\n    beforeEach(async () => {\n      plugin = autocapturePlugin({ debounceTime: TESTING_DEBOUNCE_TIME });\n      instance = createMockBrowserClient();\n      await instance.init(API_KEY, USER_ID).promise;\n      track = jest.spyOn(instance, 'track');\n\n      const content = `\n        <div id=\"main\" class=\"class1 class2\" data-test-attr=\"test-attr\">\n          <div id=\"inner-left\" class=\"column\">\n            <div id=\"addDivButton\"><span id=\"inner-div-button-text\">Add div</span></div>\n            <div id=\"go-back-button\">Go Back</div>\n            <button id=\"real-button\"><span id=\"button-text\">Click me</span></button>\n            <div class=\"red\" id=\"no-action-div\">No action div</div>\n          </div>\n          <div id=\"inner-right\" class=\"column\">\n            <div class=\"card\">\n              <h1 id=\"card-title\">Card Title</h1>\n              <a href=\"https://google.com\">Go to Google</a>\n              <a href=\"#\">Dead Link</a>\n            </div>\n          </div>\n          <span data-testid=\"test-element\">inner</span>\n        </div>\n      `;\n\n      document.body.innerHTML = content;\n\n      // Add event listener to div\n      const addDivButton = document.getElementById('addDivButton');\n      let divCount = 0;\n      const addDiv = () => {\n        divCount++;\n        const newDiv = document.createElement('div');\n        newDiv.className = 'new-div';\n        newDiv.textContent = `This is div number ${divCount}`;\n        document.body.appendChild(newDiv);\n      };\n      addDivButton?.addEventListener('click', addDiv);\n\n      // Add event listener to card\n      document.querySelector('.card')?.addEventListener('click', addDiv);\n\n      const goBackButton = document.getElementById('go-back-button');\n      const goBack = () => {\n        history.pushState(null, '', '#new-hash');\n      };\n      goBackButton?.addEventListener('click', goBack);\n\n      // mockWindowLocationFromURL(new URL('https://www.amplitude.com/unit-test?query=param'));\n    });\n\n    afterEach(() => {\n      document.body.innerHTML = '';\n    });\n\n    test('should track button click even if there is no DOM change', async () => {\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // trigger 2 click events on button\n      const realButton = document.getElementById('real-button');\n      realButton?.dispatchEvent(new Event('click'));\n      realButton?.dispatchEvent(new Event('click'));\n      await new Promise((r) => setTimeout(r, TESTING_DEBOUNCE_TIME + 3));\n\n      expect(track).toHaveBeenCalledTimes(2);\n    });\n\n    test('should not track div click if it does not change the DOM or navigate', async () => {\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // trigger click event on div which is acting as a button\n      document.getElementById('no-action-div')?.dispatchEvent(new Event('click'));\n      await new Promise((r) => setTimeout(r, TESTING_DEBOUNCE_TIME + 503));\n\n      expect(track).toHaveBeenCalledTimes(0);\n    });\n\n    test('should track div click if it causes a DOM change', async () => {\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // trigger click event on div which is acting as a button\n      document.getElementById('addDivButton')?.dispatchEvent(new Event('click'));\n      document.getElementById('addDivButton')?.dispatchEvent(new Event('click'));\n      document.getElementById('addDivButton')?.dispatchEvent(new Event('click'));\n      await new Promise((r) => setTimeout(r, TESTING_DEBOUNCE_TIME + 503));\n\n      expect(track).toHaveBeenCalledTimes(1);\n      expect(track).toHaveBeenNthCalledWith(1, '[Amplitude] Element Clicked', {\n        '[Amplitude] Element Hierarchy': [\n          {\n            id: 'addDivButton',\n            index: 0,\n            indexOfType: 0,\n            tag: 'div',\n          },\n          {\n            id: 'inner-left',\n            classes: ['column'],\n            index: 0,\n            indexOfType: 0,\n            tag: 'div',\n          },\n          {\n            attrs: {\n              'data-test-attr': 'test-attr',\n            },\n            id: 'main',\n            classes: ['class1', 'class2'],\n            index: 0,\n            indexOfType: 0,\n            tag: 'div',\n          },\n          {\n            index: 1,\n            indexOfType: 0,\n            prevSib: 'head',\n            tag: 'body',\n          },\n        ],\n        '[Amplitude] Element ID': 'addDivButton',\n        '[Amplitude] Element Parent Label': 'Card Title',\n        '[Amplitude] Element Path': 'div#addDivButton',\n        '[Amplitude] Element Position Left': 0,\n        '[Amplitude] Element Position Top': 0,\n        '[Amplitude] Element Tag': 'div',\n        '[Amplitude] Element Text': 'Add div',\n        '[Amplitude] Viewport Height': 768,\n        '[Amplitude] Viewport Width': 1024,\n      });\n    });\n\n    test('should not trigger duplicate events if the immediate click target is in the action click allowlist', async () => {\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // trigger click event on span in a button\n      document.getElementById('button-text')?.dispatchEvent(new Event('click', { bubbles: true }));\n      await new Promise((r) => setTimeout(r, TESTING_DEBOUNCE_TIME + 503));\n\n      // should only track one event, the click on the button\n      expect(track).toHaveBeenCalledTimes(1);\n      expect(track).toHaveBeenNthCalledWith(\n        1,\n        '[Amplitude] Element Clicked',\n        expect.objectContaining({\n          '[Amplitude] Element ID': 'real-button',\n          '[Amplitude] Element Tag': 'button',\n          '[Amplitude] Element Text': 'Click me',\n        }),\n      );\n    });\n\n    test('should trigger action click on innermost element', async () => {\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // trigger click event on span in a button\n      document.getElementById('inner-div-button-text')?.dispatchEvent(new Event('click', { bubbles: true }));\n      await new Promise((r) => setTimeout(r, TESTING_DEBOUNCE_TIME + 503));\n\n      // should only track one event, the click on the button\n      expect(track).toHaveBeenCalledTimes(1);\n      expect(track).toHaveBeenNthCalledWith(\n        1,\n        '[Amplitude] Element Clicked',\n        expect.objectContaining({\n          '[Amplitude] Element ID': 'inner-div-button-text',\n          '[Amplitude] Element Parent Label': 'Add div',\n          '[Amplitude] Element Tag': 'span',\n        }),\n      );\n    });\n\n    describe('actionClickAllowlist configuration', () => {\n      test('should be able to track non-default tags by overwriting default actionClickAllowlist', async () => {\n        // Use only div in allowlist\n        plugin = autocapturePlugin({ actionClickAllowlist: ['h1'], debounceTime: TESTING_DEBOUNCE_TIME });\n        await plugin?.setup?.(config as BrowserConfig, instance);\n\n        // trigger click on card which should result in no event since div is not in the allowlist\n        document.querySelector('.card')?.dispatchEvent(new Event('click'));\n        await new Promise((r) => setTimeout(r, TESTING_DEBOUNCE_TIME + 503));\n\n        expect(track).toHaveBeenCalledTimes(0);\n        expect(document.querySelectorAll('.new-div').length).toBe(1);\n\n        // trigger click on h1 in card which should result in an action click since h1 is in the allowlist and a child\n        // of the card which has the click event listener\n        document.getElementById('card-title')?.dispatchEvent(new Event('click', { bubbles: true }));\n        await new Promise((r) => setTimeout(r, TESTING_DEBOUNCE_TIME + 503));\n\n        expect(track).toHaveBeenCalledTimes(1);\n        expect(track).toHaveBeenNthCalledWith(\n          1,\n          '[Amplitude] Element Clicked',\n          expect.objectContaining({\n            '[Amplitude] Element ID': 'card-title',\n            '[Amplitude] Element Parent Label': 'Card Title',\n            '[Amplitude] Element Tag': 'h1',\n          }),\n        );\n        expect(document.querySelectorAll('.new-div').length).toBe(2);\n      });\n    });\n\n    test('should not track when element type is hidden', async () => {\n      // Use only div in allowlist\n      plugin = autocapturePlugin({ actionClickAllowlist: ['input'], debounceTime: TESTING_DEBOUNCE_TIME });\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      const input = document.createElement('input');\n      input.setAttribute('id', 'my-input-id');\n      input.setAttribute('class', 'my-input-class');\n      input.type = 'hidden';\n      document.body.appendChild(input);\n\n      // trigger click input\n      document.getElementById('my-input-id')?.dispatchEvent(new Event('click'));\n      await new Promise((r) => setTimeout(r, TESTING_DEBOUNCE_TIME + 503));\n      expect(track).toHaveBeenCalledTimes(0);\n\n      // trigger change input\n      document.getElementById('my-input-id')?.dispatchEvent(new Event('change'));\n      expect(track).toHaveBeenCalledTimes(0);\n    });\n\n    // Readd when jsdom has support for navigate events\n    describe('navigation events', () => {\n      beforeEach(() => {\n        (window.navigation as any) = {\n          _handlers: [],\n          addEventListener: function (type: string, listener: () => void) {\n            if (type === 'navigate') {\n              this._handlers.push(listener);\n            }\n          },\n          removeEventListener: function (type: string, listener: () => void) {\n            if (type === 'navigate') {\n              this._handlers = this._handlers.filter((l: () => void) => l !== listener);\n            }\n          },\n          dispatchEvent: function (event: Event) {\n            if (event.type === 'navigate') {\n              this._handlers.forEach((handler: () => void) => handler());\n            }\n          },\n        };\n      });\n\n      afterEach(() => {\n        (window.navigation as any) = undefined;\n      });\n\n      test('should track div click if it causes a navigation (popstate) change', async () => {\n        await plugin?.setup?.(config as BrowserConfig, instance);\n\n        // Set initial window location\n        window.location.href = 'https://www.test.com/query';\n\n        // trigger click event on div which is acting as a button\n        document.getElementById('go-back-button')?.dispatchEvent(new Event('click'));\n        (window.navigation as any).dispatchEvent(new Event('navigate'));\n        await new Promise((r) => setTimeout(r, TESTING_DEBOUNCE_TIME + 503));\n\n        // once for the page view end event, once for the click event\n        expect(track).toHaveBeenCalledTimes(2);\n        expect(track).toHaveBeenNthCalledWith(2, '[Amplitude] Element Clicked', expect.objectContaining({}));\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/test/autocapture-plugin/track-dead-click.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/unbound-method */\n\nimport { BrowserClient, Observable } from '@amplitude/analytics-core';\nimport { trackDeadClick } from '../../src/autocapture/track-dead-click';\nimport { AMPLITUDE_ELEMENT_DEAD_CLICKED_EVENT } from '../../src/constants';\nimport { ObservablesEnum } from '../../src/autocapture-plugin';\nimport { AllWindowObservables } from '../../src/frustration-plugin';\n\ndescribe('trackDeadClick', () => {\n  let mockAmplitude: jest.Mocked<BrowserClient>;\n  let clickObservable: any;\n  let mutationObservable: any;\n  let navigateObservable: any;\n  let browserErrorObservable: any;\n  let mouseMoveObservable: any;\n  let allObservables: AllWindowObservables;\n  let shouldTrackDeadClick: jest.Mock;\n  let getEventProperties: jest.Mock;\n  let clickObserver: any;\n  let mutationObserver: any;\n  let navigateObserver: any;\n  let subscription: any;\n\n  beforeEach(() => {\n    mockAmplitude = {\n      track: jest.fn(),\n    } as any;\n\n    clickObservable = new Observable<any>((observer) => {\n      clickObserver = observer;\n    });\n    mutationObservable = new Observable<any>((observer) => {\n      mutationObserver = observer;\n    });\n    navigateObservable = new Observable<any>((observer) => {\n      navigateObserver = observer;\n    });\n    browserErrorObservable = new Observable<any>((/* observer */) => {\n      //browserErrorObserver = observer;\n    });\n    mouseMoveObservable = new Observable<any>((/* observer */) => {\n      //mouseMoveObserver = observer;\n    });\n    allObservables = {\n      [ObservablesEnum.ClickObservable]: clickObservable,\n      [ObservablesEnum.MutationObservable]: mutationObservable,\n      [ObservablesEnum.NavigateObservable]: navigateObservable,\n      [ObservablesEnum.BrowserErrorObservable]: browserErrorObservable,\n      [ObservablesEnum.MouseMoveObservable]: mouseMoveObservable,\n    };\n    shouldTrackDeadClick = jest.fn().mockReturnValue(true);\n    getEventProperties = jest.fn().mockReturnValue({ id: 'test-element' });\n\n    jest.useFakeTimers();\n\n    subscription = trackDeadClick({\n      amplitude: mockAmplitude,\n      allObservables,\n      getEventProperties,\n      shouldTrackDeadClick,\n    });\n  });\n\n  afterEach(() => {\n    subscription?.unsubscribe();\n  });\n\n  it('should track dead click when no mutation or navigation occurs', async () => {\n    // Create a mock element\n    const mockElement = document.createElement('div');\n\n    // Simulate a click\n    clickObserver.next({\n      event: {\n        target: mockElement,\n        clientX: 100,\n        clientY: 100,\n        button: 0,\n      },\n      timestamp: Date.now(),\n      closestTrackedAncestor: mockElement,\n      targetElementProperties: { id: 'test-element' },\n      type: 'click',\n    });\n\n    // Wait for the dead click timeout\n    await jest.runAllTimersAsync();\n    expect(mockAmplitude.track).toHaveBeenCalledWith(\n      AMPLITUDE_ELEMENT_DEAD_CLICKED_EVENT,\n      expect.objectContaining({\n        ['[Amplitude] X']: 100,\n        ['[Amplitude] Y']: 100,\n        id: 'test-element',\n      }),\n      expect.any(Object),\n    );\n\n    subscription?.unsubscribe();\n    mutationObserver.complete();\n    navigateObserver.complete();\n  });\n\n  it('should not track dead click on right click', async () => {\n    // Create a mock element\n    const mockElement = document.createElement('div');\n\n    // Simulate a right click\n    clickObserver.next({\n      event: {\n        target: mockElement,\n        clientX: 100,\n        clientY: 100,\n        button: 2, // right click button\n      },\n      timestamp: Date.now(),\n      closestTrackedAncestor: mockElement,\n      targetElementProperties: { id: 'test-element' },\n      type: 'click',\n    });\n\n    // Wait for the dead click timeout\n    await jest.runAllTimersAsync();\n    expect(mockAmplitude.track).not.toHaveBeenCalled();\n\n    subscription?.unsubscribe();\n    mutationObserver.complete();\n    navigateObserver.complete();\n  });\n\n  it('should not track when mutation occurs after click', async () => {\n    // Create a mock element\n    const mockElement = document.createElement('button');\n\n    // Simulate a click\n    clickObserver.next({\n      event: {\n        target: mockElement,\n        clientX: 100,\n        clientY: 100,\n        button: 0,\n      },\n      timestamp: Date.now(),\n      closestTrackedAncestor: mockElement,\n      targetElementProperties: { id: 'test-element' },\n    });\n\n    // Simulate a mutation shortly after\n    mutationObserver.next([{ type: 'childList' }]);\n    await jest.runAllTimersAsync();\n\n    // Wait for the dead click timeout\n    expect(mockAmplitude.track).not.toHaveBeenCalled();\n    subscription?.unsubscribe();\n  });\n\n  it('should not track when navigation occurs after click', async () => {\n    // Create a mock element\n    const mockElement = document.createElement('div');\n\n    // Simulate a click\n    clickObserver.next({\n      event: {\n        target: mockElement,\n        clientX: 100,\n        clientY: 100,\n        button: 0,\n      },\n      timestamp: Date.now(),\n      closestTrackedAncestor: mockElement,\n      targetElementProperties: { id: 'test-element' },\n      type: 'click',\n    });\n\n    // Simulate a navigation shortly after\n    navigateObserver.next({ type: 'navigate' });\n    await jest.runAllTimersAsync();\n\n    // Wait for the dead click timeout\n    expect(mockAmplitude.track).not.toHaveBeenCalled();\n    subscription?.unsubscribe();\n  });\n\n  it('should not track elements that are not in the allowed list', async () => {\n    subscription?.unsubscribe();\n    shouldTrackDeadClick.mockReturnValue(false);\n\n    subscription = trackDeadClick({\n      amplitude: mockAmplitude,\n      allObservables,\n      getEventProperties,\n      shouldTrackDeadClick,\n    });\n\n    const mockElement = document.createElement('div');\n\n    clickObserver.next({\n      event: {\n        target: mockElement,\n        clientX: 100,\n        clientY: 100,\n        button: 0,\n      },\n      timestamp: Date.now(),\n      closestTrackedAncestor: mockElement,\n      targetElementProperties: { id: 'test-element' },\n    });\n\n    // Wait for the dead click timeout\n    await jest.runAllTimersAsync();\n    expect(mockAmplitude.track).not.toHaveBeenCalled();\n  });\n\n  it('should not track when target is _blank', async () => {\n    const mockElement = document.createElement('a');\n    mockElement.setAttribute('target', '_blank');\n\n    clickObserver.next({\n      event: {\n        target: mockElement,\n        button: 0,\n      },\n      timestamp: Date.now(),\n      closestTrackedAncestor: mockElement,\n      targetElementProperties: { id: 'test-element' },\n    });\n\n    // Wait for the dead click timeout\n    await jest.runAllTimersAsync();\n    expect(mockAmplitude.track).not.toHaveBeenCalled();\n  });\n\n  it('should throttle multiple dead clicks', async () => {\n    const mockElement = document.createElement('div');\n\n    // Simulate multiple clicks\n    for (let i = 0; i < 3; i++) {\n      jest.advanceTimersByTime(i);\n      clickObserver.next({\n        event: {\n          target: mockElement,\n          clientX: 100,\n          clientY: 100,\n          button: 0,\n        },\n        timestamp: Date.now(),\n        closestTrackedAncestor: mockElement,\n        targetElementProperties: { id: 'test-element' },\n        type: 'click',\n      });\n    }\n\n    // Wait for the dead click timeout plus some extra time for all clicks\n    await jest.runAllTimersAsync();\n    expect(mockAmplitude.track).toHaveBeenCalledTimes(1); // Only one dead click should be tracked\n  });\n});\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/test/autocapture-plugin/track-error-click.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/unbound-method */\n/* eslint-disable @typescript-eslint/no-empty-function */\n\nimport { BrowserClient, Observable } from '@amplitude/analytics-core';\nimport { trackErrorClicks } from '../../src/autocapture/track-error-click';\nimport { AMPLITUDE_ELEMENT_ERROR_CLICKED_EVENT } from '../../src/constants';\nimport { ObservablesEnum } from '../../src/autocapture-plugin';\nimport { AllWindowObservables } from '../../src/frustration-plugin';\nimport { MouseButton } from '../../src/helpers';\n\ndescribe('trackErrorClicks', () => {\n  let mockAmplitude: jest.Mocked<BrowserClient>;\n  let clickObservable: any;\n  let mutationObservable: any;\n  let navigateObservable: any;\n  let browserErrorObservable: any;\n  let mouseMoveObservable: any;\n  let allObservables: AllWindowObservables;\n  let shouldTrackErrorClick: jest.Mock;\n  let clickObserver: any;\n  let browserErrorObserver: any;\n  let subscription: ReturnType<typeof trackErrorClicks>;\n\n  beforeEach(() => {\n    mockAmplitude = {\n      track: jest.fn(),\n    } as any;\n\n    clickObservable = new Observable<any>((observer) => {\n      clickObserver = observer;\n    });\n    mutationObservable = new Observable<any>(() => {});\n    navigateObservable = new Observable<any>(() => {});\n    browserErrorObservable = new Observable<any>((observer) => {\n      browserErrorObserver = observer;\n    });\n    mouseMoveObservable = new Observable<any>(() => {});\n    allObservables = {\n      [ObservablesEnum.ClickObservable]: clickObservable,\n      [ObservablesEnum.MutationObservable]: mutationObservable,\n      [ObservablesEnum.NavigateObservable]: navigateObservable,\n      [ObservablesEnum.BrowserErrorObservable]: browserErrorObservable,\n      [ObservablesEnum.MouseMoveObservable]: mouseMoveObservable,\n    };\n    shouldTrackErrorClick = jest.fn().mockReturnValue(true);\n\n    subscription = trackErrorClicks({\n      amplitude: mockAmplitude,\n      allObservables,\n      shouldTrackErrorClick,\n    });\n\n    jest.useFakeTimers();\n  });\n\n  afterEach(() => {\n    subscription?.unsubscribe();\n    jest.clearAllMocks();\n  });\n\n  it('should track error click when error occurs after a click', async () => {\n    const mockElement = document.createElement('button');\n\n    // Simulate a click\n    clickObserver.next({\n      event: {\n        target: mockElement,\n        clientX: 100,\n        clientY: 100,\n        button: MouseButton.LEFT_OR_TOUCH_CONTACT,\n      },\n      timestamp: Date.now(),\n      closestTrackedAncestor: mockElement,\n      targetElementProperties: { id: 'test-button' },\n      type: 'click',\n    });\n\n    // Simulate an error shortly after\n    browserErrorObserver.next({\n      event: {\n        kind: 'error',\n        message: 'Test error message',\n        stack: 'Error stack trace',\n        filename: 'test.js',\n        lineNumber: 42,\n        columnNumber: 10,\n      },\n      timestamp: Date.now(),\n      type: 'error',\n    });\n\n    await jest.runAllTimersAsync();\n\n    expect(mockAmplitude.track).toHaveBeenCalledWith(\n      AMPLITUDE_ELEMENT_ERROR_CLICKED_EVENT,\n      expect.objectContaining({\n        ['[Amplitude] Kind']: 'error',\n        ['[Amplitude] Message']: 'Test error message',\n        ['[Amplitude] Stack']: 'Error stack trace',\n        ['[Amplitude] Filename']: 'test.js',\n        ['[Amplitude] Line Number']: 42,\n        ['[Amplitude] Column Number']: 10,\n        id: 'test-button',\n      }),\n    );\n  });\n\n  it('should not track error when no click occurred before', async () => {\n    // Simulate an error without any preceding click\n    browserErrorObserver.next({\n      event: {\n        kind: 'error',\n        message: 'Test error message',\n        stack: 'Error stack trace',\n        filename: 'test.js',\n        lineNumber: 42,\n        columnNumber: 10,\n      },\n      timestamp: Date.now(),\n      type: 'error',\n    });\n\n    await jest.runAllTimersAsync();\n\n    expect(mockAmplitude.track).not.toHaveBeenCalled();\n  });\n\n  it('should not track error click if click with no error', async () => {\n    const mockElement = document.createElement('button');\n\n    // Simulate a click\n    clickObserver.next({\n      event: {\n        target: mockElement,\n        clientX: 100,\n        clientY: 100,\n        button: MouseButton.LEFT_OR_TOUCH_CONTACT,\n      },\n      timestamp: Date.now(),\n      closestTrackedAncestor: mockElement,\n      targetElementProperties: { id: 'test-button' },\n      type: 'click',\n    });\n\n    await jest.runAllTimersAsync();\n\n    expect(mockAmplitude.track).not.toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/test/autocapture-plugin/track-exposure.test.ts",
    "content": "import { trackExposure } from '../../src/autocapture/track-exposure';\nimport { AllWindowObservables, ObservablesEnum } from '../../src/autocapture-plugin';\nimport { DataExtractor } from '../../src';\nimport { DEFAULT_EXPOSURE_DURATION } from '@amplitude/analytics-core';\n\ndescribe('trackExposure', () => {\n  let exposureObservable: any;\n  let allObservables: AllWindowObservables;\n  let onExposure: jest.Mock;\n  let unsubscribe: () => void;\n  let reset: () => void;\n  let observers: Array<(val: any) => void> = [];\n\n  beforeEach(() => {\n    jest.useFakeTimers();\n    onExposure = jest.fn();\n    observers = [];\n\n    // Mock Observable implementation\n    exposureObservable = {\n      subscribe: (fn: (val: any) => void) => {\n        observers.push(fn);\n        return {\n          unsubscribe: () => {\n            observers = observers.filter((o) => o !== fn);\n          },\n        };\n      },\n    };\n\n    allObservables = {\n      [ObservablesEnum.ExposureObservable]: exposureObservable,\n    } as any;\n\n    const dataExtractor = new DataExtractor({});\n    const result = trackExposure({\n      allObservables,\n      onExposure,\n      dataExtractor,\n    });\n    unsubscribe = result.unsubscribe;\n    reset = result.reset;\n  });\n\n  afterEach(() => {\n    unsubscribe();\n    jest.clearAllTimers();\n    jest.clearAllMocks();\n  });\n\n  const triggerExposure = (entry: Partial<IntersectionObserverEntry>) => {\n    observers.forEach((observer) => observer(entry));\n  };\n\n  test('should mark element as exposed after 2 seconds of visibility', () => {\n    const element = document.createElement('div');\n    element.id = 'test-div';\n\n    triggerExposure({\n      isIntersecting: true,\n      target: element,\n      intersectionRatio: 1.0,\n    });\n\n    // Should not be exposed yet\n    expect(onExposure).not.toHaveBeenCalled();\n\n    // Fast forward 2 seconds\n    jest.advanceTimersByTime(2000);\n\n    expect(onExposure).toHaveBeenCalledWith('div#test-div');\n  });\n\n  test('should not mark element as exposed if it becomes invisible before timeout (1 second)', () => {\n    const element = document.createElement('div');\n    element.id = 'test-div-cancel';\n\n    triggerExposure({\n      isIntersecting: true,\n      target: element,\n      intersectionRatio: 1.0,\n    });\n\n    jest.advanceTimersByTime(50);\n\n    // Element leaves viewport\n    triggerExposure({\n      isIntersecting: false,\n      target: element,\n      intersectionRatio: 0,\n    });\n\n    jest.advanceTimersByTime(50);\n\n    expect(onExposure).not.toHaveBeenCalled();\n  });\n\n  test('should not re-expose already exposed element', () => {\n    const element = document.createElement('div');\n    element.id = 'test-div-repeat';\n    const setTimeoutSpy = jest.spyOn(global, 'setTimeout');\n\n    // First exposure\n    triggerExposure({\n      isIntersecting: true,\n      target: element,\n      intersectionRatio: 1.0,\n    });\n\n    jest.advanceTimersByTime(DEFAULT_EXPOSURE_DURATION * 1.5);\n    expect(onExposure).toHaveBeenCalledWith('div#test-div-repeat');\n    expect(setTimeoutSpy).toHaveBeenCalledTimes(1);\n\n    // Reset spy\n    setTimeoutSpy.mockClear();\n\n    // Element leaves and comes back\n    triggerExposure({\n      isIntersecting: false,\n      target: element,\n      intersectionRatio: 0,\n    });\n\n    triggerExposure({\n      isIntersecting: true,\n      target: element,\n      intersectionRatio: 1.0,\n    });\n\n    // Should not start a new timer because it is already exposed in the internal map\n    expect(setTimeoutSpy).not.toHaveBeenCalled();\n  });\n\n  test('should handle multiple elements independently', () => {\n    const element1 = document.createElement('div');\n    element1.id = 'div-1';\n    const element2 = document.createElement('div');\n    element2.id = 'div-2';\n\n    // Start element 1\n    triggerExposure({\n      isIntersecting: true,\n      target: element1,\n      intersectionRatio: 1.0,\n    });\n\n    jest.advanceTimersByTime(DEFAULT_EXPOSURE_DURATION / 2);\n\n    // Start element 2\n    triggerExposure({\n      isIntersecting: true,\n      target: element2,\n      intersectionRatio: 1.0,\n    });\n\n    // Element 1 finishes\n    jest.advanceTimersByTime(DEFAULT_EXPOSURE_DURATION / 2);\n    expect(onExposure).toHaveBeenCalledWith('div#div-1');\n    expect(onExposure).not.toHaveBeenCalledWith('div#div-2');\n\n    // Element 2 finishes\n    jest.advanceTimersByTime(DEFAULT_EXPOSURE_DURATION / 2);\n    expect(onExposure).toHaveBeenCalledWith('div#div-2');\n  });\n\n  test('should clear timer when element leaves viewport (intersection check)', () => {\n    const element = document.createElement('div');\n    element.id = 'test-div-leave';\n    const clearTimeoutSpy = jest.spyOn(global, 'clearTimeout');\n\n    triggerExposure({\n      isIntersecting: true,\n      target: element,\n      intersectionRatio: 1.0,\n    });\n\n    jest.advanceTimersByTime(DEFAULT_EXPOSURE_DURATION / 2);\n\n    triggerExposure({\n      isIntersecting: false,\n      target: element,\n      intersectionRatio: 0.5, // < 1.0\n    });\n\n    expect(clearTimeoutSpy).toHaveBeenCalled();\n\n    jest.advanceTimersByTime(DEFAULT_EXPOSURE_DURATION * 1.5);\n    expect(onExposure).not.toHaveBeenCalled();\n  });\n\n  test('should clear all timers and exposure map on reset', () => {\n    const element1 = document.createElement('div');\n    element1.id = 'reset-div-1';\n    const element2 = document.createElement('div');\n    element2.id = 'reset-div-2';\n    const clearTimeoutSpy = jest.spyOn(global, 'clearTimeout');\n\n    // Start element 2 exposure and complete it\n    triggerExposure({\n      isIntersecting: true,\n      target: element2,\n      intersectionRatio: 1.0,\n    });\n    jest.advanceTimersByTime(DEFAULT_EXPOSURE_DURATION * 1.5);\n    expect(onExposure).toHaveBeenCalledWith('div#reset-div-2');\n    onExposure.mockClear();\n\n    // Start element 1 exposure (will be pending)\n    triggerExposure({\n      isIntersecting: true,\n      target: element1,\n      intersectionRatio: 1.0,\n    });\n\n    // Call reset\n    reset();\n\n    // Expect pending timer for element 1 to be cleared\n    expect(clearTimeoutSpy).toHaveBeenCalled();\n\n    // Fast forward to see if pending timer fires (should not)\n    jest.advanceTimersByTime(DEFAULT_EXPOSURE_DURATION * 1.5);\n    expect(onExposure).not.toHaveBeenCalledWith('div#reset-div-1');\n\n    // Re-expose element 2 (should work again because map was cleared)\n    triggerExposure({\n      isIntersecting: true,\n      target: element2,\n      intersectionRatio: 1.0,\n    });\n    jest.advanceTimersByTime(DEFAULT_EXPOSURE_DURATION * 1.5);\n    expect(onExposure).toHaveBeenCalledWith('div#reset-div-2');\n  });\n});\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/test/autocapture-plugin/track-long-task.test.ts",
    "content": "/* eslint-disable @typescript-eslint/unbound-method */\nimport { trackMainThreadBlock } from '../../src/autocapture/track-long-task';\nimport { createMockBrowserClient } from '../mock-browser-client';\nimport { AMPLITUDE_MAIN_THREAD_BLOCK_EVENT } from '../../src/constants';\n\ntype PerformanceObserverCallback = (list: { getEntries: () => PerformanceEntry[] }) => void;\n\nclass MockPerformanceObserver {\n  static callback: PerformanceObserverCallback;\n  static instances: MockPerformanceObserver[] = [];\n  static supportedEntryTypes: string[] = ['long-animation-frame'];\n\n  callback: PerformanceObserverCallback;\n  disconnected = false;\n  observed: { entryTypes: string[] } | null = null;\n\n  constructor(callback: PerformanceObserverCallback) {\n    this.callback = callback;\n    MockPerformanceObserver.instances.push(this);\n  }\n\n  observe(options: { entryTypes: string[] }) {\n    this.observed = options;\n  }\n\n  disconnect() {\n    this.disconnected = true;\n  }\n\n  fire(entries: Partial<PerformanceEntry>[]) {\n    this.callback({ getEntries: () => entries as PerformanceEntry[] });\n  }\n}\n\nfunction getMeasureObserver() {\n  return MockPerformanceObserver.instances.find((i) => i.observed?.entryTypes.includes('measure'))!;\n}\n\nfunction getBlockObserver() {\n  return MockPerformanceObserver.instances.find(\n    (i) => i.observed?.entryTypes.includes('long-animation-frame') || i.observed?.entryTypes.includes('longtask'),\n  )!;\n}\n\ndescribe('trackMainThreadBlock', () => {\n  let originalPerformanceObserver: typeof PerformanceObserver;\n  let amplitude: ReturnType<typeof createMockBrowserClient>;\n\n  beforeEach(() => {\n    MockPerformanceObserver.instances = [];\n    MockPerformanceObserver.supportedEntryTypes = ['long-animation-frame'];\n    originalPerformanceObserver = global.PerformanceObserver;\n    (global as any).PerformanceObserver = MockPerformanceObserver;\n    amplitude = createMockBrowserClient();\n  });\n\n  afterEach(() => {\n    global.PerformanceObserver = originalPerformanceObserver;\n  });\n\n  describe('long-animation-frame entry type', () => {\n    it('should track LoAF event with script metadata', () => {\n      trackMainThreadBlock({ amplitude, options: {} });\n\n      getBlockObserver().fire([\n        {\n          duration: 150,\n          startTime: 1000,\n          blockingDuration: 120,\n          renderStart: 1050,\n          styleAndLayoutStart: 1080,\n          scripts: [\n            { sourceURL: 'app.js', sourceFunctionName: 'onClick', invokerType: 'event-listener', invoker: 'click' },\n          ],\n        } as any,\n      ]);\n\n      expect(amplitude.track).toHaveBeenCalledWith(AMPLITUDE_MAIN_THREAD_BLOCK_EVENT, {\n        '[Amplitude] Main Thread Block Source': 'long-animation-frame',\n        '[Amplitude] Main Thread Block Duration': 150,\n        '[Amplitude] Main Thread Block Blocking Duration': 120,\n        '[Amplitude] Main Thread Block Start Time': 1000,\n        '[Amplitude] Main Thread Block Render Start': 1050,\n        '[Amplitude] Main Thread Block Style And Layout Start': 1080,\n        '[Amplitude] Main Thread Block Script Count': 1,\n        '[Amplitude] Main Thread Block Script URLs': ['app.js'],\n        '[Amplitude] Main Thread Block Script Functions': ['onClick'],\n        '[Amplitude] Main Thread Block Invoker Types': ['event-listener'],\n        '[Amplitude] Main Thread Block Invokers': ['click'],\n      });\n    });\n\n    it('should omit empty script fields', () => {\n      trackMainThreadBlock({ amplitude, options: {} });\n\n      getBlockObserver().fire([\n        {\n          duration: 150,\n          startTime: 1000,\n          blockingDuration: 120,\n          renderStart: 1050,\n          styleAndLayoutStart: 1080,\n          scripts: [{ sourceURL: '', sourceFunctionName: '', invokerType: '', invoker: '' }],\n        } as any,\n      ]);\n\n      const call = (amplitude.track as jest.Mock).mock.calls[0][1];\n      expect(call['[Amplitude] Main Thread Block Script URLs']).toBeUndefined();\n      expect(call['[Amplitude] Main Thread Block Script Functions']).toBeUndefined();\n      expect(call['[Amplitude] Main Thread Block Script Positions']).toBeUndefined();\n      expect(call['[Amplitude] Main Thread Block Invoker Types']).toBeUndefined();\n      expect(call['[Amplitude] Main Thread Block Invokers']).toBeUndefined();\n    });\n\n    it('should include script positions when sourceCharPosition is present', () => {\n      trackMainThreadBlock({ amplitude, options: {} });\n\n      getBlockObserver().fire([\n        {\n          duration: 150,\n          startTime: 1000,\n          blockingDuration: 120,\n          renderStart: 1050,\n          styleAndLayoutStart: 1080,\n          scripts: [\n            {\n              sourceURL: 'app.js',\n              sourceFunctionName: 'onClick',\n              sourceCharPosition: 1234,\n              invokerType: 'event-listener',\n              invoker: 'click',\n            },\n            {\n              sourceURL: 'vendor.js',\n              sourceFunctionName: 'handle',\n              // 0 is a valid character position and must not be filtered out\n              sourceCharPosition: 0,\n              invokerType: 'event-listener',\n              invoker: 'scroll',\n            },\n          ],\n        } as any,\n      ]);\n\n      const call = (amplitude.track as jest.Mock).mock.calls[0][1];\n      expect(call['[Amplitude] Main Thread Block Script Positions']).toEqual([1234, 0]);\n    });\n\n    it('should omit script positions when sourceCharPosition is missing on all scripts', () => {\n      trackMainThreadBlock({ amplitude, options: {} });\n\n      getBlockObserver().fire([\n        {\n          duration: 150,\n          startTime: 1000,\n          blockingDuration: 120,\n          renderStart: 1050,\n          styleAndLayoutStart: 1080,\n          scripts: [\n            { sourceURL: 'app.js', sourceFunctionName: 'onClick', invokerType: 'event-listener', invoker: 'click' },\n          ],\n        } as any,\n      ]);\n\n      const call = (amplitude.track as jest.Mock).mock.calls[0][1];\n      expect(call['[Amplitude] Main Thread Block Script Positions']).toBeUndefined();\n    });\n\n    it('should filter out -1 sentinel values from sourceCharPosition', () => {\n      trackMainThreadBlock({ amplitude, options: {} });\n\n      getBlockObserver().fire([\n        {\n          duration: 150,\n          startTime: 1000,\n          blockingDuration: 120,\n          renderStart: 1050,\n          styleAndLayoutStart: 1080,\n          scripts: [\n            {\n              sourceURL: 'app.js',\n              sourceFunctionName: 'onClick',\n              sourceCharPosition: 42,\n              invokerType: 'event-listener',\n              invoker: 'click',\n            },\n            {\n              sourceURL: 'vendor.js',\n              sourceFunctionName: 'handle',\n              sourceCharPosition: -1,\n              invokerType: 'event-listener',\n              invoker: 'scroll',\n            },\n          ],\n        } as any,\n      ]);\n\n      const call = (amplitude.track as jest.Mock).mock.calls[0][1];\n      expect(call['[Amplitude] Main Thread Block Script Positions']).toEqual([42]);\n    });\n\n    it('should include overlapping measures', () => {\n      trackMainThreadBlock({ amplitude, options: {} });\n\n      // Fire a measure entry first\n      getMeasureObserver().fire([{ name: 'my-measure', startTime: 900, duration: 200 } as any]);\n\n      // Fire a LoAF entry that overlaps with the measure\n      getBlockObserver().fire([\n        {\n          duration: 150,\n          startTime: 1000,\n          blockingDuration: 120,\n          renderStart: 1050,\n          styleAndLayoutStart: 1080,\n          scripts: [],\n        } as any,\n      ]);\n\n      const call = (amplitude.track as jest.Mock).mock.calls[0][1];\n      expect(call['[Amplitude] Main Thread Block Measures']).toEqual(['my-measure']);\n    });\n\n    it('should not include non-overlapping measures', () => {\n      trackMainThreadBlock({ amplitude, options: {} });\n\n      // Measure that ends before the block starts\n      getMeasureObserver().fire([{ name: 'old-measure', startTime: 0, duration: 500 } as any]);\n\n      getBlockObserver().fire([\n        {\n          duration: 150,\n          startTime: 1000,\n          blockingDuration: 120,\n          renderStart: 1050,\n          styleAndLayoutStart: 1080,\n          scripts: [],\n        } as any,\n      ]);\n\n      const call = (amplitude.track as jest.Mock).mock.calls[0][1];\n      expect(call['[Amplitude] Main Thread Block Measures']).toBeUndefined();\n    });\n\n    it('should not track when duration is below threshold', () => {\n      trackMainThreadBlock({ amplitude, options: {}, durationThreshold: 200 });\n\n      getBlockObserver().fire([\n        {\n          duration: 150,\n          startTime: 1000,\n          blockingDuration: 120,\n          renderStart: 1050,\n          styleAndLayoutStart: 1080,\n          scripts: [],\n        } as any,\n      ]);\n\n      expect(amplitude.track).not.toHaveBeenCalled();\n    });\n\n    it('should not track when URL is not allowed', () => {\n      trackMainThreadBlock({\n        amplitude,\n        options: { pageUrlAllowlist: ['https://allowed.com'] } as any,\n      });\n\n      // jsdom default URL is about:blank, not in allowlist\n      getBlockObserver().fire([\n        {\n          duration: 150,\n          startTime: 1000,\n          blockingDuration: 120,\n          renderStart: 1050,\n          styleAndLayoutStart: 1080,\n          scripts: [],\n        } as any,\n      ]);\n\n      expect(amplitude.track).not.toHaveBeenCalled();\n    });\n\n    it('should handle no scripts property (undefined scripts)', () => {\n      trackMainThreadBlock({ amplitude, options: {} });\n\n      getBlockObserver().fire([\n        {\n          duration: 150,\n          startTime: 1000,\n          blockingDuration: 120,\n          renderStart: 1050,\n          styleAndLayoutStart: 1080,\n          scripts: undefined,\n        } as any,\n      ]);\n\n      const call = (amplitude.track as jest.Mock).mock.calls[0][1];\n      expect(call['[Amplitude] Main Thread Block Script Count']).toBe(0);\n    });\n  });\n\n  describe('longtask entry type', () => {\n    beforeEach(() => {\n      MockPerformanceObserver.supportedEntryTypes = ['longtask'];\n    });\n\n    it('should track longtask event with attribution', () => {\n      trackMainThreadBlock({ amplitude, options: {} });\n\n      getBlockObserver().fire([\n        {\n          duration: 150,\n          startTime: 1000,\n          attribution: [{ name: 'same-origin' }],\n        } as any,\n      ]);\n\n      expect(amplitude.track).toHaveBeenCalledWith(AMPLITUDE_MAIN_THREAD_BLOCK_EVENT, {\n        '[Amplitude] Main Thread Block Source': 'long-task',\n        '[Amplitude] Main Thread Block Duration': 150,\n        '[Amplitude] Main Thread Block Blocking Duration': 150,\n        '[Amplitude] Main Thread Block Start Time': 1000,\n        '[Amplitude] Main Thread Block Attribution': ['same-origin'],\n      });\n    });\n\n    it('should omit attribution when empty', () => {\n      trackMainThreadBlock({ amplitude, options: {} });\n\n      getBlockObserver().fire([{ duration: 150, startTime: 1000, attribution: [] } as any]);\n\n      const call = (amplitude.track as jest.Mock).mock.calls[0][1];\n      expect(call['[Amplitude] Main Thread Block Attribution']).toBeUndefined();\n    });\n\n    it('should handle undefined attribution', () => {\n      trackMainThreadBlock({ amplitude, options: {} });\n\n      getBlockObserver().fire([{ duration: 150, startTime: 1000, attribution: undefined } as any]);\n\n      const call = (amplitude.track as jest.Mock).mock.calls[0][1];\n      expect(call['[Amplitude] Main Thread Block Attribution']).toBeUndefined();\n    });\n\n    it('should include overlapping measures for longtask entries', () => {\n      trackMainThreadBlock({ amplitude, options: {} });\n\n      getMeasureObserver().fire([{ name: 'my-measure', startTime: 900, duration: 200 } as any]);\n\n      getBlockObserver().fire([{ duration: 150, startTime: 1000, attribution: [] } as any]);\n\n      const call = (amplitude.track as jest.Mock).mock.calls[0][1];\n      expect(call['[Amplitude] Main Thread Block Measures']).toEqual(['my-measure']);\n    });\n  });\n\n  describe('measure buffer pruning', () => {\n    it('should prune stale measures older than the buffer window', () => {\n      jest.spyOn(performance, 'now').mockReturnValue(20_000);\n      trackMainThreadBlock({ amplitude, options: {} });\n\n      // Stale measure: startTime=0 < now(20000) - 10000 = 10000\n      getMeasureObserver().fire([{ name: 'stale', startTime: 0, duration: 100 } as any]);\n\n      getBlockObserver().fire([\n        {\n          duration: 150,\n          startTime: 15_000,\n          blockingDuration: 120,\n          renderStart: 15_050,\n          styleAndLayoutStart: 15_080,\n          scripts: [],\n        } as any,\n      ]);\n\n      const call = (amplitude.track as jest.Mock).mock.calls[0][1];\n      expect(call['[Amplitude] Main Thread Block Measures']).toBeUndefined();\n      jest.restoreAllMocks();\n    });\n  });\n\n  describe('unsupported entry types', () => {\n    it('should return no-op unsubscribe when neither long-animation-frame nor longtask is supported', () => {\n      MockPerformanceObserver.supportedEntryTypes = [];\n      const { unsubscribe } = trackMainThreadBlock({ amplitude, options: {} });\n      // Should not have created any observers\n      expect(MockPerformanceObserver.instances.length).toBe(0);\n      // unsubscribe is the istanbul-ignored no-op\n      expect(() => unsubscribe()).not.toThrow();\n    });\n  });\n\n  describe('measureObserver.observe failure', () => {\n    it('should continue without measures when measure observation throws', () => {\n      const originalObserve = MockPerformanceObserver.prototype.observe;\n      let callCount = 0;\n      MockPerformanceObserver.prototype.observe = function (opts: { entryTypes: string[] }) {\n        callCount++;\n        if (callCount === 1 && opts.entryTypes.includes('measure')) {\n          throw new Error('measure not supported');\n        }\n        originalObserve.call(this, opts);\n      };\n\n      trackMainThreadBlock({ amplitude, options: {} });\n\n      getBlockObserver().fire([\n        {\n          duration: 150,\n          startTime: 1000,\n          blockingDuration: 120,\n          renderStart: 1050,\n          styleAndLayoutStart: 1080,\n          scripts: [],\n        } as any,\n      ]);\n\n      expect(amplitude.track).toHaveBeenCalledTimes(1);\n      MockPerformanceObserver.prototype.observe = originalObserve;\n    });\n  });\n\n  describe('blockObserver.observe failure', () => {\n    it('should disconnect measureObserver and return no-op unsubscribe when block observation throws', () => {\n      const originalObserve = MockPerformanceObserver.prototype.observe;\n      let callCount = 0;\n      MockPerformanceObserver.prototype.observe = function (opts: { entryTypes: string[] }) {\n        callCount++;\n        if (callCount === 2) {\n          throw new Error('longtask not supported');\n        }\n        originalObserve.call(this, opts);\n      };\n\n      const { unsubscribe } = trackMainThreadBlock({ amplitude, options: {} });\n      unsubscribe();\n\n      expect(amplitude.track).not.toHaveBeenCalled();\n      MockPerformanceObserver.prototype.observe = originalObserve;\n    });\n  });\n\n  describe('unsubscribe', () => {\n    it('should disconnect both observers on unsubscribe', () => {\n      const { unsubscribe } = trackMainThreadBlock({ amplitude, options: {} });\n      unsubscribe();\n\n      MockPerformanceObserver.instances.forEach((i) => {\n        expect(i.disconnected).toBe(true);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/test/autocapture-plugin/track-rage-click.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/unbound-method */\n/* eslint-disable @typescript-eslint/no-empty-function */\nimport {\n  BrowserClient,\n  DEFAULT_RAGE_CLICK_THRESHOLD,\n  DEFAULT_RAGE_CLICK_WINDOW_MS,\n  Observable,\n  Unsubscribable,\n} from '@amplitude/analytics-core';\nimport { trackRageClicks } from '../../src/autocapture/track-rage-click';\nimport { AMPLITUDE_ELEMENT_RAGE_CLICKED_EVENT } from '../../src/constants';\nimport { ObservablesEnum } from '../../src/autocapture-plugin';\nimport { AllWindowObservables } from '../../src/frustration-plugin';\n\ndescribe('trackRageClicks', () => {\n  let mockAmplitude: jest.Mocked<BrowserClient>;\n  let clickObservable: Observable<any>;\n  let selectionObservable: Observable<any>;\n  let allObservables: AllWindowObservables;\n  let shouldTrackRageClick: jest.Mock;\n  let clickObserver: any;\n  let selectionObserver: any;\n  let mouseMoveObservable: any;\n  let subscription: ReturnType<typeof trackRageClicks>;\n\n  beforeEach(() => {\n    jest.useFakeTimers();\n    mockAmplitude = {\n      track: jest.fn(),\n    } as any;\n    clickObservable = new Observable<any>((observer) => {\n      clickObserver = observer;\n    });\n    selectionObservable = new Observable<any>((observer) => {\n      selectionObserver = observer;\n    });\n    mouseMoveObservable = new Observable<any>(() => {});\n    allObservables = {\n      [ObservablesEnum.ClickObservable]: clickObservable,\n      [ObservablesEnum.NavigateObservable]: new Observable<any>(() => {}),\n      [ObservablesEnum.MutationObservable]: new Observable<any>(() => {}),\n      [ObservablesEnum.BrowserErrorObservable]: new Observable<any>(() => {}),\n      [ObservablesEnum.SelectionObservable]: selectionObservable,\n      [ObservablesEnum.MouseMoveObservable]: mouseMoveObservable,\n    };\n    shouldTrackRageClick = jest.fn().mockReturnValue(true);\n\n    subscription = trackRageClicks({\n      amplitude: mockAmplitude,\n      allObservables,\n      shouldTrackRageClick,\n    });\n  });\n\n  afterEach(() => {\n    subscription?.unsubscribe();\n    jest.clearAllMocks();\n    jest.useRealTimers();\n  });\n\n  describe('selection change', () => {\n    let subscription: Unsubscribable | undefined;\n    let mockElement: HTMLElement;\n    let ancestorElement: HTMLElement;\n    let startTime: number;\n\n    beforeEach(async () => {\n      subscription = trackRageClicks({\n        amplitude: mockAmplitude,\n        allObservables,\n        shouldTrackRageClick,\n      });\n      mockElement = document.createElement('div');\n      ancestorElement = document.createElement('div');\n      startTime = Date.now();\n    });\n\n    afterEach(() => {\n      subscription?.unsubscribe();\n    });\n\n    it('should not track rage clicks when the text selection has changed', async () => {\n      for (let i = 0; i < DEFAULT_RAGE_CLICK_THRESHOLD; i++) {\n        clickObserver.next({\n          event: {\n            target: mockElement,\n            pageX: 100,\n            pageY: 100,\n          },\n          timestamp: startTime + i * 20,\n          closestTrackedAncestor: ancestorElement,\n          targetElementProperties: { id: 'test-element' },\n        });\n        if (i === DEFAULT_RAGE_CLICK_THRESHOLD - 2) {\n          jest.advanceTimersByTime(10);\n          selectionObserver.next();\n        }\n      }\n      jest.advanceTimersByTime(DEFAULT_RAGE_CLICK_WINDOW_MS + 100);\n      await jest.runAllTimersAsync();\n      expect(mockAmplitude.track).not.toHaveBeenCalled();\n    });\n\n    it('should track rage click if selection changes but 4 clicks happen after selection change', async () => {\n      for (let i = 0; i < DEFAULT_RAGE_CLICK_THRESHOLD + 3; i++) {\n        clickObserver.next({\n          event: {\n            target: mockElement,\n            pageX: 100,\n            pageY: 100,\n          },\n          timestamp: startTime + i * 20,\n          closestTrackedAncestor: ancestorElement,\n          targetElementProperties: { id: 'test-element' },\n        });\n\n        // make the 3rd click trigger a selection change\n        if (i === 2) {\n          jest.advanceTimersByTime(10);\n          selectionObserver.next();\n        }\n      }\n      jest.advanceTimersByTime(DEFAULT_RAGE_CLICK_WINDOW_MS + 100);\n      await jest.runAllTimersAsync();\n      expect(mockAmplitude.track).toHaveBeenCalled();\n    });\n  });\n\n  it('should track rage clicks when threshold is met', async () => {\n    // Create a mock element\n    const mockElement = document.createElement('div');\n\n    // Simulate clicks that exceed the time window to trigger immediate rage click detection\n    const startTime = Date.now();\n\n    // First click\n    clickObserver.next({\n      event: {\n        target: mockElement,\n        pageX: 100,\n        pageY: 100,\n      },\n      timestamp: startTime,\n      closestTrackedAncestor: mockElement,\n      targetElementProperties: { id: 'test-element' },\n    });\n\n    // Add clicks that exceed the time window\n    for (let i = 1; i < DEFAULT_RAGE_CLICK_THRESHOLD + 1; i++) {\n      clickObserver.next({\n        event: {\n          target: mockElement,\n          pageX: 100,\n          pageY: 100,\n        },\n        timestamp: startTime + DEFAULT_RAGE_CLICK_WINDOW_MS + i * 50, // Exceed the time window\n        closestTrackedAncestor: mockElement,\n        targetElementProperties: { id: 'test-element' },\n      });\n    }\n\n    // Advance timers to trigger the event processing\n    await jest.runAllTimersAsync();\n\n    expect(mockAmplitude.track).toHaveBeenCalledWith(\n      AMPLITUDE_ELEMENT_RAGE_CLICKED_EVENT,\n      expect.objectContaining({\n        '[Amplitude] Click Count': DEFAULT_RAGE_CLICK_THRESHOLD,\n        '[Amplitude] Clicks': expect.arrayContaining([\n          expect.objectContaining({\n            X: 100,\n            Y: 100,\n          }),\n        ]),\n        id: 'test-element',\n      }),\n      expect.any(Object),\n    );\n  });\n\n  it('should track rage clicks via timer when threshold is met within time window', async () => {\n    // Create a mock element\n    const mockElement = document.createElement('div');\n\n    // Simulate clicks within the time window to trigger timer-based rage click detection\n    const startTime = Date.now();\n    for (let i = 0; i < DEFAULT_RAGE_CLICK_THRESHOLD; i++) {\n      clickObserver.next({\n        event: {\n          target: mockElement,\n          pageX: 100,\n          pageY: 100,\n        },\n        timestamp: startTime + i * 50, // Space clicks 50ms apart (well within 1000ms window)\n        closestTrackedAncestor: mockElement,\n        targetElementProperties: { id: 'test-element' },\n      });\n    }\n\n    // Advance timers to complete the timer and call amplitude.track directly\n    await jest.runAllTimersAsync();\n\n    expect(mockAmplitude.track).toHaveBeenCalledWith(\n      AMPLITUDE_ELEMENT_RAGE_CLICKED_EVENT,\n      expect.objectContaining({\n        '[Amplitude] Click Count': DEFAULT_RAGE_CLICK_THRESHOLD,\n        '[Amplitude] Clicks': expect.arrayContaining([\n          expect.objectContaining({\n            X: 100,\n            Y: 100,\n          }),\n        ]),\n        id: 'test-element',\n      }),\n      expect.any(Object),\n    );\n  });\n\n  it('should track if clicks exceed threshold but first click is outside the rage click window', async () => {\n    // Create a mock element\n    const mockElement = document.createElement('div');\n\n    // Simulate clicks where the first click is outside the rage click window\n    const startTime = Date.now();\n    clickObserver.next({\n      event: {\n        target: mockElement,\n        pageX: 100,\n        pageY: 100,\n      },\n      timestamp: startTime,\n      closestTrackedAncestor: mockElement,\n      targetElementProperties: { id: 'test-element' },\n    });\n\n    // Add clicks within the rage click window\n    for (let i = 0; i < DEFAULT_RAGE_CLICK_THRESHOLD; i++) {\n      clickObserver.next({\n        event: {\n          target: mockElement,\n          pageX: 100,\n          pageY: 100,\n        },\n        timestamp: startTime + (DEFAULT_RAGE_CLICK_WINDOW_MS - 200) + i * 50,\n        closestTrackedAncestor: mockElement,\n        targetElementProperties: { id: 'test-element' },\n      });\n    }\n\n    await jest.runAllTimersAsync();\n\n    expect(mockAmplitude.track).toHaveBeenCalledTimes(1);\n  });\n\n  it('should not track when clicks are below threshold', () => {\n    // Create a mock element\n    const mockElement = document.createElement('div');\n\n    // Simulate only 3 clicks (below threshold of 4)\n    const startTime = Date.now();\n    for (let i = 0; i < DEFAULT_RAGE_CLICK_THRESHOLD - 1; i++) {\n      clickObserver.next({\n        event: {\n          target: mockElement,\n          pageX: 100,\n          pageY: 100,\n        },\n        timestamp: startTime + i * 50,\n        closestTrackedAncestor: mockElement,\n        targetElementProperties: { id: 'test-element' },\n      });\n    }\n\n    jest.advanceTimersByTime(DEFAULT_RAGE_CLICK_WINDOW_MS + 100);\n\n    expect(mockAmplitude.track).not.toHaveBeenCalled();\n  });\n\n  it('should not track when clicks are on different elements', () => {\n    // Create two different mock elements\n    const mockElement1 = document.createElement('div');\n    const mockElement2 = document.createElement('div');\n\n    // Simulate clicks alternating between elements\n    const startTime = Date.now();\n    for (let i = 0; i < DEFAULT_RAGE_CLICK_THRESHOLD * 2; i++) {\n      clickObserver.next({\n        event: {\n          target: i % 2 === 0 ? mockElement1 : mockElement2,\n          pageX: 100,\n          pageY: 100,\n        },\n        timestamp: startTime + i * 50,\n        closestTrackedAncestor: i % 2 === 0 ? mockElement1 : mockElement2,\n        targetElementProperties: { id: `test-element-${(i % 2) + 1}` },\n      });\n    }\n\n    jest.advanceTimersByTime(DEFAULT_RAGE_CLICK_WINDOW_MS + 100);\n\n    expect(mockAmplitude.track).not.toHaveBeenCalled();\n  });\n\n  it('should not track untracked elements', () => {\n    shouldTrackRageClick.mockReturnValue(false);\n\n    // element that is not tracked\n    const mockElement = document.createElement('div');\n\n    // Simulate 4 rapid clicks (threshold)\n    const startTime = Date.now();\n    for (let i = 0; i < DEFAULT_RAGE_CLICK_THRESHOLD; i++) {\n      clickObserver.next({\n        event: {\n          target: mockElement,\n          pageX: 100,\n          pageY: 100,\n        },\n        timestamp: startTime + i * 50,\n        closestTrackedAncestor: mockElement,\n        targetElementProperties: { id: 'test-element' },\n      });\n    }\n\n    jest.advanceTimersByTime(DEFAULT_RAGE_CLICK_WINDOW_MS + 100);\n\n    expect(mockAmplitude.track).not.toHaveBeenCalled();\n  });\n\n  it('should handle clicks that exceed the time window correctly', async () => {\n    // Create a mock element\n    const mockElement = document.createElement('div');\n\n    // Simulate clicks that exceed the time window\n    const startTime = Date.now();\n\n    // First set of clicks within the window\n    for (let i = 0; i < DEFAULT_RAGE_CLICK_THRESHOLD; i++) {\n      clickObserver.next({\n        event: {\n          target: mockElement,\n          pageX: 100,\n          pageY: 100,\n        },\n        timestamp: startTime + i * 50,\n        closestTrackedAncestor: mockElement,\n        targetElementProperties: { id: 'test-element' },\n      });\n    }\n\n    await jest.runAllTimersAsync();\n\n    // Add a click that exceeds the time window\n    clickObserver.next({\n      event: {\n        target: mockElement,\n        pageX: 100,\n        pageY: 100,\n      },\n      timestamp: startTime + DEFAULT_RAGE_CLICK_WINDOW_MS + 100,\n      closestTrackedAncestor: mockElement,\n      targetElementProperties: { id: 'test-element' },\n    });\n\n    await jest.runAllTimersAsync();\n\n    // Should track the first rage click event\n    expect(mockAmplitude.track).toHaveBeenCalledTimes(1);\n  });\n\n  it('should trigger rage click when switching to different element with enough previous clicks', async () => {\n    // Create two different mock elements\n    const mockElement1 = document.createElement('div');\n    const mockElement2 = document.createElement('div');\n\n    const startTime = Date.now();\n\n    // Simulate enough clicks on the first element to meet threshold\n    for (let i = 0; i < DEFAULT_RAGE_CLICK_THRESHOLD; i++) {\n      clickObserver.next({\n        event: {\n          target: mockElement1,\n          pageX: 100,\n          pageY: 100,\n        },\n        timestamp: startTime + i * 50,\n        closestTrackedAncestor: mockElement1,\n        targetElementProperties: { id: 'test-element-1' },\n      });\n    }\n\n    await jest.runAllTimersAsync();\n\n    // Now click on a different element - this should trigger rage click for the previous element\n    clickObserver.next({\n      event: {\n        target: mockElement2,\n        pageX: 200,\n        pageY: 200,\n      },\n      timestamp: startTime + DEFAULT_RAGE_CLICK_THRESHOLD * 50 + 100,\n      closestTrackedAncestor: mockElement2,\n      targetElementProperties: { id: 'test-element-2' },\n    });\n\n    await jest.runAllTimersAsync();\n\n    // Should track the rage click event for the first element\n    expect(mockAmplitude.track).toHaveBeenCalledWith(\n      AMPLITUDE_ELEMENT_RAGE_CLICKED_EVENT,\n      expect.objectContaining({\n        '[Amplitude] Click Count': DEFAULT_RAGE_CLICK_THRESHOLD,\n        '[Amplitude] Clicks': expect.arrayContaining([\n          expect.objectContaining({\n            X: 100,\n            Y: 100,\n          }),\n        ]),\n        id: 'test-element-1',\n      }),\n      expect.any(Object),\n    );\n  });\n\n  it('should not trigger rage click when switching to different element without enough previous clicks', () => {\n    // Create two different mock elements\n    const mockElement1 = document.createElement('div');\n    const mockElement2 = document.createElement('div');\n\n    const startTime = Date.now();\n\n    // Simulate clicks on the first element but not enough to meet threshold\n    for (let i = 0; i < DEFAULT_RAGE_CLICK_THRESHOLD - 1; i++) {\n      clickObserver.next({\n        event: {\n          target: mockElement1,\n          pageX: 100,\n          pageY: 100,\n        },\n        timestamp: startTime + i * 50,\n        closestTrackedAncestor: mockElement1,\n        targetElementProperties: { id: 'test-element-1' },\n      });\n    }\n\n    // Now click on a different element - this should NOT trigger rage click\n    clickObserver.next({\n      event: {\n        target: mockElement2,\n        pageX: 200,\n        pageY: 200,\n      },\n      timestamp: startTime + (DEFAULT_RAGE_CLICK_THRESHOLD - 1) * 50 + 100,\n      closestTrackedAncestor: mockElement2,\n      targetElementProperties: { id: 'test-element-2' },\n    });\n\n    jest.advanceTimersByTime(100);\n\n    // Should NOT track any rage click event\n    expect(mockAmplitude.track).not.toHaveBeenCalled();\n  });\n\n  it('should not track rage clicks when threshold is met but clicks are out of bounds', async () => {\n    // Create a mock element\n    const mockElement = document.createElement('div');\n\n    // Simulate clicks that exceed the time window to trigger immediate rage click detection\n    const startTime = Date.now();\n\n    // Add clicks that exceed the time window\n    for (let i = 0; i < DEFAULT_RAGE_CLICK_THRESHOLD; i++) {\n      clickObserver.next({\n        event: {\n          target: mockElement,\n          // have the first click and the last n - 1 clicks be in different\n          // positions to test that the rage click is not triggered\n          pageX: i === DEFAULT_RAGE_CLICK_THRESHOLD - 1 ? 1000 : 100,\n          pageY: i === DEFAULT_RAGE_CLICK_THRESHOLD - 1 ? 1000 : 100,\n          // keep clientX and clientY fixed to confirm it doesn't use\n          // viewport coordinates any more\n          clientX: 100,\n          clientY: 100,\n        },\n        timestamp: startTime + i,\n        closestTrackedAncestor: mockElement,\n        targetElementProperties: { id: 'test-element' },\n      });\n    }\n\n    // Run all timers and flush promises\n    await jest.runAllTimersAsync();\n\n    expect(mockAmplitude.track).not.toHaveBeenCalled();\n  });\n\n  it('should track rage clicks when threshold is met and next click is out of bounds', async () => {\n    // Create a mock element\n    const mockElement = document.createElement('div');\n    const startTime = Date.now();\n    for (let i = 0; i < DEFAULT_RAGE_CLICK_THRESHOLD; i++) {\n      clickObserver.next({\n        event: {\n          target: mockElement,\n          pageX: 100,\n          pageY: 100,\n        },\n        timestamp: startTime,\n        closestTrackedAncestor: mockElement,\n        targetElementProperties: { id: 'test-element' },\n      });\n    }\n    clickObserver.next({\n      event: {\n        target: mockElement,\n        pageX: 1000,\n        pageY: 1000,\n      },\n      timestamp: startTime,\n      closestTrackedAncestor: mockElement,\n      targetElementProperties: { id: 'test-element' },\n    });\n    await jest.runAllTimersAsync();\n    expect(mockAmplitude.track).toHaveBeenCalledTimes(1);\n  });\n});\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/test/autocapture-plugin/track-scroll.test.ts",
    "content": "import { trackScroll } from '../../src/autocapture/track-scroll';\nimport { ObservablesEnum } from '../../src/autocapture-plugin';\nimport { BrowserClient } from '@amplitude/analytics-core';\n\ndescribe('trackScroll', () => {\n  let scrollObservable: any;\n  let allObservables: any;\n  let unsubscribe: () => void;\n  let triggerScroll: () => void;\n  let amplitude: BrowserClient;\n\n  beforeEach(() => {\n    // Mock Observable\n    const observers: Array<() => void> = [];\n    scrollObservable = {\n      subscribe: jest.fn((fn) => {\n        observers.push(fn);\n        return {\n          unsubscribe: jest.fn(() => {\n            const index = observers.indexOf(fn);\n            if (index > -1) observers.splice(index, 1);\n          }),\n        };\n      }),\n    };\n\n    triggerScroll = () => {\n      observers.forEach((fn) => fn());\n    };\n\n    allObservables = {\n      [ObservablesEnum.ScrollObservable]: scrollObservable,\n    };\n\n    amplitude = {} as BrowserClient; // unused\n\n    // Reset window scroll properties\n    Object.defineProperty(window, 'scrollX', { value: 0, writable: true });\n    Object.defineProperty(window, 'scrollY', { value: 0, writable: true });\n    Object.defineProperty(window, 'pageXOffset', { value: 0, writable: true });\n    Object.defineProperty(window, 'pageYOffset', { value: 0, writable: true });\n  });\n\n  afterEach(() => {\n    if (unsubscribe) unsubscribe();\n    jest.clearAllMocks();\n  });\n\n  // Helper to set window scroll\n  const setScroll = (x: number, y: number) => {\n    Object.defineProperty(window, 'scrollX', { value: x, writable: true });\n    Object.defineProperty(window, 'scrollY', { value: y, writable: true });\n    Object.defineProperty(window, 'pageXOffset', { value: x, writable: true });\n    Object.defineProperty(window, 'pageYOffset', { value: y, writable: true });\n  };\n\n  test('should update state on scroll', () => {\n    const tracker = trackScroll({\n      amplitude,\n      allObservables,\n    });\n    unsubscribe = tracker.unsubscribe;\n\n    setScroll(100, 200);\n    triggerScroll();\n\n    expect(tracker.getState().maxX).toBe(100);\n    expect(tracker.getState().maxY).toBe(200);\n  });\n\n  test('should keep max values when scrolling back', () => {\n    const tracker = trackScroll({\n      amplitude,\n      allObservables,\n    });\n    unsubscribe = tracker.unsubscribe;\n\n    // Scroll down/right\n    setScroll(100, 200);\n    triggerScroll();\n    expect(tracker.getState().maxX).toBe(100);\n    expect(tracker.getState().maxY).toBe(200);\n\n    // Scroll back up/left\n    setScroll(50, 50);\n    triggerScroll();\n    expect(tracker.getState().maxX).toBe(100); // Should remain 100\n    expect(tracker.getState().maxY).toBe(200); // Should remain 200\n\n    // Scroll further down/right\n    setScroll(150, 300);\n    triggerScroll();\n    expect(tracker.getState().maxX).toBe(150);\n    expect(tracker.getState().maxY).toBe(300);\n  });\n\n  test('should handle missing scroll properties gracefully (fallback to 0)', () => {\n    const tracker = trackScroll({\n      amplitude,\n      allObservables,\n    });\n    unsubscribe = tracker.unsubscribe;\n\n    // Simulate environment where properties are missing or undefined\n    Object.defineProperty(window, 'scrollX', { value: undefined, writable: true });\n    Object.defineProperty(window, 'scrollY', { value: undefined, writable: true });\n    Object.defineProperty(window, 'pageXOffset', { value: undefined, writable: true });\n    Object.defineProperty(window, 'pageYOffset', { value: undefined, writable: true });\n\n    triggerScroll();\n\n    expect(tracker.getState().maxX).toBe(0);\n    expect(tracker.getState().maxY).toBe(0);\n  });\n\n  test('should reset state', () => {\n    const tracker = trackScroll({\n      amplitude,\n      allObservables,\n    });\n    unsubscribe = tracker.unsubscribe;\n\n    setScroll(100, 200);\n    triggerScroll();\n    expect(tracker.getState().maxX).toBe(100);\n    expect(tracker.getState().maxY).toBe(200);\n\n    tracker.reset();\n    expect(tracker.getState().maxX).toBe(0);\n    expect(tracker.getState().maxY).toBe(0);\n  });\n});\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/test/autocapture-plugin/track-thrashed-cursor.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/unbound-method */\n/* eslint-disable @typescript-eslint/no-empty-function */\n\nimport { BrowserClient, Observable, Unsubscribable } from '@amplitude/analytics-core';\nimport {\n  createMouseDirectionChangeObservable,\n  createThrashedCursorObservable,\n  trackThrashedCursor,\n} from '../../src/autocapture/track-thrashed-cursor';\nimport { AllWindowObservables } from '../../src/frustration-plugin';\nimport { ObservablesEnum } from '../../src/autocapture-plugin';\nimport { createMockBrowserClient } from '../mock-browser-client';\nimport { AMPLITUDE_THRASHED_CURSOR_EVENT } from '../../src/constants';\n\ndescribe('trackThrashedCursor', () => {\n  let amplitude: BrowserClient;\n  let mouseMoveObserver: any = {};\n  beforeEach(() => {\n    amplitude = createMockBrowserClient();\n    jest.useFakeTimers();\n  });\n\n  afterEach(() => {\n    jest.useRealTimers();\n  });\n\n  async function setupAndSimulateThrashedCursor(\n    config: {\n      directionChanges?: number;\n      thresholdMs?: number;\n      options?: {\n        pageUrlAllowlist?: RegExp[];\n        pageUrlExcludelist?: RegExp[];\n      };\n      windowLocation?: {\n        href: string;\n      };\n      mouseMovements?: {\n        iterations?: number;\n        timeAdvance?: number;\n      };\n    } = {},\n  ): Promise<{ mouseMoveObserver: any; startTime: number }> {\n    const {\n      directionChanges,\n      thresholdMs,\n      options = {\n        pageUrlAllowlist: [],\n        pageUrlExcludelist: [],\n      },\n      windowLocation,\n      mouseMovements = {\n        iterations: 10,\n        timeAdvance: 1,\n      },\n    } = config;\n\n    if (windowLocation) {\n      Object.defineProperty(window, 'location', {\n        value: windowLocation,\n        writable: true,\n      });\n    }\n\n    const promise = new Promise<void>((resolve) => {\n      trackThrashedCursor({\n        amplitude,\n        allObservables: {\n          [ObservablesEnum.MouseMoveObservable]: new Observable<MouseEvent>((observer) => {\n            mouseMoveObserver = observer;\n            resolve();\n          }),\n        } as AllWindowObservables,\n        ...(directionChanges !== undefined && { directionChanges }),\n        ...(thresholdMs !== undefined && { thresholdMs }),\n        options,\n      });\n    });\n\n    jest.runAllTimers();\n    await promise;\n\n    const startTime = +Date.now();\n    if (mouseMoveObserver.next) {\n      // simulate a circular mouse motion\n      const origin = { clientX: 100, clientY: 100 };\n      const destination = { clientX: 101, clientY: 101 };\n      for (let i = 0; i < mouseMovements.iterations!; i++) {\n        if (i % 2 === 0) {\n          mouseMoveObserver.next(origin);\n        } else {\n          mouseMoveObserver.next(destination);\n        }\n        jest.advanceTimersByTime(mouseMovements.timeAdvance!);\n      }\n    }\n    jest.runAllTimers();\n\n    return { mouseMoveObserver, startTime };\n  }\n\n  it('should track thrashed cursor', async () => {\n    // 22 iterations = 21 transitions = 20 direction changes per axis (threshold)\n    const { startTime } = await setupAndSimulateThrashedCursor({\n      windowLocation: { href: 'http://localhost/' },\n      mouseMovements: {\n        iterations: 22,\n        timeAdvance: 100,\n      },\n    });\n    const expectedTime = startTime + 2 * 100;\n    expect(amplitude.track).toHaveBeenCalledWith(AMPLITUDE_THRASHED_CURSOR_EVENT, undefined, {\n      time: expectedTime,\n    });\n  });\n\n  it('should track thrashed cursor with custom threshold and window ms', async () => {\n    const { startTime } = await setupAndSimulateThrashedCursor({\n      directionChanges: 5,\n      thresholdMs: 100,\n    });\n    const expectedTime = startTime + 2 * 1;\n    expect(amplitude.track).toHaveBeenCalledWith(AMPLITUDE_THRASHED_CURSOR_EVENT, undefined, {\n      time: expectedTime,\n    });\n  });\n\n  it('should not track thrashed cursor when pageUrlExcludelist is set', async () => {\n    await setupAndSimulateThrashedCursor({\n      directionChanges: 5,\n      thresholdMs: 100,\n      windowLocation: {\n        href: 'http://localhost/test',\n      },\n      options: {\n        pageUrlAllowlist: [],\n        pageUrlExcludelist: [new RegExp('/test')],\n      },\n    });\n    expect(amplitude.track).not.toHaveBeenCalled();\n  });\n\n  it('should not track thrashed cursor when pageUrlAllowlist is set', async () => {\n    await setupAndSimulateThrashedCursor({\n      directionChanges: 5,\n      thresholdMs: 100,\n      windowLocation: {\n        href: 'http://localhost/nomatch',\n      },\n      options: {\n        pageUrlAllowlist: [new RegExp('/match')],\n        pageUrlExcludelist: [],\n      },\n    });\n    expect(amplitude.track).not.toHaveBeenCalled();\n  });\n});\n\ndescribe('createMouseDirectionChangeObservable', () => {\n  let mouseMoveObservable: any;\n  let mouseMoveObserver: any;\n  let allWindowObservables: AllWindowObservables;\n  let directionChangeObservable: Observable<string>;\n  let subscription: Unsubscribable | undefined;\n  let subscriptionPromise: Promise<string>;\n\n  beforeEach(() => {\n    mouseMoveObservable = new Observable<any>((observer) => {\n      mouseMoveObserver = observer;\n    });\n\n    allWindowObservables = {\n      [ObservablesEnum.MouseMoveObservable]: mouseMoveObservable,\n    } as AllWindowObservables;\n\n    directionChangeObservable = createMouseDirectionChangeObservable({\n      allWindowObservables,\n    });\n\n    subscriptionPromise = new Promise<string>((resolve) => {\n      subscription = directionChangeObservable.subscribe((axis) => {\n        resolve(axis);\n      });\n    });\n  });\n\n  afterEach(() => {\n    subscription?.unsubscribe();\n    jest.clearAllMocks();\n  });\n\n  it('should emit X direction change when mouse moves to the right', async () => {\n    mouseMoveObserver.next({ clientX: 1, clientY: 1 });\n    mouseMoveObserver.next({ clientX: 2, clientY: 1 });\n    mouseMoveObserver.next({ clientX: 1, clientY: 1 });\n    const axis = await subscriptionPromise;\n    expect(axis).toEqual('x');\n  });\n\n  it('should emit X direction change when mouse moves to the left', async () => {\n    mouseMoveObserver.next({ clientX: 2, clientY: 1 });\n    mouseMoveObserver.next({ clientX: 1, clientY: 1 });\n    mouseMoveObserver.next({ clientX: 2, clientY: 1 });\n    const axis = await subscriptionPromise;\n    expect(axis).toEqual('x');\n  });\n\n  it('should emit Y direction change when mouse moves up', async () => {\n    mouseMoveObserver.next({ clientX: 1, clientY: 1 });\n    mouseMoveObserver.next({ clientX: 1, clientY: 2 });\n    mouseMoveObserver.next({ clientX: 1, clientY: 1 });\n    const axis = await subscriptionPromise;\n    expect(axis).toEqual('y');\n  });\n\n  it('should emit Y direction change when mouse moves down', async () => {\n    mouseMoveObserver.next({ clientX: 1, clientY: 2 });\n    mouseMoveObserver.next({ clientX: 1, clientY: 1 });\n    mouseMoveObserver.next({ clientX: 1, clientY: 2 });\n    const axis = await subscriptionPromise;\n    expect(axis).toEqual('y');\n  });\n});\n\ndescribe('createThrashedCursorObservable', () => {\n  let mouseDirectionChangeObservable: Observable<'x' | 'y'>;\n  let directionChangeObserver: any;\n  let thrashedCursorObservable: Observable<number>;\n  let subscription: Unsubscribable | undefined;\n  let emittedTimes: number[];\n  let startTime: number;\n  const DEFAULT_THRESHOLD = 20;\n  const DEFAULT_WINDOW_MS = 2000;\n\n  beforeEach(() => {\n    jest.useFakeTimers();\n    emittedTimes = [];\n    mouseDirectionChangeObservable = new Observable<'x' | 'y'>((observer) => {\n      directionChangeObserver = observer;\n    });\n\n    thrashedCursorObservable = createThrashedCursorObservable({\n      mouseDirectionChangeObservable: mouseDirectionChangeObservable as any,\n    });\n\n    subscription = thrashedCursorObservable.subscribe((time) => {\n      emittedTimes.push(time);\n    });\n    startTime = +Date.now();\n  });\n\n  afterEach(() => {\n    subscription?.unsubscribe();\n    jest.clearAllMocks();\n    jest.useRealTimers();\n  });\n\n  it('should not emit when direction changes are below threshold', () => {\n    for (let i = 0; i < DEFAULT_THRESHOLD - 1; i++) {\n      jest.advanceTimersByTime(100);\n      directionChangeObserver.next('x');\n    }\n    jest.advanceTimersByTime(DEFAULT_WINDOW_MS + 100);\n    expect(emittedTimes).toHaveLength(0);\n  });\n\n  it('should emit when X axis direction changes meet threshold within window', async () => {\n    for (let i = 0; i < DEFAULT_THRESHOLD; i++) {\n      directionChangeObserver.next('x');\n      jest.advanceTimersByTime(100);\n    }\n    await jest.runAllTimersAsync();\n    expect(emittedTimes).toEqual([startTime]);\n  });\n\n  it('should emit when Y axis direction changes meet threshold within window', async () => {\n    for (let i = 0; i < DEFAULT_THRESHOLD; i++) {\n      directionChangeObserver.next('y');\n      jest.advanceTimersByTime(100);\n    }\n    await jest.runAllTimersAsync();\n    expect(emittedTimes).toEqual([startTime]);\n  });\n\n  it('should emit when both X and Y axes meet threshold', async () => {\n    // Emit 20 X and Y direction changes\n    for (let i = 0; i < DEFAULT_THRESHOLD; i++) {\n      directionChangeObserver.next('x');\n      jest.advanceTimersByTime(50);\n      directionChangeObserver.next('y');\n      jest.advanceTimersByTime(50);\n    }\n    await jest.runAllTimersAsync();\n    expect(emittedTimes.length).toBeGreaterThan(0);\n    expect(emittedTimes).toEqual([startTime]);\n  });\n\n  it('should not emit when direction changes exceed window time', () => {\n    const mouseMoveIntervals = DEFAULT_WINDOW_MS / (DEFAULT_THRESHOLD - 1) + 10;\n    for (let i = 0; i < DEFAULT_THRESHOLD; i++) {\n      directionChangeObserver.next('x');\n      jest.advanceTimersByTime(mouseMoveIntervals);\n    }\n    jest.advanceTimersByTime(100);\n    expect(emittedTimes).toHaveLength(0);\n  });\n\n  it('should only trigger one thrashed cursor if there are more mouse moves than threshold', async () => {\n    for (let i = 0; i < DEFAULT_THRESHOLD + 100; i++) {\n      directionChangeObserver.next('x');\n      jest.advanceTimersByTime(100);\n    }\n    expect(emittedTimes).toHaveLength(0);\n    await jest.runAllTimersAsync();\n    expect(emittedTimes).toEqual([startTime]);\n  });\n\n  it('should trigger two thrashed cursors if there is time between them', async () => {\n    // first thrashed cursor\n    for (let i = 0; i < DEFAULT_THRESHOLD; i++) {\n      directionChangeObserver.next('x');\n      jest.advanceTimersByTime(100);\n    }\n    await jest.runAllTimersAsync();\n\n    // second thrashed cursor\n    jest.advanceTimersByTime(DEFAULT_WINDOW_MS + 100);\n    const secondStartTime = +Date.now();\n    for (let i = 0; i < DEFAULT_THRESHOLD; i++) {\n      directionChangeObserver.next('x');\n      jest.advanceTimersByTime(100);\n    }\n    await jest.runAllTimersAsync();\n    expect(emittedTimes).toEqual([startTime, secondStartTime]);\n  });\n\n  it('should trigger one thrashed cursor if trailing window is above threshold', async () => {\n    for (let i = 0; i < DEFAULT_THRESHOLD; i++) {\n      directionChangeObserver.next('x');\n      jest.advanceTimersByTime(100);\n    }\n    jest.advanceTimersByTime(DEFAULT_WINDOW_MS - 100);\n    directionChangeObserver.next('x');\n    expect(emittedTimes).toEqual([startTime]);\n  });\n\n  it('should use custom threshold and window ms', async () => {\n    const customWindowMs = 10;\n    const customThreshold = 5;\n    thrashedCursorObservable = createThrashedCursorObservable({\n      mouseDirectionChangeObservable: mouseDirectionChangeObservable as any,\n      thresholdMs: customWindowMs,\n      directionChanges: customThreshold,\n    });\n    subscription?.unsubscribe();\n    emittedTimes = [];\n    subscription = thrashedCursorObservable.subscribe((time) => {\n      emittedTimes.push(time);\n    });\n\n    for (let i = 0; i < customThreshold; i++) {\n      directionChangeObserver.next('x');\n      jest.advanceTimersByTime(2);\n    }\n    await jest.runAllTimersAsync();\n    expect(emittedTimes).toEqual([startTime]);\n  });\n\n  it('should trigger a start time when the first direction change is made', async () => {\n    const testStartTime = +Date.now();\n    directionChangeObserver.next('x');\n    jest.advanceTimersByTime(DEFAULT_WINDOW_MS + 100);\n    const thrashedCursorStartTime = +Date.now();\n    for (let i = 0; i < DEFAULT_THRESHOLD; i++) {\n      directionChangeObserver.next('x');\n      jest.advanceTimersByTime(100);\n    }\n    await jest.runAllTimersAsync();\n    expect(emittedTimes[0]).toBeGreaterThan(testStartTime);\n    expect(emittedTimes).toEqual([thrashedCursorStartTime]);\n  });\n\n  it('should slide window to the right when direction changes are above threshold', async () => {\n    // run a direction change and wait 1.5 seconds\n    directionChangeObserver.next('x');\n    jest.advanceTimersByTime(DEFAULT_WINDOW_MS - 500);\n\n    // run 20 direction changes over 2 seconds; which will push the first change out of the window\n    const expectedStartTime = +Date.now();\n    for (let i = 0; i < DEFAULT_THRESHOLD; i++) {\n      directionChangeObserver.next('x');\n      jest.advanceTimersByTime(100);\n    }\n    await jest.runAllTimersAsync();\n\n    // expect the start time to be the start of the last 20 changes and not the first change\n    expect(emittedTimes).toEqual([expectedStartTime]);\n  });\n});\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/test/autocapture-plugin/viewport-content-updated.test.ts",
    "content": "import { autocapturePlugin } from '../../src/autocapture-plugin';\nimport { BrowserClient, BrowserConfig, ILogger } from '@amplitude/analytics-core';\nimport { createMockBrowserClient } from '../mock-browser-client';\nimport { trackExposure } from '../../src/autocapture/track-exposure';\nimport {\n  fireViewportContentUpdated,\n  ScrollTracker,\n  ExposureTracker,\n} from '../../src/autocapture/track-viewport-content-updated';\nimport * as constants from '../../src/constants';\n\n// Mock trackExposure to capture onExposure callback\njest.mock('../../src/autocapture/track-exposure', () => ({\n  trackExposure: jest.fn(),\n}));\n\n// Mock fireViewportContentUpdated to verify calls\njest.mock('../../src/autocapture/track-viewport-content-updated', () => {\n  const originalModule = jest.requireActual<typeof import('../../src/autocapture/track-viewport-content-updated')>(\n    '../../src/autocapture/track-viewport-content-updated',\n  );\n  return {\n    ...originalModule,\n    fireViewportContentUpdated: jest.fn((...args: Parameters<typeof originalModule.fireViewportContentUpdated>) =>\n      originalModule.fireViewportContentUpdated(...args),\n    ),\n  };\n});\n\ndescribe('autocapturePlugin - Viewport Content Updated (Exposure)', () => {\n  let plugin: any;\n  let instance: BrowserClient;\n  let track: jest.SpyInstance;\n  let onExposureCallback: (elementPath: string) => void;\n  let trackExposureMock: jest.Mock;\n  let fireViewportContentUpdatedMock: jest.Mock;\n\n  const TESTING_DEBOUNCE_TIME = 0;\n\n  beforeEach(async () => {\n    jest.useFakeTimers();\n    jest.spyOn(console, 'log').mockImplementation(jest.fn());\n\n    trackExposureMock = trackExposure as unknown as jest.Mock;\n    trackExposureMock.mockImplementation(({ onExposure }) => {\n      onExposureCallback = onExposure;\n      return {\n        unsubscribe: jest.fn(),\n        reset: jest.fn(),\n      };\n    });\n\n    fireViewportContentUpdatedMock = fireViewportContentUpdated as unknown as jest.Mock;\n\n    const loggerProvider = {\n      log: jest.fn(),\n      warn: jest.fn(),\n      error: jest.fn(),\n      debug: jest.fn(),\n    } as unknown as ILogger;\n\n    plugin = autocapturePlugin({ debounceTime: TESTING_DEBOUNCE_TIME });\n    instance = createMockBrowserClient();\n    await instance.init('API_KEY', 'USER_ID').promise;\n    track = jest.spyOn(instance, 'track').mockImplementation(jest.fn());\n\n    const config: Partial<BrowserConfig> = {\n      defaultTracking: false,\n      loggerProvider: loggerProvider,\n    };\n    await plugin.setup(config as BrowserConfig, instance);\n  });\n\n  afterEach(() => {\n    jest.clearAllMocks();\n    jest.useRealTimers();\n    window.sessionStorage.clear();\n    plugin.teardown();\n  });\n\n  test('should trigger Viewport Content Updated when exposed elements exceed 18k chars', async () => {\n    // Verify onExposure was captured\n    expect(onExposureCallback).toBeDefined();\n\n    // 1. Add a small element, should not trigger track\n    onExposureCallback('small-element');\n    expect(fireViewportContentUpdatedMock).not.toHaveBeenCalled();\n\n    // 2. Add a very large element path to exceed 18k chars\n    // We need to exceed 18000 characters in JSON.stringify(array)\n    // The array will be [\"small-element\", \"large...\"]\n    // We can just add one massive string.\n    const largeString = 'a'.repeat(19000);\n    onExposureCallback(largeString);\n\n    // Should trigger track\n    expect(fireViewportContentUpdatedMock).toHaveBeenCalledTimes(1);\n    expect(track).toHaveBeenCalledWith(\n      '[Amplitude] Viewport Content Updated',\n      expect.objectContaining({\n        '[Amplitude] Element Exposed': expect.arrayContaining(['small-element', largeString]),\n      }),\n    );\n\n    // 3. Verify the batch is cleared after tracking\n    track.mockClear();\n    fireViewportContentUpdatedMock.mockClear();\n\n    // Advance timers to allow pageViewEndFired to reset (100ms timeout in handleViewportContentUpdated)\n    jest.advanceTimersByTime(150);\n\n    // Add another small element\n    onExposureCallback('another-small-element');\n\n    // Should not trigger again immediately\n    expect(fireViewportContentUpdatedMock).not.toHaveBeenCalled();\n\n    // But if we trigger page view end (e.g. via beforeunload), it should flush the new batch\n    window.dispatchEvent(new Event('beforeunload'));\n\n    expect(fireViewportContentUpdatedMock).toHaveBeenCalledTimes(1);\n    expect(track).toHaveBeenCalledWith(\n      '[Amplitude] Viewport Content Updated',\n      expect.objectContaining({\n        '[Amplitude] Element Exposed': expect.arrayContaining(['another-small-element']),\n      }),\n    );\n  });\n\n  test('should not re-add already exposed elements to the current batch', async () => {\n    // 1. Add an element\n    onExposureCallback('element-1');\n\n    // 2. Add the same element again\n    onExposureCallback('element-1');\n\n    // 3. Force flush via beforeunload\n    window.dispatchEvent(new Event('beforeunload'));\n\n    // Should only be in the array once\n    expect(track).toHaveBeenCalledWith(\n      '[Amplitude] Viewport Content Updated',\n      expect.objectContaining({\n        '[Amplitude] Element Exposed': ['element-1'],\n      }),\n    );\n  });\n\n  test('should include page view ID when available', async () => {\n    window.sessionStorage.setItem(\n      constants.PAGE_VIEW_SESSION_STORAGE_KEY,\n      JSON.stringify({ pageViewId: 'pv-test-123' }),\n    );\n\n    onExposureCallback('element-1');\n    window.dispatchEvent(new Event('beforeunload'));\n\n    expect(track).toHaveBeenCalledWith(\n      '[Amplitude] Viewport Content Updated',\n      expect.objectContaining({\n        '[Amplitude] Element Exposed': ['element-1'],\n        '[Amplitude] Page View ID': 'pv-test-123',\n      }),\n    );\n  });\n\n  test('should not include page view ID when sessionStorage contains invalid JSON', async () => {\n    window.sessionStorage.setItem(constants.PAGE_VIEW_SESSION_STORAGE_KEY, 'invalid-json{not-valid');\n\n    onExposureCallback('element-1');\n    window.dispatchEvent(new Event('beforeunload'));\n\n    expect(track).toHaveBeenCalledWith(\n      '[Amplitude] Viewport Content Updated',\n      expect.objectContaining({\n        '[Amplitude] Element Exposed': ['element-1'],\n      }),\n    );\n\n    // Verify Page View ID is NOT in the event properties\n    const trackCall = track.mock.calls[0];\n    expect(trackCall[1]).not.toHaveProperty('[Amplitude] Page View ID');\n  });\n\n  test('should call handleViewportContentUpdated with isPageEnd=true on beforeunload', async () => {\n    onExposureCallback('element-1');\n    window.dispatchEvent(new Event('beforeunload'));\n\n    expect(fireViewportContentUpdatedMock).toHaveBeenCalledTimes(1);\n    expect(fireViewportContentUpdatedMock).toHaveBeenCalledWith(\n      expect.objectContaining({\n        isPageEnd: true,\n      }),\n    );\n  });\n\n  test('should call handleViewportContentUpdated with isPageEnd=false when exposure exceeds 18k chars', async () => {\n    // Add a very large element path to exceed 18k chars\n    const largeString = 'a'.repeat(19000);\n    onExposureCallback(largeString);\n\n    expect(fireViewportContentUpdatedMock).toHaveBeenCalledTimes(1);\n    expect(fireViewportContentUpdatedMock).toHaveBeenCalledWith(\n      expect.objectContaining({\n        isPageEnd: false,\n      }),\n    );\n  });\n});\n\ndescribe('fireViewportContentUpdated - exposureTracker optional chaining', () => {\n  let mockAmplitude: BrowserClient;\n  let mockScrollTracker: ScrollTracker;\n\n  beforeEach(async () => {\n    mockAmplitude = createMockBrowserClient();\n    await mockAmplitude.init('API_KEY', 'USER_ID').promise;\n    jest.spyOn(mockAmplitude, 'track').mockImplementation(jest.fn());\n\n    mockScrollTracker = {\n      getState: jest.fn().mockReturnValue({ maxX: 100, maxY: 200 }),\n      reset: jest.fn(),\n    };\n  });\n\n  afterEach(() => {\n    jest.clearAllMocks();\n  });\n\n  test('should handle undefined exposureTracker gracefully when isPageEnd is true and early-returning', () => {\n    const currentElementExposed = new Set<string>();\n    const elementExposedForPage = new Set<string>(['stale-element']);\n\n    expect(() => {\n      fireViewportContentUpdated({\n        amplitude: mockAmplitude,\n        scrollTracker: mockScrollTracker,\n        currentElementExposed,\n        elementExposedForPage,\n        exposureTracker: undefined,\n        isPageEnd: true,\n        lastScroll: { maxX: 100, maxY: 200 }, // Same as scrollTracker state → triggers early return\n      });\n    }).not.toThrow();\n\n    expect(mockScrollTracker.reset).toHaveBeenCalled();\n    expect(elementExposedForPage.size).toBe(0);\n  });\n\n  test('should handle undefined exposureTracker gracefully when isPageEnd is true', () => {\n    const currentElementExposed = new Set<string>(['element-1']);\n    const elementExposedForPage = new Set<string>(['element-1']);\n\n    // Call with exposureTracker as undefined and isPageEnd as true\n    expect(() => {\n      fireViewportContentUpdated({\n        amplitude: mockAmplitude,\n        scrollTracker: mockScrollTracker,\n        currentElementExposed,\n        elementExposedForPage,\n        exposureTracker: undefined,\n        isPageEnd: true,\n        lastScroll: { maxX: undefined, maxY: undefined },\n      });\n    }).not.toThrow();\n\n    // Verify scrollTracker.reset was still called\n    expect(mockScrollTracker.reset).toHaveBeenCalled();\n    // Verify elementExposedForPage was cleared\n    expect(elementExposedForPage.size).toBe(0);\n  });\n\n  test('should call exposureTracker.reset when exposureTracker is defined and isPageEnd is true', () => {\n    const currentElementExposed = new Set<string>(['element-1']);\n    const elementExposedForPage = new Set<string>(['element-1']);\n    const mockExposureTracker: ExposureTracker = {\n      reset: jest.fn(),\n    };\n\n    fireViewportContentUpdated({\n      amplitude: mockAmplitude,\n      scrollTracker: mockScrollTracker,\n      currentElementExposed,\n      elementExposedForPage,\n      exposureTracker: mockExposureTracker,\n      isPageEnd: true,\n      lastScroll: { maxX: undefined, maxY: undefined },\n    });\n\n    // Verify exposureTracker.reset was called\n    expect(mockExposureTracker.reset).toHaveBeenCalled();\n    // Verify scrollTracker.reset was also called\n    expect(mockScrollTracker.reset).toHaveBeenCalled();\n  });\n\n  test('should not call exposureTracker.reset when isPageEnd is false', () => {\n    const currentElementExposed = new Set<string>(['element-1']);\n    const elementExposedForPage = new Set<string>(['element-1']);\n    const mockExposureTracker: ExposureTracker = {\n      reset: jest.fn(),\n    };\n\n    fireViewportContentUpdated({\n      amplitude: mockAmplitude,\n      scrollTracker: mockScrollTracker,\n      currentElementExposed,\n      elementExposedForPage,\n      exposureTracker: mockExposureTracker,\n      isPageEnd: false,\n      lastScroll: { maxX: undefined, maxY: undefined },\n    });\n\n    // Verify exposureTracker.reset was NOT called\n    expect(mockExposureTracker.reset).not.toHaveBeenCalled();\n    // Verify scrollTracker.reset was also NOT called\n    expect(mockScrollTracker.reset).not.toHaveBeenCalled();\n  });\n});\n\ndescribe('fireViewportContentUpdated - early return when no changes', () => {\n  let mockAmplitude: BrowserClient;\n  let mockScrollTracker: ScrollTracker;\n  let trackSpy: jest.SpyInstance;\n\n  beforeEach(async () => {\n    mockAmplitude = createMockBrowserClient();\n    await mockAmplitude.init('API_KEY', 'USER_ID').promise;\n    trackSpy = jest.spyOn(mockAmplitude, 'track').mockImplementation(jest.fn());\n\n    mockScrollTracker = {\n      getState: jest.fn().mockReturnValue({ maxX: 100, maxY: 200 }),\n      reset: jest.fn(),\n    };\n  });\n\n  afterEach(() => {\n    jest.clearAllMocks();\n  });\n\n  test('should not track when no elements exposed and scroll position unchanged', () => {\n    const currentElementExposed = new Set<string>();\n    const elementExposedForPage = new Set<string>();\n\n    fireViewportContentUpdated({\n      amplitude: mockAmplitude,\n      scrollTracker: mockScrollTracker,\n      currentElementExposed,\n      elementExposedForPage,\n      exposureTracker: undefined,\n      isPageEnd: false,\n      lastScroll: { maxX: 100, maxY: 200 }, // Same as scrollTracker state\n    });\n\n    // Should NOT call track because no elements exposed and scroll is same\n    expect(trackSpy).not.toHaveBeenCalled();\n  });\n\n  test('should still run page-end cleanup when early-returning with isPageEnd=true', () => {\n    const currentElementExposed = new Set<string>();\n    const elementExposedForPage = new Set<string>(['stale-element']);\n    const mockExposureTracker: ExposureTracker = { reset: jest.fn() };\n\n    fireViewportContentUpdated({\n      amplitude: mockAmplitude,\n      scrollTracker: mockScrollTracker,\n      currentElementExposed,\n      elementExposedForPage,\n      exposureTracker: mockExposureTracker,\n      isPageEnd: true,\n      lastScroll: { maxX: 100, maxY: 200 }, // Same as scrollTracker state\n    });\n\n    // Should NOT track an event (no new data)\n    expect(trackSpy).not.toHaveBeenCalled();\n\n    // But page-end cleanup MUST still run\n    expect(mockScrollTracker.reset).toHaveBeenCalled();\n    expect(elementExposedForPage.size).toBe(0);\n    expect(mockExposureTracker.reset).toHaveBeenCalled();\n  });\n\n  test('should track when elements are exposed even if scroll position unchanged', () => {\n    const currentElementExposed = new Set<string>(['element-1']);\n    const elementExposedForPage = new Set<string>(['element-1']);\n\n    fireViewportContentUpdated({\n      amplitude: mockAmplitude,\n      scrollTracker: mockScrollTracker,\n      currentElementExposed,\n      elementExposedForPage,\n      exposureTracker: undefined,\n      isPageEnd: false,\n      lastScroll: { maxX: 100, maxY: 200 }, // Same as scrollTracker state\n    });\n\n    // Should call track because there are exposed elements\n    expect(trackSpy).toHaveBeenCalledWith(\n      '[Amplitude] Viewport Content Updated',\n      expect.objectContaining({\n        '[Amplitude] Element Exposed': ['element-1'],\n      }),\n    );\n  });\n\n  test('should track when maxX changed even if no elements exposed', () => {\n    const currentElementExposed = new Set<string>();\n    const elementExposedForPage = new Set<string>();\n\n    fireViewportContentUpdated({\n      amplitude: mockAmplitude,\n      scrollTracker: mockScrollTracker,\n      currentElementExposed,\n      elementExposedForPage,\n      exposureTracker: undefined,\n      isPageEnd: false,\n      lastScroll: { maxX: 50, maxY: 200 }, // Different maxX\n    });\n\n    // Should call track because maxX changed\n    expect(trackSpy).toHaveBeenCalledWith(\n      '[Amplitude] Viewport Content Updated',\n      expect.objectContaining({\n        '[Amplitude] Element Exposed': [],\n      }),\n    );\n  });\n\n  test('should track when maxY changed even if no elements exposed', () => {\n    const currentElementExposed = new Set<string>();\n    const elementExposedForPage = new Set<string>();\n\n    fireViewportContentUpdated({\n      amplitude: mockAmplitude,\n      scrollTracker: mockScrollTracker,\n      currentElementExposed,\n      elementExposedForPage,\n      exposureTracker: undefined,\n      isPageEnd: false,\n      lastScroll: { maxX: 100, maxY: 150 }, // Different maxY\n    });\n\n    // Should call track because maxY changed\n    expect(trackSpy).toHaveBeenCalledWith(\n      '[Amplitude] Viewport Content Updated',\n      expect.objectContaining({\n        '[Amplitude] Element Exposed': [],\n      }),\n    );\n  });\n\n  test('should strip URL query parameters from Page URL property', () => {\n    const originalLocation = window.location;\n    const locationMock = {\n      ...originalLocation,\n      href: 'https://www.test.com/path?foo=bar&baz=qux',\n    } as unknown as Location;\n    Object.defineProperty(window, 'location', {\n      value: locationMock,\n      writable: true,\n      configurable: true,\n    });\n\n    const currentElementExposed = new Set<string>(['element-1']);\n    const elementExposedForPage = new Set<string>(['element-1']);\n\n    try {\n      fireViewportContentUpdated({\n        amplitude: mockAmplitude,\n        scrollTracker: mockScrollTracker,\n        currentElementExposed,\n        elementExposedForPage,\n        exposureTracker: undefined,\n        isPageEnd: false,\n        lastScroll: { maxX: undefined, maxY: undefined },\n      });\n\n      expect(trackSpy).toHaveBeenCalledWith(\n        '[Amplitude] Viewport Content Updated',\n        expect.objectContaining({\n          [constants.AMPLITUDE_EVENT_PROP_PAGE_URL]: 'https://www.test.com/path',\n        }),\n      );\n\n      const trackCall = trackSpy.mock.calls[0];\n      expect(trackCall[1][constants.AMPLITUDE_EVENT_PROP_PAGE_URL]).not.toContain('?');\n      expect(trackCall[1][constants.AMPLITUDE_EVENT_PROP_PAGE_URL]).not.toContain('foo=bar');\n    } finally {\n      Object.defineProperty(window, 'location', {\n        value: originalLocation,\n        writable: true,\n        configurable: true,\n      });\n    }\n  });\n\n  test('should decode URI-encoded characters in Page URL property', () => {\n    const originalLocation = window.location;\n    const locationMock = {\n      ...originalLocation,\n      href: 'https://www.topps.com/products/2025-bowman-chrome%C2%AE-baseball-mega-box?foo=bar',\n    } as unknown as Location;\n    Object.defineProperty(window, 'location', {\n      value: locationMock,\n      writable: true,\n      configurable: true,\n    });\n\n    const currentElementExposed = new Set<string>(['element-1']);\n    const elementExposedForPage = new Set<string>(['element-1']);\n\n    try {\n      fireViewportContentUpdated({\n        amplitude: mockAmplitude,\n        scrollTracker: mockScrollTracker,\n        currentElementExposed,\n        elementExposedForPage,\n        exposureTracker: undefined,\n        isPageEnd: false,\n        lastScroll: { maxX: undefined, maxY: undefined },\n      });\n\n      expect(trackSpy).toHaveBeenCalledWith(\n        '[Amplitude] Viewport Content Updated',\n        expect.objectContaining({\n          [constants.AMPLITUDE_EVENT_PROP_PAGE_URL]:\n            'https://www.topps.com/products/2025-bowman-chrome®-baseball-mega-box',\n        }),\n      );\n    } finally {\n      Object.defineProperty(window, 'location', {\n        value: originalLocation,\n        writable: true,\n        configurable: true,\n      });\n    }\n  });\n\n  test('should preserve Page URL when no query parameters are present', () => {\n    const originalLocation = window.location;\n    const locationMock = {\n      ...originalLocation,\n      href: 'https://www.test.com/path',\n    } as unknown as Location;\n    Object.defineProperty(window, 'location', {\n      value: locationMock,\n      writable: true,\n      configurable: true,\n    });\n\n    const currentElementExposed = new Set<string>(['element-1']);\n    const elementExposedForPage = new Set<string>(['element-1']);\n\n    try {\n      fireViewportContentUpdated({\n        amplitude: mockAmplitude,\n        scrollTracker: mockScrollTracker,\n        currentElementExposed,\n        elementExposedForPage,\n        exposureTracker: undefined,\n        isPageEnd: false,\n        lastScroll: { maxX: undefined, maxY: undefined },\n      });\n\n      expect(trackSpy).toHaveBeenCalledWith(\n        '[Amplitude] Viewport Content Updated',\n        expect.objectContaining({\n          [constants.AMPLITUDE_EVENT_PROP_PAGE_URL]: 'https://www.test.com/path',\n        }),\n      );\n    } finally {\n      Object.defineProperty(window, 'location', {\n        value: originalLocation,\n        writable: true,\n        configurable: true,\n      });\n    }\n  });\n\n  test('should track when lastScroll has undefined values', () => {\n    const currentElementExposed = new Set<string>();\n    const elementExposedForPage = new Set<string>();\n\n    fireViewportContentUpdated({\n      amplitude: mockAmplitude,\n      scrollTracker: mockScrollTracker,\n      currentElementExposed,\n      elementExposedForPage,\n      exposureTracker: undefined,\n      isPageEnd: false,\n      lastScroll: { maxX: undefined, maxY: undefined }, // First call, undefined values\n    });\n\n    // Should call track because undefined !== 100 and undefined !== 200\n    expect(trackSpy).toHaveBeenCalledWith(\n      '[Amplitude] Viewport Content Updated',\n      expect.objectContaining({\n        '[Amplitude] Element Exposed': [],\n      }),\n    );\n  });\n\n  test('should mutate lastScroll so consecutive calls deduplicate correctly', () => {\n    const currentElementExposed = new Set<string>();\n    const elementExposedForPage = new Set<string>();\n    const lastScroll: { maxX: undefined | number; maxY: undefined | number } = { maxX: undefined, maxY: undefined };\n\n    // First call: scroll changed from undefined -> 100/200, should track\n    fireViewportContentUpdated({\n      amplitude: mockAmplitude,\n      scrollTracker: mockScrollTracker,\n      currentElementExposed,\n      elementExposedForPage,\n      exposureTracker: undefined,\n      isPageEnd: false,\n      lastScroll,\n    });\n    expect(trackSpy).toHaveBeenCalledTimes(1);\n\n    // Verify lastScroll was mutated (not reassigned)\n    expect(lastScroll.maxX).toBe(100);\n    expect(lastScroll.maxY).toBe(200);\n\n    // Second call: same scroll position, no new elements — should be deduplicated\n    fireViewportContentUpdated({\n      amplitude: mockAmplitude,\n      scrollTracker: mockScrollTracker,\n      currentElementExposed,\n      elementExposedForPage,\n      exposureTracker: undefined,\n      isPageEnd: false,\n      lastScroll,\n    });\n    expect(trackSpy).toHaveBeenCalledTimes(1); // Still 1, deduplication worked\n  });\n});\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/test/constants.test.ts",
    "content": "import {\n  AMPLITUDE_ORIGIN,\n  AMPLITUDE_ORIGIN_EU,\n  AMPLITUDE_ORIGIN_STAGING,\n  AMPLITUDE_ORIGINS_MAP,\n  AMPLITUDE_BACKGROUND_CAPTURE_SCRIPT_URL,\n} from '../src/constants';\n\ndescribe('constants re-exports from analytics-core', () => {\n  test('should export AMPLITUDE_ORIGIN', () => {\n    expect(AMPLITUDE_ORIGIN).toBe('https://app.amplitude.com');\n  });\n\n  test('should export AMPLITUDE_ORIGIN_EU', () => {\n    expect(AMPLITUDE_ORIGIN_EU).toBe('https://app.eu.amplitude.com');\n  });\n\n  test('should export AMPLITUDE_ORIGIN_STAGING', () => {\n    expect(AMPLITUDE_ORIGIN_STAGING).toBe('https://apps.stag2.amplitude.com');\n  });\n\n  test('should export AMPLITUDE_ORIGINS_MAP with all zones', () => {\n    expect(AMPLITUDE_ORIGINS_MAP).toEqual({\n      US: 'https://app.amplitude.com',\n      EU: 'https://app.eu.amplitude.com',\n      STAGING: 'https://apps.stag2.amplitude.com',\n    });\n  });\n\n  test('should export AMPLITUDE_BACKGROUND_CAPTURE_SCRIPT_URL', () => {\n    expect(typeof AMPLITUDE_BACKGROUND_CAPTURE_SCRIPT_URL).toBe('string');\n    expect(AMPLITUDE_BACKGROUND_CAPTURE_SCRIPT_URL.length).toBeGreaterThan(0);\n  });\n});\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/test/data-extractor.test.ts",
    "content": "import { DataExtractor } from '../src/data-extractor';\nimport * as constants from '../src/constants';\nimport { mockWindowLocationFromURL } from './utils';\nimport type { ElementBasedTimestampedEvent } from '../src/helpers';\nimport { DATA_AMP_MASK_ATTRIBUTES } from '../src/constants';\nimport * as hierarchy from '../src/hierarchy';\nimport type { Hierarchy } from '../src/typings/autocapture';\nimport { MASKED_TEXT_VALUE } from '@amplitude/analytics-core';\n\ndescribe('data extractor', () => {\n  let dataExtractor: DataExtractor;\n\n  beforeEach(() => {\n    dataExtractor = new DataExtractor({ maskTextRegex: [/Florida|California/, /Pennsylvania/] });\n  });\n\n  describe('constructor - maskTextRegex pattern compilation', () => {\n    test('should compile valid pattern strings from pattern objects', () => {\n      const extractor = new DataExtractor({\n        maskTextRegex: [{ pattern: 'Texas|Nevada', description: 'US States' }],\n      });\n\n      const button = document.createElement('button');\n      button.textContent = 'Visit Texas today';\n      const result = extractor.getText(button);\n\n      expect(result).toEqual(`Visit ${MASKED_TEXT_VALUE} today`);\n    });\n\n    test('should ignore invalid regex pattern strings without throwing', () => {\n      // Invalid regex patterns with unclosed brackets, invalid escapes, etc.\n      expect(() => {\n        new DataExtractor({\n          maskTextRegex: [\n            { pattern: '[invalid(regex', description: 'Invalid pattern 1' },\n            { pattern: '(?:unclosed', description: 'Invalid pattern 2' },\n            { pattern: '\\\\k<invalid>', description: 'Invalid pattern 3' },\n          ],\n        });\n      }).not.toThrow();\n    });\n\n    test('should continue processing valid patterns after encountering invalid ones', () => {\n      const extractor = new DataExtractor({\n        maskTextRegex: [\n          { pattern: '[invalid(', description: 'Invalid' },\n          { pattern: 'Secret', description: 'Valid' },\n          /Confidential/,\n        ],\n      });\n\n      const button1 = document.createElement('button');\n      button1.textContent = 'Secret information';\n      const result1 = extractor.getText(button1);\n      expect(result1).toEqual(`${MASKED_TEXT_VALUE} information`);\n\n      const button2 = document.createElement('button');\n      button2.textContent = 'Confidential data';\n      const result2 = extractor.getText(button2);\n      expect(result2).toEqual(`${MASKED_TEXT_VALUE} data`);\n    });\n\n    test('should handle mixed RegExp and pattern objects', () => {\n      const extractor = new DataExtractor({\n        maskTextRegex: [/DirectRegex/, { pattern: 'PatternObject', description: 'Pattern as object' }],\n      });\n\n      const button1 = document.createElement('button');\n      button1.textContent = 'DirectRegex test';\n      expect(extractor.getText(button1)).toEqual(`${MASKED_TEXT_VALUE} test`);\n\n      const button2 = document.createElement('button');\n      button2.textContent = 'PatternObject test';\n      expect(extractor.getText(button2)).toEqual(`${MASKED_TEXT_VALUE} test`);\n    });\n\n    test('should compile patterns with case-insensitive flag', () => {\n      const extractor = new DataExtractor({\n        maskTextRegex: [{ pattern: 'sensitive', description: 'Case insensitive' }],\n      });\n\n      const button1 = document.createElement('button');\n      button1.textContent = 'SENSITIVE data';\n      expect(extractor.getText(button1)).toEqual(`${MASKED_TEXT_VALUE} data`);\n\n      const button2 = document.createElement('button');\n      button2.textContent = 'Sensitive data';\n      expect(extractor.getText(button2)).toEqual(`${MASKED_TEXT_VALUE} data`);\n\n      const button3 = document.createElement('button');\n      button3.textContent = 'sensitive data';\n      expect(extractor.getText(button3)).toEqual(`${MASKED_TEXT_VALUE} data`);\n    });\n\n    test('should respect MAX_MASK_TEXT_PATTERNS limit', () => {\n      const maxPatterns = constants.MAX_MASK_TEXT_PATTERNS;\n      const patterns = Array.from({ length: maxPatterns + 5 }, (_, i) => ({\n        pattern: `word${i}\\\\b`,\n        description: `Pattern ${i}`,\n      }));\n\n      const extractor = new DataExtractor({\n        maskTextRegex: patterns,\n      });\n\n      // The first maxPatterns should work\n      const button1 = document.createElement('button');\n      button1.textContent = `word${maxPatterns - 1} test`;\n      expect(extractor.getText(button1)).toEqual(`${MASKED_TEXT_VALUE} test`);\n\n      // Patterns beyond the limit should not be compiled\n      const button2 = document.createElement('button');\n      button2.textContent = `word${maxPatterns} test`;\n      expect(extractor.getText(button2)).toEqual(`word${maxPatterns} test`);\n    });\n  });\n\n  describe('getText', () => {\n    test('should return empty string when element is sensitive', () => {\n      const inputEl: HTMLInputElement = document.createElement('input');\n      inputEl.value = 'test';\n      const result = dataExtractor.getText(inputEl);\n      expect(result).toEqual('');\n    });\n\n    test('should return text when element has text attribute', () => {\n      const element = document.createElement('a');\n      (element as unknown as { text: string }).text = 'test';\n      const result = dataExtractor.getText(element);\n      expect(result).toEqual('test');\n    });\n\n    test('should return text when element has text node', () => {\n      const button = document.createElement('button');\n      const buttonText = document.createTextNode('submit');\n      button.appendChild(buttonText);\n      const result = dataExtractor.getText(button);\n      expect(result).toEqual('submit');\n    });\n\n    test('should return concatenated text when element has child text nodes', () => {\n      const button = document.createElement('button');\n      const buttonText = document.createTextNode('submit');\n      button.appendChild(buttonText);\n      const div = document.createElement('div');\n      div.innerText = ' and pay';\n      button.appendChild(div);\n      const result = dataExtractor.getText(button);\n      expect(result).toEqual('submit and pay');\n    });\n\n    test('should return concatenated text with sensitive text masked', () => {\n      const button = document.createElement('button');\n      const buttonText = document.createTextNode('submit');\n      button.appendChild(buttonText);\n      const div = document.createElement('div');\n      div.innerText = '269-28-9315';\n      button.appendChild(div);\n      const result = dataExtractor.getText(button);\n      expect(result).toEqual(`submit${MASKED_TEXT_VALUE}`);\n    });\n\n    test('should return concatenated text with extra space removed', () => {\n      const button = document.createElement('button');\n      const buttonText = document.createTextNode('submit');\n      button.appendChild(buttonText);\n      const div = document.createElement('div');\n      div.innerText = ' and   \\n pay';\n      button.appendChild(div);\n      const result = dataExtractor.getText(button);\n      expect(result).toEqual('submit and pay');\n    });\n\n    test('should return MASKED_TEXT_VALUE when element has data-amp-mask attribute', () => {\n      const button = document.createElement('button');\n      button.setAttribute('data-amp-mask', 'true');\n      button.innerText = 'sensitive button text';\n      const result = dataExtractor.getText(button);\n      expect(result).toEqual(MASKED_TEXT_VALUE);\n    });\n\n    test('should return MASKED_TEXT_VALUE when parent element has data-amp-mask attribute', () => {\n      const container = document.createElement('div');\n      container.setAttribute('data-amp-mask', 'true');\n      const button = document.createElement('button');\n      button.innerText = 'button text';\n      container.appendChild(button);\n      const result = dataExtractor.getText(button);\n      expect(result).toEqual(MASKED_TEXT_VALUE);\n    });\n\n    test('should return MASKED_TEXT_VALUE when ancestor element has data-amp-mask attribute', () => {\n      const grandparent = document.createElement('div');\n      grandparent.setAttribute('data-amp-mask', 'true');\n      const parent = document.createElement('div');\n      const button = document.createElement('button');\n      button.innerText = 'nested button text';\n      grandparent.appendChild(parent);\n      parent.appendChild(button);\n      const result = dataExtractor.getText(button);\n      expect(result).toEqual(MASKED_TEXT_VALUE);\n    });\n\n    test('should mask sensitive text content containing credit card numbers', () => {\n      const button = document.createElement('button');\n      const safeText = document.createTextNode('Pay with card ');\n      button.appendChild(safeText);\n      const sensitiveDiv = document.createElement('div');\n      sensitiveDiv.innerText = '4111111111111111'; // Credit card number\n      button.appendChild(sensitiveDiv);\n      const moreText = document.createTextNode(' securely');\n      button.appendChild(moreText);\n      const result = dataExtractor.getText(button);\n      expect(result).toEqual(`Pay with card ${MASKED_TEXT_VALUE} securely`);\n    });\n\n    test('should mask sensitive text content containing SSN', () => {\n      const button = document.createElement('button');\n      const safeText = document.createTextNode('Submit form ');\n      button.appendChild(safeText);\n      const sensitiveDiv = document.createElement('div');\n      sensitiveDiv.innerText = '269-28-9315'; // SSN\n      button.appendChild(sensitiveDiv);\n      const result = dataExtractor.getText(button);\n      expect(result).toEqual(`Submit form ${MASKED_TEXT_VALUE}`);\n    });\n\n    test('should mask sensitive text content containing email addresses', () => {\n      const button = document.createElement('button');\n      const safeText = document.createTextNode('Contact ');\n      button.appendChild(safeText);\n      const sensitiveDiv = document.createElement('div');\n      sensitiveDiv.innerText = 'user@example.com'; // Email\n      button.appendChild(sensitiveDiv);\n      const moreText = document.createTextNode(' for support');\n      button.appendChild(moreText);\n      const result = dataExtractor.getText(button);\n      expect(result).toEqual(`Contact ${MASKED_TEXT_VALUE} for support`);\n    });\n\n    test('should mask text matching custom maskTextRegex patterns', () => {\n      const button = document.createElement('button');\n      const safeText = document.createTextNode('Welcome to ');\n      button.appendChild(safeText);\n      const sensitiveDiv = document.createElement('div');\n      sensitiveDiv.innerText = 'Florida'; // Matches the regex pattern in beforeEach\n      button.appendChild(sensitiveDiv);\n      const moreText = document.createTextNode(' tourism');\n      button.appendChild(moreText);\n      const result = dataExtractor.getText(button);\n      expect(result).toEqual(`Welcome to ${MASKED_TEXT_VALUE} tourism`);\n    });\n\n    test('should handle mixed content with both masked attribute and sensitive text masking', () => {\n      const container = document.createElement('div');\n      const maskedDiv = document.createElement('div');\n      maskedDiv.setAttribute('data-amp-mask', 'true');\n      maskedDiv.innerText = 'This should be masked';\n\n      const normalDiv = document.createElement('div');\n      normalDiv.innerText = 'Normal text ';\n\n      const sensitiveDiv = document.createElement('div');\n      sensitiveDiv.innerText = '4111111111111111'; // This would be filtered by sensitive text logic\n\n      container.appendChild(normalDiv);\n      container.appendChild(maskedDiv);\n      container.appendChild(sensitiveDiv);\n\n      // Test the masked div individually\n      const maskedResult = dataExtractor.getText(maskedDiv);\n      expect(maskedResult).toEqual(MASKED_TEXT_VALUE);\n\n      // Test container with mixed content - masked elements return MASKED_TEXT_VALUE, sensitive text is also masked\n      const containerResult = dataExtractor.getText(container);\n      expect(containerResult).toEqual(`Normal text ${MASKED_TEXT_VALUE}${MASKED_TEXT_VALUE}`);\n    });\n\n    test('should mask nested content without cloning the element tree', () => {\n      const container = document.createElement('div');\n      const maskedChild = document.createElement('div');\n      maskedChild.setAttribute('data-amp-mask', 'true');\n      maskedChild.innerText = 'masked content';\n      container.appendChild(maskedChild);\n\n      const cloneNodeSpy = jest.spyOn(container, 'cloneNode');\n\n      const result = dataExtractor.getText(container);\n      expect(result).toEqual(MASKED_TEXT_VALUE);\n      expect(cloneNodeSpy).not.toHaveBeenCalled();\n\n      cloneNodeSpy.mockRestore();\n    });\n\n    test('should handle deeply nested masked and contenteditable branches without cloning', () => {\n      const container = document.createElement('div');\n      container.appendChild(document.createTextNode('Start '));\n\n      const section = document.createElement('section');\n      const maskedBranch = document.createElement('div');\n      maskedBranch.setAttribute('data-amp-mask', 'true');\n      maskedBranch.innerText = 'credit card 4111111111111111';\n      const nestedVideo = document.createElement('video');\n      nestedVideo.setAttribute('src', '/sample.mp4');\n      maskedBranch.appendChild(nestedVideo);\n\n      const visibleBranch = document.createElement('div');\n      visibleBranch.appendChild(document.createTextNode('middle '));\n      const editableBranch = document.createElement('div');\n      editableBranch.setAttribute('contenteditable', 'true');\n      editableBranch.innerText = 'editable text';\n      visibleBranch.appendChild(editableBranch);\n      visibleBranch.appendChild(document.createTextNode(' end'));\n\n      section.appendChild(maskedBranch);\n      section.appendChild(document.createTextNode(' '));\n      section.appendChild(visibleBranch);\n      container.appendChild(section);\n      container.appendChild(document.createTextNode(' California'));\n\n      const cloneNodeSpy = jest.spyOn(container, 'cloneNode');\n\n      const result = dataExtractor.getText(container);\n      expect(result).toEqual(`Start ${MASKED_TEXT_VALUE} middle ${MASKED_TEXT_VALUE} end ${MASKED_TEXT_VALUE}`);\n      expect(cloneNodeSpy).not.toHaveBeenCalled();\n\n      cloneNodeSpy.mockRestore();\n    });\n\n    test('should use innerText in recursive fast path for unmasked descendants', () => {\n      const container = document.createElement('div');\n      const maskedChild = document.createElement('div');\n      maskedChild.setAttribute('data-amp-mask', 'true');\n      maskedChild.innerText = 'secret';\n\n      const plainChild = document.createElement('div');\n      const plainGrandchild = document.createElement('span');\n      plainGrandchild.innerText = 'Visible text';\n      plainChild.appendChild(plainGrandchild);\n\n      container.appendChild(maskedChild);\n      container.appendChild(plainChild);\n\n      const result = dataExtractor.getText(container);\n      expect(result).toEqual(`${MASKED_TEXT_VALUE}Visible text`);\n    });\n\n    test('should ignore non-element non-text nodes while traversing masked descendants', () => {\n      const container = document.createElement('div');\n      container.appendChild(document.createTextNode('Start '));\n      container.appendChild(document.createComment('ignore me'));\n\n      const maskedChild = document.createElement('div');\n      maskedChild.setAttribute('data-amp-mask', 'true');\n      maskedChild.innerText = 'secret';\n      container.appendChild(maskedChild);\n\n      container.appendChild(document.createTextNode(' End'));\n\n      const result = dataExtractor.getText(container);\n      expect(result).toEqual(`Start ${MASKED_TEXT_VALUE} End`);\n    });\n\n    test('should handle null textContent for text nodes while traversing masked descendants', () => {\n      const container = document.createElement('div');\n      const textNode = document.createTextNode('transient text');\n      container.appendChild(textNode);\n\n      // Ensure getText() enters getTextWithMaskedDescendants branch\n      const maskedChild = document.createElement('div');\n      maskedChild.setAttribute('data-amp-mask', 'true');\n      maskedChild.innerText = 'secret';\n      container.appendChild(maskedChild);\n\n      const textContentSpy = jest.spyOn(textNode, 'textContent', 'get').mockReturnValue(null as unknown as string);\n\n      const result = dataExtractor.getText(container);\n\n      // Null textContent should contribute '' and not crash\n      expect(result).toEqual(MASKED_TEXT_VALUE);\n\n      textContentSpy.mockRestore();\n    });\n  });\n\n  describe('getNearestLabel', () => {\n    test('should return nearest label of the element', () => {\n      const div = document.createElement('div');\n      const span = document.createElement('span');\n      span.innerText = 'nearest label';\n      const input = document.createElement('input');\n      div.appendChild(span);\n      div.appendChild(input);\n\n      const result = dataExtractor.getNearestLabel(input);\n      expect(result).toEqual('nearest label');\n    });\n\n    test('should return masked nearest label when content is sensitive', () => {\n      const div = document.createElement('div');\n      const span = document.createElement('span');\n      span.innerText = '4916024123820164';\n      const input = document.createElement('input');\n      div.appendChild(span);\n      div.appendChild(input);\n\n      const result = dataExtractor.getNearestLabel(input);\n      expect(result).toEqual(MASKED_TEXT_VALUE);\n    });\n\n    test('should return nearest label of the element parent', () => {\n      const div = document.createElement('div');\n      const innerDiv = document.createElement('div');\n      div.appendChild(innerDiv);\n      const span = document.createElement('span');\n      span.innerText = 'parent label';\n      div.appendChild(span);\n      const input = document.createElement('input');\n      innerDiv.appendChild(input);\n\n      const result = dataExtractor.getNearestLabel(input);\n      expect(result).toEqual('parent label');\n    });\n\n    test('should return empty string when there is no parent', () => {\n      const input = document.createElement('input');\n\n      const result = dataExtractor.getNearestLabel(input);\n      expect(result).toEqual('');\n    });\n  });\n\n  describe('getElementPath', () => {\n    test('should return empty string when element is null', () => {\n      const result = dataExtractor.getElementPath(null);\n      expect(result).toEqual('');\n    });\n\n    test('should return CSS path when element is valid', () => {\n      document.getElementsByTagName('body')[0].innerHTML = `\n        <div id=\"container\">\n          <button id=\"test-button\">Click me</button>\n        </div>\n      `;\n\n      const button = document.getElementById('test-button');\n      const result = dataExtractor.getElementPath(button);\n\n      expect(result).toEqual('button#test-button');\n    });\n  });\n\n  describe('getEventTagProps', () => {\n    beforeAll(() => {\n      Object.defineProperty(window, 'location', {\n        value: {\n          hostname: '',\n          href: '',\n          pathname: '',\n          search: '',\n        },\n        writable: true,\n      });\n    });\n\n    beforeEach(() => {\n      mockWindowLocationFromURL(new URL('https://www.amplitude.com/unit-test?query=getEventTagProps'));\n    });\n\n    test('should return the tag properties', () => {\n      document.getElementsByTagName('body')[0].innerHTML = `\n        <div id=\"container\">\n          <div id=\"inner\">\n            xxx\n          </div>\n        </div>\n      `;\n\n      const inner = document.getElementById('inner');\n      expect(dataExtractor.getEventTagProps(inner as HTMLElement)).toEqual({\n        '[Amplitude] Element Tag': 'div',\n        '[Amplitude] Element Text': 'xxx',\n        '[Amplitude] Page URL': 'https://www.amplitude.com/unit-test',\n      });\n    });\n\n    test('should return empty object when element is not present', () => {\n      expect(dataExtractor.getEventTagProps(null as unknown as HTMLElement)).toEqual({});\n    });\n\n    test('should not use the visual highlight class when retrieving selector', () => {\n      document.getElementsByTagName('body')[0].innerHTML = `\n        <div id=\"container\">\n          <div class=\"amp-visual-tagging-selector-highlight\">\n            xxx\n          </div>\n        </div>\n      `;\n\n      const inner = document.getElementsByClassName('amp-visual-tagging-selector-highlight')[0];\n      expect(dataExtractor.getEventTagProps(inner as HTMLElement)).toEqual({\n        '[Amplitude] Element Tag': 'div',\n        '[Amplitude] Element Text': 'xxx',\n        '[Amplitude] Page URL': 'https://www.amplitude.com/unit-test',\n      });\n    });\n  });\n\n  describe('addAdditionalEventProperties', () => {\n    beforeEach(() => {\n      // Mock window.location\n      mockWindowLocationFromURL(new URL('https://test.com'));\n      // Mock document.title\n      Object.defineProperty(document, 'title', {\n        value: 'Test Page',\n        writable: true,\n      });\n      // Mock window.innerHeight and innerWidth\n      Object.defineProperty(window, 'innerHeight', { value: 800 });\n      Object.defineProperty(window, 'innerWidth', { value: 1200 });\n    });\n\n    test('should add properties when isCapturingCursorPointer is true and element has pointer cursor', () => {\n      // Create a button element with pointer cursor\n      const span = document.createElement('span');\n      span.style.cursor = 'pointer';\n      span.innerText = 'Click me';\n      document.body.appendChild(span);\n\n      // Create a click event\n      const clickEvent = {\n        bubbles: true,\n        cancelable: true,\n        view: window,\n        target: span,\n      };\n\n      // Call the function with isCapturingCursorPointer set to true\n      const result = dataExtractor.addAdditionalEventProperties(\n        clickEvent,\n        'click',\n        ['.button'], // selector allowlist\n        'data-amp-', // data attribute prefix\n        true, // isCapturingCursorPointer\n      ) as ElementBasedTimestampedEvent<MouseEvent>;\n\n      // Verify the result\n      expect(result.closestTrackedAncestor).toBeDefined();\n    });\n  });\n\n  describe('getEventProperties with maskion', () => {\n    test('should NOT mask id or class when both specified on parent', () => {\n      const container = document.createElement('div');\n      container.setAttribute(DATA_AMP_MASK_ATTRIBUTES, 'id, class');\n\n      const element = document.createElement('button');\n      element.setAttribute('id', 'secret-id');\n      element.setAttribute('class', 'secret-class');\n      element.textContent = 'Click me';\n\n      container.appendChild(element);\n      document.body.appendChild(container);\n\n      const result = dataExtractor.getEventProperties('click', element, 'data-amp-track-');\n\n      expect(result['[Amplitude] Element ID']).toBe('secret-id'); // ID should NOT be masked\n      expect(result['[Amplitude] Element Class']).toBe('secret-class'); // Class should NOT be masked\n      expect(result['[Amplitude] Element Tag']).toBe('button');\n      expect(result['[Amplitude] Element Text']).toBe('Click me');\n\n      document.body.removeChild(container);\n    });\n\n    test('should mask attributes when mask rule is on element itself but never mask id or class', () => {\n      const element = document.createElement('button');\n      element.setAttribute('id', 'test-id');\n      element.setAttribute('class', 'test-class');\n      element.setAttribute('aria-label', 'Test button');\n      element.setAttribute(DATA_AMP_MASK_ATTRIBUTES, 'id, class, aria-label'); // On element itself\n      element.textContent = 'Click me';\n\n      document.body.appendChild(element);\n\n      const result = dataExtractor.getEventProperties('click', element, 'data-amp-track-');\n\n      expect(result['[Amplitude] Element ID']).toBe('test-id'); // ID should NEVER be masked\n      expect(result['[Amplitude] Element Class']).toBe('test-class'); // Class should NEVER be masked\n      expect(result['[Amplitude] Element Aria Label']).toBe(MASKED_TEXT_VALUE);\n\n      document.body.removeChild(element);\n    });\n\n    test('should mask aria-label when specified on parent', () => {\n      const container = document.createElement('div');\n      container.setAttribute(DATA_AMP_MASK_ATTRIBUTES, 'aria-label');\n\n      const element = document.createElement('button');\n      element.setAttribute('aria-label', 'Secret button label');\n      element.textContent = 'Click me';\n\n      container.appendChild(element);\n      document.body.appendChild(container);\n\n      const result = dataExtractor.getEventProperties('click', element, 'data-amp-track-');\n\n      expect(result['[Amplitude] Element Aria Label']).toBe(MASKED_TEXT_VALUE);\n      expect(result['[Amplitude] Element Text']).toBe('Click me');\n\n      document.body.removeChild(container);\n    });\n\n    test('should not mask href for anchor elements when specified on parent', () => {\n      const container = document.createElement('div');\n      container.setAttribute(DATA_AMP_MASK_ATTRIBUTES, 'href');\n\n      const element = document.createElement('a');\n      element.setAttribute('href', 'https://secret-url.com');\n      element.textContent = 'Secret link';\n\n      container.appendChild(element);\n      document.body.appendChild(container);\n\n      const result = dataExtractor.getEventProperties('click', element, 'data-amp-track-');\n\n      expect(result['[Amplitude] Element Href']).toBe('https://secret-url.com/');\n      expect(result['[Amplitude] Element Text']).toBe('Secret link');\n\n      document.body.removeChild(container);\n    });\n\n    test('should truncate href when it exceeds MAX_ATTRIBUTE_LENGTH', () => {\n      const container = document.createElement('div');\n\n      const element = document.createElement('a');\n      // Create a very large href value (simulating a data URI or long URL)\n      const largeHref = 'data:image/png;base64,' + 'A'.repeat(5000);\n      element.setAttribute('href', largeHref);\n      element.textContent = 'Large data link';\n\n      container.appendChild(element);\n      document.body.appendChild(container);\n\n      const result = dataExtractor.getEventProperties('click', element, 'data-amp-track-');\n\n      const hrefValue = result[constants.AMPLITUDE_EVENT_PROP_ELEMENT_HREF];\n      expect((hrefValue as string).length).toBe(constants.MAX_ATTRIBUTE_LENGTH);\n      expect(largeHref.startsWith(hrefValue as string)).toBe(true);\n\n      document.body.removeChild(container);\n    });\n\n    test('should not mask attributes when not specified in maskion list', () => {\n      const container = document.createElement('div');\n      container.setAttribute(DATA_AMP_MASK_ATTRIBUTES, 'other-attr');\n\n      const element = document.createElement('button');\n      element.setAttribute('id', 'test-id');\n      element.setAttribute('class', 'test-class');\n      element.setAttribute('aria-label', 'Test button');\n      element.textContent = 'Click me';\n\n      container.appendChild(element);\n      document.body.appendChild(container);\n\n      const result = dataExtractor.getEventProperties('click', element, 'data-amp-track-');\n\n      expect(result['[Amplitude] Element ID']).toBe('test-id');\n      expect(result['[Amplitude] Element Class']).toBe('test-class');\n      expect(result['[Amplitude] Element Aria Label']).toBe('Test button');\n\n      document.body.removeChild(container);\n    });\n\n    test('should mask data attributes when specified on parent', () => {\n      const container = document.createElement('div');\n      container.setAttribute(DATA_AMP_MASK_ATTRIBUTES, 'data-amp-track-user-name');\n\n      const element = document.createElement('span');\n      element.setAttribute('data-amp-track-user-id', '12345');\n      element.setAttribute('data-amp-track-user-name', 'John Doe');\n      element.textContent = 'User info';\n\n      container.appendChild(element);\n      document.body.appendChild(container);\n\n      const result = dataExtractor.getEventProperties('click', element, 'data-amp-track-');\n\n      expect(result['[Amplitude] Element Attributes']).toEqual({ 'user-id': '12345', 'user-name': MASKED_TEXT_VALUE });\n\n      document.body.removeChild(container);\n    });\n\n    test('should never mask id or class attributes even when explicitly specified', () => {\n      const container = document.createElement('div');\n      container.setAttribute(DATA_AMP_MASK_ATTRIBUTES, 'id, class, aria-label');\n\n      const element = document.createElement('button');\n      element.setAttribute('id', 'important-id');\n      element.setAttribute('class', 'secret-class');\n      element.setAttribute('aria-label', 'Secret label');\n      element.textContent = 'Click me';\n\n      container.appendChild(element);\n      document.body.appendChild(container);\n\n      const result = dataExtractor.getEventProperties('click', element, 'data-amp-track-');\n\n      expect(result['[Amplitude] Element ID']).toBe('important-id'); // ID should NEVER be masked\n      expect(result['[Amplitude] Element Class']).toBe('secret-class'); // Class should NEVER be masked\n      expect(result['[Amplitude] Element Aria Label']).toBe(MASKED_TEXT_VALUE); // Aria-label should be masked\n\n      document.body.removeChild(container);\n    });\n  });\n\n  describe('getHierarchy', () => {\n    test('should return a list starting from the target element', () => {\n      document.getElementsByTagName('body')[0].innerHTML = `\n        <div id=\"parent2\">\n          <div id=\"parent1\">\n            <div id=\"inner\">\n              xxx\n            </div>\n            <div id=\"inner2\">\n              xxx\n            </div>\n          </div>\n        </div>\n      `;\n\n      const inner2 = document.getElementById('inner2');\n\n      expect(dataExtractor.getHierarchy(inner2)).toEqual([\n        {\n          id: 'inner2',\n          index: 1,\n          indexOfType: 1,\n          prevSib: 'div',\n          tag: 'div',\n        },\n        {\n          id: 'parent1',\n          index: 0,\n          indexOfType: 0,\n          tag: 'div',\n        },\n        {\n          id: 'parent2',\n          index: 0,\n          indexOfType: 0,\n          tag: 'div',\n        },\n        {\n          index: 1,\n          indexOfType: 0,\n          prevSib: 'head',\n          tag: 'body',\n        },\n      ]);\n    });\n\n    test('should not fail when element is null', () => {\n      const nullElement = null;\n      expect(dataExtractor.getHierarchy(nullElement)).toEqual([]);\n    });\n\n    test('should handle null elements in hierarchy when getElementProperties returns null', () => {\n      // Create a valid element\n      const element = document.createElement('div');\n      element.id = 'test-element';\n      document.body.appendChild(element);\n\n      // Mock getAncestors to return an array with a null element\n      const getAncestorsSpy = jest\n        .spyOn(hierarchy, 'getAncestors')\n        .mockReturnValue([element, null as unknown as Element]);\n\n      // getHierarchy should include null results from getElementProperties\n      const hierarchyResult = dataExtractor.getHierarchy(element);\n\n      // Verify that the first element is properly formed and the second is null\n      expect(hierarchyResult).toHaveLength(2);\n      expect(hierarchyResult[0]).toHaveProperty('id', 'test-element');\n      expect(hierarchyResult[0]).toHaveProperty('tag', 'div');\n      expect(hierarchyResult[0]).toHaveProperty('index');\n      expect(hierarchyResult[0]).toHaveProperty('indexOfType');\n      expect(hierarchyResult[1]).toBeNull();\n\n      // Restore original function\n      getAncestorsSpy.mockRestore();\n      document.body.removeChild(element);\n    });\n\n    test('should handle currentElementAttributes when hierarchy[0] is null or undefined', () => {\n      // Create a test element\n      const element = document.createElement('div');\n      element.id = 'test-element';\n      element.setAttribute('data-test', 'value');\n      document.body.appendChild(element);\n\n      // Mock getHierarchy to return an array with null/undefined at index 0\n      const originalGetHierarchy = dataExtractor.getHierarchy;\n      jest.spyOn(dataExtractor, 'getHierarchy').mockReturnValue([null, undefined] as Hierarchy);\n\n      // Call getEventProperties which uses hierarchy[0]?.attrs on line 145\n      const result = dataExtractor.getEventProperties('click', element, 'data-');\n\n      // Verify that currentElementAttributes is undefined when hierarchy[0] is null\n      // This should not cause an error due to the optional chaining (?.) and nullish coalescing (??)\n      expect(result).toBeDefined();\n\n      // The ELEMENT_ATTRIBUTES property should be undefined because removeEmptyProperties\n      // removes empty objects, and extractPrefixedAttributes({}, 'data-') returns {}\n      expect(result[constants.AMPLITUDE_EVENT_PROP_ELEMENT_ATTRIBUTES]).toBeUndefined();\n      expect(result[constants.AMPLITUDE_EVENT_PROP_ELEMENT_HIERARCHY]).toEqual([null, undefined]);\n\n      // Verify that the method handles the null/undefined hierarchy gracefully\n      expect(result[constants.AMPLITUDE_EVENT_PROP_ELEMENT_TAG]).toBe('div');\n      expect(result[constants.AMPLITUDE_EVENT_PROP_ELEMENT_ID]).toBe('test-element');\n\n      // The aria-label should also be undefined since currentElementAttributes is undefined\n      expect(result[constants.AMPLITUDE_EVENT_PROP_ELEMENT_ARIA_LABEL]).toBeUndefined();\n\n      // Restore original method and clean up\n      dataExtractor.getHierarchy = originalGetHierarchy;\n      document.body.removeChild(element);\n    });\n\n    describe('[Amplitude] Element Hierarchy property:', () => {\n      test('should cut off hierarchy output nodes to stay less than or equal to 1024 chars', () => {\n        document.getElementsByTagName('body')[0].innerHTML = `\n        <div id=\"parent2\">\n          <div id=\"parent1\"\n            long-attribute=\"${'a'.repeat(2000)}end\"\n            long-attribute2=\"${'a'.repeat(128)}\"\n            long-attribute3=\"${'a'.repeat(128)}\"\n            long-attribute4=\"${'a'.repeat(128)}\"\n            long-attribute5=\"${'a'.repeat(128)}\"\n            attribute6=\"${'a'.repeat(8)}\"\n          >\n            <div id=\"inner12345\">\n              xxx\n            </div>\n          </div>\n        </div>\n      `;\n\n        const inner12345 = document.getElementById('inner12345');\n        const innerHierarchy = dataExtractor.getHierarchy(inner12345);\n        // expect innerHierarchy to not have body to stay under 1024 chars\n        expect(innerHierarchy).toEqual([\n          {\n            id: 'inner12345',\n            index: 0,\n            indexOfType: 0,\n            tag: 'div',\n          },\n          {\n            id: 'parent1',\n            index: 0,\n            indexOfType: 0,\n            tag: 'div',\n            attrs: {\n              'long-attribute': 'a'.repeat(128),\n              'long-attribute2': 'a'.repeat(128),\n              'long-attribute3': 'a'.repeat(128),\n              'long-attribute4': 'a'.repeat(128),\n              'long-attribute5': 'a'.repeat(128),\n              attribute6: 'a'.repeat(8),\n            },\n          },\n          {\n            id: 'parent2',\n            index: 0,\n            indexOfType: 0,\n            tag: 'div',\n          },\n          {\n            index: 1,\n            indexOfType: 0,\n            prevSib: 'head',\n            tag: 'body',\n          },\n        ]);\n        const resultLength = JSON.stringify(innerHierarchy).length;\n        expect(resultLength).toBeLessThanOrEqual(1024);\n        expect(resultLength).toEqual(1005);\n      });\n    });\n\n    describe('attribute maskion', () => {\n      test(`should mask attributes specified in ${DATA_AMP_MASK_ATTRIBUTES} on target element`, () => {\n        document.getElementsByTagName('body')[0].innerHTML = `\n          <div id=\"parent\">\n            <div id=\"target\" ${DATA_AMP_MASK_ATTRIBUTES}=\"custom-attr,secret-data\" custom-attr=\"should-be-masked\" secret-data=\"hidden\" visible-attr=\"should-remain\">\n              content\n            </div>\n          </div>\n        `;\n\n        const target = document.getElementById('target');\n        const hierarchy = dataExtractor.getHierarchy(target);\n\n        expect(hierarchy[0]).toEqual({\n          id: 'target',\n          index: 0,\n          indexOfType: 0,\n          tag: 'div',\n          attrs: {\n            'visible-attr': 'should-remain',\n            'custom-attr': MASKED_TEXT_VALUE,\n            'secret-data': MASKED_TEXT_VALUE,\n          },\n        });\n      });\n\n      test(`should mask attributes from child elements when specified in parent ${DATA_AMP_MASK_ATTRIBUTES}`, () => {\n        document.getElementsByTagName('body')[0].innerHTML = `\n          <div id=\"parent\" ${DATA_AMP_MASK_ATTRIBUTES}=\"sensitive-attr\">\n            <div id=\"target\" sensitive-attr=\"should-be-masked\" normal-attr=\"should-remain\">\n              content\n            </div>\n          </div>\n        `;\n\n        const target = document.getElementById('target');\n        const hierarchy = dataExtractor.getHierarchy(target);\n\n        // Target element should have sensitive-attr masked\n        expect(hierarchy[0]).toEqual({\n          id: 'target',\n          index: 0,\n          indexOfType: 0,\n          tag: 'div',\n          attrs: {\n            'normal-attr': 'should-remain',\n            'sensitive-attr': MASKED_TEXT_VALUE,\n          },\n        });\n\n        // Parent element should keep DATA_AMP_MASK_ATTRIBUTES\n        expect(hierarchy[1]).toEqual({\n          id: 'parent',\n          index: 0,\n          indexOfType: 0,\n          tag: 'div',\n        });\n      });\n\n      test(`should accumulate masked attributes from multiple ancestors`, () => {\n        document.getElementsByTagName('body')[0].innerHTML = `\n          <div id=\"grandparent\" ${DATA_AMP_MASK_ATTRIBUTES}=\"attr1,attr2\">\n            <div id=\"parent\" ${DATA_AMP_MASK_ATTRIBUTES}=\"attr3\">\n              <div id=\"target\" attr1=\"mask1\" attr2=\"mask2\" attr3=\"mask3\" normal-attr=\"keep\">\n                content\n              </div>\n            </div>\n          </div>\n        `;\n\n        const target = document.getElementById('target');\n        const hierarchy = dataExtractor.getHierarchy(target);\n\n        // Target should have all specified attributes masked\n        expect(hierarchy[0]).toEqual({\n          id: 'target',\n          index: 0,\n          indexOfType: 0,\n          tag: 'div',\n          attrs: {\n            attr1: MASKED_TEXT_VALUE,\n            attr2: MASKED_TEXT_VALUE,\n            attr3: MASKED_TEXT_VALUE,\n            'normal-attr': 'keep',\n          },\n        });\n      });\n\n      test(`should not mask id and class attributes even if specified in ${DATA_AMP_MASK_ATTRIBUTES}`, () => {\n        document.getElementsByTagName('body')[0].innerHTML = `\n          <div id=\"parent\" ${DATA_AMP_MASK_ATTRIBUTES}=\"id,class,custom-attr\">\n            <div id=\"target\" class=\"test-class\" custom-attr=\"should-be-masked\">\n              content\n            </div>\n          </div>\n        `;\n\n        const target = document.getElementById('target');\n        const hierarchy = dataExtractor.getHierarchy(target);\n\n        // Target should keep id and class but mask custom-attr\n        expect(hierarchy[0]).toEqual({\n          id: 'target',\n          index: 0,\n          indexOfType: 0,\n          tag: 'div',\n          classes: ['test-class'],\n          attrs: {\n            'custom-attr': MASKED_TEXT_VALUE,\n          },\n        });\n      });\n\n      test(`should handle empty ${DATA_AMP_MASK_ATTRIBUTES} gracefully`, () => {\n        document.getElementsByTagName('body')[0].innerHTML = `\n          <div id=\"parent\" ${DATA_AMP_MASK_ATTRIBUTES}=\"\">\n            <div id=\"target\" custom-attr=\"should-remain\">\n              content\n            </div>\n          </div>\n        `;\n\n        const target = document.getElementById('target');\n        const hierarchy = dataExtractor.getHierarchy(target);\n\n        expect(hierarchy[0]).toEqual({\n          id: 'target',\n          index: 0,\n          indexOfType: 0,\n          tag: 'div',\n          attrs: {\n            'custom-attr': 'should-remain',\n          },\n        });\n      });\n\n      test(`should handle whitespace and malformed attribute lists in ${DATA_AMP_MASK_ATTRIBUTES}`, () => {\n        document.getElementsByTagName('body')[0].innerHTML = `\n          <div id=\"parent\" ${DATA_AMP_MASK_ATTRIBUTES}=\" attr1 , , attr2 , \">\n            <div id=\"target\" attr1=\"mask1\" attr2=\"mask2\" attr3=\"keep\">\n              content\n            </div>\n          </div>\n        `;\n\n        const target = document.getElementById('target');\n        const hierarchy = dataExtractor.getHierarchy(target);\n\n        expect(hierarchy[0]).toEqual({\n          id: 'target',\n          index: 0,\n          indexOfType: 0,\n          tag: 'div',\n          attrs: {\n            attr1: MASKED_TEXT_VALUE,\n            attr2: MASKED_TEXT_VALUE,\n            attr3: 'keep',\n          },\n        });\n      });\n    });\n\n    test('should record histogram with diagnostics client when provided', () => {\n      const mockDiagnosticsClient = {\n        recordHistogram: jest.fn(),\n        setTag: jest.fn(),\n        increment: jest.fn(),\n        recordEvent: jest.fn(),\n        _flush: jest.fn(),\n        _setSampleRate: jest.fn(),\n      };\n\n      // Create a new data extractor with diagnostics client\n      const dataExtractorWithDiagnostics = new DataExtractor(\n        {\n          maskTextRegex: [/Florida|California/, /Pennsylvania/],\n        },\n        {\n          diagnosticsClient: mockDiagnosticsClient,\n        },\n      );\n\n      // Set up DOM\n      document.getElementsByTagName('body')[0].innerHTML = `\n        <div id=\"parent\">\n          <div id=\"child\">\n            <button id=\"target\">Click me</button>\n          </div>\n        </div>\n      `;\n\n      const target = document.getElementById('target');\n      dataExtractorWithDiagnostics.getHierarchy(target);\n\n      // Verify that recordHistogram was called with the correct metric name\n      expect(mockDiagnosticsClient.recordHistogram).toHaveBeenCalledWith(\n        'autocapturePlugin.getHierarchy',\n        expect.any(Number),\n      );\n\n      dataExtractorWithDiagnostics.getElementPath(target);\n\n      expect(mockDiagnosticsClient.recordHistogram).toHaveBeenCalledWith(\n        'autocapturePlugin.getElementPath',\n        expect.any(Number),\n      );\n\n      // Verify that the recorded value is a positive number (execution time)\n      // eslint-disable-next-line\n      const recordedValue = mockDiagnosticsClient.recordHistogram.mock.calls[0][1];\n      expect(recordedValue).toBeGreaterThanOrEqual(0);\n    });\n\n    test('should not call diagnostics client when not provided', () => {\n      // Create a new data extractor without diagnostics client\n      const dataExtractorWithoutDiagnostics = new DataExtractor({\n        maskTextRegex: [/Florida|California/, /Pennsylvania/],\n      });\n      // Ensure diagnosticsClient is undefined\n      expect(dataExtractor.diagnosticsClient).toBeUndefined();\n\n      // Set up DOM\n      document.getElementsByTagName('body')[0].innerHTML = `\n        <div id=\"parent\">\n          <div id=\"child\">\n            <button id=\"target\">Click me</button>\n          </div>\n        </div>\n      `;\n\n      const target = document.getElementById('target');\n\n      // This should not throw an error even when diagnosticsClient is undefined\n      expect(() => {\n        dataExtractorWithoutDiagnostics.getHierarchy(target);\n      }).not.toThrow();\n    });\n  });\n\n  describe('getEventProperties with title masking', () => {\n    beforeEach(() => {\n      // Mock window.location\n      mockWindowLocationFromURL(new URL('https://test.com'));\n      // Mock document.title\n      Object.defineProperty(document, 'title', {\n        value: 'Test Page Title',\n        writable: true,\n      });\n      // Mock window.innerHeight and innerWidth\n      Object.defineProperty(window, 'innerHeight', { value: 800 });\n      Object.defineProperty(window, 'innerWidth', { value: 1200 });\n    });\n\n    afterEach(() => {\n      // Clean up any title elements added during tests\n      const titleElements = document.querySelectorAll('title');\n      titleElements.forEach((el) => el.remove());\n    });\n\n    test('should include masked page title when title element has data-amp-mask', () => {\n      // Create and add title element with data-amp-mask\n      const titleElement = document.createElement('title');\n      titleElement.setAttribute('data-amp-mask', 'true');\n      titleElement.textContent = 'Sensitive Page Title';\n      document.head.appendChild(titleElement);\n\n      const element = document.createElement('button');\n      element.textContent = 'Click me';\n      document.body.appendChild(element);\n\n      const result = dataExtractor.getEventProperties('click', element, 'data-amp-track-');\n\n      expect(result[constants.AMPLITUDE_EVENT_PROP_PAGE_TITLE]).toBe(MASKED_TEXT_VALUE);\n\n      document.body.removeChild(element);\n    });\n\n    test('should include normal page title when title element does not have data-amp-mask', () => {\n      const element = document.createElement('button');\n      element.textContent = 'Click me';\n      document.body.appendChild(element);\n\n      const result = dataExtractor.getEventProperties('click', element, 'data-amp-track-');\n\n      expect(result[constants.AMPLITUDE_EVENT_PROP_PAGE_TITLE]).toBe('Test Page Title');\n\n      document.body.removeChild(element);\n    });\n  });\n\n  describe('getEventProperties with page URL', () => {\n    test('should escape special characters in page URL', () => {\n      mockWindowLocationFromURL(new URL('https://www.topps.com/products/2025-bowman-chrome%C2%AE-baseball-mega-box'));\n      const element = document.createElement('button');\n      element.textContent = 'Click me';\n      document.body.appendChild(element);\n\n      const result = dataExtractor.getEventProperties('click', element, 'data-amp-track-');\n\n      expect(result[constants.AMPLITUDE_EVENT_PROP_PAGE_URL]).toBe(\n        'https://www.topps.com/products/2025-bowman-chrome®-baseball-mega-box',\n      );\n\n      document.body.removeChild(element);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/test/default-event-tracking-advanced.test.ts",
    "content": "import { autocapturePlugin } from '../src/autocapture-plugin';\n\nimport * as AnalyticsCore from '@amplitude/analytics-core';\nimport { BrowserConfig, EnrichmentPlugin, ILogger, BrowserClient, IDiagnosticsClient } from '@amplitude/analytics-core';\nimport { mockWindowLocationFromURL } from './utils';\nimport { VERSION } from '../src/version';\nimport { createMockBrowserClient } from './mock-browser-client';\n\nconst TESTING_DEBOUNCE_TIME = 4;\n\ndescribe('autoTrackingPlugin', () => {\n  let plugin: EnrichmentPlugin | undefined;\n\n  beforeAll(() => {\n    Object.defineProperty(window, 'location', {\n      value: {\n        hostname: '',\n        href: '',\n        pathname: '',\n        search: '',\n      },\n      writable: true,\n    });\n  });\n\n  beforeEach(() => {\n    jest.useFakeTimers();\n    (window.location as any) = {\n      hostname: '',\n      href: '',\n      pathname: '',\n      search: '',\n    };\n    plugin = autocapturePlugin({ debounceTime: TESTING_DEBOUNCE_TIME });\n  });\n\n  afterEach(() => {\n    void plugin?.teardown?.();\n    document.getElementsByTagName('body')[0].innerHTML = '';\n    jest.clearAllMocks();\n    jest.useRealTimers();\n  });\n\n  describe('name', () => {\n    test('should return the plugin name', () => {\n      expect(plugin?.name).toBe('@amplitude/plugin-autocapture-browser');\n    });\n  });\n\n  describe('type', () => {\n    test('should return the plugin type', () => {\n      expect(plugin?.type).toBe('enrichment');\n    });\n  });\n\n  describe('version', () => {\n    test('should return the plugin version', () => {\n      expect(VERSION != null).toBe(true);\n    });\n  });\n\n  describe('diagnostics', () => {\n    test('should set plugin version tag when diagnostics client is provided', () => {\n      const mockDiagnosticsClient = {\n        setTag: jest.fn(),\n        increment: jest.fn(),\n        recordEvent: jest.fn(),\n        recordHistogram: jest.fn(),\n        _flush: jest.fn(),\n        _setSampleRate: jest.fn(),\n      };\n\n      autocapturePlugin({}, { diagnosticsClient: mockDiagnosticsClient as IDiagnosticsClient });\n\n      expect(mockDiagnosticsClient.setTag).toHaveBeenCalledWith('plugin.autocapture.version', VERSION);\n    });\n\n    test('should not throw error when diagnostics client is not provided', () => {\n      expect(() => {\n        autocapturePlugin({});\n      }).not.toThrow();\n    });\n  });\n\n  describe('setup', () => {\n    test('should setup successfully', async () => {\n      const loggerProvider: Partial<ILogger> = {\n        log: jest.fn(),\n        warn: jest.fn(),\n        error: jest.fn(),\n      };\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider as ILogger,\n      };\n      const amplitude: Partial<BrowserClient> = {};\n      await plugin?.setup?.(config as BrowserConfig, amplitude as BrowserClient);\n      expect(loggerProvider.warn).toHaveBeenCalledTimes(0);\n      expect(loggerProvider.log).toHaveBeenCalledTimes(1);\n      expect(loggerProvider.log).toHaveBeenNthCalledWith(1, `${plugin?.name as string} has been successfully added.`);\n    });\n\n    test('should setup visual tagging selector', async () => {\n      window.opener = true;\n      const messengerMock = {\n        setup: jest.fn(),\n        registerActionHandler: jest.fn(),\n      };\n      jest.spyOn(AnalyticsCore, 'getOrCreateWindowMessenger').mockReturnValue(messengerMock as any);\n      jest.spyOn(AnalyticsCore, 'enableBackgroundCapture').mockImplementation(jest.fn());\n      plugin = autocapturePlugin({\n        visualTaggingOptions: { enabled: true },\n      });\n      const loggerProvider: Partial<ILogger> = {\n        log: jest.fn(),\n        warn: jest.fn(),\n        error: jest.fn(),\n      };\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider as ILogger,\n      };\n      const amplitude: Partial<BrowserClient> = {};\n      await plugin?.setup?.(config as BrowserConfig, amplitude as BrowserClient);\n\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n      expect((messengerMock as any).setup).toHaveBeenCalledTimes(1);\n    });\n\n    test('should use custom exposureDuration from deprecated flat option', async () => {\n      const customDuration = 500;\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      let intersectionCallback: (entries: any[]) => void;\n\n      // Mock IntersectionObserver\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      (window as any).IntersectionObserver = jest.fn((cb) => {\n        intersectionCallback = cb;\n        return {\n          observe: jest.fn(),\n          disconnect: jest.fn(),\n        };\n      });\n\n      plugin = autocapturePlugin({\n        exposureDuration: customDuration,\n      });\n      const loggerProvider: Partial<ILogger> = {\n        log: jest.fn(),\n        warn: jest.fn(),\n        error: jest.fn(),\n      };\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider as ILogger,\n      };\n      const amplitude = createMockBrowserClient();\n      await amplitude.init('API_KEY', 'USER_ID').promise;\n      const track = jest.spyOn(amplitude, 'track').mockImplementation(jest.fn());\n\n      await plugin?.setup?.(config as BrowserConfig, amplitude);\n\n      // Create and expose an element\n      const element = document.createElement('button');\n      element.id = 'exposure-test-button';\n      document.body.appendChild(element);\n\n      // Trigger intersection (element becomes visible)\n      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n      intersectionCallback!([\n        {\n          isIntersecting: true,\n          intersectionRatio: 1.0,\n          target: element,\n        },\n      ]);\n\n      // Should not be exposed before custom duration\n      jest.advanceTimersByTime(customDuration - 50);\n      expect(track).not.toHaveBeenCalledWith('[Amplitude] Viewport Content Updated', expect.anything());\n\n      // Should be exposed after custom duration\n      jest.advanceTimersByTime(100);\n\n      // Trigger page end to flush the exposure\n      window.dispatchEvent(new Event('beforeunload'));\n\n      expect(track).toHaveBeenCalledWith(\n        '[Amplitude] Viewport Content Updated',\n        expect.objectContaining({\n          '[Amplitude] Element Exposed': expect.arrayContaining(['button#exposure-test-button']),\n        }),\n      );\n\n      // Cleanup\n      element.remove();\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      (window as any).IntersectionObserver = undefined;\n    });\n\n    test('should use custom exposureDuration from viewportContentUpdated', async () => {\n      const customDuration = 500;\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      let intersectionCallback: (entries: any[]) => void;\n\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      (window as any).IntersectionObserver = jest.fn((cb) => {\n        intersectionCallback = cb;\n        return {\n          observe: jest.fn(),\n          disconnect: jest.fn(),\n        };\n      });\n\n      plugin = autocapturePlugin({\n        viewportContentUpdated: { exposureDuration: customDuration },\n      });\n      const loggerProvider: Partial<ILogger> = {\n        log: jest.fn(),\n        warn: jest.fn(),\n        error: jest.fn(),\n      };\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider as ILogger,\n      };\n      const amplitude = createMockBrowserClient();\n      await amplitude.init('API_KEY', 'USER_ID').promise;\n      const track = jest.spyOn(amplitude, 'track').mockImplementation(jest.fn());\n\n      await plugin?.setup?.(config as BrowserConfig, amplitude);\n\n      const element = document.createElement('button');\n      element.id = 'exposure-test-button';\n      document.body.appendChild(element);\n\n      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n      intersectionCallback!([\n        {\n          isIntersecting: true,\n          intersectionRatio: 1.0,\n          target: element,\n        },\n      ]);\n\n      jest.advanceTimersByTime(customDuration - 50);\n      expect(track).not.toHaveBeenCalledWith('[Amplitude] Viewport Content Updated', expect.anything());\n\n      jest.advanceTimersByTime(100);\n\n      window.dispatchEvent(new Event('beforeunload'));\n\n      expect(track).toHaveBeenCalledWith(\n        '[Amplitude] Viewport Content Updated',\n        expect.objectContaining({\n          '[Amplitude] Element Exposed': expect.arrayContaining(['button#exposure-test-button']),\n        }),\n      );\n\n      element.remove();\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      (window as any).IntersectionObserver = undefined;\n    });\n\n    test('viewportContentUpdated.exposureDuration should take precedence over deprecated flat exposureDuration', async () => {\n      const nestedDuration = 300;\n      const flatDuration = 600;\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      let intersectionCallback: (entries: any[]) => void;\n\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      (window as any).IntersectionObserver = jest.fn((cb) => {\n        intersectionCallback = cb;\n        return {\n          observe: jest.fn(),\n          disconnect: jest.fn(),\n        };\n      });\n\n      plugin = autocapturePlugin({\n        exposureDuration: flatDuration,\n        viewportContentUpdated: { exposureDuration: nestedDuration },\n      });\n      const loggerProvider: Partial<ILogger> = {\n        log: jest.fn(),\n        warn: jest.fn(),\n        error: jest.fn(),\n      };\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider as ILogger,\n      };\n      const amplitude = createMockBrowserClient();\n      await amplitude.init('API_KEY', 'USER_ID').promise;\n      const track = jest.spyOn(amplitude, 'track').mockImplementation(jest.fn());\n\n      await plugin?.setup?.(config as BrowserConfig, amplitude);\n\n      const element = document.createElement('button');\n      element.id = 'precedence-test-button';\n      document.body.appendChild(element);\n\n      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n      intersectionCallback!([\n        {\n          isIntersecting: true,\n          intersectionRatio: 1.0,\n          target: element,\n        },\n      ]);\n\n      // Should not fire at nestedDuration - 50\n      jest.advanceTimersByTime(nestedDuration - 50);\n      expect(track).not.toHaveBeenCalledWith('[Amplitude] Viewport Content Updated', expect.anything());\n\n      // Should fire after nestedDuration (not flatDuration)\n      jest.advanceTimersByTime(100);\n      window.dispatchEvent(new Event('beforeunload'));\n\n      expect(track).toHaveBeenCalledWith(\n        '[Amplitude] Viewport Content Updated',\n        expect.objectContaining({\n          '[Amplitude] Element Exposed': expect.arrayContaining(['button#precedence-test-button']),\n        }),\n      );\n\n      element.remove();\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      (window as any).IntersectionObserver = undefined;\n    });\n\n    test('should not fire Viewport Content Updated when enabled is false', async () => {\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      (window as any).IntersectionObserver = jest.fn(() => ({\n        observe: jest.fn(),\n        disconnect: jest.fn(),\n      }));\n\n      plugin = autocapturePlugin({\n        viewportContentUpdated: { enabled: false },\n      });\n      const loggerProvider: Partial<ILogger> = {\n        log: jest.fn(),\n        warn: jest.fn(),\n        error: jest.fn(),\n      };\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider as ILogger,\n      };\n      const amplitude = createMockBrowserClient();\n      await amplitude.init('API_KEY', 'USER_ID').promise;\n      const track = jest.spyOn(amplitude, 'track').mockImplementation(jest.fn());\n\n      await plugin?.setup?.(config as BrowserConfig, amplitude);\n\n      window.dispatchEvent(new Event('beforeunload'));\n\n      expect(track).not.toHaveBeenCalledWith('[Amplitude] Viewport Content Updated', expect.anything());\n\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      (window as any).IntersectionObserver = undefined;\n    });\n  });\n\n  describe('execute', () => {\n    test('should return the same event type', async () => {\n      const event = await plugin?.execute?.({\n        event_type: 'custom_event',\n      });\n      expect(event).toEqual({\n        event_type: 'custom_event',\n      });\n    });\n  });\n\n  describe('auto-tracked events', () => {\n    const API_KEY = 'API_KEY';\n    const USER_ID = 'USER_ID';\n\n    let instance = createMockBrowserClient();\n    let track: jest.SpyInstance;\n    let loggerProvider: ILogger;\n\n    beforeEach(async () => {\n      jest.useFakeTimers();\n      loggerProvider = {\n        log: jest.fn(),\n        warn: jest.fn(),\n        error: jest.fn(),\n        debug: jest.fn(),\n      } as unknown as ILogger;\n      plugin = autocapturePlugin({ debounceTime: TESTING_DEBOUNCE_TIME });\n      instance = createMockBrowserClient();\n      await instance.init(API_KEY, USER_ID).promise;\n      track = jest.spyOn(instance, 'track').mockImplementation(jest.fn());\n\n      const link = document.createElement('a');\n      link.setAttribute('id', 'my-link-id');\n      link.setAttribute('class', 'my-link-class');\n      link.setAttribute('aria-label', 'my-link');\n      link.href = 'https://www.amplitude.com/click-link';\n      link.text = 'my-link-text';\n      document.body.appendChild(link);\n\n      const h2 = document.createElement('h2');\n      h2.textContent = 'my-h2-text';\n      document.body.appendChild(h2);\n\n      mockWindowLocationFromURL(new URL('https://www.amplitude.com/unit-test?query=param'));\n    });\n\n    afterEach(() => {\n      document.querySelector('a#my-link-id')?.remove();\n      document.querySelector('button#my-button-id')?.remove();\n      document.querySelector('input#my-input-id')?.remove();\n      jest.useRealTimers();\n    });\n\n    test('should monitor element clicked event', async () => {\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n      };\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // trigger click event\n      document.getElementById('my-link-id')?.dispatchEvent(new Event('click'));\n\n      jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n      expect(track).toHaveBeenCalledTimes(1);\n      expect(track).toHaveBeenNthCalledWith(1, '[Amplitude] Element Clicked', {\n        '[Amplitude] Element Class': 'my-link-class',\n        '[Amplitude] Element Hierarchy': [\n          {\n            attrs: {\n              'aria-label': 'my-link',\n              href: 'https://www.amplitude.com/click-link',\n            },\n            classes: ['my-link-class'],\n            id: 'my-link-id',\n            index: 0,\n            indexOfType: 0,\n            tag: 'a',\n          },\n          {\n            index: 1,\n            indexOfType: 0,\n            prevSib: 'head',\n            tag: 'body',\n          },\n        ],\n        '[Amplitude] Element Href': 'https://www.amplitude.com/click-link',\n        '[Amplitude] Element ID': 'my-link-id',\n        '[Amplitude] Element Position Left': 0,\n        '[Amplitude] Element Position Top': 0,\n        '[Amplitude] Element Tag': 'a',\n        '[Amplitude] Element Text': 'my-link-text',\n        '[Amplitude] Element Aria Label': 'my-link',\n        '[Amplitude] Element Parent Label': 'my-h2-text',\n        '[Amplitude] Element Path': 'a#my-link-id',\n        '[Amplitude] Page URL': 'https://www.amplitude.com/unit-test',\n        '[Amplitude] Viewport Height': 768,\n        '[Amplitude] Viewport Width': 1024,\n      });\n\n      // stop observer and listeners\n      await plugin?.teardown?.();\n\n      // trigger click event\n      document.getElementById('my-link-id')?.dispatchEvent(new Event('click'));\n\n      jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n      // assert no additional event was tracked\n      expect(track).toHaveBeenCalledTimes(1);\n    });\n\n    test('should only collect element hierarchy once', async () => {\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n      };\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // trigger click event\n      document.getElementById('my-link-id')?.dispatchEvent(new Event('click'));\n\n      jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n      expect(track).toHaveBeenCalledTimes(1);\n      expect(track).toHaveBeenNthCalledWith(\n        1,\n        '[Amplitude] Element Clicked',\n        expect.objectContaining({\n          '[Amplitude] Element Hierarchy': [\n            {\n              attrs: {\n                'aria-label': 'my-link',\n                href: 'https://www.amplitude.com/click-link',\n              },\n              classes: ['my-link-class'],\n              id: 'my-link-id',\n              index: 0,\n              indexOfType: 0,\n              tag: 'a',\n            },\n            {\n              index: 1,\n              indexOfType: 0,\n              prevSib: 'head',\n              tag: 'body',\n            },\n          ],\n        }),\n      );\n\n      // stop observer and listeners\n      await plugin?.teardown?.();\n\n      // trigger click event\n      document.getElementById('my-link-id')?.dispatchEvent(new Event('click'));\n\n      jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n      // assert no additional event was tracked after teardown\n      expect(track).toHaveBeenCalledTimes(1);\n    });\n\n    // In the browser, this would happen in form elements due to named property accessors\n    // form > input[name=\"id\"]\n    // However in jsdom, this behavior is not implemented, so we set the id to the input element itself\n    // Note: in a browser, setting an id directly already casts to a string\n    test('should not error when element properties resolve to an element', async () => {\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n      };\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // Create scenario where element properties are elements\n      const formEl = document.createElement('form');\n      formEl.id = 'my-form-id';\n      formEl.setAttribute('data-attr', 'testing');\n      document.body.appendChild(formEl);\n\n      const input1 = document.createElement('input');\n      formEl.appendChild(input1);\n\n      // Set attributes to an element to test if they are cast to a string\n      formEl.id = input1 as unknown as string;\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore\n      formEl.classList = input1 as unknown as Array<string>;\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore\n      formEl.className = input1 as unknown as string;\n\n      const submitButton = document.createElement('button');\n      submitButton.setAttribute('type', 'submit');\n      formEl.appendChild(submitButton);\n\n      // trigger click event\n      submitButton?.dispatchEvent(new Event('click'));\n\n      jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n      expect(track).toHaveBeenCalledTimes(1);\n      expect(track).toHaveBeenNthCalledWith(\n        1,\n        '[Amplitude] Element Clicked',\n        expect.objectContaining({\n          '[Amplitude] Element Hierarchy': [\n            { attrs: { type: 'submit' }, index: 1, indexOfType: 0, prevSib: 'input', tag: 'button' },\n            {\n              attrs: { 'data-attr': 'testing' },\n              classes: ['[object', 'HTMLInputElement]'],\n              id: '[object HTMLInputElement]',\n              index: 2,\n              indexOfType: 0,\n              prevSib: 'h2',\n              tag: 'form',\n            },\n            { index: 1, indexOfType: 0, prevSib: 'head', tag: 'body' },\n          ],\n        }),\n      );\n\n      // stop observer and listeners\n      await plugin?.teardown?.();\n\n      // trigger click event\n      document.getElementById('my-link-id')?.dispatchEvent(new Event('click'));\n\n      jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n      // assert no additional event was tracked\n      expect(track).toHaveBeenCalledTimes(1);\n    });\n\n    test('should track click event properties immediately', async () => {\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n      };\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // trigger click event\n      const linkEl = document.getElementById('my-link-id') as HTMLAnchorElement;\n      linkEl?.dispatchEvent(new Event('click'));\n\n      // Change the link text immediately after click\n      linkEl.textContent = 'updated-link-text';\n\n      jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n      expect(track).toHaveBeenCalledTimes(1);\n      expect(track).toHaveBeenNthCalledWith(1, '[Amplitude] Element Clicked', {\n        '[Amplitude] Element Class': 'my-link-class',\n        '[Amplitude] Element Hierarchy': [\n          {\n            attrs: {\n              'aria-label': 'my-link',\n              href: 'https://www.amplitude.com/click-link',\n            },\n            classes: ['my-link-class'],\n            id: 'my-link-id',\n            index: 0,\n            indexOfType: 0,\n            tag: 'a',\n          },\n          {\n            index: 1,\n            indexOfType: 0,\n            prevSib: 'head',\n            tag: 'body',\n          },\n        ],\n        '[Amplitude] Element Href': 'https://www.amplitude.com/click-link',\n        '[Amplitude] Element ID': 'my-link-id',\n        '[Amplitude] Element Position Left': 0,\n        '[Amplitude] Element Position Top': 0,\n        '[Amplitude] Element Tag': 'a',\n        '[Amplitude] Element Text': 'my-link-text',\n        '[Amplitude] Element Aria Label': 'my-link',\n        '[Amplitude] Element Parent Label': 'my-h2-text',\n        '[Amplitude] Element Path': 'a#my-link-id',\n        '[Amplitude] Page URL': 'https://www.amplitude.com/unit-test',\n        '[Amplitude] Viewport Height': 768,\n        '[Amplitude] Viewport Width': 1024,\n      });\n\n      // stop observer and listeners\n      await plugin?.teardown?.();\n\n      // trigger click event\n      document.getElementById('my-link-id')?.dispatchEvent(new Event('click'));\n\n      jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n      // assert no additional event was tracked\n      expect(track).toHaveBeenCalledTimes(1);\n    });\n\n    test('should mask sensitive text from element content', async () => {\n      plugin = autocapturePlugin({\n        maskTextRegex: [/CONFIDENTIAL_TEXT/],\n      });\n\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n      };\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      const button = document.createElement('button');\n      button.setAttribute('id', 'mask-button');\n      button.setAttribute('class', 'my-button-class');\n      button.appendChild(document.createTextNode('pay'));\n      button.textContent = 'CONFIDENTIAL_TEXT';\n      const div = document.createElement('div');\n      div.textContent = '4111111111111111'; // Visa test number (should be masked)\n      button.appendChild(div);\n      document.body.appendChild(button);\n\n      document.getElementById('mask-button')?.dispatchEvent(new Event('click'));\n\n      jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n      expect(track).toHaveBeenCalledTimes(1);\n      expect(track).toHaveBeenNthCalledWith(\n        1,\n        '[Amplitude] Element Clicked',\n        expect.not.objectContaining({\n          '[Amplitude] Element Text': 'CONFIDENTIAL_TEXT',\n        }),\n      );\n    });\n\n    test('should monitor element clicked event when dynamically rendered', async () => {\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n      };\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // trigger click event\n      const button = document.createElement('button');\n      const buttonText = document.createTextNode('submit');\n      button.setAttribute('id', 'my-button-id');\n      button.setAttribute('class', 'my-button-class');\n      button.setAttribute('aria-label', 'my-button');\n      button.appendChild(buttonText);\n      document.body.appendChild(button);\n\n      document.getElementById('my-button-id')?.dispatchEvent(new Event('click'));\n\n      jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n      expect(track).toHaveBeenCalledTimes(1);\n      expect(track).toHaveBeenNthCalledWith(1, '[Amplitude] Element Clicked', {\n        '[Amplitude] Element Class': 'my-button-class',\n        '[Amplitude] Element Hierarchy': [\n          {\n            attrs: {\n              'aria-label': 'my-button',\n            },\n            classes: ['my-button-class'],\n            id: 'my-button-id',\n            index: 2,\n            indexOfType: 0,\n            prevSib: 'h2',\n            tag: 'button',\n          },\n          {\n            index: 1,\n            indexOfType: 0,\n            prevSib: 'head',\n            tag: 'body',\n          },\n        ],\n        '[Amplitude] Element ID': 'my-button-id',\n        '[Amplitude] Element Position Left': 0,\n        '[Amplitude] Element Position Top': 0,\n        '[Amplitude] Element Tag': 'button',\n        '[Amplitude] Element Text': 'submit',\n        '[Amplitude] Element Aria Label': 'my-button',\n        '[Amplitude] Element Parent Label': 'my-h2-text',\n        '[Amplitude] Element Path': 'button#my-button-id',\n        '[Amplitude] Page URL': 'https://www.amplitude.com/unit-test',\n        '[Amplitude] Viewport Height': 768,\n        '[Amplitude] Viewport Width': 1024,\n      });\n\n      // stop observer and listeners\n      await plugin?.teardown?.();\n\n      // trigger click event\n      document.getElementById('my-link-id')?.dispatchEvent(new Event('click'));\n\n      // assert no additional event was tracked\n      expect(track).toHaveBeenCalledTimes(1);\n    });\n    test('should track clicks to elements added after initial load', async () => {\n      const body = document.body;\n      const bodyParent = body?.parentNode;\n      bodyParent?.removeChild(body);\n\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n      };\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      bodyParent?.appendChild(body);\n      // fire the load event, so that the mutation observer can be mounted\n      window.dispatchEvent(new Event('load'));\n\n      // Create new button after DOM load\n      const button = document.createElement('button');\n      const buttonText = document.createTextNode('submit');\n      button.setAttribute('id', 'my-button-id');\n      button.setAttribute('class', 'my-button-class');\n      button.setAttribute('aria-label', 'my-button');\n      button.appendChild(buttonText);\n      document.body.appendChild(button);\n\n      // trigger click event\n      document.getElementById('my-button-id')?.dispatchEvent(new Event('click'));\n      jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n      expect(track).toHaveBeenCalledTimes(1);\n      expect(track).toHaveBeenNthCalledWith(1, '[Amplitude] Element Clicked', {\n        '[Amplitude] Element Class': 'my-button-class',\n        '[Amplitude] Element Hierarchy': [\n          {\n            attrs: {\n              'aria-label': 'my-button',\n            },\n            classes: ['my-button-class'],\n            id: 'my-button-id',\n            index: 2,\n            indexOfType: 0,\n            prevSib: 'h2',\n            tag: 'button',\n          },\n          {\n            index: 1,\n            indexOfType: 0,\n            prevSib: 'head',\n            tag: 'body',\n          },\n        ],\n        '[Amplitude] Element ID': 'my-button-id',\n        '[Amplitude] Element Position Left': 0,\n        '[Amplitude] Element Position Top': 0,\n        '[Amplitude] Element Tag': 'button',\n        '[Amplitude] Element Text': 'submit',\n        '[Amplitude] Element Aria Label': 'my-button',\n        '[Amplitude] Element Parent Label': 'my-h2-text',\n        '[Amplitude] Element Path': 'button#my-button-id',\n        '[Amplitude] Page URL': 'https://www.amplitude.com/unit-test',\n        '[Amplitude] Viewport Height': 768,\n        '[Amplitude] Viewport Width': 1024,\n      });\n\n      // stop observer and listeners\n      await plugin?.teardown?.();\n    });\n    test('should not track disallowed tag', async () => {\n      const div = document.createElement('div');\n      div.setAttribute('id', 'my-div-id');\n      document.body.appendChild(div);\n\n      plugin = autocapturePlugin({ debounceTime: TESTING_DEBOUNCE_TIME });\n\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n      };\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // trigger click div which should not be tracked\n      document.getElementById('my-div-id')?.dispatchEvent(new Event('click'));\n      jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n      expect(track).toHaveBeenCalledTimes(0);\n\n      // trigger click link\n      document.getElementById('my-link-id')?.dispatchEvent(new Event('click'));\n      jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n      expect(track).toHaveBeenCalledTimes(1);\n    });\n\n    describe('cssSelectorAllowlist configuration', () => {\n      test('should only track selector class', async () => {\n        const button = document.createElement('button');\n        const buttonText = document.createTextNode('submit');\n        button.setAttribute('id', 'my-button-id');\n        button.setAttribute('class', 'my-button-class');\n        button.appendChild(buttonText);\n        document.body.appendChild(button);\n\n        plugin = autocapturePlugin({\n          cssSelectorAllowlist: ['.my-button-class'],\n          debounceTime: TESTING_DEBOUNCE_TIME,\n        });\n        const config: Partial<BrowserConfig> = {\n          defaultTracking: false,\n          loggerProvider: loggerProvider,\n        };\n        await plugin?.setup?.(config as BrowserConfig, instance);\n\n        // trigger click link\n        document.getElementById('my-link-id')?.dispatchEvent(new Event('click'));\n        jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n        expect(track).toHaveBeenCalledTimes(0);\n\n        // trigger click button\n        document.getElementById('my-button-id')?.dispatchEvent(new Event('click'));\n        jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n        expect(track).toHaveBeenCalledTimes(1);\n      });\n\n      test('should be able to track non-default tags by overwriting default cssSelectorAllowlist', async () => {\n        const div = document.createElement('div');\n        div.textContent = 'my-div-text';\n        div.setAttribute('id', 'my-div-id');\n        document.body.appendChild(div);\n\n        const button = document.createElement('button');\n        button.textContent = 'my-button-text';\n        button.setAttribute('id', 'my-button-id');\n        document.body.appendChild(button);\n\n        // Use only div in allowlist\n        plugin = autocapturePlugin({ cssSelectorAllowlist: ['div'], debounceTime: TESTING_DEBOUNCE_TIME });\n        const loggerProvider: Partial<ILogger> = {\n          log: jest.fn(),\n          warn: jest.fn(),\n          error: jest.fn(),\n        };\n        const config: Partial<BrowserConfig> = {\n          defaultTracking: false,\n          loggerProvider: loggerProvider as ILogger,\n        };\n        await plugin?.setup?.(config as BrowserConfig, instance);\n\n        // trigger click button\n        document.getElementById('my-button-id')?.dispatchEvent(new Event('click'));\n        jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n        expect(track).toHaveBeenCalledTimes(0);\n\n        // trigger click div\n        document.getElementById('my-div-id')?.dispatchEvent(new Event('click'));\n        jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n        expect(track).toHaveBeenCalledTimes(1);\n      });\n\n      test('should respect default cssSelectorAllowlist', async () => {\n        const div1 = document.createElement('div');\n        div1.textContent = 'my-div-text1';\n        div1.setAttribute('id', 'my-div-id1');\n        div1.className = 'amp-default-track'; // default css class to enable tracking\n        document.body.appendChild(div1);\n\n        const div2 = document.createElement('div');\n        div2.textContent = 'my-div-text2';\n        div2.setAttribute('id', 'my-div-id2');\n        div2.setAttribute('data-amp-default-track', ''); // default data attribute to enable tracking\n        document.body.appendChild(div2);\n\n        const button = document.createElement('button');\n        button.textContent = 'my-button-text';\n        button.setAttribute('id', 'my-button-id');\n        document.body.appendChild(button);\n\n        plugin = autocapturePlugin({ debounceTime: TESTING_DEBOUNCE_TIME });\n        const loggerProvider: Partial<ILogger> = {\n          log: jest.fn(),\n          warn: jest.fn(),\n          error: jest.fn(),\n        };\n        const config: Partial<BrowserConfig> = {\n          defaultTracking: false,\n          loggerProvider: loggerProvider as ILogger,\n        };\n        await plugin?.setup?.(config as BrowserConfig, instance);\n\n        // trigger click button\n        document.getElementById('my-button-id')?.dispatchEvent(new Event('click'));\n        jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n        expect(track).toHaveBeenCalledTimes(1);\n\n        // trigger click div1\n        document.getElementById('my-div-id1')?.dispatchEvent(new Event('click'));\n        jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n        expect(track).toHaveBeenCalledTimes(2);\n\n        // trigger click div2\n        document.getElementById('my-div-id2')?.dispatchEvent(new Event('click'));\n        jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n        expect(track).toHaveBeenCalledTimes(3);\n      });\n    });\n\n    test('should follow pageUrlAllowlist configuration', async () => {\n      plugin = autocapturePlugin({\n        pageUrlAllowlist: [new RegExp('https://www.test.com')],\n        debounceTime: TESTING_DEBOUNCE_TIME,\n      });\n\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n      };\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // trigger click link\n      document.getElementById('my-link-id')?.dispatchEvent(new Event('click'));\n      jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n      expect(track).toHaveBeenCalledTimes(0);\n\n      // update current page url to match allowlist\n      mockWindowLocationFromURL(new URL('https://www.test.com/abc?query=param'));\n      const link = document.createElement('a');\n      link.setAttribute('id', 'my-link-id-new-url');\n      link.setAttribute('class', 'my-link-class');\n      link.setAttribute('aria-label', 'my-link');\n      link.href = 'https://www.amplitude.com/test';\n      link.text = 'my-link-text';\n      document.body.appendChild(link);\n\n      // trigger click link\n      document.getElementById('my-link-id-new-url')?.dispatchEvent(new Event('click'));\n      jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n      expect(track).toHaveBeenCalledTimes(1);\n    });\n\n    test('should follow pageUrlExcludelist configuration', async () => {\n      plugin = autocapturePlugin({\n        pageUrlExcludelist: [new RegExp('https://www.test.com')],\n        debounceTime: TESTING_DEBOUNCE_TIME,\n      });\n\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n      };\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // update current page url to match excludelist\n      mockWindowLocationFromURL(new URL('https://www.test.com/abc?query=param'));\n      const link = document.createElement('a');\n      link.setAttribute('id', 'my-link-id-excluded-url');\n      link.setAttribute('class', 'my-link-class');\n      link.setAttribute('aria-label', 'my-link');\n      link.href = 'https://www.amplitude.com/test';\n      link.text = 'my-link-text';\n      document.body.appendChild(link);\n\n      // trigger click link - should be blocked by excludelist\n      document.getElementById('my-link-id-excluded-url')?.dispatchEvent(new Event('click'));\n      jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n      expect(track).toHaveBeenCalledTimes(0);\n\n      // update current page url to NOT match excludelist\n      mockWindowLocationFromURL(new URL('https://www.different.com/abc?query=param'));\n      const link2 = document.createElement('a');\n      link2.setAttribute('id', 'my-link-id-allowed-url');\n      link2.setAttribute('class', 'my-link-class');\n      link2.setAttribute('aria-label', 'my-link');\n      link2.href = 'https://www.amplitude.com/test';\n      link2.text = 'my-link-text';\n      document.body.appendChild(link2);\n\n      // trigger click link - should be allowed\n      document.getElementById('my-link-id-allowed-url')?.dispatchEvent(new Event('click'));\n      jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n      expect(track).toHaveBeenCalledTimes(1);\n    });\n\n    test('should prioritize pageUrlExcludelist over pageUrlAllowlist', async () => {\n      plugin = autocapturePlugin({\n        pageUrlAllowlist: [new RegExp('https://www.test.com')],\n        pageUrlExcludelist: [new RegExp('https://www.test.com')],\n        debounceTime: TESTING_DEBOUNCE_TIME,\n      });\n\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n      };\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // update current page url to match both allowlist and excludelist\n      mockWindowLocationFromURL(new URL('https://www.test.com/abc?query=param'));\n      const link = document.createElement('a');\n      link.setAttribute('id', 'my-link-id-conflict-url');\n      link.setAttribute('class', 'my-link-class');\n      link.setAttribute('aria-label', 'my-link');\n      link.href = 'https://www.amplitude.com/test';\n      link.text = 'my-link-text';\n      document.body.appendChild(link);\n\n      // trigger click link - should be blocked by excludelist even though it matches allowlist\n      document.getElementById('my-link-id-conflict-url')?.dispatchEvent(new Event('click'));\n      jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n      expect(track).toHaveBeenCalledTimes(0);\n    });\n\n    test('should follow shouldTrackEventResolver configuration', async () => {\n      const button1 = document.createElement('button');\n      const buttonText1 = document.createTextNode('submit');\n      button1.setAttribute('id', 'my-button-id-1');\n      button1.setAttribute('class', 'my-button-class');\n      button1.appendChild(buttonText1);\n      document.body.appendChild(button1);\n\n      const button2 = document.createElement('button');\n      const buttonText2 = document.createTextNode('submit');\n      button2.setAttribute('id', 'my-button-id-2');\n      button2.setAttribute('class', 'my-button-class');\n      button2.appendChild(buttonText2);\n      document.body.appendChild(button2);\n\n      plugin = autocapturePlugin({\n        shouldTrackEventResolver: (actionType, element) =>\n          actionType === 'click' && element.getAttribute('id') === 'my-button-id-1' && element.tagName === 'BUTTON',\n        debounceTime: TESTING_DEBOUNCE_TIME,\n      });\n\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n      };\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // trigger click button2\n      document.getElementById('my-button-id-2')?.dispatchEvent(new Event('click'));\n      jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n      expect(track).toHaveBeenCalledTimes(0);\n\n      // trigger click button1\n      document.getElementById('my-button-id-1')?.dispatchEvent(new Event('click'));\n      jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n      expect(track).toHaveBeenCalledTimes(1);\n    });\n\n    test('should follow dataAttributePrefix configuration', async () => {\n      const button = document.createElement('button');\n      const buttonText = document.createTextNode('submit');\n      button.setAttribute('id', 'my-button-id');\n      button.setAttribute('class', 'my-button-class');\n      button.setAttribute('data-amp-test-hello', 'world');\n      button.setAttribute('data-amp-test-time', 'machine');\n      button.setAttribute('data-amp-test-test', '');\n      button.appendChild(buttonText);\n      document.body.appendChild(button);\n\n      plugin = autocapturePlugin({\n        dataAttributePrefix: 'data-amp-test-',\n        debounceTime: TESTING_DEBOUNCE_TIME,\n      });\n\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n      };\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // trigger click button\n      document.getElementById('my-button-id')?.dispatchEvent(new Event('click'));\n      jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n      expect(track).toHaveBeenCalledTimes(1);\n      expect(track).toHaveBeenNthCalledWith(1, '[Amplitude] Element Clicked', {\n        '[Amplitude] Element Class': 'my-button-class',\n        '[Amplitude] Element Hierarchy': [\n          {\n            attrs: {\n              'data-amp-test-hello': 'world',\n              'data-amp-test-test': '',\n              'data-amp-test-time': 'machine',\n            },\n            classes: ['my-button-class'],\n            id: 'my-button-id',\n            index: 2,\n            indexOfType: 0,\n            prevSib: 'h2',\n            tag: 'button',\n          },\n\n          {\n            index: 1,\n            indexOfType: 0,\n            prevSib: 'head',\n            tag: 'body',\n          },\n        ],\n        '[Amplitude] Element ID': 'my-button-id',\n        '[Amplitude] Element Position Left': 0,\n        '[Amplitude] Element Position Top': 0,\n        '[Amplitude] Element Tag': 'button',\n        '[Amplitude] Element Text': 'submit',\n        '[Amplitude] Element Parent Label': 'my-h2-text',\n        '[Amplitude] Element Path': 'button#my-button-id',\n        '[Amplitude] Page URL': 'https://www.amplitude.com/unit-test',\n        '[Amplitude] Viewport Height': 768,\n        '[Amplitude] Viewport Width': 1024,\n        '[Amplitude] Element Attributes': {\n          hello: 'world',\n          time: 'machine',\n          test: '',\n        },\n      });\n    });\n    test('should follow default debounceTime configuration', async () => {\n      const oldFetch = global.fetch;\n      global.fetch = jest.fn(() =>\n        Promise.resolve({\n          json: () =>\n            Promise.resolve({\n              code: 200,\n            }),\n        }),\n      ) as jest.Mock;\n      const button = document.createElement('button');\n      const buttonText = document.createTextNode('submit');\n      button.setAttribute('id', 'my-button-id');\n      button.appendChild(buttonText);\n      document.body.appendChild(button);\n\n      plugin = autocapturePlugin();\n\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n      };\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // trigger click button\n      document.getElementById('my-button-id')?.dispatchEvent(new Event('click'));\n      jest.advanceTimersByTime(0);\n      expect(track).toHaveBeenCalledTimes(1);\n\n      global.fetch = oldFetch;\n    });\n\n    test('should track change event', async () => {\n      const input = document.createElement('input');\n      input.setAttribute('id', 'my-input-id');\n      input.setAttribute('class', 'my-input-class');\n      document.body.appendChild(input);\n\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n      };\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // trigger click input\n      document.getElementById('my-input-id')?.dispatchEvent(new Event('click'));\n      jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n      expect(track).toHaveBeenCalledTimes(1);\n\n      // trigger change input\n      document.getElementById('my-input-id')?.dispatchEvent(new Event('change'));\n      expect(track).toHaveBeenCalledTimes(2);\n    });\n\n    test('should not track when element type is hidden', async () => {\n      const input = document.createElement('input');\n      input.setAttribute('id', 'my-input-id');\n      input.setAttribute('class', 'my-input-class');\n      input.type = 'hidden';\n      document.body.appendChild(input);\n\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n      };\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // trigger click input\n      document.getElementById('my-input-id')?.dispatchEvent(new Event('click'));\n      expect(track).toHaveBeenCalledTimes(0);\n\n      // trigger change input\n      document.getElementById('my-input-id')?.dispatchEvent(new Event('change'));\n      expect(track).toHaveBeenCalledTimes(0);\n    });\n\n    test('should not track when element type is password', async () => {\n      const input = document.createElement('input');\n      input.setAttribute('id', 'my-input-id');\n      input.setAttribute('class', 'my-input-class');\n      input.type = 'password';\n      document.body.appendChild(input);\n\n      const loggerProvider: Partial<ILogger> = {\n        log: jest.fn(),\n        warn: jest.fn(),\n        error: jest.fn(),\n      };\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider as ILogger,\n      };\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // trigger click input\n      document.getElementById('my-input-id')?.dispatchEvent(new Event('click'));\n      expect(track).toHaveBeenCalledTimes(0);\n\n      // trigger change input\n      document.getElementById('my-input-id')?.dispatchEvent(new Event('change'));\n      expect(track).toHaveBeenCalledTimes(0);\n    });\n\n    test('should not track for div tags', async () => {\n      const div = document.createElement('div');\n      div.setAttribute('id', 'my-div-id');\n      div.setAttribute('class', 'my-div-class');\n      document.body.appendChild(div);\n\n      const loggerProvider: Partial<ILogger> = {\n        log: jest.fn(),\n        warn: jest.fn(),\n        error: jest.fn(),\n      };\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider as ILogger,\n      };\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // trigger click input\n      document.getElementById('my-div-id')?.dispatchEvent(new Event('click'));\n      expect(track).toHaveBeenCalledTimes(0);\n\n      // trigger change input\n      document.getElementById('my-div-id')?.dispatchEvent(new Event('change'));\n      expect(track).toHaveBeenCalledTimes(0);\n    });\n\n    test('should not throw error when there is text node added to the page', async () => {\n      const loggerProvider: Partial<ILogger> = {\n        log: jest.fn(),\n        warn: jest.fn(),\n        error: jest.fn(),\n      };\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider as ILogger,\n      };\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      const textNode = document.createTextNode('Some text node');\n      document.body.appendChild(textNode);\n\n      const div = document.createElement('div');\n      div.setAttribute('id', 'my-div-id');\n      div.setAttribute('class', 'my-div-class');\n      document.body.appendChild(div);\n\n      // allow mutation observer to execute and event listener to be attached\n      await new Promise((r) => r(undefined)); // basically, await next clock tick\n\n      // trigger click input\n      document.getElementById('my-div-id')?.dispatchEvent(new Event('click'));\n      expect(track).toHaveBeenCalledTimes(0);\n    });\n\n    describe('when facing nested elements', () => {\n      /*\n        <div id=\"container2\">\n          <div id=\"container1\">\n            <div id=\"inner\">\n              click me\n            </div>\n          </div>\n        </div>\n        cssSelectorAllowlist: ['div']\n        expect: only track inner, as we should only track the innermost allowed element\n      */\n      test('should only fire event for the inner element when container element also matches the allowlist and is the same tag', async () => {\n        document.getElementsByTagName('body')[0].innerHTML = `\n          <div id=\"container2\">\n            <div id=\"container1\">\n              <div id=\"inner\">\n                click me\n              </div>\n            </div>\n          </div>\n        `;\n\n        plugin = autocapturePlugin({ cssSelectorAllowlist: ['div'], debounceTime: TESTING_DEBOUNCE_TIME });\n        const config: Partial<BrowserConfig> = {\n          defaultTracking: false,\n          loggerProvider: loggerProvider,\n        };\n        await plugin?.setup?.(config as BrowserConfig, instance);\n\n        // trigger click inner\n        document.getElementById('inner')?.dispatchEvent(new Event('click', { bubbles: true }));\n        jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n        expect(track).toHaveBeenCalledTimes(1);\n        expect(track).toHaveBeenNthCalledWith(\n          1,\n          '[Amplitude] Element Clicked',\n          expect.objectContaining({\n            '[Amplitude] Element ID': 'inner',\n          }),\n        );\n\n        // trigger click container\n        document.getElementById('container1')?.dispatchEvent(new Event('click', { bubbles: true }));\n        jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n        expect(track).toHaveBeenCalledTimes(2);\n        expect(track).toHaveBeenNthCalledWith(\n          2,\n          '[Amplitude] Element Clicked',\n          expect.objectContaining({\n            '[Amplitude] Element ID': 'container1',\n          }),\n        );\n      });\n\n      /*\n        <div id=\"container2\" class=\"match-me\">\n          <div id=\"container1\" class=\"match-me\">\n            <div id=\"inner\">\n              click me\n            </div>\n          </div>\n        </div>\n        cssSelectorAllowlist: ['.match-me']\n        expect: only track container1, as we should only track the innermost allowed element\n      */\n      test('should only fire event for the immediate parent element when inner element does not match but parent matches', async () => {\n        document.getElementsByTagName('body')[0].innerHTML = `\n          <div id=\"container2\" class=\"match-me\">\n            <div id=\"container1\" class=\"match-me\">\n              <div id=\"inner\">\n                click me\n              </div>\n            </div>\n          </div>\n        `;\n\n        plugin = autocapturePlugin({ cssSelectorAllowlist: ['.match-me'], debounceTime: TESTING_DEBOUNCE_TIME });\n        const config: Partial<BrowserConfig> = {\n          defaultTracking: false,\n          loggerProvider: loggerProvider,\n        };\n        await plugin?.setup?.(config as BrowserConfig, instance);\n\n        // trigger click inner\n        document.getElementById('inner')?.dispatchEvent(new Event('click', { bubbles: true }));\n        jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n        expect(track).toHaveBeenCalledTimes(1);\n        expect(track).toHaveBeenNthCalledWith(\n          1,\n          '[Amplitude] Element Clicked',\n          expect.objectContaining({\n            '[Amplitude] Element ID': 'container1',\n          }),\n        );\n\n        // trigger click container\n        document.getElementById('container1')?.dispatchEvent(new Event('click', { bubbles: true }));\n        jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n        expect(track).toHaveBeenCalledTimes(2);\n        expect(track).toHaveBeenNthCalledWith(\n          2,\n          '[Amplitude] Element Clicked',\n          expect.objectContaining({\n            '[Amplitude] Element ID': 'container1',\n          }),\n        );\n      });\n\n      /*\n        <button id=\"container\">\n          <div id=\"inner\">\n            click me\n          </div>\n        </button>\n        cssSelectorAllowlist: ['button']\n        expect: only track button click, as div is not allowed\n      */\n      test('should only fire event for the container element when inner element does not match the allowlist', async () => {\n        document.getElementsByTagName('body')[0].innerHTML = `\n          <button id=\"container\">\n            <div id=\"inner\">\n              click me\n            </div>\n          </button>\n        `;\n\n        plugin = autocapturePlugin({ cssSelectorAllowlist: ['button'], debounceTime: TESTING_DEBOUNCE_TIME });\n        const config: Partial<BrowserConfig> = {\n          defaultTracking: false,\n          loggerProvider: loggerProvider,\n        };\n        await plugin?.setup?.(config as BrowserConfig, instance);\n\n        // trigger click inner\n        document.getElementById('inner')?.dispatchEvent(new Event('click', { bubbles: true }));\n        jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n        expect(track).toHaveBeenCalledTimes(1);\n        expect(track).toHaveBeenNthCalledWith(\n          1,\n          '[Amplitude] Element Clicked',\n          expect.objectContaining({\n            '[Amplitude] Element ID': 'container',\n          }),\n        );\n\n        // trigger click container\n        document.getElementById('container')?.dispatchEvent(new Event('click', { bubbles: true }));\n        jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n        expect(track).toHaveBeenCalledTimes(2);\n        expect(track).toHaveBeenNthCalledWith(\n          2,\n          '[Amplitude] Element Clicked',\n          expect.objectContaining({\n            '[Amplitude] Element ID': 'container',\n          }),\n        );\n      });\n\n      /*\n        <button id=\"container\" data-track>\n          <div id=\"inner\" data-track>\n            click me\n          </div>\n        </button>\n        cssSelectorAllowlist: ['[data-track]']\n        expect: only track div click, as div is innermost element that matches allowlist\n        note: we do not track the button click here, this is a rare case that the inner div is also allowed\n      */\n      test('should only fire event for the inner element when container element also matches the allowlist and is different tag', async () => {\n        document.getElementsByTagName('body')[0].innerHTML = `\n          <button id=\"container\" data-track>\n            <div id=\"inner\" data-track>\n              click me\n            </div>\n          </button>\n        `;\n\n        plugin = autocapturePlugin({ cssSelectorAllowlist: ['[data-track]'], debounceTime: TESTING_DEBOUNCE_TIME });\n        const config: Partial<BrowserConfig> = {\n          defaultTracking: false,\n          loggerProvider: loggerProvider,\n        };\n        await plugin?.setup?.(config as BrowserConfig, instance);\n\n        // trigger click inner\n        document.getElementById('inner')?.dispatchEvent(new Event('click', { bubbles: true }));\n        jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n        expect(track).toHaveBeenCalledTimes(1);\n        expect(track).toHaveBeenNthCalledWith(\n          1,\n          '[Amplitude] Element Clicked',\n          expect.objectContaining({\n            '[Amplitude] Element ID': 'inner',\n          }),\n        );\n\n        // trigger click container\n        document.getElementById('container')?.dispatchEvent(new Event('click', { bubbles: true }));\n        jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n        expect(track).toHaveBeenCalledTimes(2);\n        expect(track).toHaveBeenNthCalledWith(\n          2,\n          '[Amplitude] Element Clicked',\n          expect.objectContaining({\n            '[Amplitude] Element ID': 'container',\n          }),\n        );\n      });\n    });\n\n    test('should not track click for an event fired without a target', async () => {\n      const event = new Event('click', {\n        bubbles: true,\n        cancelable: true,\n      });\n\n      window.dispatchEvent(event);\n\n      jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n      expect(track).toHaveBeenCalledTimes(0);\n    });\n\n    describe('rage click detection:', () => {\n      test('clicking on the same element 4 times should track 4 clicks separately', async () => {\n        const config: Partial<BrowserConfig> = {\n          defaultTracking: false,\n          loggerProvider: loggerProvider,\n        };\n        await plugin?.setup?.(config as BrowserConfig, instance);\n\n        const button = document.createElement('button');\n        document.body.appendChild(button);\n\n        // trigger click event\n        button.dispatchEvent(new Event('click'));\n        button.dispatchEvent(new Event('click'));\n        button.dispatchEvent(new Event('click'));\n        button.dispatchEvent(new Event('click'));\n\n        jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n        expect(track).toHaveBeenCalledTimes(4);\n      });\n\n      // TODO: this will change in the future\n      test('clicking on the same element 5 times should track 6 clicks separately', async () => {\n        const config: Partial<BrowserConfig> = {\n          defaultTracking: false,\n          loggerProvider: loggerProvider,\n        };\n        await plugin?.setup?.(config as BrowserConfig, instance);\n\n        const button = document.createElement('button');\n        document.body.appendChild(button);\n\n        // trigger click event\n        button.dispatchEvent(new Event('click'));\n        button.dispatchEvent(new Event('click'));\n        button.dispatchEvent(new Event('click'));\n        button.dispatchEvent(new Event('click'));\n        button.dispatchEvent(new Event('click'));\n        button.dispatchEvent(new Event('click'));\n\n        jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n        expect(track).toHaveBeenCalledTimes(6);\n      });\n    });\n\n    describe('page view ID handling', () => {\n      // Tests for data-extractor.ts lines 160-170 which use optional chaining\n      // (window?.sessionStorage?.getItem) to safely access sessionStorage\n      test('should not throw error when sessionStorage is deleted', async () => {\n        const config: Partial<BrowserConfig> = {\n          defaultTracking: false,\n          loggerProvider: loggerProvider,\n        };\n        await plugin?.setup?.(config as BrowserConfig, instance);\n\n        // Save original sessionStorage\n        const originalSessionStorage = window.sessionStorage;\n\n        // Delete sessionStorage temporarily - tests window?.sessionStorage when sessionStorage is undefined\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\n        delete (window as any).sessionStorage;\n\n        // trigger click event\n        const link = document.createElement('a');\n        link.setAttribute('id', 'test-link-id');\n        link.setAttribute('class', 'test-link-class');\n        link.href = 'https://www.amplitude.com/test';\n        link.text = 'test-link-text';\n        document.body.appendChild(link);\n\n        document.getElementById('test-link-id')?.dispatchEvent(new Event('click'));\n        jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n        expect(track).toHaveBeenCalledTimes(1);\n        // Verify that page view ID is not included in the event properties\n        expect(track).toHaveBeenNthCalledWith(\n          1,\n          '[Amplitude] Element Clicked',\n          expect.not.objectContaining({\n            '[Amplitude] Page View ID': expect.anything(),\n          }),\n        );\n\n        // Restore sessionStorage\n        window.sessionStorage = originalSessionStorage;\n\n        // Cleanup\n        document.getElementById('test-link-id')?.remove();\n      });\n\n      test('should not throw error when window.sessionStorage is undefined', async () => {\n        const config: Partial<BrowserConfig> = {\n          defaultTracking: false,\n          loggerProvider: loggerProvider,\n        };\n        await plugin?.setup?.(config as BrowserConfig, instance);\n\n        // Save original window.sessionStorage\n        const originalSessionStorage = window.sessionStorage;\n\n        // Set window.sessionStorage to undefined - tests optional chaining when window?.sessionStorage is undefined\n        Object.defineProperty(window, 'sessionStorage', {\n          value: undefined,\n          writable: true,\n          configurable: true,\n        });\n\n        // trigger click event\n        const link = document.createElement('a');\n        link.setAttribute('id', 'test-link-id-2');\n        link.setAttribute('class', 'test-link-class');\n        link.href = 'https://www.amplitude.com/test';\n        link.text = 'test-link-text';\n        document.body.appendChild(link);\n\n        document.getElementById('test-link-id-2')?.dispatchEvent(new Event('click'));\n        jest.advanceTimersByTime(TESTING_DEBOUNCE_TIME + 3);\n\n        expect(track).toHaveBeenCalledTimes(1);\n        // Verify that page view ID is not included in the event properties\n        expect(track).toHaveBeenNthCalledWith(\n          1,\n          '[Amplitude] Element Clicked',\n          expect.not.objectContaining({\n            '[Amplitude] Page View ID': expect.anything(),\n          }),\n        );\n\n        // Restore sessionStorage\n        window.sessionStorage = originalSessionStorage;\n\n        // Cleanup\n        document.getElementById('test-link-id-2')?.remove();\n      });\n    });\n  });\n\n  describe('Viewport Content Updated Tracking', () => {\n    const API_KEY = 'API_KEY';\n    const USER_ID = 'USER_ID';\n\n    let instance = createMockBrowserClient();\n    let track: jest.SpyInstance;\n    let loggerProvider: ILogger;\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    const originalPushState = history.pushState;\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    let intersectionCallback: (entries: any[]) => void;\n\n    beforeEach(async () => {\n      // Ensure navigation API is not present to test fallback (pushState proxy)\n      Object.defineProperty(window, 'navigation', {\n        value: undefined,\n        writable: true,\n        configurable: true,\n      });\n\n      loggerProvider = {\n        log: jest.fn(),\n        warn: jest.fn(),\n        error: jest.fn(),\n        debug: jest.fn(),\n      } as unknown as ILogger;\n\n      // Mock IntersectionObserver\n      (window as any).IntersectionObserver = jest.fn((cb) => {\n        intersectionCallback = cb;\n        return {\n          observe: jest.fn(),\n          disconnect: jest.fn(),\n        };\n      });\n\n      instance = createMockBrowserClient();\n      await instance.init(API_KEY, USER_ID).promise;\n      track = jest.spyOn(instance, 'track').mockImplementation(jest.fn());\n    });\n\n    afterEach(async () => {\n      if (originalPushState) {\n        history.pushState = originalPushState;\n      }\n      (window as any).IntersectionObserver = undefined;\n    });\n\n    test('should track [Amplitude] Viewport Content Updated on beforeunload', async () => {\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n      };\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      window.dispatchEvent(new Event('beforeunload'));\n\n      expect(track).toHaveBeenCalledWith(\n        '[Amplitude] Viewport Content Updated',\n        expect.objectContaining({\n          '[Amplitude] Page URL': expect.any(String),\n          '[Amplitude] Viewport Height': expect.any(Number),\n          '[Amplitude] Viewport Width': expect.any(Number),\n        }),\n      );\n    });\n\n    test('should not track duplicate [Amplitude] Viewport Content Updated events on multiple beforeunload', async () => {\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n      };\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      window.dispatchEvent(new Event('beforeunload'));\n      window.dispatchEvent(new Event('beforeunload'));\n\n      expect(track).toHaveBeenCalledTimes(1);\n    });\n\n    test('should track [Amplitude] Viewport Content Updated on history.pushState and reset state', async () => {\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n      };\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // history.pushState is proxied.\n      history.pushState({}, 'test', '/new-page');\n\n      expect(track).toHaveBeenCalledWith('[Amplitude] Viewport Content Updated', expect.any(Object));\n\n      jest.advanceTimersByTime(1000);\n      //  change scroll depth to trigger a new viewport content updated event\n      Object.defineProperty(window, 'scrollY', { value: 100, writable: true });\n      Object.defineProperty(window, 'pageYOffset', { value: 100, writable: true });\n      window.dispatchEvent(new Event('scroll'));\n\n      // Verify it can fire again (pageViewEndFired should be reset to false by the proxy)\n      history.pushState({}, 'test', '/another-page');\n      expect(track).toHaveBeenCalledTimes(2);\n    });\n\n    test('should track [Amplitude] Viewport Content Updated on popstate event', async () => {\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n      };\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // Simulate popstate event\n      window.dispatchEvent(new Event('popstate'));\n\n      expect(track).toHaveBeenCalledWith('[Amplitude] Viewport Content Updated', expect.any(Object));\n    });\n\n    test('should flush Viewport Content Updated event when exposure buffer limit is reached', async () => {\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n      };\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // Mock finder to avoid DOM dependencies for path generation\n      // We can't easily mock the finder inside the module from here without jest.mock hoisting.\n      // Instead, we rely on elements having IDs which finder uses.\n\n      // We need to trigger exposure for enough unique elements to exceed 18000 chars.\n      // exposedString = JSON.stringify([\"#id1\", \"#id2\", ...])\n      // A simple id like \"#e-1\" is 4 chars. Quotes and comma add 3 chars. ~7 chars per element.\n      // 18000 / 7 = ~2571 elements.\n\n      const entries: any[] = [];\n      const elements: HTMLElement[] = [];\n\n      // Create a batch of elements\n      // Make ids long to reduce iteration count\n      const longIdPrefix = 'e'.repeat(100); // 100 chars\n      const count = 180; // 180 * 100 = 18000.\n\n      for (let i = 0; i < count; i++) {\n        const el = document.createElement('div');\n        el.id = `${longIdPrefix}-${i}`;\n        document.body.appendChild(el);\n        elements.push(el);\n\n        entries.push({\n          isIntersecting: true,\n          intersectionRatio: 1.0,\n          target: el,\n        });\n      }\n\n      // Trigger intersection\n      intersectionCallback(entries);\n\n      // Exposure has a debounce or delay?\n      // trackExposure uses observables which might be async or use internal logic.\n      // trackExposure has an internal buffer/timer.\n      // trackExposure implementation waits for element to be visible for some time (defaults 0?)\n      // Actually trackExposure defaults to 0 debounce/timeout?\n      // Let's check track-exposure.ts logic. It sets a timeout.\n      // We need to advance timers.\n\n      // The default threshold is likely 0 if not configured?\n      // No, trackExposure has hardcoded logic or uses options.\n      // Looking at track-exposure.ts:\n      // It sets a timeout of 2000ms (hardcoded in the file I saw previously?)\n      // Or it reads options?\n\n      // Let's verify with a smaller test first or assume 2s.\n      jest.advanceTimersByTime(2000); // Wait for exposure to be confirmed\n\n      // Now onExposure should be called for each element.\n      // onExposure adds to set and checks size.\n\n      // We expect at least one track call\n      expect(track).toHaveBeenCalledWith('[Amplitude] Viewport Content Updated', expect.any(Object));\n\n      // Cleanup\n      elements.forEach((el) => el.remove());\n    });\n\n    test('should include scroll and exposure state in Viewport Content Updated event', async () => {\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n      };\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // Trigger a scroll to update state\n      Object.defineProperty(window, 'scrollX', { value: 100, writable: true });\n      Object.defineProperty(window, 'scrollY', { value: 200, writable: true });\n      Object.defineProperty(window, 'pageXOffset', { value: 100, writable: true });\n      Object.defineProperty(window, 'pageYOffset', { value: 200, writable: true });\n      window.dispatchEvent(new Event('scroll'));\n\n      // Trigger page view end\n      window.dispatchEvent(new Event('beforeunload'));\n\n      expect(track).toHaveBeenCalledWith(\n        '[Amplitude] Viewport Content Updated',\n        expect.objectContaining({\n          '[Amplitude] Max Page X': 100 + 1024,\n          '[Amplitude] Max Page Y': 200 + 768,\n          '[Amplitude] Element Exposed': expect.any(Array),\n        }),\n      );\n    });\n  });\n\n  describe('teardown', () => {\n    // eslint-disable-next-line jest/expect-expect\n    test('should teardown plugin', () => {\n      void plugin?.teardown?.();\n    });\n  });\n});\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/test/helpers.test.ts",
    "content": "import {\n  isTextNode,\n  isNonSensitiveElement,\n  parseAttributesToMask,\n  isEmpty,\n  removeEmptyProperties,\n  querySelectUniqueElements,\n  getClosestElement,\n  asyncLoadScript,\n  generateUniqueId,\n  createShouldTrackEvent,\n} from '../src/helpers';\nimport { autocapturePlugin } from '../src/autocapture-plugin';\nimport { mockWindowLocationFromURL } from './utils';\nimport { DATA_AMP_MASK_ATTRIBUTES } from '../src/constants';\n\nimport type { ElementInteractionsOptions } from '@amplitude/analytics-core/lib/esm/types/element-interactions';\n\n// Mock implementations for functions that are expected by tests but don't exist in current implementation\nconst getMaskedAttributeNames = (element: Element): Set<string> => {\n  const redactedAttributeNames = new Set<string>();\n  let currentElement: Element | null = element.closest(`[${DATA_AMP_MASK_ATTRIBUTES}]`);\n\n  while (currentElement) {\n    const redactValue = currentElement.getAttribute(DATA_AMP_MASK_ATTRIBUTES);\n    if (redactValue) {\n      const attributesToMask = parseAttributesToMask(redactValue);\n      attributesToMask.forEach((attr) => {\n        redactedAttributeNames.add(attr);\n      });\n    }\n    currentElement = currentElement.parentElement?.closest(`[${DATA_AMP_MASK_ATTRIBUTES}]`) || null;\n  }\n\n  return redactedAttributeNames;\n};\n\n// Mock extractPrefixedAttributes to act like getMaskedAttributeNames for the tests\nconst extractPrefixedAttributes = (element: Element): Set<string> => {\n  return getMaskedAttributeNames(element);\n};\n\ndescribe('autocapture-plugin helpers', () => {\n  afterEach(() => {\n    document.getElementsByTagName('body')[0].innerHTML = '';\n    jest.clearAllMocks();\n  });\n\n  describe('isTextNode', () => {\n    test('should return false when node is not a text node', () => {\n      const node = document.createElement('a');\n      const result = isTextNode(node);\n      expect(result).toEqual(false);\n    });\n\n    test('should return false when node is missing', () => {\n      const node = null;\n      const result = isTextNode(node as unknown as Node);\n      expect(result).toEqual(false);\n    });\n\n    test('should return true when node is a text node', () => {\n      const node = document.createTextNode('text');\n      const result = isTextNode(node);\n      expect(result).toEqual(true);\n    });\n  });\n\n  describe('isNonSensitiveElement', () => {\n    test('should return false when element is a sensitive tag', () => {\n      const element = document.createElement('textarea');\n      const result = isNonSensitiveElement(element);\n      expect(result).toEqual(false);\n    });\n\n    test('should return true when element is a non-sensitive tag', () => {\n      const element = document.createElement('a');\n      const result = isNonSensitiveElement(element);\n      expect(result).toEqual(true);\n    });\n\n    test('should detect contenteditable as a sensitive tag', () => {\n      // Create the SVG element\n      const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n      svg.setAttribute('width', '200');\n      svg.setAttribute('height', '200');\n      svg.setAttribute('viewBox', '0 0 200 200');\n\n      expect(isNonSensitiveElement(svg)).toEqual(true);\n      const element = document.createElement('div');\n      expect(isNonSensitiveElement(element)).toEqual(true);\n\n      element.setAttribute('contenteditable', 'True');\n      expect(isNonSensitiveElement(element)).toEqual(false);\n    });\n  });\n\n  describe('extractPrefixedAttributes', () => {\n    test('should return empty set when no redaction attributes present', () => {\n      const element = document.createElement('div');\n      const result = extractPrefixedAttributes(element);\n      expect(result).toEqual(new Set());\n    });\n\n    test(`should return redacted attributes when ${DATA_AMP_MASK_ATTRIBUTES} is on element itself`, () => {\n      const element = document.createElement('div');\n      element.setAttribute(DATA_AMP_MASK_ATTRIBUTES, 'name, email');\n      const result = extractPrefixedAttributes(element);\n      expect(result).toEqual(new Set(['name', 'email'])); // Should include attributes from element itself\n    });\n\n    test('should collect redacted attributes from element and ancestor elements and exclude id and class', () => {\n      const grandparent = document.createElement('div');\n      grandparent.setAttribute(DATA_AMP_MASK_ATTRIBUTES, 'name, id, class'); // id and class should be ignored\n\n      const parent = document.createElement('div');\n      parent.setAttribute(DATA_AMP_MASK_ATTRIBUTES, 'email, phone');\n\n      const child = document.createElement('span');\n      child.setAttribute(DATA_AMP_MASK_ATTRIBUTES, 'category'); // This should now be included\n\n      grandparent.appendChild(parent);\n      parent.appendChild(child);\n      document.body.appendChild(grandparent);\n\n      const parentResult = extractPrefixedAttributes(parent);\n      expect(parentResult).toEqual(new Set(['name', 'email', 'phone'])); // Includes own attributes plus ancestors\n\n      const result = extractPrefixedAttributes(child);\n      expect(result).toEqual(new Set(['name', 'email', 'phone', 'category'])); // Includes own attributes plus ancestors, id and class excluded\n\n      document.body.removeChild(grandparent);\n    });\n\n    test('should handle whitespace and empty values in redaction list from parent', () => {\n      const parent = document.createElement('div');\n      parent.setAttribute(DATA_AMP_MASK_ATTRIBUTES, ' name , , email , ');\n\n      const element = document.createElement('span');\n      parent.appendChild(element);\n      document.body.appendChild(parent);\n\n      const result = extractPrefixedAttributes(element);\n      expect(result).toEqual(new Set(['name', 'email']));\n\n      document.body.removeChild(parent);\n    });\n\n    test('should handle empty redaction attribute value from parent', () => {\n      const parent = document.createElement('div');\n      parent.setAttribute(DATA_AMP_MASK_ATTRIBUTES, '');\n\n      const element = document.createElement('span');\n      parent.appendChild(element);\n      document.body.appendChild(parent);\n\n      const result = extractPrefixedAttributes(element);\n      expect(result).toEqual(new Set());\n\n      document.body.removeChild(parent);\n    });\n\n    test('should never include id or class in redacted attributes even when specified', () => {\n      const parent = document.createElement('div');\n      parent.setAttribute(DATA_AMP_MASK_ATTRIBUTES, 'id, class, name');\n\n      const element = document.createElement('span');\n      parent.appendChild(element);\n      document.body.appendChild(parent);\n\n      const result = extractPrefixedAttributes(element);\n      expect(result).toEqual(new Set(['name'])); // id and class should be excluded\n      expect(result.has('id')).toBe(false);\n      expect(result.has('class')).toBe(false);\n\n      document.body.removeChild(parent);\n    });\n  });\n\n  describe('isEmpty', () => {\n    test('should return true when value is undefined', () => {\n      const result = isEmpty(undefined);\n      expect(result).toEqual(true);\n    });\n\n    test('should return true when value is null', () => {\n      const result = isEmpty(null);\n      expect(result).toEqual(true);\n    });\n\n    test('should return true when value is empty array', () => {\n      const result = isEmpty([]);\n      expect(result).toEqual(true);\n    });\n\n    test('should return true when value is empty object', () => {\n      const result = isEmpty({});\n      expect(result).toEqual(true);\n    });\n\n    test('should return true when value is empty string', () => {\n      const result = isEmpty('');\n      expect(result).toEqual(true);\n    });\n\n    test('should return true when value is string with spaces only', () => {\n      const result = isEmpty('  ');\n      expect(result).toEqual(true);\n    });\n\n    test('should return false when value is array', () => {\n      const result = isEmpty([1, 2]);\n      expect(result).toEqual(false);\n    });\n\n    test('should return false when value is object', () => {\n      const result = isEmpty({ x: 1 });\n      expect(result).toEqual(false);\n    });\n\n    test('should return false when value is string', () => {\n      const result = isEmpty('xxx');\n      expect(result).toEqual(false);\n    });\n  });\n\n  describe('removeEmptyProperties', () => {\n    test('should filter out empty properties', () => {\n      const result = removeEmptyProperties({\n        x: 1,\n        y: [1],\n        z: { z: 1 },\n        w: 'w',\n        a: undefined,\n        b: [],\n        c: {},\n        d: '  ',\n        e: null,\n      });\n      expect(result).toEqual({\n        x: 1,\n        y: [1],\n        z: { z: 1 },\n        w: 'w',\n      });\n    });\n  });\n\n  describe('querySelectUniqueElements', () => {\n    test('should return unique elements with selector under root', () => {\n      const container = document.createElement('div');\n\n      const div1 = document.createElement('div');\n      div1.className = 'test-class';\n      container.appendChild(div1);\n      const div2 = document.createElement('div');\n      container.appendChild(div2);\n\n      let result = querySelectUniqueElements(container, ['div']);\n      expect(result).toEqual([div1, div2]);\n\n      // elements should be deduped\n      result = querySelectUniqueElements(container, ['div', '.test-class']);\n      expect(result).toEqual([div1, div2]);\n    });\n\n    test('should return empty array with root not available', () => {\n      const result = querySelectUniqueElements(null as unknown as Element, ['div']);\n      expect(result).toEqual([]);\n    });\n  });\n\n  describe('getClosestElement', () => {\n    test('should return null when element null', () => {\n      expect(getClosestElement(null, ['div'])).toEqual(null);\n    });\n\n    test('should return current element if it matches any selectors', () => {\n      document.getElementsByTagName('body')[0].innerHTML = `\n        <div id=\"container\">\n          <div id=\"inner\">\n            xxx\n          </div>\n        </div>\n      `;\n\n      const inner = document.getElementById('inner');\n      expect(getClosestElement(inner, ['span', 'div'])?.getAttribute('id')).toEqual('inner');\n    });\n\n    test('should return closest element if it matches any selectors', () => {\n      document.getElementsByTagName('body')[0].innerHTML = `\n        <div id=\"parent2\" data-target>\n          <div id=\"parent1-sibling\" data-target>\n          </div>\n          <div id=\"parent1\">\n            <div id=\"inner\">\n              xxx\n            </div>\n          </div>\n        </div>\n      `;\n\n      const inner = document.getElementById('inner');\n      expect(getClosestElement(inner, ['span', '[data-target]'])?.getAttribute('id')).toEqual('parent2');\n    });\n\n    test('should return null when no element matches', () => {\n      document.getElementsByTagName('body')[0].innerHTML = `\n        <div id=\"parent2\">\n          <div id=\"parent1\">\n            <div id=\"inner\">\n              xxx\n            </div>\n          </div>\n        </div>\n      `;\n\n      const inner = document.getElementById('inner');\n      expect(getClosestElement(inner, ['div.some-class'])).toEqual(null);\n    });\n  });\n\n  describe('asyncLoadScript', () => {\n    test('should append the script to document and resolve with status true', () => {\n      void asyncLoadScript('https://test-url.amplitude/').then((result) => {\n        expect(result).toEqual({ status: true });\n      });\n      const script = document.getElementsByTagName('script')[0];\n      expect(document.getElementsByTagName('script')[0].src).toEqual('https://test-url.amplitude/');\n\n      script.dispatchEvent(new Event('load'));\n    });\n\n    test('should reject with status false when error', () => {\n      void asyncLoadScript('https://test-url.amplitude/').then(\n        () => {\n          expect('should not be called').toEqual(true);\n        },\n        (result) => {\n          expect(result).toEqual({\n            status: false,\n            message: 'Failed to load the script https://test-url.amplitude/',\n          });\n        },\n      );\n      const script = document.getElementsByTagName('script')[0];\n      expect(document.getElementsByTagName('script')[0].src).toEqual('https://test-url.amplitude/');\n\n      script.dispatchEvent(new Event('error'));\n    });\n  });\n\n  describe('generateUniqueId', () => {\n    test('should return a unique id', () => {\n      const id1 = generateUniqueId();\n      const id2 = generateUniqueId();\n      expect(id1).not.toEqual(id2);\n\n      // Test random characters in second part of the id\n      const randomChar1 = id1.split('-')[1];\n      const randomChar2 = id2.split('-')[1];\n      expect(randomChar1).not.toEqual(randomChar2);\n    });\n  });\n\n  describe('pageUrlExcludelist processing', () => {\n    let consoleWarnSpy: jest.SpyInstance;\n\n    beforeEach(() => {\n      consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation();\n    });\n\n    afterEach(() => {\n      jest.restoreAllMocks();\n    });\n\n    describe('string values', () => {\n      test('should process string values correctly', () => {\n        const options: ElementInteractionsOptions = {\n          pageUrlExcludelist: ['https://example.com', 'https://test.com/admin'],\n        };\n\n        autocapturePlugin(options);\n\n        // Verify that string values are preserved in the processed array\n        expect(options.pageUrlExcludelist).toEqual(['https://example.com', 'https://test.com/admin']);\n      });\n\n      test('should handle empty string values', () => {\n        const options: ElementInteractionsOptions = {\n          pageUrlExcludelist: ['', 'https://example.com', ''],\n        };\n\n        autocapturePlugin(options);\n\n        // Empty strings should still be included\n        expect(options.pageUrlExcludelist).toEqual(['', 'https://example.com', '']);\n      });\n    });\n\n    describe('RegExp instances', () => {\n      test('should process RegExp instances correctly', () => {\n        const regex1 = new RegExp('https://example\\\\.com');\n        const regex2 = /https:\\/\\/test\\.com\\/admin/;\n\n        const options: ElementInteractionsOptions = {\n          pageUrlExcludelist: [regex1, regex2],\n        };\n\n        autocapturePlugin(options);\n\n        // Verify that RegExp instances are preserved\n        expect(options.pageUrlExcludelist).toEqual([regex1, regex2]);\n      });\n\n      test('should handle mix of strings and RegExp instances', () => {\n        const regex = new RegExp('https://example\\\\.com');\n\n        const options: ElementInteractionsOptions = {\n          pageUrlExcludelist: ['https://test.com', regex, 'https://admin.com'],\n        };\n\n        autocapturePlugin(options);\n\n        expect(options.pageUrlExcludelist).toEqual(['https://test.com', regex, 'https://admin.com']);\n      });\n    });\n\n    describe('regex pattern objects', () => {\n      test('should convert pattern objects to RegExp instances', () => {\n        const options: ElementInteractionsOptions = {\n          pageUrlExcludelist: [{ pattern: 'https://example\\\\.com' }, { pattern: 'https://test\\\\.com/admin.*' }],\n        };\n\n        autocapturePlugin(options);\n\n        // Verify that pattern objects are converted to RegExp instances\n        expect(options.pageUrlExcludelist).toHaveLength(2);\n        expect(options.pageUrlExcludelist?.[0]).toBeInstanceOf(RegExp);\n        expect(options.pageUrlExcludelist?.[1]).toBeInstanceOf(RegExp);\n        expect((options.pageUrlExcludelist?.[0] as RegExp).source).toBe('https:\\\\/\\\\/example\\\\.com');\n        expect((options.pageUrlExcludelist?.[1] as RegExp).source).toBe('https:\\\\/\\\\/test\\\\.com\\\\/admin.*');\n      });\n\n      test('should handle mix of all supported types', () => {\n        const regex = new RegExp('existing-regex');\n\n        const options: ElementInteractionsOptions = {\n          pageUrlExcludelist: ['https://string.com', regex, { pattern: 'https://pattern\\\\.com' }, 'another-string'],\n        };\n\n        autocapturePlugin(options);\n\n        expect(options.pageUrlExcludelist).toHaveLength(4);\n        expect(options.pageUrlExcludelist?.[0]).toBe('https://string.com');\n        expect(options.pageUrlExcludelist?.[1]).toBe(regex);\n        expect(options.pageUrlExcludelist?.[2]).toBeInstanceOf(RegExp);\n        expect((options.pageUrlExcludelist?.[2] as RegExp).source).toBe('https:\\\\/\\\\/pattern\\\\.com');\n        expect(options.pageUrlExcludelist?.[3]).toBe('another-string');\n      });\n    });\n\n    describe('invalid regex patterns', () => {\n      test('should handle invalid regex patterns gracefully and log warning', () => {\n        const options: ElementInteractionsOptions = {\n          pageUrlExcludelist: [\n            'https://valid.com',\n            { pattern: '[invalid-regex' }, // Invalid regex - unclosed bracket\n            'https://another-valid.com',\n          ],\n        };\n\n        autocapturePlugin(options);\n\n        // Verify that warning was logged\n        expect(consoleWarnSpy).toHaveBeenCalledWith('Invalid regex pattern: [invalid-regex', expect.any(Error));\n\n        // Verify that valid items are still processed and invalid ones are skipped\n        expect(options.pageUrlExcludelist).toEqual(['https://valid.com', 'https://another-valid.com']);\n      });\n\n      test('should handle multiple invalid regex patterns', () => {\n        const options: ElementInteractionsOptions = {\n          pageUrlExcludelist: [\n            { pattern: '[invalid1' },\n            'https://valid.com',\n            { pattern: '*invalid2' },\n            { pattern: 'valid\\\\.pattern' },\n          ],\n        };\n\n        autocapturePlugin(options);\n\n        // Verify that warnings were logged for both invalid patterns\n        expect(consoleWarnSpy).toHaveBeenCalledTimes(2);\n        expect(consoleWarnSpy).toHaveBeenNthCalledWith(1, 'Invalid regex pattern: [invalid1', expect.any(Error));\n        expect(consoleWarnSpy).toHaveBeenNthCalledWith(2, 'Invalid regex pattern: *invalid2', expect.any(Error));\n\n        // Valid items should still be processed\n        expect(options.pageUrlExcludelist).toHaveLength(2);\n        expect(options.pageUrlExcludelist?.[0]).toBe('https://valid.com');\n        expect(options.pageUrlExcludelist?.[1]).toBeInstanceOf(RegExp);\n        expect((options.pageUrlExcludelist?.[1] as RegExp).source).toBe('valid\\\\.pattern');\n      });\n    });\n\n    describe('edge cases', () => {\n      test('should handle undefined pageUrlExcludelist', () => {\n        const options: ElementInteractionsOptions = {\n          pageUrlExcludelist: undefined,\n        };\n\n        autocapturePlugin(options);\n\n        // Should remain undefined\n        expect(options.pageUrlExcludelist).toBeUndefined();\n        expect(consoleWarnSpy).not.toHaveBeenCalled();\n      });\n\n      test('should handle empty pageUrlExcludelist array', () => {\n        const options: ElementInteractionsOptions = {\n          pageUrlExcludelist: [],\n        };\n\n        autocapturePlugin(options);\n\n        // Should result in empty array\n        expect(options.pageUrlExcludelist).toEqual([]);\n        expect(consoleWarnSpy).not.toHaveBeenCalled();\n      });\n\n      test('should handle array with only invalid regex patterns', () => {\n        const options: ElementInteractionsOptions = {\n          pageUrlExcludelist: [{ pattern: '[invalid1' }, { pattern: '*invalid2' }],\n        };\n\n        autocapturePlugin(options);\n\n        // Should result in empty array since all patterns were invalid\n        expect(options.pageUrlExcludelist).toEqual([]);\n        expect(consoleWarnSpy).toHaveBeenCalledTimes(2);\n      });\n\n      test('should handle objects without pattern property', () => {\n        const options: ElementInteractionsOptions = {\n          pageUrlExcludelist: [\n            'https://valid.com',\n            { notPattern: 'some-value' } as any, // Object without 'pattern' property\n            'https://another-valid.com',\n          ],\n        };\n\n        autocapturePlugin(options);\n\n        // Objects without 'pattern' property should be ignored\n        expect(options.pageUrlExcludelist).toEqual(['https://valid.com', 'https://another-valid.com']);\n        expect(consoleWarnSpy).not.toHaveBeenCalled();\n      });\n\n      test('should handle objects with empty pattern', () => {\n        const options: ElementInteractionsOptions = {\n          pageUrlExcludelist: ['https://valid.com', { pattern: '' }, 'https://another-valid.com'],\n        };\n\n        autocapturePlugin(options);\n\n        // Empty pattern should create a valid regex\n        expect(options.pageUrlExcludelist).toHaveLength(3);\n        expect(options.pageUrlExcludelist?.[0]).toBe('https://valid.com');\n        expect(options.pageUrlExcludelist?.[1]).toBeInstanceOf(RegExp);\n        expect((options.pageUrlExcludelist?.[1] as RegExp).source).toBe('(?:)');\n        expect(options.pageUrlExcludelist?.[2]).toBe('https://another-valid.com');\n        expect(consoleWarnSpy).not.toHaveBeenCalled();\n      });\n    });\n\n    describe('type safety', () => {\n      test('should handle various falsy values gracefully', () => {\n        const options: ElementInteractionsOptions = {\n          pageUrlExcludelist: [\n            'https://valid.com',\n            null as any,\n            undefined as any,\n            false as any,\n            0 as any,\n            'https://another-valid.com',\n          ],\n        };\n\n        autocapturePlugin(options);\n\n        // Only string and valid types should be preserved\n        expect(options.pageUrlExcludelist).toEqual(['https://valid.com', 'https://another-valid.com']);\n        expect(consoleWarnSpy).not.toHaveBeenCalled();\n      });\n\n      test('should handle numbers and other primitive types', () => {\n        const options: ElementInteractionsOptions = {\n          pageUrlExcludelist: [\n            'https://valid.com',\n            123 as any,\n            true as any,\n            Symbol('test') as any,\n            'https://another-valid.com',\n          ],\n        };\n\n        autocapturePlugin(options);\n\n        // Only string types should be preserved\n        expect(options.pageUrlExcludelist).toEqual(['https://valid.com', 'https://another-valid.com']);\n        expect(consoleWarnSpy).not.toHaveBeenCalled();\n      });\n    });\n  });\n\n  describe('createShouldTrackEvent', () => {\n    test('should not fail when given window as element', () => {\n      const shouldTrackEvent = createShouldTrackEvent({}, ['div']);\n\n      expect(shouldTrackEvent('click', window as unknown as Element)).toEqual(false);\n      expect(shouldTrackEvent('click', document as unknown as Element)).toEqual(false);\n    });\n\n    test('should track any element with pointer cursor when isAlwaysCaptureCursorPointer is true', () => {\n      const element = document.createElement('div');\n      const style = document.createElement('style');\n      style.textContent = '.pointer { cursor: pointer; }';\n      document.head.appendChild(style);\n      element.className = 'pointer';\n\n      const shouldTrackEvent = createShouldTrackEvent(\n        {\n          pageUrlAllowlist: undefined,\n          shouldTrackEventResolver: undefined,\n        },\n        [],\n        true, // isAlwaysCaptureCursorPointer\n      );\n\n      expect(shouldTrackEvent('click', element)).toEqual(true);\n      document.head.removeChild(style);\n    });\n\n    test('should respect pageUrlExcludelist configuration', () => {\n      // Mock window.location to a test URL\n      mockWindowLocationFromURL(new URL('https://www.test.com/page'));\n\n      const element = document.createElement('button');\n      element.textContent = 'Click me';\n\n      const shouldTrackEvent = createShouldTrackEvent(\n        {\n          pageUrlExcludelist: [new RegExp('https://www.test.com')],\n        },\n        ['button'],\n      );\n\n      expect(shouldTrackEvent('click', element)).toEqual(true);\n    });\n\n    test('should allow tracking when URL does not match excludelist', () => {\n      // Mock window.location to a different URL\n      mockWindowLocationFromURL(new URL('https://www.different.com/page'));\n\n      const element = document.createElement('button');\n      element.textContent = 'Click me';\n\n      const shouldTrackEvent = createShouldTrackEvent(\n        {\n          pageUrlExcludelist: [new RegExp('https://www.test.com')],\n        },\n        ['button'],\n      );\n\n      expect(shouldTrackEvent('click', element)).toEqual(true);\n    });\n\n    test('should prioritize excludelist over allowlist', () => {\n      // Mock window.location to a URL that matches both lists\n      mockWindowLocationFromURL(new URL('https://www.test.com/page'));\n\n      const element = document.createElement('button');\n      element.textContent = 'Click me';\n\n      const shouldTrackEvent = createShouldTrackEvent(\n        {\n          pageUrlAllowlist: [new RegExp('https://www.test.com')],\n          pageUrlExcludelist: [new RegExp('https://www.test.com')],\n        },\n        ['button'],\n      );\n\n      expect(shouldTrackEvent('click', element)).toEqual(false);\n    });\n\n    test('should allow tracking when pageUrlExcludelist is empty', () => {\n      // Mock window.location to any URL\n      mockWindowLocationFromURL(new URL('https://www.example.com/page'));\n\n      const element = document.createElement('button');\n      element.textContent = 'Click me';\n\n      const shouldTrackEvent = createShouldTrackEvent(\n        {\n          pageUrlExcludelist: [], // Empty excludelist should not block any URLs\n        },\n        ['button'],\n      );\n\n      expect(shouldTrackEvent('click', element)).toEqual(true);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/test/hierarchy.test.ts",
    "content": "import * as HierarchyUtil from '../src/hierarchy';\nimport { DATA_AMP_MASK_ATTRIBUTES } from '../src/constants';\n\ndescribe('autocapture-plugin hierarchy', () => {\n  afterEach(() => {\n    document.getElementsByTagName('body')[0].innerHTML = '';\n    jest.clearAllMocks();\n  });\n\n  describe('getElementProperties', () => {\n    test('should return null when element is null', () => {\n      document.getElementsByTagName('body')[0].innerHTML = `\n        <div id=\"parent2\">\n          <div id=\"parent1\">\n            <div id=\"inner\">\n              xxx\n            </div>\n          </div>\n        </div>\n      `;\n\n      const nullElement = document.getElementById('null-element');\n      expect(HierarchyUtil.getElementProperties(nullElement, new Set())).toEqual(null);\n    });\n\n    test('should return tag and index information if element has siblings', () => {\n      document.getElementsByTagName('body')[0].innerHTML = `\n        <div id=\"container\">\n          <div id=\"inner\">\n            xxx\n          </div>\n          <div id=\"inner2\">\n            xxx\n          </div>\n          <a id=\"inner3\">\n            xxx\n          </a>\n          <a id=\"inner4\">\n            xxx\n          </a>\n        </div>\n      `;\n\n      const inner4 = document.getElementById('inner4');\n      expect(HierarchyUtil.getElementProperties(inner4, new Set())).toEqual({\n        id: 'inner4',\n        index: 3,\n        indexOfType: 1,\n        prevSib: 'a',\n        tag: 'a',\n      });\n    });\n\n    test('should not return prevSib if it has no previous siblings', () => {\n      document.getElementsByTagName('body')[0].innerHTML = `\n        <div id=\"container\">\n          <div id=\"inner\">\n            xxx\n          </div>\n          <div id=\"inner2\">\n            xxx\n          </div>\n        </div>\n      `;\n\n      const inner = document.getElementById('inner');\n      expect(HierarchyUtil.getElementProperties(inner, new Set())).toEqual({\n        id: 'inner',\n        index: 0,\n        indexOfType: 0,\n        tag: 'div',\n      });\n    });\n\n    test('should return effective class list correctly', () => {\n      document.getElementsByTagName('body')[0].innerHTML = `\n        <div id=\"container\">\n          <div id=\"inner\" class=\"class1 class2 class2\">\n            xxx\n          </div>\n        </div>\n      `;\n\n      const inner = document.getElementById('inner');\n      expect(HierarchyUtil.getElementProperties(inner, new Set())).toEqual({\n        id: 'inner',\n        index: 0,\n        indexOfType: 0,\n        tag: 'div',\n        classes: ['class1', 'class2'],\n      });\n    });\n  });\n\n  test('should not fail when parent element is null', () => {\n    const parentlessElement = document.createElement('div');\n\n    expect(HierarchyUtil.getElementProperties(parentlessElement, new Set())).toEqual({\n      tag: 'div',\n    });\n  });\n\n  describe('should filter out attributes', () => {\n    test('should filter out blocked attributes', () => {\n      document.getElementsByTagName('body')[0].innerHTML = `\n      <div id=\"target\" style=\"background-color:#fff;\" ok-attribute=\"hi\"></div>\n    `;\n\n      const target = document.getElementById('target');\n      expect(HierarchyUtil.getElementProperties(target, new Set())).toEqual({\n        id: 'target',\n        index: 0,\n        indexOfType: 0,\n        tag: 'div',\n        attrs: {\n          'ok-attribute': 'hi',\n        },\n      });\n    });\n\n    test('should filter out all non whitelisted attributes from sensitive elements', () => {\n      document.getElementsByTagName('body')[0].innerHTML = `\n      <input id=\"target\" type=\"checkbox\" style=\"background-color:#fff;\" ok-attribute=\"hi\"></input>\n    `;\n\n      const target = document.getElementById('target');\n      expect(HierarchyUtil.getElementProperties(target, new Set())).toEqual({\n        id: 'target',\n        index: 0,\n        indexOfType: 0,\n        tag: 'input',\n        attrs: {\n          type: 'checkbox',\n        },\n      });\n    });\n\n    test('should filter out all attributes from highly sensitive elements', () => {\n      document.getElementsByTagName('body')[0].innerHTML = `\n      <input id=\"target\" class=\"test\" type=\"password\" ok-attribute=\"hi\"></input>\n    `;\n\n      const target = document.getElementById('target');\n      expect(HierarchyUtil.getElementProperties(target, new Set())).toEqual({\n        id: 'target',\n        index: 0,\n        indexOfType: 0,\n        tag: 'input',\n        classes: ['test'],\n      });\n    });\n\n    test('should discard attributes for svg-related elements', () => {\n      document.getElementsByTagName('body')[0].innerHTML = `\n      <svg id=\"target\" class=\"test\" ok-attribute=\"hi\"></svg>\n    `;\n\n      const target = document.getElementById('target');\n      expect(HierarchyUtil.getElementProperties(target, new Set())).toEqual({\n        id: 'target',\n        index: 0,\n        indexOfType: 0,\n        tag: 'svg',\n        classes: ['test'],\n      });\n    });\n\n    test(`should not capture ${DATA_AMP_MASK_ATTRIBUTES} in getElementProperties for regular elements`, () => {\n      document.getElementsByTagName('body')[0].innerHTML = `\n      <div id=\"target\" ${DATA_AMP_MASK_ATTRIBUTES}=\"custom-attr,another-attr\" custom-attr=\"secret\" another-attr=\"hidden\" ok-attribute=\"visible\"></div>\n    `;\n\n      const target = document.getElementById('target');\n      expect(HierarchyUtil.getElementProperties(target, new Set())).toEqual({\n        id: 'target',\n        index: 0,\n        indexOfType: 0,\n        tag: 'div',\n        attrs: {\n          'custom-attr': 'secret',\n          'another-attr': 'hidden',\n          'ok-attribute': 'visible',\n        },\n      });\n    });\n\n    test(`should not include ${DATA_AMP_MASK_ATTRIBUTES} in getElementProperties`, () => {\n      document.getElementsByTagName('body')[0].innerHTML = `\n      <div id=\"target\" ${DATA_AMP_MASK_ATTRIBUTES}=\"custom-attr\" custom-attr=\"secret\" other-attr=\"visible\"></div>\n    `;\n\n      const target = document.getElementById('target');\n\n      // getElementProperties should not include DATA_AMP_MASK_ATTRIBUTES\n      const elementProps = HierarchyUtil.getElementProperties(target, new Set());\n      expect(elementProps?.attrs?.[DATA_AMP_MASK_ATTRIBUTES]).toBeUndefined();\n    });\n  });\n});\n\ndescribe('getAncestors', () => {\n  test('should return a list starting from the target element', () => {\n    document.getElementsByTagName('body')[0].innerHTML = `\n      <div id=\"parent2\">\n        <div id=\"parent1\">\n          <div id=\"inner\">\n            xxx\n          </div>\n        </div>\n      </div>\n    `;\n\n    const inner = document.getElementById('inner');\n    expect(HierarchyUtil.getAncestors(inner)).toEqual([\n      inner,\n      document.getElementById('parent1'),\n      document.getElementById('parent2'),\n      document.body,\n    ]);\n  });\n\n  test('should not fail when element is null', () => {\n    const nullElement = null;\n    expect(HierarchyUtil.getAncestors(nullElement)).toEqual([]);\n  });\n\n  // Note: getHierarchy has been moved to data-extractor.test.ts\n  // as it is now an instance method of DataExtractor\n});\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/test/mock-browser-client.ts",
    "content": "import { BrowserClient } from '@amplitude/analytics-core';\n\n// Mock BrowserClient implementation\nexport const createMockBrowserClient = (): jest.Mocked<BrowserClient> => {\n  const mockClient = {\n    init: jest.fn(),\n    add: jest.fn(),\n    remove: jest.fn(),\n    track: jest.fn(),\n    logEvent: jest.fn(),\n    identify: jest.fn(),\n    groupIdentify: jest.fn(),\n    setGroup: jest.fn(),\n    revenue: jest.fn(),\n    flush: jest.fn(),\n    getUserId: jest.fn(),\n    setUserId: jest.fn(),\n    getDeviceId: jest.fn(),\n    setDeviceId: jest.fn(),\n    getSessionId: jest.fn(),\n    setSessionId: jest.fn(),\n    extendSession: jest.fn(),\n    reset: jest.fn(),\n    setOptOut: jest.fn(),\n    setTransport: jest.fn(),\n    getOptOut: jest.fn(),\n    getIdentity: jest.fn(),\n    setIdentity: jest.fn(),\n    _setDiagnosticsSampleRate: jest.fn(),\n  } as jest.Mocked<BrowserClient>;\n\n  // Set up default return values for methods that return promises\n  mockClient.init.mockReturnValue({\n    promise: Promise.resolve(),\n  });\n\n  mockClient.track.mockReturnValue({\n    promise: Promise.resolve({\n      code: 200,\n      message: '',\n      event: {\n        event_type: '[Amplitude] Element Clicked',\n      },\n    }),\n  });\n\n  return mockClient;\n};\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/test/observable.test.ts",
    "content": "import { createExposureObservable } from '../src/observables';\nimport { Observable } from '@amplitude/analytics-core';\nimport { TimestampedEvent } from '../src/helpers';\n\ndescribe('createExposureObservable', () => {\n  let mutationObservable: Observable<TimestampedEvent<MutationRecord[]>>;\n  let mockMutationObserver: { subscribe: jest.Mock };\n  let mockIntersectionObserver: { observe: jest.Mock; disconnect: jest.Mock };\n  let intersectionCallback: (entries: IntersectionObserverEntry[]) => void;\n  let observers: ((value: TimestampedEvent<MutationRecord[]>) => void)[] = [];\n\n  beforeEach(() => {\n    observers = [];\n    // Mock Mutation Observable\n    mockMutationObserver = {\n      subscribe: jest.fn((cb) => {\n        observers.push(cb);\n        return { unsubscribe: jest.fn() };\n      }),\n    };\n    mutationObservable = mockMutationObserver as unknown as Observable<TimestampedEvent<MutationRecord[]>>;\n\n    // Mock IntersectionObserver\n    mockIntersectionObserver = {\n      observe: jest.fn(),\n      disconnect: jest.fn(),\n    };\n\n    (global as any).IntersectionObserver = jest.fn((cb) => {\n      intersectionCallback = cb;\n      return mockIntersectionObserver;\n    });\n\n    document.body.innerHTML = '';\n  });\n\n  afterEach(() => {\n    document.body.innerHTML = '';\n    jest.clearAllMocks();\n  });\n\n  test('should observe initial elements matching the allowlist', () => {\n    const div = document.createElement('div');\n    div.className = 'track-me';\n    document.body.appendChild(div);\n\n    const exposureObservable = createExposureObservable(mutationObservable, ['.track-me']);\n    exposureObservable.subscribe(() => {\n      return;\n    });\n\n    expect(mockIntersectionObserver.observe).toHaveBeenCalledWith(div);\n  });\n\n  test('should emit event when element intersects (visible)', () => {\n    const div = document.createElement('div');\n    document.body.appendChild(div);\n    const listener = jest.fn();\n\n    const exposureObservable = createExposureObservable(mutationObservable, ['div']);\n    exposureObservable.subscribe(listener);\n\n    // Simulate intersection\n    const entry = {\n      isIntersecting: true,\n      intersectionRatio: 1.0,\n      target: div,\n    } as unknown as IntersectionObserverEntry;\n\n    intersectionCallback([entry]);\n\n    expect(listener).toHaveBeenCalledWith(entry);\n  });\n\n  test('should emit event when element leaves viewport (invisible)', () => {\n    const div = document.createElement('div');\n    document.body.appendChild(div);\n    const listener = jest.fn();\n\n    const exposureObservable = createExposureObservable(mutationObservable, ['div']);\n    exposureObservable.subscribe(listener);\n\n    // Simulate leaving viewport\n    const entry = {\n      isIntersecting: false,\n      intersectionRatio: 0.5,\n      target: div,\n    } as unknown as IntersectionObserverEntry;\n\n    intersectionCallback([entry]);\n\n    expect(listener).toHaveBeenCalledWith(entry);\n  });\n\n  test('should observe new elements added via mutation that match allowlist', () => {\n    const exposureObservable = createExposureObservable(mutationObservable, ['div']);\n    exposureObservable.subscribe(() => {\n      return;\n    });\n\n    // Simulate mutation adding a node\n    const newDiv = document.createElement('div');\n    const mutationRecord = {\n      addedNodes: [newDiv] as unknown as NodeList,\n    } as MutationRecord;\n\n    // Trigger mutation subscription callback\n    observers.forEach((cb) => {\n      cb({\n        event: [mutationRecord],\n        timestamp: Date.now(),\n        type: 'mutation',\n      });\n    });\n\n    expect(mockIntersectionObserver.observe).toHaveBeenCalledWith(newDiv);\n  });\n\n  test('should NOT observe new elements added via mutation that do not match allowlist', () => {\n    const exposureObservable = createExposureObservable(mutationObservable, ['.track-me']);\n    exposureObservable.subscribe(() => {\n      return;\n    });\n\n    // Reset observe calls from initial querySelectorAll\n    mockIntersectionObserver.observe.mockClear();\n\n    const newSpan = document.createElement('span');\n    const mutationRecord = {\n      addedNodes: [newSpan] as unknown as NodeList,\n    } as MutationRecord;\n\n    observers.forEach((cb) => {\n      cb({\n        event: [mutationRecord],\n        timestamp: Date.now(),\n        type: 'mutation',\n      });\n    });\n\n    expect(mockIntersectionObserver.observe).not.toHaveBeenCalled();\n  });\n\n  test('should observe matching descendants within added mutation nodes', () => {\n    const exposureObservable = createExposureObservable(mutationObservable, ['.track-me']);\n    exposureObservable.subscribe(() => {\n      return;\n    });\n\n    mockIntersectionObserver.observe.mockClear();\n\n    // Container div that doesn't match, but has a child that does\n    const container = document.createElement('div');\n    const matchingChild = document.createElement('span');\n    matchingChild.className = 'track-me';\n    container.appendChild(matchingChild);\n\n    const mutationRecord = {\n      addedNodes: [container] as unknown as NodeList,\n    } as MutationRecord;\n\n    observers.forEach((cb) => {\n      cb({\n        event: [mutationRecord],\n        timestamp: Date.now(),\n        type: 'mutation',\n      });\n    });\n\n    // Container doesn't match, but its child does\n    expect(mockIntersectionObserver.observe).not.toHaveBeenCalledWith(container);\n    expect(mockIntersectionObserver.observe).toHaveBeenCalledWith(matchingChild);\n  });\n\n  test('should skip non-Element nodes added via mutation', () => {\n    const exposureObservable = createExposureObservable(mutationObservable, ['div']);\n    exposureObservable.subscribe(() => {\n      return;\n    });\n\n    mockIntersectionObserver.observe.mockClear();\n\n    const textNode = document.createTextNode('hello');\n    const mutationRecord = {\n      addedNodes: [textNode] as unknown as NodeList,\n    } as MutationRecord;\n\n    observers.forEach((cb) => {\n      cb({\n        event: [mutationRecord],\n        timestamp: Date.now(),\n        type: 'mutation',\n      });\n    });\n\n    expect(mockIntersectionObserver.observe).not.toHaveBeenCalled();\n  });\n\n  test('should disconnect observer on unsubscribe', () => {\n    const exposureObservable = createExposureObservable(mutationObservable, ['div']);\n    const subscription = exposureObservable.subscribe(() => {\n      return;\n    });\n\n    subscription.unsubscribe();\n\n    expect(mockIntersectionObserver.disconnect).toHaveBeenCalled();\n  });\n\n  test('should handle missing IntersectionObserver support gracefully', () => {\n    const originalIntersectionObserver = (global as any).IntersectionObserver;\n    (global as any).IntersectionObserver = undefined;\n\n    const exposureObservable = createExposureObservable(mutationObservable, ['div']);\n    const subscription = exposureObservable.subscribe(() => {\n      return;\n    });\n\n    subscription.unsubscribe();\n    (global as any).IntersectionObserver = originalIntersectionObserver;\n  });\n});\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/test/observables-coverage.test.ts",
    "content": "import { Observable, getGlobalScope } from '@amplitude/analytics-core';\nimport { TimestampedEvent } from '../src/helpers';\n\njest.mock('@amplitude/analytics-core', () => {\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n  const actual = jest.requireActual('@amplitude/analytics-core');\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n  return {\n    ...actual,\n    getGlobalScope: jest.fn(),\n  };\n});\n\nconst mockGetGlobalScope = getGlobalScope as jest.Mock;\n\nimport {\n  createClickObservable,\n  createScrollObservable,\n  createMutationObservable,\n  createExposureObservable,\n} from '../src/observables';\n\ndescribe('Observables Coverage', () => {\n  beforeEach(() => {\n    jest.clearAllMocks();\n  });\n\n  describe('when getGlobalScope returns undefined', () => {\n    beforeEach(() => {\n      mockGetGlobalScope.mockReturnValue(undefined);\n    });\n\n    test('createClickObservable should handle undefined global scope safely', () => {\n      const observable = createClickObservable();\n      const subscription = observable.subscribe(() => {\n        return;\n      });\n      subscription.unsubscribe();\n      // Should not throw\n      expect(mockGetGlobalScope).toHaveBeenCalled();\n    });\n\n    test('createScrollObservable should handle undefined global scope safely', () => {\n      const observable = createScrollObservable();\n      const subscription = observable.subscribe(() => {\n        return;\n      });\n      subscription.unsubscribe();\n      // Should not throw\n      expect(mockGetGlobalScope).toHaveBeenCalled();\n    });\n\n    test('createExposureObservable should handle undefined global scope safely', () => {\n      const mutationObservable = new Observable<TimestampedEvent<MutationRecord[]>>(() => {\n        return;\n      });\n      const observable = createExposureObservable(mutationObservable, ['div']);\n      const subscription = observable.subscribe(() => {\n        return;\n      });\n      subscription.unsubscribe();\n      // Should not throw\n      expect(mockGetGlobalScope).toHaveBeenCalled();\n    });\n  });\n\n  describe('createMutationObservable', () => {\n    test('should handle missing document.body safely', () => {\n      // Save original body\n      const originalBody = document.body;\n      // Delete body\n      Object.defineProperty(document, 'body', { value: null, configurable: true });\n\n      mockGetGlobalScope.mockReturnValue(window); // Ensure global scope is present\n\n      const observable = createMutationObservable();\n      const subscription = observable.subscribe(() => {\n        return;\n      });\n\n      subscription.unsubscribe();\n\n      // Restore body\n      Object.defineProperty(document, 'body', { value: originalBody, configurable: true });\n\n      // Verify it didn't throw and executed safely\n      expect(true).toBe(true);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/test/observables.test.ts",
    "content": "import { Unsubscribable } from '@amplitude/analytics-core';\nimport { createMouseMoveObservable } from '../src/observables';\n\ndescribe('createMouseMoveObservable', () => {\n  it('should create a mouse move observable and capture mouse move events', async () => {\n    const observable = createMouseMoveObservable();\n    let subscription: Unsubscribable | undefined;\n    const subscriptionPromise = new Promise<MouseEvent>((resolve) => {\n      subscription = observable.subscribe((event) => {\n        resolve(event);\n      });\n    });\n    const mouseMoveEvent = new MouseEvent('mousemove', {\n      clientX: 100,\n      clientY: 100,\n    });\n    document.dispatchEvent(mouseMoveEvent);\n    const event = await subscriptionPromise;\n    expect(event.clientX).toBe(100);\n    expect(event.clientY).toBe(100);\n    subscription?.unsubscribe();\n  });\n});\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/test/pageActions/matchEventToFilter.test.ts",
    "content": "import { EventSubpropKey } from './../../../analytics-core/src/types/element-interactions';\nimport type { Filter } from '@amplitude/analytics-core/lib/esm/types/element-interactions';\nimport { matchEventToFilter } from '../../src/pageActions/matchEventToFilter';\nimport { ElementBasedTimestampedEvent } from 'src/helpers';\n\n// Helper to create a mock MouseEvent\nconst createMockMouseEvent = (): MouseEvent => {\n  // In a browser environment, you could use `new MouseEvent('click')`\n  // For Node.js testing environments (like Jest with JSDOM),\n  // creating a full MouseEvent might be more involved or unnecessary\n  // if only its presence is required.\n  return {\n    // Add any specific MouseEvent properties your function might access from `event.event`\n  } as MouseEvent;\n};\n\n// Helper to create a base mock ElementBasedTimestampedEvent with real DOM elements\nconst createEventForTesting = (\n  text: string | undefined,\n  trackedElement: Element, // This will be the element the event is considered to have originated from\n): ElementBasedTimestampedEvent<MouseEvent> => ({\n  event: createMockMouseEvent(),\n  type: 'click',\n  timestamp: Date.now(),\n  closestTrackedAncestor: trackedElement, // This is the element .closest() will be called on\n  targetElementProperties: {\n    '[Amplitude] Element Text': text,\n  },\n});\n\ndescribe('matchEventToFilter', () => {\n  let testContainer: HTMLDivElement;\n\n  beforeEach(() => {\n    // Create a container for test elements\n    testContainer = document.createElement('div');\n    document.body.appendChild(testContainer);\n  });\n\n  afterEach(() => {\n    // Clean up the DOM\n    document.body.removeChild(testContainer);\n  });\n\n  // --- Test Suite for '[Amplitude] Element Text' ---\n  describe('when filter.subprop_key is \"[Amplitude] Element Text\"', () => {\n    const textFilterKey = '[Amplitude] Element Text';\n    let dummyElement: HTMLElement;\n\n    beforeEach(() => {\n      dummyElement = document.createElement('button'); // Any element will do\n      testContainer.appendChild(dummyElement);\n    });\n\n    test('should return true if subprop_op is \"is\" and text matches', () => {\n      const event = createEventForTesting('Hello World', dummyElement);\n      const filter: Filter = {\n        subprop_key: textFilterKey,\n        subprop_op: 'is',\n        subprop_value: ['Hello World'],\n      };\n      expect(matchEventToFilter(event, filter)).toBe(true);\n    });\n\n    test('should return true if subprop_op is \"is\" and text is one of the values', () => {\n      const event = createEventForTesting('Click Here', dummyElement);\n      const filter: Filter = {\n        subprop_key: textFilterKey,\n        subprop_op: 'is',\n        subprop_value: ['Submit', 'Click Here', 'View More'],\n      };\n      expect(matchEventToFilter(event, filter)).toBe(true);\n    });\n\n    test('should return false if subprop_op is \"is\" and text does not match', () => {\n      const event = createEventForTesting('Goodbye World', dummyElement);\n      const filter: Filter = {\n        subprop_key: textFilterKey,\n        subprop_op: 'is',\n        subprop_value: ['Hello World'],\n      };\n      expect(matchEventToFilter(event, filter)).toBe(false);\n    });\n\n    test('should return false if event text is undefined and looking for exact match', () => {\n      const event = createEventForTesting(undefined, dummyElement);\n      const filter: Filter = {\n        subprop_key: textFilterKey,\n        subprop_op: 'is',\n        subprop_value: ['Hello World'],\n      };\n      expect(matchEventToFilter(event, filter)).toBe(false);\n    });\n\n    // TODO: add tests for other operators\n    test('should return false if subprop_op is not \"is\" (due to other operators not implemented)', () => {\n      const event = createEventForTesting('Hello World', dummyElement);\n      const filter: Filter = {\n        subprop_key: textFilterKey,\n        subprop_op: 'contains', // Any other operator\n        subprop_value: ['Hello'],\n      };\n      expect(matchEventToFilter(event, filter)).toBe(false);\n    });\n\n    test('should return false if subprop_value is an empty array for \"is\" text match', () => {\n      const event = createEventForTesting('Hello World', dummyElement);\n      const filter: Filter = {\n        subprop_key: textFilterKey,\n        subprop_op: 'is',\n        subprop_value: [],\n      };\n      expect(matchEventToFilter(event, filter)).toBe(false);\n    });\n  });\n\n  // --- Test Suite for '[Amplitude] Element Hierarchy' ---\n  describe('when filter.subprop_key is \"[Amplitude] Element Hierarchy\"', () => {\n    const hierarchyFilterKey = '[Amplitude] Element Hierarchy';\n\n    test('should return true if subprop_op is \"autotrack css match\" and element matches CSS selector', () => {\n      // DOM Structure: <div> <button class=\"my-button\"></button> </div>\n      const parentDiv = document.createElement('div');\n      const button = document.createElement('button');\n      button.className = 'my-button';\n      parentDiv.appendChild(button);\n      testContainer.appendChild(parentDiv);\n\n      const event = createEventForTesting('Button Text', button); // Event on the button\n      const filter: Filter = {\n        subprop_key: hierarchyFilterKey,\n        subprop_op: 'autotrack css match',\n        subprop_value: ['div > .my-button'], // Selector targeting the button\n      };\n      expect(matchEventToFilter(event, filter)).toBe(true);\n    });\n\n    test('should return true if subprop_op is \"autotrack css match\" and a parent matches CSS selector', () => {\n      // DOM Structure: <div id=\"container\"> <button class=\"my-button\"></button> </div>\n      const parentDiv = document.createElement('div');\n      parentDiv.id = 'container';\n      const button = document.createElement('button');\n      button.className = 'my-button';\n      parentDiv.appendChild(button);\n      testContainer.appendChild(parentDiv);\n\n      const event = createEventForTesting('Button Text', button); // Event on the button\n      const filter: Filter = {\n        subprop_key: hierarchyFilterKey,\n        subprop_op: 'autotrack css match',\n        subprop_value: ['#container'], // Selector targeting the parent\n      };\n      // event.closestTrackedAncestor is 'button'. button.closest('#container') should be parentDiv\n      expect(matchEventToFilter(event, filter)).toBe(true);\n    });\n\n    test('should return false if subprop_op is \"autotrack css match\" and element does not match CSS selector', () => {\n      const button = document.createElement('button');\n      button.className = 'another-button';\n      testContainer.appendChild(button);\n\n      const event = createEventForTesting('Button Text', button);\n      const filter: Filter = {\n        subprop_key: hierarchyFilterKey,\n        subprop_op: 'autotrack css match',\n        subprop_value: ['div > .my-button'], // This selector won't match the button\n      };\n      expect(matchEventToFilter(event, filter)).toBe(false);\n    });\n\n    test('should return false if subprop_op is not \"autotrack css match\"', () => {\n      const button = document.createElement('button');\n      testContainer.appendChild(button);\n\n      const event = createEventForTesting('Any text', button);\n      const filter: Filter = {\n        subprop_key: hierarchyFilterKey,\n        subprop_op: 'is', // Any other operator\n        subprop_value: ['div > .my-button'],\n      };\n      expect(matchEventToFilter(event, filter)).toBe(false);\n    });\n\n    test('should use the first value in subprop_value for CSS selector', () => {\n      const button = document.createElement('button');\n      button.id = 'active-btn';\n      testContainer.appendChild(button);\n\n      const event = createEventForTesting('Any text', button);\n      const filter: Filter = {\n        subprop_key: hierarchyFilterKey,\n        subprop_op: 'autotrack css match',\n        subprop_value: ['#active-btn', '.ignored-selector'],\n      };\n      expect(matchEventToFilter(event, filter)).toBe(true);\n    });\n\n    test('should return false if subprop_value is an empty array for hierarchy match', () => {\n      const button = document.createElement('button');\n      testContainer.appendChild(button);\n      const event = createEventForTesting('Any text', button);\n      const filter: Filter = {\n        subprop_key: hierarchyFilterKey,\n        subprop_op: 'autotrack css match',\n        subprop_value: [], // .toString() on this will be \"\"\n      };\n      // element.closest('') would typically return null or throw, depending on impl.\n      // JSDOM's .closest('') returns null.\n      expect(matchEventToFilter(event, filter)).toBe(false);\n    });\n\n    test('should return false if selector in subprop_value is invalid CSS', () => {\n      const button = document.createElement('button');\n      testContainer.appendChild(button);\n      const event = createEventForTesting('Any text', button);\n      const filter: Filter = {\n        subprop_key: hierarchyFilterKey,\n        subprop_op: 'autotrack css match',\n        subprop_value: ['invalid>>><<<selector'],\n      };\n      expect(matchEventToFilter(event, filter)).toBe(false);\n    });\n  });\n\n  // --- Test Suite for unknown subprop_key ---\n  describe('when filter.subprop_key is unknown', () => {\n    test('should return false', () => {\n      const dummyElement = document.createElement('div');\n      testContainer.appendChild(dummyElement);\n      const event = createEventForTesting('Some Text', dummyElement);\n      const filter: Filter = {\n        subprop_key: '[Amplitude] Unknown Key' as EventSubpropKey, // Intentionally unknown\n        subprop_op: 'is',\n        subprop_value: ['Some Text'],\n      };\n      expect(matchEventToFilter(event, filter)).toBe(false);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/test/pageActions/triggers.test.ts",
    "content": "import { mockWindowLocationFromURL } from './../utils';\nimport type { ElementBasedTimestampedEvent } from '../../src/helpers';\nimport type {\n  LabeledEvent,\n  Trigger,\n  ElementInteractionsOptions,\n} from '@amplitude/analytics-core/lib/esm/types/element-interactions';\nimport {\n  groupLabeledEventIdsByEventType,\n  matchEventToLabeledEvents,\n  createLabeledEventToTriggerMap,\n  createTriggerEvaluator,\n} from '../../src/pageActions/triggers';\nimport * as matchEventToFilterModule from '../../src/pageActions/matchEventToFilter';\nimport * as actionsModule from '../../src/pageActions/actions';\nimport { AMPLITUDE_ELEMENT_CLICKED_EVENT, AMPLITUDE_ELEMENT_CHANGED_EVENT } from '../../src/constants';\nimport { autocapturePlugin } from '../../src/autocapture-plugin';\nimport type { BrowserClient, BrowserConfig, EnrichmentPlugin, ILogger } from '@amplitude/analytics-core';\nimport { createMockBrowserClient } from '../mock-browser-client';\nimport * as triggersModule from '../../src/pageActions/triggers';\nimport { DataExtractor } from '../../src/data-extractor';\n\n/* eslint-disable @typescript-eslint/unbound-method */\n\njest.mock('../../src/pageActions/matchEventToFilter');\njest.mock('../../src/pageActions/actions');\n\ndescribe('groupLabeledEventIdsByEventType', () => {\n  // Test 1: Handles an empty array\n  test('should return empty sets for an empty input array', () => {\n    const labeledEvents: LabeledEvent[] = [];\n    const result = groupLabeledEventIdsByEventType(labeledEvents);\n    expect(result.click.size).toBe(0);\n    expect(result.change.size).toBe(0);\n  });\n\n  // Test 2: Handles null or undefined input\n  test('should return empty sets for null or undefined input', () => {\n    let result = groupLabeledEventIdsByEventType(null);\n    expect(result.click.size).toBe(0);\n    expect(result.change.size).toBe(0);\n\n    result = groupLabeledEventIdsByEventType(undefined);\n    expect(result.click.size).toBe(0);\n    expect(result.change.size).toBe(0);\n  });\n\n  // Test 3: Groups 'click' events correctly\n  test('should group click event IDs correctly', () => {\n    const labeledEvents: LabeledEvent[] = [\n      { id: 'event1', definition: [{ event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT, filters: [] }] },\n      {\n        id: 'event2',\n        definition: [\n          {\n            event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT,\n            filters: [{ subprop_key: '[Amplitude] Element Text', subprop_op: 'is', subprop_value: ['v'] }],\n          },\n        ],\n      },\n    ] as LabeledEvent[];\n    const result = groupLabeledEventIdsByEventType(labeledEvents);\n    expect(result.click).toEqual(new Set(['event1', 'event2']));\n    expect(result.change.size).toBe(0);\n  });\n\n  // Test 4: Groups 'change' events correctly\n  test('should group change event IDs correctly', () => {\n    const labeledEvents: LabeledEvent[] = [\n      { id: 'event3', definition: [{ event_type: AMPLITUDE_ELEMENT_CHANGED_EVENT, filters: [] }] },\n      { id: 'event4', definition: [{ event_type: AMPLITUDE_ELEMENT_CHANGED_EVENT, filters: [] }] },\n    ];\n    const result = groupLabeledEventIdsByEventType(labeledEvents);\n    expect(result.change).toEqual(new Set(['event3', 'event4']));\n    expect(result.click.size).toBe(0);\n  });\n\n  // Test 5: Groups a mix of 'click' and 'change' events\n  test('should group a mix of click and change event IDs', () => {\n    const labeledEvents: LabeledEvent[] = [\n      { id: 'event1', definition: [{ event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT, filters: [] }] },\n      { id: 'event5', definition: [{ event_type: AMPLITUDE_ELEMENT_CHANGED_EVENT, filters: [] }] },\n      { id: 'event2', definition: [{ event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT, filters: [] }] },\n      { id: 'event6', definition: [{ event_type: AMPLITUDE_ELEMENT_CHANGED_EVENT, filters: [] }] },\n    ];\n    const result = groupLabeledEventIdsByEventType(labeledEvents);\n    expect(result.click).toEqual(new Set(['event1', 'event2']));\n    expect(result.change).toEqual(new Set(['event5', 'event6']));\n  });\n\n  // Test 6: Handles multiple definitions (for different event_types) within a single LabeledEvent\n  test('should handle multiple definitions in one LabeledEvent, adding ID to all relevant sets', () => {\n    const labeledEvents: LabeledEvent[] = [\n      {\n        id: 'eventA',\n        definition: [\n          { event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT, filters: [] },\n          { event_type: AMPLITUDE_ELEMENT_CHANGED_EVENT, filters: [] },\n        ],\n      },\n      {\n        id: 'eventB', // Belongs only to click\n        definition: [{ event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT, filters: [] }],\n      },\n    ];\n    const result = groupLabeledEventIdsByEventType(labeledEvents);\n    expect(result.click).toEqual(new Set(['eventA', 'eventB']));\n    expect(result.change).toEqual(new Set(['eventA']));\n  });\n\n  // Test 6b: Handles separate LabeledEvent items with the same ID but different event types\n  test('should handle separate LabeledEvent items with the same ID for different types', () => {\n    const labeledEvents: LabeledEvent[] = [\n      { id: 'eventC', definition: [{ event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT, filters: [] }] },\n      { id: 'eventC', definition: [{ event_type: AMPLITUDE_ELEMENT_CHANGED_EVENT, filters: [] }] },\n    ];\n    const result = groupLabeledEventIdsByEventType(labeledEvents);\n    expect(result.click).toEqual(new Set(['eventC']));\n    expect(result.change).toEqual(new Set(['eventC']));\n  });\n\n  // Test 7: Handles duplicate event IDs for the same event type (Set should ensure uniqueness)\n  test('should handle duplicate event IDs for the same type, ensuring uniqueness', () => {\n    const labeledEvents: LabeledEvent[] = [\n      { id: 'event1', definition: [{ event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT, filters: [] }] },\n      { id: 'event1', definition: [{ event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT, filters: [] }] }, // Processed, but ID is already in Set\n      {\n        id: 'event1', // Same ID, multiple definitions, one of which is click\n        definition: [\n          { event_type: AMPLITUDE_ELEMENT_CHANGED_EVENT, filters: [] }, // This would add 'event1' to change set\n          { event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT, filters: [] }, // This would attempt to add 'event1' to click set (no change if already there)\n        ],\n      },\n      { id: 'event8', definition: [{ event_type: AMPLITUDE_ELEMENT_CHANGED_EVENT, filters: [] }] },\n      { id: 'event8', definition: [{ event_type: AMPLITUDE_ELEMENT_CHANGED_EVENT, filters: [] }] },\n    ];\n    const result = groupLabeledEventIdsByEventType(labeledEvents);\n    expect(result.click).toEqual(new Set(['event1']));\n    expect(result.change).toEqual(new Set(['event1', 'event8'])); // event1 from the third item\n  });\n\n  // Test 8: Ignores LabeledEvents with empty or missing/null definition arrays\n  test('should ignore LabeledEvents with empty or malformed definition arrays', () => {\n    const labeledEvents: LabeledEvent[] = [\n      { id: 'event9', definition: [] }, // Empty definition array\n      { id: 'event10' }, // Missing definition property\n      { id: 'event10b', definition: null }, // Null definition property\n      { id: 'event11', definition: [{ event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT, filters: [] }] },\n    ] as LabeledEvent[];\n    const result = groupLabeledEventIdsByEventType(labeledEvents);\n    expect(result.click).toEqual(new Set(['event11']));\n    expect(result.change.size).toBe(0);\n  });\n\n  // Test 9: Ignores definitions with event_types not 'click' or 'change' (or malformed event_type)\n  test('should ignore definitions with unknown or malformed event_types', () => {\n    const labeledEvents: LabeledEvent[] = [\n      { id: 'event12', definition: [{ event_type: 'mouseover', filters: [] }] }, // 'mouseover' is not in groupedLabeledEvents\n      { id: 'event13', definition: [{ event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT, filters: [] }] },\n      {\n        id: 'event14',\n        definition: [\n          { event_type: 'custom_event', filters: [] }, // Ignored\n          { event_type: AMPLITUDE_ELEMENT_CHANGED_EVENT, filters: [] }, // Processed\n        ],\n      },\n      { id: 'event14b', definition: [{ event_type: null, filters: [] }] }, // Malformed event_type\n      { id: 'event14c', definition: [{ filters: [] }] }, // Missing event_type\n    ] as LabeledEvent[];\n    const result = groupLabeledEventIdsByEventType(labeledEvents);\n    expect(result.click).toEqual(new Set(['event13']));\n    expect(result.change).toEqual(new Set(['event14']));\n  });\n\n  // Test 10: Handles LabeledEvents with definition items that are null or malformed\n  test('should handle LabeledEvents with null or malformed definition items', () => {\n    const labeledEvents: LabeledEvent[] = [\n      { id: 'event15', definition: [null, { event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT, filters: [] }] }, // Null item in definition array\n      { id: 'event16', definition: [{ event_type: AMPLITUDE_ELEMENT_CHANGED_EVENT, filters: [] }, {}] }, // Empty object as definition item\n      { id: 'event17', definition: [{ event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT, filters: [] }] },\n      { id: 'event18', definition: [undefined, { event_type: AMPLITUDE_ELEMENT_CHANGED_EVENT, filters: [] }] }, // Undefined item\n    ] as LabeledEvent[];\n    const result = groupLabeledEventIdsByEventType(labeledEvents);\n    expect(result.click).toEqual(new Set(['event17']));\n    expect(result.change).toEqual(new Set(['event16']));\n  });\n\n  // Test 11: Handles LabeledEvent items that are null or not objects within the input array\n  test('should gracefully handle null or non-object items in labeledEvents array', () => {\n    const labeledEvents: LabeledEvent[] = [\n      { id: 'c1', definition: [{ event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT, filters: [] }] },\n      null, // Null item in labeledEvents\n      { id: 'ch1', definition: [{ event_type: AMPLITUDE_ELEMENT_CHANGED_EVENT, filters: [] }] },\n      'not_an_object', // String item in labeledEvents\n      undefined, // Undefined item\n      { id: 'c2', definition: [{ event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT, filters: [] }] },\n    ] as LabeledEvent[];\n    const result = groupLabeledEventIdsByEventType(labeledEvents);\n    expect(result.click).toEqual(new Set(['c1', 'c2']));\n    expect(result.change).toEqual(new Set(['ch1']));\n  });\n\n  // Test 12: Should ignore unknown Amplitude event types\n  test('should ignore unknown Amplitude event types like \"[Amplitude] Random Event\"', () => {\n    const labeledEvents: LabeledEvent[] = [\n      { id: 'validClick', definition: [{ event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT, filters: [] }] },\n      { id: 'validChange', definition: [{ event_type: AMPLITUDE_ELEMENT_CHANGED_EVENT, filters: [] }] },\n      {\n        id: 'randomEvent',\n        definition: [\n          { event_type: '[Amplitude] Random Event' as unknown as typeof AMPLITUDE_ELEMENT_CLICKED_EVENT, filters: [] },\n        ],\n      },\n      {\n        id: 'mixedEvent',\n        definition: [\n          { event_type: '[Amplitude] Unknown Event' as unknown as typeof AMPLITUDE_ELEMENT_CLICKED_EVENT, filters: [] }, // Should be ignored\n          { event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT, filters: [] }, // Should be processed\n        ],\n      },\n    ];\n    const result = groupLabeledEventIdsByEventType(labeledEvents);\n    expect(result.click).toEqual(new Set(['validClick', 'mixedEvent']));\n    expect(result.change).toEqual(new Set(['validChange']));\n  });\n\n  // Test 13: Complex scenario with mixed valid, invalid, and duplicate data\n  test('should handle a complex mix of data correctly', () => {\n    const labeledEvents: LabeledEvent[] = [\n      { id: 'c1', definition: [{ event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT, filters: [] }] },\n      null,\n      { id: 'ch1', definition: [{ event_type: AMPLITUDE_ELEMENT_CHANGED_EVENT, filters: [] }] },\n      {\n        id: 'c2',\n        definition: [\n          { event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT, filters: [] },\n          { event_type: 'focus', filters: [] },\n        ],\n      },\n      { id: 'ch1', definition: [{ event_type: AMPLITUDE_ELEMENT_CHANGED_EVENT, filters: [] }] }, // Duplicate ID for change\n      {\n        id: 'multi1',\n        definition: [\n          { event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT, filters: [] },\n          { event_type: AMPLITUDE_ELEMENT_CHANGED_EVENT, filters: [] },\n        ],\n      },\n      { id: 'eventWithoutDef' }, // Missing definition\n      { id: 'eventWithEmptyDef', definition: [] }, // Empty definition array\n      { id: 'eventWithNullDefItem', definition: [null, { event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT, filters: [] }] },\n      { id: 'eventWithInvalidDefObj', definition: [{ some_other_prop: 'value' }] }, // Missing event_type\n      { id: 'eventWithOnlyChange', definition: [{ event_type: AMPLITUDE_ELEMENT_CHANGED_EVENT, filters: [] }] },\n    ] as LabeledEvent[];\n    const result = groupLabeledEventIdsByEventType(labeledEvents);\n    expect(result.click).toEqual(new Set(['c1', 'c2', 'multi1']));\n    expect(result.change).toEqual(new Set(['ch1', 'multi1', 'eventWithOnlyChange']));\n  });\n});\n\ndescribe('matchEventToLabeledEvents', () => {\n  let spy: jest.SpyInstance;\n  beforeAll(() => {\n    spy = jest.spyOn(matchEventToFilterModule, 'matchEventToFilter');\n  });\n  beforeEach(() => {\n    // Clear mock calls before each test\n    spy.mockClear();\n  });\n\n  const mockMouseEvent = new MouseEvent('click');\n\n  const mockEvent: ElementBasedTimestampedEvent<MouseEvent> = {\n    event: mockMouseEvent,\n    type: 'click',\n    closestTrackedAncestor: document.createElement('div'),\n    targetElementProperties: {},\n    timestamp: 0, // Add timestamp to satisfy BaseTimestampedEvent\n  };\n\n  it('should return an empty array if no labeled events match', () => {\n    spy.mockReturnValue(false); // Simulate no filter matches\n    const labeledEvents: LabeledEvent[] = [\n      {\n        id: '1',\n        definition: [\n          {\n            event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT,\n            filters: [\n              {\n                subprop_key: '[Amplitude] Element Text',\n                subprop_op: 'is',\n                subprop_value: ['Button A'],\n              },\n            ],\n          },\n        ],\n      },\n    ];\n\n    const result = matchEventToLabeledEvents(mockEvent, labeledEvents);\n    expect(result).toEqual([]);\n    expect(spy).toHaveBeenCalledTimes(1);\n  });\n\n  it('should return a single matching labeled event', () => {\n    spy.mockReturnValue(true); // Simulate all filters match\n\n    const labeledEvents: LabeledEvent[] = [\n      {\n        id: '2',\n        definition: [\n          {\n            event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT,\n            filters: [\n              {\n                subprop_key: '[Amplitude] Element Hierarchy',\n                subprop_op: 'contains',\n                subprop_value: ['div > span'],\n              },\n            ],\n          },\n        ],\n      },\n      {\n        id: '3',\n        definition: [\n          {\n            event_type: AMPLITUDE_ELEMENT_CHANGED_EVENT,\n            filters: [\n              {\n                subprop_key: '[Amplitude] Element Text',\n                subprop_op: 'is',\n                subprop_value: ['Input Field'],\n              },\n            ],\n          },\n        ],\n      },\n    ];\n\n    const result = matchEventToLabeledEvents(mockEvent, labeledEvents);\n    expect(result).toEqual([labeledEvents[0]]);\n    expect(spy).toHaveBeenCalledTimes(1); // Only for the first labeled event's first filter\n  });\n\n  it('should return multiple matching labeled events', () => {\n    spy.mockReturnValue(true); // Simulate all filters match\n\n    const labeledEvents: LabeledEvent[] = [\n      {\n        id: '4',\n        definition: [\n          {\n            event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT,\n            filters: [\n              {\n                subprop_key: '[Amplitude] Element Text',\n                subprop_op: 'is',\n                subprop_value: ['Link 1'],\n              },\n            ],\n          },\n        ],\n      },\n      {\n        id: '5',\n        definition: [\n          {\n            event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT,\n            filters: [\n              {\n                subprop_key: '[Amplitude] Element Hierarchy',\n                subprop_op: 'contains',\n                subprop_value: ['a.some-class'],\n              },\n            ],\n          },\n        ],\n      },\n      {\n        id: '6',\n        definition: [\n          {\n            event_type: AMPLITUDE_ELEMENT_CHANGED_EVENT,\n            filters: [\n              {\n                subprop_key: '[Amplitude] Element Text',\n                subprop_op: 'is',\n                subprop_value: ['Dropdown'],\n              },\n            ],\n          },\n        ],\n      },\n    ];\n\n    const result = matchEventToLabeledEvents(mockEvent, labeledEvents);\n    expect(result).toEqual([labeledEvents[0], labeledEvents[1]]);\n    expect(spy).toHaveBeenCalledTimes(2); // For the first two labeled events\n  });\n\n  it('should match if one of multiple definitions matches', () => {\n    const labeledEvent: LabeledEvent = {\n      id: '7',\n      definition: [\n        {\n          event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT, // This definition will not match `mockEvent.type`\n          filters: [\n            {\n              subprop_key: '[Amplitude] Element Text',\n              subprop_op: 'is',\n              subprop_value: ['Some other text'],\n            },\n          ],\n        },\n        {\n          event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT, // This definition will match\n          filters: [\n            {\n              subprop_key: '[Amplitude] Element Hierarchy',\n              subprop_op: 'autotrack css match',\n              subprop_value: ['body > div'],\n            },\n          ],\n        },\n      ],\n    };\n\n    // First filter of the first definition will return false\n    spy.mockReturnValueOnce(false);\n    // First filter of the second definition will return true\n    spy.mockReturnValueOnce(true);\n\n    const result = matchEventToLabeledEvents(mockEvent, [labeledEvent]);\n    expect(result).toEqual([labeledEvent]);\n    // It should be called for the first filter of the first definition,\n    // and then for the first filter of the second definition.\n    expect(spy).toHaveBeenCalledTimes(2);\n  });\n\n  it('should not match if all definitions do not match', () => {\n    const labeledEvent: LabeledEvent = {\n      id: '8',\n      definition: [\n        {\n          event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT,\n          filters: [\n            {\n              subprop_key: '[Amplitude] Element Text',\n              subprop_op: 'is',\n              subprop_value: ['Text 1'],\n            },\n          ],\n        },\n        {\n          event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT,\n          filters: [\n            {\n              subprop_key: '[Amplitude] Element Hierarchy',\n              subprop_op: 'autotrack css match',\n              subprop_value: ['path2'],\n            },\n          ],\n        },\n      ],\n    };\n\n    spy.mockReturnValue(false);\n\n    const result = matchEventToLabeledEvents(mockEvent, [labeledEvent]);\n    expect(result).toEqual([]);\n    expect(spy).toHaveBeenCalledTimes(2); // Called for both filters of the two definitions\n  });\n\n  it('should match if all filters within a definition match', () => {\n    const labeledEvent: LabeledEvent = {\n      id: '9',\n      definition: [\n        {\n          event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT,\n          filters: [\n            {\n              subprop_key: '[Amplitude] Element Text',\n              subprop_op: 'is',\n              subprop_value: ['Primary Button'],\n            },\n            {\n              subprop_key: '[Amplitude] Element Hierarchy',\n              subprop_op: 'autotrack css match',\n              subprop_value: ['button'],\n            },\n          ],\n        },\n      ],\n    };\n\n    spy.mockReturnValue(true); // Both filters will return true\n\n    const result = matchEventToLabeledEvents(mockEvent, [labeledEvent]);\n    expect(result).toEqual([labeledEvent]);\n    expect(spy).toHaveBeenCalledTimes(2); // Called for both filters\n  });\n\n  it('should not match if any filter within a definition does not match', () => {\n    const labeledEvent: LabeledEvent = {\n      id: '10',\n      definition: [\n        {\n          event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT,\n          filters: [\n            {\n              subprop_key: '[Amplitude] Element Text',\n              subprop_op: 'is',\n              subprop_value: ['Matching Text'],\n            },\n            {\n              subprop_key: '[Amplitude] Element Hierarchy',\n              subprop_op: 'autotrack css match',\n              subprop_value: ['non-matching-path'],\n            },\n          ],\n        },\n      ],\n    };\n\n    // First filter returns true, second returns false\n    spy.mockReturnValueOnce(true).mockReturnValueOnce(false);\n\n    const result = matchEventToLabeledEvents(mockEvent, [labeledEvent]);\n    expect(result).toEqual([]);\n    expect(spy).toHaveBeenCalledTimes(2); // Called for both filters until one fails\n  });\n\n  it('should handle an empty filters array within a definition (should match by default)', () => {\n    // If there are no filters, `every` will return true, so it should match\n    const labeledEvent: LabeledEvent = {\n      id: '11',\n      definition: [\n        {\n          event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT,\n          filters: [], // Empty filters array\n        },\n      ],\n    };\n\n    const result = matchEventToLabeledEvents(mockEvent, [labeledEvent]);\n    expect(result).toEqual([labeledEvent]);\n    expect(spy).not.toHaveBeenCalled(); // No filters to check\n  });\n\n  it('should handle empty definition array for a labeled event', () => {\n    const labeledEvent: LabeledEvent = {\n      id: '12',\n      definition: [], // Empty definition array\n    };\n\n    const result = matchEventToLabeledEvents(mockEvent, [labeledEvent]);\n    expect(result).toEqual([]);\n    expect(spy).not.toHaveBeenCalled();\n  });\n\n  it('should return an empty array if labeledEvents is empty', () => {\n    const result = matchEventToLabeledEvents(mockEvent, []);\n    expect(result).toEqual([]);\n    expect(spy).not.toHaveBeenCalled();\n  });\n});\n\ndescribe('TriggerEvaluator', () => {\n  const executeActionsSpy = jest.spyOn(actionsModule, 'executeActions');\n  const matchEventToFilterSpy = jest.spyOn(matchEventToFilterModule, 'matchEventToFilter');\n\n  beforeEach(() => {\n    executeActionsSpy.mockClear();\n    matchEventToFilterSpy.mockClear();\n  });\n\n  const mockMouseEvent = new MouseEvent('click');\n  const mockEvent: ElementBasedTimestampedEvent<MouseEvent> = {\n    event: mockMouseEvent,\n    type: 'click',\n    closestTrackedAncestor: document.createElement('div'),\n    targetElementProperties: {},\n    timestamp: 0,\n  };\n\n  const labeledEvents: Record<string, LabeledEvent> = {\n    'le-click': {\n      id: 'le-click',\n      definition: [\n        {\n          event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT,\n          filters: [{ subprop_key: '[Amplitude] Element Text', subprop_op: 'is', subprop_value: ['value'] }],\n        },\n      ],\n    },\n    'le-change': {\n      id: 'le-change',\n      definition: [{ event_type: AMPLITUDE_ELEMENT_CHANGED_EVENT, filters: [] }],\n    },\n  };\n\n  const triggers: Trigger[] = [\n    {\n      id: 'trigger-1',\n      name: 'Trigger 1',\n      actions: [\n        {\n          id: 'action-1',\n          actionType: 'ATTACH_EVENT_PROPERTY',\n          destinationKey: 'prop',\n          dataSource: { sourceType: 'DOM_ELEMENT', selector: 'div', elementExtractType: 'TEXT' },\n        },\n      ],\n      conditions: [{ type: 'LABELED_EVENT', match: { eventId: 'le-click' } }],\n    },\n  ];\n\n  const options: ElementInteractionsOptions = {\n    pageActions: {\n      labeledEvents: labeledEvents,\n      triggers: triggers,\n    },\n  };\n\n  const groupedLabeledEvents = groupLabeledEventIdsByEventType(Object.values(labeledEvents));\n  const labeledEventToTriggerMap = createLabeledEventToTriggerMap(triggers);\n\n  it('should do nothing if pageActions is not configured', () => {\n    const triggerEvaluator = createTriggerEvaluator(\n      groupedLabeledEvents,\n      labeledEventToTriggerMap,\n      new DataExtractor({}),\n      {},\n    );\n    const result = triggerEvaluator.evaluate(mockEvent);\n\n    expect(result).toBe(mockEvent);\n    expect(executeActionsSpy).not.toHaveBeenCalled();\n  });\n\n  it('should not call executeActions if no labeled event matches', () => {\n    matchEventToFilterSpy.mockReturnValue(false); // No filter match\n\n    const triggerEvaluator = createTriggerEvaluator(\n      groupedLabeledEvents,\n      labeledEventToTriggerMap,\n      new DataExtractor({}),\n      options,\n    );\n    triggerEvaluator.evaluate(mockEvent);\n\n    expect(executeActionsSpy).not.toHaveBeenCalled();\n  });\n\n  it('should not call executeActions if a labeled event matches but has no trigger', () => {\n    const optionsWithUntriggeredEvent: ElementInteractionsOptions = {\n      pageActions: {\n        labeledEvents: {\n          'untriggered-event': {\n            id: 'untriggered-event',\n            definition: [{ event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT, filters: [] }],\n          },\n        },\n        triggers: [], // No triggers\n      },\n    };\n\n    const grouped = groupLabeledEventIdsByEventType(\n      Object.values(optionsWithUntriggeredEvent.pageActions?.labeledEvents || {}),\n    );\n    const triggerMap = createLabeledEventToTriggerMap(optionsWithUntriggeredEvent.pageActions?.triggers || []);\n\n    matchEventToFilterSpy.mockReturnValue(true); // event matches\n\n    const dataExtractor = new DataExtractor({});\n    const triggerEvaluator = createTriggerEvaluator(grouped, triggerMap, dataExtractor, optionsWithUntriggeredEvent);\n    triggerEvaluator.evaluate(mockEvent);\n\n    expect(executeActionsSpy).not.toHaveBeenCalled();\n  });\n\n  it('should call executeActions with correct actions when a trigger is matched', () => {\n    matchEventToFilterSpy.mockReturnValue(true); // Labeled event matches\n\n    const dataExtractor = new DataExtractor({});\n    const triggerEvaluator = createTriggerEvaluator(\n      groupedLabeledEvents,\n      labeledEventToTriggerMap,\n      dataExtractor,\n      options,\n    );\n    triggerEvaluator.evaluate(mockEvent);\n\n    expect(executeActionsSpy).toHaveBeenCalledTimes(1);\n    expect(executeActionsSpy).toHaveBeenCalledWith(triggers[0].actions, mockEvent, dataExtractor);\n  });\n\n  it('should handle multiple matching triggers for a single event', () => {\n    const multiTrigger: Trigger[] = [\n      {\n        id: 'trigger-1',\n        name: 'Trigger 1',\n        actions: [\n          {\n            id: 'action-1',\n            actionType: 'ATTACH_EVENT_PROPERTY',\n            destinationKey: 'prop1',\n            dataSource: { sourceType: 'DOM_ELEMENT', selector: 'div', elementExtractType: 'TEXT' },\n          },\n        ],\n        conditions: [{ type: 'LABELED_EVENT', match: { eventId: 'le-click' } }],\n      },\n      {\n        id: 'trigger-2',\n        name: 'Trigger 2',\n        actions: [\n          {\n            id: 'action-2',\n            actionType: 'ATTACH_EVENT_PROPERTY',\n            destinationKey: 'prop2',\n            dataSource: { sourceType: 'DOM_ELEMENT', selector: 'div', elementExtractType: 'TEXT' },\n          },\n        ],\n        conditions: [{ type: 'LABELED_EVENT', match: { eventId: 'le-click' } }],\n      },\n    ];\n\n    const multiTriggerOptions: ElementInteractionsOptions = {\n      pageActions: {\n        labeledEvents,\n        triggers: multiTrigger,\n      },\n    };\n\n    const triggerMap = createLabeledEventToTriggerMap(multiTrigger);\n    matchEventToFilterSpy.mockReturnValue(true);\n\n    const dataExtractor = new DataExtractor({});\n    const triggerEvaluator = createTriggerEvaluator(\n      groupedLabeledEvents,\n      triggerMap,\n      dataExtractor,\n      multiTriggerOptions,\n    );\n    triggerEvaluator.evaluate(mockEvent);\n\n    expect(executeActionsSpy).toHaveBeenCalledTimes(2);\n    expect(executeActionsSpy).toHaveBeenCalledWith(multiTrigger[0].actions, mockEvent, dataExtractor);\n    expect(executeActionsSpy).toHaveBeenCalledWith(multiTrigger[1].actions, mockEvent, dataExtractor);\n  });\n\n  it('should update state when update method is called', () => {\n    const dataExtractor = new DataExtractor({});\n    const triggerEvaluator = createTriggerEvaluator(groupedLabeledEvents, labeledEventToTriggerMap, dataExtractor, {});\n\n    // Initially should do nothing since pageActions is empty\n    triggerEvaluator.evaluate(mockEvent);\n    expect(executeActionsSpy).not.toHaveBeenCalled();\n\n    // Update the evaluator with proper options\n    triggerEvaluator.update(groupedLabeledEvents, labeledEventToTriggerMap, options);\n    matchEventToFilterSpy.mockReturnValue(true);\n\n    // Now it should execute actions\n    triggerEvaluator.evaluate(mockEvent);\n    expect(executeActionsSpy).toHaveBeenCalledTimes(1);\n    expect(executeActionsSpy).toHaveBeenCalledWith(triggers[0].actions, mockEvent, dataExtractor);\n  });\n});\n\ndescribe('autocapturePlugin recomputePageActionsData functionality', () => {\n  let plugin: EnrichmentPlugin | undefined;\n  let instance: jest.Mocked<BrowserClient>;\n  let loggerProvider: ILogger;\n\n  // Mock data\n  const mockLabeledEvents: Record<string, LabeledEvent> = {\n    'local-event-1': {\n      id: 'local-event-1',\n      definition: [\n        {\n          event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT,\n          filters: [\n            {\n              subprop_key: '[Amplitude] Element Text',\n              subprop_op: 'is',\n              subprop_value: ['Local Button'],\n            },\n          ],\n        },\n      ],\n    },\n    'local-event-2': {\n      id: 'local-event-2',\n      definition: [\n        {\n          event_type: AMPLITUDE_ELEMENT_CHANGED_EVENT,\n          filters: [\n            {\n              subprop_key: '[Amplitude] Element Text',\n              subprop_op: 'is',\n              subprop_value: ['Local Input'],\n            },\n          ],\n        },\n      ],\n    },\n  };\n\n  const mockTriggers: Trigger[] = [\n    {\n      id: 'local-trigger-1',\n      name: 'Local Trigger',\n      conditions: [\n        {\n          type: 'LABELED_EVENT',\n          match: {\n            eventId: 'local-event-1',\n          },\n        },\n      ],\n      actions: [\n        {\n          id: 'local-action-1',\n          actionType: 'ATTACH_EVENT_PROPERTY',\n          dataSource: {\n            sourceType: 'DOM_ELEMENT',\n            elementExtractType: 'TEXT',\n            scope: '.container',\n            selector: '.title',\n          },\n          destinationKey: 'title',\n        },\n      ],\n    },\n  ];\n\n  const mockRemoteLabeledEvents: Record<string, LabeledEvent> = {\n    'remote-event-1': {\n      id: 'remote-event-1',\n      definition: [\n        {\n          event_type: AMPLITUDE_ELEMENT_CLICKED_EVENT,\n          filters: [\n            {\n              subprop_key: '[Amplitude] Element Text',\n              subprop_op: 'is',\n              subprop_value: ['Remote Button'],\n            },\n          ],\n        },\n      ],\n    },\n    'remote-event-2': {\n      id: 'remote-event-2',\n      definition: [\n        {\n          event_type: AMPLITUDE_ELEMENT_CHANGED_EVENT,\n          filters: [\n            {\n              subprop_key: '[Amplitude] Element Text',\n              subprop_op: 'is',\n              subprop_value: ['Remote Input'],\n            },\n          ],\n        },\n      ],\n    },\n  };\n\n  const mockRemoteTriggers: Trigger[] = [\n    {\n      id: 'remote-trigger-1',\n      name: 'Remote Trigger',\n      conditions: [\n        {\n          type: 'LABELED_EVENT',\n          match: {\n            eventId: 'remote-event-1',\n          },\n        },\n      ],\n      actions: [\n        {\n          id: 'remote-action-1',\n          actionType: 'ATTACH_EVENT_PROPERTY',\n          dataSource: {\n            sourceType: 'DOM_ELEMENT',\n            elementExtractType: 'TEXT',\n            scope: '.remote-container',\n            selector: '.remote-title',\n          },\n          destinationKey: 'remote-title',\n        },\n      ],\n    },\n  ];\n\n  beforeAll(() => {\n    Object.defineProperty(window, 'location', {\n      value: {\n        hostname: '',\n        href: '',\n        pathname: '',\n        search: '',\n      },\n      writable: true,\n    });\n  });\n\n  beforeEach(() => {\n    mockWindowLocationFromURL(new URL('https://test.com'));\n\n    loggerProvider = {\n      log: jest.fn(),\n      warn: jest.fn(),\n      error: jest.fn(),\n      debug: jest.fn(),\n    } as unknown as ILogger;\n\n    instance = createMockBrowserClient();\n\n    // Reset all mocks\n    jest.clearAllMocks();\n  });\n\n  afterEach(() => {\n    void plugin?.teardown?.();\n    if (typeof document !== 'undefined') {\n      document.getElementsByTagName('body')[0].innerHTML = '';\n    }\n    jest.clearAllMocks();\n  });\n\n  describe('with local pageActions only', () => {\n    it('should initialize with local pageActions', async () => {\n      const autocaptureConfig: ElementInteractionsOptions = {\n        pageActions: {\n          labeledEvents: mockLabeledEvents,\n          triggers: mockTriggers,\n        },\n      };\n\n      plugin = autocapturePlugin(autocaptureConfig);\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n      };\n\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // Verify setup was called (indirectly through the functions being used)\n      expect(plugin?.name).toBe('@amplitude/plugin-autocapture-browser');\n      expect(plugin?.type).toBe('enrichment');\n    });\n  });\n\n  describe('with remote config integration', () => {\n    it('should fetch remote config and merge with local pageActions', async () => {\n      const mockRemoteConfigClient = {\n        subscribe: jest.fn(),\n        unsubscribe: jest.fn(),\n        updateConfigs: jest.fn(),\n      };\n\n      const autocaptureConfig: ElementInteractionsOptions = {\n        pageActions: {\n          labeledEvents: mockLabeledEvents,\n          triggers: mockTriggers,\n        },\n      };\n\n      plugin = autocapturePlugin(autocaptureConfig);\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n        fetchRemoteConfig: true,\n        remoteConfigClient: mockRemoteConfigClient,\n      };\n\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // Wait for remote config to be fetched and processed\n      await new Promise((resolve) => setTimeout(resolve, 10));\n\n      // Verify remote config client subscribe was called\n      expect(mockRemoteConfigClient.subscribe).toHaveBeenCalledWith(\n        'configs.analyticsSDK.pageActions',\n        'all',\n        expect.any(Function),\n      );\n    });\n\n    it('should not fetch remote config when fetchRemoteConfig is false', async () => {\n      const mockRemoteConfigClient = {\n        subscribe: jest.fn(),\n        unsubscribe: jest.fn(),\n        updateConfigs: jest.fn(),\n      };\n\n      const autocaptureConfig: ElementInteractionsOptions = {\n        pageActions: {\n          labeledEvents: mockLabeledEvents,\n          triggers: mockTriggers,\n        },\n      };\n\n      plugin = autocapturePlugin(autocaptureConfig);\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n        // No remoteConfigClient provided\n      };\n\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // Wait to ensure no remote config processing happens\n      await new Promise((resolve) => setTimeout(resolve, 10));\n\n      // Verify remote config client subscribe was not called\n      expect(mockRemoteConfigClient.subscribe).not.toHaveBeenCalled();\n    });\n\n    it('should log when fetchRemoteConfig is true but remoteConfigClient undefined', async () => {\n      const autocaptureConfig: ElementInteractionsOptions = {\n        pageActions: {\n          labeledEvents: mockLabeledEvents,\n          triggers: mockTriggers,\n        },\n      };\n\n      plugin = autocapturePlugin(autocaptureConfig);\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n        fetchRemoteConfig: true,\n        // remoteConfigClient is undefined\n      };\n\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // Wait for setup to complete\n      await new Promise((resolve) => setTimeout(resolve, 10));\n\n      // Verify warning was logged about missing remoteConfigClient\n      expect(loggerProvider.debug).toHaveBeenCalledWith(\n        'Remote config client is not provided, skipping remote config fetch',\n      );\n    });\n\n    it('should handle null/undefined remote pageActions', async () => {\n      const mockRemoteConfigClient = {\n        subscribe: jest\n          .fn()\n          .mockImplementation(\n            (_key, _deliveryMode, callback: (remoteConfig: any, source: string, lastFetch: Date) => void) => {\n              // Simulate calling the callback with null remote config\n              callback(null, 'cache', new Date());\n            },\n          ),\n        unsubscribe: jest.fn(),\n        updateConfigs: jest.fn(),\n      };\n\n      const autocaptureConfig: ElementInteractionsOptions = {\n        pageActions: {\n          labeledEvents: mockLabeledEvents,\n          triggers: mockTriggers,\n        },\n      };\n\n      plugin = autocapturePlugin(autocaptureConfig);\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n        remoteConfigClient: mockRemoteConfigClient,\n      };\n\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // Wait for remote config to be processed\n      await new Promise((resolve) => setTimeout(resolve, 10));\n\n      // No errors should be logged for null remote config\n      expect(loggerProvider.error).not.toHaveBeenCalled();\n    });\n\n    it('should handle when local pageActions is undefined and remote config provides pageActions', async () => {\n      const mockRemoteConfigClient = {\n        subscribe: jest\n          .fn()\n          .mockImplementation(\n            (_key, _deliveryMode, callback: (remoteConfig: any, source: string, lastFetch: Date) => void) => {\n              // Simulate calling the callback with remote config data\n              callback(\n                {\n                  labeledEvents: mockRemoteLabeledEvents,\n                  triggers: mockRemoteTriggers,\n                },\n                'cache',\n                new Date(),\n              );\n            },\n          ),\n        unsubscribe: jest.fn(),\n        updateConfigs: jest.fn(),\n      };\n\n      // Start with undefined pageActions\n      const autocaptureConfig: ElementInteractionsOptions = {\n        pageActions: undefined,\n      };\n\n      plugin = autocapturePlugin(autocaptureConfig);\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n        fetchRemoteConfig: true,\n        remoteConfigClient: mockRemoteConfigClient,\n      };\n\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // Wait for remote config to be processed\n      await new Promise((resolve) => setTimeout(resolve, 10));\n\n      // Verify remote config client subscribe was called\n      expect(mockRemoteConfigClient.subscribe).toHaveBeenCalledWith(\n        'configs.analyticsSDK.pageActions',\n        'all',\n        expect.any(Function),\n      );\n\n      // No errors should be logged when starting with undefined pageActions\n      expect(loggerProvider.error).not.toHaveBeenCalled();\n\n      // Plugin should still function normally\n      expect(plugin?.name).toBe('@amplitude/plugin-autocapture-browser');\n      expect(plugin?.type).toBe('enrichment');\n    });\n\n    it('should handle when remote pageActions overwrites local labeledEvents with undefined', async () => {\n      // Mock the module function before creating the plugin\n      const originalGroupLabeledEvents = triggersModule.groupLabeledEventIdsByEventType;\n      const groupLabeledEventsSpy = jest.spyOn(triggersModule, 'groupLabeledEventIdsByEventType');\n      groupLabeledEventsSpy.mockImplementation(originalGroupLabeledEvents);\n\n      const mockRemoteConfigClient = {\n        subscribe: jest\n          .fn()\n          .mockImplementation(\n            (_key, _deliveryMode, callback: (remoteConfig: any, source: string, lastFetch: Date) => void) => {\n              // Simulate calling the callback with remote config that has undefined labeledEvents\n              callback(\n                {\n                  // Remote config explicitly sets labeledEvents to undefined, overwriting local\n                  labeledEvents: undefined,\n                  triggers: mockRemoteTriggers,\n                },\n                'cache',\n                new Date(),\n              );\n            },\n          ),\n        unsubscribe: jest.fn(),\n        updateConfigs: jest.fn(),\n      };\n\n      // Start with local pageActions that has labeledEvents\n      const autocaptureConfig: ElementInteractionsOptions = {\n        pageActions: {\n          labeledEvents: mockLabeledEvents,\n          triggers: mockTriggers,\n        },\n      };\n\n      plugin = autocapturePlugin(autocaptureConfig);\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n        fetchRemoteConfig: true,\n        remoteConfigClient: mockRemoteConfigClient,\n      };\n\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // Wait for remote config to be processed\n      await new Promise((resolve) => setTimeout(resolve, 100));\n\n      // The spy should have been called twice:\n      // 1. Once during initial plugin creation with local labeledEvents\n      // 2. Once during recomputePageActionsData with empty array (due to undefined labeledEvents after merge)\n      expect(groupLabeledEventsSpy).toHaveBeenCalledTimes(2);\n\n      // Check the second call (recomputePageActionsData) received empty array\n      const secondCall = groupLabeledEventsSpy.mock.calls[1];\n      expect(secondCall[0]).toEqual([]); // Object.values({}) when labeledEvents is undefined\n\n      // No errors should be logged\n      expect(loggerProvider.error).not.toHaveBeenCalled();\n\n      groupLabeledEventsSpy.mockRestore();\n    });\n\n    it('should handle when both local and remote labeledEvents are undefined', async () => {\n      // Mock the module function before creating the plugin\n      const originalGroupLabeledEvents = triggersModule.groupLabeledEventIdsByEventType;\n      const groupLabeledEventsSpy = jest.spyOn(triggersModule, 'groupLabeledEventIdsByEventType');\n      groupLabeledEventsSpy.mockImplementation(originalGroupLabeledEvents);\n\n      const mockRemoteConfigClient = {\n        subscribe: jest\n          .fn()\n          .mockImplementation(\n            (_key, _deliveryMode, callback: (remoteConfig: any, source: string, lastFetch: Date) => void) => {\n              // Simulate calling the callback with remote config that has undefined labeledEvents\n              callback(\n                {\n                  labeledEvents: undefined,\n                  triggers: mockRemoteTriggers,\n                },\n                'cache',\n                new Date(),\n              );\n            },\n          ),\n        unsubscribe: jest.fn(),\n        updateConfigs: jest.fn(),\n      };\n\n      // Start with local pageActions that also has undefined labeledEvents\n      const autocaptureConfig: ElementInteractionsOptions = {\n        pageActions: {\n          labeledEvents: undefined as unknown as Record<string, LabeledEvent>,\n          triggers: mockTriggers,\n        },\n      };\n\n      plugin = autocapturePlugin(autocaptureConfig);\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n        fetchRemoteConfig: true,\n        remoteConfigClient: mockRemoteConfigClient,\n      };\n\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // Wait for remote config to be processed\n      await new Promise((resolve) => setTimeout(resolve, 100));\n\n      // The spy should have been called twice:\n      // 1. Once during initial plugin creation with empty array (local labeledEvents undefined)\n      // 2. Once during recomputePageActionsData with empty array (remote labeledEvents also undefined)\n      expect(groupLabeledEventsSpy).toHaveBeenCalledTimes(2);\n\n      // Both calls should receive empty array due to the \"?? {}\" fallback\n      expect(groupLabeledEventsSpy.mock.calls[0][0]).toEqual([]); // Initial call\n      expect(groupLabeledEventsSpy.mock.calls[1][0]).toEqual([]); // recomputePageActionsData call\n\n      // No errors should be logged\n      expect(loggerProvider.error).not.toHaveBeenCalled();\n\n      groupLabeledEventsSpy.mockRestore();\n    });\n\n    it('should handle when both local and remote triggers are undefined', async () => {\n      // Mock the module function before creating the plugin\n      const originalCreateLabeledEventToTriggerMap = triggersModule.createLabeledEventToTriggerMap;\n      const createLabeledEventToTriggerMapSpy = jest.spyOn(triggersModule, 'createLabeledEventToTriggerMap');\n      createLabeledEventToTriggerMapSpy.mockImplementation(originalCreateLabeledEventToTriggerMap);\n\n      const mockRemoteConfigClient = {\n        subscribe: jest\n          .fn()\n          .mockImplementation(\n            (_key, _deliveryMode, callback: (remoteConfig: any, source: string, lastFetch: Date) => void) => {\n              // Simulate calling the callback with remote config that has undefined triggers\n              callback(\n                {\n                  labeledEvents: mockRemoteLabeledEvents,\n                  triggers: undefined,\n                },\n                'cache',\n                new Date(),\n              );\n            },\n          ),\n        unsubscribe: jest.fn(),\n        updateConfigs: jest.fn(),\n      };\n\n      // Start with local pageActions that also has undefined triggers\n      const autocaptureConfig: ElementInteractionsOptions = {\n        pageActions: {\n          labeledEvents: mockLabeledEvents,\n          triggers: undefined as unknown as Trigger[],\n        },\n      };\n\n      plugin = autocapturePlugin(autocaptureConfig);\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n        fetchRemoteConfig: true,\n        remoteConfigClient: mockRemoteConfigClient,\n      };\n\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      // Wait for remote config to be processed\n      await new Promise((resolve) => setTimeout(resolve, 100));\n\n      // The spy should have been called twice:\n      // 1. Once during initial plugin creation with empty array (local triggers undefined)\n      // 2. Once during recomputePageActionsData with empty array (remote triggers also undefined)\n      expect(createLabeledEventToTriggerMapSpy).toHaveBeenCalledTimes(2);\n\n      // Both calls should receive empty array due to the \"?? []\" fallback\n      expect(createLabeledEventToTriggerMapSpy.mock.calls[0][0]).toEqual([]); // Initial call\n      expect(createLabeledEventToTriggerMapSpy.mock.calls[1][0]).toEqual([]); // recomputePageActionsData call\n\n      // No errors should be logged\n      expect(loggerProvider.error).not.toHaveBeenCalled();\n\n      createLabeledEventToTriggerMapSpy.mockRestore();\n    });\n  });\n\n  describe('plugin initialization without pageActions', () => {\n    it('should handle initialization without pageActions', async () => {\n      const autocaptureConfig: ElementInteractionsOptions = {};\n\n      plugin = autocapturePlugin(autocaptureConfig);\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n      };\n\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      expect(plugin?.name).toBe('@amplitude/plugin-autocapture-browser');\n      expect(plugin?.type).toBe('enrichment');\n    });\n\n    it('should handle undefined pageActions', async () => {\n      const autocaptureConfig: ElementInteractionsOptions = {\n        pageActions: undefined,\n      };\n\n      plugin = autocapturePlugin(autocaptureConfig);\n      const config: Partial<BrowserConfig> = {\n        defaultTracking: false,\n        loggerProvider: loggerProvider,\n      };\n\n      await plugin?.setup?.(config as BrowserConfig, instance);\n\n      expect(plugin?.name).toBe('@amplitude/plugin-autocapture-browser');\n      expect(plugin?.type).toBe('enrichment');\n    });\n  });\n});\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/test/setup.ts",
    "content": "require('css.escape');\n\n// Polyfill innerText for jsdom since it doesn't support it properly\nObject.defineProperty(HTMLElement.prototype, 'innerText', {\n  get(this: HTMLElement): string {\n    return this.textContent ?? '';\n  },\n  set(this: HTMLElement, value: string) {\n    this.textContent = value;\n  },\n});\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/test/utils.ts",
    "content": "/* eslint-disable no-restricted-globals, @typescript-eslint/no-empty-function, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-assignment */\n\nexport const mockWindowLocationFromURL = (url: URL) => {\n  window.location.href = url.toString();\n  window.location.search = url.search;\n  window.location.hostname = url.hostname;\n  window.location.pathname = url.pathname;\n};\n\nexport const dispatchUnhandledRejection = (window: Window, reason: unknown = new Error('Synthetic rejection')) => {\n  const promise = Promise.reject(reason);\n  promise.catch(() => {}); // prevent Node from treating it as truly unhandled\n\n  const evt = new (window as any).Event('unhandledrejection', { cancelable: true });\n\n  // Match browser PromiseRejectionEvent shape:\n  evt.reason = reason;\n  evt.promise = promise;\n\n  window.dispatchEvent(evt);\n  return { event: evt, promise };\n};\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/tsconfig.es5.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/cjs\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/tsconfig.esm.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"es6\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/esm\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-autocapture-browser/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src/**/*\", \"test/**/*\", \"e2e/**/*\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"esModuleInterop\": true,\n    \"lib\": [\"dom\"],\n    \"noEmit\": true,\n    \"rootDir\": \".\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-custom-enrichment-browser/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.1.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-custom-enrichment-browser@0.1.7...@amplitude/plugin-custom-enrichment-browser@0.1.8) (2026-04-28)\n\n**Note:** Version bump only for package @amplitude/plugin-custom-enrichment-browser\n\n\n\n\n\n## [0.1.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-custom-enrichment-browser@0.1.6...@amplitude/plugin-custom-enrichment-browser@0.1.7) (2026-04-22)\n\n**Note:** Version bump only for package @amplitude/plugin-custom-enrichment-browser\n\n\n\n\n\n## [0.1.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-custom-enrichment-browser@0.1.5...@amplitude/plugin-custom-enrichment-browser@0.1.6) (2026-04-21)\n\n**Note:** Version bump only for package @amplitude/plugin-custom-enrichment-browser\n\n\n\n\n\n## [0.1.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-custom-enrichment-browser@0.1.4...@amplitude/plugin-custom-enrichment-browser@0.1.5) (2026-04-14)\n\n**Note:** Version bump only for package @amplitude/plugin-custom-enrichment-browser\n\n\n\n\n\n## [0.1.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-custom-enrichment-browser@0.1.3...@amplitude/plugin-custom-enrichment-browser@0.1.4) (2026-04-09)\n\n**Note:** Version bump only for package @amplitude/plugin-custom-enrichment-browser\n\n\n\n\n\n## [0.1.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-custom-enrichment-browser@0.1.2...@amplitude/plugin-custom-enrichment-browser@0.1.3) (2026-04-01)\n\n**Note:** Version bump only for package @amplitude/plugin-custom-enrichment-browser\n\n\n\n\n\n## [0.1.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-custom-enrichment-browser@0.1.1...@amplitude/plugin-custom-enrichment-browser@0.1.2) (2026-03-26)\n\n**Note:** Version bump only for package @amplitude/plugin-custom-enrichment-browser\n\n\n\n\n\n## [0.1.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-custom-enrichment-browser@0.1.0...@amplitude/plugin-custom-enrichment-browser@0.1.1) (2026-03-23)\n\n**Note:** Version bump only for package @amplitude/plugin-custom-enrichment-browser\n\n\n\n\n\n# 0.1.0 (2026-03-20)\n\n\n### Features\n\n* **plugin-custom-enrichment:** add custom enrichment plugin ([#1339](https://github.com/amplitude/Amplitude-TypeScript/issues/1339)) ([b236190](https://github.com/amplitude/Amplitude-TypeScript/commit/b236190fa30d0e4325c37b8896824e11f980e20c))\n* **plugin-custom-enrichment:** add plugin based on remote config settings ([#1586](https://github.com/amplitude/Amplitude-TypeScript/issues/1586)) ([617ebfe](https://github.com/amplitude/Amplitude-TypeScript/commit/617ebfe7aaee04b0aef3db09b48ed11bad9a6ca3))\n\n\n\n\n\n# Change Log\n"
  },
  {
    "path": "packages/plugin-custom-enrichment-browser/README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://amplitude.com\" target=\"_blank\" align=\"center\">\n    <img src=\"https://static.amplitude.com/lightning/46c85bfd91905de8047f1ee65c7c93d6fa9ee6ea/static/media/amplitude-logo-with-text.4fb9e463.svg\" width=\"280\">\n  </a>\n  <br />\n</p>\n\n# @amplitude/plugin-custom-enrichment-browser\n\nOfficial Browser SDK plugin for custom enrichment\n\n## Installation\n\nThis package is published on NPM registry and is available to be installed using npm and yarn.\n\n```sh\n# npm\nnpm install @amplitude/plugin-custom-enrichment-browser\n\n# yarn\nyarn add @amplitude/plugin-custom-enrichment-browser\n```\n\n## Usage\n\nThis plugin works on top of Amplitude Browser SDK and allows the user to execute custom functionality on their events. To use this plugin, you need to install `@amplitude/analytics-browser` version `v2.0.0` or later.\n\n### 1. Import Amplitude packages\n\n* `@amplitude/plugin-custom-enrichment-browser`\n\n```typescript\nimport { customEnrichmentPlugin } from '@amplitude/plugin-custom-enrichment-browser';\n```\n\n### 2. Instantiate custom enrichment plugin\n```typescript\nconst customEnrichmentPlugin = customEnrichmentPlugin();\n```\n\n#### Options\n\n\n### 3. Install plugin to Amplitude SDK\n\n```typescript\namplitude.add(customEnrichmentPlugin);\n```\n\n### 4. Initialize Amplitude SDK\n\n```typescript\namplitude.init('API_KEY');\n```\n\n## Result\nThis plugin executes a user-defined script, defined within Amplitude Remote Configuration Settings.\n\n#### Event type\n* No event type added\n\n#### Event properties\n* Defined by user"
  },
  {
    "path": "packages/plugin-custom-enrichment-browser/jest.config.js",
    "content": "const baseConfig = require('../../jest.config.js');\nconst package = require('./package');\n\nmodule.exports = {\n  ...baseConfig,\n  displayName: package.name,\n  rootDir: '.',\n  testEnvironment: 'jsdom',\n  coveragePathIgnorePatterns: ['index.ts'],\n};\n"
  },
  {
    "path": "packages/plugin-custom-enrichment-browser/package.json",
    "content": "{\n  \"name\": \"@amplitude/plugin-custom-enrichment-browser\",\n  \"version\": \"0.1.8\",\n  \"description\": \"\",\n  \"author\": \"Amplitude Inc\",\n  \"homepage\": \"https://github.com/amplitude/Amplitude-TypeScript\",\n  \"license\": \"MIT\",\n  \"main\": \"lib/cjs/index.js\",\n  \"module\": \"lib/esm/index.js\",\n  \"types\": \"lib/esm/index.d.ts\",\n  \"sideEffects\": false,\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"tag\": \"latest\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/amplitude/Amplitude-TypeScript.git\"\n  },\n  \"scripts\": {\n    \"build\": \"pnpm bundle && pnpm build:es5 && pnpm build:esm\",\n    \"bundle\": \"rollup --config rollup.config.js\",\n    \"build:es5\": \"tsc -p ./tsconfig.es5.json\",\n    \"build:esm\": \"tsc -p ./tsconfig.esm.json\",\n    \"watch\": \"tsc -p ./tsconfig.esm.json --watch\",\n    \"clean\": \"rimraf node_modules lib coverage\",\n    \"fix\": \"pnpm fix:eslint & pnpm fix:prettier\",\n    \"fix:eslint\": \"eslint '{src,test}/**/*.ts' --fix\",\n    \"fix:prettier\": \"prettier --write \\\"{src,test}/**/*.ts\\\"\",\n    \"lint\": \"pnpm lint:eslint & pnpm lint:prettier\",\n    \"lint:eslint\": \"eslint '{src,test}/**/*.ts'\",\n    \"lint:prettier\": \"prettier --check \\\"{src,test}/**/*.ts\\\"\",\n    \"test\": \"jest\",\n    \"typecheck\": \"tsc -p ./tsconfig.json\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/amplitude/Amplitude-TypeScript/issues\"\n  },\n  \"dependencies\": {\n    \"@amplitude/analytics-core\": \"workspace:*\",\n    \"tslib\": \"^2.4.1\"\n  },\n  \"devDependencies\": {\n    \"@rollup/plugin-commonjs\": \"^23.0.4\",\n    \"@rollup/plugin-node-resolve\": \"^15.0.1\",\n    \"@rollup/plugin-typescript\": \"^10.0.1\",\n    \"rollup\": \"^2.79.1\",\n    \"rollup-plugin-execute\": \"^1.1.1\",\n    \"rollup-plugin-gzip\": \"^3.1.0\",\n    \"rollup-plugin-terser\": \"^7.0.2\"\n  },\n  \"files\": [\n    \"lib\"\n  ]\n}\n"
  },
  {
    "path": "packages/plugin-custom-enrichment-browser/rollup.config.js",
    "content": "import { iife, umd } from '../../scripts/build/rollup.config';\n\niife.input = umd.input;\niife.output.name = 'amplitudeCustomEnrichmentPlugin';\n\n\nif (process.env.NODE_ENV === 'development') {\n  iife.output.sourcemap = 'inline';\n}\nexport default [umd, iife];"
  },
  {
    "path": "packages/plugin-custom-enrichment-browser/src/custom-enrichment.ts",
    "content": "import type {\n  BrowserClient,\n  BrowserConfig,\n  CustomEnrichmentOptions,\n  EnrichmentPlugin,\n  Event,\n  ILogger,\n  RemoteConfig,\n} from '@amplitude/analytics-core';\n\nexport const customEnrichmentPlugin = (): EnrichmentPlugin => {\n  let loggerProvider: ILogger | undefined;\n  let unsubscribe: (() => void) | undefined;\n\n  let enrichEvent: ((event: Event) => Event) | undefined;\n\n  function isCustomEnrichmentConfig(config: RemoteConfig): config is CustomEnrichmentOptions {\n    // 1. Check if it's an object and not null\n    if (typeof config !== 'object' || config === null) {\n      return false;\n    }\n\n    // 2. Validate specific properties exist and are the correct type\n    return 'body' in config && typeof config.body === 'string';\n  }\n\n  function createEnrichEvent(body: string): (event: Event) => Event {\n    if (body) {\n      try {\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-implied-eval\n        const fn = new Function('return ' + body)() as unknown;\n        if (typeof fn === 'function') {\n          return fn as (event: Event) => Event;\n        }\n        loggerProvider?.error('Custom enrichment body did not evaluate to a function');\n      } catch (error) {\n        loggerProvider?.error('Could not create custom enrichment function', error);\n      }\n    }\n\n    return (event: Event) => event;\n  }\n\n  const plugin: EnrichmentPlugin = {\n    name: '@amplitude/plugin-custom-enrichment-browser',\n    type: 'enrichment',\n\n    setup: async (config: BrowserConfig, _: BrowserClient) => {\n      loggerProvider = config.loggerProvider;\n      loggerProvider?.log('Installing @amplitude/plugin-custom-enrichment-browser');\n\n      // Fetch remote config for custom enrichment in a non-blocking manner\n      if (config.remoteConfig?.fetchRemoteConfig) {\n        if (!config.remoteConfigClient) {\n          // TODO(xinyi): Diagnostics.recordEvent\n          loggerProvider?.debug('Remote config client is not provided, skipping remote config fetch');\n        } else {\n          const subscriptionId = config.remoteConfigClient.subscribe(\n            'configs.analyticsSDK.browserSDK.customEnrichment',\n            'all',\n            (remoteConfig: RemoteConfig | null) => {\n              if (remoteConfig && isCustomEnrichmentConfig(remoteConfig)) {\n                enrichEvent = createEnrichEvent(remoteConfig.body || '');\n              } else {\n                // if there is no valid body, clear enrich event\n                enrichEvent = createEnrichEvent('');\n              }\n            },\n          );\n          unsubscribe = () => config.remoteConfigClient?.unsubscribe(subscriptionId);\n        }\n      }\n    },\n    execute: async (event: Event) => {\n      if (enrichEvent) {\n        try {\n          return enrichEvent(event) ?? null;\n        } catch (error) {\n          loggerProvider?.error('Could not execute custom enrichment function', error);\n          return event;\n        }\n      }\n\n      return event;\n    },\n    teardown: async () => {\n      if (unsubscribe) {\n        unsubscribe();\n      }\n    },\n  };\n\n  return plugin;\n};\n"
  },
  {
    "path": "packages/plugin-custom-enrichment-browser/src/index.ts",
    "content": "export { customEnrichmentPlugin } from './custom-enrichment';\nexport { customEnrichmentPlugin as plugin } from './custom-enrichment';\n"
  },
  {
    "path": "packages/plugin-custom-enrichment-browser/test/custom-enrichment.test.ts",
    "content": "import {\n  type BrowserClient,\n  type BrowserConfig,\n  type ILogger,\n  IRemoteConfigClient,\n  Logger,\n  LogLevel,\n} from '@amplitude/analytics-core';\nimport { customEnrichmentPlugin } from '../src/custom-enrichment';\n\n// Mock BrowserClient implementation\nconst createMockBrowserClient = (): jest.Mocked<BrowserClient> => {\n  const mockClient = {\n    init: jest.fn().mockReturnValue({\n      promise: Promise.resolve(),\n    }),\n    add: jest.fn(),\n    remove: jest.fn(),\n    track: jest.fn(),\n    logEvent: jest.fn(),\n    identify: jest.fn(),\n    groupIdentify: jest.fn(),\n    setGroup: jest.fn(),\n    revenue: jest.fn(),\n    flush: jest.fn(),\n    getUserId: jest.fn(),\n    setUserId: jest.fn(),\n    getDeviceId: jest.fn(),\n    setDeviceId: jest.fn(),\n    getSessionId: jest.fn(),\n    setSessionId: jest.fn(),\n    extendSession: jest.fn(),\n    reset: jest.fn(),\n    setOptOut: jest.fn(),\n    setTransport: jest.fn(),\n  } as unknown as jest.Mocked<BrowserClient>;\n\n  mockClient.track.mockReturnValue({\n    promise: Promise.resolve({\n      code: 200,\n      message: '',\n      event: {\n        event_type: 'test-event',\n      },\n    }),\n  });\n\n  return mockClient;\n};\n\nconst createMockConfig = (): BrowserConfig => ({\n  apiKey: 'test-api-key',\n  flushQueueSize: 10,\n  flushIntervalMillis: 1000,\n  logLevel: LogLevel.Verbose,\n  loggerProvider: new Logger(),\n  sessionTimeout: 30000,\n  flushMaxRetries: 5,\n  optOut: false,\n  useBatch: false,\n  fetchRemoteConfig: false,\n  trackingOptions: {\n    ipAddress: true,\n    language: true,\n    platform: true,\n  },\n  cookieStorage: {\n    isEnabled: jest.fn().mockReturnValue(true),\n    get: jest.fn(),\n    set: jest.fn(),\n    remove: jest.fn(),\n    reset: jest.fn(),\n    getRaw: jest.fn(),\n  },\n  storageProvider: {\n    isEnabled: jest.fn().mockReturnValue(true),\n    get: jest.fn(),\n    set: jest.fn(),\n    remove: jest.fn(),\n    reset: jest.fn(),\n    getRaw: jest.fn(),\n  },\n  transportProvider: {\n    send: jest.fn(),\n  },\n});\n\ndescribe('Custom Enrichment Plugin', () => {\n  let mockClient: jest.Mocked<BrowserClient>;\n  let mockConfig: BrowserConfig;\n  let mockLogger: ILogger;\n\n  beforeEach(() => {\n    jest.clearAllMocks();\n    mockClient = createMockBrowserClient();\n    mockConfig = createMockConfig();\n    mockLogger = {\n      log: jest.fn(),\n      error: jest.fn(),\n      warn: jest.fn(),\n      debug: jest.fn(),\n      logLevel: LogLevel.Verbose,\n      disable: jest.fn(),\n      enable: jest.fn(),\n    } as ILogger;\n    mockConfig.loggerProvider = mockLogger;\n  });\n  describe('execute', () => {\n    it('should execute custom enrichment function successfully', async () => {\n      const customFunction = `function(event) {\n        event.event_properties = event.event_properties || {};\n        event.event_properties.custom_field = 'enriched_value';\n        return event;\n      }`;\n      const plugin = customEnrichmentPlugin();\n\n      // Mock remote config to provide the custom function\n      const mockRemoteConfigClient = {\n        subscribe: jest.fn((key, _audience, callback) => {\n          if (key === 'configs.analyticsSDK.browserSDK.customEnrichment') {\n            callback({ body: customFunction });\n          }\n        }),\n      };\n\n      const configWithRemoteConfig = {\n        ...mockConfig,\n        remoteConfigClient: mockRemoteConfigClient,\n        remoteConfig: {\n          fetchRemoteConfig: true,\n        },\n      };\n\n      await plugin.setup?.(configWithRemoteConfig, mockClient);\n\n      const originalEvent = {\n        event_type: 'test_event',\n        event_properties: { original: 'value' },\n      };\n\n      const result = await plugin.execute?.(originalEvent);\n\n      expect(result).toEqual({\n        event_type: 'test_event',\n        event_properties: {\n          original: 'value',\n          custom_field: 'enriched_value',\n        },\n      });\n    });\n\n    it('should handle enrichment function that adds or modifies the event', async () => {\n      const timestamp = Date.now();\n      const customFunction = `function(event) {\n        event.user_properties = { custom_user_prop: 'user_value' };\n        event.event_properties = { ...event.event_properties, timestamp: ${timestamp} };\n        event.event_type = 'enriched_event';\n        return event;\n      }`;\n      const plugin = customEnrichmentPlugin();\n\n      // Mock remote config to provide the custom function\n      const mockRemoteConfigClient = {\n        subscribe: jest.fn((key, _audience, callback) => {\n          if (key === 'configs.analyticsSDK.browserSDK.customEnrichment') {\n            callback({ body: customFunction });\n          }\n        }),\n      };\n\n      const configWithRemoteConfig = {\n        ...mockConfig,\n        remoteConfigClient: mockRemoteConfigClient,\n        remoteConfig: {\n          fetchRemoteConfig: true,\n        },\n      };\n\n      await plugin.setup?.(configWithRemoteConfig, mockClient);\n\n      const originalEvent = {\n        event_type: 'test_event',\n        event_properties: { test: 'value' },\n      };\n\n      const result = await plugin.execute?.(originalEvent);\n\n      expect(result?.event_type).toBe('enriched_event');\n      expect(result?.event_properties).toStrictEqual({ test: 'value', timestamp: timestamp });\n      expect(result?.user_properties).toStrictEqual({ custom_user_prop: 'user_value' });\n    });\n\n    it('should return original event if enrichment function throws error', async () => {\n      const invalidFunction = `function(event) {\n        throw new Error('Invalid enrichment function');\n      }`;\n      const plugin = customEnrichmentPlugin();\n\n      // Mock remote config to provide the invalid function\n      const mockRemoteConfigClient = {\n        subscribe: jest.fn((key, _audience, callback) => {\n          if (key === 'configs.analyticsSDK.browserSDK.customEnrichment') {\n            callback({ body: invalidFunction });\n          }\n        }),\n      };\n\n      const configWithRemoteConfig = {\n        ...mockConfig,\n        remoteConfigClient: mockRemoteConfigClient,\n        remoteConfig: {\n          fetchRemoteConfig: true,\n        },\n      };\n\n      await plugin.setup?.(configWithRemoteConfig, mockClient);\n\n      const originalEvent = { event_type: 'test_event' };\n      const result = await plugin.execute?.(originalEvent);\n\n      expect(result).toEqual(originalEvent);\n      expect((mockLogger.error as jest.Mock).mock.calls.length).toBe(1);\n      expect((mockLogger.error as jest.Mock).mock.calls[0][0]).toBe('Could not execute custom enrichment function');\n    });\n\n    it('should handle undefined loggerProvider in execute error case', async () => {\n      const configWithoutLogger = { ...mockConfig, loggerProvider: undefined as unknown as Logger } as BrowserConfig;\n      const plugin = customEnrichmentPlugin();\n\n      // Mock remote config to provide the error function\n      const mockRemoteConfigClient = {\n        subscribe: jest.fn((key, _audience, callback) => {\n          if (key === 'configs.analyticsSDK.browserSDK.customEnrichment') {\n            callback({ body: 'function(event) { throw new Error(\"test error\"); }' });\n          }\n        }),\n      };\n\n      const configWithRemoteConfig = {\n        ...configWithoutLogger,\n        remoteConfigClient: mockRemoteConfigClient,\n        remoteConfig: {\n          fetchRemoteConfig: true,\n        },\n      };\n\n      await plugin.setup?.(configWithRemoteConfig, mockClient);\n\n      const originalEvent = { event_type: 'test_event' };\n      const result = await plugin.execute?.(originalEvent);\n\n      // Should return original event even with undefined loggerProvider\n      expect(result).toEqual(originalEvent);\n    });\n\n    it('should return original event if enrichment function is invalid', async () => {\n      const invalidFunction = 'invalid javascript syntax {';\n      const plugin = customEnrichmentPlugin();\n\n      // Mock remote config to provide the invalid function\n      const mockRemoteConfigClient = {\n        subscribe: jest.fn((key, _audience, callback) => {\n          if (key === 'configs.analyticsSDK.browserSDK.customEnrichment') {\n            callback({ body: invalidFunction });\n          }\n        }),\n      };\n\n      const configWithRemoteConfig = {\n        ...mockConfig,\n        remoteConfigClient: mockRemoteConfigClient,\n        remoteConfig: {\n          fetchRemoteConfig: true,\n        },\n      };\n\n      await plugin.setup?.(configWithRemoteConfig, mockClient);\n\n      const originalEvent = { event_type: 'test_event' };\n      const result = await plugin.execute?.(originalEvent);\n\n      expect(result).toEqual(originalEvent);\n      expect((mockLogger.error as jest.Mock).mock.calls.length).toBe(1);\n      expect((mockLogger.error as jest.Mock).mock.calls[0][0]).toBe('Could not create custom enrichment function');\n    });\n\n    it('should handle empty enrichment function', async () => {\n      const plugin = customEnrichmentPlugin();\n\n      // Mock remote config to provide empty function\n      const mockRemoteConfigClient = {\n        subscribe: jest.fn((key, _audience, callback) => {\n          if (key === 'configs.analyticsSDK.browserSDK.customEnrichment') {\n            callback({ body: '' });\n          }\n        }),\n      };\n\n      const configWithRemoteConfig = {\n        ...mockConfig,\n        remoteConfigClient: mockRemoteConfigClient,\n        remoteConfig: {\n          fetchRemoteConfig: true,\n        },\n      };\n\n      await plugin.setup?.(configWithRemoteConfig, mockClient);\n\n      const originalEvent = { event_type: 'test_event' };\n      const result = await plugin.execute?.(originalEvent);\n\n      expect(result).toEqual(originalEvent);\n    });\n\n    it('should handle enrichment function with only comments', async () => {\n      const plugin = customEnrichmentPlugin();\n\n      // Mock remote config to provide comment-only function\n      const mockRemoteConfigClient = {\n        subscribe: jest.fn((key, _audience, callback) => {\n          if (key === 'configs.analyticsSDK.browserSDK.customEnrichment') {\n            callback({ body: '// This is just a comment' });\n          }\n        }),\n      };\n\n      const configWithRemoteConfig = {\n        ...mockConfig,\n        remoteConfigClient: mockRemoteConfigClient,\n        remoteConfig: {\n          fetchRemoteConfig: true,\n        },\n      };\n\n      await plugin.setup?.(configWithRemoteConfig, mockClient);\n\n      const originalEvent = { event_type: 'test_event' };\n      const result = await plugin.execute?.(originalEvent);\n\n      expect(result).toEqual(originalEvent);\n      expect((mockLogger.error as jest.Mock).mock.calls.length).toBe(1);\n      expect((mockLogger.error as jest.Mock).mock.calls[0][0]).toBe(\n        'Custom enrichment body did not evaluate to a function',\n      );\n    });\n\n    it('should return null when enrichment function returns undefined', async () => {\n      const plugin = customEnrichmentPlugin();\n\n      const mockRemoteConfigClient = {\n        subscribe: jest.fn((key, _audience, callback) => {\n          if (key === 'configs.analyticsSDK.browserSDK.customEnrichment') {\n            callback({ body: 'function(event) {}' });\n          }\n        }),\n      };\n\n      const configWithRemoteConfig = {\n        ...mockConfig,\n        remoteConfigClient: mockRemoteConfigClient,\n        remoteConfig: {\n          fetchRemoteConfig: true,\n        },\n      };\n\n      await plugin.setup?.(configWithRemoteConfig, mockClient);\n\n      const originalEvent = { event_type: 'test_event' };\n      const result = await plugin.execute?.(originalEvent);\n\n      expect(result).toBeNull();\n    });\n\n    it('should handle remote config with invalid config', async () => {\n      const plugin = customEnrichmentPlugin();\n\n      const mockRemoteConfigClient = {\n        subscribe: jest.fn((key, _audience, callback) => {\n          if (key === 'configs.analyticsSDK.browserSDK.customEnrichment') {\n            callback('not an object');\n          }\n        }),\n      };\n\n      const configWithRemoteConfig = {\n        ...mockConfig,\n        remoteConfigClient: mockRemoteConfigClient,\n        remoteConfig: {\n          fetchRemoteConfig: true,\n        },\n      };\n\n      await plugin.setup?.(configWithRemoteConfig, mockClient);\n\n      const originalEvent = { event_type: 'test_event' };\n      const result = await plugin.execute?.(originalEvent);\n\n      expect(result).toEqual(originalEvent);\n    });\n\n    it('should handle null remote config', async () => {\n      const plugin = customEnrichmentPlugin();\n\n      const mockRemoteConfigClient = {\n        subscribe: jest.fn((key, _audience, callback) => {\n          if (key === 'configs.analyticsSDK.browserSDK.customEnrichment') {\n            callback(null);\n          }\n        }),\n      };\n\n      const configWithRemoteConfig = {\n        ...mockConfig,\n        remoteConfigClient: mockRemoteConfigClient,\n        remoteConfig: {\n          fetchRemoteConfig: true,\n        },\n      };\n\n      await plugin.setup?.(configWithRemoteConfig, mockClient);\n\n      const originalEvent = { event_type: 'test_event' };\n      const result = await plugin.execute?.(originalEvent);\n\n      expect(result).toEqual(originalEvent);\n    });\n\n    it('should handle null remote config body', async () => {\n      const plugin = customEnrichmentPlugin();\n\n      const mockRemoteConfigClient = {\n        subscribe: jest.fn((key, _audience, callback) => {\n          if (key === 'configs.analyticsSDK.browserSDK.customEnrichment') {\n            callback({ body: null });\n          }\n        }),\n      };\n\n      const configWithRemoteConfig = {\n        ...mockConfig,\n        remoteConfigClient: mockRemoteConfigClient,\n        remoteConfig: {\n          fetchRemoteConfig: true,\n        },\n      };\n\n      await plugin.setup?.(configWithRemoteConfig, mockClient);\n\n      const originalEvent = { event_type: 'test_event' };\n      const result = await plugin.execute?.(originalEvent);\n\n      expect(result).toEqual(originalEvent);\n    });\n\n    it('should handle when remote config body becomes null', async () => {\n      const plugin = customEnrichmentPlugin();\n      const customFunction = `function(event) {\n        event.event_properties = { test: \"value\" };\n        return event;\n      }`;\n\n      // Store the callback so we can invoke it multiple times to simulate config changes\n      let subscribedCallback: ((config: any) => void) | undefined;\n\n      const mockRemoteConfigClient = {\n        subscribe: jest.fn((key, _audience, callback) => {\n          if (key === 'configs.analyticsSDK.browserSDK.customEnrichment') {\n            subscribedCallback = callback;\n            // Initial call with valid custom function\n            callback({ body: customFunction });\n          }\n        }),\n      };\n\n      const configWithRemoteConfig = {\n        ...mockConfig,\n        remoteConfigClient: mockRemoteConfigClient,\n        remoteConfig: {\n          fetchRemoteConfig: true,\n        },\n      };\n\n      await plugin.setup?.(configWithRemoteConfig, mockClient);\n\n      // First execution should apply the custom enrichment\n      const firstEvent = { event_type: 'test_event' };\n      const firstResult = await plugin.execute?.(firstEvent);\n      expect(firstResult).toEqual({\n        event_type: 'test_event',\n        event_properties: { test: 'value' },\n      });\n\n      // Now simulate the remote config changing to null\n      subscribedCallback?.({ body: null });\n\n      // Second execution should return the event unchanged (enrichment disabled)\n      const secondEvent = { event_type: 'test_event_2' };\n      const secondResult = await plugin.execute?.(secondEvent);\n      expect(secondResult).toEqual(secondEvent);\n    });\n  });\n\n  describe('remote config integration', () => {\n    it('should handle missing remote config client', async () => {\n      const plugin = customEnrichmentPlugin();\n\n      const configWithRemoteConfig = {\n        ...mockConfig,\n        remoteConfigClient: undefined,\n        remoteConfig: {\n          fetchRemoteConfig: true,\n        },\n      };\n\n      await plugin.setup?.(configWithRemoteConfig, mockClient);\n\n      const originalEvent = { event_type: 'test_event' };\n      const result = await plugin.execute?.(originalEvent);\n\n      // Should return original event when no remote config is available\n      expect(result).toEqual(originalEvent);\n      expect((mockLogger.debug as jest.Mock).mock.calls.length).toBe(1);\n      expect((mockLogger.debug as jest.Mock).mock.calls[0][0]).toBe(\n        'Remote config client is not provided, skipping remote config fetch',\n      );\n    });\n\n    it('should handle fetchRemoteConfig disabled', async () => {\n      const plugin = customEnrichmentPlugin();\n\n      const configWithoutRemoteConfig = {\n        ...mockConfig,\n        remoteConfigClient: undefined,\n        remoteConfig: {\n          fetchRemoteConfig: false,\n        },\n      };\n\n      await plugin.setup?.(configWithoutRemoteConfig, mockClient);\n\n      const originalEvent = { event_type: 'test_event' };\n      const result = await plugin.execute?.(originalEvent);\n\n      // Should return original event when remote config is disabled\n      expect(result).toEqual(originalEvent);\n    });\n\n    it('should handle remote config subscription', async () => {\n      const plugin = customEnrichmentPlugin();\n\n      const mockRemoteConfigClient = {\n        subscribe: jest.fn(),\n      };\n\n      const configWithRemoteConfig = {\n        ...mockConfig,\n        remoteConfigClient: mockRemoteConfigClient,\n        remoteConfig: {\n          fetchRemoteConfig: true,\n        },\n      };\n\n      await plugin.setup?.(configWithRemoteConfig, mockClient);\n\n      // Verify that subscribe was called with the correct parameters\n      expect(mockRemoteConfigClient.subscribe).toHaveBeenCalled();\n      expect(mockRemoteConfigClient.subscribe.mock.calls[0][0]).toBe(\n        'configs.analyticsSDK.browserSDK.customEnrichment',\n      );\n      expect(mockRemoteConfigClient.subscribe.mock.calls[0][1]).toBe('all');\n      expect(typeof mockRemoteConfigClient.subscribe.mock.calls[0][2]).toBe('function');\n    });\n  });\n\n  describe('teardown', () => {\n    it('should complete teardown without errors and unsubscribe from remote config', async () => {\n      const plugin = customEnrichmentPlugin();\n\n      const mockRemoteConfigClient = {\n        subscribe: jest.fn(),\n        unsubscribe: jest.fn(),\n      };\n\n      const configWithRemoteConfig = {\n        ...mockConfig,\n        remoteConfigClient: mockRemoteConfigClient,\n        remoteConfig: {\n          fetchRemoteConfig: true,\n        },\n      };\n      await plugin.setup?.(configWithRemoteConfig, mockClient);\n      await expect(plugin.teardown?.()).resolves.toBeUndefined();\n      expect(mockRemoteConfigClient.unsubscribe).toHaveBeenCalled();\n    });\n\n    it('should handle when config.remoteConfigClient is undefined', async () => {\n      const plugin = customEnrichmentPlugin();\n\n      const mockRemoteConfigClient = {\n        subscribe: jest.fn(),\n      } as unknown as IRemoteConfigClient;\n\n      const configWithRemoteConfig = {\n        ...mockConfig,\n        remoteConfigClient: mockRemoteConfigClient,\n        remoteConfig: {\n          fetchRemoteConfig: true,\n        },\n      };\n      await plugin.setup?.(configWithRemoteConfig, mockClient);\n      configWithRemoteConfig.remoteConfigClient = undefined as unknown as IRemoteConfigClient;\n\n      await expect(plugin.teardown?.()).resolves.toBeUndefined();\n    });\n\n    it('should handle when unsubscribe is undefined', async () => {\n      const plugin = customEnrichmentPlugin();\n\n      const mockRemoteConfigClient = {\n        subscribe: jest.fn(),\n        unsubscribe: jest.fn(),\n      };\n\n      const configWithRemoteConfig = {\n        ...mockConfig,\n        remoteConfigClient: mockRemoteConfigClient,\n        remoteConfig: {\n          fetchRemoteConfig: true,\n        },\n      };\n\n      await plugin.setup?.(configWithRemoteConfig, mockClient);\n      await expect(plugin.teardown?.()).resolves.toBeUndefined();\n    });\n  });\n\n  describe('undefined loggerProvider', () => {\n    it('should handle undefined loggerProvider in setup', async () => {\n      const configWithoutLogger = { ...mockConfig, loggerProvider: undefined } as unknown as BrowserConfig;\n      const plugin = customEnrichmentPlugin();\n\n      // Should not throw an error even with undefined loggerProvider\n      await expect(plugin.setup?.(configWithoutLogger, mockClient)).resolves.toBeUndefined();\n    });\n\n    it('should handle missing loggerProvider and missing remote config client', async () => {\n      const plugin = customEnrichmentPlugin();\n\n      const configWithRemoteConfig = {\n        ...mockConfig,\n        remoteConfigClient: undefined,\n        remoteConfig: {\n          fetchRemoteConfig: true,\n        },\n        loggerProvider: undefined,\n      } as unknown as BrowserConfig;\n\n      await plugin.setup?.(configWithRemoteConfig, mockClient);\n\n      const originalEvent = { event_type: 'test_event' };\n      const result = await plugin.execute?.(originalEvent);\n\n      // Should return original event when no remote config is available\n      expect(result).toEqual(originalEvent);\n    });\n\n    it('should handle undefined loggerProvider in execute error case', async () => {\n      const plugin = customEnrichmentPlugin();\n\n      // Mock remote config to provide the error function\n      const mockRemoteConfigClient = {\n        subscribe: jest.fn((key, _audience, callback) => {\n          if (key === 'configs.analyticsSDK.browserSDK.customEnrichment') {\n            callback({ body: 'function(event) { throw new Error(\"test error\"); }' });\n          }\n        }),\n      };\n\n      const configWithRemoteConfig = {\n        ...mockConfig,\n        remoteConfigClient: mockRemoteConfigClient,\n        remoteConfig: {\n          fetchRemoteConfig: true,\n        },\n        loggerProvider: undefined,\n      } as unknown as BrowserConfig;\n\n      await plugin.setup?.(configWithRemoteConfig, mockClient);\n\n      const originalEvent = { event_type: 'test_event' };\n      const result = await plugin.execute?.(originalEvent);\n\n      // Should return original event and not throw even with undefined loggerProvider\n      expect(result).toEqual(originalEvent);\n    });\n\n    it('should handle undefined loggerProvider in createEnrichEvent when body throws', async () => {\n      const plugin = customEnrichmentPlugin();\n\n      const mockRemoteConfigClient = {\n        subscribe: jest.fn((key, _audience, callback) => {\n          if (key === 'configs.analyticsSDK.browserSDK.customEnrichment') {\n            callback({ body: 'not an actual function' });\n          }\n        }),\n      };\n\n      const configWithRemoteConfig = {\n        ...mockConfig,\n        remoteConfigClient: mockRemoteConfigClient,\n        remoteConfig: {\n          fetchRemoteConfig: true,\n        },\n        loggerProvider: undefined,\n      } as unknown as BrowserConfig;\n\n      await plugin.setup?.(configWithRemoteConfig, mockClient);\n\n      const originalEvent = { event_type: 'test_event' };\n      const result = await plugin.execute?.(originalEvent);\n\n      expect(result).toEqual(originalEvent);\n    });\n\n    it('should handle undefined loggerProvider when body evaluates to non-function', async () => {\n      const plugin = customEnrichmentPlugin();\n\n      const mockRemoteConfigClient = {\n        subscribe: jest.fn((key, _audience, callback) => {\n          if (key === 'configs.analyticsSDK.browserSDK.customEnrichment') {\n            callback({ body: '\"a string, not a function\"' });\n          }\n        }),\n      };\n\n      const configWithRemoteConfig = {\n        ...mockConfig,\n        remoteConfigClient: mockRemoteConfigClient,\n        remoteConfig: {\n          fetchRemoteConfig: true,\n        },\n        loggerProvider: undefined,\n      } as unknown as BrowserConfig;\n\n      await plugin.setup?.(configWithRemoteConfig, mockClient);\n\n      const originalEvent = { event_type: 'test_event' };\n      const result = await plugin.execute?.(originalEvent);\n\n      expect(result).toEqual(originalEvent);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/plugin-custom-enrichment-browser/tsconfig.es5.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/cjs\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-custom-enrichment-browser/tsconfig.esm.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"es6\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/esm\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-custom-enrichment-browser/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src/**/*\", \"test/**/*\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"esModuleInterop\": true,\n    \"lib\": [\"dom\"],\n    \"noEmit\": true,\n    \"rootDir\": \".\",\n  }\n}\n"
  },
  {
    "path": "packages/plugin-event-property-attribution-browser/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.2.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-event-property-attribution-browser@0.1.2...@amplitude/plugin-event-property-attribution-browser@0.2.0) (2026-04-28)\n\n\n### Features\n\n* remove experimental request body compression backdoor ([#1699](https://github.com/amplitude/Amplitude-TypeScript/issues/1699)) ([98ecb9d](https://github.com/amplitude/Amplitude-TypeScript/commit/98ecb9dc1f3658cf6d0dfae1e9784335c9d33b5e))\n\n\n\n\n\n## [0.1.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-event-property-attribution-browser@0.1.1...@amplitude/plugin-event-property-attribution-browser@0.1.2) (2026-04-22)\n\n**Note:** Version bump only for package @amplitude/plugin-event-property-attribution-browser\n\n\n\n\n\n## [0.1.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-event-property-attribution-browser@0.1.0...@amplitude/plugin-event-property-attribution-browser@0.1.1) (2026-04-21)\n\n**Note:** Version bump only for package @amplitude/plugin-event-property-attribution-browser\n\n\n\n\n\n# 0.1.0 (2026-04-14)\n\n\n### Features\n\n* **analytics-browser:** event property attribution ([#1628](https://github.com/amplitude/Amplitude-TypeScript/issues/1628)) ([6d37e79](https://github.com/amplitude/Amplitude-TypeScript/commit/6d37e797976e0e77dc11046b9259eb4b80259996))\n\n\n\n\n\n# Changelog\n"
  },
  {
    "path": "packages/plugin-event-property-attribution-browser/README.md",
    "content": "# @amplitude/plugin-event-property-attribution-browser\n\nEvent property attribution enrichment plugin for the Amplitude Browser SDK.\n"
  },
  {
    "path": "packages/plugin-event-property-attribution-browser/jest.config.js",
    "content": "const baseConfig = require('../../jest.config.js');\nconst package = require('./package');\n\nmodule.exports = {\n  ...baseConfig,\n  displayName: package.name,\n  rootDir: '.',\n  testEnvironment: 'jsdom',\n  coveragePathIgnorePatterns: ['index.ts'],\n};\n"
  },
  {
    "path": "packages/plugin-event-property-attribution-browser/package.json",
    "content": "{\n  \"name\": \"@amplitude/plugin-event-property-attribution-browser\",\n  \"version\": \"0.2.0\",\n  \"description\": \"\",\n  \"author\": \"Amplitude Inc\",\n  \"homepage\": \"https://github.com/amplitude/Amplitude-TypeScript\",\n  \"license\": \"MIT\",\n  \"main\": \"lib/cjs/index.js\",\n  \"module\": \"lib/esm/index.js\",\n  \"types\": \"lib/esm/index.d.ts\",\n  \"sideEffects\": false,\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"tag\": \"latest\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/amplitude/Amplitude-TypeScript.git\"\n  },\n  \"scripts\": {\n    \"build\": \"pnpm bundle && pnpm build:es5 && pnpm build:esm\",\n    \"bundle\": \"rollup --config rollup.config.js\",\n    \"build:es5\": \"tsc -p ./tsconfig.es5.json\",\n    \"build:esm\": \"tsc -p ./tsconfig.esm.json\",\n    \"watch\": \"tsc -p ./tsconfig.esm.json --watch\",\n    \"clean\": \"rimraf node_modules lib coverage\",\n    \"fix\": \"pnpm fix:eslint & pnpm fix:prettier\",\n    \"fix:eslint\": \"eslint '{src,test}/**/*.ts' --fix\",\n    \"fix:prettier\": \"prettier --write \\\"{src,test}/**/*.ts\\\"\",\n    \"lint\": \"pnpm lint:eslint & pnpm lint:prettier\",\n    \"lint:eslint\": \"eslint '{src,test}/**/*.ts'\",\n    \"lint:prettier\": \"prettier --check \\\"{src,test}/**/*.ts\\\"\",\n    \"test\": \"jest\",\n    \"typecheck\": \"tsc -p ./tsconfig.json\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/amplitude/Amplitude-TypeScript/issues\"\n  },\n  \"dependencies\": {\n    \"@amplitude/analytics-core\": \"workspace:*\",\n    \"tslib\": \"^2.4.1\"\n  },\n  \"devDependencies\": {\n    \"@rollup/plugin-commonjs\": \"^23.0.4\",\n    \"@rollup/plugin-node-resolve\": \"^15.0.1\",\n    \"@rollup/plugin-typescript\": \"^10.0.1\",\n    \"rollup\": \"^2.79.1\",\n    \"rollup-plugin-execute\": \"^1.1.1\",\n    \"rollup-plugin-gzip\": \"^3.1.0\",\n    \"rollup-plugin-terser\": \"^7.0.2\"\n  },\n  \"files\": [\n    \"lib\"\n  ]\n}\n"
  },
  {
    "path": "packages/plugin-event-property-attribution-browser/rollup.config.js",
    "content": "import { umd } from '../../scripts/build/rollup.config';\n\nexport default [umd];\n"
  },
  {
    "path": "packages/plugin-event-property-attribution-browser/src/event-property-tracking.ts",
    "content": "import {\n  AttributionOptions,\n  BrowserClient,\n  BrowserConfig,\n  Campaign,\n  CampaignParser,\n  EnrichmentPlugin,\n  Event,\n  getGlobalScope,\n  ILogger,\n  omitUndefined,\n  SpecialEventType,\n} from '@amplitude/analytics-core';\n\nconst ATTRIBUTION_EVENT_TYPE = '[Amplitude] Attribution';\nconst EVENT_PROPERTY_EXCLUDED_EVENT_TYPES = new Set<string>([\n  SpecialEventType.IDENTIFY,\n  SpecialEventType.GROUP_IDENTIFY,\n]);\n\ntype HistoryStateMethod = History['pushState'];\n\nconst toEventPropertyCampaign = (campaign: Campaign): Partial<Campaign> => omitUndefined(campaign);\n\nexport const eventPropertyTrackingPlugin = (\n  options: AttributionOptions = {},\n): EnrichmentPlugin<BrowserClient, BrowserConfig> => {\n  const fallbackAttributionEvent = options.fallbackAttributionEvent ?? false;\n  const globalScope = getGlobalScope();\n  let amplitude: BrowserClient | undefined;\n  let loggerProvider: ILogger | undefined;\n  let eventPropertyCampaign: Partial<Campaign> = {};\n  let isTracking = false;\n  let isProxied = false;\n  let originalPushState: History['pushState'] | undefined;\n  let originalReplaceState: History['replaceState'] | undefined;\n  let installedPushState: History['pushState'] | undefined;\n  let installedReplaceState: History['replaceState'] | undefined;\n\n  const updateCampaignState = async () => {\n    const currentCampaign = await new CampaignParser().parse();\n    eventPropertyCampaign = toEventPropertyCampaign(currentCampaign);\n\n    if (fallbackAttributionEvent) {\n      /* istanbul ignore next */\n      loggerProvider?.log('Tracking attribution fallback event.');\n      /* istanbul ignore next */\n      amplitude?.track(ATTRIBUTION_EVENT_TYPE, eventPropertyCampaign);\n    }\n  };\n\n  const onHistoryChange = () => {\n    // CampaignParser.parse() is async by type, but its current implementation computes synchronously.\n    // In the Browser SDK, this history-triggered refresh starts immediately and reaches its continuation\n    // before Timeline.scheduleApply(0) runs event enrichment, so pushState()/replaceState() followed by\n    // track() in the same tick does not currently race. Revisit this assumption if campaign parsing or\n    // timeline scheduling becomes truly async in the future.\n    void updateCampaignState();\n  };\n\n  const createHistoryStateProxy = (method: HistoryStateMethod): HistoryStateMethod =>\n    new Proxy(method, {\n      apply: (target, thisArg, args: Parameters<HistoryStateMethod>) => {\n        Reflect.apply(target, thisArg, args);\n        if (isTracking) {\n          onHistoryChange();\n        }\n      },\n    });\n\n  return {\n    name: '@amplitude/plugin-event-property-attribution-browser',\n    type: 'enrichment',\n\n    setup: async (config, client) => {\n      amplitude = client;\n      loggerProvider = config.loggerProvider;\n      isTracking = true;\n\n      loggerProvider.log('Installing event property attribution tracking.');\n      await updateCampaignState();\n\n      if (!globalScope) {\n        return;\n      }\n\n      globalScope.addEventListener('popstate', onHistoryChange);\n\n      if (!isProxied) {\n        // There is no global browser listener for history mutations, so proxy both methods.\n        originalPushState = Reflect.get(globalScope.history, 'pushState') as History['pushState'] | undefined;\n        originalReplaceState = Reflect.get(globalScope.history, 'replaceState') as History['replaceState'] | undefined;\n\n        /* istanbul ignore next */\n        if (!originalPushState || !originalReplaceState) {\n          return;\n        }\n\n        installedPushState = createHistoryStateProxy(originalPushState);\n        globalScope.history.pushState = installedPushState;\n\n        installedReplaceState = createHistoryStateProxy(originalReplaceState);\n        globalScope.history.replaceState = installedReplaceState;\n\n        isProxied = true;\n      }\n    },\n\n    execute: async (event: Event) => {\n      if (EVENT_PROPERTY_EXCLUDED_EVENT_TYPES.has(event.event_type)) {\n        return event;\n      }\n\n      event.event_properties = {\n        ...eventPropertyCampaign,\n        ...event.event_properties,\n      };\n\n      return event;\n    },\n\n    teardown: async () => {\n      if (globalScope) {\n        globalScope.removeEventListener('popstate', onHistoryChange);\n\n        const currentPushState = Reflect.get(globalScope.history, 'pushState') as History['pushState'] | undefined;\n        const currentReplaceState = Reflect.get(globalScope.history, 'replaceState') as\n          | History['replaceState']\n          | undefined;\n\n        if (isProxied && currentPushState === installedPushState && originalPushState) {\n          globalScope.history.pushState = originalPushState;\n        }\n\n        if (isProxied && currentReplaceState === installedReplaceState && originalReplaceState) {\n          globalScope.history.replaceState = originalReplaceState;\n        }\n      }\n\n      isTracking = false;\n      isProxied = false;\n      originalPushState = undefined;\n      originalReplaceState = undefined;\n      installedPushState = undefined;\n      installedReplaceState = undefined;\n      eventPropertyCampaign = {};\n    },\n  };\n};\n"
  },
  {
    "path": "packages/plugin-event-property-attribution-browser/src/index.ts",
    "content": "export { eventPropertyTrackingPlugin } from './event-property-tracking';\n"
  },
  {
    "path": "packages/plugin-event-property-attribution-browser/test/event-property-tracking.test.ts",
    "content": "import {\n  BASE_CAMPAIGN,\n  BrowserConfig,\n  BrowserClient,\n  Campaign,\n  CookieStorage,\n  FetchTransport,\n  LogLevel,\n  Logger,\n  UUID,\n} from '@amplitude/analytics-core';\nimport { eventPropertyTrackingPlugin } from '../src/event-property-tracking';\nimport * as Core from '@amplitude/analytics-core';\n\nconst createMockBrowserClient = (): jest.Mocked<BrowserClient> =>\n  ({\n    init: jest.fn(),\n    add: jest.fn(),\n    remove: jest.fn(),\n    track: jest.fn().mockReturnValue({\n      promise: Promise.resolve({\n        code: 200,\n        message: '',\n        event: {\n          event_type: '[Amplitude] Attribution',\n        },\n      }),\n    }),\n    logEvent: jest.fn(),\n    identify: jest.fn(),\n    groupIdentify: jest.fn(),\n    setGroup: jest.fn(),\n    revenue: jest.fn(),\n    setOptOut: jest.fn(),\n    getOptOut: jest.fn(),\n    getIdentity: jest.fn(),\n    setIdentity: jest.fn(),\n    flush: jest.fn(),\n    getUserId: jest.fn(),\n    setUserId: jest.fn(),\n    getDeviceId: jest.fn(),\n    setDeviceId: jest.fn(),\n    getSessionId: jest.fn(),\n    setSessionId: jest.fn(),\n    extendSession: jest.fn(),\n    reset: jest.fn(),\n    setTransport: jest.fn(),\n    _setDiagnosticsSampleRate: jest.fn(),\n  } as unknown as jest.Mocked<BrowserClient>);\n\nconst createConfigurationMock = (overrides: Partial<BrowserConfig> = {}): BrowserConfig =>\n  ({\n    apiKey: UUID(),\n    flushIntervalMillis: 0,\n    flushMaxRetries: 0,\n    flushQueueSize: 0,\n    logLevel: LogLevel.None,\n    loggerProvider: new Logger(),\n    offline: false,\n    optOut: false,\n    serverUrl: undefined,\n    transportProvider: new FetchTransport(),\n    useBatch: false,\n    cookieOptions: {\n      domain: '.amplitude.com',\n      expiration: 365,\n      sameSite: 'Lax',\n      secure: false,\n      upgrade: true,\n    },\n    cookieStorage: new CookieStorage(),\n    sessionTimeout: 30 * 60 * 1000,\n    trackingOptions: {\n      ipAddress: true,\n      language: true,\n      platform: true,\n    },\n    ...overrides,\n  } as BrowserConfig);\n\nconst createCampaign = (overrides: Partial<Campaign> = {}): Campaign => {\n  const campaign = { ...BASE_CAMPAIGN };\n\n  for (const [index, key] of (Object.keys(BASE_CAMPAIGN) as (keyof Campaign)[]).entries()) {\n    campaign[key] = `${key}-${index}`;\n  }\n\n  return {\n    ...campaign,\n    ...overrides,\n  };\n};\n\ndescribe('eventPropertyTrackingPlugin', () => {\n  const originalPushState = window.history.pushState.bind(window.history);\n  const originalReplaceState = window.history.replaceState.bind(window.history);\n  let plugin = eventPropertyTrackingPlugin();\n\n  beforeEach(() => {\n    plugin = eventPropertyTrackingPlugin();\n  });\n\n  afterEach(async () => {\n    await plugin.teardown?.();\n    window.history.pushState = originalPushState;\n    window.history.replaceState = originalReplaceState;\n    jest.restoreAllMocks();\n  });\n\n  test('should attach the current campaign to events without overwriting customer-supplied values', async () => {\n    const campaign = createCampaign();\n    const parseSpy = jest.spyOn(Core.CampaignParser.prototype, 'parse').mockResolvedValue(campaign);\n    const client = createMockBrowserClient();\n\n    await plugin.setup?.(createConfigurationMock(), client);\n\n    const event = await plugin.execute?.({\n      event_type: 'test-event',\n      event_properties: {\n        existing: 'value',\n        utm_source: 'stale',\n      },\n    });\n\n    expect(event).toEqual({\n      event_type: 'test-event',\n      event_properties: {\n        ...campaign,\n        existing: 'value',\n        utm_source: 'stale',\n      },\n    });\n    expect(parseSpy).toHaveBeenCalledTimes(1);\n  });\n\n  test('should ignore excludeReferrers for event property tracking', async () => {\n    const campaign = createCampaign({\n      referrer: 'https://www.google.com',\n      referring_domain: 'www.google.com',\n      utm_source: 'google',\n    });\n    jest.spyOn(Core.CampaignParser.prototype, 'parse').mockResolvedValue(campaign);\n    plugin = eventPropertyTrackingPlugin({\n      excludeReferrers: ['www.google.com'],\n    });\n\n    await plugin.setup?.(createConfigurationMock(), createMockBrowserClient());\n\n    const event = await plugin.execute?.({\n      event_type: 'test-event',\n      event_properties: {\n        existing: 'value',\n      },\n    });\n\n    expect(event).toEqual({\n      event_type: 'test-event',\n      event_properties: {\n        existing: 'value',\n        ...campaign,\n      },\n    });\n  });\n\n  test('should ignore excludeInternalReferrers for event property tracking', async () => {\n    const campaign = createCampaign({\n      referrer: 'https://analytics.amplitude.com/path',\n      referring_domain: 'analytics.amplitude.com',\n      utm_source: 'google',\n    });\n    jest.spyOn(Core.CampaignParser.prototype, 'parse').mockResolvedValue(campaign);\n    plugin = eventPropertyTrackingPlugin({\n      excludeInternalReferrers: true,\n    });\n\n    await plugin.setup?.(\n      createConfigurationMock({\n        topLevelDomain: '.amplitude.com',\n      }),\n      createMockBrowserClient(),\n    );\n\n    const event = await plugin.execute?.({\n      event_type: 'test-event',\n      event_properties: {\n        existing: 'value',\n      },\n    });\n\n    expect(event).toEqual({\n      event_type: 'test-event',\n      event_properties: {\n        existing: 'value',\n        ...campaign,\n      },\n    });\n  });\n\n  test('should ignore excludeInternalReferrers ifEmptyCampaign for event property tracking', async () => {\n    const campaign = createCampaign({\n      referrer: 'https://analytics.amplitude.com/path',\n      referring_domain: 'analytics.amplitude.com',\n      utm_source: 'google',\n    });\n    jest.spyOn(Core.CampaignParser.prototype, 'parse').mockResolvedValue(campaign);\n    plugin = eventPropertyTrackingPlugin({\n      excludeInternalReferrers: { condition: 'ifEmptyCampaign' },\n    });\n\n    await plugin.setup?.(\n      createConfigurationMock({\n        topLevelDomain: '.amplitude.com',\n      }),\n      createMockBrowserClient(),\n    );\n\n    const event = await plugin.execute?.({\n      event_type: 'test-event',\n      event_properties: {\n        existing: 'value',\n      },\n    });\n\n    expect(event).toEqual({\n      event_type: 'test-event',\n      event_properties: {\n        existing: 'value',\n        ...campaign,\n      },\n    });\n  });\n\n  test('should ignore excludeInternalReferrers ifEmptyCampaign for otherwise empty internal campaigns', async () => {\n    const campaign = {\n      ...BASE_CAMPAIGN,\n      referrer: 'https://analytics.amplitude.com/path',\n      referring_domain: 'analytics.amplitude.com',\n    };\n    jest.spyOn(Core.CampaignParser.prototype, 'parse').mockResolvedValue(campaign);\n    plugin = eventPropertyTrackingPlugin({\n      excludeInternalReferrers: { condition: 'ifEmptyCampaign' },\n    });\n\n    await plugin.setup?.(\n      createConfigurationMock({\n        topLevelDomain: '.amplitude.com',\n      }),\n      createMockBrowserClient(),\n    );\n\n    const event = await plugin.execute?.({\n      event_type: 'test-event',\n      event_properties: {\n        existing: 'value',\n        utm_source: 'stale',\n      },\n    });\n\n    expect(event).toEqual({\n      event_type: 'test-event',\n      event_properties: {\n        existing: 'value',\n        referrer: 'https://analytics.amplitude.com/path',\n        referring_domain: 'analytics.amplitude.com',\n        utm_source: 'stale',\n      },\n    });\n  });\n\n  test('should ignore resetSessionOnNewCampaign for event property tracking', async () => {\n    const campaign = createCampaign({\n      utm_source: 'google',\n    });\n    jest.spyOn(Core.CampaignParser.prototype, 'parse').mockResolvedValue(campaign);\n    plugin = eventPropertyTrackingPlugin({\n      resetSessionOnNewCampaign: true,\n      trackingMethod: 'eventProperty',\n    });\n\n    await plugin.setup?.(createConfigurationMock(), createMockBrowserClient());\n\n    const event = await plugin.execute?.({\n      event_type: 'test-event',\n      event_properties: {\n        existing: 'value',\n      },\n    });\n\n    expect(event).toEqual({\n      event_type: 'test-event',\n      event_properties: {\n        existing: 'value',\n        ...campaign,\n      },\n    });\n  });\n\n  test('should re-parse only on setup and history changes', async () => {\n    const parseSpy = jest\n      .spyOn(Core.CampaignParser.prototype, 'parse')\n      .mockResolvedValueOnce(\n        createCampaign({\n          utm_source: 'google',\n        }),\n      )\n      .mockResolvedValueOnce({\n        ...BASE_CAMPAIGN,\n      });\n\n    await plugin.setup?.(createConfigurationMock(), createMockBrowserClient());\n    await plugin.execute?.({\n      event_type: 'test-event',\n    });\n\n    expect(parseSpy).toHaveBeenCalledTimes(1);\n\n    window.history.pushState(undefined, '', '/next');\n    await new Promise((resolve) => setTimeout(resolve, 0));\n\n    expect(parseSpy).toHaveBeenCalledTimes(2);\n\n    window.history.replaceState(undefined, '', '/next-2');\n    await new Promise((resolve) => setTimeout(resolve, 0));\n\n    expect(parseSpy).toHaveBeenCalledTimes(3);\n\n    const event = await plugin.execute?.({\n      event_type: 'test-event',\n      event_properties: {\n        existing: 'value',\n        utm_source: 'google',\n      },\n    });\n\n    expect(parseSpy).toHaveBeenCalledTimes(3);\n    expect(event).toEqual({\n      event_type: 'test-event',\n      event_properties: {\n        existing: 'value',\n        utm_source: 'google',\n      },\n    });\n  });\n\n  test('should restore original history methods on teardown', async () => {\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    const pushState = window.history.pushState;\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    const replaceState = window.history.replaceState;\n\n    await plugin.setup?.(createConfigurationMock(), createMockBrowserClient());\n\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    expect(window.history.pushState).not.toBe(pushState);\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    expect(window.history.replaceState).not.toBe(replaceState);\n\n    await plugin.teardown?.();\n\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    expect(window.history.pushState).toBe(pushState);\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    expect(window.history.replaceState).toBe(replaceState);\n  });\n\n  test('should not overwrite history wrappers installed after setup during teardown', async () => {\n    const pushStateWrapper: History['pushState'] = () => undefined;\n    const replaceStateWrapper: History['replaceState'] = () => undefined;\n\n    await plugin.setup?.(createConfigurationMock(), createMockBrowserClient());\n\n    window.history.pushState = pushStateWrapper;\n    window.history.replaceState = replaceStateWrapper;\n\n    await plugin.teardown?.();\n\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    expect(window.history.pushState).toBe(pushStateWrapper);\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    expect(window.history.replaceState).toBe(replaceStateWrapper);\n  });\n\n  test('should not enrich identify events', async () => {\n    const campaign = createCampaign();\n    jest.spyOn(Core.CampaignParser.prototype, 'parse').mockResolvedValue(campaign);\n\n    await plugin.setup?.(createConfigurationMock(), createMockBrowserClient());\n\n    const event = await plugin.execute?.({\n      event_type: '$identify',\n      event_properties: {\n        existing: 'value',\n      },\n    });\n\n    expect(event).toEqual({\n      event_type: '$identify',\n      event_properties: {\n        existing: 'value',\n      },\n    });\n  });\n\n  test('should skip browser listeners when global scope is unavailable', async () => {\n    const campaign = createCampaign({\n      utm_source: 'google',\n    });\n    jest.spyOn(Core, 'getGlobalScope').mockReturnValue(undefined);\n    jest.spyOn(Core.CampaignParser.prototype, 'parse').mockResolvedValue(campaign);\n    plugin = eventPropertyTrackingPlugin({\n      trackingMethod: 'eventProperty',\n    });\n\n    await plugin.setup?.(createConfigurationMock(), createMockBrowserClient());\n\n    const event = await plugin.execute?.({\n      event_type: 'test-event',\n      event_properties: {\n        existing: 'value',\n      },\n    });\n\n    expect(event).toEqual({\n      event_type: 'test-event',\n      event_properties: {\n        existing: 'value',\n        ...campaign,\n      },\n    });\n  });\n\n  test('should fire fallback attribution events whenever campaign state is updated', async () => {\n    const parseSpy = jest\n      .spyOn(Core.CampaignParser.prototype, 'parse')\n      .mockResolvedValueOnce(\n        createCampaign({\n          utm_source: 'google',\n        }),\n      )\n      .mockResolvedValueOnce({\n        ...BASE_CAMPAIGN,\n      })\n      .mockResolvedValueOnce(\n        createCampaign({\n          utm_source: 'bing',\n        }),\n      );\n    plugin = eventPropertyTrackingPlugin({\n      fallbackAttributionEvent: true,\n    });\n    const client = createMockBrowserClient();\n    const trackCalls = client.track.mock.calls;\n\n    await plugin.setup?.(createConfigurationMock(), client);\n\n    expect(trackCalls).toHaveLength(1);\n    expect(trackCalls[0]).toEqual([\n      '[Amplitude] Attribution',\n      expect.objectContaining({\n        utm_source: 'google',\n      }),\n    ]);\n\n    window.history.pushState(undefined, '', '/direct');\n    await new Promise((resolve) => setTimeout(resolve, 0));\n\n    expect(trackCalls).toHaveLength(2);\n    expect(trackCalls[1]).toEqual(['[Amplitude] Attribution', {}]);\n    expect(parseSpy).toHaveBeenCalledTimes(2);\n\n    window.history.pushState(undefined, '', '/campaign');\n    await new Promise((resolve) => setTimeout(resolve, 0));\n\n    expect(trackCalls).toHaveLength(3);\n    expect(trackCalls[2]).toEqual([\n      '[Amplitude] Attribution',\n      expect.objectContaining({\n        utm_source: 'bing',\n      }),\n    ]);\n  });\n});\n"
  },
  {
    "path": "packages/plugin-event-property-attribution-browser/tsconfig.es5.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/cjs\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-event-property-attribution-browser/tsconfig.esm.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"es6\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/esm\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-event-property-attribution-browser/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src/**/*\", \"test/**/*\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"esModuleInterop\": true,\n    \"lib\": [\"dom\"],\n    \"noEmit\": true,\n    \"rootDir\": \".\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-experiment-browser/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.0.0-beta.27](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-experiment-browser@1.0.0-beta.26...@amplitude/plugin-experiment-browser@1.0.0-beta.27) (2026-04-28)\n\n**Note:** Version bump only for package @amplitude/plugin-experiment-browser\n\n\n\n\n\n# [1.0.0-beta.26](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-experiment-browser@1.0.0-beta.25...@amplitude/plugin-experiment-browser@1.0.0-beta.26) (2026-04-22)\n\n**Note:** Version bump only for package @amplitude/plugin-experiment-browser\n\n\n\n\n\n# [1.0.0-beta.25](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-experiment-browser@1.0.0-beta.24...@amplitude/plugin-experiment-browser@1.0.0-beta.25) (2026-04-21)\n\n**Note:** Version bump only for package @amplitude/plugin-experiment-browser\n\n\n\n\n\n# [1.0.0-beta.24](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-experiment-browser@1.0.0-beta.23...@amplitude/plugin-experiment-browser@1.0.0-beta.24) (2026-04-14)\n\n**Note:** Version bump only for package @amplitude/plugin-experiment-browser\n\n\n\n\n\n# [1.0.0-beta.23](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-experiment-browser@1.0.0-beta.22...@amplitude/plugin-experiment-browser@1.0.0-beta.23) (2026-04-09)\n\n**Note:** Version bump only for package @amplitude/plugin-experiment-browser\n\n\n\n\n\n# [1.0.0-beta.22](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-experiment-browser@1.0.0-beta.21...@amplitude/plugin-experiment-browser@1.0.0-beta.22) (2026-04-01)\n\n**Note:** Version bump only for package @amplitude/plugin-experiment-browser\n\n\n\n\n\n# [1.0.0-beta.21](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-experiment-browser@1.0.0-beta.20...@amplitude/plugin-experiment-browser@1.0.0-beta.21) (2026-03-26)\n\n**Note:** Version bump only for package @amplitude/plugin-experiment-browser\n\n\n\n\n\n# [1.0.0-beta.20](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-experiment-browser@1.0.0-beta.19...@amplitude/plugin-experiment-browser@1.0.0-beta.20) (2026-03-23)\n\n**Note:** Version bump only for package @amplitude/plugin-experiment-browser\n\n\n\n\n\n# [1.0.0-beta.19](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-experiment-browser@1.0.0-beta.18...@amplitude/plugin-experiment-browser@1.0.0-beta.19) (2026-03-20)\n\n**Note:** Version bump only for package @amplitude/plugin-experiment-browser\n\n\n\n\n\n# [1.0.0-beta.18](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-experiment-browser@1.0.0-beta.17...@amplitude/plugin-experiment-browser@1.0.0-beta.18) (2026-03-19)\n\n**Note:** Version bump only for package @amplitude/plugin-experiment-browser\n\n\n\n\n\n# [1.0.0-beta.17](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-experiment-browser@1.0.0-beta.16...@amplitude/plugin-experiment-browser@1.0.0-beta.17) (2026-03-17)\n\n**Note:** Version bump only for package @amplitude/plugin-experiment-browser\n\n\n\n\n\n# [1.0.0-beta.16](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-experiment-browser@1.0.0-beta.15...@amplitude/plugin-experiment-browser@1.0.0-beta.16) (2026-03-16)\n\n**Note:** Version bump only for package @amplitude/plugin-experiment-browser\n\n\n\n\n\n# [1.0.0-beta.15](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-experiment-browser@1.0.0-beta.14...@amplitude/plugin-experiment-browser@1.0.0-beta.15) (2026-03-13)\n\n**Note:** Version bump only for package @amplitude/plugin-experiment-browser\n\n\n\n\n\n# [1.0.0-beta.14](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-experiment-browser@1.0.0-beta.13...@amplitude/plugin-experiment-browser@1.0.0-beta.14) (2026-03-12)\n\n**Note:** Version bump only for package @amplitude/plugin-experiment-browser\n\n\n\n\n\n# [1.0.0-beta.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-experiment-browser@1.0.0-beta.12...@amplitude/plugin-experiment-browser@1.0.0-beta.13) (2026-03-09)\n\n**Note:** Version bump only for package @amplitude/plugin-experiment-browser\n\n\n\n\n\n# [1.0.0-beta.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-experiment-browser@1.0.0-beta.11...@amplitude/plugin-experiment-browser@1.0.0-beta.12) (2026-03-05)\n\n**Note:** Version bump only for package @amplitude/plugin-experiment-browser\n\n\n\n\n\n# [1.0.0-beta.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-experiment-browser@1.0.0-beta.10...@amplitude/plugin-experiment-browser@1.0.0-beta.11) (2026-03-03)\n\n**Note:** Version bump only for package @amplitude/plugin-experiment-browser\n\n\n\n\n\n# [1.0.0-beta.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-experiment-browser@1.0.0-beta.9...@amplitude/plugin-experiment-browser@1.0.0-beta.10) (2026-03-03)\n\n**Note:** Version bump only for package @amplitude/plugin-experiment-browser\n\n\n\n\n\n# [1.0.0-beta.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-experiment-browser@1.0.0-beta.8...@amplitude/plugin-experiment-browser@1.0.0-beta.9) (2026-02-26)\n\n**Note:** Version bump only for package @amplitude/plugin-experiment-browser\n\n\n\n\n\n# [1.0.0-beta.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-experiment-browser@1.0.0-beta.7...@amplitude/plugin-experiment-browser@1.0.0-beta.8) (2026-02-24)\n\n**Note:** Version bump only for package @amplitude/plugin-experiment-browser\n\n\n\n\n\n# [1.0.0-beta.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-experiment-browser@1.0.0-beta.6...@amplitude/plugin-experiment-browser@1.0.0-beta.7) (2026-02-19)\n\n**Note:** Version bump only for package @amplitude/plugin-experiment-browser\n\n\n\n\n\n# [1.0.0-beta.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-experiment-browser@1.0.0-beta.5...@amplitude/plugin-experiment-browser@1.0.0-beta.6) (2026-02-17)\n\n**Note:** Version bump only for package @amplitude/plugin-experiment-browser\n\n\n\n\n\n# [1.0.0-beta.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-experiment-browser@1.0.0-beta.4...@amplitude/plugin-experiment-browser@1.0.0-beta.5) (2026-02-10)\n\n**Note:** Version bump only for package @amplitude/plugin-experiment-browser\n\n\n\n\n\n# [1.0.0-beta.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-experiment-browser@1.0.0-beta.3...@amplitude/plugin-experiment-browser@1.0.0-beta.4) (2026-01-26)\n\n\n### Features\n\n* **analytics-browser:** add shouldTrackSubmit for custom form validation ([#1500](https://github.com/amplitude/Amplitude-TypeScript/issues/1500)) ([1d76745](https://github.com/amplitude/Amplitude-TypeScript/commit/1d76745dc202e27d188bfe47ae76d69806bbb566))\n\n\n\n\n\n# [1.0.0-beta.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-experiment-browser@1.0.0-beta.2...@amplitude/plugin-experiment-browser@1.0.0-beta.3) (2026-01-21)\n\n**Note:** Version bump only for package @amplitude/plugin-experiment-browser\n\n\n\n\n\n# 1.0.0-beta.2 (2026-01-15)\n\n\n### Bug Fixes\n\n* **plugin-experiment-browser:** deployment key over api key ([#1041](https://github.com/amplitude/Amplitude-TypeScript/issues/1041)) ([b2a6f2f](https://github.com/amplitude/Amplitude-TypeScript/commit/b2a6f2f7d54c5df29614552a31ef3aa37d3b4424))\n* **plugin-experiment-browser:** private false ([#1495](https://github.com/amplitude/Amplitude-TypeScript/issues/1495)) ([1ee2497](https://github.com/amplitude/Amplitude-TypeScript/commit/1ee249772d62e05bf529e3b82e24e2090a1d0d91))\n"
  },
  {
    "path": "packages/plugin-experiment-browser/README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://amplitude.com\" target=\"_blank\" align=\"center\">\n    <img src=\"https://static.amplitude.com/lightning/46c85bfd91905de8047f1ee65c7c93d6fa9ee6ea/static/media/amplitude-logo-with-text.4fb9e463.svg\" width=\"280\">\n  </a>\n  <br />\n</p>\n\n# @amplitude/plugin-experiment-browser\n\nOfficial Browser SDK plugin for Amplitude Experiment integration\n\n## Installation\n\nThis package is published on NPM registry and is available to be installed using npm and yarn.\n\n```sh\n# npm\nnpm install @amplitude/plugin-experiment-browser\n\n# yarn\nyarn add @amplitude/plugin-experiment-browser\n```\n\n## Usage\n\nThis plugin works on top of Amplitude Browser SDK and adds Amplitude Experiment integration features. To use this plugin, you need to install `@amplitude/analytics-browser` version `v2.17.5` or later.\n\n### 1. Import Amplitude packages\n\n* `@amplitude/plugin-experiment-browser`\n\n```typescript\nimport { experimentPlugin } from '@amplitude/plugin-experiment-browser';\n```\n\n### 2. Instantiate experiment plugin\n\nThe plugin accepts an optional parameter of type `ExperimentPluginConfig` to configure the plugin based on your use case.\n\n```typescript\nconst experiment = experimentPlugin({\n  deploymentKey: 'DEPLOYMENT_KEY', // Optional if using the same key as analytics\n  // Other experiment configuration options\n});\n```\n\n#### Options\n\n|Name|Type|Default|Description|\n|-|-|-|-|\n|`deploymentKey`|`string`|`undefined`|The deployment key for Amplitude Experiment. If not provided, the plugin will use the Amplitude API key.|\n|`...`|`ExperimentConfig`|`{}`|All other configuration options from `@amplitude/experiment-js-client`.|\n\n### 3. Install plugin to Amplitude SDK\n\n```typescript\namplitude.add(experiment);\n```\n\n### 4. Initialize Amplitude SDK\n\n```typescript\namplitude.init('API_KEY');\n```\n\n## Experiment Integration\n\nThis plugin integrates Amplitude Experiment with Amplitude Analytics. The plugin:\n\n1. Automatically initializes the Experiment client using the Amplitude Analytics configuration\n2. Sets up the connection between Experiment and Analytics for consistent user identity\n3. Allows you to use all features of the Experiment client while maintaining the connection with Analytics\n\n### Accessing the Experiment client\n\nThe Experiment client is accessible through the plugin instance:\n\n```typescript\nconst plugin = experimentPlugin(config);\namplitude.add(plugin);\namplitude.init('API_KEY');\n\n// Now you can access the Experiment client\nconst variant = await plugin.experiment.fetch();\n```\n\n## Learn More\n\nFor more information about Amplitude Experiment, visit the [official documentation](https://www.docs.developers.amplitude.com/experiment/).\n"
  },
  {
    "path": "packages/plugin-experiment-browser/jest.config.js",
    "content": "const baseConfig = require('../../jest.config.js');\nconst package = require('./package');\n\nmodule.exports = {\n  ...baseConfig,\n  displayName: package.name,\n  rootDir: '.',\n  testEnvironment: 'jsdom',\n  coveragePathIgnorePatterns: ['index.ts'],\n};\n"
  },
  {
    "path": "packages/plugin-experiment-browser/package.json",
    "content": "{\n  \"name\": \"@amplitude/plugin-experiment-browser\",\n  \"version\": \"1.0.0-beta.27\",\n  \"description\": \"\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/amplitude/Amplitude-TypeScript.git\"\n  },\n  \"author\": \"Amplitude Inc\",\n  \"license\": \"MIT\",\n  \"main\": \"lib/cjs/index.js\",\n  \"module\": \"lib/esm/index.js\",\n  \"types\": \"lib/esm/index.d.ts\",\n  \"sideEffects\": false,\n  \"bugs\": {\n    \"url\": \"https://github.com/amplitude/Amplitude-TypeScript/issues\"\n  },\n  \"publishConfig\": {\n    \"tag\": \"beta\"\n  },\n  \"files\": [\n    \"lib\"\n  ],\n  \"scripts\": {\n    \"build\": \"pnpm bundle && pnpm build:es5 && pnpm build:esm\",\n    \"bundle\": \"rollup --config rollup.config.js\",\n    \"build:es5\": \"tsc -p ./tsconfig.es5.json\",\n    \"build:esm\": \"tsc -p ./tsconfig.esm.json\",\n    \"watch\": \"tsc -p ./tsconfig.esm.json --watch\",\n    \"clean\": \"rimraf node_modules lib coverage\",\n    \"fix\": \"pnpm fix:eslint & pnpm fix:prettier\",\n    \"fix:eslint\": \"eslint '{src,test}/**/*.ts' --fix\",\n    \"fix:prettier\": \"prettier --write \\\"{src,test}/**/*.ts\\\"\",\n    \"lint\": \"pnpm lint:eslint & pnpm lint:prettier\",\n    \"lint:eslint\": \"eslint '{src,test}/**/*.ts'\",\n    \"lint:prettier\": \"prettier --check \\\"{src,test}/**/*.ts\\\"\",\n    \"test\": \"jest\",\n    \"typecheck\": \"tsc -p ./tsconfig.json\",\n    \"version\": \"pnpm version-file && pnpm build\",\n    \"version-file\": \"echo '// Autogenerated by `npm run version-file`. DO NOT EDIT' > src/version.ts && node -p \\\"'export const VERSION = \\\\'' + require('./package.json').version + '\\\\';'\\\" >> src/version.ts\"\n  },\n  \"dependencies\": {\n    \"@amplitude/analytics-core\": \"workspace:*\",\n    \"@amplitude/experiment-js-client\": \"^1.15.5\"\n  },\n  \"devDependencies\": {\n    \"rollup\": \"^2.79.1\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-experiment-browser/rollup.config.js",
    "content": "import { umd } from '../../scripts/build/rollup.config';\n\nexport default [umd];\n"
  },
  {
    "path": "packages/plugin-experiment-browser/src/experiment.ts",
    "content": "import { EnrichmentPlugin, BrowserClient, BrowserConfig } from '@amplitude/analytics-core';\n\nimport {\n  ExperimentConfig,\n  Client as IExperimentClient,\n  initializeWithAmplitudeAnalytics,\n} from '@amplitude/experiment-js-client';\n\n/**\n * Fallback to project API key if no experiment deployment key.\n */\nexport type ExperimentPluginConfig = ExperimentConfig & { deploymentKey?: string };\n\nexport class ExperimentPlugin implements EnrichmentPlugin<BrowserClient, BrowserConfig> {\n  static pluginName = '@amplitude/experiment-analytics-plugin';\n  name = ExperimentPlugin.pluginName;\n  // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n  // @ts-ignore\n  experiment: IExperimentClient;\n  config?: ExperimentPluginConfig;\n\n  constructor(config?: ExperimentPluginConfig) {\n    this.config = config;\n  }\n\n  async setup(config: BrowserConfig, _client: BrowserClient) {\n    this.experiment = initializeWithAmplitudeAnalytics(this.config?.deploymentKey || config.apiKey, this.config);\n  }\n}\n\nexport const experimentPlugin: (config?: ExperimentPluginConfig) => EnrichmentPlugin<BrowserClient, BrowserConfig> = (\n  config?: ExperimentPluginConfig,\n) => {\n  return new ExperimentPlugin(config);\n};\n"
  },
  {
    "path": "packages/plugin-experiment-browser/src/index.ts",
    "content": "export { ExperimentPlugin, experimentPlugin, ExperimentPluginConfig } from './experiment';\nexport { Client as IExperimentClient } from '@amplitude/experiment-js-client';\n"
  },
  {
    "path": "packages/plugin-experiment-browser/src/version.ts",
    "content": "// Autogenerated by `npm run version-file`. DO NOT EDIT\nexport const VERSION = '1.0.0-beta.27';\n"
  },
  {
    "path": "packages/plugin-experiment-browser/test/experiment.test.ts",
    "content": "import { ExperimentPlugin, experimentPlugin, ExperimentPluginConfig } from '../src/experiment';\nimport { ExperimentClient, ExperimentConfig, initializeWithAmplitudeAnalytics } from '@amplitude/experiment-js-client';\nimport { BrowserClient, BrowserConfig, ILogger, LogLevel } from '@amplitude/analytics-core';\nimport { VERSION } from '../src/version';\n\ntype MockedLogger = jest.Mocked<ILogger>;\ntype MockedBrowserClient = jest.Mocked<BrowserClient>;\ntype MockedExperimentClient = jest.Mock<ExperimentClient>;\n\n// eslint-disable-next-line @typescript-eslint/no-unsafe-return\njest.mock('@amplitude/experiment-js-client', () => ({\n  ...jest.requireActual('@amplitude/experiment-js-client'),\n  initializeWithAmplitudeAnalytics: jest.fn(),\n}));\n\ndescribe('ExperimentPlugin', () => {\n  const mockLoggerProviderDebug = jest.fn();\n  const mockLoggerProvider: MockedLogger = {\n    error: jest.fn(),\n    log: jest.fn(),\n    disable: jest.fn(),\n    enable: jest.fn(),\n    warn: jest.fn(),\n    debug: mockLoggerProviderDebug,\n  };\n  const mockConfig: BrowserConfig = {\n    apiKey: 'static_key',\n    flushIntervalMillis: 0,\n    flushMaxRetries: 1,\n    flushQueueSize: 0,\n    logLevel: LogLevel.None,\n    loggerProvider: mockLoggerProvider,\n    optOut: false,\n    deviceId: '1a2b3c',\n    serverUrl: 'url',\n    serverZone: 'US',\n    useBatch: false,\n    sessionId: 123,\n    cookieExpiration: 365,\n    cookieSameSite: 'Lax',\n    cookieSecure: false,\n    cookieUpgrade: true,\n    disableCookies: false,\n    domain: '.amplitude.com',\n    sessionTimeout: 30 * 60 * 1000,\n    trackingOptions: {\n      ipAddress: true,\n      language: true,\n      platform: true,\n    },\n  } as unknown as BrowserConfig;\n  const mockAmplitude: MockedBrowserClient = {\n    add: jest.fn(),\n    remove: jest.fn(),\n  } as unknown as MockedBrowserClient;\n\n  beforeEach(() => {\n    (initializeWithAmplitudeAnalytics as jest.Mock).mockReturnValue({} as unknown as MockedExperimentClient);\n  });\n\n  afterEach(() => {\n    jest.clearAllMocks();\n  });\n\n  describe('constructor', () => {\n    test('should set config', () => {\n      const experimentConfig: ExperimentPluginConfig = {\n        debug: true,\n      };\n      const plugin = new ExperimentPlugin(experimentConfig);\n      expect(plugin.name).toEqual('@amplitude/experiment-analytics-plugin');\n      expect(plugin.experiment).toBeUndefined();\n      expect(plugin.config).toBe(experimentConfig);\n    });\n  });\n\n  describe('setup', () => {\n    test.each([\n      {\n        debug: true,\n      },\n      undefined,\n    ])('should initialize experiment client with API key and set it on plugin', async (config) => {\n      const experimentConfig: ExperimentPluginConfig | undefined = config;\n      const mockExperimentClient = {} as unknown as ExperimentClient;\n      (initializeWithAmplitudeAnalytics as jest.Mock).mockReturnValue(mockExperimentClient);\n      const plugin = new ExperimentPlugin(experimentConfig);\n      await plugin.setup(mockConfig, mockAmplitude);\n      expect(initializeWithAmplitudeAnalytics).toHaveBeenCalledWith(mockConfig.apiKey, experimentConfig);\n      expect(plugin.experiment).toBe(mockExperimentClient);\n    });\n\n    test('should initialize experiment client with deployment key and set it on plugin', async () => {\n      const experimentConfig: ExperimentPluginConfig = {\n        debug: true,\n        deploymentKey: 'test-deployment-key',\n      };\n      const mockExperimentClient = {} as unknown as ExperimentClient;\n      (initializeWithAmplitudeAnalytics as jest.Mock).mockReturnValue(mockExperimentClient);\n      const plugin = new ExperimentPlugin(experimentConfig);\n      await plugin.setup(mockConfig, mockAmplitude);\n      expect(initializeWithAmplitudeAnalytics).toHaveBeenCalledWith(experimentConfig.deploymentKey, experimentConfig);\n      expect(plugin.experiment).toBe(mockExperimentClient);\n    });\n  });\n\n  describe('experimentPlugin', () => {\n    test('should return an instance of ExperimentPlugin with config', () => {\n      const experimentConfig: ExperimentConfig = {\n        debug: true,\n      };\n      const plugin = experimentPlugin(experimentConfig);\n      expect(plugin).toBeInstanceOf(ExperimentPlugin);\n      expect((plugin as ExperimentPlugin).config).toEqual(experimentConfig);\n    });\n\n    test('should return an instance of ExperimentPlugin without config', () => {\n      const plugin = experimentPlugin();\n      expect(plugin).toBeInstanceOf(ExperimentPlugin);\n      expect((plugin as ExperimentPlugin).config).toBeUndefined();\n    });\n  });\n});\n\ndescribe('version', () => {\n  test('should return the plugin version', () => {\n    expect(VERSION != null).toBe(true);\n  });\n});\n"
  },
  {
    "path": "packages/plugin-experiment-browser/test/version.test.ts",
    "content": "import { VERSION } from '../src/version';\n\ndescribe('version', () => {\n  test('should be defined', () => {\n    expect(VERSION).toBeDefined();\n  });\n\n  test('should be a valid semver string', () => {\n    // Matches versions like 1.0.0, 1.0.0-beta.2, etc.\n    expect(VERSION).toMatch(/^\\d+\\.\\d+\\.\\d+(-[\\w.]+)?$/);\n  });\n});\n"
  },
  {
    "path": "packages/plugin-experiment-browser/tsconfig.es5.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/cjs\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-experiment-browser/tsconfig.esm.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"es6\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/esm\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-experiment-browser/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src/**/*\", \"test/**/*\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"esModuleInterop\": true,\n    \"lib\": [\"dom\"],\n    \"noEmit\": true,\n    \"rootDir\": \".\",\n  }\n}\n"
  },
  {
    "path": "packages/plugin-global-user-properties/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.136](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.135...@amplitude/plugin-global-user-properties@1.2.136) (2026-04-09)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.135](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.134...@amplitude/plugin-global-user-properties@1.2.135) (2026-04-01)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.134](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.133...@amplitude/plugin-global-user-properties@1.2.134) (2026-03-26)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.133](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.132...@amplitude/plugin-global-user-properties@1.2.133) (2026-03-24)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.132](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.131...@amplitude/plugin-global-user-properties@1.2.132) (2026-03-23)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.131](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.130...@amplitude/plugin-global-user-properties@1.2.131) (2026-03-20)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.130](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.129...@amplitude/plugin-global-user-properties@1.2.130) (2026-03-19)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.129](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.128...@amplitude/plugin-global-user-properties@1.2.129) (2026-03-17)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.128](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.127...@amplitude/plugin-global-user-properties@1.2.128) (2026-03-16)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.127](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.126...@amplitude/plugin-global-user-properties@1.2.127) (2026-03-13)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.126](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.125...@amplitude/plugin-global-user-properties@1.2.126) (2026-03-12)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.125](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.124...@amplitude/plugin-global-user-properties@1.2.125) (2026-03-09)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.124](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.123...@amplitude/plugin-global-user-properties@1.2.124) (2026-03-05)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.123](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.122...@amplitude/plugin-global-user-properties@1.2.123) (2026-03-03)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.122](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.121...@amplitude/plugin-global-user-properties@1.2.122) (2026-03-03)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.121](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.120...@amplitude/plugin-global-user-properties@1.2.121) (2026-02-26)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.120](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.119...@amplitude/plugin-global-user-properties@1.2.120) (2026-02-24)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.119](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.118...@amplitude/plugin-global-user-properties@1.2.119) (2026-02-20)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.118](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.117...@amplitude/plugin-global-user-properties@1.2.118) (2026-02-19)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.117](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.116...@amplitude/plugin-global-user-properties@1.2.117) (2026-02-17)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.116](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.115...@amplitude/plugin-global-user-properties@1.2.116) (2026-02-10)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.115](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.114...@amplitude/plugin-global-user-properties@1.2.115) (2026-01-26)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.114](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.113...@amplitude/plugin-global-user-properties@1.2.114) (2026-01-21)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.113](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.112...@amplitude/plugin-global-user-properties@1.2.113) (2026-01-15)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.112](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.111...@amplitude/plugin-global-user-properties@1.2.112) (2026-01-14)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.111](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.110...@amplitude/plugin-global-user-properties@1.2.111) (2026-01-14)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.110](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.109...@amplitude/plugin-global-user-properties@1.2.110) (2025-12-30)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.109](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.108...@amplitude/plugin-global-user-properties@1.2.109) (2025-12-24)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.108](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.107...@amplitude/plugin-global-user-properties@1.2.108) (2025-12-16)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.107](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.106...@amplitude/plugin-global-user-properties@1.2.107) (2025-12-12)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.106](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.105...@amplitude/plugin-global-user-properties@1.2.106) (2025-12-09)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.105](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.104...@amplitude/plugin-global-user-properties@1.2.105) (2025-12-08)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.104](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.103...@amplitude/plugin-global-user-properties@1.2.104) (2025-11-21)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.103](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.102...@amplitude/plugin-global-user-properties@1.2.103) (2025-11-20)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.102](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.101...@amplitude/plugin-global-user-properties@1.2.102) (2025-11-17)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.101](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.100...@amplitude/plugin-global-user-properties@1.2.101) (2025-11-17)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.100](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.99...@amplitude/plugin-global-user-properties@1.2.100) (2025-11-05)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.99](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.98...@amplitude/plugin-global-user-properties@1.2.99) (2025-10-29)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.98](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.97...@amplitude/plugin-global-user-properties@1.2.98) (2025-10-23)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.97](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.96...@amplitude/plugin-global-user-properties@1.2.97) (2025-10-23)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.96](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.95...@amplitude/plugin-global-user-properties@1.2.96) (2025-10-21)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.95](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.94...@amplitude/plugin-global-user-properties@1.2.95) (2025-10-17)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.94](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.93...@amplitude/plugin-global-user-properties@1.2.94) (2025-10-15)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.93](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.92...@amplitude/plugin-global-user-properties@1.2.93) (2025-10-14)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.92](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.91...@amplitude/plugin-global-user-properties@1.2.92) (2025-10-14)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.91](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.90...@amplitude/plugin-global-user-properties@1.2.91) (2025-10-07)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.90](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.89...@amplitude/plugin-global-user-properties@1.2.90) (2025-10-06)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.89](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.88...@amplitude/plugin-global-user-properties@1.2.89) (2025-10-03)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.88](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.87...@amplitude/plugin-global-user-properties@1.2.88) (2025-10-01)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.87](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.86...@amplitude/plugin-global-user-properties@1.2.87) (2025-09-25)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.86](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.85...@amplitude/plugin-global-user-properties@1.2.86) (2025-09-23)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.85](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.84...@amplitude/plugin-global-user-properties@1.2.85) (2025-09-18)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.84](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.83...@amplitude/plugin-global-user-properties@1.2.84) (2025-09-12)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.83](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.82...@amplitude/plugin-global-user-properties@1.2.83) (2025-09-09)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.82](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.81...@amplitude/plugin-global-user-properties@1.2.82) (2025-09-05)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.81](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.80...@amplitude/plugin-global-user-properties@1.2.81) (2025-08-28)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.80](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.79...@amplitude/plugin-global-user-properties@1.2.80) (2025-08-26)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.79](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.78...@amplitude/plugin-global-user-properties@1.2.79) (2025-08-25)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.78](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.77...@amplitude/plugin-global-user-properties@1.2.78) (2025-08-25)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.77](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.76...@amplitude/plugin-global-user-properties@1.2.77) (2025-08-22)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.76](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.75...@amplitude/plugin-global-user-properties@1.2.76) (2025-08-21)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.75](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.74...@amplitude/plugin-global-user-properties@1.2.75) (2025-08-13)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.74](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.73...@amplitude/plugin-global-user-properties@1.2.74) (2025-08-08)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.73](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.72...@amplitude/plugin-global-user-properties@1.2.73) (2025-08-05)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.72](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.71...@amplitude/plugin-global-user-properties@1.2.72) (2025-07-30)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.71](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.70...@amplitude/plugin-global-user-properties@1.2.71) (2025-07-29)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.70](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.69...@amplitude/plugin-global-user-properties@1.2.70) (2025-07-18)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.69](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.68...@amplitude/plugin-global-user-properties@1.2.69) (2025-07-17)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.68](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.67...@amplitude/plugin-global-user-properties@1.2.68) (2025-07-15)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.67](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.66...@amplitude/plugin-global-user-properties@1.2.67) (2025-07-11)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.66](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.65...@amplitude/plugin-global-user-properties@1.2.66) (2025-07-08)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.65](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.64...@amplitude/plugin-global-user-properties@1.2.65) (2025-06-30)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.64](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.63...@amplitude/plugin-global-user-properties@1.2.64) (2025-06-26)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.63](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.62...@amplitude/plugin-global-user-properties@1.2.63) (2025-06-25)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.62](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.61...@amplitude/plugin-global-user-properties@1.2.62) (2025-06-16)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.61](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.60...@amplitude/plugin-global-user-properties@1.2.61) (2025-06-11)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.60](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.59...@amplitude/plugin-global-user-properties@1.2.60) (2025-06-03)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.59](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.59-main.0...@amplitude/plugin-global-user-properties@1.2.59) (2025-05-27)\n\n\n### Reverts\n\n* \"chore(release): publish\" ([#1094](https://github.com/amplitude/Amplitude-TypeScript/issues/1094)) ([f6db1ee](https://github.com/amplitude/Amplitude-TypeScript/commit/f6db1eed32ed77c7ce626624dc55972971f3b27d))\n\n\n\n\n\n## [1.2.58](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.57...@amplitude/plugin-global-user-properties@1.2.58) (2025-05-14)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.57](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.56...@amplitude/plugin-global-user-properties@1.2.57) (2025-05-13)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.56](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.55...@amplitude/plugin-global-user-properties@1.2.56) (2025-05-07)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.55](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.54...@amplitude/plugin-global-user-properties@1.2.55) (2025-05-05)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.54](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.53...@amplitude/plugin-global-user-properties@1.2.54) (2025-05-02)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.53](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.52...@amplitude/plugin-global-user-properties@1.2.53) (2025-05-02)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.52](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.51...@amplitude/plugin-global-user-properties@1.2.52) (2025-05-02)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.51](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.50...@amplitude/plugin-global-user-properties@1.2.51) (2025-04-30)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.50](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.49...@amplitude/plugin-global-user-properties@1.2.50) (2025-04-22)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.49](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.48...@amplitude/plugin-global-user-properties@1.2.49) (2025-04-17)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.48](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.47...@amplitude/plugin-global-user-properties@1.2.48) (2025-04-15)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.47](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.46...@amplitude/plugin-global-user-properties@1.2.47) (2025-04-10)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.46](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.45...@amplitude/plugin-global-user-properties@1.2.46) (2025-04-07)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.45](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.44...@amplitude/plugin-global-user-properties@1.2.45) (2025-04-07)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.44](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.43...@amplitude/plugin-global-user-properties@1.2.44) (2025-04-02)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.43](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.42...@amplitude/plugin-global-user-properties@1.2.43) (2025-03-24)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.42](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.41...@amplitude/plugin-global-user-properties@1.2.42) (2025-03-21)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.41](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.40...@amplitude/plugin-global-user-properties@1.2.41) (2025-03-14)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.40](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.39...@amplitude/plugin-global-user-properties@1.2.40) (2025-02-28)\n\n\n### Reverts\n\n* Revert \"chore(release): publish\" ([d392f62](https://github.com/amplitude/Amplitude-TypeScript/commit/d392f6290b8bb4dd955d6e6f20b00191679489c4))\n\n\n\n\n\n## [1.2.39](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.38...@amplitude/plugin-global-user-properties@1.2.39) (2025-02-14)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.38](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.37...@amplitude/plugin-global-user-properties@1.2.38) (2024-12-31)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.37](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.36...@amplitude/plugin-global-user-properties@1.2.37) (2024-12-17)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.36](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.35...@amplitude/plugin-global-user-properties@1.2.36) (2024-11-05)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.35](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.34...@amplitude/plugin-global-user-properties@1.2.35) (2024-10-21)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.34](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.33...@amplitude/plugin-global-user-properties@1.2.34) (2024-09-26)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.33](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.32...@amplitude/plugin-global-user-properties@1.2.33) (2024-09-18)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.32](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.31...@amplitude/plugin-global-user-properties@1.2.32) (2024-09-17)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.31](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.30...@amplitude/plugin-global-user-properties@1.2.31) (2024-09-16)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.30](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.29...@amplitude/plugin-global-user-properties@1.2.30) (2024-09-10)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.29](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.28...@amplitude/plugin-global-user-properties@1.2.29) (2024-09-05)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.28](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.27...@amplitude/plugin-global-user-properties@1.2.28) (2024-08-23)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.27](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.26...@amplitude/plugin-global-user-properties@1.2.27) (2024-08-13)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.26](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.25...@amplitude/plugin-global-user-properties@1.2.26) (2024-08-02)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n## [1.2.25](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.24...@amplitude/plugin-global-user-properties@1.2.25) (2024-06-26)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n\n\n\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.24](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.23...@amplitude/plugin-global-user-properties@1.2.24) (2024-06-24)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.23](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.22...@amplitude/plugin-global-user-properties@1.2.23) (2024-06-24)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.22](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.21...@amplitude/plugin-global-user-properties@1.2.22) (2024-06-17)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.21](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.20...@amplitude/plugin-global-user-properties@1.2.21) (2024-05-24)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.20](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.19...@amplitude/plugin-global-user-properties@1.2.20) (2024-05-21)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.19](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.18...@amplitude/plugin-global-user-properties@1.2.19) (2024-05-17)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.18](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.17...@amplitude/plugin-global-user-properties@1.2.18) (2024-05-15)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.17](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.16...@amplitude/plugin-global-user-properties@1.2.17) (2024-05-07)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.16](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.15...@amplitude/plugin-global-user-properties@1.2.16) (2024-05-03)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.15](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.15-beta.0...@amplitude/plugin-global-user-properties@1.2.15) (2024-04-29)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.15-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.14...@amplitude/plugin-global-user-properties@1.2.15-beta.0) (2024-04-19)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.14](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.14-beta.0...@amplitude/plugin-global-user-properties@1.2.14) (2024-04-09)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.14-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.13...@amplitude/plugin-global-user-properties@1.2.14-beta.0) (2024-03-28)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.12...@amplitude/plugin-global-user-properties@1.2.13) (2024-03-27)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.11...@amplitude/plugin-global-user-properties@1.2.12) (2024-03-23)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.10...@amplitude/plugin-global-user-properties@1.2.11) (2024-03-12)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.9...@amplitude/plugin-global-user-properties@1.2.10) (2024-02-23)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.8...@amplitude/plugin-global-user-properties@1.2.9) (2024-02-23)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.7...@amplitude/plugin-global-user-properties@1.2.8) (2024-02-13)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.6...@amplitude/plugin-global-user-properties@1.2.7) (2024-01-24)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.5...@amplitude/plugin-global-user-properties@1.2.6) (2023-12-20)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.4...@amplitude/plugin-global-user-properties@1.2.5) (2023-12-12)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.4-beta.0...@amplitude/plugin-global-user-properties@1.2.4) (2023-12-01)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.4-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.3...@amplitude/plugin-global-user-properties@1.2.4-beta.0) (2023-11-22)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.2...@amplitude/plugin-global-user-properties@1.2.3) (2023-11-16)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.1...@amplitude/plugin-global-user-properties@1.2.2) (2023-11-16)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.2.0...@amplitude/plugin-global-user-properties@1.2.1) (2023-10-18)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.2.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.1.1...@amplitude/plugin-global-user-properties@1.2.0) (2023-10-05)\n\n### Bug Fixes\n\n- lint and pretttier\n  ([4fcb1a9](https://github.com/amplitude/Amplitude-TypeScript/commit/4fcb1a9ac726b9407f08fe127f18596b53e49ace))\n\n### Features\n\n- add transform option to global user property\n  ([3f4966b](https://github.com/amplitude/Amplitude-TypeScript/commit/3f4966bab25ecdbe688528b4d8a7b33e7b294ee3))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-global-user-properties@1.1.0...@amplitude/plugin-global-user-properties@1.1.1) (2023-09-26)\n\n**Note:** Version bump only for package @amplitude/plugin-global-user-properties\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# 1.1.0 (2023-09-18)\n\n### Bug Fixes\n\n- correct flow of readme\n  ([cc06fa8](https://github.com/amplitude/Amplitude-TypeScript/commit/cc06fa8f2127a809a0fa1d122afbfd8c6f9738f7))\n- **docs:** fix broken language in docs, pr comments\n  ([c2d1e37](https://github.com/amplitude/Amplitude-TypeScript/commit/c2d1e37865cdfbe9776457d849dbb4e2172be2cf))\n- dont modify types in analytics-types\n  ([488832f](https://github.com/amplitude/Amplitude-TypeScript/commit/488832f618c77b81f7ed318aa0af2a92caacae1a))\n- **global user properties:** test, and fix filename\n  ([84bdbef](https://github.com/amplitude/Amplitude-TypeScript/commit/84bdbef3697aba4838ac5cfdddefa85f50420dd7))\n- import statement preventing rollup\n  ([0f632d2](https://github.com/amplitude/Amplitude-TypeScript/commit/0f632d25329c9d04188c41350c03ded78ba57b93))\n- rename modules, move import\n  ([c1a5424](https://github.com/amplitude/Amplitude-TypeScript/commit/c1a5424d37fa98bb513fa66ea3142ebd9f91608c))\n- type hacks for tests\n  ([ed19571](https://github.com/amplitude/Amplitude-TypeScript/commit/ed195715b53b505f39c2a4dc91bcf6f816675d47))\n- version ([919947b](https://github.com/amplitude/Amplitude-TypeScript/commit/919947bcb62eed4144ac4d0d9f5cb3e9fb614286))\n\n### Features\n\n- add readme docs\n  ([91e741f](https://github.com/amplitude/Amplitude-TypeScript/commit/91e741fb72a76af8c3305023e6312456decade50))\n"
  },
  {
    "path": "packages/plugin-global-user-properties/README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://amplitude.com\" target=\"_blank\" align=\"center\">\n    <img src=\"https://static.amplitude.com/lightning/46c85bfd91905de8047f1ee65c7c93d6fa9ee6ea/static/media/amplitude-logo-with-text.4fb9e463.svg\" width=\"280\">\n  </a>\n  <br />\n</p>\n\n# @amplitude/plugin-global-user-properties\n\nOfficial SDK plugin for adding global user properties to events\n\n## Installation\n\nThis package is published on NPM registry and is available to be installed using npm and yarn.\n\n```sh\n# npm\nnpm install @amplitude/plugin-global-user-properties\n\n# yarn\nyarn add @amplitude/plugin-global-user-properties\n```\n\n## Usage\n\nThis plugin works on top of the Amplitude SDK and sends user properties as global user properties, a beta feature for that allows projects to share user properties (i.e. user properties can become \"global\" across multiple projects). \n\nTo use this plugin, you need to install `@amplitude/plugin-global-user-properties `v1.0.0` or later.\n\n### 1. Import Amplitude packages\n\n* `@amplitude/plugin-global-user-properties`\n\n```typescript\nimport * as Amplitude from '@amplitude/analytics-browser'\nimport { globalUserPropertiesPlugin } from '@amplitude/plugin-global-user-properties';\n```\n\n### 2. Instantiate page view plugin\n\nThe plugin accepts an optional parameter of type `Object` to configure the plugin based on your use case.\n\n```typescript\nconst globalUserPropertiesPlugin = globalUserPropertiesPlugin({\n  shouldKeepOriginalUserProperties: true,\n});\n```\n\n#### Options\n\n|Name|Type|Default|Description|\n|-|-|-|-|\n|`shouldKeepOriginalUserProperties`|`boolean`| `false` | Use this option if you want the user properties to be sent along with the global user properties. Since global user properties do not appear in Data yet, this would allow indirect governance (by observing the same properties as regular user properties). |\n\n### 3. Install plugin to Amplitude SDK\n\n```typescript\namplitude.add(globalUserPropertiesPlugin);\n```\n\n### 4. Initialize Amplitude SDK\n\n```typescript\namplitude.init('API_KEY');\n```\n\n"
  },
  {
    "path": "packages/plugin-global-user-properties/jest.config.js",
    "content": "const baseConfig = require('../../jest.config.js');\nconst package = require('./package');\n\nmodule.exports = {\n  ...baseConfig,\n  displayName: package.name,\n  rootDir: '.',\n  testEnvironment: 'jsdom',\n  coveragePathIgnorePatterns: ['index.ts'],\n};\n"
  },
  {
    "path": "packages/plugin-global-user-properties/package.json",
    "content": "{\n  \"name\": \"@amplitude/plugin-global-user-properties\",\n  \"version\": \"1.2.136\",\n  \"description\": \"An event enrichment plugin that adds the experimental global user properties field to events\",\n  \"author\": \"Amplitude Inc\",\n  \"homepage\": \"https://github.com/amplitude/Amplitude-TypeScript\",\n  \"license\": \"MIT\",\n  \"main\": \"lib/cjs/index.js\",\n  \"module\": \"lib/esm/index.js\",\n  \"types\": \"lib/esm/index.d.ts\",\n  \"sideEffects\": false,\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"tag\": \"latest\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/amplitude/Amplitude-TypeScript.git\"\n  },\n  \"scripts\": {\n    \"build\": \"pnpm bundle && pnpm build:es5 && pnpm build:esm\",\n    \"bundle\": \"rollup --config rollup.config.js\",\n    \"build:es5\": \"tsc -p ./tsconfig.es5.json\",\n    \"build:esm\": \"tsc -p ./tsconfig.esm.json\",\n    \"watch\": \"tsc -p ./tsconfig.esm.json --watch\",\n    \"clean\": \"rimraf node_modules lib coverage\",\n    \"fix\": \"pnpm fix:eslint & pnpm fix:prettier\",\n    \"fix:eslint\": \"eslint '{src,test}/**/*.ts' --fix\",\n    \"fix:prettier\": \"prettier --write \\\"{src,test}/**/*.ts\\\"\",\n    \"lint\": \"pnpm lint:eslint & pnpm lint:prettier\",\n    \"lint:eslint\": \"eslint '{src,test}/**/*.ts'\",\n    \"lint:prettier\": \"prettier --check \\\"{src,test}/**/*.ts\\\"\",\n    \"test\": \"jest\",\n    \"typecheck\": \"tsc -p ./tsconfig.json\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/amplitude/Amplitude-TypeScript/issues\"\n  },\n  \"dependencies\": {\n    \"@amplitude/analytics-types\": \"workspace:*\",\n    \"tslib\": \"^2.4.1\"\n  },\n  \"devDependencies\": {\n    \"@rollup/plugin-commonjs\": \"^23.0.4\",\n    \"@rollup/plugin-node-resolve\": \"^15.0.1\",\n    \"@rollup/plugin-typescript\": \"^10.0.1\",\n    \"rollup\": \"^2.79.1\",\n    \"rollup-plugin-execute\": \"^1.1.1\",\n    \"rollup-plugin-gzip\": \"^3.1.0\",\n    \"rollup-plugin-terser\": \"^7.0.2\"\n  },\n  \"files\": [\n    \"lib\"\n  ]\n}\n"
  },
  {
    "path": "packages/plugin-global-user-properties/rollup.config.js",
    "content": "import { umd } from '../../scripts/build/rollup.config';\n\nexport default [umd];\n"
  },
  {
    "path": "packages/plugin-global-user-properties/src/global-user-properties.ts",
    "content": "import { EnrichmentPlugin, Event } from '@amplitude/analytics-types';\nimport { GlobalUserPropertiesPlugin, Options } from './typings/global-user-properties';\nimport { isAmplitudeIdentifyEvent, isTrackEvent } from './helpers';\n\nexport const globalUserPropertiesPlugin: GlobalUserPropertiesPlugin = function (options: Options = {}) {\n  const plugin: EnrichmentPlugin = {\n    name: '@amplitude/plugin-global-user-properties',\n    type: 'enrichment',\n\n    /* Note: The promise is because of the interface, not because this has any asynchronous behavior */\n    execute: async (event: Event): Promise<Event> => {\n      if (!isTrackEvent(event) && !isAmplitudeIdentifyEvent(event)) {\n        return event;\n      }\n\n      let globalUserProperties = event.user_properties;\n      if (options.propertyTransform && globalUserProperties) {\n        globalUserProperties = options.propertyTransform(globalUserProperties);\n      }\n\n      if (!globalUserProperties) {\n        return event;\n      }\n\n      event.global_user_properties = globalUserProperties;\n\n      if (!options.shouldKeepOriginalUserProperties) {\n        delete event.user_properties;\n      }\n\n      return event;\n    },\n  };\n\n  return plugin;\n};\n"
  },
  {
    "path": "packages/plugin-global-user-properties/src/helpers.ts",
    "content": "import { Event, TrackEvent, SpecialEventType, IdentifyEvent } from '@amplitude/analytics-types';\n\nconst specialAmplitudeEvents = new Set(Object.values(SpecialEventType));\n\nexport const isTrackEvent = (event: Event): event is TrackEvent => {\n  return !specialAmplitudeEvents.has(event.event_type as SpecialEventType);\n};\n\nexport const isAmplitudeIdentifyEvent = (event: Event): event is IdentifyEvent => {\n  return event.event_type === SpecialEventType.IDENTIFY;\n};\n"
  },
  {
    "path": "packages/plugin-global-user-properties/src/index.ts",
    "content": "export { globalUserPropertiesPlugin } from './global-user-properties';\nexport { globalUserPropertiesPlugin as plugin } from './global-user-properties';\nexport { GlobalUserPropertiesPlugin, Options } from './typings/global-user-properties';\n"
  },
  {
    "path": "packages/plugin-global-user-properties/src/typings/global-user-properties.ts",
    "content": "import { EnrichmentPlugin } from '@amplitude/analytics-types';\n\nexport interface Options {\n  /**\n   * A configuration to modify the user properties before they are attached as global user properties\n   *\n   * @param properties The original user properties on the event\n   * @returns The modified global user properties. Returning no properties is possible\n   */\n  propertyTransform?: (properties: { [key: string]: any }) => { [key: string]: any } | undefined;\n  /**\n   * Whether or not the orignal user_properties field should be kept on the event\n   */\n  shouldKeepOriginalUserProperties?: boolean;\n}\n\nexport interface GlobalUserPropertiesPlugin {\n  (options?: Options): EnrichmentPlugin;\n}\n"
  },
  {
    "path": "packages/plugin-global-user-properties/test/global-user-properties.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unsafe-member-access */\nimport { globalUserPropertiesPlugin } from '../src/global-user-properties';\nimport { TrackEvent, IdentifyEvent, RevenueEvent, SpecialEventType } from '@amplitude/analytics-types';\n\n// ts-jest is having difficulty finding the module declaration types, so there are some any's\ndescribe('globalUserPropertiesPlugin', () => {\n  const TEST_USER_PROPERTIES = {\n    USER_PROPERTY_ONE: 'TEST_VALUE_ONE',\n  };\n\n  const TEST_USER_IDENTIFY_PROPERTIES = {\n    $set: {\n      USER_PROPERTY_ONE: 'TEST_VALUE_ONE',\n    },\n  };\n\n  test('adds global properties on regular events', async () => {\n    const plugin = globalUserPropertiesPlugin();\n\n    const event: TrackEvent = {\n      event_type: 'NOT A REAL EVENT TYPE',\n      user_properties: TEST_USER_PROPERTIES,\n    };\n\n    const newEvent: any = await plugin.execute?.({ ...event });\n\n    expect(newEvent?.event_type).toEqual(event.event_type);\n    expect(newEvent?.global_user_properties).toStrictEqual(TEST_USER_PROPERTIES);\n    expect(newEvent?.user_properties).toStrictEqual(undefined);\n  });\n\n  test('adds global properties on identify events', async () => {\n    const plugin = globalUserPropertiesPlugin();\n\n    const event: IdentifyEvent = {\n      event_type: SpecialEventType.IDENTIFY,\n      user_properties: TEST_USER_IDENTIFY_PROPERTIES,\n    };\n\n    const newEvent: any = await plugin.execute?.({ ...event });\n\n    expect(newEvent?.global_user_properties).toStrictEqual(TEST_USER_IDENTIFY_PROPERTIES);\n    expect(newEvent?.user_properties).toStrictEqual(undefined);\n  });\n\n  test('does not add global properties when user properties are not present', async () => {\n    const plugin = globalUserPropertiesPlugin();\n\n    const event: TrackEvent = {\n      event_type: 'NOT A REAL EVENT TYPE',\n    };\n\n    const newEvent: any = await plugin.execute?.({ ...event });\n    expect(newEvent?.global_user_properties).toStrictEqual(undefined);\n  });\n\n  test('does not add global properties on revenue events', async () => {\n    const plugin = globalUserPropertiesPlugin();\n\n    const event: RevenueEvent = {\n      event_type: SpecialEventType.REVENUE,\n      revenue: 3,\n      event_properties: {},\n    };\n\n    const newEvent: any = await plugin.execute?.({ ...event });\n\n    expect(newEvent?.global_user_properties).toStrictEqual(undefined);\n    expect(newEvent?.user_properties).toStrictEqual(event.user_properties);\n  });\n\n  test('adds global properties and user properties on identify events with shouldKeepOriginalUserProperties option', async () => {\n    const plugin = globalUserPropertiesPlugin({ shouldKeepOriginalUserProperties: true });\n\n    const event: IdentifyEvent = {\n      event_type: SpecialEventType.IDENTIFY,\n      user_properties: TEST_USER_IDENTIFY_PROPERTIES,\n    };\n\n    const newEvent: any = await plugin.execute?.({ ...event });\n\n    expect(newEvent?.global_user_properties).toStrictEqual(TEST_USER_IDENTIFY_PROPERTIES);\n    expect(newEvent?.user_properties).toStrictEqual(TEST_USER_IDENTIFY_PROPERTIES);\n  });\n\n  test('transforms properties when the property transform option is passed', async () => {\n    const plugin = globalUserPropertiesPlugin({ propertyTransform: () => TEST_USER_IDENTIFY_PROPERTIES });\n\n    const event: TrackEvent = {\n      event_type: 'NOT A REAL EVENT TYPE',\n      user_properties: TEST_USER_PROPERTIES,\n    };\n\n    const newEvent: any = await plugin.execute?.({ ...event });\n    expect(newEvent?.global_user_properties).toStrictEqual(TEST_USER_IDENTIFY_PROPERTIES);\n  });\n});\n"
  },
  {
    "path": "packages/plugin-global-user-properties/tsconfig.es5.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/cjs\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-global-user-properties/tsconfig.esm.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"es6\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/esm\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-global-user-properties/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src/**/*\", \"test/**/*\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"esModuleInterop\": true,\n    \"lib\": [\"dom\"],\n    \"noEmit\": true,\n    \"rootDir\": \".\",\n  }\n}\n"
  },
  {
    "path": "packages/plugin-network-capture-browser/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.10.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.9.16...@amplitude/plugin-network-capture-browser@1.10.0) (2026-04-28)\n\n\n### Features\n\n* remove experimental request body compression backdoor ([#1699](https://github.com/amplitude/Amplitude-TypeScript/issues/1699)) ([98ecb9d](https://github.com/amplitude/Amplitude-TypeScript/commit/98ecb9dc1f3658cf6d0dfae1e9784335c9d33b5e))\n\n\n\n\n\n## [1.9.16](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.9.15...@amplitude/plugin-network-capture-browser@1.9.16) (2026-04-22)\n\n\n### Bug Fixes\n\n* **analytics-browser:** replace \"blocklist\" with \"excludelist\" in networkTracking ([#1692](https://github.com/amplitude/Amplitude-TypeScript/issues/1692)) ([f84374e](https://github.com/amplitude/Amplitude-TypeScript/commit/f84374eb0a4754e9fedfec0fbb9694531ba021e9))\n\n\n\n\n\n## [1.9.15](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.9.14...@amplitude/plugin-network-capture-browser@1.9.15) (2026-04-21)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.9.14](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.9.13...@amplitude/plugin-network-capture-browser@1.9.14) (2026-04-14)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.9.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.9.12...@amplitude/plugin-network-capture-browser@1.9.13) (2026-04-09)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.9.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.9.11...@amplitude/plugin-network-capture-browser@1.9.12) (2026-04-01)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.9.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.9.10...@amplitude/plugin-network-capture-browser@1.9.11) (2026-03-26)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.9.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.9.9...@amplitude/plugin-network-capture-browser@1.9.10) (2026-03-23)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.9.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.9.8...@amplitude/plugin-network-capture-browser@1.9.9) (2026-03-20)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.9.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.9.7...@amplitude/plugin-network-capture-browser@1.9.8) (2026-03-19)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.9.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.9.6...@amplitude/plugin-network-capture-browser@1.9.7) (2026-03-17)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.9.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.9.5...@amplitude/plugin-network-capture-browser@1.9.6) (2026-03-16)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.9.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.9.4...@amplitude/plugin-network-capture-browser@1.9.5) (2026-03-13)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.9.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.9.3...@amplitude/plugin-network-capture-browser@1.9.4) (2026-03-12)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.9.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.9.2...@amplitude/plugin-network-capture-browser@1.9.3) (2026-03-09)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.9.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.9.1...@amplitude/plugin-network-capture-browser@1.9.2) (2026-03-05)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.9.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.9.0...@amplitude/plugin-network-capture-browser@1.9.1) (2026-03-03)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n# [1.9.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.8.3...@amplitude/plugin-network-capture-browser@1.9.0) (2026-03-03)\n\n\n### Features\n\n* manual opt in gzip ([#1568](https://github.com/amplitude/Amplitude-TypeScript/issues/1568)) ([303c130](https://github.com/amplitude/Amplitude-TypeScript/commit/303c130429c51b0913f3903db4ace5263e1c78e7))\n\n\n\n\n\n## [1.8.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.8.2...@amplitude/plugin-network-capture-browser@1.8.3) (2026-02-26)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.8.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.8.1...@amplitude/plugin-network-capture-browser@1.8.2) (2026-02-24)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.8.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.8.0...@amplitude/plugin-network-capture-browser@1.8.1) (2026-02-19)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n# [1.8.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.7.9...@amplitude/plugin-network-capture-browser@1.8.0) (2026-02-17)\n\n\n### Features\n\n* **analytics-browser:** add setIdentity() ([#1517](https://github.com/amplitude/Amplitude-TypeScript/issues/1517)) ([314b3c1](https://github.com/amplitude/Amplitude-TypeScript/commit/314b3c1b7ee5b0ef135848a66156eb2874daec5f))\n\n\n\n\n\n## [1.7.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.7.8...@amplitude/plugin-network-capture-browser@1.7.9) (2026-02-10)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.7.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.7.7...@amplitude/plugin-network-capture-browser@1.7.8) (2026-01-26)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.7.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.7.6...@amplitude/plugin-network-capture-browser@1.7.7) (2026-01-21)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.7.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.7.5...@amplitude/plugin-network-capture-browser@1.7.6) (2026-01-15)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.7.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.7.4...@amplitude/plugin-network-capture-browser@1.7.5) (2026-01-14)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.7.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.7.3...@amplitude/plugin-network-capture-browser@1.7.4) (2026-01-14)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.7.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.7.2...@amplitude/plugin-network-capture-browser@1.7.3) (2025-12-24)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.7.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.7.1...@amplitude/plugin-network-capture-browser@1.7.2) (2025-12-16)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.7.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.7.0...@amplitude/plugin-network-capture-browser@1.7.1) (2025-12-09)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n# [1.7.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.6.16...@amplitude/plugin-network-capture-browser@1.7.0) (2025-11-21)\n\n\n### Features\n\n* **analytics-browser:** reduce bundle size via refactoring out rxjs ([#1391](https://github.com/amplitude/Amplitude-TypeScript/issues/1391)) ([09ade0b](https://github.com/amplitude/Amplitude-TypeScript/commit/09ade0b37cfdbaacb0e328cb812168d60dc25124))\n\n\n\n\n\n## [1.6.16](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.6.15...@amplitude/plugin-network-capture-browser@1.6.16) (2025-11-20)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.6.15](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.6.14...@amplitude/plugin-network-capture-browser@1.6.15) (2025-11-17)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.6.14](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.6.13...@amplitude/plugin-network-capture-browser@1.6.14) (2025-11-17)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.6.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.6.12...@amplitude/plugin-network-capture-browser@1.6.13) (2025-11-05)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.6.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.6.11...@amplitude/plugin-network-capture-browser@1.6.12) (2025-10-29)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.6.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.6.10...@amplitude/plugin-network-capture-browser@1.6.11) (2025-10-23)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.6.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.6.9...@amplitude/plugin-network-capture-browser@1.6.10) (2025-10-23)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.6.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.6.8...@amplitude/plugin-network-capture-browser@1.6.9) (2025-10-17)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.6.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.6.7...@amplitude/plugin-network-capture-browser@1.6.8) (2025-10-15)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.6.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.6.6...@amplitude/plugin-network-capture-browser@1.6.7) (2025-10-14)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.6.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.6.5...@amplitude/plugin-network-capture-browser@1.6.6) (2025-10-14)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.6.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.6.4...@amplitude/plugin-network-capture-browser@1.6.5) (2025-10-03)\n\n\n### Bug Fixes\n\n* add diagnostics to client and track autocapture getHierachy block time ([#1312](https://github.com/amplitude/Amplitude-TypeScript/issues/1312)) ([a919e22](https://github.com/amplitude/Amplitude-TypeScript/commit/a919e223428083a87954cffa50bc765baa5360b0))\n\n\n\n\n\n## [1.6.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.6.3...@amplitude/plugin-network-capture-browser@1.6.4) (2025-10-01)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.6.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.6.2...@amplitude/plugin-network-capture-browser@1.6.3) (2025-09-25)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.6.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.6.1...@amplitude/plugin-network-capture-browser@1.6.2) (2025-09-23)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.6.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.6.0...@amplitude/plugin-network-capture-browser@1.6.1) (2025-09-18)\n\n\n### Bug Fixes\n\n* **analytics-browser:** stringify request/response bodies in Network Request Event ([#1292](https://github.com/amplitude/Amplitude-TypeScript/issues/1292)) ([a5dd03c](https://github.com/amplitude/Amplitude-TypeScript/commit/a5dd03cf19328e5d0bef5192480cea58db304da0))\n\n\n\n\n\n# [1.6.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.5.5...@amplitude/plugin-network-capture-browser@1.6.0) (2025-09-12)\n\n\n### Features\n\n* **analytics-browser:** add urlsRegex to remote capture rule for network tracking ([#1284](https://github.com/amplitude/Amplitude-TypeScript/issues/1284)) ([04392c9](https://github.com/amplitude/Amplitude-TypeScript/commit/04392c96844f5328e8d04d7c3840ad273ce38a43))\n\n\n\n\n\n## [1.5.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.5.4...@amplitude/plugin-network-capture-browser@1.5.5) (2025-09-05)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.5.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.5.3...@amplitude/plugin-network-capture-browser@1.5.4) (2025-08-28)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.5.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.5.2...@amplitude/plugin-network-capture-browser@1.5.3) (2025-08-26)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.5.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.5.1...@amplitude/plugin-network-capture-browser@1.5.2) (2025-08-25)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.5.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.5.0...@amplitude/plugin-network-capture-browser@1.5.1) (2025-08-22)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n# [1.5.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.4.5...@amplitude/plugin-network-capture-browser@1.5.0) (2025-08-21)\n\n\n### Features\n\n* **analytics-browser:** add urls matching attribute to network capture rules (experimental) ([#1252](https://github.com/amplitude/Amplitude-TypeScript/issues/1252)) ([c28a98c](https://github.com/amplitude/Amplitude-TypeScript/commit/c28a98c13536d3eb2472edcce6ec225539db00aa))\n* **plugin-network-capture-browser:** add ability to capture headers (experimental) ([#1253](https://github.com/amplitude/Amplitude-TypeScript/issues/1253)) ([52cfc0c](https://github.com/amplitude/Amplitude-TypeScript/commit/52cfc0c6dab309f30cfce56c091065ff95d95fc2))\n* **plugin-network-capture-browser:** add request + response body capture (experimental) ([#1256](https://github.com/amplitude/Amplitude-TypeScript/issues/1256)) ([1850c58](https://github.com/amplitude/Amplitude-TypeScript/commit/1850c58d145973b3bd104ab70368eb4e2fdbafbc))\n\n\n\n\n\n## [1.4.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.4.4...@amplitude/plugin-network-capture-browser@1.4.5) (2025-08-13)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.4.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.4.3...@amplitude/plugin-network-capture-browser@1.4.4) (2025-08-08)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.4.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.4.2...@amplitude/plugin-network-capture-browser@1.4.3) (2025-08-05)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.4.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.4.1...@amplitude/plugin-network-capture-browser@1.4.2) (2025-07-29)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.4.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.4.0...@amplitude/plugin-network-capture-browser@1.4.1) (2025-07-17)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n# [1.4.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.3.1...@amplitude/plugin-network-capture-browser@1.4.0) (2025-07-15)\n\n\n### Bug Fixes\n\n* **analytics-browser:** prevent infinite Amplitude network requests ([#1100](https://github.com/amplitude/Amplitude-TypeScript/issues/1100)) ([fde763c](https://github.com/amplitude/Amplitude-TypeScript/commit/fde763cd4889bda41edc55789ee18186711d825e))\n\n\n### Features\n\n* **analytics-browser:** add experimental frustrationInteractions ([#1209](https://github.com/amplitude/Amplitude-TypeScript/issues/1209)) ([e321744](https://github.com/amplitude/Amplitude-TypeScript/commit/e3217444c58be15e779ff1fd54a55027c93f5db0))\n\n\n\n\n\n## [1.3.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.3.0...@amplitude/plugin-network-capture-browser@1.3.1) (2025-07-08)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n# [1.3.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.2.0...@amplitude/plugin-network-capture-browser@1.3.0) (2025-06-30)\n\n\n### Features\n\n* add getOptOut() and getIdentity() ([#1174](https://github.com/amplitude/Amplitude-TypeScript/issues/1174)) ([72017c8](https://github.com/amplitude/Amplitude-TypeScript/commit/72017c8a1a54d929542e883e61d61168f214a780))\n\n\n\n\n\n# [1.2.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.1.10...@amplitude/plugin-network-capture-browser@1.2.0) (2025-06-26)\n\n\n### Features\n\n* **plugin-autocapture-browser:** add rage+dead clicks to autocapture plugin ([#1146](https://github.com/amplitude/Amplitude-TypeScript/issues/1146)) ([c850f02](https://github.com/amplitude/Amplitude-TypeScript/commit/c850f020a6b56bbd8d64e0f946acaf0eac15ccf7))\n\n\n\n\n\n## [1.1.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.1.9...@amplitude/plugin-network-capture-browser@1.1.10) (2025-06-25)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.1.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.1.8...@amplitude/plugin-network-capture-browser@1.1.9) (2025-06-11)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.1.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.1.7...@amplitude/plugin-network-capture-browser@1.1.8) (2025-06-03)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.1.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.1.7-main.0...@amplitude/plugin-network-capture-browser@1.1.7) (2025-05-27)\n\n\n### Bug Fixes\n\n* **analytics-browser:** support XHR in network capture ([#1089](https://github.com/amplitude/Amplitude-TypeScript/issues/1089)) ([339d49c](https://github.com/amplitude/Amplitude-TypeScript/commit/339d49cfa7b07ffc20fe085b8548f6489a3029f3))\n\n\n### Reverts\n\n* \"chore(release): publish\" ([#1094](https://github.com/amplitude/Amplitude-TypeScript/issues/1094)) ([f6db1ee](https://github.com/amplitude/Amplitude-TypeScript/commit/f6db1eed32ed77c7ce626624dc55972971f3b27d))\n\n\n\n\n\n## [1.1.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.1.5...@amplitude/plugin-network-capture-browser@1.1.6) (2025-05-14)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.1.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.1.4...@amplitude/plugin-network-capture-browser@1.1.5) (2025-05-13)\n\n\n### Bug Fixes\n\n* **analytics-core:** make network observer event callbacks handle exceptions ([#1071](https://github.com/amplitude/Amplitude-TypeScript/issues/1071)) ([baf46e2](https://github.com/amplitude/Amplitude-TypeScript/commit/baf46e22585f58924b801e301db78c7aecda1b4a))\n\n\n\n\n\n## [1.1.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.1.3...@amplitude/plugin-network-capture-browser@1.1.4) (2025-05-07)\n\n\n### Bug Fixes\n\n* **plugin-network-capture:** fix bug that fails to capture relative URLs ([#1064](https://github.com/amplitude/Amplitude-TypeScript/issues/1064)) ([22ceea3](https://github.com/amplitude/Amplitude-TypeScript/commit/22ceea375a7d603f5b48d20682f93ac49f204670))\n\n\n\n\n\n## [1.1.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.1.2...@amplitude/plugin-network-capture-browser@1.1.3) (2025-05-05)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n## [1.1.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.1.1...@amplitude/plugin-network-capture-browser@1.1.2) (2025-05-02)\n\n\n### Bug Fixes\n\n* change Network Request startTime and completionTime to Unix Epoch to match with iOS ([#1059](https://github.com/amplitude/Amplitude-TypeScript/issues/1059)) ([9cf0246](https://github.com/amplitude/Amplitude-TypeScript/commit/9cf02463d95e1d2d067d801e09cfed41864bd571))\n\n\n\n\n\n## [1.1.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-network-capture-browser@1.1.0...@amplitude/plugin-network-capture-browser@1.1.1) (2025-05-02)\n\n**Note:** Version bump only for package @amplitude/plugin-network-capture-browser\n\n\n\n\n\n# 1.1.0 (2025-05-02)\n\n\n### Features\n\n* **analytics-browser:** autocapture network errors ([#1050](https://github.com/amplitude/Amplitude-TypeScript/issues/1050)) ([104350f](https://github.com/amplitude/Amplitude-TypeScript/commit/104350ffe8b1bd1a7090482ac3bf24d85672bd43))\n"
  },
  {
    "path": "packages/plugin-network-capture-browser/README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://amplitude.com\" target=\"_blank\" align=\"center\">\n    <img src=\"https://static.amplitude.com/lightning/46c85bfd91905de8047f1ee65c7c93d6fa9ee6ea/static/media/amplitude-logo-with-text.4fb9e463.svg\" width=\"280\">\n  </a>\n  <br />\n</p>\n\n# @amplitude/plugin-network-capture-browser (beta)\n**This plugin is in beta at the moment, naming and interface might change in the future.**\n\n## TODO: Re-write this README.md to match plugin-network-capture\n\nBrowser SDK plugin for network capture.\n\n## Installation\n\nThis package is published on NPM registry and is available to be installed using npm and yarn.\n\n```sh\n# npm\nnpm install @amplitude/plugin-network-capture-browser@beta\n\n# yarn\nyarn add @amplitude/plugin-network-capture-browser@beta\n```\n\n## Usage\n\nThis plugin works on top of the Amplitude Browser SDK, and tracks network request events\n\nTo use this plugin, you need to install `@amplitude/plugin-network-capture-browser`\n\n### 1. Import Amplitude packages\n\n* `@amplitude/analytics-browser`\n* `@amplitude/plugin-network-capture-browser`\n\n```typescript\nimport * as amplitude from '@amplitude/analytics-browser';\nimport { networkCapturePlugin } from '@amplitude/plugin-network-capture-browser';\n```\n\n### 2. Instantiate the plugin\n\nThe plugin accepts 1 optional parameter, which is an `Object` to configure the allowed tracking options.\n\n```typescript\nconst plugin = networkCapturePlugin({\n  ignoreHosts: ['host.com', 'host2.com'], // hosts to ignore; default []\n  ignoreAmplitudeRequests: true, // ignore requests to amplitude.com; default \"true\",\n  captureRules: [\n    {hosts: ['host3.com', 'host4.com'], statusCodeRange: '400-499'},\n    {hosts: ['example.com'], statusCodeRange: '403,500-599'},\n  ],\n});\n```\n\n### 3. Install plugin to Amplitude SDK\n\n```typescript\namplitude.add(plugin);\n```\n\n### 4. Initialize Amplitude SDK\n\n```typescript\namplitude.init('API_KEY');\n```\n"
  },
  {
    "path": "packages/plugin-network-capture-browser/jest.config.js",
    "content": "const baseConfig = require('../../jest.config.js');\nconst package = require('./package');\n\nmodule.exports = {\n  ...baseConfig,\n  displayName: package.name,\n  rootDir: '.',\n  testEnvironment: 'jsdom',\n  coveragePathIgnorePatterns: ['index.ts'],\n  setupFiles: ['./test/setup.ts'],\n};\n\n"
  },
  {
    "path": "packages/plugin-network-capture-browser/package.json",
    "content": "{\n  \"name\": \"@amplitude/plugin-network-capture-browser\",\n  \"version\": \"1.10.0\",\n  \"description\": \"\",\n  \"author\": \"Amplitude Inc\",\n  \"homepage\": \"https://github.com/amplitude/Amplitude-TypeScript\",\n  \"license\": \"MIT\",\n  \"main\": \"lib/cjs/index.js\",\n  \"module\": \"lib/esm/index.js\",\n  \"types\": \"lib/esm/index.d.ts\",\n  \"sideEffects\": false,\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"tag\": \"beta\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/amplitude/Amplitude-TypeScript.git\"\n  },\n  \"scripts\": {\n    \"build\": \"pnpm bundle && pnpm build:es5 && pnpm build:esm\",\n    \"bundle\": \"rollup --config rollup.config.js\",\n    \"build:es5\": \"tsc -p ./tsconfig.es5.json\",\n    \"build:esm\": \"tsc -p ./tsconfig.esm.json\",\n    \"watch\": \"tsc -p ./tsconfig.esm.json --watch\",\n    \"clean\": \"rimraf node_modules lib coverage\",\n    \"fix\": \"pnpm fix:eslint & pnpm fix:prettier\",\n    \"fix:eslint\": \"eslint '{src,test}/**/*.ts' --fix\",\n    \"fix:prettier\": \"prettier --write \\\"{src,test}/**/*.ts\\\"\",\n    \"lint\": \"pnpm lint:eslint & pnpm lint:prettier\",\n    \"lint:eslint\": \"eslint '{src,test}/**/*.ts'\",\n    \"lint:prettier\": \"prettier --check \\\"{src,test}/**/*.ts\\\"\",\n    \"publish\": \"node ../../scripts/publish/upload-to-s3.js\",\n    \"test\": \"jest\",\n    \"typecheck\": \"tsc -p ./tsconfig.json\",\n    \"version\": \"pnpm version-file && pnpm build\",\n    \"version-file\": \"node -p \\\"'export const VERSION = \\\\'' + require('./package.json').version + '\\\\';'\\\" > src/version.ts\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/amplitude/Amplitude-TypeScript/issues\"\n  },\n  \"dependencies\": {\n    \"@amplitude/analytics-core\": \"workspace:*\",\n    \"tslib\": \"^2.4.1\"\n  },\n  \"devDependencies\": {\n    \"@aws-sdk/client-s3\": \"^3.229.0\",\n    \"@rollup/plugin-commonjs\": \"^23.0.4\",\n    \"@rollup/plugin-node-resolve\": \"^15.0.1\",\n    \"@rollup/plugin-typescript\": \"^10.0.1\",\n    \"css.escape\": \"^1.5.1\",\n    \"rollup\": \"^2.79.1\",\n    \"rollup-plugin-execute\": \"^1.1.1\",\n    \"rollup-plugin-gzip\": \"^3.1.0\",\n    \"rollup-plugin-sourcemaps\": \"^0.6.3\",\n    \"rollup-plugin-terser\": \"^7.0.2\"\n  },\n  \"files\": [\n    \"lib\"\n  ]\n}\n"
  },
  {
    "path": "packages/plugin-network-capture-browser/rollup.config.js",
    "content": "import { iife, umd } from '../../scripts/build/rollup.config';\n\niife.input = umd.input;\niife.output.name = 'amplitudeNetworkCapturePlugin';\n\nexport default [umd, iife];\n"
  },
  {
    "path": "packages/plugin-network-capture-browser/src/constants.ts",
    "content": "export const PLUGIN_NAME = '@amplitude/plugin-network-capture-browser';\n\nexport const AMPLITUDE_NETWORK_REQUEST_EVENT = '[Amplitude] Network Request';\n\n// TODO: when @experimental is removed from responseHeaders and requestHeaders,\n// remove this constant or set it to false\nexport const IS_HEADER_CAPTURE_EXPERIMENTAL = true;\n"
  },
  {
    "path": "packages/plugin-network-capture-browser/src/index.ts",
    "content": "export { networkCapturePlugin as plugin, networkCapturePlugin } from './network-capture-plugin';\n"
  },
  {
    "path": "packages/plugin-network-capture-browser/src/network-capture-plugin.ts",
    "content": "/* eslint-disable no-restricted-globals */\nimport {\n  BrowserClient,\n  BrowserConfig,\n  EnrichmentPlugin,\n  NetworkRequestEvent,\n  networkObserver,\n  NetworkEventCallback,\n  NetworkTrackingOptions,\n  ILogger,\n} from '@amplitude/analytics-core';\nimport * as constants from './constants';\nimport { Observable, Unsubscribable } from '@amplitude/analytics-core';\nimport { trackNetworkEvents } from './track-network-event';\n\nexport type BrowserEnrichmentPlugin = EnrichmentPlugin<BrowserClient, BrowserConfig>;\n\nexport enum ObservablesEnum {\n  NetworkObservable = 'networkObservable',\n}\n\n// Base TimestampedEvent type\ntype BaseTimestampedEvent<T> = {\n  event: T;\n  timestamp: number;\n  type: 'rage' | 'click' | 'change' | 'error' | 'navigate' | 'mutation' | 'network';\n};\n\n// Specific types for events with targetElementProperties\nexport type ElementBasedEvent = MouseEvent | Event;\nexport type ElementBasedTimestampedEvent<T> = BaseTimestampedEvent<T> & {\n  event: MouseEvent | Event;\n  type: 'click' | 'change';\n  closestTrackedAncestor: Element;\n  targetElementProperties: Record<string, any>;\n};\n\n// Union type for all possible TimestampedEvents\nexport type TimestampedEvent<T> = BaseTimestampedEvent<T> | ElementBasedTimestampedEvent<T>;\n\nexport interface AllWindowObservables {\n  [ObservablesEnum.NetworkObservable]: Observable<TimestampedEvent<NetworkRequestEvent>>;\n}\n\nlet subscription: Unsubscribable;\n\nexport const networkCapturePlugin = (options: NetworkTrackingOptions = {}): BrowserEnrichmentPlugin => {\n  const name = constants.PLUGIN_NAME;\n  const type = 'enrichment';\n  let logger: ILogger;\n\n  const addAdditionalEventProperties = <T>(\n    event: T,\n    type: TimestampedEvent<T>['type'],\n  ): TimestampedEvent<T> | ElementBasedTimestampedEvent<T> => {\n    const baseEvent: BaseTimestampedEvent<T> | ElementBasedTimestampedEvent<T> = {\n      event,\n      timestamp: Date.now(),\n      type,\n    };\n\n    return baseEvent;\n  };\n\n  // Create observables on events on the window\n  const createObservables = (): AllWindowObservables => {\n    const networkObservable = new Observable<TimestampedEvent<NetworkRequestEvent>>((observer) => {\n      const callback = new NetworkEventCallback((event) => {\n        const eventWithProperties = addAdditionalEventProperties(event, 'network');\n        observer.next(eventWithProperties);\n      });\n      networkObserver.subscribe(callback, logger);\n      return () => {\n        networkObserver.unsubscribe(callback);\n      };\n    });\n\n    return {\n      [ObservablesEnum.NetworkObservable]: networkObservable,\n    };\n  };\n\n  const setup: BrowserEnrichmentPlugin['setup'] = async (config, amplitude) => {\n    /* istanbul ignore if */\n    if (typeof document === 'undefined') {\n      return;\n    }\n\n    // Create observables for events on the window\n    const allObservables = createObservables();\n\n    /* istanbul ignore next */\n    logger = config?.loggerProvider;\n\n    subscription = trackNetworkEvents({\n      allObservables,\n      networkTrackingOptions: options,\n      amplitude,\n      loggerProvider: logger,\n    });\n\n    /* istanbul ignore next */\n    logger?.log(`${name} has been successfully added.`);\n  };\n\n  /* istanbul ignore next */\n  const execute: BrowserEnrichmentPlugin['execute'] = async (event) => {\n    return event;\n  };\n\n  const teardown = async () => {\n    subscription.unsubscribe();\n  };\n\n  return {\n    name,\n    type,\n    setup,\n    execute,\n    teardown,\n  };\n};\n"
  },
  {
    "path": "packages/plugin-network-capture-browser/src/track-network-event.ts",
    "content": "import {\n  BrowserClient,\n  NetworkRequestEvent,\n  NetworkCaptureRule,\n  NetworkTrackingOptions,\n  getGlobalScope,\n  isUrlMatchAllowlist,\n  SAFE_HEADERS,\n  ILogger,\n  IRequestWrapper,\n  Unsubscribable,\n} from '@amplitude/analytics-core';\nimport { AllWindowObservables, TimestampedEvent } from './network-capture-plugin';\nimport { AMPLITUDE_NETWORK_REQUEST_EVENT, IS_HEADER_CAPTURE_EXPERIMENTAL } from './constants';\nimport { BodyCaptureRule } from '@amplitude/analytics-core/lib/esm/types/network-tracking';\n\nconst DEFAULT_STATUS_CODE_RANGE = '500-599';\n\nfunction wildcardMatch(str: string, pattern: string) {\n  // Escape all regex special characters except for *\n  const escapedPattern = pattern.replace(/[-[\\]{}()+?.,\\\\^$|#\\s]/g, '\\\\$&');\n  // Replace * with .*\n  const regexPattern = '^' + escapedPattern.replace(/\\*/g, '.*') + '$';\n  const regex = new RegExp(regexPattern);\n  return regex.test(str);\n}\n\nfunction isStatusCodeInRange(statusCode: number, range: string) {\n  const ranges = range.split(',');\n  for (const r of ranges) {\n    const [start, end] = r.split('-').map(Number);\n    if (statusCode === start && end === undefined) {\n      return true;\n    }\n    if (statusCode >= start && statusCode <= end) {\n      return true;\n    }\n  }\n  return false;\n}\n\nfunction isCaptureRuleMatch(\n  rule: NetworkCaptureRule,\n  hostname: string,\n  status?: number,\n  url?: string,\n  method?: string,\n) {\n  // check if the host is in the allowed hosts\n  if (rule.hosts && !rule.hosts.find((host: string) => wildcardMatch(hostname, host))) {\n    return;\n  }\n\n  // check if the URL is in the allowed URL patterns\n  if (url && rule.urls && !isUrlMatchAllowlist(url, rule.urls)) {\n    return;\n  }\n\n  // check if the method is in the allowed methods\n  if (\n    method &&\n    rule.methods &&\n    !rule.methods.find(\n      (allowedMethod: string) => method.toLowerCase() === allowedMethod.toLowerCase() || allowedMethod === '*',\n    )\n  ) {\n    return;\n  }\n\n  // check if the status code is in the allowed range\n  if (status || status === 0) {\n    const statusCodeRange = rule.statusCodeRange || DEFAULT_STATUS_CODE_RANGE;\n    if (!isStatusCodeInRange(status, statusCodeRange)) {\n      return false;\n    }\n  }\n\n  return true;\n}\n\nfunction parseUrl(url: string | undefined) {\n  if (!url) {\n    return;\n  }\n  try {\n    /* istanbul ignore next */\n    const currentHref = getGlobalScope()?.location.href;\n    const urlObj = new URL(url, currentHref);\n    const query = urlObj.searchParams.toString();\n    const fragment = urlObj.hash.replace('#', '');\n    const href = urlObj.href;\n    const host = urlObj.host;\n    urlObj.hash = '';\n    urlObj.search = '';\n    const hrefWithoutQueryOrHash = urlObj.href;\n    return { query, fragment, href, hrefWithoutQueryOrHash, host };\n  } catch (e) {\n    /* istanbul ignore next */\n    return;\n  }\n}\n\nfunction isAmplitudeNetworkRequestEvent(host: string, requestWrapper: IRequestWrapper): boolean {\n  if (host.includes('amplitude.com')) {\n    try {\n      const body = requestWrapper.body;\n      if (typeof body !== 'string') {\n        return false;\n      }\n      const bodyObj = JSON.parse(body) as { events: any[] };\n      const { events } = bodyObj;\n      /* eslint-disable-next-line @typescript-eslint/no-unsafe-member-access */\n      if (events.find((event: any) => event.event_type === AMPLITUDE_NETWORK_REQUEST_EVENT)) {\n        return true;\n      }\n    } catch (e) {\n      // do nothing\n    }\n  }\n  return false;\n}\n\n/**\n * Takes a user provided header capture rule and returns a\n * HeaderCaptureRule object that sets proper default values.\n *\n * @param rule - The header capture rule to parse.\n * @returns A HeaderCaptureRule object.\n */\nexport function parseHeaderCaptureRule(rule: string[] | boolean | undefined | null): string[] | undefined {\n  if (typeof rule !== 'object' || rule === null) {\n    // if rule is truthy or undefined, return SAFE_HEADERS\n    if (rule) {\n      return [...SAFE_HEADERS];\n    } else if (rule === undefined) {\n      /* istanbul ignore next */\n      const res = IS_HEADER_CAPTURE_EXPERIMENTAL ? undefined : [...SAFE_HEADERS];\n      return res;\n    }\n    return;\n  }\n\n  // if the rule is defined but empty, return undefined\n  if (rule.length === 0) {\n    return;\n  }\n\n  return rule;\n}\n\nfunction isBodyCaptureRuleEmpty(rule: BodyCaptureRule) {\n  /* istanbul ignore next */\n  return !rule?.allowlist?.length && !rule?.blocklist?.length && !rule?.excludelist?.length;\n}\n\nexport function shouldTrackNetworkEvent(networkEvent: NetworkRequestEvent, options: NetworkTrackingOptions = {}) {\n  const urlObj = parseUrl(networkEvent.url);\n  /* istanbul ignore if */\n  if (!urlObj) {\n    // if the URL failed to parse, do not track the event\n    // this is a probably impossible case that would only happen if the URL is malformed\n    /* istanbul ignore next */\n    return false;\n  }\n  const { host } = urlObj;\n\n  // false if is amplitude request and not configured to track amplitude requests\n  if (\n    options.ignoreAmplitudeRequests !== false &&\n    (wildcardMatch(host, '*.amplitude.com') || wildcardMatch(host, 'amplitude.com'))\n  ) {\n    return false;\n  }\n\n  // false if the host is in the ignore list\n  if (options.ignoreHosts?.find((ignoreHost: string) => wildcardMatch(host, ignoreHost))) {\n    return false;\n  }\n\n  // false if the status code is not 500-599 and there are no captureRules\n  if (\n    !options.captureRules &&\n    networkEvent.status !== undefined &&\n    !isStatusCodeInRange(networkEvent.status, DEFAULT_STATUS_CODE_RANGE)\n  ) {\n    return false;\n  }\n\n  if (options.captureRules) {\n    // find the first capture rule, in reverse-order,\n    // that is a match (true) or a miss (false)\n    let isMatch: boolean | undefined;\n    [...options.captureRules].reverse().find((rule) => {\n      isMatch = isCaptureRuleMatch(rule, host, networkEvent.status, networkEvent.url, networkEvent.method);\n\n      if (isMatch) {\n        const responseHeadersRule = parseHeaderCaptureRule(rule.responseHeaders);\n        if (networkEvent.responseWrapper && responseHeadersRule) {\n          const responseHeaders = networkEvent.responseWrapper.headers(responseHeadersRule);\n          if (responseHeaders) {\n            networkEvent.responseHeaders = responseHeaders;\n          }\n        }\n\n        // if requestHeaders rule is specified, enrich the event with the request headers\n        const requestHeadersRule = parseHeaderCaptureRule(rule.requestHeaders);\n        if (networkEvent.requestWrapper && requestHeadersRule) {\n          const requestHeaders = networkEvent.requestWrapper.headers(requestHeadersRule);\n          if (requestHeaders) {\n            networkEvent.requestHeaders = requestHeaders;\n          }\n        }\n\n        // if responseBody rule is specified, enrich the event with the response body\n        if (networkEvent.responseWrapper && rule.responseBody && !isBodyCaptureRuleEmpty(rule.responseBody)) {\n          const excludelist = rule.responseBody.excludelist || rule.responseBody.blocklist;\n          networkEvent.responseBodyJson = networkEvent.responseWrapper.json(rule.responseBody.allowlist, excludelist);\n        }\n\n        // if requestBody rule is specified, enrich the event with the request body\n        if (networkEvent.requestWrapper && rule.requestBody && !isBodyCaptureRuleEmpty(rule.requestBody)) {\n          const excludelist = rule.requestBody.excludelist || rule.requestBody.blocklist;\n          networkEvent.requestBodyJson = networkEvent.requestWrapper.json(rule.requestBody.allowlist, excludelist);\n        }\n      }\n\n      return isMatch !== undefined;\n    });\n\n    // if we found a miss (false) or no match (undefined),\n    // then do not track the event\n    if (!isMatch) {\n      return false;\n    }\n  }\n\n  // skip Amplitude network requests to \"[Amplitude] Network Request\" to avoid infinite loop\n  if (networkEvent.requestWrapper && isAmplitudeNetworkRequestEvent(host, networkEvent.requestWrapper)) {\n    return false;\n  }\n\n  return true;\n}\n\nexport type NetworkAnalyticsEvent = {\n  ['[Amplitude] URL']: string;\n  ['[Amplitude] URL Query']?: string;\n  ['[Amplitude] URL Fragment']?: string;\n  ['[Amplitude] Request Method']: string;\n  ['[Amplitude] Status Code']?: number;\n  ['[Amplitude] Start Time']?: number; // unix timestamp\n  ['[Amplitude] Completion Time']?: number; // unix timestamp\n  ['[Amplitude] Duration']?: number; // completionTime - startTime (millis)\n  ['[Amplitude] Request Body Size']?: number;\n  ['[Amplitude] Request Headers']?: Record<string, string>;\n  ['[Amplitude] Request Body']?: string;\n  ['[Amplitude] Response Body Size']?: number;\n  ['[Amplitude] Response Headers']?: Record<string, string>;\n  ['[Amplitude] Response Body']?: string;\n  ['[Amplitude] Request Type']?: 'xhr' | 'fetch';\n};\n\nexport async function logNetworkAnalyticsEvent(\n  networkAnalyticsEvent: NetworkAnalyticsEvent,\n  request: NetworkRequestEvent,\n  amplitude: BrowserClient,\n  loggerProvider?: ILogger,\n) {\n  if (request.requestBodyJson || request.responseBodyJson) {\n    const [requestBody, responseBody] = await Promise.all([request.requestBodyJson, request.responseBodyJson]);\n    if (requestBody) {\n      try {\n        networkAnalyticsEvent['[Amplitude] Request Body'] = JSON.stringify(requestBody);\n      } catch (e) {\n        /* istanbul ignore next */\n        loggerProvider?.debug('Failed to stringify request body', e);\n      }\n    }\n    if (responseBody) {\n      try {\n        networkAnalyticsEvent['[Amplitude] Response Body'] = JSON.stringify(responseBody);\n      } catch (e) {\n        /* istanbul ignore next */\n        loggerProvider?.debug('Failed to stringify response body');\n      }\n    }\n  }\n  /* istanbul ignore next */\n  amplitude?.track(AMPLITUDE_NETWORK_REQUEST_EVENT, networkAnalyticsEvent);\n}\n\nexport function trackNetworkEvents({\n  allObservables,\n  networkTrackingOptions,\n  amplitude,\n  loggerProvider,\n}: {\n  allObservables: AllWindowObservables;\n  networkTrackingOptions: NetworkTrackingOptions;\n  amplitude: BrowserClient;\n  loggerProvider?: ILogger;\n}): Unsubscribable {\n  const { networkObservable } = allObservables;\n\n  const filteredNetworkObservable = networkObservable.filter((event: TimestampedEvent<NetworkRequestEvent>) => {\n    // Only track network events that should be tracked\n    return shouldTrackNetworkEvent(event.event as NetworkRequestEvent, networkTrackingOptions);\n  });\n\n  return filteredNetworkObservable.subscribe((networkEvent) => {\n    const request = networkEvent.event;\n\n    // convert to NetworkAnalyticsEvent\n    const urlObj = parseUrl(request.url);\n    /* istanbul ignore if */\n    if (!urlObj) {\n      // if the URL failed to parse, do not track the event\n      // this is a very unlikely case, because URL() shouldn't throw an exception\n      // when the URL is a valid URL\n      /* istanbul ignore next */\n      return;\n    }\n\n    const responseBodySize = request.responseWrapper?.bodySize;\n    /* istanbul ignore next */\n    const requestBodySize = request.requestWrapper?.bodySize;\n\n    const networkAnalyticsEvent: NetworkAnalyticsEvent = {\n      ['[Amplitude] URL']: urlObj.hrefWithoutQueryOrHash,\n      ['[Amplitude] URL Query']: urlObj.query,\n      ['[Amplitude] URL Fragment']: urlObj.fragment,\n      ['[Amplitude] Request Method']: request.method,\n      ['[Amplitude] Status Code']: request.status,\n      ['[Amplitude] Start Time']: request.startTime,\n      ['[Amplitude] Completion Time']: request.endTime,\n      ['[Amplitude] Duration']: request.duration,\n      ['[Amplitude] Request Body Size']: requestBodySize,\n      ['[Amplitude] Response Body Size']: responseBodySize,\n      ['[Amplitude] Request Type']: request.type,\n      ['[Amplitude] Request Headers']: request.requestHeaders,\n      ['[Amplitude] Response Headers']: request.responseHeaders,\n    };\n\n    // fire-and-forget promise that tracks the event\n    void logNetworkAnalyticsEvent(networkAnalyticsEvent, request, amplitude, loggerProvider);\n  });\n}\n"
  },
  {
    "path": "packages/plugin-network-capture-browser/src/version.ts",
    "content": "export const VERSION = '1.10.0';\n"
  },
  {
    "path": "packages/plugin-network-capture-browser/test/autocapture-plugin/track-network-event.test.ts",
    "content": "// make a test class that implements NetworkRequestEvent\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-unsafe-argument */\nimport {\n  BrowserClient,\n  BrowserConfig,\n  CookieStorage,\n  FetchTransport,\n  JsonObject,\n  Logger,\n  LogLevel,\n  NetworkEventCallback,\n  networkObserver,\n  NetworkRequestEvent,\n  NetworkTrackingOptions,\n  SAFE_HEADERS,\n} from '@amplitude/analytics-core';\nimport * as AnalyticsCore from '@amplitude/analytics-core';\nimport {\n  logNetworkAnalyticsEvent,\n  NetworkAnalyticsEvent,\n  parseHeaderCaptureRule,\n  shouldTrackNetworkEvent,\n} from '../../src/track-network-event';\nimport { BrowserEnrichmentPlugin, networkCapturePlugin } from '../../src/network-capture-plugin';\nimport { AMPLITUDE_NETWORK_REQUEST_EVENT } from '../../src/constants';\nimport { VERSION } from '../../src/version';\nimport { createMockBrowserClient } from '../mock-browser-client';\nimport * as streams from 'stream/web';\nimport { TextEncoder } from 'util';\ntype PartialGlobal = Pick<typeof globalThis, 'fetch'>;\n\ntype ResourceType = 'fetch' | 'xhr';\n\nclass MockNetworkRequestEvent implements NetworkRequestEvent {\n  public responseHeaders?: Record<string, string>;\n  public requestHeaders?: Record<string, string>;\n  public requestBodyJson?: Promise<JsonObject | null>;\n  public responseBodyJson?: Promise<JsonObject | null>;\n\n  constructor(\n    public url: string = 'https://example.com',\n    public type: ResourceType = 'fetch',\n    public method: string = 'GET',\n    public status: number = 200,\n    public duration: number = 100,\n    public responseWrapper = {\n      bodySize: 100,\n      headers() {\n        return { 'Content-Type': 'application/json' };\n      },\n      async json() {\n        return { message: 'hello' };\n      },\n    } as any,\n    public requestWrapper = {\n      bodySize: 100,\n      headers() {\n        return { 'Content-Type': 'application/json' };\n      },\n      async json() {\n        return { message: 'hello' };\n      },\n    } as any,\n    public startTime: number = Date.now(),\n    public timestamp: number = Date.now(),\n    public endTime: number = Date.now() + 100,\n  ) {\n    this.type = 'fetch';\n  }\n\n  toSerializable(): Record<string, any> {\n    return {\n      ...this,\n      responseBodySize: this.responseWrapper.bodySize,\n      requestBodySize: this.requestWrapper.bodySize,\n      requestHeaders: this.requestWrapper.headers,\n      responseHeaders: this.responseWrapper.headers,\n    };\n  }\n}\n\nconst baseBrowserConfig: BrowserConfig = {\n  apiKey: '<FAKE_API_KEY>',\n  flushIntervalMillis: 0,\n  flushMaxRetries: 0,\n  flushQueueSize: 0,\n  logLevel: LogLevel.None,\n  loggerProvider: new Logger(),\n  offline: false,\n  optOut: false,\n  serverUrl: undefined,\n  transportProvider: new FetchTransport(),\n  useBatch: false,\n  cookieOptions: {\n    domain: '.amplitude.com',\n    expiration: 365,\n    sameSite: 'Lax',\n    secure: false,\n    upgrade: true,\n  },\n  cookieStorage: new CookieStorage(),\n  sessionTimeout: 30 * 60 * 1000,\n  trackingOptions: {\n    ipAddress: true,\n    language: true,\n    platform: true,\n  },\n};\n\ndescribe('track-network-event', () => {\n  let networkEvent: MockNetworkRequestEvent;\n  let localConfig: BrowserConfig;\n  beforeEach(() => {\n    localConfig = {\n      ...baseBrowserConfig,\n      autocapture: {\n        networkTracking: true,\n      },\n      networkTrackingOptions: {},\n    } as BrowserConfig;\n    networkEvent = new MockNetworkRequestEvent();\n  });\n\n  describe('parseHeaderCaptureRule()', () => {\n    describe('returns SAFE_HEADERS when headers', () => {\n      test('is \"true\"', () => {\n        expect(parseHeaderCaptureRule(true)).toEqual([...SAFE_HEADERS]);\n      });\n    });\n\n    describe('returns undefined when', () => {\n      test('allowlist is \"empty\"', () => {\n        expect(parseHeaderCaptureRule([])).toBeUndefined();\n      });\n\n      test('allowlist is \"undefined\"', () => {\n        expect(parseHeaderCaptureRule(undefined)).toEqual(undefined);\n      });\n\n      test('allowlist is \"false\"', () => {\n        expect(parseHeaderCaptureRule(false)).toBeUndefined();\n      });\n    });\n\n    test('should return undefined when rule is null', () => {\n      const result = parseHeaderCaptureRule(null);\n      expect(result).toBeUndefined();\n    });\n\n    test('should return undefined when rule is false', () => {\n      const result = parseHeaderCaptureRule(false);\n      expect(result).toBeUndefined();\n    });\n  });\n\n  describe('trackNetworkEvent()', () => {\n    let client: BrowserClient;\n    let trackSpy: jest.SpyInstance;\n    let eventCallbacks: any[] = [];\n    const subscribe = jest.fn((cb: NetworkEventCallback) => {\n      eventCallbacks.push(cb);\n      return () => {\n        eventCallbacks = [];\n      };\n    });\n\n    let plugin: BrowserEnrichmentPlugin;\n    let amendedGlobalScope: PartialGlobal;\n    let originalFetchMock: jest.Mock;\n\n    beforeEach(async () => {\n      originalFetchMock = jest.fn();\n      amendedGlobalScope = {\n        fetch: originalFetchMock,\n        TextEncoder,\n        ReadableStream: streams,\n      } as PartialGlobal;\n      // keep reference to original getGlobalScope\n      const originalGetGlobalScope = AnalyticsCore.getGlobalScope;\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockImplementation((): any => {\n        return {\n          ...originalGetGlobalScope(),\n          ...amendedGlobalScope,\n        };\n      });\n\n      client = createMockBrowserClient();\n      trackSpy = jest.spyOn(client, 'track');\n      client.init('<FAKE_API_KEY>', undefined, localConfig);\n      jest.spyOn(networkObserver, 'subscribe').mockImplementation(subscribe);\n      plugin = networkCapturePlugin();\n      await plugin.setup?.(localConfig, client);\n    });\n\n    afterEach(async () => {\n      await plugin?.teardown?.();\n    });\n\n    test('should track a network request event with status=500', async () => {\n      const responseHeaders = new Headers();\n      responseHeaders.set('content-length', '100');\n      eventCallbacks.forEach((cb: NetworkEventCallback) => {\n        cb.callback({\n          url: 'https://example.com/track?hello=world#hash',\n          type: 'fetch',\n          method: 'POST',\n          status: 500,\n          duration: 100,\n          requestWrapper: {\n            bodySize: 10,\n            headers: { 'content-type': 'application/json' },\n          } as any,\n          responseWrapper: {\n            bodySize: 100,\n            headers: { 'content-length': '100' },\n          } as any,\n          startTime: Date.now(),\n          timestamp: Date.now(),\n          endTime: Date.now() + 100,\n          toSerializable: () => networkEvent.toSerializable(),\n        });\n      });\n      const networkEventCall = trackSpy.mock.calls.find((call) => {\n        return call[0] === AMPLITUDE_NETWORK_REQUEST_EVENT;\n      });\n      const [eventName, eventProperties] = networkEventCall;\n      expect(eventName).toBe(AMPLITUDE_NETWORK_REQUEST_EVENT);\n      expect(eventProperties).toEqual({\n        '[Amplitude] URL': 'https://example.com/track',\n        '[Amplitude] URL Query': 'hello=world',\n        '[Amplitude] URL Fragment': 'hash',\n        '[Amplitude] Request Method': 'POST',\n        '[Amplitude] Status Code': 500,\n        '[Amplitude] Start Time': expect.any(Number),\n        '[Amplitude] Completion Time': expect.any(Number),\n        '[Amplitude] Duration': expect.any(Number),\n        '[Amplitude] Request Body Size': 10,\n        '[Amplitude] Response Body Size': 100,\n        '[Amplitude] Request Type': 'fetch',\n      });\n    });\n\n    test('should track a network request event with status=500 and network request missing attributes', async () => {\n      eventCallbacks.forEach((cb: NetworkEventCallback) => {\n        cb.callback({\n          url: 'https://example.com/track?hello=world#hash',\n          type: 'xhr',\n          method: 'POST',\n          status: 500,\n          duration: 100,\n          requestWrapper: {\n            bodySize: undefined,\n            headers: { 'content-type': 'application/json' },\n          } as any,\n          timestamp: Date.now(),\n          startTime: Date.now(),\n          endTime: Date.now() + 100,\n          toSerializable: () => networkEvent.toSerializable(),\n        });\n      });\n      const networkEventCall = trackSpy.mock.calls.find((call) => {\n        return call[0] === AMPLITUDE_NETWORK_REQUEST_EVENT;\n      });\n      const [eventName, eventProperties] = networkEventCall;\n      expect(eventName).toBe(AMPLITUDE_NETWORK_REQUEST_EVENT);\n      expect(eventProperties).toEqual({\n        '[Amplitude] URL': 'https://example.com/track',\n        '[Amplitude] URL Query': 'hello=world',\n        '[Amplitude] URL Fragment': 'hash',\n        '[Amplitude] Request Method': 'POST',\n        '[Amplitude] Status Code': 500,\n        '[Amplitude] Start Time': expect.any(Number),\n        '[Amplitude] Completion Time': expect.any(Number),\n        '[Amplitude] Duration': expect.any(Number),\n        '[Amplitude] Request Body Size': undefined,\n        '[Amplitude] Response Body Size': undefined,\n        '[Amplitude] Request Type': 'xhr',\n      });\n    });\n\n    test('should not track a network request event with status=200', async () => {\n      eventCallbacks.forEach((cb: NetworkEventCallback) => {\n        cb.callback({\n          url: 'https://example.com/track?hello=world#hash',\n          type: 'fetch',\n          method: 'POST',\n          status: 200,\n          duration: 100,\n          requestWrapper: {\n            bodySize: 10,\n            headers: { 'content-type': 'application/json' },\n          } as any,\n          startTime: Date.now(),\n          timestamp: Date.now(),\n          endTime: Date.now() + 100,\n          toSerializable: () => networkEvent.toSerializable(),\n        });\n      });\n      const networkEventCall = trackSpy.mock.calls.find((call) => {\n        return call[0] === AMPLITUDE_NETWORK_REQUEST_EVENT;\n      });\n      expect(networkEventCall).toBeUndefined();\n    });\n\n    test('should not track event if request event is missing URL', () => {\n      eventCallbacks.forEach((cb: NetworkEventCallback) => {\n        const event = {\n          type: 'fetch',\n          method: 'POST',\n          status: 500,\n          duration: 100,\n          requestWrapper: {\n            bodySize: 10,\n            headers: { 'content-type': 'application/json' },\n          } as any,\n          startTime: Date.now(),\n          timestamp: Date.now(),\n          endTime: Date.now() + 100,\n        } as NetworkRequestEvent;\n        cb.callback({\n          ...event,\n          toSerializable: () => event,\n        });\n      });\n      const networkEventCall = trackSpy.mock.calls.find((call) => {\n        return call[0] === AMPLITUDE_NETWORK_REQUEST_EVENT;\n      });\n      expect(networkEventCall).toBeUndefined();\n    });\n  });\n\n  describe('shouldTrackNetworkEvent returns false when', () => {\n    test('network request body contains \"[Amplitude] Network Request\"', () => {\n      networkEvent.url = 'https://api2.amplitude.com/track';\n      const body =\n        '{\"api_key\":\"*****\",\"events\":[{\"user_id\":\"****\",\"device_id\":\"a1c372c9-e8bb-4be2-9865-1ba97787d485\",\"session_id\":1747961537096,\"time\":1747963021841,\"platform\":\"Web\",\"language\":\"en-US\",\"ip\":\"$remote\",\"insert_id\":\"22c2c614-ca7c-4668-9ad4-1576f3372bc0\",\"event_type\":\"[Amplitude] Page Viewed\",\"event_properties\":{\"referrer\":\"http://localhost:5173/browser-sdk/fetch.html\",\"referring_domain\":\"localhost:5173\",\"[Amplitude] Page Domain\":\"localhost\",\"[Amplitude] Page Location\":\"http://localhost:5173/browser-sdk/fetch.html\",\"[Amplitude] Page Path\":\"/browser-sdk/fetch.html\",\"[Amplitude] Page Title\":\"Fetch & XHR Network Tracking Test\",\"[Amplitude] Page URL\":\"http://localhost:5173/browser-sdk/fetch.html\",\"[Amplitude] Page Counter\":24},\"event_id\":14683,\"library\":\"amplitude-ts/2.17.6\",\"user_agent\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36\"},{\"user_id\":\"daniel.graham.dev\",\"device_id\":\"a1c372c9-e8bb-4be2-9865-1ba97787d485\",\"session_id\":1747961537096,\"time\":1747963022828,\"platform\":\"Web\",\"language\":\"en-US\",\"ip\":\"$remote\",\"insert_id\":\"d5c71b76-22d5-4bbf-9b44-79a8b315a47f\",\"event_type\":\"[Amplitude] Network Request\",\"event_properties\":{\"[Amplitude] URL\":\"https://httpstat.us/200\",\"[Amplitude] URL Query\":\"\",\"[Amplitude] URL Fragment\":\"\",\"[Amplitude] Request Method\":\"POST\",\"[Amplitude] Status Code\":0,\"[Amplitude] Start Time\":1747963022814,\"[Amplitude] Completion Time\":1747963022825,\"[Amplitude] Duration\":11,\"[Amplitude] Request Body Size\":28,\"[Amplitude] Request Type\":\"fetch\"},\"event_id\":14684,\"library\":\"amplitude-ts/2.17.6\",\"user_agent\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36\"}],\"options\":{},\"client_upload_time\":\"2025-05-23T01:17:02.843Z\",\"request_metadata\":{\"sdk\":{\"metrics\":{\"histogram\":{\"remote_config_fetch_time_API_success\":6}}}}}';\n      networkEvent.requestWrapper.body = body;\n      const networkTracking = {\n        ignoreAmplitudeRequests: false,\n        captureRules: [{ hosts: ['*'], statusCodeRange: '200-299' }],\n      };\n      const result = shouldTrackNetworkEvent(networkEvent, networkTracking);\n      expect(result).toBe(false);\n    });\n\n    test('status code is empty', () => {\n      const networkEvent = new MockNetworkRequestEvent(\n        'fetch',\n        undefined,\n        'POST',\n        0,\n        0,\n        'https://example.com/track',\n        // leave status empty\n      );\n      const result = shouldTrackNetworkEvent(\n        networkEvent,\n        localConfig.networkTrackingOptions as NetworkTrackingOptions,\n      );\n      expect(result).toBe(false);\n    });\n\n    test('domain is amplitude.com', () => {\n      networkEvent.url = 'https://api.amplitude.com/track';\n      expect(shouldTrackNetworkEvent(networkEvent)).toBe(false);\n    });\n\n    test('domain is in ignoreHosts', () => {\n      localConfig.networkTrackingOptions = { ignoreHosts: ['example.com'] };\n      networkEvent.url = 'https://example.com/track';\n      expect(shouldTrackNetworkEvent(networkEvent, localConfig.networkTrackingOptions)).toBe(false);\n    });\n\n    test('domain matches a wildcard in ignoreHosts', () => {\n      localConfig.networkTrackingOptions = { ignoreHosts: ['*.example.com', 'dummy.url'] };\n      networkEvent.url = 'https://sub.example.com/track';\n      const result = shouldTrackNetworkEvent(networkEvent, localConfig.networkTrackingOptions);\n      expect(result).toBe(false);\n    });\n\n    test('host is not in one of the captureRules', () => {\n      localConfig.networkTrackingOptions = {\n        captureRules: [\n          {\n            hosts: ['example.com'],\n          },\n        ],\n      };\n      networkEvent.url = 'https://otherexample.com/apicall';\n      const result = shouldTrackNetworkEvent(networkEvent, localConfig.networkTrackingOptions);\n      expect(result).toBe(false);\n    });\n\n    test('status code is 403 and 400 is in the forbidden status codes', () => {\n      localConfig.networkTrackingOptions = {\n        captureRules: [\n          {\n            hosts: ['example.com'],\n            statusCodeRange: '404-599',\n          },\n        ],\n      };\n      networkEvent.url = 'https://example.com/track';\n      networkEvent.status = 403;\n      const result = shouldTrackNetworkEvent(networkEvent, localConfig.networkTrackingOptions);\n      expect(result).toBe(false);\n    });\n\n    test('status code is 400 and no status code range is defined', () => {\n      localConfig.networkTrackingOptions = {\n        captureRules: [\n          {\n            hosts: ['example.com'],\n          },\n        ],\n      };\n      networkEvent.url = 'https://example.com/track';\n      networkEvent.status = 400;\n      const result = shouldTrackNetworkEvent(networkEvent, localConfig.networkTrackingOptions);\n      expect(result).toBe(false);\n    });\n\n    test('status code is 200 and no captureRules are defined', () => {\n      networkEvent.url = 'https://notamplitude.com/track';\n      networkEvent.status = 200;\n      const result = shouldTrackNetworkEvent(\n        networkEvent,\n        localConfig.networkTrackingOptions as NetworkTrackingOptions,\n      );\n      expect(result).toBe(false);\n    });\n\n    test('status code is 0 and no captureRules are defined', () => {\n      networkEvent.url = 'https://notamplitude.com/track';\n      networkEvent.status = 0;\n      const result = shouldTrackNetworkEvent(\n        networkEvent,\n        localConfig.networkTrackingOptions as NetworkTrackingOptions,\n      );\n      expect(result).toBe(false);\n    });\n\n    test('host matches in captureRules but status code is not in the range', () => {\n      localConfig.networkTrackingOptions = {\n        captureRules: [\n          {\n            hosts: ['*'],\n            statusCodeRange: '200-299',\n          },\n          {\n            hosts: ['example.com'],\n            statusCodeRange: '500-599',\n          },\n        ],\n      };\n      networkEvent.url = 'https://example.com/track';\n      networkEvent.status = 200;\n      const result = shouldTrackNetworkEvent(networkEvent, localConfig.networkTrackingOptions);\n      expect(result).toBe(false);\n    });\n\n    test('url does not match any of the captureRule.urls', () => {\n      const networkTracking = {\n        captureRules: [\n          {\n            hosts: ['*'],\n            urls: [/login/],\n            statusCodeRange: '500-599',\n          },\n        ],\n      };\n      networkEvent.status = 500;\n      networkEvent.url = 'https://example.com/logout';\n      const result = shouldTrackNetworkEvent(networkEvent, networkTracking);\n      expect(result).toBe(false);\n    });\n\n    test('method does not match any of the methods in captureRules', () => {\n      const networkTracking = {\n        captureRules: [\n          {\n            hosts: ['*'],\n            methods: ['POST', 'PUT'],\n            statusCodeRange: '500-599',\n          },\n        ],\n      };\n      networkEvent.status = 500;\n      networkEvent.method = 'GET';\n      networkEvent.url = 'https://example.com/api';\n      const result = shouldTrackNetworkEvent(networkEvent, networkTracking);\n      expect(result).toBe(false);\n    });\n  });\n\n  describe('shouldTrackNetworkEvent returns true when', () => {\n    const defaultHref = window.location.href;\n\n    beforeAll(() => {\n      window.location.href = 'https://example.com';\n    });\n\n    afterAll(() => {\n      window.location.href = defaultHref;\n    });\n\n    test('url omits baseURL and window.location.href is not ignored', () => {\n      networkEvent.url = '/some/url';\n      networkEvent.status = 500;\n      const result = shouldTrackNetworkEvent(networkEvent, localConfig.networkTrackingOptions);\n      expect(result).toBe(true);\n    });\n\n    test('url is a relative URL and location.href is not ignored', () => {\n      networkEvent.url = 'relativeurl';\n      networkEvent.status = 500;\n      const result = shouldTrackNetworkEvent(networkEvent, localConfig.networkTrackingOptions);\n      expect(result).toBe(true);\n    });\n\n    test('domain is api.amplitude.com and ignoreAmplitudeRequests is false', () => {\n      localConfig.networkTrackingOptions = { ignoreAmplitudeRequests: false };\n      networkEvent.url = 'https://api.amplitude.com/track';\n      networkEvent.status = 500;\n      const result = shouldTrackNetworkEvent(networkEvent, localConfig.networkTrackingOptions);\n      expect(result).toBe(true);\n    });\n\n    test('domain is amplitude.com and ignoreAmplitudeRequests is false', () => {\n      localConfig.networkTrackingOptions = { ignoreAmplitudeRequests: false };\n      networkEvent.url = 'https://amplitude.com/track';\n      networkEvent.status = 500;\n      const result = shouldTrackNetworkEvent(networkEvent, localConfig.networkTrackingOptions);\n      expect(result).toBe(true);\n    });\n\n    test('status code is 500', () => {\n      networkEvent.url = 'https://notamplitude.com/track';\n      networkEvent.status = 500;\n      const result = shouldTrackNetworkEvent(\n        networkEvent,\n        localConfig.networkTrackingOptions as NetworkTrackingOptions,\n      );\n      expect(result).toBe(true);\n    });\n\n    test('status code is 0', () => {\n      networkEvent.url = 'https://notamplitude.com/track';\n      networkEvent.status = 0;\n      localConfig.networkTrackingOptions = {\n        captureRules: [\n          {\n            hosts: ['notamplitude.com'],\n            statusCodeRange: '0,400-499',\n          },\n        ],\n      };\n      const result = shouldTrackNetworkEvent(networkEvent, localConfig.networkTrackingOptions);\n      expect(result).toBe(true);\n    });\n\n    test('status code is 200 and 200 is allowed in captureRules', () => {\n      localConfig.networkTrackingOptions = {\n        captureRules: [\n          {\n            hosts: ['example.com'],\n            statusCodeRange: '200',\n          },\n        ],\n      };\n      networkEvent.url = 'https://example.com/track';\n      networkEvent.status = 200;\n      const result = shouldTrackNetworkEvent(networkEvent, localConfig.networkTrackingOptions);\n      expect(result).toBe(true);\n    });\n\n    test('status code is 403 and 400 is within the statusCodeRange', () => {\n      localConfig.networkTrackingOptions = {\n        captureRules: [\n          {\n            hosts: ['example.com'],\n            statusCodeRange: '402-599',\n          },\n        ],\n      };\n      networkEvent.url = 'https://example.com/track';\n      networkEvent.status = 403;\n      const result = shouldTrackNetworkEvent(networkEvent, localConfig.networkTrackingOptions);\n      expect(result).toBe(true);\n    });\n\n    test('host does not match with second capture rule but matches with first', () => {\n      localConfig.networkTrackingOptions = {\n        captureRules: [\n          {\n            hosts: ['*.example.com'],\n            statusCodeRange: '400-499',\n          },\n          {\n            hosts: ['otherexample.com'],\n            statusCodeRange: '400-599',\n          },\n        ],\n      };\n      networkEvent.url = 'https://some.example.com/track';\n      networkEvent.status = 403;\n      const result = shouldTrackNetworkEvent(networkEvent, localConfig.networkTrackingOptions);\n      expect(result).toBe(true);\n    });\n\n    test('url matches one of the urls in captureRules', () => {\n      const networkTracking = {\n        captureRules: [\n          {\n            hosts: ['*'],\n            urls: [/login/],\n            statusCodeRange: '500-599',\n          },\n        ],\n      };\n      networkEvent.status = 500;\n      networkEvent.url = 'https://example.com/login';\n      const result = shouldTrackNetworkEvent(networkEvent, networkTracking);\n      expect(result).toBe(true);\n    });\n\n    test('method matches one of the methods in captureRules', () => {\n      const networkTracking = {\n        captureRules: [\n          {\n            hosts: ['*'],\n            methods: ['POST', 'PUT'],\n            statusCodeRange: '500-599',\n          },\n        ],\n      };\n      networkEvent.status = 500;\n      networkEvent.method = 'POST';\n      networkEvent.url = 'https://example.com/api';\n      const result = shouldTrackNetworkEvent(networkEvent, networkTracking);\n      expect(result).toBe(true);\n    });\n\n    test('captureRules.method is a wildcard', () => {\n      const networkTracking = {\n        captureRules: [\n          {\n            hosts: ['*'],\n            methods: ['*'],\n            statusCodeRange: '500-599',\n          },\n        ],\n      };\n      networkEvent.status = 500;\n      networkEvent.method = 'REQUEST';\n      networkEvent.url = 'https://example.com/api';\n      const result = shouldTrackNetworkEvent(networkEvent, networkTracking);\n      expect(result).toBe(true);\n    });\n  });\n\n  describe('shouldTrackNetworkEvent with header enrichment', () => {\n    beforeEach(() => {\n      networkEvent = new MockNetworkRequestEvent();\n    });\n\n    test('should call headers with allowlist and should enrich network event', () => {\n      const networkTracking = {\n        captureRules: [\n          {\n            hosts: ['example.com'],\n            statusCodeRange: '500-599',\n            responseHeaders: ['content-type'],\n            requestHeaders: ['content-length'],\n          },\n        ],\n      };\n      networkEvent.status = 500;\n      const responseHeadersSpy = jest.spyOn(networkEvent.responseWrapper, 'headers');\n      const requestHeadersSpy = jest.spyOn(networkEvent.requestWrapper, 'headers');\n\n      shouldTrackNetworkEvent(networkEvent, networkTracking);\n\n      expect(responseHeadersSpy).toHaveBeenCalledWith(['content-type']);\n      expect(requestHeadersSpy).toHaveBeenCalledWith(['content-length']);\n      expect(networkEvent.responseHeaders).toBeDefined();\n      expect(networkEvent.requestHeaders).toBeDefined();\n    });\n\n    test('should not enrich network event if responseHeaders and requestHeaders are false', () => {\n      const networkTracking = {\n        captureRules: [\n          {\n            hosts: ['example.com'],\n            statusCodeRange: '500-599',\n            responseHeaders: false,\n            requestHeaders: false,\n          },\n        ],\n      };\n      networkEvent.status = 500;\n      const responseHeadersSpy = jest.spyOn(networkEvent.responseWrapper, 'headers');\n      const requestHeadersSpy = jest.spyOn(networkEvent.requestWrapper, 'headers');\n      const result = shouldTrackNetworkEvent(networkEvent, networkTracking);\n      expect(result).toBe(true);\n      expect(networkEvent.responseHeaders).toBeUndefined();\n      expect(networkEvent.requestHeaders).toBeUndefined();\n      expect(responseHeadersSpy).not.toHaveBeenCalled();\n      expect(requestHeadersSpy).not.toHaveBeenCalled();\n    });\n\n    test('should enrich network event if responseHeaders and requestHeaders are true', () => {\n      const networkTracking = {\n        captureRules: [\n          {\n            hosts: ['example.com'],\n            statusCodeRange: '500-599',\n            responseHeaders: true,\n            requestHeaders: true,\n          },\n        ],\n      };\n      networkEvent.status = 500;\n      const responseHeadersSpy = jest.spyOn(networkEvent.responseWrapper, 'headers');\n      const requestHeadersSpy = jest.spyOn(networkEvent.requestWrapper, 'headers');\n      const result = shouldTrackNetworkEvent(networkEvent, networkTracking);\n      expect(result).toBe(true);\n      expect(networkEvent.responseHeaders).toBeDefined();\n      expect(networkEvent.requestHeaders).toBeDefined();\n      expect(responseHeadersSpy).toHaveBeenCalled();\n      expect(requestHeadersSpy).toHaveBeenCalled();\n    });\n  });\n\n  describe('shouldTrackNetworkEvent with body enrichment', () => {\n    beforeEach(() => {\n      networkEvent = new MockNetworkRequestEvent();\n    });\n\n    test('should enrich network event with request and response body', () => {\n      const networkTracking = {\n        captureRules: [\n          {\n            hosts: ['example.com'],\n            statusCodeRange: '500-599',\n            responseBody: { allowlist: ['*'] },\n            requestBody: { allowlist: ['*'] },\n          },\n        ],\n      };\n      networkEvent.status = 500;\n      networkEvent.url = 'https://example.com/track';\n      const result = shouldTrackNetworkEvent(networkEvent, networkTracking);\n      expect(result).toBe(true);\n      expect(networkEvent.requestBodyJson).toBeDefined();\n      expect(networkEvent.responseBodyJson).toBeDefined();\n    });\n\n    test.each(['excludelist', 'blocklist'] as const)(\n      'should pass allowlist and %s to request and response json()',\n      (excludelist) => {\n        const responseJsonSpy = jest.spyOn(networkEvent.responseWrapper, 'json');\n        const requestJsonSpy = jest.spyOn(networkEvent.requestWrapper, 'json');\n        const allow = ['**'];\n        const exclude = ['/secret'];\n        const networkTracking = {\n          captureRules: [\n            {\n              hosts: ['example.com'],\n              statusCodeRange: '500-599',\n              responseBody: { allowlist: allow, [excludelist]: exclude },\n              requestBody: { allowlist: allow, [excludelist]: exclude },\n            },\n          ],\n        };\n        networkEvent.status = 500;\n        networkEvent.url = 'https://example.com/track';\n        shouldTrackNetworkEvent(networkEvent, networkTracking);\n        expect(responseJsonSpy).toHaveBeenCalledWith(allow, exclude);\n        expect(requestJsonSpy).toHaveBeenCalledWith(allow, exclude);\n      },\n    );\n\n    test('should prioritize excludelist over blocklist', () => {\n      const responseJsonSpy = jest.spyOn(networkEvent.responseWrapper, 'json');\n      const requestJsonSpy = jest.spyOn(networkEvent.requestWrapper, 'json');\n      const allow = ['**'];\n      const exclude = ['/secret'];\n      const networkTracking = {\n        captureRules: [\n          {\n            hosts: ['example.com'],\n            statusCodeRange: '500-599',\n            responseBody: { allowlist: allow, excludelist: exclude, blocklist: ['/ignore-me'] },\n            requestBody: { allowlist: allow, excludelist: exclude, blocklist: ['/ignore-me'] },\n          },\n        ],\n      };\n      networkEvent.status = 500;\n      networkEvent.url = 'https://example.com/track';\n      shouldTrackNetworkEvent(networkEvent, networkTracking);\n      expect(responseJsonSpy).toHaveBeenCalledWith(allow, exclude);\n      expect(requestJsonSpy).toHaveBeenCalledWith(allow, exclude);\n    });\n\n    test('should use blocklist if excludelist is undefined', () => {\n      const responseJsonSpy = jest.spyOn(networkEvent.responseWrapper, 'json');\n      const requestJsonSpy = jest.spyOn(networkEvent.requestWrapper, 'json');\n      const allow = ['**'];\n      const block = ['/ignore-me'];\n      const networkTracking = {\n        captureRules: [\n          {\n            hosts: ['example.com'],\n            statusCodeRange: '500-599',\n            responseBody: { allowlist: allow, excludelist: undefined, blocklist: block },\n            requestBody: { allowlist: allow, excludelist: undefined, blocklist: block },\n          },\n        ],\n      };\n      networkEvent.status = 500;\n      networkEvent.url = 'https://example.com/track';\n      shouldTrackNetworkEvent(networkEvent, networkTracking);\n      expect(responseJsonSpy).toHaveBeenCalledWith(allow, block);\n      expect(requestJsonSpy).toHaveBeenCalledWith(allow, block);\n    });\n  });\n\n  describe('logNetworkAnalyticsEvent', () => {\n    test('should log network analytics event with request and response body', async () => {\n      const networkAnalyticsEvent: NetworkAnalyticsEvent = {\n        '[Amplitude] URL': 'https://example.com/track',\n        '[Amplitude] URL Query': 'hello=world',\n        '[Amplitude] URL Fragment': 'hash',\n        '[Amplitude] Request Method': 'POST',\n        '[Amplitude] Status Code': 500,\n      };\n      const request = new MockNetworkRequestEvent();\n      request.requestBodyJson = Promise.resolve({ message: 'hello' });\n      request.responseBodyJson = Promise.resolve({ message: 'world' });\n      const amplitude = createMockBrowserClient();\n      await logNetworkAnalyticsEvent(networkAnalyticsEvent, request, amplitude, new Logger());\n      /* eslint-disable-next-line @typescript-eslint/unbound-method */\n      expect(amplitude.track).toHaveBeenCalledWith(AMPLITUDE_NETWORK_REQUEST_EVENT, networkAnalyticsEvent);\n    });\n  });\n});\n\ndescribe('version', () => {\n  test('should return the plugin version', () => {\n    expect(VERSION != null).toBe(true);\n  });\n});\n"
  },
  {
    "path": "packages/plugin-network-capture-browser/test/e2e/fetch.spec.ts",
    "content": "import { test, expect } from '@playwright/test';\n\n/* eslint-disable @typescript-eslint/await-thenable */\n\ntest.describe('Network Capture Plugin - Fetch Tests', () => {\n  test('fetch.html page loads and runs without errors', async ({ page }) => {\n    // Listen for any uncaught exceptions\n    const uncaughtExceptions: string[] = [];\n    await page.route('https://httpstat.us/*', async (route) => {\n      const status = route.request().url().split('/').pop();\n      await route.fulfill({\n        status: Number(status),\n        body: JSON.stringify({\n          message: 'OK',\n        }),\n        headers: {\n          'Content-Type': 'application/json',\n        },\n      });\n    });\n    page.on('pageerror', (error) => {\n      uncaughtExceptions.push(error.message);\n    });\n\n    // Load the fetch.html page\n    await page.goto('http://localhost:5173/network-capture/fetch.html');\n\n    // Wait for the completion indicator to show tests are done\n    const completionIndicator = page.locator('#completion-indicator');\n    await completionIndicator.waitFor({ state: 'visible' });\n    await expect(completionIndicator).toHaveAttribute('data-complete', 'true', { timeout: 90000 });\n\n    // Check that there were no uncaught exceptions\n    expect(uncaughtExceptions).toHaveLength(0);\n\n    // Verify that results are displayed on the page\n    const resultsContainer = await page.locator('#results');\n    await expect(resultsContainer).toBeVisible();\n\n    // Verify that we have some result items\n    const resultItems = await page.locator('.result-item');\n    const count = await resultItems.count();\n    expect(count).toBeGreaterThan(0);\n\n    // Verify that all result items have either success or error class\n    const items = await resultItems.all();\n    for (const item of items) {\n      const className = await item.getAttribute('class');\n      expect(className).toMatch(/result-item (success|error)/);\n    }\n  });\n});\n"
  },
  {
    "path": "packages/plugin-network-capture-browser/test/e2e/xhr.spec.ts",
    "content": "import { test, expect } from '@playwright/test';\n\n/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-return, no-restricted-globals */\n\ntest.describe('XHR network tracking', () => {\n  // override remote config\n  test.beforeEach(async ({ page }) => {\n    await page.route('https://sr-client-cfg.amplitude.com/config/*', async (route) => {\n      await route.fulfill({\n        status: 200,\n        body: JSON.stringify({\n          configs: {\n            sessionReplay: {},\n            analyticsSDK: {\n              browserSDK: {\n                autocapture: {\n                  sessions: false,\n                  networkTracking: {\n                    captureRules: [\n                      {\n                        urlsRegex: ['.*/api/status/.*'],\n                        statusCodeRange: '400-599',\n                      },\n                    ],\n                  },\n                },\n              },\n            },\n          },\n        }),\n      });\n    });\n  });\n\n  test('should track XHR requests', async ({ page }) => {\n    // Navigate to the test page - no need to mock routes since we have a mock API server\n    await page.goto('http://localhost:5173/network-capture/xhr.html');\n\n    // Wait for the completion indicator to be visible\n    const completionIndicator = page.locator('#completion-indicator');\n    await completionIndicator.waitFor({ state: 'visible' });\n\n    // Wait for the completion indicator to show success\n    await expect(completionIndicator).toHaveAttribute('data-complete', 'true', { timeout: 30000 });\n\n    // Check that there were no uncaught exceptions\n    const consoleErrors = await page.evaluate(() => {\n      return (window as any).__consoleErrors || [];\n    });\n    expect(consoleErrors).toHaveLength(0);\n  });\n});\n"
  },
  {
    "path": "packages/plugin-network-capture-browser/test/mock-browser-client.ts",
    "content": "import { BrowserClient } from '@amplitude/analytics-core';\n\n// Mock BrowserClient implementation\nexport const createMockBrowserClient = (): jest.Mocked<BrowserClient> => {\n  const mockClient = {\n    init: jest.fn(),\n    add: jest.fn(),\n    remove: jest.fn(),\n    track: jest.fn(),\n    logEvent: jest.fn(),\n    identify: jest.fn(),\n    groupIdentify: jest.fn(),\n    setGroup: jest.fn(),\n    revenue: jest.fn(),\n    flush: jest.fn(),\n    getUserId: jest.fn(),\n    setUserId: jest.fn(),\n    getDeviceId: jest.fn(),\n    setDeviceId: jest.fn(),\n    getSessionId: jest.fn(),\n    setSessionId: jest.fn(),\n    extendSession: jest.fn(),\n    reset: jest.fn(),\n    setOptOut: jest.fn(),\n    setTransport: jest.fn(),\n    getOptOut: jest.fn(),\n    getIdentity: jest.fn(),\n    setIdentity: jest.fn(),\n    _setDiagnosticsSampleRate: jest.fn(),\n  } as jest.Mocked<BrowserClient>;\n\n  // Set up default return values for methods that return promises\n  mockClient.init.mockReturnValue({\n    promise: Promise.resolve(),\n  });\n\n  mockClient.track.mockReturnValue({\n    promise: Promise.resolve({\n      code: 200,\n      message: '',\n      event: {\n        event_type: '[Amplitude] Network Request',\n      },\n    }),\n  });\n\n  return mockClient;\n};\n"
  },
  {
    "path": "packages/plugin-network-capture-browser/test/setup.ts",
    "content": "require('css.escape');\n"
  },
  {
    "path": "packages/plugin-network-capture-browser/tsconfig.es5.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/cjs\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-network-capture-browser/tsconfig.esm.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"es6\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/esm\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-network-capture-browser/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src/**/*\", \"test/**/*\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"esModuleInterop\": true,\n    \"lib\": [\"dom\"],\n    \"noEmit\": true,\n    \"rootDir\": \".\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-page-url-enrichment-browser/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.7.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.7.9...@amplitude/plugin-page-url-enrichment-browser@0.7.10) (2026-05-13)\n\n\n### Bug Fixes\n\n* **autocapture:** fix stale URL storage for MPAs, also for leave-and-returns ([#1737](https://github.com/amplitude/Amplitude-TypeScript/issues/1737)) ([a736be2](https://github.com/amplitude/Amplitude-TypeScript/commit/a736be216331064dc3646a9c495ea7165cd0f683))\n\n\n\n\n\n## [0.7.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.7.8...@amplitude/plugin-page-url-enrichment-browser@0.7.9) (2026-04-28)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.7.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.7.7...@amplitude/plugin-page-url-enrichment-browser@0.7.8) (2026-04-22)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.7.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.7.6...@amplitude/plugin-page-url-enrichment-browser@0.7.7) (2026-04-21)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.7.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.7.5...@amplitude/plugin-page-url-enrichment-browser@0.7.6) (2026-04-14)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.7.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.7.4...@amplitude/plugin-page-url-enrichment-browser@0.7.5) (2026-04-09)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.7.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.7.3...@amplitude/plugin-page-url-enrichment-browser@0.7.4) (2026-04-01)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.7.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.7.2...@amplitude/plugin-page-url-enrichment-browser@0.7.3) (2026-03-26)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.7.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.7.1...@amplitude/plugin-page-url-enrichment-browser@0.7.2) (2026-03-24)\n\n\n### Bug Fixes\n\n* swallow session storage errors ([#1618](https://github.com/amplitude/Amplitude-TypeScript/issues/1618)) ([6c8066b](https://github.com/amplitude/Amplitude-TypeScript/commit/6c8066ba365fd11dbdcb48ac15f249e089b6a912))\n\n\n\n\n\n## [0.7.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.7.0...@amplitude/plugin-page-url-enrichment-browser@0.7.1) (2026-03-23)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n# [0.7.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.6.12...@amplitude/plugin-page-url-enrichment-browser@0.7.0) (2026-03-20)\n\n\n### Features\n\n* **plugin-custom-enrichment:** add custom enrichment plugin ([#1339](https://github.com/amplitude/Amplitude-TypeScript/issues/1339)) ([b236190](https://github.com/amplitude/Amplitude-TypeScript/commit/b236190fa30d0e4325c37b8896824e11f980e20c))\n\n\n\n\n\n## [0.6.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.6.11...@amplitude/plugin-page-url-enrichment-browser@0.6.12) (2026-03-19)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.6.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.6.10...@amplitude/plugin-page-url-enrichment-browser@0.6.11) (2026-03-17)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.6.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.6.9...@amplitude/plugin-page-url-enrichment-browser@0.6.10) (2026-03-16)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.6.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.6.8...@amplitude/plugin-page-url-enrichment-browser@0.6.9) (2026-03-13)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.6.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.6.7...@amplitude/plugin-page-url-enrichment-browser@0.6.8) (2026-03-12)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.6.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.6.6...@amplitude/plugin-page-url-enrichment-browser@0.6.7) (2026-03-09)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.6.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.6.5...@amplitude/plugin-page-url-enrichment-browser@0.6.6) (2026-03-05)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.6.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.6.4...@amplitude/plugin-page-url-enrichment-browser@0.6.5) (2026-03-03)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.6.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.6.3...@amplitude/plugin-page-url-enrichment-browser@0.6.4) (2026-03-03)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.6.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.6.2...@amplitude/plugin-page-url-enrichment-browser@0.6.3) (2026-02-26)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.6.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.6.1...@amplitude/plugin-page-url-enrichment-browser@0.6.2) (2026-02-24)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.6.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.6.0...@amplitude/plugin-page-url-enrichment-browser@0.6.1) (2026-02-19)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n# [0.6.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.5.15...@amplitude/plugin-page-url-enrichment-browser@0.6.0) (2026-02-17)\n\n\n### Features\n\n* **analytics-browser:** add setIdentity() ([#1517](https://github.com/amplitude/Amplitude-TypeScript/issues/1517)) ([314b3c1](https://github.com/amplitude/Amplitude-TypeScript/commit/314b3c1b7ee5b0ef135848a66156eb2874daec5f))\n\n\n\n\n\n## [0.5.15](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.5.14...@amplitude/plugin-page-url-enrichment-browser@0.5.15) (2026-02-10)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.5.14](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.5.13...@amplitude/plugin-page-url-enrichment-browser@0.5.14) (2026-01-26)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.5.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.5.12...@amplitude/plugin-page-url-enrichment-browser@0.5.13) (2026-01-21)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.5.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.5.11...@amplitude/plugin-page-url-enrichment-browser@0.5.12) (2026-01-15)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.5.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.5.10...@amplitude/plugin-page-url-enrichment-browser@0.5.11) (2026-01-14)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.5.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.5.9...@amplitude/plugin-page-url-enrichment-browser@0.5.10) (2026-01-14)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.5.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.5.8...@amplitude/plugin-page-url-enrichment-browser@0.5.9) (2025-12-24)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.5.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.5.7...@amplitude/plugin-page-url-enrichment-browser@0.5.8) (2025-12-16)\n\n\n### Bug Fixes\n\n* **plugin-page-url-enrichment-browser:** add internalDomains config for subdomain matching ([#1433](https://github.com/amplitude/Amplitude-TypeScript/issues/1433)) ([cf97ca3](https://github.com/amplitude/Amplitude-TypeScript/commit/cf97ca344e81666d4227aba67b0368d2213c9b34))\n\n\n\n\n\n## [0.5.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.5.6...@amplitude/plugin-page-url-enrichment-browser@0.5.7) (2025-12-09)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.5.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.5.5...@amplitude/plugin-page-url-enrichment-browser@0.5.6) (2025-11-21)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.5.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.5.4...@amplitude/plugin-page-url-enrichment-browser@0.5.5) (2025-11-20)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.5.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.5.3...@amplitude/plugin-page-url-enrichment-browser@0.5.4) (2025-11-17)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.5.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.5.2...@amplitude/plugin-page-url-enrichment-browser@0.5.3) (2025-11-17)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.5.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.5.1...@amplitude/plugin-page-url-enrichment-browser@0.5.2) (2025-11-05)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.5.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.5.0...@amplitude/plugin-page-url-enrichment-browser@0.5.1) (2025-10-29)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n# [0.5.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.4.4...@amplitude/plugin-page-url-enrichment-browser@0.5.0) (2025-10-23)\n\n\n### Bug Fixes\n\n* previous page location set to current page on first load in SPAs ([#1366](https://github.com/amplitude/Amplitude-TypeScript/issues/1366)) ([880e59b](https://github.com/amplitude/Amplitude-TypeScript/commit/880e59bd109d1225475403f4faec4cd5da45bf79))\n\n\n### Features\n\n* **autocapture:** set page url enrichment plugin to default on and add/fix tests ([#1287](https://github.com/amplitude/Amplitude-TypeScript/issues/1287)) ([d96d7dd](https://github.com/amplitude/Amplitude-TypeScript/commit/d96d7dd7db156eae51a342b4956db2530ca64d29))\n\n\n\n\n\n## [0.4.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.4.3...@amplitude/plugin-page-url-enrichment-browser@0.4.4) (2025-10-23)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.4.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.4.2...@amplitude/plugin-page-url-enrichment-browser@0.4.3) (2025-10-17)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.4.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.4.1...@amplitude/plugin-page-url-enrichment-browser@0.4.2) (2025-10-15)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.4.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.4.0...@amplitude/plugin-page-url-enrichment-browser@0.4.1) (2025-10-14)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n# [0.4.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.3.4...@amplitude/plugin-page-url-enrichment-browser@0.4.0) (2025-10-14)\n\n\n### Features\n\n* **autocapture:** add excluded events list and remove deprecated pac… ([#1330](https://github.com/amplitude/Amplitude-TypeScript/issues/1330)) ([2721b69](https://github.com/amplitude/Amplitude-TypeScript/commit/2721b69154c0535de9747dda1c7608bb2387f162))\n* **autocapture:** refactor getPageTitle from autocapture to make it reusable ([#1331](https://github.com/amplitude/Amplitude-TypeScript/issues/1331)) ([44eabd1](https://github.com/amplitude/Amplitude-TypeScript/commit/44eabd1139252ed71845d29a86ceccd2ef119d15))\n\n\n\n\n\n## [0.3.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.3.3...@amplitude/plugin-page-url-enrichment-browser@0.3.4) (2025-10-07)\n\n\n### Bug Fixes\n\n* Revert \"feat(analytics-client-common): refactor getPageTitle from aut… ([#1328](https://github.com/amplitude/Amplitude-TypeScript/issues/1328)) ([3976910](https://github.com/amplitude/Amplitude-TypeScript/commit/3976910d2e17a61f9f8e588a006cd44012f2f250))\n\n\n\n\n\n## [0.3.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.3.2...@amplitude/plugin-page-url-enrichment-browser@0.3.3) (2025-10-03)\n\n\n### Bug Fixes\n\n* add diagnostics to client and track autocapture getHierachy block time ([#1312](https://github.com/amplitude/Amplitude-TypeScript/issues/1312)) ([a919e22](https://github.com/amplitude/Amplitude-TypeScript/commit/a919e223428083a87954cffa50bc765baa5360b0))\n\n\n\n\n\n## [0.3.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.3.1...@amplitude/plugin-page-url-enrichment-browser@0.3.2) (2025-10-01)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.3.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.3.0...@amplitude/plugin-page-url-enrichment-browser@0.3.1) (2025-09-25)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n# [0.3.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.2.10...@amplitude/plugin-page-url-enrichment-browser@0.3.0) (2025-09-23)\n\n\n### Features\n\n* **analytics-client-common:** refactor getPageTitle from autocapture to make it reusable ([#1298](https://github.com/amplitude/Amplitude-TypeScript/issues/1298)) ([3c931ee](https://github.com/amplitude/Amplitude-TypeScript/commit/3c931eeb7bb4d2482523c48cf796113187d9b078))\n\n\n\n\n\n## [0.2.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.2.9...@amplitude/plugin-page-url-enrichment-browser@0.2.10) (2025-09-18)\n\n\n### Bug Fixes\n\n* **analytics-browser:** add URI decoding to Element Clicked event attribute ([#1297](https://github.com/amplitude/Amplitude-TypeScript/issues/1297)) ([ebb2120](https://github.com/amplitude/Amplitude-TypeScript/commit/ebb212080948e8acbaeadbdc410580e04202f818))\n\n\n\n\n\n## [0.2.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.2.8...@amplitude/plugin-page-url-enrichment-browser@0.2.9) (2025-09-12)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.2.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.2.7...@amplitude/plugin-page-url-enrichment-browser@0.2.8) (2025-09-05)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.2.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.2.6...@amplitude/plugin-page-url-enrichment-browser@0.2.7) (2025-08-28)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.2.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.2.5...@amplitude/plugin-page-url-enrichment-browser@0.2.6) (2025-08-26)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.2.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.2.4...@amplitude/plugin-page-url-enrichment-browser@0.2.5) (2025-08-25)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.2.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.2.3...@amplitude/plugin-page-url-enrichment-browser@0.2.4) (2025-08-22)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.2.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.2.2...@amplitude/plugin-page-url-enrichment-browser@0.2.3) (2025-08-21)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.2.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.2.1...@amplitude/plugin-page-url-enrichment-browser@0.2.2) (2025-08-13)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n## [0.2.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-url-enrichment-browser@0.2.0...@amplitude/plugin-page-url-enrichment-browser@0.2.1) (2025-08-08)\n\n**Note:** Version bump only for package @amplitude/plugin-page-url-enrichment-browser\n\n\n\n\n\n# 0.2.0 (2025-08-05)\n\n\n### Bug Fixes\n\n* **analtyics-browser): Revert \"feat(analytics-browser:** add page-url-previous-page plugin\" ([#1237](https://github.com/amplitude/Amplitude-TypeScript/issues/1237)) ([dfd7340](https://github.com/amplitude/Amplitude-TypeScript/commit/dfd7340f6519e647a814b3c66913b0c96b0567cf))\n\n\n### Features\n\n* **analytics-browser:** add page-url-previous-page plugin ([#1110](https://github.com/amplitude/Amplitude-TypeScript/issues/1110)) ([dc053ed](https://github.com/amplitude/Amplitude-TypeScript/commit/dc053ed9f0b6378fce6a49f6a6e4196f3622bd25))\n* **plugin-page-url-enrichment-browser:** AMP-130401 create Page URL Enrichment plugin for additional Page URL related properties ([#1238](https://github.com/amplitude/Amplitude-TypeScript/issues/1238)) ([4673be8](https://github.com/amplitude/Amplitude-TypeScript/commit/4673be86ab5535fdca66d1743ef4ee071d5fdef7))\n\n\n\n\n\n# Change Log\n"
  },
  {
    "path": "packages/plugin-page-url-enrichment-browser/README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://amplitude.com\" target=\"_blank\" align=\"center\">\n    <img src=\"https://static.amplitude.com/lightning/46c85bfd91905de8047f1ee65c7c93d6fa9ee6ea/static/media/amplitude-logo-with-text.4fb9e463.svg\" width=\"280\">\n  </a>\n  <br />\n</p>\n\n# @amplitude/plugin-page-url-enrichment-browser\n\nOfficial Browser SDK plugin for page url enrichment\n\n## Installation\n\nThis package is published on NPM registry and is available to be installed using npm and yarn.\n\n```sh\n# npm\nnpm install @amplitude/plugin-page-url-enrichment-browser\n\n# yarn\nyarn add @amplitude/plugin-page-url-enrichment-browser\n```\n\n## Usage\n\nThis plugin works on top of Amplitude Browser SDK and adds page url enrichment properties to all events. To use this plugin, you need to install `@amplitude/analytics-browser` version `v2.0.0` or later.\n\n### 1. Import Amplitude packages\n\n* `@amplitude/plugin-page-url-enrichment-browser`\n\n```typescript\nimport { pageUrlEnrichmentPlugin } from '@amplitude/plugin-page-url-enrichment-browser';\n```\n\n### 2. Instantiate page url enrichment plugin\n```typescript\nconst pageUrlEnrichment = pageUrlEnrichmentPlugin();\n```\n\n#### Options\n\n\n### 3. Install plugin to Amplitude SDK\n\n```typescript\namplitude.add(pageUrlEnrichment);\n```\n\n### 4. Initialize Amplitude SDK\n\n```typescript\namplitude.init('API_KEY');\n```\n\n## Resulting Page URL properties\n\nThis plugin adds Page URL properties to all events based on your configuration\n\n#### Event type\n* No event type added\n\n#### Event properties\n\n| Property                               | Description                                                                                                                                                          |\n| -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `'[Amplitude] Page Domain'`            | The website's hostname or `location.hostname`                                                                                                                        |\n| `'[Amplitude] Page Location'`          | The website's full url or `location.href`                                                                                                                            |\n| `'[Amplitude] Page Path'`              | The website's pathname or `location.pathname`                                                                                                                        |\n| `'[Amplitude] Page Title'`             | The website's title or `document.title`                                                                                                                              |\n| `'[Amplitude] Page URL'`               | The website's url excluding query parameters                                                                                                                         |\n| `'[Amplitude] Previous Page Location'` | The URL of the previous page the user visited; document.referrer if coming from an external domain; and using the sessionStorage which tracks the last url otherwise |\n| `'Amplitude] Previous Page Type'`      | A classification of the previous page (e.g., 'Internal', 'External', 'Direct'), typically derived from a custom function that analyzes the previous page's URL       |\n"
  },
  {
    "path": "packages/plugin-page-url-enrichment-browser/jest.config.js",
    "content": "const baseConfig = require('../../jest.config.js');\nconst package = require('./package');\n\nmodule.exports = {\n  ...baseConfig,\n  displayName: package.name,\n  rootDir: '.',\n  testEnvironment: 'jsdom',\n  coveragePathIgnorePatterns: ['index.ts'],\n};\n"
  },
  {
    "path": "packages/plugin-page-url-enrichment-browser/package.json",
    "content": "{\n  \"name\": \"@amplitude/plugin-page-url-enrichment-browser\",\n  \"version\": \"0.7.10\",\n  \"description\": \"\",\n  \"author\": \"Amplitude Inc\",\n  \"homepage\": \"https://github.com/amplitude/Amplitude-TypeScript\",\n  \"license\": \"MIT\",\n  \"main\": \"lib/cjs/index.js\",\n  \"module\": \"lib/esm/index.js\",\n  \"types\": \"lib/esm/index.d.ts\",\n  \"sideEffects\": false,\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"tag\": \"latest\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/amplitude/Amplitude-TypeScript.git\"\n  },\n  \"scripts\": {\n    \"build\": \"pnpm bundle && pnpm build:es5 && pnpm build:esm\",\n    \"bundle\": \"rollup --config rollup.config.js\",\n    \"build:es5\": \"tsc -p ./tsconfig.es5.json\",\n    \"build:esm\": \"tsc -p ./tsconfig.esm.json\",\n    \"watch\": \"tsc -p ./tsconfig.esm.json --watch\",\n    \"clean\": \"rimraf node_modules lib coverage\",\n    \"fix\": \"pnpm fix:eslint & pnpm fix:prettier\",\n    \"fix:eslint\": \"eslint '{src,test}/**/*.ts' --fix\",\n    \"fix:prettier\": \"prettier --write \\\"{src,test}/**/*.ts\\\"\",\n    \"lint\": \"pnpm lint:eslint & pnpm lint:prettier\",\n    \"lint:eslint\": \"eslint '{src,test}/**/*.ts'\",\n    \"lint:prettier\": \"prettier --check \\\"{src,test}/**/*.ts\\\"\",\n    \"test\": \"jest\",\n    \"typecheck\": \"tsc -p ./tsconfig.json\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/amplitude/Amplitude-TypeScript/issues\"\n  },\n  \"dependencies\": {\n    \"@amplitude/analytics-core\": \"workspace:*\",\n    \"tslib\": \"^2.4.1\"\n  },\n  \"devDependencies\": {\n    \"@rollup/plugin-commonjs\": \"^23.0.4\",\n    \"@rollup/plugin-node-resolve\": \"^15.0.1\",\n    \"@rollup/plugin-typescript\": \"^10.0.1\",\n    \"rollup\": \"^2.79.1\",\n    \"rollup-plugin-execute\": \"^1.1.1\",\n    \"rollup-plugin-gzip\": \"^3.1.0\",\n    \"rollup-plugin-terser\": \"^7.0.2\"\n  },\n  \"files\": [\n    \"lib\"\n  ]\n}\n"
  },
  {
    "path": "packages/plugin-page-url-enrichment-browser/rollup.config.js",
    "content": "import { umd } from '../../scripts/build/rollup.config';\n\nexport default [umd];\n"
  },
  {
    "path": "packages/plugin-page-url-enrichment-browser/src/index.ts",
    "content": "export {\n  pageUrlEnrichmentPlugin,\n  CURRENT_PAGE_STORAGE_KEY,\n  PREVIOUS_PAGE_STORAGE_KEY,\n  URL_INFO_STORAGE_KEY,\n} from './page-url-enrichment';\nexport { pageUrlEnrichmentPlugin as plugin } from './page-url-enrichment';\n"
  },
  {
    "path": "packages/plugin-page-url-enrichment-browser/src/page-url-enrichment.ts",
    "content": "import {\n  type BrowserClient,\n  type BrowserConfig,\n  BrowserStorage,\n  type EnrichmentPlugin,\n  type Event,\n  getDecodeURI,\n  getGlobalScope,\n  getPageTitle,\n  type ILogger,\n  type PageUrlEnrichmentOptions,\n  replaceSensitiveString,\n  SpecialEventType,\n} from '@amplitude/analytics-core';\n\nexport const CURRENT_PAGE_STORAGE_KEY = 'AMP_CURRENT_PAGE';\nexport const PREVIOUS_PAGE_STORAGE_KEY = 'AMP_PREVIOUS_PAGE';\nexport const URL_INFO_STORAGE_KEY = 'AMP_URL_INFO';\n\nexport type URLInfo = {\n  [CURRENT_PAGE_STORAGE_KEY]?: string;\n  [PREVIOUS_PAGE_STORAGE_KEY]?: string;\n};\n\nenum PreviousPageType {\n  Direct = 'direct', // for no prev page or referrer\n  Internal = 'internal', // for internal domains - exact domain matches or when current and previous page are both internal domains\n  External = 'external', // for different domains\n}\n\nexport const EXCLUDED_DEFAULT_EVENT_TYPES = new Set<string>([\n  SpecialEventType.IDENTIFY,\n  SpecialEventType.GROUP_IDENTIFY,\n  SpecialEventType.REVENUE,\n]);\n\nexport const isPageUrlEnrichmentEnabled = (option: unknown): boolean => {\n  if (typeof option === 'boolean') {\n    return option;\n  }\n  if (typeof option === 'object' && option !== null && 'pageUrlEnrichment' in option) {\n    return Boolean((option as { pageUrlEnrichment?: boolean }).pageUrlEnrichment);\n  }\n  return false;\n};\n\nexport const pageUrlEnrichmentPlugin = ({ internalDomains = [] }: PageUrlEnrichmentOptions = {}): EnrichmentPlugin => {\n  const globalScope = getGlobalScope();\n  let sessionStorage: BrowserStorage<URLInfo> | undefined = undefined;\n  let isStorageEnabled = false;\n  let loggerProvider: ILogger | undefined = undefined;\n\n  let isProxied = false;\n  let isTracking = false;\n\n  const getHostname = (url: string): string | undefined => {\n    let hostname: string | undefined;\n\n    try {\n      const decodedUrl = getDecodeURI(url, loggerProvider);\n      hostname = new URL(decodedUrl).hostname;\n    } catch (e) {\n      /* istanbul ignore next */\n      loggerProvider?.error('Could not parse URL: ', e);\n    }\n\n    return hostname;\n  };\n\n  const getPrevPageType = (previousPage: string) => {\n    const currentDomain = (typeof location !== 'undefined' && location.hostname) || '';\n    const previousPageDomain = previousPage ? getHostname(previousPage) : undefined;\n\n    if (!previousPageDomain) {\n      return PreviousPageType.Direct;\n    }\n\n    const isCurrentInternal = internalDomains.some((domain) => currentDomain.indexOf(domain) !== -1);\n    const isPrevInternal = internalDomains.some((domain) => previousPageDomain.indexOf(domain) !== -1);\n\n    if (currentDomain === previousPageDomain || (isPrevInternal && isCurrentInternal)) {\n      return PreviousPageType.Internal;\n    }\n\n    return PreviousPageType.External;\n  };\n\n  const saveURLInfo = async () => {\n    if (sessionStorage && isStorageEnabled) {\n      const URLInfo = await sessionStorage.get(URL_INFO_STORAGE_KEY);\n      const currentURL = getDecodeURI((typeof location !== 'undefined' && location.href) || '');\n      const storedCurrentURL = URLInfo?.[CURRENT_PAGE_STORAGE_KEY] || '';\n\n      let previousURL: string | undefined;\n      if (currentURL === storedCurrentURL) {\n        previousURL = URLInfo?.[PREVIOUS_PAGE_STORAGE_KEY] || '';\n      } else if (storedCurrentURL) {\n        previousURL = storedCurrentURL;\n      } else {\n        previousURL = document.referrer || '';\n      }\n\n      await sessionStorage.set(URL_INFO_STORAGE_KEY, {\n        [CURRENT_PAGE_STORAGE_KEY]: currentURL,\n        [PREVIOUS_PAGE_STORAGE_KEY]: previousURL,\n      });\n    }\n  };\n\n  const saveUrlInfoWrapper = () => {\n    void saveURLInfo();\n  };\n\n  const plugin: EnrichmentPlugin = {\n    name: '@amplitude/plugin-page-url-enrichment-browser',\n    type: 'enrichment',\n\n    setup: async (config: BrowserConfig, _: BrowserClient) => {\n      loggerProvider = config.loggerProvider;\n      loggerProvider.log('Installing @amplitude/plugin-page-url-enrichment-browser');\n\n      isTracking = true;\n\n      if (globalScope) {\n        try {\n          sessionStorage = new BrowserStorage<URLInfo>(globalScope.sessionStorage);\n        } catch (error) {\n          /* istanbul ignore next */\n          loggerProvider?.debug('sessionStorage is not available in this environment.');\n        }\n        isStorageEnabled = (await sessionStorage?.isEnabled()) ?? false;\n\n        if (sessionStorage && isStorageEnabled) {\n          const referrer = (typeof document !== 'undefined' && document.referrer) || '';\n          const referrerHostname = referrer ? getHostname(referrer) : undefined;\n          const currentHostname = (typeof location !== 'undefined' && location.hostname) || '';\n          const currentURL = getDecodeURI((typeof location !== 'undefined' && location.href) || '');\n\n          const existingURLInfo = await sessionStorage.get(URL_INFO_STORAGE_KEY);\n          const storedCurrentURL = existingURLInfo?.[CURRENT_PAGE_STORAGE_KEY] || '';\n\n          // document.referrer is preserved across pushState navigations and full-page\n          // reloads, so a different referrer hostname alone does not prove an external\n          // arrival. Also require the stored \"current\" to differ from location.href —\n          // that's what distinguishes a genuine new landing in this tab from a refresh\n          // of an already-tracked page (where storage holds the truthful previous).\n          const arrivedFromDifferentOrigin =\n            !!referrerHostname && referrerHostname !== currentHostname && storedCurrentURL !== currentURL;\n\n          if (arrivedFromDifferentOrigin) {\n            // sessionStorage survives same-tab cross-origin trips (siteA -> external -> siteA),\n            // leaving stale \"current\" that would wrongly become \"previous\". document.referrer\n            // is the truthful previous, so overwrite — at the cost of dropping the prior siteA page.\n            await sessionStorage.set(URL_INFO_STORAGE_KEY, {\n              [CURRENT_PAGE_STORAGE_KEY]: currentURL,\n              [PREVIOUS_PAGE_STORAGE_KEY]: referrer,\n            });\n          } else {\n            await saveURLInfo();\n          }\n        }\n\n        globalScope.addEventListener('popstate', saveUrlInfoWrapper);\n\n        if (!isProxied) {\n          /* istanbul ignore next */\n          // There is no global browser listener for changes to history, so we have\n          // to modify pushState and replaceState directly.\n          // https://stackoverflow.com/a/64927639\n          // eslint-disable-next-line @typescript-eslint/unbound-method\n          globalScope.history.pushState = new Proxy(globalScope.history.pushState, {\n            apply: (target, thisArg, [state, unused, url]) => {\n              target.apply(thisArg, [state, unused, url]);\n              if (isTracking) {\n                saveUrlInfoWrapper();\n              }\n            },\n          });\n\n          // eslint-disable-next-line @typescript-eslint/unbound-method\n          globalScope.history.replaceState = new Proxy(globalScope.history.replaceState, {\n            apply: (target, thisArg, [state, unused, url]) => {\n              target.apply(thisArg, [state, unused, url]);\n              if (isTracking) {\n                saveUrlInfoWrapper();\n              }\n            },\n          });\n\n          isProxied = true;\n        }\n      }\n    },\n    execute: async (event: Event) => {\n      const locationHREF = getDecodeURI((typeof location !== 'undefined' && location.href) || '');\n\n      if (sessionStorage && isStorageEnabled) {\n        // setup() seeds AMP_URL_INFO via saveURLInfo(), and pushState/replaceState/popstate\n        // keep it in sync, so we just read the previous page here.\n        const URLInfo = await sessionStorage.get(URL_INFO_STORAGE_KEY);\n        const previousPage = URLInfo?.[PREVIOUS_PAGE_STORAGE_KEY] || '';\n\n        // no need to proceed to add additional properties if the event is one of the default event types to be excluded\n        if (EXCLUDED_DEFAULT_EVENT_TYPES.has(event.event_type)) {\n          return event;\n        }\n\n        event.event_properties = {\n          ...(event.event_properties || {}),\n          '[Amplitude] Page Domain': addIfNotExist(\n            event,\n            '[Amplitude] Page Domain',\n            (typeof location !== 'undefined' && location.hostname) || '',\n          ),\n          '[Amplitude] Page Location': addIfNotExist(event, '[Amplitude] Page Location', locationHREF),\n          '[Amplitude] Page Path': addIfNotExist(\n            event,\n            '[Amplitude] Page Path',\n            (typeof location !== 'undefined' && getDecodeURI(location.pathname)) || '',\n          ),\n          '[Amplitude] Page Title': addIfNotExist(\n            event,\n            '[Amplitude] Page Title',\n            getPageTitle(replaceSensitiveString),\n          ),\n          '[Amplitude] Page URL': addIfNotExist(event, '[Amplitude] Page URL', locationHREF.split('?')[0]),\n          '[Amplitude] Previous Page Location': previousPage,\n          '[Amplitude] Previous Page Type': getPrevPageType(previousPage),\n        };\n      }\n\n      return event;\n    },\n    teardown: async () => {\n      if (globalScope) {\n        globalScope.removeEventListener('popstate', saveUrlInfoWrapper);\n\n        isTracking = false;\n      }\n\n      if (sessionStorage && isStorageEnabled) {\n        await sessionStorage.set(URL_INFO_STORAGE_KEY, {});\n      }\n    },\n  };\n\n  return plugin;\n};\n\nfunction addIfNotExist(event: Event, key: string, value: string): string {\n  if (!event.event_properties) {\n    event.event_properties = {};\n  }\n\n  if ((event.event_properties as { [key: string]: any })[key] === undefined) {\n    return value;\n  }\n\n  return (event.event_properties as { [key: string]: any })[key] as string;\n}\n"
  },
  {
    "path": "packages/plugin-page-url-enrichment-browser/src/typings/page-url-enrichment.ts",
    "content": "import type { EnrichmentPlugin, PageUrlEnrichmentOptions as Options } from '@amplitude/analytics-core';\n\nexport type { PageUrlEnrichmentOptions as Options } from '@amplitude/analytics-core';\n\nexport interface CreatePageUrlEnrichmentBrowserPlugin {\n  (options?: Options): EnrichmentPlugin;\n}\n"
  },
  {
    "path": "packages/plugin-page-url-enrichment-browser/test/mock-browser-client.ts",
    "content": "import { BrowserClient } from '@amplitude/analytics-core';\n\n// Mock BrowserClient implementation\nexport const createMockBrowserClient = (): jest.Mocked<BrowserClient> => {\n  const mockClient = {\n    init: jest.fn(),\n    add: jest.fn(),\n    remove: jest.fn(),\n    track: jest.fn(),\n    logEvent: jest.fn(),\n    identify: jest.fn(),\n    groupIdentify: jest.fn(),\n    setGroup: jest.fn(),\n    revenue: jest.fn(),\n    flush: jest.fn(),\n    getUserId: jest.fn(),\n    setUserId: jest.fn(),\n    getDeviceId: jest.fn(),\n    setDeviceId: jest.fn(),\n    getSessionId: jest.fn(),\n    setSessionId: jest.fn(),\n    extendSession: jest.fn(),\n    reset: jest.fn(),\n    setOptOut: jest.fn(),\n    setTransport: jest.fn(),\n    getOptOut: jest.fn(),\n    getIdentity: jest.fn(),\n    setIdentity: jest.fn(),\n    _setDiagnosticsSampleRate: jest.fn(),\n  } as jest.Mocked<BrowserClient>;\n\n  // Set up default return values for methods that return promises\n  mockClient.init.mockReturnValue({\n    promise: Promise.resolve(),\n  });\n\n  mockClient.track.mockReturnValue({\n    promise: Promise.resolve({\n      code: 200,\n      message: '',\n      event: {\n        event_type: '[Amplitude] Page Viewed',\n      },\n    }),\n  });\n\n  return mockClient;\n};\n"
  },
  {
    "path": "packages/plugin-page-url-enrichment-browser/test/page-url-enrichment.test.ts",
    "content": "import {\n  type BrowserClient,\n  type BrowserConfig,\n  CookieStorage,\n  FetchTransport,\n  getGlobalScope,\n  LogLevel,\n  Logger,\n  UUID,\n} from '@amplitude/analytics-core';\nimport {\n  CURRENT_PAGE_STORAGE_KEY,\n  PREVIOUS_PAGE_STORAGE_KEY,\n  URL_INFO_STORAGE_KEY,\n  isPageUrlEnrichmentEnabled,\n  pageUrlEnrichmentPlugin,\n} from '../src/page-url-enrichment';\nimport * as Core from '@amplitude/analytics-core';\n\n// Mock BrowserClient implementation\nconst createMockBrowserClient = (): jest.Mocked<BrowserClient> => {\n  const mockClient = {\n    init: jest.fn().mockReturnValue({\n      promise: Promise.resolve(),\n    }),\n    add: jest.fn(),\n    remove: jest.fn(),\n    track: jest.fn(),\n    logEvent: jest.fn(),\n    identify: jest.fn(),\n    groupIdentify: jest.fn(),\n    setGroup: jest.fn(),\n    revenue: jest.fn(),\n    flush: jest.fn(),\n    getUserId: jest.fn(),\n    setUserId: jest.fn(),\n    getDeviceId: jest.fn(),\n    setDeviceId: jest.fn(),\n    getSessionId: jest.fn(),\n    setSessionId: jest.fn(),\n    extendSession: jest.fn(),\n    reset: jest.fn(),\n    setOptOut: jest.fn(),\n    setTransport: jest.fn(),\n  } as unknown as jest.Mocked<BrowserClient>;\n\n  // Set up default return values for methods that return promises\n  mockClient.track.mockReturnValue({\n    promise: Promise.resolve({\n      code: 200,\n      message: '',\n      event: {\n        event_type: '[Amplitude] Page Viewed',\n      },\n    }),\n  });\n\n  return mockClient;\n};\n\nconst createConfigurationMock = (): jest.Mocked<BrowserConfig> => {\n  return {\n    apiKey: UUID(),\n    flushIntervalMillis: 0,\n    flushMaxRetries: 0,\n    flushQueueSize: 0,\n    logLevel: LogLevel.None,\n    loggerProvider: new Logger(),\n    offline: false,\n    optOut: false,\n    serverUrl: undefined,\n    transportProvider: new FetchTransport(),\n    useBatch: false,\n    cookieOptions: {\n      domain: '.amplitude.com',\n      expiration: 365,\n      sameSite: 'Lax',\n      secure: false,\n      upgrade: true,\n    },\n    cookieStorage: new CookieStorage(),\n    sessionTimeout: 30 * 60 * 1000,\n    trackingOptions: {\n      ipAddress: true,\n      language: true,\n      platform: true,\n    },\n    pageCounter: 0,\n  } as unknown as jest.Mocked<BrowserConfig>;\n};\n\ndescribe('pageUrlEnrichmentPlugin', () => {\n  let mockConfig: BrowserConfig = createConfigurationMock();\n  let mockAmplitude = createMockBrowserClient();\n  const plugin = pageUrlEnrichmentPlugin();\n\n  beforeAll(() => {\n    Object.defineProperty(window, 'location', {\n      value: {\n        hostname: '',\n        href: '',\n        pathname: '',\n        search: '',\n      },\n      writable: true,\n    });\n  });\n\n  beforeEach(() => {\n    mockAmplitude = createMockBrowserClient();\n    mockConfig = createConfigurationMock();\n\n    (window.location as any) = {\n      hostname: '',\n      href: '',\n      pathname: '',\n      search: '',\n    };\n  });\n\n  afterEach(async () => {\n    await plugin.teardown?.();\n    window.sessionStorage.setItem('AMP_URL_INFO', '{}');\n    // Reset document.referrer so tests that set it can't leak into later tests;\n    // setup()'s external-origin shortcut depends on this value.\n    Object.defineProperty(document, 'referrer', { value: '', configurable: true });\n    jest.restoreAllMocks();\n  });\n\n  describe('setup', () => {\n    test('should track page changes if we move to a new page', async () => {\n      await plugin.setup?.(mockConfig, mockAmplitude);\n      const sessionStorage = getGlobalScope()?.sessionStorage;\n      const history = getGlobalScope()?.history;\n\n      // test falsy location href\n      history?.pushState(undefined, '');\n      const falsyUrlInfo = {\n        [CURRENT_PAGE_STORAGE_KEY]: '',\n        [PREVIOUS_PAGE_STORAGE_KEY]: '',\n      };\n      // block event loop so that the sessionStorage is updated since pushState is async\n      await new Promise((resolve) => setTimeout(resolve, 0));\n      const storedFalsyUrlInfo = sessionStorage?.getItem(URL_INFO_STORAGE_KEY) || '';\n      expect(JSON.parse(storedFalsyUrlInfo)).toStrictEqual(falsyUrlInfo);\n\n      // move to first url\n      const firstUrl = new URL('https://www.example.com/home');\n      mockWindowLocationFromURL(firstUrl);\n      history?.pushState(undefined, firstUrl.href);\n      const firstUrlInfo = {\n        [CURRENT_PAGE_STORAGE_KEY]: 'https://www.example.com/home',\n        [PREVIOUS_PAGE_STORAGE_KEY]: '',\n      };\n      // block event loop so that the sessionStorage is updated since pushState is async\n      await new Promise((resolve) => setTimeout(resolve, 0));\n      const storedFirstUrlInfo = sessionStorage?.getItem(URL_INFO_STORAGE_KEY) || '';\n      expect(JSON.parse(storedFirstUrlInfo)).toStrictEqual(firstUrlInfo);\n\n      // move to second url\n      const secondUrl = new URL('https://www.example.com/about');\n      mockWindowLocationFromURL(secondUrl);\n      history?.pushState(undefined, secondUrl.href);\n      const secondUrlInfo = {\n        [CURRENT_PAGE_STORAGE_KEY]: 'https://www.example.com/about',\n        [PREVIOUS_PAGE_STORAGE_KEY]: 'https://www.example.com/home',\n      };\n      // block event loop so that the sessionStorage is updated since pushState is async\n      await new Promise((resolve) => setTimeout(resolve, 0));\n      const storedSecondUrlInfo = sessionStorage?.getItem(URL_INFO_STORAGE_KEY) || '';\n      expect(JSON.parse(storedSecondUrlInfo)).toStrictEqual(secondUrlInfo);\n\n      // move to third url\n      const thirdUrl = new URL('https://www.example.com/contact');\n      mockWindowLocationFromURL(thirdUrl);\n      history?.pushState(undefined, thirdUrl.href);\n      const thirdUrlInfo = {\n        [CURRENT_PAGE_STORAGE_KEY]: 'https://www.example.com/contact',\n        [PREVIOUS_PAGE_STORAGE_KEY]: 'https://www.example.com/about',\n      };\n      // block event loop so that the sessionStorage is updated since pushState is async\n      await new Promise((resolve) => setTimeout(resolve, 0));\n      const storedThirdUrlInfo = sessionStorage?.getItem(URL_INFO_STORAGE_KEY) || '';\n      expect(JSON.parse(storedThirdUrlInfo)).toStrictEqual(thirdUrlInfo);\n    });\n\n    test('should track page changes if we replace state', async () => {\n      await plugin.setup?.(mockConfig, mockAmplitude);\n      const sessionStorage = getGlobalScope()?.sessionStorage;\n      const history = getGlobalScope()?.history;\n\n      // move to first url\n      const firstUrl = new URL('https://www.example.com/home');\n      mockWindowLocationFromURL(firstUrl);\n      history?.pushState(undefined, firstUrl.href);\n      const firstUrlInfo = {\n        [CURRENT_PAGE_STORAGE_KEY]: 'https://www.example.com/home',\n        [PREVIOUS_PAGE_STORAGE_KEY]: '',\n      };\n      // block event loop so that the sessionStorage is updated since pushState is async\n      await new Promise((resolve) => setTimeout(resolve, 0));\n      const urlInfoStr = sessionStorage?.getItem(URL_INFO_STORAGE_KEY) || '';\n      expect(JSON.parse(urlInfoStr)).toStrictEqual(firstUrlInfo);\n\n      // move to second url\n      const secondUrl = new URL('https://www.example.com/about');\n      mockWindowLocationFromURL(secondUrl);\n      history?.replaceState(undefined, secondUrl.href);\n      const secondUrlInfo = {\n        [CURRENT_PAGE_STORAGE_KEY]: 'https://www.example.com/about',\n        [PREVIOUS_PAGE_STORAGE_KEY]: 'https://www.example.com/home',\n      };\n      // block event loop so that the sessionStorage is updated since pushState is async\n      await new Promise((resolve) => setTimeout(resolve, 0));\n      const storedSecondUrlInfo = sessionStorage?.getItem(URL_INFO_STORAGE_KEY) || '';\n      expect(JSON.parse(storedSecondUrlInfo)).toStrictEqual(secondUrlInfo);\n\n      // move to third url\n      const thirdUrl = new URL('https://www.example.com/contact');\n      mockWindowLocationFromURL(thirdUrl);\n      history?.pushState(undefined, thirdUrl.href);\n      const thirdUrlInfo = {\n        [CURRENT_PAGE_STORAGE_KEY]: 'https://www.example.com/contact',\n        [PREVIOUS_PAGE_STORAGE_KEY]: 'https://www.example.com/about',\n      };\n      // block event loop so that the sessionStorage is updated since pushState is async\n      await new Promise((resolve) => setTimeout(resolve, 0));\n      const storedThirdUrlInfo = sessionStorage?.getItem(URL_INFO_STORAGE_KEY) || '';\n      expect(JSON.parse(storedThirdUrlInfo)).toStrictEqual(thirdUrlInfo);\n    });\n  });\n\n  describe('execute', () => {\n    test('should add additional Page URL and Previous Page properties to an event', async () => {\n      await plugin.setup?.(mockConfig, mockAmplitude);\n\n      // test falsy location href\n      history?.pushState(undefined, '');\n      // block event loop so that the sessionStorage is updated since pushState is async\n      await new Promise((resolve) => setTimeout(resolve, 0));\n\n      const event_1 = await plugin.execute?.({\n        event_type: 'test_event_1',\n      });\n\n      expect(event_1?.event_properties).toStrictEqual({\n        '[Amplitude] Page Domain': '',\n        '[Amplitude] Page Location': '',\n        '[Amplitude] Page Path': '',\n        '[Amplitude] Page Title': '',\n        '[Amplitude] Page URL': '',\n        '[Amplitude] Previous Page Location': '',\n        '[Amplitude] Previous Page Type': 'direct',\n      });\n\n      const firstUrl = new URL('https://www.example.com/home');\n      mockWindowLocationFromURL(firstUrl);\n      mockDocumentTitle('Home - Example');\n      window.history.pushState(undefined, firstUrl.href);\n      // block event loop so that the sessionStorage is updated since pushState is async\n      await new Promise((resolve) => setTimeout(resolve, 0));\n\n      const secondUrl = new URL('https://www.example.com/about?test=param');\n      mockWindowLocationFromURL(secondUrl);\n      mockDocumentTitle('About - Example');\n      window.history.pushState(undefined, secondUrl.href);\n      // block event loop so that the sessionStorage is updated since pushState is async\n      await new Promise((resolve) => setTimeout(resolve, 0));\n\n      const event_2 = await plugin.execute?.({\n        event_type: 'test_event_2',\n      });\n\n      expect(event_2?.event_properties).toStrictEqual({\n        '[Amplitude] Page Domain': 'www.example.com',\n        '[Amplitude] Page Location': 'https://www.example.com/about?test=param',\n        '[Amplitude] Page Path': '/about',\n        '[Amplitude] Page Title': 'About - Example',\n        '[Amplitude] Page URL': 'https://www.example.com/about',\n        '[Amplitude] Previous Page Location': 'https://www.example.com/home',\n        '[Amplitude] Previous Page Type': 'internal',\n      });\n    });\n\n    test('should assign external to previous page type for non-matching domains', async () => {\n      await plugin.setup?.(mockConfig, mockAmplitude);\n\n      const firstUrl = new URL('https://www.externalexample.com/home');\n      mockWindowLocationFromURL(firstUrl);\n      mockDocumentTitle('HOME | External Example');\n      window.history.pushState(undefined, firstUrl.href);\n      // block event loop so that the sessionStorage is updated since pushState is async\n      await new Promise((resolve) => setTimeout(resolve, 0));\n\n      const secondUrl = new URL('https://www.example.com/about?test=param');\n      mockWindowLocationFromURL(secondUrl);\n      mockDocumentTitle('About - Example');\n      window.history.pushState(undefined, secondUrl.href);\n      // block event loop so that the sessionStorage is updated since pushState is async\n      await new Promise((resolve) => setTimeout(resolve, 0));\n\n      const event = await plugin.execute?.({\n        event_type: 'test_event',\n      });\n\n      expect(event?.event_properties).toStrictEqual({\n        '[Amplitude] Page Domain': 'www.example.com',\n        '[Amplitude] Page Location': 'https://www.example.com/about?test=param',\n        '[Amplitude] Page Path': '/about',\n        '[Amplitude] Page Title': 'About - Example',\n        '[Amplitude] Page URL': 'https://www.example.com/about',\n        '[Amplitude] Previous Page Location': 'https://www.externalexample.com/home',\n        '[Amplitude] Previous Page Type': 'external',\n      });\n    });\n\n    test('should assign external to previous page type for subdomains', async () => {\n      await plugin.setup?.(mockConfig, mockAmplitude);\n\n      const firstUrl = new URL('https://www.sub.example.com/home');\n      mockWindowLocationFromURL(firstUrl);\n      window.history.pushState(undefined, firstUrl.href);\n      // block event loop so that the sessionStorage is updated since pushState is async\n      await new Promise((resolve) => setTimeout(resolve, 0));\n\n      const secondUrl = new URL('https://www.example.com/about?test=param');\n      mockWindowLocationFromURL(secondUrl);\n      mockDocumentTitle('About - Example');\n      window.history.pushState(undefined, secondUrl.href);\n      // block event loop so that the sessionStorage is updated since pushState is async\n      await new Promise((resolve) => setTimeout(resolve, 0));\n\n      const event = await plugin.execute?.({\n        event_type: 'test_event',\n      });\n\n      expect(event?.event_properties).toStrictEqual({\n        '[Amplitude] Page Domain': 'www.example.com',\n        '[Amplitude] Page Location': 'https://www.example.com/about?test=param',\n        '[Amplitude] Page Path': '/about',\n        '[Amplitude] Page Title': 'About - Example',\n        '[Amplitude] Page URL': 'https://www.example.com/about',\n        '[Amplitude] Previous Page Location': 'https://www.sub.example.com/home',\n        '[Amplitude] Previous Page Type': 'external',\n      });\n    });\n\n    test('should assign internal to previous page type for matching domains', async () => {\n      await plugin.setup?.(mockConfig, mockAmplitude);\n\n      const firstUrl = new URL('https://www.example.com/home');\n      mockWindowLocationFromURL(firstUrl);\n      window.history.pushState(undefined, firstUrl.href);\n      // block event loop so that the sessionStorage is updated since pushState is async\n      await new Promise((resolve) => setTimeout(resolve, 0));\n\n      const secondUrl = new URL('https://www.example.com/about?test=param');\n      mockWindowLocationFromURL(secondUrl);\n      mockDocumentTitle('About - Example');\n      window.history.pushState(undefined, secondUrl.href);\n      // block event loop so that the sessionStorage is updated since pushState is async\n      await new Promise((resolve) => setTimeout(resolve, 0));\n\n      const event = await plugin.execute?.({\n        event_type: 'test_event',\n      });\n\n      expect(event?.event_properties).toStrictEqual({\n        '[Amplitude] Page Domain': 'www.example.com',\n        '[Amplitude] Page Location': 'https://www.example.com/about?test=param',\n        '[Amplitude] Page Path': '/about',\n        '[Amplitude] Page Title': 'About - Example',\n        '[Amplitude] Page URL': 'https://www.example.com/about',\n        '[Amplitude] Previous Page Location': 'https://www.example.com/home',\n        '[Amplitude] Previous Page Type': 'internal',\n      });\n    });\n\n    test('should assign internal/external to previous page type for based on internal domain match', async () => {\n      const plugin = pageUrlEnrichmentPlugin({ internalDomains: ['example.com', 'example.co.uk'] });\n      await plugin.setup?.(mockConfig, mockAmplitude);\n\n      // go from example.com to subdomain.test.example.com (internal)\n      const firstUrl = new URL('https://www.example.com/home');\n      mockWindowLocationFromURL(firstUrl);\n      window.history.pushState(undefined, firstUrl.href);\n      // block event loop so that the sessionStorage is updated since pushState is async\n      await new Promise((resolve) => setTimeout(resolve, 0));\n\n      const secondUrl = new URL('https://www.subdomain.test.example.com/about?test=param');\n      mockWindowLocationFromURL(secondUrl);\n      mockDocumentTitle('About - Example');\n      window.history.pushState(undefined, secondUrl.href);\n      // block event loop so that the sessionStorage is updated since pushState is async\n      await new Promise((resolve) => setTimeout(resolve, 0));\n\n      const event = await plugin.execute?.({\n        event_type: 'test_event',\n      });\n\n      expect(event?.event_properties).toStrictEqual({\n        '[Amplitude] Page Domain': 'www.subdomain.test.example.com',\n        '[Amplitude] Page Location': 'https://www.subdomain.test.example.com/about?test=param',\n        '[Amplitude] Page Path': '/about',\n        '[Amplitude] Page Title': 'About - Example',\n        '[Amplitude] Page URL': 'https://www.subdomain.test.example.com/about',\n        '[Amplitude] Previous Page Location': 'https://www.example.com/home',\n        '[Amplitude] Previous Page Type': 'internal',\n      });\n\n      // go from subdomain.test.example.com to example.co.uk (internal)\n      const thirdUrl = new URL('https://www.example.co.uk/contact');\n      mockWindowLocationFromURL(thirdUrl);\n      mockDocumentTitle('Contact - Example');\n      window.history.pushState(undefined, thirdUrl.href);\n      // block event loop so that the sessionStorage is updated since pushState is async\n      await new Promise((resolve) => setTimeout(resolve, 0));\n\n      const event2 = await plugin.execute?.({\n        event_type: 'test_event_2',\n      });\n\n      expect(event2?.event_properties).toStrictEqual({\n        '[Amplitude] Page Domain': 'www.example.co.uk',\n        '[Amplitude] Page Location': 'https://www.example.co.uk/contact',\n        '[Amplitude] Page Path': '/contact',\n        '[Amplitude] Page Title': 'Contact - Example',\n        '[Amplitude] Page URL': 'https://www.example.co.uk/contact',\n        '[Amplitude] Previous Page Location': 'https://www.subdomain.test.example.com/about?test=param',\n        '[Amplitude] Previous Page Type': 'internal',\n      });\n\n      // go from example.co.uk to example.org (external)\n      const fourthUrl = new URL('https://www.example.org/home');\n      mockWindowLocationFromURL(fourthUrl);\n      mockDocumentTitle('Home - Example');\n      window.history.pushState(undefined, fourthUrl.href);\n      // block event loop so that the sessionStorage is updated since pushState is async\n      await new Promise((resolve) => setTimeout(resolve, 0));\n\n      const event3 = await plugin.execute?.({\n        event_type: 'test_event_3',\n      });\n\n      expect(event3?.event_properties).toStrictEqual({\n        '[Amplitude] Page Domain': 'www.example.org',\n        '[Amplitude] Page Location': 'https://www.example.org/home',\n        '[Amplitude] Page Path': '/home',\n        '[Amplitude] Page Title': 'Home - Example',\n        '[Amplitude] Page URL': 'https://www.example.org/home',\n        '[Amplitude] Previous Page Location': 'https://www.example.co.uk/contact',\n        '[Amplitude] Previous Page Type': 'external',\n      });\n\n      // go from example.org to example.com (external)\n      const fifthUrl = new URL('https://www.example.com/about');\n      mockWindowLocationFromURL(fifthUrl);\n      mockDocumentTitle('About - Example');\n      window.history.pushState(undefined, fifthUrl.href);\n      // block event loop so that the sessionStorage is updated since pushState is async\n      await new Promise((resolve) => setTimeout(resolve, 0));\n\n      const event4 = await plugin.execute?.({\n        event_type: 'test_event_4',\n      });\n\n      expect(event4?.event_properties).toStrictEqual({\n        '[Amplitude] Page Domain': 'www.example.com',\n        '[Amplitude] Page Location': 'https://www.example.com/about',\n        '[Amplitude] Page Path': '/about',\n        '[Amplitude] Page Title': 'About - Example',\n        '[Amplitude] Page URL': 'https://www.example.com/about',\n        '[Amplitude] Previous Page Location': 'https://www.example.org/home',\n        '[Amplitude] Previous Page Type': 'external',\n      });\n    });\n\n    test('should assign direct to previous page type for unknown missing domains', async () => {\n      await plugin.setup?.(mockConfig, mockAmplitude);\n\n      const firstUrl = new URL('https://www.example.com/about?test=param');\n      mockWindowLocationFromURL(firstUrl);\n      mockDocumentTitle('About - Example');\n      window.history.pushState(undefined, firstUrl.href);\n      // block event loop so that the sessionStorage is updated since pushState is async\n      await new Promise((resolve) => setTimeout(resolve, 0));\n\n      const event = await plugin.execute?.({\n        event_type: 'test_event',\n      });\n\n      expect(event?.event_properties).toStrictEqual({\n        '[Amplitude] Page Domain': 'www.example.com',\n        '[Amplitude] Page Location': 'https://www.example.com/about?test=param',\n        '[Amplitude] Page Path': '/about',\n        '[Amplitude] Page Title': 'About - Example',\n        '[Amplitude] Page URL': 'https://www.example.com/about',\n        '[Amplitude] Previous Page Location': '',\n        '[Amplitude] Previous Page Type': 'direct',\n      });\n    });\n\n    test('should shift current to previous on setup when stale storage exists (MPA / full-page reload)', async () => {\n      // Simulate stale sessionStorage left over from the previous page load,\n      // e.g. user clicked an <a href> link triggering a full-page navigation.\n      sessionStorage.setItem(\n        URL_INFO_STORAGE_KEY,\n        JSON.stringify({\n          [CURRENT_PAGE_STORAGE_KEY]: 'https://www.example.com/home',\n          [PREVIOUS_PAGE_STORAGE_KEY]: 'https://google.com/search',\n        }),\n      );\n\n      // Same-origin referrer simulates a real <a href> click within the site;\n      // the external-origin shortcut in setup() should NOT fire here.\n      Object.defineProperty(document, 'referrer', {\n        value: 'https://www.example.com/home',\n        configurable: true,\n      });\n\n      // The new page has now booted; location is the new URL.\n      const newUrl = new URL('https://www.example.com/about');\n      mockWindowLocationFromURL(newUrl);\n      mockDocumentTitle('About - Example');\n\n      const newPlugin = pageUrlEnrichmentPlugin();\n      await newPlugin.setup?.(mockConfig, mockAmplitude);\n\n      const urlInfoStr = sessionStorage?.getItem(URL_INFO_STORAGE_KEY) || '';\n      expect(JSON.parse(urlInfoStr)).toStrictEqual({\n        [CURRENT_PAGE_STORAGE_KEY]: 'https://www.example.com/about',\n        [PREVIOUS_PAGE_STORAGE_KEY]: 'https://www.example.com/home',\n      });\n\n      // The first event after setup should also report the prior page as the previous location.\n      const event = await newPlugin.execute?.({\n        event_type: 'test_event',\n      });\n\n      expect(event?.event_properties).toMatchObject({\n        '[Amplitude] Page Location': 'https://www.example.com/about',\n        '[Amplitude] Previous Page Location': 'https://www.example.com/home',\n        '[Amplitude] Previous Page Type': 'internal',\n      });\n\n      await newPlugin.teardown?.();\n    });\n\n    test('should not add properties if they already exist', async () => {\n      await plugin.setup?.(mockConfig, mockAmplitude);\n\n      const firstUrl = new URL('https://www.example.com/home');\n      mockWindowLocationFromURL(firstUrl);\n      window.history.pushState(undefined, firstUrl.href);\n      // block event loop so that the sessionStorage is updated since pushState is async\n      await new Promise((resolve) => setTimeout(resolve, 0));\n\n      const event = await plugin.execute?.({\n        event_type: 'test_event',\n        event_properties: {\n          '[Amplitude] Page Domain': 'www.existingexample.com',\n          '[Amplitude] Page Location': 'https://www.existingexample.com/about?test=param',\n          '[Amplitude] Page Path': '/existingexample',\n          '[Amplitude] Page Title': 'Existing Example',\n          '[Amplitude] Page URL': 'https://www.existingexample.com/about',\n        },\n      });\n\n      expect(event?.event_properties).toStrictEqual({\n        '[Amplitude] Page Domain': 'www.existingexample.com',\n        '[Amplitude] Page Location': 'https://www.existingexample.com/about?test=param',\n        '[Amplitude] Page Path': '/existingexample',\n        '[Amplitude] Page Title': 'Existing Example',\n        '[Amplitude] Page URL': 'https://www.existingexample.com/about',\n        '[Amplitude] Previous Page Location': '',\n        '[Amplitude] Previous Page Type': 'direct',\n      });\n    });\n\n    test('should prefer document.referrer over stale storage when arriving from a different origin', async () => {\n      // Simulate the round-trip-away case: user was on /home, left to google.com,\n      // then arrived back on the site (e.g. by clicking a Google search result\n      // pointing at /about). The stored \"current\" of /home is stale and should NOT\n      // be used as the previous page; document.referrer is the truthful answer.\n      sessionStorage.setItem(\n        URL_INFO_STORAGE_KEY,\n        JSON.stringify({\n          [CURRENT_PAGE_STORAGE_KEY]: 'https://www.example.com/home',\n          [PREVIOUS_PAGE_STORAGE_KEY]: 'https://www.example.com/landing',\n        }),\n      );\n\n      Object.defineProperty(document, 'referrer', {\n        value: 'https://www.google.com/search?q=example',\n        configurable: true,\n      });\n\n      const newUrl = new URL('https://www.example.com/about');\n      mockWindowLocationFromURL(newUrl);\n      mockDocumentTitle('About - Example');\n\n      const newPlugin = pageUrlEnrichmentPlugin();\n      await newPlugin.setup?.(mockConfig, mockAmplitude);\n\n      const urlInfoStr = sessionStorage?.getItem(URL_INFO_STORAGE_KEY) || '';\n      expect(JSON.parse(urlInfoStr)).toStrictEqual({\n        [CURRENT_PAGE_STORAGE_KEY]: 'https://www.example.com/about',\n        [PREVIOUS_PAGE_STORAGE_KEY]: 'https://www.google.com/search?q=example',\n      });\n\n      const event = await newPlugin.execute?.({\n        event_type: 'test_event',\n      });\n\n      expect(event?.event_properties).toMatchObject({\n        '[Amplitude] Page Location': 'https://www.example.com/about',\n        '[Amplitude] Previous Page Location': 'https://www.google.com/search?q=example',\n        '[Amplitude] Previous Page Type': 'external',\n      });\n\n      await newPlugin.teardown?.();\n    });\n\n    test('should keep stored previous page on refresh even when document.referrer is a stale external origin', async () => {\n      // Repro of the SPA-refresh bug: user arrived at /landing from Google,\n      // pushState-navigated to /about, then hit refresh on /about. Browsers\n      // preserve document.referrer (still google.com) across pushState and\n      // full-page reloads, so a referrer-hostname-only check would mistakenly\n      // re-fire the external-origin branch and clobber the truthful internal\n      // previous page (/landing) that pushState had stored.\n      sessionStorage.setItem(\n        URL_INFO_STORAGE_KEY,\n        JSON.stringify({\n          [CURRENT_PAGE_STORAGE_KEY]: 'https://www.example.com/about',\n          [PREVIOUS_PAGE_STORAGE_KEY]: 'https://www.example.com/landing',\n        }),\n      );\n\n      Object.defineProperty(document, 'referrer', {\n        value: 'https://www.google.com/search?q=example',\n        configurable: true,\n      });\n\n      const refreshedUrl = new URL('https://www.example.com/about');\n      mockWindowLocationFromURL(refreshedUrl);\n      mockDocumentTitle('About - Example');\n\n      const newPlugin = pageUrlEnrichmentPlugin();\n      await newPlugin.setup?.(mockConfig, mockAmplitude);\n\n      const urlInfoStr = sessionStorage?.getItem(URL_INFO_STORAGE_KEY) || '';\n      expect(JSON.parse(urlInfoStr)).toStrictEqual({\n        [CURRENT_PAGE_STORAGE_KEY]: 'https://www.example.com/about',\n        [PREVIOUS_PAGE_STORAGE_KEY]: 'https://www.example.com/landing',\n      });\n\n      const event = await newPlugin.execute?.({\n        event_type: 'test_event',\n      });\n\n      expect(event?.event_properties).toMatchObject({\n        '[Amplitude] Page Location': 'https://www.example.com/about',\n        '[Amplitude] Previous Page Location': 'https://www.example.com/landing',\n        '[Amplitude] Previous Page Type': 'internal',\n      });\n\n      await newPlugin.teardown?.();\n    });\n\n    test('should fall back to empty previous page when sessionStorage is wiped mid-session', async () => {\n      await plugin.setup?.(mockConfig, mockAmplitude);\n\n      const url = new URL('https://www.example.com/about');\n      mockWindowLocationFromURL(url);\n      mockDocumentTitle('About - Example');\n\n      // Externally wipe AMP_URL_INFO after setup has seeded it. execute() should\n      // gracefully degrade to an empty previous page rather than throw.\n      sessionStorage.removeItem(URL_INFO_STORAGE_KEY);\n\n      const event = await plugin.execute?.({\n        event_type: 'test_event',\n      });\n\n      expect(event?.event_properties).toMatchObject({\n        '[Amplitude] Page Location': 'https://www.example.com/about',\n        '[Amplitude] Previous Page Location': '',\n        '[Amplitude] Previous Page Type': 'direct',\n      });\n    });\n\n    test('should ignore event if it is one of the default event types to be excluded', async () => {\n      await plugin.setup?.(mockConfig, mockAmplitude);\n\n      const excludedEvent = await plugin.execute?.({\n        event_type: '$identify',\n      });\n\n      expect(excludedEvent?.event_properties).toStrictEqual(undefined);\n    });\n  });\n\n  describe('teardown', () => {\n    test('should call remove listeners', async () => {\n      const removeEventListener = jest.spyOn(window, 'removeEventListener');\n      await plugin.setup?.(mockConfig, mockAmplitude);\n      await plugin.teardown?.();\n      expect(removeEventListener).toHaveBeenCalledTimes(1);\n    });\n\n    test('sessionStorage items should be removed', async () => {\n      await plugin.setup?.(mockConfig, mockAmplitude);\n      const sessionStorage = getGlobalScope()?.sessionStorage;\n\n      const initialURLInfo = {\n        [CURRENT_PAGE_STORAGE_KEY]: 'www.example.com/home',\n        [PREVIOUS_PAGE_STORAGE_KEY]: 'www.example.com/about',\n      };\n\n      sessionStorage?.setItem(URL_INFO_STORAGE_KEY, JSON.stringify(initialURLInfo));\n      expect(sessionStorage?.getItem(URL_INFO_STORAGE_KEY)).toStrictEqual(JSON.stringify(initialURLInfo));\n\n      await plugin.teardown?.();\n      expect(sessionStorage?.getItem(URL_INFO_STORAGE_KEY)).toStrictEqual(JSON.stringify({}));\n    });\n  });\n\n  describe('first page load with document.referrer', () => {\n    test('should set Previous Page Type to \"direct\" when no referrer exists', async () => {\n      sessionStorage.clear();\n\n      Object.defineProperty(document, 'referrer', {\n        value: '',\n        configurable: true,\n      });\n\n      const newPlugin = pageUrlEnrichmentPlugin();\n      await newPlugin.setup?.(mockConfig, mockAmplitude);\n\n      const firstUrl = new URL('https://www.example.com/');\n      mockWindowLocationFromURL(firstUrl);\n      mockDocumentTitle('Home - Example');\n\n      window.history.replaceState(undefined, '');\n      await new Promise((resolve) => setTimeout(resolve, 0));\n\n      const event = await newPlugin.execute?.({\n        event_type: 'Page View',\n      });\n\n      expect(event?.event_properties).toMatchObject({\n        '[Amplitude] Page Domain': 'www.example.com',\n        '[Amplitude] Page Location': 'https://www.example.com/',\n        '[Amplitude] Previous Page Location': '',\n        '[Amplitude] Previous Page Type': 'direct',\n      });\n\n      const urlInfoStr = sessionStorage?.getItem(URL_INFO_STORAGE_KEY) || '';\n      const urlInfo = JSON.parse(urlInfoStr);\n      expect(urlInfo[CURRENT_PAGE_STORAGE_KEY]).toBe('https://www.example.com/');\n      expect(urlInfo[PREVIOUS_PAGE_STORAGE_KEY]).toBe('');\n\n      await newPlugin.teardown?.();\n    });\n\n    test('should preserve external referrer on first page load', async () => {\n      sessionStorage.clear();\n\n      Object.defineProperty(document, 'referrer', {\n        value: 'https://google.com/search',\n        configurable: true,\n      });\n\n      const newPlugin = pageUrlEnrichmentPlugin();\n      await newPlugin.setup?.(mockConfig, mockAmplitude);\n\n      const firstUrl = new URL('https://www.example.com/');\n      mockWindowLocationFromURL(firstUrl);\n      mockDocumentTitle('Home - Example');\n\n      window.history.replaceState(undefined, '');\n      await new Promise((resolve) => setTimeout(resolve, 0));\n\n      const event = await newPlugin.execute?.({\n        event_type: 'Page View',\n      });\n\n      expect(event?.event_properties).toMatchObject({\n        '[Amplitude] Page Domain': 'www.example.com',\n        '[Amplitude] Page Location': 'https://www.example.com/',\n        '[Amplitude] Previous Page Location': 'https://google.com/search',\n        '[Amplitude] Previous Page Type': 'external',\n      });\n\n      const urlInfoStr = sessionStorage?.getItem(URL_INFO_STORAGE_KEY) || '';\n      const urlInfo = JSON.parse(urlInfoStr);\n      expect(urlInfo[CURRENT_PAGE_STORAGE_KEY]).toBe('https://www.example.com/');\n      expect(urlInfo[PREVIOUS_PAGE_STORAGE_KEY]).toBe('https://google.com/search');\n\n      await newPlugin.teardown?.();\n    });\n\n    test('should handle history events before first event is tracked', async () => {\n      sessionStorage.clear();\n\n      Object.defineProperty(document, 'referrer', {\n        value: '',\n        configurable: true,\n      });\n\n      const newPlugin = pageUrlEnrichmentPlugin();\n      await newPlugin.setup?.(mockConfig, mockAmplitude);\n\n      const firstUrl = new URL('https://www.example.com/home');\n      mockWindowLocationFromURL(firstUrl);\n\n      window.history.pushState(undefined, '');\n      await new Promise((resolve) => setTimeout(resolve, 0));\n\n      window.history.replaceState(undefined, '');\n      await new Promise((resolve) => setTimeout(resolve, 0));\n\n      const event = await newPlugin.execute?.({\n        event_type: 'Page View',\n      });\n\n      expect(event?.event_properties).toMatchObject({\n        '[Amplitude] Previous Page Location': '',\n        '[Amplitude] Previous Page Type': 'direct',\n      });\n\n      await newPlugin.teardown?.();\n    });\n  });\n\n  describe('others', () => {\n    test('should handle when globalScope is not defined', async () => {\n      jest.spyOn(Core, 'getGlobalScope').mockReturnValue(undefined);\n      const newPlugin = pageUrlEnrichmentPlugin();\n      await newPlugin.setup?.(mockConfig, mockAmplitude);\n      await newPlugin.teardown?.();\n      expect(Core.getGlobalScope).toHaveBeenCalledTimes(1);\n    });\n    test('should handle sessionStorage throwing (e.g. sandboxed iframe) and continue without session storage', async () => {\n      const logger = new Logger();\n      const debugSpy = jest.spyOn(logger, 'debug');\n      const configWithLogger = { ...mockConfig, loggerProvider: logger };\n\n      // Build scope without spreading window so sessionStorage getter is only invoked when plugin accesses it\n      const scopeWithThrowingSessionStorage = {\n        addEventListener: window.addEventListener.bind(window),\n        removeEventListener: window.removeEventListener.bind(window),\n        history: window.history,\n        get sessionStorage() {\n          throw new DOMException('The operation is insecure', 'SecurityError');\n        },\n      };\n      jest\n        .spyOn(Core, 'getGlobalScope')\n        .mockReturnValue(scopeWithThrowingSessionStorage as unknown as typeof globalThis);\n\n      const newPlugin = pageUrlEnrichmentPlugin();\n      await expect(newPlugin.setup?.(configWithLogger, mockAmplitude)).resolves.not.toThrow();\n      expect(debugSpy).toHaveBeenCalledWith(\n        expect.stringContaining('sessionStorage is not available in this environment'),\n      );\n\n      await newPlugin.teardown?.();\n    });\n\n    test('should handle when sessionStorage is not defined', async () => {\n      const actual = jest.requireActual('@amplitude/analytics-core') as unknown as typeof Core;\n      jest.spyOn(Core, 'getGlobalScope').mockReturnValue({\n        ...actual.getGlobalScope(),\n        sessionStorage: undefined,\n      } as unknown as typeof globalThis);\n      const newPlugin = pageUrlEnrichmentPlugin();\n      await newPlugin.setup?.(mockConfig, mockAmplitude);\n\n      const firstUrl = new URL('https://www.example.com/home');\n      mockWindowLocationFromURL(firstUrl);\n      mockDocumentTitle('Home - Example');\n      window.history.pushState(undefined, firstUrl.href);\n      // block event loop so that the sessionStorage is updated since pushState is async\n      await new Promise((resolve) => setTimeout(resolve, 0));\n\n      await newPlugin.execute?.({\n        event_type: 'test_event',\n      });\n      await newPlugin.teardown?.();\n      expect(Core.getGlobalScope).toHaveBeenCalledTimes(2);\n    });\n  });\n});\n\ndescribe('isPageUrlEnrichmentEnabled', () => {\n  test('should return true with true parameter', () => {\n    expect(isPageUrlEnrichmentEnabled(true)).toBe(true);\n  });\n\n  test('should return false with undefined parameter', () => {\n    expect(isPageUrlEnrichmentEnabled(undefined)).toBe(false);\n  });\n\n  test('should return false with false parameter', () => {\n    expect(isPageUrlEnrichmentEnabled(false)).toBe(false);\n  });\n\n  test('should return true with object parameter set to true', () => {\n    expect(\n      isPageUrlEnrichmentEnabled({\n        pageUrlEnrichment: true,\n      }),\n    ).toBe(true);\n  });\n\n  test('should return false with object parameter set to false', () => {\n    expect(\n      isPageUrlEnrichmentEnabled({\n        pageUrlEnrichment: false,\n      }),\n    ).toBe(false);\n  });\n\n  test('should return false with object parameter undefined', () => {\n    expect(\n      isPageUrlEnrichmentEnabled({\n        pageUrlEnrichment: undefined,\n      }),\n    ).toBe(false);\n  });\n});\n\nconst mockWindowLocationFromURL = (url: URL) => {\n  window.location.href = url.toString();\n  window.location.search = url.search;\n  window.location.hostname = url.hostname;\n  window.location.pathname = url.pathname;\n};\n\nconst mockDocumentTitle = (title: string) => {\n  document.title = title;\n};\n"
  },
  {
    "path": "packages/plugin-page-url-enrichment-browser/tsconfig.es5.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/cjs\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-page-url-enrichment-browser/tsconfig.esm.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"es6\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/esm\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-page-url-enrichment-browser/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src/**/*\", \"test/**/*\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"esModuleInterop\": true,\n    \"lib\": [\"dom\"],\n    \"noEmit\": true,\n    \"rootDir\": \".\",\n  }\n}\n"
  },
  {
    "path": "packages/plugin-page-view-tracking-browser/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.11.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.10.2...@amplitude/plugin-page-view-tracking-browser@2.11.0) (2026-04-28)\n\n\n### Features\n\n* remove experimental request body compression backdoor ([#1699](https://github.com/amplitude/Amplitude-TypeScript/issues/1699)) ([98ecb9d](https://github.com/amplitude/Amplitude-TypeScript/commit/98ecb9dc1f3658cf6d0dfae1e9784335c9d33b5e))\n\n\n\n\n\n## [2.10.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.10.1...@amplitude/plugin-page-view-tracking-browser@2.10.2) (2026-04-22)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.10.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.10.0...@amplitude/plugin-page-view-tracking-browser@2.10.1) (2026-04-21)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n# [2.10.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.9.6...@amplitude/plugin-page-view-tracking-browser@2.10.0) (2026-04-14)\n\n\n### Features\n\n* **analytics-browser:** event property attribution ([#1628](https://github.com/amplitude/Amplitude-TypeScript/issues/1628)) ([6d37e79](https://github.com/amplitude/Amplitude-TypeScript/commit/6d37e797976e0e77dc11046b9259eb4b80259996))\n\n\n\n\n\n## [2.9.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.9.5...@amplitude/plugin-page-view-tracking-browser@2.9.6) (2026-04-09)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.9.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.9.4...@amplitude/plugin-page-view-tracking-browser@2.9.5) (2026-04-01)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.9.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.9.3...@amplitude/plugin-page-view-tracking-browser@2.9.4) (2026-03-26)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.9.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.9.2...@amplitude/plugin-page-view-tracking-browser@2.9.3) (2026-03-24)\n\n\n### Bug Fixes\n\n* swallow session storage errors ([#1618](https://github.com/amplitude/Amplitude-TypeScript/issues/1618)) ([6c8066b](https://github.com/amplitude/Amplitude-TypeScript/commit/6c8066ba365fd11dbdcb48ac15f249e089b6a912))\n\n\n\n\n\n## [2.9.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.9.1...@amplitude/plugin-page-view-tracking-browser@2.9.2) (2026-03-23)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.9.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.9.0...@amplitude/plugin-page-view-tracking-browser@2.9.1) (2026-03-20)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n# [2.9.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.8.7...@amplitude/plugin-page-view-tracking-browser@2.9.0) (2026-03-19)\n\n\n### Features\n\n* **autocapture:** zoning beta  ([#1589](https://github.com/amplitude/Amplitude-TypeScript/issues/1589)) ([2bb3608](https://github.com/amplitude/Amplitude-TypeScript/commit/2bb36088dc1342512ba0289fb1108ed8a61361f6))\n\n\n\n\n\n## [2.8.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.8.6...@amplitude/plugin-page-view-tracking-browser@2.8.7) (2026-03-17)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.8.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.8.5...@amplitude/plugin-page-view-tracking-browser@2.8.6) (2026-03-16)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.8.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.8.4...@amplitude/plugin-page-view-tracking-browser@2.8.5) (2026-03-13)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.8.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.8.3...@amplitude/plugin-page-view-tracking-browser@2.8.4) (2026-03-12)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.8.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.8.2...@amplitude/plugin-page-view-tracking-browser@2.8.3) (2026-03-09)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.8.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.8.1...@amplitude/plugin-page-view-tracking-browser@2.8.2) (2026-03-05)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.8.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.8.0...@amplitude/plugin-page-view-tracking-browser@2.8.1) (2026-03-03)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n# [2.8.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.7.3...@amplitude/plugin-page-view-tracking-browser@2.8.0) (2026-03-03)\n\n\n### Features\n\n* manual opt in gzip ([#1568](https://github.com/amplitude/Amplitude-TypeScript/issues/1568)) ([303c130](https://github.com/amplitude/Amplitude-TypeScript/commit/303c130429c51b0913f3903db4ace5263e1c78e7))\n\n\n\n\n\n## [2.7.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.7.2...@amplitude/plugin-page-view-tracking-browser@2.7.3) (2026-02-26)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.7.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.7.1...@amplitude/plugin-page-view-tracking-browser@2.7.2) (2026-02-24)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.7.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.7.0...@amplitude/plugin-page-view-tracking-browser@2.7.1) (2026-02-19)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n# [2.7.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.6.12...@amplitude/plugin-page-view-tracking-browser@2.7.0) (2026-02-17)\n\n\n### Features\n\n* **analytics-browser:** add setIdentity() ([#1517](https://github.com/amplitude/Amplitude-TypeScript/issues/1517)) ([314b3c1](https://github.com/amplitude/Amplitude-TypeScript/commit/314b3c1b7ee5b0ef135848a66156eb2874daec5f))\n\n\n\n\n\n## [2.6.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.6.11...@amplitude/plugin-page-view-tracking-browser@2.6.12) (2026-02-10)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.6.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.6.10...@amplitude/plugin-page-view-tracking-browser@2.6.11) (2026-01-26)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.6.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.6.9...@amplitude/plugin-page-view-tracking-browser@2.6.10) (2026-01-21)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.6.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.6.8...@amplitude/plugin-page-view-tracking-browser@2.6.9) (2026-01-15)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.6.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.6.7...@amplitude/plugin-page-view-tracking-browser@2.6.8) (2026-01-14)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.6.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.6.6...@amplitude/plugin-page-view-tracking-browser@2.6.7) (2026-01-14)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.6.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.6.5...@amplitude/plugin-page-view-tracking-browser@2.6.6) (2025-12-24)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.6.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.6.4...@amplitude/plugin-page-view-tracking-browser@2.6.5) (2025-12-16)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.6.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.6.3...@amplitude/plugin-page-view-tracking-browser@2.6.4) (2025-12-09)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.6.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.6.2...@amplitude/plugin-page-view-tracking-browser@2.6.3) (2025-11-21)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.6.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.6.1...@amplitude/plugin-page-view-tracking-browser@2.6.2) (2025-11-20)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.6.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.6.0...@amplitude/plugin-page-view-tracking-browser@2.6.1) (2025-11-17)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n# [2.6.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.5.7...@amplitude/plugin-page-view-tracking-browser@2.6.0) (2025-11-17)\n\n\n### Features\n\n* **analytics-browser:** add reset listener API ([#1393](https://github.com/amplitude/Amplitude-TypeScript/issues/1393)) ([7bd85e5](https://github.com/amplitude/Amplitude-TypeScript/commit/7bd85e51b01cefdb43b8474d930e8c219b739323))\n\n\n\n\n\n## [2.5.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.5.6...@amplitude/plugin-page-view-tracking-browser@2.5.7) (2025-11-05)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.5.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.5.5...@amplitude/plugin-page-view-tracking-browser@2.5.6) (2025-10-29)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.5.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.5.4...@amplitude/plugin-page-view-tracking-browser@2.5.5) (2025-10-23)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.5.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.5.3...@amplitude/plugin-page-view-tracking-browser@2.5.4) (2025-10-23)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.5.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.5.2...@amplitude/plugin-page-view-tracking-browser@2.5.3) (2025-10-17)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.5.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.5.1...@amplitude/plugin-page-view-tracking-browser@2.5.2) (2025-10-15)\n\n\n### Bug Fixes\n\n* **plugin-page-view-tracking-browser:** migrate to analytics-core ([#1341](https://github.com/amplitude/Amplitude-TypeScript/issues/1341)) ([676d347](https://github.com/amplitude/Amplitude-TypeScript/commit/676d347a04a6bd1ab5264ac8f58a358fd983ea54))\n\n\n\n\n\n## [2.5.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.5.0...@amplitude/plugin-page-view-tracking-browser@2.5.1) (2025-10-14)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n# [2.5.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.4.4...@amplitude/plugin-page-view-tracking-browser@2.5.0) (2025-10-14)\n\n\n### Features\n\n* **autocapture:** refactor getPageTitle from autocapture to make it reusable ([#1331](https://github.com/amplitude/Amplitude-TypeScript/issues/1331)) ([44eabd1](https://github.com/amplitude/Amplitude-TypeScript/commit/44eabd1139252ed71845d29a86ceccd2ef119d15))\n\n\n\n\n\n## [2.4.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.4.3...@amplitude/plugin-page-view-tracking-browser@2.4.4) (2025-10-07)\n\n\n### Bug Fixes\n\n* Revert \"feat(analytics-client-common): refactor getPageTitle from aut… ([#1328](https://github.com/amplitude/Amplitude-TypeScript/issues/1328)) ([3976910](https://github.com/amplitude/Amplitude-TypeScript/commit/3976910d2e17a61f9f8e588a006cd44012f2f250))\n\n\n\n\n\n## [2.4.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.4.2...@amplitude/plugin-page-view-tracking-browser@2.4.3) (2025-10-03)\n\n\n### Bug Fixes\n\n* add diagnostics to client and track autocapture getHierachy block time ([#1312](https://github.com/amplitude/Amplitude-TypeScript/issues/1312)) ([a919e22](https://github.com/amplitude/Amplitude-TypeScript/commit/a919e223428083a87954cffa50bc765baa5360b0))\n\n\n\n\n\n## [2.4.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.4.1...@amplitude/plugin-page-view-tracking-browser@2.4.2) (2025-10-01)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.4.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.4.0...@amplitude/plugin-page-view-tracking-browser@2.4.1) (2025-09-25)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n# [2.4.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.48...@amplitude/plugin-page-view-tracking-browser@2.4.0) (2025-09-23)\n\n\n### Features\n\n* **analytics-client-common:** refactor getPageTitle from autocapture to make it reusable ([#1298](https://github.com/amplitude/Amplitude-TypeScript/issues/1298)) ([3c931ee](https://github.com/amplitude/Amplitude-TypeScript/commit/3c931eeb7bb4d2482523c48cf796113187d9b078))\n\n\n\n\n\n## [2.3.48](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.47...@amplitude/plugin-page-view-tracking-browser@2.3.48) (2025-09-18)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.47](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.46...@amplitude/plugin-page-view-tracking-browser@2.3.47) (2025-09-12)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.46](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.45...@amplitude/plugin-page-view-tracking-browser@2.3.46) (2025-09-05)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.45](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.44...@amplitude/plugin-page-view-tracking-browser@2.3.45) (2025-08-28)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.44](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.43...@amplitude/plugin-page-view-tracking-browser@2.3.44) (2025-08-26)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.43](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.42...@amplitude/plugin-page-view-tracking-browser@2.3.43) (2025-08-25)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.42](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.41...@amplitude/plugin-page-view-tracking-browser@2.3.42) (2025-08-22)\n\n\n### Bug Fixes\n\n* **analytics-core:** fix typo in Reddit click-id ([#1267](https://github.com/amplitude/Amplitude-TypeScript/issues/1267)) ([43e581d](https://github.com/amplitude/Amplitude-TypeScript/commit/43e581d6465546a38373f758f179eee103172755))\n\n\n\n\n\n## [2.3.41](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.40...@amplitude/plugin-page-view-tracking-browser@2.3.41) (2025-08-21)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.40](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.39...@amplitude/plugin-page-view-tracking-browser@2.3.40) (2025-08-13)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.39](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.38...@amplitude/plugin-page-view-tracking-browser@2.3.39) (2025-08-08)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.38](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.37...@amplitude/plugin-page-view-tracking-browser@2.3.38) (2025-08-05)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.37](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.36...@amplitude/plugin-page-view-tracking-browser@2.3.37) (2025-07-29)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.36](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.35...@amplitude/plugin-page-view-tracking-browser@2.3.36) (2025-07-17)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.35](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.34...@amplitude/plugin-page-view-tracking-browser@2.3.35) (2025-07-15)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.34](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.33...@amplitude/plugin-page-view-tracking-browser@2.3.34) (2025-07-08)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.33](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.32...@amplitude/plugin-page-view-tracking-browser@2.3.33) (2025-06-30)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.32](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.31...@amplitude/plugin-page-view-tracking-browser@2.3.32) (2025-06-26)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.31](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.30...@amplitude/plugin-page-view-tracking-browser@2.3.31) (2025-06-25)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.30](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.29...@amplitude/plugin-page-view-tracking-browser@2.3.30) (2025-06-11)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.29](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.28...@amplitude/plugin-page-view-tracking-browser@2.3.29) (2025-06-03)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.28](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.28-main.0...@amplitude/plugin-page-view-tracking-browser@2.3.28) (2025-05-27)\n\n\n### Reverts\n\n* \"chore(release): publish\" ([#1094](https://github.com/amplitude/Amplitude-TypeScript/issues/1094)) ([f6db1ee](https://github.com/amplitude/Amplitude-TypeScript/commit/f6db1eed32ed77c7ce626624dc55972971f3b27d))\n\n\n\n\n\n## [2.3.27](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.26...@amplitude/plugin-page-view-tracking-browser@2.3.27) (2025-05-14)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.26](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.25...@amplitude/plugin-page-view-tracking-browser@2.3.26) (2025-05-13)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.25](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.24...@amplitude/plugin-page-view-tracking-browser@2.3.25) (2025-05-07)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.24](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.23...@amplitude/plugin-page-view-tracking-browser@2.3.24) (2025-05-05)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.23](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.22...@amplitude/plugin-page-view-tracking-browser@2.3.23) (2025-05-02)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.22](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.21...@amplitude/plugin-page-view-tracking-browser@2.3.22) (2025-05-02)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.21](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.20...@amplitude/plugin-page-view-tracking-browser@2.3.21) (2025-05-02)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.20](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.19...@amplitude/plugin-page-view-tracking-browser@2.3.20) (2025-04-30)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.19](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.18...@amplitude/plugin-page-view-tracking-browser@2.3.19) (2025-04-22)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.18](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.17...@amplitude/plugin-page-view-tracking-browser@2.3.18) (2025-04-17)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.17](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.16...@amplitude/plugin-page-view-tracking-browser@2.3.17) (2025-04-15)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.16](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.15...@amplitude/plugin-page-view-tracking-browser@2.3.16) (2025-04-10)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.15](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.14...@amplitude/plugin-page-view-tracking-browser@2.3.15) (2025-04-07)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.14](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.13...@amplitude/plugin-page-view-tracking-browser@2.3.14) (2025-04-07)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.12...@amplitude/plugin-page-view-tracking-browser@2.3.13) (2025-04-02)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.11...@amplitude/plugin-page-view-tracking-browser@2.3.12) (2025-03-24)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.10...@amplitude/plugin-page-view-tracking-browser@2.3.11) (2025-03-21)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.9...@amplitude/plugin-page-view-tracking-browser@2.3.10) (2025-03-14)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.8...@amplitude/plugin-page-view-tracking-browser@2.3.9) (2025-02-28)\n\n\n### Reverts\n\n* Revert \"chore(release): publish\" ([d392f62](https://github.com/amplitude/Amplitude-TypeScript/commit/d392f6290b8bb4dd955d6e6f20b00191679489c4))\n\n\n\n\n\n## [2.3.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.7...@amplitude/plugin-page-view-tracking-browser@2.3.8) (2025-02-14)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.6...@amplitude/plugin-page-view-tracking-browser@2.3.7) (2024-12-31)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.5...@amplitude/plugin-page-view-tracking-browser@2.3.6) (2024-12-17)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.4...@amplitude/plugin-page-view-tracking-browser@2.3.5) (2024-11-05)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.3...@amplitude/plugin-page-view-tracking-browser@2.3.4) (2024-10-21)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.2...@amplitude/plugin-page-view-tracking-browser@2.3.3) (2024-09-26)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.1...@amplitude/plugin-page-view-tracking-browser@2.3.2) (2024-09-18)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.3.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.3.0...@amplitude/plugin-page-view-tracking-browser@2.3.1) (2024-09-17)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n# [2.3.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.2.22...@amplitude/plugin-page-view-tracking-browser@2.3.0) (2024-09-16)\n\n\n### Bug Fixes\n\n* fix the pathOnly option ([#869](https://github.com/amplitude/Amplitude-TypeScript/issues/869)) ([2ac566e](https://github.com/amplitude/Amplitude-TypeScript/commit/2ac566e7eef76d0d4328ff55f1516f6eec5636d4))\n\n\n### Features\n\n* decode URI for page view properties ([#870](https://github.com/amplitude/Amplitude-TypeScript/issues/870)) ([aa1cc9d](https://github.com/amplitude/Amplitude-TypeScript/commit/aa1cc9dc93a86eacb5cb03e9c1c8a3d6cf7ed766))\n\n\n\n\n\n## [2.2.22](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.2.21...@amplitude/plugin-page-view-tracking-browser@2.2.22) (2024-09-10)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.2.21](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.2.20...@amplitude/plugin-page-view-tracking-browser@2.2.21) (2024-09-05)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.2.20](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.2.19...@amplitude/plugin-page-view-tracking-browser@2.2.20) (2024-08-23)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.2.19](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.2.18...@amplitude/plugin-page-view-tracking-browser@2.2.19) (2024-08-13)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.2.18](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.2.17...@amplitude/plugin-page-view-tracking-browser@2.2.18) (2024-08-02)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n## [2.2.17](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.2.16...@amplitude/plugin-page-view-tracking-browser@2.2.17) (2024-06-26)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n\n\n\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.16](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.2.15...@amplitude/plugin-page-view-tracking-browser@2.2.16) (2024-06-24)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.15](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.2.14...@amplitude/plugin-page-view-tracking-browser@2.2.15) (2024-06-24)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.14](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.2.13...@amplitude/plugin-page-view-tracking-browser@2.2.14) (2024-06-17)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.2.12...@amplitude/plugin-page-view-tracking-browser@2.2.13) (2024-05-24)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.2.11...@amplitude/plugin-page-view-tracking-browser@2.2.12) (2024-05-21)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.2.10...@amplitude/plugin-page-view-tracking-browser@2.2.11) (2024-05-17)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.2.9...@amplitude/plugin-page-view-tracking-browser@2.2.10) (2024-05-15)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.2.8...@amplitude/plugin-page-view-tracking-browser@2.2.9) (2024-05-07)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.2.7...@amplitude/plugin-page-view-tracking-browser@2.2.8) (2024-05-03)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.2.7-beta.0...@amplitude/plugin-page-view-tracking-browser@2.2.7) (2024-04-29)\n\n### Bug Fixes\n\n- [AMP-95816] fix pageCounter bug ([#720](https://github.com/amplitude/Amplitude-TypeScript/issues/720))\n  ([8899853](https://github.com/amplitude/Amplitude-TypeScript/commit/88998534b3bd3c88e66fb88bafd41768e41d377c))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.7-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.2.6...@amplitude/plugin-page-view-tracking-browser@2.2.7-beta.0) (2024-04-19)\n\n### Bug Fixes\n\n- fix web attribution identify and session start order\n  ([#696](https://github.com/amplitude/Amplitude-TypeScript/issues/696))\n  ([2f077da](https://github.com/amplitude/Amplitude-TypeScript/commit/2f077da7b528ed6f23f7459b7c961c099dbcb1bb))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.2.6-beta.0...@amplitude/plugin-page-view-tracking-browser@2.2.6) (2024-04-09)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.6-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.2.5...@amplitude/plugin-page-view-tracking-browser@2.2.6-beta.0) (2024-03-28)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.2.4...@amplitude/plugin-page-view-tracking-browser@2.2.5) (2024-03-27)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.2.3...@amplitude/plugin-page-view-tracking-browser@2.2.4) (2024-03-23)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.2.2...@amplitude/plugin-page-view-tracking-browser@2.2.3) (2024-03-12)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.2.1...@amplitude/plugin-page-view-tracking-browser@2.2.2) (2024-02-27)\n\n### Bug Fixes\n\n- Page counter fix ([#670](https://github.com/amplitude/Amplitude-TypeScript/issues/670))\n  ([1bd9105](https://github.com/amplitude/Amplitude-TypeScript/commit/1bd9105a788d068a2803af91797f8db741ce3a83))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.2.0...@amplitude/plugin-page-view-tracking-browser@2.2.1) (2024-02-23)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.2.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.1.1...@amplitude/plugin-page-view-tracking-browser@2.2.0) (2024-02-23)\n\n### Features\n\n- landing page improvement ([#667](https://github.com/amplitude/Amplitude-TypeScript/issues/667))\n  ([5f365f0](https://github.com/amplitude/Amplitude-TypeScript/commit/5f365f0b933ee890aee1d9ac083576f09b0defc3))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.1.0...@amplitude/plugin-page-view-tracking-browser@2.1.1) (2024-02-13)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.1.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.0.18...@amplitude/plugin-page-view-tracking-browser@2.1.0) (2024-01-24)\n\n### Features\n\n- add offline mode ([#644](https://github.com/amplitude/Amplitude-TypeScript/issues/644))\n  ([f2cd717](https://github.com/amplitude/Amplitude-TypeScript/commit/f2cd717316eef66b101153cb8eedf37fadc6de0c))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.18](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.0.17...@amplitude/plugin-page-view-tracking-browser@2.0.18) (2023-12-20)\n\n### Reverts\n\n- update attribution plugin to apply utm params to the `session_start` event\n  ([#638](https://github.com/amplitude/Amplitude-TypeScript/issues/638))\n  ([c820279](https://github.com/amplitude/Amplitude-TypeScript/commit/c820279cbef2123d890beb7861d7edbbc3926f6e))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.17](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.0.16...@amplitude/plugin-page-view-tracking-browser@2.0.17) (2023-12-12)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.16](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.0.16-beta.0...@amplitude/plugin-page-view-tracking-browser@2.0.16) (2023-12-01)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.16-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.0.15...@amplitude/plugin-page-view-tracking-browser@2.0.16-beta.0) (2023-11-22)\n\n### Bug Fixes\n\n- update attribution plugin to apply utm params to the `session_start` event\n  ([#619](https://github.com/amplitude/Amplitude-TypeScript/issues/619))\n  ([bf45ca6](https://github.com/amplitude/Amplitude-TypeScript/commit/bf45ca6c17ac8d656cb6c5bb4f4fa19ff344ac85))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.15](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.0.14...@amplitude/plugin-page-view-tracking-browser@2.0.15) (2023-11-16)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.14](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.0.13...@amplitude/plugin-page-view-tracking-browser@2.0.14) (2023-11-16)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.0.12...@amplitude/plugin-page-view-tracking-browser@2.0.13) (2023-10-18)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.0.11...@amplitude/plugin-page-view-tracking-browser@2.0.12) (2023-09-26)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.0.10...@amplitude/plugin-page-view-tracking-browser@2.0.11) (2023-09-18)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.0.9...@amplitude/plugin-page-view-tracking-browser@2.0.10) (2023-09-15)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.0.8...@amplitude/plugin-page-view-tracking-browser@2.0.9) (2023-08-31)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.0.7...@amplitude/plugin-page-view-tracking-browser@2.0.8) (2023-08-29)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.0.6...@amplitude/plugin-page-view-tracking-browser@2.0.7) (2023-08-24)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.0.5...@amplitude/plugin-page-view-tracking-browser@2.0.6) (2023-08-15)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.0.4...@amplitude/plugin-page-view-tracking-browser@2.0.5) (2023-07-27)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.0.3...@amplitude/plugin-page-view-tracking-browser@2.0.4) (2023-07-03)\n\n### Bug Fixes\n\n- handle concurrent history push state calls ([#466](https://github.com/amplitude/Amplitude-TypeScript/issues/466))\n  ([f261e73](https://github.com/amplitude/Amplitude-TypeScript/commit/f261e7354aae5450ce51a5b13eb70b9ad780a4ca))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.0.2...@amplitude/plugin-page-view-tracking-browser@2.0.3) (2023-06-30)\n\n### Bug Fixes\n\n- allow plugins to teardown to remove listeners ([#460](https://github.com/amplitude/Amplitude-TypeScript/issues/460))\n  ([c337363](https://github.com/amplitude/Amplitude-TypeScript/commit/c337363c25b0a1285e8df455511516fc0a9bec7e))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.0.1...@amplitude/plugin-page-view-tracking-browser@2.0.2) (2023-06-22)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.0.0...@amplitude/plugin-page-view-tracking-browser@2.0.1) (2023-06-21)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.0.0-beta.10...@amplitude/plugin-page-view-tracking-browser@2.0.0) (2023-06-14)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.0.0-beta.9...@amplitude/plugin-page-view-tracking-browser@2.0.0-beta.10) (2023-06-14)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.0.0-beta.8...@amplitude/plugin-page-view-tracking-browser@2.0.0-beta.9) (2023-06-14)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.0.0-beta.7...@amplitude/plugin-page-view-tracking-browser@2.0.0-beta.8) (2023-06-13)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.0.0-beta.6...@amplitude/plugin-page-view-tracking-browser@2.0.0-beta.7) (2023-06-13)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.0.0-beta.5...@amplitude/plugin-page-view-tracking-browser@2.0.0-beta.6) (2023-06-09)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.0.0-beta.4...@amplitude/plugin-page-view-tracking-browser@2.0.0-beta.5) (2023-06-08)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.0.0-beta.3...@amplitude/plugin-page-view-tracking-browser@2.0.0-beta.4) (2023-06-07)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.0.0-beta.2...@amplitude/plugin-page-view-tracking-browser@2.0.0-beta.3) (2023-06-07)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@2.0.0-beta.1...@amplitude/plugin-page-view-tracking-browser@2.0.0-beta.2) (2023-06-06)\n\n### Bug Fixes\n\n- simplify plugins and eliminate enums ([#407](https://github.com/amplitude/Amplitude-TypeScript/issues/407))\n  ([890ec66](https://github.com/amplitude/Amplitude-TypeScript/commit/890ec6695a8b25cd6988e9f7ae584d4ba2835f67))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.8.2...@amplitude/plugin-page-view-tracking-browser@2.0.0-beta.1) (2023-06-06)\n\n### Bug Fixes\n\n- dependency tree\n  ([d7ce659](https://github.com/amplitude/Amplitude-TypeScript/commit/d7ce659c72321c373346bab0f4c0e6d23304e1b6))\n- dyanamic page view tracking to run after navigation\n  ([#395](https://github.com/amplitude/Amplitude-TypeScript/issues/395))\n  ([484d8f6](https://github.com/amplitude/Amplitude-TypeScript/commit/484d8f61955e7bf169576b3a0c588bf9f440e726))\n\n### Features\n\n- simplify browser SDK options and plugin options interface\n  ([#384](https://github.com/amplitude/Amplitude-TypeScript/issues/384))\n  ([b464cfb](https://github.com/amplitude/Amplitude-TypeScript/commit/b464cfb8e09d722bf06ed3c11955f77465a23daf))\n- simplify user identity storage options/configuration\n  ([#390](https://github.com/amplitude/Amplitude-TypeScript/issues/390))\n  ([f8cf0cc](https://github.com/amplitude/Amplitude-TypeScript/commit/f8cf0cca8c2a17738f13878642fa5b37c0070f77))\n- track page dynamic page views in single page applications be default\n  ([#394](https://github.com/amplitude/Amplitude-TypeScript/issues/394))\n  ([7ce6b3a](https://github.com/amplitude/Amplitude-TypeScript/commit/7ce6b3ac610cded95e817a16d22fac82ec21c4e4))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.8.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.8.1...@amplitude/plugin-page-view-tracking-browser@0.8.2) (2023-06-05)\n\n### Bug Fixes\n\n- Reference error for location ([#398](https://github.com/amplitude/Amplitude-TypeScript/issues/398))\n  ([85f063e](https://github.com/amplitude/Amplitude-TypeScript/commit/85f063e65165b3571366e96dfecb866c6286670b))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.8.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.8.0...@amplitude/plugin-page-view-tracking-browser@0.8.1) (2023-06-02)\n\n### Bug Fixes\n\n- dyanamic page view tracking to run after navigation\n  ([#396](https://github.com/amplitude/Amplitude-TypeScript/issues/396))\n  ([31d6435](https://github.com/amplitude/Amplitude-TypeScript/commit/31d6435b0f50da89302e83431a6fb5c1b46ec71b))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.8.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.7.3...@amplitude/plugin-page-view-tracking-browser@0.8.0) (2023-05-04)\n\n### Features\n\n- add attribution tracking for linkedin click id li_fat_id\n  ([ca81f3d](https://github.com/amplitude/Amplitude-TypeScript/commit/ca81f3d75ece7e0e23a1bc1b6889107d53a60a86))\n- add rtd_cid for Reddit campaign tracking/attribution\n  ([784e080](https://github.com/amplitude/Amplitude-TypeScript/commit/784e080aa129c37e850d7f34115beb9770044e4e))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.7.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.7.2...@amplitude/plugin-page-view-tracking-browser@0.7.3) (2023-04-27)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.7.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.7.1...@amplitude/plugin-page-view-tracking-browser@0.7.2) (2023-04-27)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.7.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.7.0...@amplitude/plugin-page-view-tracking-browser@0.7.1) (2023-04-25)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.7.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.6.3...@amplitude/plugin-page-view-tracking-browser@0.7.0) (2023-04-06)\n\n### Features\n\n- update Plugin implementation to allow for dropping events\n  ([#361](https://github.com/amplitude/Amplitude-TypeScript/issues/361))\n  ([3db4d13](https://github.com/amplitude/Amplitude-TypeScript/commit/3db4d1327e87ebcf7a2a8c1d50a62e5c8bc2b418))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.6.2...@amplitude/plugin-page-view-tracking-browser@0.6.3) (2023-03-31)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.6.2-beta.0...@amplitude/plugin-page-view-tracking-browser@0.6.2) (2023-03-31)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.2-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.6.1...@amplitude/plugin-page-view-tracking-browser@0.6.2-beta.0) (2023-03-31)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.6.1-beta.1...@amplitude/plugin-page-view-tracking-browser@0.6.1) (2023-03-03)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.1-beta.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.6.1-beta.0...@amplitude/plugin-page-view-tracking-browser@0.6.1-beta.1) (2023-03-03)\n\n### Bug Fixes\n\n- event types and properties for default events ([#341](https://github.com/amplitude/Amplitude-TypeScript/issues/341))\n  ([707522d](https://github.com/amplitude/Amplitude-TypeScript/commit/707522d440d5aa3be48809afcb44a4147f103903))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.1-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.6.0...@amplitude/plugin-page-view-tracking-browser@0.6.1-beta.0) (2023-03-03)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.6.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.6.0-beta.4...@amplitude/plugin-page-view-tracking-browser@0.6.0) (2023-02-27)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.6.0-beta.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.6.0-beta.3...@amplitude/plugin-page-view-tracking-browser@0.6.0-beta.4) (2023-02-27)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.6.0-beta.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.6.0-beta.2...@amplitude/plugin-page-view-tracking-browser@0.6.0-beta.3) (2023-02-26)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.6.0-beta.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.6.0-beta.1...@amplitude/plugin-page-view-tracking-browser@0.6.0-beta.2) (2023-02-25)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.6.0-beta.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.6.0-beta.0...@amplitude/plugin-page-view-tracking-browser@0.6.0-beta.1) (2023-02-24)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.6.0-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.5.7...@amplitude/plugin-page-view-tracking-browser@0.6.0-beta.0) (2023-02-24)\n\n### Bug Fixes\n\n- remove client parameter requirement for page view tracking plugin\n  ([#329](https://github.com/amplitude/Amplitude-TypeScript/issues/329))\n  ([1e01575](https://github.com/amplitude/Amplitude-TypeScript/commit/1e015750b52880ca63afa5162cb482995f04d1c6))\n\n### Features\n\n- allow custom page view event type ([#335](https://github.com/amplitude/Amplitude-TypeScript/issues/335))\n  ([0a4f8ed](https://github.com/amplitude/Amplitude-TypeScript/commit/0a4f8ede6e30ec3450ac0a468cf22b9266b0b23c))\n- retrofit web attribution and page view plugins to browser SDK\n  ([#331](https://github.com/amplitude/Amplitude-TypeScript/issues/331))\n  ([ba845d3](https://github.com/amplitude/Amplitude-TypeScript/commit/ba845d3329bd6bebe3b89f24f4f316088c2d62b9))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.5.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.5.6...@amplitude/plugin-page-view-tracking-browser@0.5.7) (2023-02-09)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.5.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.5.5...@amplitude/plugin-page-view-tracking-browser@0.5.6) (2023-02-02)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.5.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.5.5-beta.0...@amplitude/plugin-page-view-tracking-browser@0.5.5) (2023-01-31)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.5.5-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.5.4...@amplitude/plugin-page-view-tracking-browser@0.5.5-beta.0) (2023-01-26)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.5.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.5.3...@amplitude/plugin-page-view-tracking-browser@0.5.4) (2023-01-11)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.5.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.5.2...@amplitude/plugin-page-view-tracking-browser@0.5.3) (2022-12-21)\n\n### Bug Fixes\n\n- upgrade dependencies to resolve dependabot vulnerability alerts\n  ([#299](https://github.com/amplitude/Amplitude-TypeScript/issues/299))\n  ([7dd1cd1](https://github.com/amplitude/Amplitude-TypeScript/commit/7dd1cd1b23a71981a4ad90b4b30cc9b7d28c4412))\n\n### Reverts\n\n- Revert \"Updated dependencies\"\n  ([7ca9964](https://github.com/amplitude/Amplitude-TypeScript/commit/7ca9964781e4b900c6c027bdddf2ae1e7428ba18))\n\n## [0.5.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.5.1...@amplitude/plugin-page-view-tracking-browser@0.5.2) (2022-12-06)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n## [0.5.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.5.0...@amplitude/plugin-page-view-tracking-browser@0.5.1) (2022-12-05)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# [0.5.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.4.9...@amplitude/plugin-page-view-tracking-browser@0.5.0) (2022-11-28)\n\n### Features\n\n- add utm_id tracking ([#284](https://github.com/amplitude/Amplitude-TypeScript/issues/284))\n  ([f72dcf1](https://github.com/amplitude/Amplitude-TypeScript/commit/f72dcf1788ebc84544aaee1dc41b1d1ba6e4c06e))\n\n## [0.4.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.4.8...@amplitude/plugin-page-view-tracking-browser@0.4.9) (2022-11-22)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n## [0.4.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.4.7...@amplitude/plugin-page-view-tracking-browser@0.4.8) (2022-11-15)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n## [0.4.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.4.6...@amplitude/plugin-page-view-tracking-browser@0.4.7) (2022-11-01)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n## [0.4.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.4.5...@amplitude/plugin-page-view-tracking-browser@0.4.6) (2022-11-01)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n## [0.4.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.4.4...@amplitude/plugin-page-view-tracking-browser@0.4.5) (2022-10-30)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n## [0.4.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.4.3...@amplitude/plugin-page-view-tracking-browser@0.4.4) (2022-10-26)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n## [0.4.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.4.3-beta.1...@amplitude/plugin-page-view-tracking-browser@0.4.3) (2022-10-25)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n## [0.4.3-beta.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.4.3-beta.0...@amplitude/plugin-page-view-tracking-browser@0.4.3-beta.1) (2022-10-25)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n## [0.4.3-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.4.2...@amplitude/plugin-page-view-tracking-browser@0.4.3-beta.0) (2022-10-25)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n## [0.4.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.4.1...@amplitude/plugin-page-view-tracking-browser@0.4.2) (2022-10-25)\n\n### Bug Fixes\n\n- add safe check for global scope before loading SDK\n  ([#252](https://github.com/amplitude/Amplitude-TypeScript/issues/252))\n  ([a3f4f6f](https://github.com/amplitude/Amplitude-TypeScript/commit/a3f4f6f7b11abd9cdbdf064e31e32d5fc3e92031))\n\n## [0.4.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.4.0...@amplitude/plugin-page-view-tracking-browser@0.4.1) (2022-10-14)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# [0.4.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.3.4...@amplitude/plugin-page-view-tracking-browser@0.4.0) (2022-10-04)\n\n### Features\n\n- add gbraid and wbraid as campaign parameters ([#242](https://github.com/amplitude/Amplitude-TypeScript/issues/242))\n  ([514b7cd](https://github.com/amplitude/Amplitude-TypeScript/commit/514b7cdea9fee0c4e61479b087f7acdfea889350))\n\n## [0.3.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.3.3...@amplitude/plugin-page-view-tracking-browser@0.3.4) (2022-09-30)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n## [0.3.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.3.2...@amplitude/plugin-page-view-tracking-browser@0.3.3) (2022-09-30)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n## [0.3.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.3.2-beta.2...@amplitude/plugin-page-view-tracking-browser@0.3.2) (2022-09-28)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n## [0.3.2-beta.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.3.2-beta.1...@amplitude/plugin-page-view-tracking-browser@0.3.2-beta.2) (2022-09-27)\n\n### Bug Fixes\n\n- js script export name for marketing analytics plugins\n  ([aa7b05c](https://github.com/amplitude/Amplitude-TypeScript/commit/aa7b05cb192e23924081a363f3567573f76a3b62))\n\n## [0.3.2-beta.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.3.2-beta.0...@amplitude/plugin-page-view-tracking-browser@0.3.2-beta.1) (2022-09-27)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n## [0.3.2-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.3.1...@amplitude/plugin-page-view-tracking-browser@0.3.2-beta.0) (2022-09-26)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n## [0.3.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.3.0...@amplitude/plugin-page-view-tracking-browser@0.3.1) (2022-09-26)\n\n**Note:** Version bump only for package @amplitude/plugin-page-view-tracking-browser\n\n# [0.3.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.2.0...@amplitude/plugin-page-view-tracking-browser@0.3.0) (2022-09-26)\n\n### Bug Fixes\n\n- update base config to include additional click ids\n  ([#229](https://github.com/amplitude/Amplitude-TypeScript/issues/229))\n  ([5596931](https://github.com/amplitude/Amplitude-TypeScript/commit/55969310714c43f138e1702ba285fd4dadcdcb44))\n\n### Features\n\n- add single page app page view tracking option ([#224](https://github.com/amplitude/Amplitude-TypeScript/issues/224))\n  ([2d97c9e](https://github.com/amplitude/Amplitude-TypeScript/commit/2d97c9ef8501da04465225ef8366fe0419b3415a))\n\n# [0.2.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-page-view-tracking-browser@0.1.0...@amplitude/plugin-page-view-tracking-browser@0.2.0) (2022-09-22)\n\n### Features\n\n- add campaign params to page view events ([#216](https://github.com/amplitude/Amplitude-TypeScript/issues/216))\n  ([c0f99b9](https://github.com/amplitude/Amplitude-TypeScript/commit/c0f99b98d0d2c24f6f9486312b568194c690a202))\n\n# 0.1.0 (2022-09-16)\n\n### Features\n\n- new marketing analytics plugin ([#213](https://github.com/amplitude/Amplitude-TypeScript/issues/213))\n  ([02ff174](https://github.com/amplitude/Amplitude-TypeScript/commit/02ff174e3361173dbf15ed3acf72e950810e174f))\n"
  },
  {
    "path": "packages/plugin-page-view-tracking-browser/README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://amplitude.com\" target=\"_blank\" align=\"center\">\n    <img src=\"https://static.amplitude.com/lightning/46c85bfd91905de8047f1ee65c7c93d6fa9ee6ea/static/media/amplitude-logo-with-text.4fb9e463.svg\" width=\"280\">\n  </a>\n  <br />\n</p>\n\n# @amplitude/plugin-page-view-tracking-browser\n\nOfficial Browser SDK plugin for page view tracking\n\n## Installation\n\nThis package is published on NPM registry and is available to be installed using npm and yarn.\n\n```sh\n# npm\nnpm install @amplitude/plugin-page-view-tracking-browser\n\n# yarn\nyarn add @amplitude/plugin-page-view-tracking-browser\n```\n\n## Usage\n\nThis plugin works on top of Amplitude Browser SDK and adds page view tracking features to built-in features. To use this plugin, you need to install `@amplitude/analytics-browser` version `v2.0.0` or later.\n\n### 1. Import Amplitude packages\n\n* `@amplitude/plugin-page-view-tracking-browser`\n\n```typescript\nimport { pageViewTrackingPlugin } from '@amplitude/plugin-page-view-tracking-browser';\n```\n\n### 2. Instantiate page view plugin\n\nThe plugin accepts an optional parameter of type `Object` to configure the plugin based on your use case.\n\n```typescript\nconst pageViewTracking = pageViewTrackingPlugin({\n  trackOn: undefined,\n  trackHistoryChanges: undefined,\n});\n```\n\n#### Options\n\n|Name|Type|Default|Description|\n|-|-|-|-|\n|`trackOn`|`\"attribution\"` or `() => boolean`|`undefined`|Use this option to control when to track a page view event. By default, a page view event is sent on each SDK initialization.<br/><br/>Use `() => boolean` to control sending page view events using custom conditional logic.<br/><br/>Use `\"attribution\"` to send page view events with attribution events. This option requires using [@amplitude/plugin-web-attribution-browser](https://github.com/amplitude/Amplitude-TypeScript/tree/main/packages/plugin-web-attribution-browser).|\n|`trackHistoryChanges`|`\"all\"` or `\"pathOnly\"`|`undefined`|Use this option to subscribe to page view changes based on full URL or URL path in a single page application like React.js. By default, page view changes are based on full URL.<br/><br/>Use `\"all\"` to compare the full url changes.<br/><br/>Use `\"pathOnly\"` to compare only url path changes.|\n\n### 3. Install plugin to Amplitude SDK\n\n```typescript\namplitude.add(pageViewTracking);\n```\n\n### 4. Initialize Amplitude SDK\n\n```typescript\namplitude.init('API_KEY');\n```\n\n## Resulting page view event\n\nThis plugin tracks page views based on your configuration. A page view event is composed of the following values:\n\n#### Event type\n* `\"[Amplitude ]Page Viewed\"`\n\n#### Event properties\n\n|Property|Description|\n|-|-|\n|`'[Amplitude] Page Domain'`|The website's hostname or `location.hostname`|\n|`'[Amplitude] Page Location'`|The website's full url or `location.href`|\n|`'[Amplitude] Page Path'`|The website's pathname or `location.pathname`|\n|`'[Amplitude] Page Title'`|The website's title or `document.title`|\n|`'[Amplitude] Page URL'`|The website's url excluding query parameters|\n"
  },
  {
    "path": "packages/plugin-page-view-tracking-browser/jest.config.js",
    "content": "const baseConfig = require('../../jest.config.js');\nconst package = require('./package');\n\nmodule.exports = {\n  ...baseConfig,\n  displayName: package.name,\n  rootDir: '.',\n  testEnvironment: 'jsdom',\n  coveragePathIgnorePatterns: ['index.ts'],\n};\n"
  },
  {
    "path": "packages/plugin-page-view-tracking-browser/package.json",
    "content": "{\n  \"name\": \"@amplitude/plugin-page-view-tracking-browser\",\n  \"version\": \"2.11.0\",\n  \"description\": \"\",\n  \"author\": \"Amplitude Inc\",\n  \"homepage\": \"https://github.com/amplitude/Amplitude-TypeScript\",\n  \"license\": \"MIT\",\n  \"main\": \"lib/cjs/index.js\",\n  \"module\": \"lib/esm/index.js\",\n  \"types\": \"lib/esm/index.d.ts\",\n  \"sideEffects\": false,\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"tag\": \"latest\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/amplitude/Amplitude-TypeScript.git\"\n  },\n  \"scripts\": {\n    \"build\": \"pnpm bundle && pnpm build:es5 && pnpm build:esm\",\n    \"bundle\": \"rollup --config rollup.config.js\",\n    \"build:es5\": \"tsc -p ./tsconfig.es5.json\",\n    \"build:esm\": \"tsc -p ./tsconfig.esm.json\",\n    \"watch\": \"tsc -p ./tsconfig.esm.json --watch\",\n    \"clean\": \"rimraf node_modules lib coverage\",\n    \"fix\": \"pnpm fix:eslint & pnpm fix:prettier\",\n    \"fix:eslint\": \"eslint '{src,test}/**/*.ts' --fix\",\n    \"fix:prettier\": \"prettier --write \\\"{src,test}/**/*.ts\\\"\",\n    \"lint\": \"pnpm lint:eslint & pnpm lint:prettier\",\n    \"lint:eslint\": \"eslint '{src,test}/**/*.ts'\",\n    \"lint:prettier\": \"prettier --check \\\"{src,test}/**/*.ts\\\"\",\n    \"test\": \"jest\",\n    \"typecheck\": \"tsc -p ./tsconfig.json\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/amplitude/Amplitude-TypeScript/issues\"\n  },\n  \"dependencies\": {\n    \"@amplitude/analytics-core\": \"workspace:*\",\n    \"tslib\": \"^2.4.1\"\n  },\n  \"devDependencies\": {\n    \"@rollup/plugin-commonjs\": \"^23.0.4\",\n    \"@rollup/plugin-node-resolve\": \"^15.0.1\",\n    \"@rollup/plugin-typescript\": \"^10.0.1\",\n    \"rollup\": \"^2.79.1\",\n    \"rollup-plugin-execute\": \"^1.1.1\",\n    \"rollup-plugin-gzip\": \"^3.1.0\",\n    \"rollup-plugin-terser\": \"^7.0.2\"\n  },\n  \"files\": [\n    \"lib\"\n  ]\n}\n"
  },
  {
    "path": "packages/plugin-page-view-tracking-browser/rollup.config.js",
    "content": "import { umd } from '../../scripts/build/rollup.config';\n\nexport default [umd];\n"
  },
  {
    "path": "packages/plugin-page-view-tracking-browser/src/index.ts",
    "content": "export { pageViewTrackingPlugin } from './page-view-tracking';\nexport { pageViewTrackingPlugin as plugin } from './page-view-tracking';\n"
  },
  {
    "path": "packages/plugin-page-view-tracking-browser/src/page-view-tracking.ts",
    "content": "import {\n  getPageTitle,\n  replaceSensitiveString,\n  BrowserConfig,\n  BrowserClient,\n  EnrichmentPlugin,\n  Event,\n  IdentifyOperation,\n  IdentifyUserProperties,\n  ILogger,\n  CampaignParser,\n  getGlobalScope,\n  BASE_CAMPAIGN,\n  BrowserStorage,\n  UUID,\n  omitUndefined,\n} from '@amplitude/analytics-core';\nimport { CreatePageViewTrackingPlugin, Options } from './typings/page-view-tracking';\n\nexport const defaultPageViewEvent = '[Amplitude] Page Viewed';\nexport const PAGE_VIEW_SESSION_STORAGE_KEY = 'AMP_PAGE_VIEW';\n\ntype PageViewSessionStorage = {\n  pageViewId: string;\n};\n\nexport const pageViewTrackingPlugin: CreatePageViewTrackingPlugin = (options: Options = {}) => {\n  let amplitude: BrowserClient | undefined;\n  const globalScope = getGlobalScope();\n  let loggerProvider: ILogger | undefined = undefined;\n  let isTracking = false;\n  let localConfig: BrowserConfig;\n  let sessionStorage: BrowserStorage<PageViewSessionStorage> | undefined;\n  const { trackOn, trackHistoryChanges, eventType = defaultPageViewEvent } = options;\n\n  const getDecodeURI = (locationStr: string): string => {\n    let decodedLocationStr = locationStr;\n    try {\n      decodedLocationStr = decodeURI(locationStr);\n    } catch (e) {\n      /* istanbul ignore next */\n      loggerProvider?.error('Malformed URI sequence: ', e);\n    }\n\n    return decodedLocationStr;\n  };\n\n  const createPageViewEvent = async (pageViewId: string | undefined): Promise<Event> => {\n    /* istanbul ignore next */\n    const locationHREF = getDecodeURI((typeof location !== 'undefined' && location.href) || '');\n    return {\n      event_type: eventType,\n      event_properties: {\n        ...(await getCampaignParams()),\n        '[Amplitude] Page Domain':\n          /* istanbul ignore next */ (typeof location !== 'undefined' && location.hostname) || '',\n        '[Amplitude] Page Location': locationHREF,\n        '[Amplitude] Page Path':\n          /* istanbul ignore next */ (typeof location !== 'undefined' && getDecodeURI(location.pathname)) || '',\n        '[Amplitude] Page Title': /* istanbul ignore next */ getPageTitle(replaceSensitiveString),\n        '[Amplitude] Page URL': locationHREF.split('?')[0],\n        '[Amplitude] Page View ID': pageViewId,\n      },\n    };\n  };\n\n  const shouldTrackOnPageLoad = () => typeof trackOn === 'undefined' || (typeof trackOn === 'function' && trackOn());\n\n  /* istanbul ignore next */\n  let previousURL: string | null = typeof location !== 'undefined' ? location.href : null;\n\n  const trackHistoryPageView = async (): Promise<void> => {\n    const newURL = location.href;\n    const shouldTrackPageView =\n      shouldTrackHistoryPageView(trackHistoryChanges, newURL, previousURL || '') && shouldTrackOnPageLoad();\n    // Note: Update `previousURL` in the same clock tick as `shouldTrackHistoryPageView()`\n    // This was previously done after `amplitude?.track(await createPageViewEvent());` and\n    // causes a concurrency issue where app triggers `pushState` twice with the same URL target\n    // but `previousURL` is only updated after the second `pushState` producing two page viewed events\n    previousURL = newURL;\n\n    if (shouldTrackPageView) {\n      // Generate new page view id and set it in session storage\n      let pageViewId: string | undefined;\n      if (sessionStorage) {\n        pageViewId = UUID();\n        void sessionStorage.set(PAGE_VIEW_SESSION_STORAGE_KEY, { pageViewId });\n      }\n\n      /* istanbul ignore next */\n      loggerProvider?.log('Tracking page view event');\n      amplitude?.track(await createPageViewEvent(pageViewId));\n    }\n  };\n\n  /* istanbul ignore next */\n  const handlePageChange = () => {\n    void trackHistoryPageView();\n  };\n\n  const plugin: EnrichmentPlugin = {\n    name: '@amplitude/plugin-page-view-tracking-browser',\n    type: 'enrichment',\n\n    setup: async (config: BrowserConfig, client: BrowserClient) => {\n      amplitude = client;\n      localConfig = config;\n\n      loggerProvider = config.loggerProvider;\n      loggerProvider.log('Installing @amplitude/plugin-page-view-tracking-browser');\n\n      isTracking = true;\n      if (globalScope) {\n        // init session storage\n        try {\n          sessionStorage = new BrowserStorage<PageViewSessionStorage>(globalScope.sessionStorage);\n        } catch (error) {\n          /* istanbul ignore next */\n          loggerProvider?.debug('sessionStorage is not available in this environment.');\n        }\n\n        globalScope.addEventListener('popstate', handlePageChange);\n\n        /* istanbul ignore next */\n        // There is no global browser listener for changes to history, so we have\n        // to modify pushState directly.\n        // https://stackoverflow.com/a/64927639\n        // eslint-disable-next-line @typescript-eslint/unbound-method\n        globalScope.history.pushState = new Proxy(globalScope.history.pushState, {\n          apply: (target, thisArg, [state, unused, url]) => {\n            target.apply(thisArg, [state, unused, url]);\n            if (isTracking) {\n              handlePageChange();\n            }\n          },\n        });\n      }\n\n      if (shouldTrackOnPageLoad()) {\n        loggerProvider.log('Tracking page view event');\n        // Generate new page view id and set it in session storage\n        let pageViewId: string | undefined;\n\n        if (sessionStorage) {\n          pageViewId = UUID();\n          void sessionStorage.set(PAGE_VIEW_SESSION_STORAGE_KEY, { pageViewId });\n        }\n\n        amplitude.track(await createPageViewEvent(pageViewId));\n      }\n    },\n\n    execute: async (event: Event) => {\n      if (trackOn === 'attribution' && isCampaignEvent(event)) {\n        /* istanbul ignore next */ // loggerProvider should be defined by the time execute is invoked\n        loggerProvider?.log('Enriching campaign event to page view event with campaign parameters');\n        // Retrieve current page view id from session storage\n        let pageViewId: string | undefined;\n        if (sessionStorage) {\n          const pageViewSession = await sessionStorage.get(PAGE_VIEW_SESSION_STORAGE_KEY);\n          pageViewId = pageViewSession?.pageViewId;\n        }\n\n        const pageViewEvent = await createPageViewEvent(pageViewId);\n        event.event_type = pageViewEvent.event_type;\n        event.event_properties = {\n          ...event.event_properties,\n          ...pageViewEvent.event_properties,\n        };\n      }\n\n      // Update the pageCounter for the page view event\n      if (localConfig && event.event_type === eventType) {\n        localConfig.pageCounter = !localConfig.pageCounter ? 1 : localConfig.pageCounter + 1;\n        event.event_properties = {\n          ...event.event_properties,\n          '[Amplitude] Page Counter': localConfig.pageCounter,\n        };\n      }\n      return event;\n    },\n\n    teardown: async () => {\n      if (globalScope) {\n        globalScope.removeEventListener('popstate', handlePageChange);\n        isTracking = false;\n      }\n    },\n  };\n  return plugin;\n};\n\nconst getCampaignParams = async () => omitUndefined(await new CampaignParser().parse());\n\nconst isCampaignEvent = (event: Event) => {\n  if (event.event_type === '$identify' && event.user_properties) {\n    const properties = event.user_properties as IdentifyUserProperties;\n    const $set = properties[IdentifyOperation.SET] || {};\n    const $unset = properties[IdentifyOperation.UNSET] || {};\n    const userProperties = [...Object.keys($set), ...Object.keys($unset)];\n    return Object.keys(BASE_CAMPAIGN).every((value) => userProperties.includes(value));\n  }\n  return false;\n};\n\nexport const shouldTrackHistoryPageView = (\n  trackingOption: Options['trackHistoryChanges'],\n  newURLStr: string,\n  oldURLStr: string,\n): boolean => {\n  switch (trackingOption) {\n    case 'pathOnly': {\n      if (oldURLStr == '') return true;\n      const newURL = new URL(newURLStr);\n      const oldURL = new URL(oldURLStr);\n      const newBaseStr = newURL.origin + newURL.pathname;\n      const oldBaseStr = oldURL.origin + oldURL.pathname;\n      return newBaseStr !== oldBaseStr;\n    }\n    default:\n      return newURLStr !== oldURLStr;\n  }\n};\n"
  },
  {
    "path": "packages/plugin-page-view-tracking-browser/src/typings/page-view-tracking.ts",
    "content": "import { EnrichmentPlugin, PageTrackingOptions as Options } from '@amplitude/analytics-core';\n\nexport {\n  PageTrackingOptions as Options,\n  PageTrackingTrackOn,\n  PageTrackingHistoryChanges,\n} from '@amplitude/analytics-core';\n\nexport interface CreatePageViewTrackingPlugin {\n  (options?: Options): EnrichmentPlugin;\n}\n"
  },
  {
    "path": "packages/plugin-page-view-tracking-browser/test/mock-browser-client.ts",
    "content": "import { BrowserClient } from '@amplitude/analytics-core';\n\n// Mock BrowserClient implementation\nexport const createMockBrowserClient = (): jest.Mocked<BrowserClient> => {\n  const mockClient = {\n    init: jest.fn(),\n    add: jest.fn(),\n    remove: jest.fn(),\n    track: jest.fn(),\n    logEvent: jest.fn(),\n    identify: jest.fn(),\n    groupIdentify: jest.fn(),\n    setGroup: jest.fn(),\n    revenue: jest.fn(),\n    flush: jest.fn(),\n    getUserId: jest.fn(),\n    setUserId: jest.fn(),\n    getDeviceId: jest.fn(),\n    setDeviceId: jest.fn(),\n    getSessionId: jest.fn(),\n    setSessionId: jest.fn(),\n    extendSession: jest.fn(),\n    reset: jest.fn(),\n    setOptOut: jest.fn(),\n    setTransport: jest.fn(),\n    _setDiagnosticsSampleRate: jest.fn(),\n    getOptOut: jest.fn(),\n    getIdentity: jest.fn(),\n    setIdentity: jest.fn(),\n  } as jest.Mocked<BrowserClient>;\n\n  // Set up default return values for methods that return promises\n  mockClient.init.mockReturnValue({\n    promise: Promise.resolve(),\n  });\n\n  mockClient.track.mockReturnValue({\n    promise: Promise.resolve({\n      code: 200,\n      message: '',\n      event: {\n        event_type: '[Amplitude] Page Viewed',\n      },\n    }),\n  });\n\n  return mockClient;\n};\n"
  },
  {
    "path": "packages/plugin-page-view-tracking-browser/test/page-view-tracking.test.ts",
    "content": "import {\n  Logger,\n  UUID,\n  BrowserClient,\n  BrowserConfig,\n  LogLevel,\n  getGlobalScope,\n  CookieStorage,\n  FetchTransport,\n} from '@amplitude/analytics-core';\nimport {\n  defaultPageViewEvent,\n  pageViewTrackingPlugin,\n  shouldTrackHistoryPageView,\n  PAGE_VIEW_SESSION_STORAGE_KEY,\n} from '../src/page-view-tracking';\n\njest.mock('@amplitude/analytics-core', () => {\n  const actual = jest.requireActual<typeof import('@amplitude/analytics-core')>('@amplitude/analytics-core');\n  return {\n    ...actual,\n    UUID: jest.fn(function (...args) {\n      // Call through to original\n      return actual.UUID(...args);\n    }),\n    getGlobalScope: jest.fn(() => (typeof window !== 'undefined' ? window : undefined)),\n  };\n});\n\n// Mock BrowserClient implementation\nconst createMockBrowserClient = (): jest.Mocked<BrowserClient> => {\n  const mockClient = {\n    init: jest.fn(),\n    add: jest.fn(),\n    remove: jest.fn(),\n    track: jest.fn(),\n    logEvent: jest.fn(),\n    identify: jest.fn(),\n    groupIdentify: jest.fn(),\n    setGroup: jest.fn(),\n    revenue: jest.fn(),\n    flush: jest.fn(),\n    getUserId: jest.fn(),\n    setUserId: jest.fn(),\n    getDeviceId: jest.fn(),\n    setDeviceId: jest.fn(),\n    getSessionId: jest.fn(),\n    setSessionId: jest.fn(),\n    extendSession: jest.fn(),\n    reset: jest.fn(),\n    setOptOut: jest.fn(),\n    setTransport: jest.fn(),\n    getOptOut: jest.fn(),\n    getIdentity: jest.fn(),\n    setIdentity: jest.fn(),\n    _setDiagnosticsSampleRate: jest.fn(),\n  } as jest.Mocked<BrowserClient>;\n\n  // Set up default return values for methods that return promises\n  mockClient.track.mockReturnValue({\n    promise: Promise.resolve({\n      code: 200,\n      message: '',\n      event: {\n        event_type: '[Amplitude] Page Viewed',\n      },\n    }),\n  });\n\n  return mockClient;\n};\n\ndescribe('pageViewTrackingPlugin', () => {\n  const mockConfig: BrowserConfig = {\n    apiKey: UUID(),\n    flushIntervalMillis: 0,\n    flushMaxRetries: 0,\n    flushQueueSize: 0,\n    logLevel: LogLevel.None,\n    loggerProvider: new Logger(),\n    offline: false,\n    optOut: false,\n    serverUrl: undefined,\n    transportProvider: new FetchTransport(),\n    useBatch: false,\n    cookieOptions: {\n      domain: '.amplitude.com',\n      expiration: 365,\n      sameSite: 'Lax',\n      secure: false,\n      upgrade: true,\n    },\n    cookieStorage: new CookieStorage(),\n    sessionTimeout: 30 * 60 * 1000,\n    trackingOptions: {\n      ipAddress: true,\n      language: true,\n      platform: true,\n    },\n    pageCounter: 0,\n  };\n\n  beforeAll(() => {\n    Object.defineProperty(window, 'location', {\n      value: {\n        hostname: '',\n        href: '',\n        pathname: '',\n        search: '',\n      },\n      writable: true,\n    });\n  });\n\n  beforeEach(() => {\n    (window.location as any) = {\n      hostname: '',\n      href: '',\n      pathname: '',\n      search: '',\n    };\n  });\n\n  describe('setup', () => {\n    test.each([\n      { trackHistoryChanges: undefined },\n      { trackHistoryChanges: 'pathOnly' as const },\n      { trackHistoryChanges: 'all' as const },\n    ])('should track dynamic page view', async (options) => {\n      mockConfig.pageCounter = 0;\n\n      const amplitude = createMockBrowserClient();\n      const track = jest.spyOn(amplitude, 'track').mockReturnValue({\n        promise: Promise.resolve({\n          code: 200,\n          message: '',\n          event: {\n            event_type: '[Amplitude] Page Viewed',\n          },\n        }),\n      });\n\n      const oldURL = new URL('https://www.example.com/home');\n      mockWindowLocationFromURL(oldURL);\n      const plugin = pageViewTrackingPlugin(options);\n      await plugin.setup?.(mockConfig, amplitude);\n\n      const newURL = new URL('https://www.example.com/about');\n      mockWindowLocationFromURL(newURL);\n      window.history.pushState(undefined, newURL.href);\n\n      // Page view tracking on push state executes async\n      // Block event loop for 1s before asserting\n      await new Promise((resolve) => setTimeout(resolve, 1000));\n\n      // Expect session storage to match the latest page view id\n      const sessionStorageItem = window.sessionStorage.getItem(PAGE_VIEW_SESSION_STORAGE_KEY);\n      expect(sessionStorageItem).toBeDefined();\n      const sessionStorageItemJson = JSON.parse(sessionStorageItem as string) as { pageViewId: string };\n      const pageViewIdSessionStorage = sessionStorageItemJson.pageViewId;\n\n      expect(track).toHaveBeenNthCalledWith(2, {\n        event_properties: {\n          '[Amplitude] Page Domain': newURL.hostname,\n          '[Amplitude] Page Location': newURL.toString(),\n          '[Amplitude] Page Path': newURL.pathname,\n          '[Amplitude] Page Title': '',\n          '[Amplitude] Page URL': newURL.toString(),\n          '[Amplitude] Page View ID': pageViewIdSessionStorage,\n        },\n        event_type: '[Amplitude] Page Viewed',\n      });\n      expect(track).toHaveBeenCalledTimes(2);\n    });\n\n    test.each([\n      undefined,\n      {},\n      {\n        trackOn: undefined,\n      },\n      {\n        trackOn: () => true,\n        eventType: 'Page Viewed',\n      },\n    ])('should track initial page view', async (options) => {\n      mockConfig.pageCounter = 0;\n      const amplitude = createMockBrowserClient();\n      const search = 'utm_source=google&utm_medium=cpc&utm_campaign=brand&utm_term=keyword&utm_content=adcopy';\n      const hostname = 'www.example.com';\n      const pathname = '/path/to/page';\n      const url = new URL(`https://${hostname}${pathname}?${search}`);\n      mockWindowLocationFromURL(url);\n      const track = jest.spyOn(amplitude, 'track').mockReturnValueOnce({\n        promise: Promise.resolve({\n          code: 200,\n          message: '',\n          event: {\n            event_type: '[Amplitude] Page Viewed',\n          },\n        }),\n      });\n      const plugin = pageViewTrackingPlugin(options);\n      await plugin.setup?.(mockConfig, amplitude);\n      expect(track).toHaveBeenCalledWith({\n        event_properties: {\n          '[Amplitude] Page Domain': hostname,\n          '[Amplitude] Page Location': url.toString(),\n          '[Amplitude] Page Path': pathname,\n          '[Amplitude] Page Title': '',\n          '[Amplitude] Page URL': `https://${hostname}${pathname}`,\n          '[Amplitude] Page View ID': expect.any(String),\n          utm_source: 'google',\n          utm_medium: 'cpc',\n          utm_campaign: 'brand',\n          utm_term: 'keyword',\n          utm_content: 'adcopy',\n        },\n        event_type: options?.eventType ?? '[Amplitude] Page Viewed',\n      });\n      expect(track).toHaveBeenCalledTimes(1);\n    });\n\n    test.each([\n      {\n        trackOn: 'attribution' as const,\n      },\n      {\n        trackOn: () => false,\n      },\n    ])('should not track initial page view', async (options) => {\n      const amplitude = createMockBrowserClient();\n      const track = jest.spyOn(amplitude, 'track');\n      const plugin = pageViewTrackingPlugin(options);\n      await plugin.setup?.(mockConfig, amplitude);\n      expect(track).toHaveBeenCalledTimes(0);\n    });\n\n    test('should handle sessionStorage throwing (e.g. sandboxed iframe) and continue without session storage', async () => {\n      const logger = new Logger();\n      const debugSpy = jest.spyOn(logger, 'debug');\n      const configWithLogger = { ...mockConfig, loggerProvider: logger };\n\n      // Build scope without spreading window so sessionStorage getter is only invoked when plugin accesses it\n      const scopeWithThrowingSessionStorage = {\n        addEventListener: window.addEventListener.bind(window),\n        removeEventListener: window.removeEventListener.bind(window),\n        history: window.history,\n        get sessionStorage() {\n          throw new DOMException('The operation is insecure', 'SecurityError');\n        },\n      };\n      (getGlobalScope as jest.Mock).mockReturnValue(scopeWithThrowingSessionStorage);\n\n      const amplitude = createMockBrowserClient();\n      jest.spyOn(amplitude, 'track').mockReturnValue({\n        promise: Promise.resolve({\n          code: 200,\n          message: '',\n          event: { event_type: '[Amplitude] Page Viewed' },\n        }),\n      });\n\n      const plugin = pageViewTrackingPlugin();\n      await expect(plugin.setup?.(configWithLogger, amplitude)).resolves.not.toThrow();\n      expect(debugSpy).toHaveBeenCalledWith(\n        expect.stringContaining('sessionStorage is not available in this environment'),\n      );\n\n      (getGlobalScope as jest.Mock).mockImplementation(() => (typeof window !== 'undefined' ? window : undefined));\n    });\n\n    test.each([\n      { trackHistoryChanges: 'pathOnly' as const },\n      {\n        trackOn: () => {\n          return !location.search.includes('about');\n        },\n      },\n    ])('should not track dynamic page view', async (options) => {\n      const amplitude = createMockBrowserClient();\n      const track = jest.spyOn(amplitude, 'track').mockReturnValue({\n        promise: Promise.resolve({\n          code: 200,\n          message: '',\n          event: {\n            event_type: '[Amplitude] Page Viewed',\n          },\n        }),\n      });\n\n      const oldURL = new URL('https://www.example.com?page=home');\n      mockWindowLocationFromURL(oldURL);\n\n      const plugin = pageViewTrackingPlugin(options);\n      await plugin.setup?.(mockConfig, amplitude);\n\n      const newURL = new URL('https://www.example.com?page=about');\n      mockWindowLocationFromURL(newURL);\n      window.history.pushState(undefined, newURL.href);\n\n      // Page view tracking on push state executes async\n      // Block event loop for 1s before asserting\n      await new Promise((resolve) => setTimeout(resolve, 1000));\n\n      expect(track).toHaveBeenCalledTimes(1);\n    });\n\n    test('should track dynamic page view with decoded URI location info', async () => {\n      mockConfig.pageCounter = 0;\n\n      const amplitude = createMockBrowserClient();\n      const track = jest.spyOn(amplitude, 'track').mockReturnValue({\n        promise: Promise.resolve({\n          code: 200,\n          message: '',\n          event: {\n            event_type: '[Amplitude] Page Viewed',\n          },\n        }),\n      });\n\n      const oldURL = new URL('https://www.example.com');\n      mockWindowLocationFromURL(oldURL);\n      const plugin = pageViewTrackingPlugin();\n      await plugin.setup?.(mockConfig, amplitude);\n\n      // https://www.example.com/home-шеллы?x=test\n      const newURL = new URL('https://www.example.com/home-%D1%88%D0%B5%D0%BB%D0%BB%D1%8B?x=test');\n      mockWindowLocationFromURL(newURL);\n      window.history.pushState(undefined, newURL.href);\n\n      // Page view tracking on push state executes async\n      // Block event loop for 1s before asserting\n      await new Promise((resolve) => setTimeout(resolve, 1000));\n\n      expect(track).toHaveBeenNthCalledWith(1, {\n        event_properties: {\n          '[Amplitude] Page Domain': oldURL.hostname,\n          '[Amplitude] Page Location': oldURL.toString(),\n          '[Amplitude] Page Path': oldURL.pathname,\n          '[Amplitude] Page Title': '',\n          '[Amplitude] Page URL': oldURL.toString(),\n          '[Amplitude] Page View ID': expect.any(String),\n        },\n        event_type: '[Amplitude] Page Viewed',\n      });\n\n      expect(track).toHaveBeenNthCalledWith(2, {\n        event_properties: {\n          '[Amplitude] Page Domain': newURL.hostname,\n          '[Amplitude] Page Location': 'https://www.example.com/home-шеллы?x=test',\n          '[Amplitude] Page Path': '/home-шеллы',\n          '[Amplitude] Page Title': '',\n          '[Amplitude] Page URL': 'https://www.example.com/home-шеллы',\n          '[Amplitude] Page View ID': expect.any(String),\n        },\n        event_type: '[Amplitude] Page Viewed',\n      });\n\n      expect(track).toHaveBeenCalledTimes(2);\n    });\n\n    test('should track dynamic page view with malformed location info', async () => {\n      mockConfig.pageCounter = 0;\n\n      const amplitude = createMockBrowserClient();\n      const track = jest.spyOn(amplitude, 'track').mockReturnValue({\n        promise: Promise.resolve({\n          code: 200,\n          message: '',\n          event: {\n            event_type: '[Amplitude] Page Viewed',\n          },\n        }),\n      });\n\n      const oldURL = new URL('https://www.example.com');\n      mockWindowLocationFromURL(oldURL);\n      const plugin = pageViewTrackingPlugin();\n      await plugin.setup?.(mockConfig, amplitude);\n\n      const malformedPath = '/home-%D1%88%D0%B5%D0BB%D0%BB%D1%8B'; // Invalid encoding string\n      const malformedURL = `https://www.example.com${malformedPath}`;\n      const malformedLocation = `https://www.example.com${malformedPath}?x=test`;\n      const newURL = new URL(malformedLocation);\n      mockWindowLocationFromURL(newURL);\n      window.history.pushState(undefined, newURL.href);\n\n      // Page view tracking on push state executes async\n      // Block event loop for 1s before asserting\n      await new Promise((resolve) => setTimeout(resolve, 1000));\n\n      expect(track).toHaveBeenNthCalledWith(1, {\n        event_properties: {\n          '[Amplitude] Page Domain': oldURL.hostname,\n          '[Amplitude] Page Location': oldURL.toString(),\n          '[Amplitude] Page Path': oldURL.pathname,\n          '[Amplitude] Page Title': '',\n          '[Amplitude] Page URL': oldURL.toString(),\n          '[Amplitude] Page View ID': expect.any(String),\n        },\n        event_type: '[Amplitude] Page Viewed',\n      });\n\n      expect(track).toHaveBeenNthCalledWith(2, {\n        event_properties: {\n          '[Amplitude] Page Domain': newURL.hostname,\n          '[Amplitude] Page Location': malformedLocation,\n          '[Amplitude] Page Path': malformedPath,\n          '[Amplitude] Page Title': '',\n          '[Amplitude] Page URL': malformedURL,\n          '[Amplitude] Page View ID': expect.any(String),\n        },\n        event_type: '[Amplitude] Page Viewed',\n      });\n\n      expect(track).toHaveBeenCalledTimes(2);\n    });\n\n    test('should track dynamic page view with regular location info', async () => {\n      mockConfig.pageCounter = 0;\n\n      const amplitude = createMockBrowserClient();\n      const track = jest.spyOn(amplitude, 'track').mockReturnValue({\n        promise: Promise.resolve({\n          code: 200,\n          message: '',\n          event: {\n            event_type: '[Amplitude] Page Viewed',\n          },\n        }),\n      });\n\n      const oldURL = new URL('https://www.example.com');\n      mockWindowLocationFromURL(oldURL);\n      const plugin = pageViewTrackingPlugin();\n      await plugin.setup?.(mockConfig, amplitude);\n\n      const newBaseURL = `https://www.example.com/home-shell`;\n      const newURL = new URL(`${newBaseURL}?x=test`);\n      mockWindowLocationFromURL(newURL);\n      window.history.pushState(undefined, newURL.href);\n\n      // Page view tracking on push state executes async\n      // Block event loop for 1s before asserting\n      await new Promise((resolve) => setTimeout(resolve, 1000));\n\n      expect(track).toHaveBeenNthCalledWith(1, {\n        event_properties: {\n          '[Amplitude] Page Domain': oldURL.hostname,\n          '[Amplitude] Page Location': oldURL.toString(),\n          '[Amplitude] Page Path': oldURL.pathname,\n          '[Amplitude] Page Title': '',\n          '[Amplitude] Page URL': oldURL.toString(),\n          '[Amplitude] Page View ID': expect.any(String),\n        },\n        event_type: '[Amplitude] Page Viewed',\n      });\n\n      expect(track).toHaveBeenNthCalledWith(2, {\n        event_properties: {\n          '[Amplitude] Page Domain': newURL.hostname,\n          '[Amplitude] Page Location': newURL.toString(),\n          '[Amplitude] Page Path': newURL.pathname,\n          '[Amplitude] Page Title': '',\n          '[Amplitude] Page URL': newBaseURL,\n          '[Amplitude] Page View ID': expect.any(String),\n        },\n        event_type: '[Amplitude] Page Viewed',\n      });\n\n      expect(track).toHaveBeenCalledTimes(2);\n    });\n  });\n\n  describe('execute', () => {\n    test('should track page view on attribution', async () => {\n      const amplitude = createMockBrowserClient();\n      const plugin = pageViewTrackingPlugin({\n        trackOn: 'attribution',\n      });\n      await plugin.setup?.(mockConfig, amplitude);\n      const event = await plugin.execute?.({\n        event_type: '$identify',\n        user_properties: {\n          $set: {\n            utm_source: 'amp-test',\n          },\n          $setOnce: {\n            initial_dclid: 'EMPTY',\n            initial_fbclid: 'EMPTY',\n            initial_gbraid: 'EMPTY',\n            initial_gclid: 'EMPTY',\n            initial_ko_click_id: 'EMPTY',\n            initial_li_fat_id: 'EMPTY',\n            initial_msclkid: 'EMPTY',\n            initial_wbraid: 'EMPTY',\n            initial_referrer: 'EMPTY',\n            initial_referring_domain: 'EMPTY',\n            initial_rdt_cid: 'EMPTY',\n            initial_ttclid: 'EMPTY',\n            initial_twclid: 'EMPTY',\n            initial_utm_campaign: 'EMPTY',\n            initial_utm_content: 'EMPTY',\n            initial_utm_id: 'EMPTY',\n            initial_utm_medium: 'EMPTY',\n            initial_utm_source: 'amp-test',\n            initial_utm_term: 'EMPTY',\n          },\n          $unset: {\n            dclid: '-',\n            fbclid: '-',\n            gbraid: '-',\n            gclid: '-',\n            ko_click_id: '-',\n            li_fat_id: '-',\n            msclkid: '-',\n            wbraid: '-',\n            referrer: '-',\n            referring_domain: '-',\n            rdt_cid: '-',\n            ttclid: '-',\n            twclid: '-',\n            utm_campaign: '-',\n            utm_content: '-',\n            utm_id: '-',\n            utm_medium: '-',\n            utm_term: '-',\n          },\n        },\n      });\n      expect(event?.event_type).toBe('[Amplitude] Page Viewed');\n    });\n\n    test('should track attribution page view when session storage is unavailable', async () => {\n      // Mock getGlobalScope to return undefined to simulate no global scope\n      const orig = (getGlobalScope as jest.Mock).getMockImplementation();\n\n      (getGlobalScope as jest.Mock).mockReturnValue(undefined);\n\n      const amplitude = createMockBrowserClient();\n\n      const plugin = pageViewTrackingPlugin({\n        trackOn: 'attribution',\n      });\n\n      await plugin.setup?.(mockConfig, amplitude);\n      const event = await plugin.execute?.({\n        event_type: '$identify',\n        user_properties: {\n          $set: {\n            utm_source: 'amp-test',\n          },\n          $setOnce: {\n            initial_dclid: 'EMPTY',\n            initial_fbclid: 'EMPTY',\n            initial_gbraid: 'EMPTY',\n            initial_gclid: 'EMPTY',\n            initial_ko_click_id: 'EMPTY',\n            initial_li_fat_id: 'EMPTY',\n            initial_msclkid: 'EMPTY',\n            initial_wbraid: 'EMPTY',\n            initial_referrer: 'EMPTY',\n            initial_referring_domain: 'EMPTY',\n            initial_rdt_cid: 'EMPTY',\n            initial_ttclid: 'EMPTY',\n            initial_twclid: 'EMPTY',\n            initial_utm_campaign: 'EMPTY',\n            initial_utm_content: 'EMPTY',\n            initial_utm_id: 'EMPTY',\n            initial_utm_medium: 'EMPTY',\n            initial_utm_source: 'amp-test',\n            initial_utm_term: 'EMPTY',\n          },\n          $unset: {\n            dclid: '-',\n            fbclid: '-',\n            gbraid: '-',\n            gclid: '-',\n            ko_click_id: '-',\n            li_fat_id: '-',\n            msclkid: '-',\n            wbraid: '-',\n            referrer: '-',\n            referring_domain: '-',\n            rdt_cid: '-',\n            ttclid: '-',\n            twclid: '-',\n            utm_campaign: '-',\n            utm_content: '-',\n            utm_id: '-',\n            utm_medium: '-',\n            utm_term: '-',\n          },\n        },\n      });\n\n      expect(event?.event_type).toBe('[Amplitude] Page Viewed');\n      expect(event?.event_properties).not.toHaveProperty('[Amplitude] Page View ID');\n      (getGlobalScope as jest.Mock).mockImplementation(orig);\n    });\n\n    test('should track attribution page view when session storage is empty', async () => {\n      const amplitude = createMockBrowserClient();\n      const plugin = pageViewTrackingPlugin({\n        trackOn: 'attribution',\n      });\n\n      // Clear session storage\n      window.sessionStorage.setItem(PAGE_VIEW_SESSION_STORAGE_KEY, 'undefined');\n\n      await plugin.setup?.(mockConfig, amplitude);\n      const event = await plugin.execute?.({\n        event_type: '$identify',\n        user_properties: {\n          $set: {\n            utm_source: 'amp-test',\n          },\n          $setOnce: {\n            initial_dclid: 'EMPTY',\n            initial_fbclid: 'EMPTY',\n            initial_gbraid: 'EMPTY',\n            initial_gclid: 'EMPTY',\n            initial_ko_click_id: 'EMPTY',\n            initial_li_fat_id: 'EMPTY',\n            initial_msclkid: 'EMPTY',\n            initial_wbraid: 'EMPTY',\n            initial_referrer: 'EMPTY',\n            initial_referring_domain: 'EMPTY',\n            initial_rdt_cid: 'EMPTY',\n            initial_ttclid: 'EMPTY',\n            initial_twclid: 'EMPTY',\n            initial_utm_campaign: 'EMPTY',\n            initial_utm_content: 'EMPTY',\n            initial_utm_id: 'EMPTY',\n            initial_utm_medium: 'EMPTY',\n            initial_utm_source: 'amp-test',\n            initial_utm_term: 'EMPTY',\n          },\n          $unset: {\n            dclid: '-',\n            fbclid: '-',\n            gbraid: '-',\n            gclid: '-',\n            ko_click_id: '-',\n            li_fat_id: '-',\n            msclkid: '-',\n            wbraid: '-',\n            referrer: '-',\n            referring_domain: '-',\n            rdt_cid: '-',\n            ttclid: '-',\n            twclid: '-',\n            utm_campaign: '-',\n            utm_content: '-',\n            utm_id: '-',\n            utm_medium: '-',\n            utm_term: '-',\n          },\n        },\n      });\n\n      expect(event?.event_type).toBe('[Amplitude] Page Viewed');\n      expect(event?.event_properties).not.toHaveProperty('[Amplitude] Page View ID');\n    });\n\n    test('should return same event if it is not attribution event', async () => {\n      const plugin = pageViewTrackingPlugin({\n        trackOn: 'attribution',\n      });\n      const sentEvent = {\n        event_type: '$identify',\n        user_properties: {},\n      };\n      const event = await plugin.execute?.(sentEvent);\n      expect(event).toBe(sentEvent);\n    });\n\n    test('should return same event if it does not have user_properties', async () => {\n      const plugin = pageViewTrackingPlugin({\n        trackOn: 'attribution',\n      });\n\n      const sentEvent = {\n        event_type: '$identify',\n      };\n      const event = await plugin.execute?.(sentEvent);\n      expect(event).toBe(sentEvent);\n    });\n\n    test('should return same event if it is not identify event', async () => {\n      const plugin = pageViewTrackingPlugin({\n        trackOn: 'attribution',\n      });\n\n      const sentEvent = {\n        event_type: '[Amplitude] Page Viewed',\n      };\n      const event = await plugin.execute?.(sentEvent);\n      expect(event).toBe(sentEvent);\n    });\n\n    test('should set the pageCounter', async () => {\n      const config = { ...mockConfig };\n      config.pageCounter = 0;\n      const amplitude = createMockBrowserClient();\n      jest.spyOn(amplitude, 'track').mockReturnValue({\n        promise: Promise.resolve({\n          code: 200,\n          message: '',\n          event: {\n            event_type: defaultPageViewEvent,\n          },\n        }),\n      });\n\n      const plugin = pageViewTrackingPlugin();\n      await plugin.setup?.(config, amplitude);\n      await plugin.execute?.({ event_type: defaultPageViewEvent });\n      expect(config.pageCounter).toBe(1);\n\n      await plugin.execute?.({ event_type: defaultPageViewEvent });\n      expect(config.pageCounter).toBe(2);\n    });\n\n    test('should not set the pageCounter', async () => {\n      const config = { ...mockConfig };\n      config.pageCounter = 0;\n      const amplitude = createMockBrowserClient();\n      jest.spyOn(amplitude, 'track').mockReturnValue({\n        promise: Promise.resolve({\n          code: 200,\n          message: '',\n          event: {\n            event_type: defaultPageViewEvent,\n          },\n        }),\n      });\n\n      const plugin = pageViewTrackingPlugin();\n      await plugin.setup?.(config, amplitude);\n      await plugin.execute?.({ event_type: 'other event' });\n      expect(config.pageCounter).toBe(0);\n    });\n  });\n\n  describe('teardown', () => {\n    test('should call remove listeners', async () => {\n      const amplitude = createMockBrowserClient();\n      const removeEventListener = jest.spyOn(window, 'removeEventListener');\n      jest.spyOn(amplitude, 'track').mockReturnValueOnce({\n        promise: Promise.resolve({\n          code: 200,\n          message: '',\n          event: {\n            event_type: 'event_type',\n          },\n        }),\n      });\n      const plugin = pageViewTrackingPlugin();\n      await plugin.setup?.(mockConfig, amplitude);\n      await plugin.teardown?.();\n      expect(removeEventListener).toHaveBeenCalledTimes(1);\n    });\n\n    test('should call remove listeners without proxy', async () => {\n      const removeEventListener = jest.spyOn(window, 'removeEventListener');\n      const plugin = pageViewTrackingPlugin();\n      await plugin.teardown?.();\n      expect(removeEventListener).toHaveBeenCalledTimes(1);\n    });\n\n    test('should not restore history.pushState after teardown', async () => {\n      /* eslint-disable @typescript-eslint/unbound-method */\n      const history = window.history;\n      const originalPushState = history.pushState;\n      const plugin = pageViewTrackingPlugin({\n        trackHistoryChanges: 'all',\n      });\n      expect(history.pushState).toBe(originalPushState);\n      await plugin.setup?.(mockConfig, createMockBrowserClient());\n      expect(history.pushState).not.toBe(originalPushState);\n      await plugin.teardown?.();\n      expect(history.pushState).not.toBe(originalPushState);\n      /* eslint-enable @typescript-eslint/unbound-method */\n    });\n  });\n\n  test('shouldTrackHistoryPageView pathOnly option', () => {\n    const url1 = 'https://www.example.com/path/to/page';\n    const url2 = 'https://www.example.com/path/to/page?query=1';\n    expect(shouldTrackHistoryPageView('all', url1, url2)).toBe(true);\n    expect(shouldTrackHistoryPageView('pathOnly', url1, url2)).toBe(false);\n  });\n\n  test('shouldTrackHistoryPageView pathOnly option with hash route', () => {\n    const url1 = 'https://www.example.com/path/to/page';\n    const url2 = 'https://www.example.com/path/to/page#home';\n    expect(shouldTrackHistoryPageView('all', url1, url2)).toBe(true);\n    expect(shouldTrackHistoryPageView('pathOnly', url1, url2)).toBe(false);\n  });\n\n  test('shouldTrackHistoryPageView pathOnly option with null previous url', () => {\n    const url1 = 'https://www.example.com/path/to/page';\n    const url2 = '';\n    expect(shouldTrackHistoryPageView('all', url1, url2)).toBe(true);\n    expect(shouldTrackHistoryPageView('pathOnly', url1, url2)).toBe(true);\n  });\n});\n\nconst mockWindowLocationFromURL = (url: URL) => {\n  window.location.href = url.toString();\n  window.location.search = url.search;\n  window.location.hostname = url.hostname;\n  window.location.pathname = url.pathname;\n};\n"
  },
  {
    "path": "packages/plugin-page-view-tracking-browser/tsconfig.es5.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/cjs\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-page-view-tracking-browser/tsconfig.esm.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"es6\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/esm\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-page-view-tracking-browser/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src/**/*\", \"test/**/*\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"esModuleInterop\": true,\n    \"lib\": [\"dom\"],\n    \"noEmit\": true,\n    \"rootDir\": \".\",\n  }\n}\n"
  },
  {
    "path": "packages/plugin-session-replay-browser/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.30.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.30.3...@amplitude/plugin-session-replay-browser@1.30.4) (2026-05-14)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.30.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.30.2...@amplitude/plugin-session-replay-browser@1.30.3) (2026-05-11)\n\n\n### Bug Fixes\n\n* **plugin-session-replay-browser:** forward crossOriginIframes to underlying SDK ([#1745](https://github.com/amplitude/Amplitude-TypeScript/issues/1745)) ([e944a13](https://github.com/amplitude/Amplitude-TypeScript/commit/e944a1381a9e70146f1d31c413636579554b30db))\n\n\n\n\n\n## [1.30.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.30.1...@amplitude/plugin-session-replay-browser@1.30.2) (2026-05-08)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.30.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.30.0...@amplitude/plugin-session-replay-browser@1.30.1) (2026-05-07)\n\n\n### Bug Fixes\n\n* **session-replay-browser:** reduce snapshot size and handle 413s ([#1685](https://github.com/amplitude/Amplitude-TypeScript/issues/1685)) ([36db705](https://github.com/amplitude/Amplitude-TypeScript/commit/36db705d3b4b648aeab09c9e4dc89cf6b8dbf64b))\n\n\n\n\n\n# [1.30.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.29.0...@amplitude/plugin-session-replay-browser@1.30.0) (2026-05-06)\n\n\n### Features\n\n* **session-replay-browser:** default storeType to memory (SR-3878 experiment) ([#1704](https://github.com/amplitude/Amplitude-TypeScript/issues/1704)) ([a893023](https://github.com/amplitude/Amplitude-TypeScript/commit/a8930230a7822fb2ae1fb5150d98f9c150a617bb))\n\n\n\n\n\n# [1.29.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.28.1...@amplitude/plugin-session-replay-browser@1.29.0) (2026-05-05)\n\n\n### Features\n\n* **session-replay:** upgrade rrweb to 2.0.0-alpha.40 ([#1714](https://github.com/amplitude/Amplitude-TypeScript/issues/1714)) ([8474dd5](https://github.com/amplitude/Amplitude-TypeScript/commit/8474dd52448ddb9190f1b8b8ac96f11a371807be))\n\n\n\n\n\n## [1.28.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.28.0...@amplitude/plugin-session-replay-browser@1.28.1) (2026-04-28)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n# [1.28.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.27.10...@amplitude/plugin-session-replay-browser@1.28.0) (2026-04-22)\n\n\n### Features\n\n* **session-replay-browser:** expose captureAdoptedStyleSheets option ([#1695](https://github.com/amplitude/Amplitude-TypeScript/issues/1695)) ([9cec47c](https://github.com/amplitude/Amplitude-TypeScript/commit/9cec47c14b6e8f9057309922e36fb4c0714f06e1))\n\n\n\n\n\n## [1.27.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.27.9...@amplitude/plugin-session-replay-browser@1.27.10) (2026-04-21)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.27.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.27.8...@amplitude/plugin-session-replay-browser@1.27.9) (2026-04-16)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.27.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.27.7...@amplitude/plugin-session-replay-browser@1.27.8) (2026-04-14)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.27.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.27.6...@amplitude/plugin-session-replay-browser@1.27.7) (2026-04-09)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.27.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.27.5...@amplitude/plugin-session-replay-browser@1.27.6) (2026-04-01)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.27.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.27.4...@amplitude/plugin-session-replay-browser@1.27.5) (2026-03-26)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.27.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.27.3...@amplitude/plugin-session-replay-browser@1.27.4) (2026-03-24)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.27.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.27.2...@amplitude/plugin-session-replay-browser@1.27.3) (2026-03-24)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.27.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.27.1...@amplitude/plugin-session-replay-browser@1.27.2) (2026-03-23)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.27.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.27.0...@amplitude/plugin-session-replay-browser@1.27.1) (2026-03-20)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n# [1.27.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.26.4...@amplitude/plugin-session-replay-browser@1.27.0) (2026-03-19)\n\n\n### Features\n\n* **session-replay-browser:** implement attribute masking functionality ([#1602](https://github.com/amplitude/Amplitude-TypeScript/issues/1602)) ([ad8b8ac](https://github.com/amplitude/Amplitude-TypeScript/commit/ad8b8ac383a698ab6727b3bff8147323eef3d36e))\n\n\n\n\n\n## [1.26.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.26.3...@amplitude/plugin-session-replay-browser@1.26.4) (2026-03-17)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.26.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.26.2...@amplitude/plugin-session-replay-browser@1.26.3) (2026-03-16)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.26.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.26.1...@amplitude/plugin-session-replay-browser@1.26.2) (2026-03-13)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.26.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.26.0...@amplitude/plugin-session-replay-browser@1.26.1) (2026-03-12)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n# [1.26.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.25.21...@amplitude/plugin-session-replay-browser@1.26.0) (2026-03-11)\n\n\n### Features\n\n* **session-replay:** enhance targeting evaluation with page URL ([#1571](https://github.com/amplitude/Amplitude-TypeScript/issues/1571)) ([509bec0](https://github.com/amplitude/Amplitude-TypeScript/commit/509bec01ccdb795c0f9dbf83a99e585c6d16ee63))\n\n\n\n\n\n## [1.25.21](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.25.20...@amplitude/plugin-session-replay-browser@1.25.21) (2026-03-09)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.25.20](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.25.19...@amplitude/plugin-session-replay-browser@1.25.20) (2026-03-06)\n\n\n### Bug Fixes\n\n* **session-replay:** guarantee in-order batch delivery including retries ([#1576](https://github.com/amplitude/Amplitude-TypeScript/issues/1576)) ([0afcac6](https://github.com/amplitude/Amplitude-TypeScript/commit/0afcac6cd42b999b74ba797717f7cf0d447029ef))\n\n\n\n\n\n## [1.25.20-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.25.19...@amplitude/plugin-session-replay-browser@1.25.20-beta.0) (2026-03-06)\n\n\n### Bug Fixes\n\n* **session-replay:** guarantee in-order batch delivery including retries ([#1576](https://github.com/amplitude/Amplitude-TypeScript/issues/1576)) ([0afcac6](https://github.com/amplitude/Amplitude-TypeScript/commit/0afcac6cd42b999b74ba797717f7cf0d447029ef))\n\n\n\n\n\n## [1.25.20-in-order.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.25.19...@amplitude/plugin-session-replay-browser@1.25.20-in-order.0) (2026-03-06)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.25.19](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.25.18...@amplitude/plugin-session-replay-browser@1.25.19) (2026-03-05)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.25.18](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.25.17...@amplitude/plugin-session-replay-browser@1.25.18) (2026-03-03)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.25.17](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.25.16...@amplitude/plugin-session-replay-browser@1.25.17) (2026-03-03)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.25.16](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.25.15...@amplitude/plugin-session-replay-browser@1.25.16) (2026-02-26)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.25.15](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.25.14...@amplitude/plugin-session-replay-browser@1.25.15) (2026-02-24)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.25.14](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.25.13...@amplitude/plugin-session-replay-browser@1.25.14) (2026-02-20)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.25.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.25.12...@amplitude/plugin-session-replay-browser@1.25.13) (2026-02-19)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.25.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.25.11...@amplitude/plugin-session-replay-browser@1.25.12) (2026-02-17)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.25.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.25.10...@amplitude/plugin-session-replay-browser@1.25.11) (2026-02-10)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.25.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.25.9...@amplitude/plugin-session-replay-browser@1.25.10) (2026-01-26)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.25.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.25.8...@amplitude/plugin-session-replay-browser@1.25.9) (2026-01-21)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.25.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.25.7...@amplitude/plugin-session-replay-browser@1.25.8) (2026-01-15)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.25.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.25.6...@amplitude/plugin-session-replay-browser@1.25.7) (2026-01-14)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.25.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.25.5...@amplitude/plugin-session-replay-browser@1.25.6) (2026-01-14)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.25.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.25.4...@amplitude/plugin-session-replay-browser@1.25.5) (2025-12-30)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.25.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.25.3...@amplitude/plugin-session-replay-browser@1.25.4) (2025-12-24)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.25.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.25.2...@amplitude/plugin-session-replay-browser@1.25.3) (2025-12-22)\n\n\n### Bug Fixes\n\n* **plugin-session-replay:** remove [Amplitude] Session Replay ID ([#1439](https://github.com/amplitude/Amplitude-TypeScript/issues/1439)) ([f0a2ec3](https://github.com/amplitude/Amplitude-TypeScript/commit/f0a2ec3ca0fcab59fb7b82d5bb6e7709c975c816))\n\n\n\n\n\n## [1.25.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.25.1...@amplitude/plugin-session-replay-browser@1.25.2) (2025-12-16)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.25.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.25.0...@amplitude/plugin-session-replay-browser@1.25.1) (2025-12-12)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n# [1.25.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.24.1...@amplitude/plugin-session-replay-browser@1.25.0) (2025-12-09)\n\n\n### Features\n\n* **plugin-session-replay-browser:** add performance config for selector generation ([#1423](https://github.com/amplitude/Amplitude-TypeScript/issues/1423)) ([85ec6e4](https://github.com/amplitude/Amplitude-TypeScript/commit/85ec6e430077be996ff85b4c033d8744d95a3ea2))\n\n\n\n\n\n## [1.24.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.24.0...@amplitude/plugin-session-replay-browser@1.24.1) (2025-12-08)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n# [1.24.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.23.6...@amplitude/plugin-session-replay-browser@1.24.0) (2025-12-05)\n\n\n### Features\n\n* **session-replay-browser:** move web worker out of experimental ([#1416](https://github.com/amplitude/Amplitude-TypeScript/issues/1416)) ([50e3063](https://github.com/amplitude/Amplitude-TypeScript/commit/50e30636fb00f98989a2085b8b79d1792e1705d4))\n\n\n\n\n\n## [1.23.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.23.5...@amplitude/plugin-session-replay-browser@1.23.6) (2025-11-21)\n\n\n### Bug Fixes\n\n* handle null remote config cases for session capture ([#1396](https://github.com/amplitude/Amplitude-TypeScript/issues/1396)) ([18e98d0](https://github.com/amplitude/Amplitude-TypeScript/commit/18e98d0b9a561cf30c241197e9627c49b75cd00f))\n\n\n\n\n\n## [1.23.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.23.4...@amplitude/plugin-session-replay-browser@1.23.5) (2025-11-20)\n\n\n### Bug Fixes\n\n* **plugin-session-replay-browser:** handle nullable config in teardown ([#1410](https://github.com/amplitude/Amplitude-TypeScript/issues/1410)) ([32e89ec](https://github.com/amplitude/Amplitude-TypeScript/commit/32e89ec00541819e9636f8e73672e74f896d62da))\n\n\n\n\n\n## [1.23.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.23.3...@amplitude/plugin-session-replay-browser@1.23.4) (2025-11-17)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.23.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.23.2...@amplitude/plugin-session-replay-browser@1.23.3) (2025-11-17)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.23.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.23.1...@amplitude/plugin-session-replay-browser@1.23.2) (2025-11-05)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.23.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.23.0...@amplitude/plugin-session-replay-browser@1.23.1) (2025-10-29)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n# [1.23.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.22.27...@amplitude/plugin-session-replay-browser@1.23.0) (2025-10-23)\n\n\n### Features\n\n* **autocapture:** set page url enrichment plugin to default on and add/fix tests ([#1287](https://github.com/amplitude/Amplitude-TypeScript/issues/1287)) ([d96d7dd](https://github.com/amplitude/Amplitude-TypeScript/commit/d96d7dd7db156eae51a342b4956db2530ca64d29))\n\n\n\n\n\n## [1.22.27](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.22.26...@amplitude/plugin-session-replay-browser@1.22.27) (2025-10-23)\n\n\n### Bug Fixes\n\n* **session-replay-browser:** should respect configServerUrl ([#1362](https://github.com/amplitude/Amplitude-TypeScript/issues/1362)) ([a452d6e](https://github.com/amplitude/Amplitude-TypeScript/commit/a452d6e2f58bf5b1fe1ee01353a2680403a71d8b))\n\n\n\n\n\n## [1.22.26](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.22.25...@amplitude/plugin-session-replay-browser@1.22.26) (2025-10-21)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.22.25](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.22.24...@amplitude/plugin-session-replay-browser@1.22.25) (2025-10-17)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.22.24](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.22.23...@amplitude/plugin-session-replay-browser@1.22.24) (2025-10-15)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.22.23](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.22.22...@amplitude/plugin-session-replay-browser@1.22.23) (2025-10-14)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.22.22](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.22.21...@amplitude/plugin-session-replay-browser@1.22.22) (2025-10-14)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.22.21](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.22.20...@amplitude/plugin-session-replay-browser@1.22.21) (2025-10-07)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.22.20](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.22.19...@amplitude/plugin-session-replay-browser@1.22.20) (2025-10-06)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.22.19](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.22.18...@amplitude/plugin-session-replay-browser@1.22.19) (2025-10-03)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.22.18](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.22.17...@amplitude/plugin-session-replay-browser@1.22.18) (2025-10-01)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.22.17](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.22.16...@amplitude/plugin-session-replay-browser@1.22.17) (2025-09-25)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.22.16](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.22.15...@amplitude/plugin-session-replay-browser@1.22.16) (2025-09-25)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.22.15](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.22.14...@amplitude/plugin-session-replay-browser@1.22.15) (2025-09-23)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.22.14](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.22.13...@amplitude/plugin-session-replay-browser@1.22.14) (2025-09-18)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.22.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.22.12...@amplitude/plugin-session-replay-browser@1.22.13) (2025-09-12)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.22.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.22.11...@amplitude/plugin-session-replay-browser@1.22.12) (2025-09-09)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.22.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.22.10...@amplitude/plugin-session-replay-browser@1.22.11) (2025-09-05)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.22.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.22.9...@amplitude/plugin-session-replay-browser@1.22.10) (2025-08-28)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.22.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.22.8...@amplitude/plugin-session-replay-browser@1.22.9) (2025-08-26)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.22.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.22.7...@amplitude/plugin-session-replay-browser@1.22.8) (2025-08-25)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.22.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.22.6...@amplitude/plugin-session-replay-browser@1.22.7) (2025-08-25)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.22.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.22.5...@amplitude/plugin-session-replay-browser@1.22.6) (2025-08-22)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.22.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.22.4...@amplitude/plugin-session-replay-browser@1.22.5) (2025-08-21)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.22.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.22.3...@amplitude/plugin-session-replay-browser@1.22.4) (2025-08-13)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.22.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.22.2...@amplitude/plugin-session-replay-browser@1.22.3) (2025-08-08)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.22.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.22.1...@amplitude/plugin-session-replay-browser@1.22.2) (2025-08-05)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.22.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.22.0...@amplitude/plugin-session-replay-browser@1.22.1) (2025-07-30)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n# [1.22.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.21.1...@amplitude/plugin-session-replay-browser@1.22.0) (2025-07-29)\n\n\n### Features\n\n* targeting replay capture ([#1203](https://github.com/amplitude/Amplitude-TypeScript/issues/1203)) ([a1fc5b7](https://github.com/amplitude/Amplitude-TypeScript/commit/a1fc5b71cd71b33e6c6cd578cee4d0a17576e576))\n\n\n\n\n\n## [1.21.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.21.0...@amplitude/plugin-session-replay-browser@1.21.1) (2025-07-18)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n# [1.21.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.20.2...@amplitude/plugin-session-replay-browser@1.21.0) (2025-07-17)\n\n\n### Features\n\n* detect URL changes ([#1192](https://github.com/amplitude/Amplitude-TypeScript/issues/1192)) ([4957c16](https://github.com/amplitude/Amplitude-TypeScript/commit/4957c16df1f1b102cb2420d72b8f60847f49424a))\n\n\n\n\n\n## [1.20.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.20.1...@amplitude/plugin-session-replay-browser@1.20.2) (2025-07-15)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.20.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.20.0...@amplitude/plugin-session-replay-browser@1.20.1) (2025-07-11)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n# [1.20.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.19.3...@amplitude/plugin-session-replay-browser@1.20.0) (2025-07-08)\n\n\n### Features\n\n* **session-replay-browser:** allows users to omit scripts and comments from being captured ([#1179](https://github.com/amplitude/Amplitude-TypeScript/issues/1179)) ([4a705bc](https://github.com/amplitude/Amplitude-TypeScript/commit/4a705bc21eaae7e3319042701d6e2b0dbef971aa))\n\n\n### Performance Improvements\n\n* **session-replay:** enable compression performance by default ([#1181](https://github.com/amplitude/Amplitude-TypeScript/issues/1181)) ([c91e192](https://github.com/amplitude/Amplitude-TypeScript/commit/c91e1927a81e4c87b1d25a3494749ce5820a231c))\n\n\n\n\n\n## [1.19.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.19.2...@amplitude/plugin-session-replay-browser@1.19.3) (2025-06-30)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.19.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.19.1...@amplitude/plugin-session-replay-browser@1.19.2) (2025-06-26)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.19.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.19.0...@amplitude/plugin-session-replay-browser@1.19.1) (2025-06-25)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n# [1.19.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.18.2...@amplitude/plugin-session-replay-browser@1.19.0) (2025-06-17)\n\n\n### Bug Fixes\n\n* **unified:** rename sr to sessionReplay ([#1102](https://github.com/amplitude/Amplitude-TypeScript/issues/1102)) ([e1fa514](https://github.com/amplitude/Amplitude-TypeScript/commit/e1fa5148325bebfcb7054c83c38cd6d42a21ac5f))\n\n\n### Features\n\n* **session replay:** dynamically import rrweb ([#1156](https://github.com/amplitude/Amplitude-TypeScript/issues/1156)) ([510cc67](https://github.com/amplitude/Amplitude-TypeScript/commit/510cc67bf04f740940504e3351c39c05d54c5c32))\n\n\n\n\n\n## [1.18.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.18.1...@amplitude/plugin-session-replay-browser@1.18.2) (2025-06-17)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.18.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.18.0...@amplitude/plugin-session-replay-browser@1.18.1) (2025-06-16)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n# [1.18.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.17.0...@amplitude/plugin-session-replay-browser@1.18.0) (2025-06-13)\n\n\n### Features\n\n* **session-replay:** support background colors on blocked elements ([#1153](https://github.com/amplitude/Amplitude-TypeScript/issues/1153)) ([36fcd40](https://github.com/amplitude/Amplitude-TypeScript/commit/36fcd409b996c3c898bedd04ed77c9057ebbf994))\n\n\n\n\n\n# [1.17.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.16.15...@amplitude/plugin-session-replay-browser@1.17.0) (2025-06-12)\n\n\n### Features\n\n* **session-replay-browser:** ugc removal poc ([#1062](https://github.com/amplitude/Amplitude-TypeScript/issues/1062)) ([c63fafd](https://github.com/amplitude/Amplitude-TypeScript/commit/c63fafdaea2507a273cd23d8ef56dbe43c5aa1c3))\n\n\n\n\n\n## [1.16.15](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.16.14...@amplitude/plugin-session-replay-browser@1.16.15) (2025-06-11)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.16.14](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.16.13...@amplitude/plugin-session-replay-browser@1.16.14) (2025-06-11)\n\n\n### Bug Fixes\n\n* **session replay:** add gzip to cdn ([#1150](https://github.com/amplitude/Amplitude-TypeScript/issues/1150)) ([f61e38f](https://github.com/amplitude/Amplitude-TypeScript/commit/f61e38fc37d9a825a0c3f31147631eb1a16546a4))\n\n\n\n\n\n## [1.16.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.16.12...@amplitude/plugin-session-replay-browser@1.16.13) (2025-06-03)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.16.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.16.11...@amplitude/plugin-session-replay-browser@1.16.12) (2025-06-03)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.16.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.16.10...@amplitude/plugin-session-replay-browser@1.16.11) (2025-05-30)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.16.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.16.10-main.0...@amplitude/plugin-session-replay-browser@1.16.10) (2025-05-27)\n\n\n### Reverts\n\n* \"chore(release): publish\" ([#1094](https://github.com/amplitude/Amplitude-TypeScript/issues/1094)) ([f6db1ee](https://github.com/amplitude/Amplitude-TypeScript/commit/f6db1eed32ed77c7ce626624dc55972971f3b27d))\n\n\n\n\n\n## [1.16.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.16.8...@amplitude/plugin-session-replay-browser@1.16.9) (2025-05-14)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.16.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.16.7...@amplitude/plugin-session-replay-browser@1.16.8) (2025-05-13)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.16.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.16.6...@amplitude/plugin-session-replay-browser@1.16.7) (2025-05-07)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.16.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.16.5...@amplitude/plugin-session-replay-browser@1.16.6) (2025-05-07)\n\n\n### Bug Fixes\n\n* **session replay:** dynamically import plugin-console-record ([#983](https://github.com/amplitude/Amplitude-TypeScript/issues/983)) ([990def9](https://github.com/amplitude/Amplitude-TypeScript/commit/990def985a06b462ad16b33b811d46bde6f66b01))\n\n\n\n\n\n## [1.16.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.16.4...@amplitude/plugin-session-replay-browser@1.16.5) (2025-05-05)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.16.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.16.3...@amplitude/plugin-session-replay-browser@1.16.4) (2025-05-02)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.16.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.16.2...@amplitude/plugin-session-replay-browser@1.16.3) (2025-05-02)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.16.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.16.1...@amplitude/plugin-session-replay-browser@1.16.2) (2025-05-02)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.16.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.16.0...@amplitude/plugin-session-replay-browser@1.16.1) (2025-04-30)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n# [1.16.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.15.0...@amplitude/plugin-session-replay-browser@1.16.0) (2025-04-22)\n\n\n### Features\n\n* **plugin-session-replay-browser:** add an sr instance property ([#1034](https://github.com/amplitude/Amplitude-TypeScript/issues/1034)) ([7159658](https://github.com/amplitude/Amplitude-TypeScript/commit/7159658916008faec6cefacab615cb535dd2562b))\n\n\n\n\n\n# [1.15.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.14.0...@amplitude/plugin-session-replay-browser@1.15.0) (2025-04-17)\n\n\n### Features\n\n* **analytics-core:** new plugin interfaces onXXXchanged() ([#1025](https://github.com/amplitude/Amplitude-TypeScript/issues/1025)) ([e6fd23b](https://github.com/amplitude/Amplitude-TypeScript/commit/e6fd23b17809d0c7d94e7627636b200166d41a0f))\n\n\n\n\n\n# [1.14.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.13.13...@amplitude/plugin-session-replay-browser@1.14.0) (2025-04-15)\n\n\n### Features\n\n* **session-replay-browser:** migrate to core v2.x ([#1022](https://github.com/amplitude/Amplitude-TypeScript/issues/1022)) ([7a665d5](https://github.com/amplitude/Amplitude-TypeScript/commit/7a665d55fff89092ed5f2bb94caa1eb2c7efe5b1))\n\n\n\n\n\n## [1.13.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.13.12...@amplitude/plugin-session-replay-browser@1.13.13) (2025-04-10)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.13.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.13.11...@amplitude/plugin-session-replay-browser@1.13.12) (2025-04-07)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.13.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.13.10...@amplitude/plugin-session-replay-browser@1.13.11) (2025-04-07)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.13.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.13.9...@amplitude/plugin-session-replay-browser@1.13.10) (2025-04-02)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.13.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.13.8...@amplitude/plugin-session-replay-browser@1.13.9) (2025-03-25)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.13.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.13.7...@amplitude/plugin-session-replay-browser@1.13.8) (2025-03-24)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.13.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.13.6...@amplitude/plugin-session-replay-browser@1.13.7) (2025-03-21)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.13.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.13.5...@amplitude/plugin-session-replay-browser@1.13.6) (2025-03-14)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.13.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.13.4...@amplitude/plugin-session-replay-browser@1.13.5) (2025-03-06)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## [1.13.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.13.3...@amplitude/plugin-session-replay-browser@1.13.4) (2025-03-04)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n\n\n\n\n## 1.13.3 (2025-02-28)\n\n\n### Reverts\n\n* Revert \"chore(release): publish\" ([d392f62](https://github.com/amplitude/Amplitude-TypeScript/commit/d392f6290b8bb4dd955d6e6f20b00191679489c4))\n\n\n\n\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.13.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.13.2-beta.0...@amplitude/plugin-session-replay-browser@1.13.2) (2025-02-14)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.13.2-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.13.1...@amplitude/plugin-session-replay-browser@1.13.2-beta.0) (2025-02-14)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.13.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.13.0...@amplitude/plugin-session-replay-browser@1.13.1) (2025-02-13)\n\n### Bug Fixes\n\n- add safe access to loggerProvider in session replay plugin\n  ([#949](https://github.com/amplitude/Amplitude-TypeScript/issues/949))\n  ([54f16ef](https://github.com/amplitude/Amplitude-TypeScript/commit/54f16ef1a2c9936a012d08ff6d28267706a899f3))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.13.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.12.1...@amplitude/plugin-session-replay-browser@1.13.0) (2025-02-03)\n\n### Features\n\n- **plugin-session-replay-browser:** support custom device id\n  ([#951](https://github.com/amplitude/Amplitude-TypeScript/issues/951))\n  ([6f63ca5](https://github.com/amplitude/Amplitude-TypeScript/commit/6f63ca5d78e4ee4d1f4b2cc2693fa95a6a90382e))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.12.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.12.0...@amplitude/plugin-session-replay-browser@1.12.1) (2025-01-14)\n\n### Bug Fixes\n\n- **plugin-session-replay-browser:** default forceSessionTracking to false\n  ([#944](https://github.com/amplitude/Amplitude-TypeScript/issues/944))\n  ([bf8f66c](https://github.com/amplitude/Amplitude-TypeScript/commit/bf8f66c4a6d438295bbe4fd274b89d58a798799c))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.12.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.11.1...@amplitude/plugin-session-replay-browser@1.12.0) (2024-12-17)\n\n### Features\n\n- **session-replay-browser:** WebWorker support for compression\n  ([#932](https://github.com/amplitude/Amplitude-TypeScript/issues/932))\n  ([4ebe04a](https://github.com/amplitude/Amplitude-TypeScript/commit/4ebe04adda714ae02851835c49e6bc224df7f4af))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.11.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.11.0...@amplitude/plugin-session-replay-browser@1.11.1) (2024-12-16)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.11.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.10.0...@amplitude/plugin-session-replay-browser@1.11.0) (2024-12-13)\n\n### Features\n\n- **session-replay-browser:** support custom urls for remote config and track endpoints.\n  ([#931](https://github.com/amplitude/Amplitude-TypeScript/issues/931))\n  ([af6aa43](https://github.com/amplitude/Amplitude-TypeScript/commit/af6aa43b12fa577b5fa8434065b43e4e94668f0e))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.10.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.9.0...@amplitude/plugin-session-replay-browser@1.10.0) (2024-12-06)\n\n### Features\n\n- **session-replay:** supporting string session id\n  ([deecad4](https://github.com/amplitude/Amplitude-TypeScript/commit/deecad4f6a9e5522b5d567f5ff48513c7e2ae880))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.9.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.8.2...@amplitude/plugin-session-replay-browser@1.9.0) (2024-12-06)\n\n### Features\n\n- **session-replay-browser:** supporting string session id\n  ([633aa04](https://github.com/amplitude/Amplitude-TypeScript/commit/633aa048c7794660eef6b538dfe3b1cecd93b020))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.8.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.8.2-beta.0...@amplitude/plugin-session-replay-browser@1.8.2) (2024-10-30)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.8.2-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.8.1...@amplitude/plugin-session-replay-browser@1.8.2-beta.0) (2024-10-29)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.8.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.8.0...@amplitude/plugin-session-replay-browser@1.8.1) (2024-10-24)\n\n### Bug Fixes\n\n- **plugin-session-replay-browser:** add error catching/isolation to sr plugin apis\n  ([ab6cbb5](https://github.com/amplitude/Amplitude-TypeScript/commit/ab6cbb599db322b9b27685b3fcfc0d60a3cd41b3))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.8.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.7.3...@amplitude/plugin-session-replay-browser@1.8.0) (2024-10-10)\n\n### Features\n\n- **session-replay-browser:** in memory events storage\n  ([#895](https://github.com/amplitude/Amplitude-TypeScript/issues/895))\n  ([85f4fd1](https://github.com/amplitude/Amplitude-TypeScript/commit/85f4fd1adcbc9cdde8d1ea97ead9655acca15461))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.7.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.7.2...@amplitude/plugin-session-replay-browser@1.7.3) (2024-10-08)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.7.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.7.1...@amplitude/plugin-session-replay-browser@1.7.2) (2024-10-04)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.7.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.7.0...@amplitude/plugin-session-replay-browser@1.7.1) (2024-10-02)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.7.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.6.25...@amplitude/plugin-session-replay-browser@1.7.0) (2024-09-24)\n\n### Features\n\n- **session replay:** adding timeout into config\n  ([fd67792](https://github.com/amplitude/Amplitude-TypeScript/commit/fd677929ef772b46e103d002230e87fa2d3b587d))\n- **session replay:** performance config for requestIdleCallback\n  ([df7983e](https://github.com/amplitude/Amplitude-TypeScript/commit/df7983ea1d1a255cdb770a0e8cab23f875b5a2ea))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.6.25](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.6.24...@amplitude/plugin-session-replay-browser@1.6.25) (2024-09-18)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.6.24](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.6.23...@amplitude/plugin-session-replay-browser@1.6.24) (2024-09-10)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.6.23](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.6.22...@amplitude/plugin-session-replay-browser@1.6.23) (2024-08-27)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.6.22](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.6.21...@amplitude/plugin-session-replay-browser@1.6.22) (2024-08-23)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.6.21](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.6.20...@amplitude/plugin-session-replay-browser@1.6.21) (2024-08-19)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.6.20](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.6.19...@amplitude/plugin-session-replay-browser@1.6.20) (2024-08-14)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.6.19](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.6.18...@amplitude/plugin-session-replay-browser@1.6.19) (2024-08-13)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.6.18](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.6.17...@amplitude/plugin-session-replay-browser@1.6.18) (2024-08-13)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.6.17](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.6.16...@amplitude/plugin-session-replay-browser@1.6.17) (2024-08-12)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.6.16](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.6.15...@amplitude/plugin-session-replay-browser@1.6.16) (2024-08-06)\n\n### Bug Fixes\n\n- **session replay:** add version and sdk type\n  ([803c8f9](https://github.com/amplitude/Amplitude-TypeScript/commit/803c8f9e99a418939c1793d0106d9c7404c0e22d))\n- **session replay:** send library header for version and type of sdk\n  ([b2fedfc](https://github.com/amplitude/Amplitude-TypeScript/commit/b2fedfce3284cc436e9c87d829dc127b88d047b5))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.6.15](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.6.14...@amplitude/plugin-session-replay-browser@1.6.15) (2024-08-02)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.6.14](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.6.13...@amplitude/plugin-session-replay-browser@1.6.14) (2024-08-01)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.6.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.6.12...@amplitude/plugin-session-replay-browser@1.6.13) (2024-07-30)\n\n### Bug Fixes\n\n- **session-replay-browser:** we need to rerun build for the plugin or the version changes won't update\n  ([#826](https://github.com/amplitude/Amplitude-TypeScript/issues/826))\n  ([61deb3b](https://github.com/amplitude/Amplitude-TypeScript/commit/61deb3bd5e2e72353066bc4c16ab4139984a3f7d))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.6.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.6.11...@amplitude/plugin-session-replay-browser@1.6.12) (2024-07-29)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.6.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.6.10...@amplitude/plugin-session-replay-browser@1.6.11) (2024-07-25)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.6.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.6.9...@amplitude/plugin-session-replay-browser@1.6.10) (2024-07-25)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.6.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.6.8...@amplitude/plugin-session-replay-browser@1.6.9) (2024-07-24)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.6.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.6.7...@amplitude/plugin-session-replay-browser@1.6.8) (2024-07-23)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.6.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.6.6...@amplitude/plugin-session-replay-browser@1.6.7) (2024-07-23)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.6.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.6.5...@amplitude/plugin-session-replay-browser@1.6.6) (2024-07-05)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.6.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.6.4...@amplitude/plugin-session-replay-browser@1.6.5) (2024-07-01)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.6.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.6.3...@amplitude/plugin-session-replay-browser@1.6.4) (2024-06-25)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.6.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.6.2...@amplitude/plugin-session-replay-browser@1.6.3) (2024-06-24)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.6.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.6.1...@amplitude/plugin-session-replay-browser@1.6.2) (2024-06-24)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.6.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.6.0...@amplitude/plugin-session-replay-browser@1.6.1) (2024-06-17)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.6.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.5.0...@amplitude/plugin-session-replay-browser@1.6.0) (2024-06-17)\n\n### Features\n\n- **session-replay-browser:** adds capability to track click events in session replay\n  ([#776](https://github.com/amplitude/Amplitude-TypeScript/issues/776))\n  ([6eee2b9](https://github.com/amplitude/Amplitude-TypeScript/commit/6eee2b9b9970ebaf18525f71b82de96ea9687862))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.5.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.4.2...@amplitude/plugin-session-replay-browser@1.5.0) (2024-06-12)\n\n### Features\n\n- **session replay:** add ability to set inline stylesheets to false\n  ([f78b0c9](https://github.com/amplitude/Amplitude-TypeScript/commit/f78b0c9a5bdd6803119292e54acf6b1b1c3c7524))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.4.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.4.1...@amplitude/plugin-session-replay-browser@1.4.2) (2024-06-11)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.4.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.4.0...@amplitude/plugin-session-replay-browser@1.4.1) (2024-06-07)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.4.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.3.2...@amplitude/plugin-session-replay-browser@1.4.0) (2024-06-07)\n\n### Features\n\n- **session-replay-browser:** additional privacy configs\n  ([#756](https://github.com/amplitude/Amplitude-TypeScript/issues/756))\n  ([4812beb](https://github.com/amplitude/Amplitude-TypeScript/commit/4812bebeb5c31c1a37eef77687ed50051f170959))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.3.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.3.2-beta.0...@amplitude/plugin-session-replay-browser@1.3.2) (2024-06-06)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.3.2-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.3.1...@amplitude/plugin-session-replay-browser@1.3.2-beta.0) (2024-06-06)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.3.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.3.0...@amplitude/plugin-session-replay-browser@1.3.1) (2024-05-28)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.3.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.2.3...@amplitude/plugin-session-replay-browser@1.3.0) (2024-05-16)\n\n### Features\n\n- **session-replay-browser:** fetch privacy configs remotely and join with local\n  ([c224041](https://github.com/amplitude/Amplitude-TypeScript/commit/c22404195e894c85d1d463b3b6d14e52beeeef50))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.2.2...@amplitude/plugin-session-replay-browser@1.2.3) (2024-05-16)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.2.1...@amplitude/plugin-session-replay-browser@1.2.2) (2024-05-15)\n\n### Bug Fixes\n\n- **plugin session replay browser:** remove circular dependency\n  ([177c8d8](https://github.com/amplitude/Amplitude-TypeScript/commit/177c8d8add53bc8869bf4b77af8586659e747edd))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.2.0...@amplitude/plugin-session-replay-browser@1.2.1) (2024-05-10)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.2.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.1.9...@amplitude/plugin-session-replay-browser@1.2.0) (2024-05-06)\n\n### Features\n\n- **session replay:** add ability to wait for setSessionId process to complete\n  ([a60b0c9](https://github.com/amplitude/Amplitude-TypeScript/commit/a60b0c9f3fe668c87d82d75a4f566262107e748c))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.1.8...@amplitude/plugin-session-replay-browser@1.1.9) (2024-04-23)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.1.7...@amplitude/plugin-session-replay-browser@1.1.8) (2024-04-22)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.1.6...@amplitude/plugin-session-replay-browser@1.1.7) (2024-04-18)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.1.5...@amplitude/plugin-session-replay-browser@1.1.6) (2024-04-15)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.1.4...@amplitude/plugin-session-replay-browser@1.1.5) (2024-04-12)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.1.3...@amplitude/plugin-session-replay-browser@1.1.4) (2024-04-09)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.1.2...@amplitude/plugin-session-replay-browser@1.1.3) (2024-04-08)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.1.1...@amplitude/plugin-session-replay-browser@1.1.2) (2024-04-02)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.1.0...@amplitude/plugin-session-replay-browser@1.1.1) (2024-03-26)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.1.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.1.0-beta.0...@amplitude/plugin-session-replay-browser@1.1.0) (2024-03-14)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.1.0-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.0.2...@amplitude/plugin-session-replay-browser@1.1.0-beta.0) (2024-03-13)\n\n### Bug Fixes\n\n- **session replay:** fix test typo and add documentation\n  ([dbfe608](https://github.com/amplitude/Amplitude-TypeScript/commit/dbfe60817c35d76d4b32fb70e9c74c7305d7ecbf))\n\n### Features\n\n- **session replay:** add option to disable session tracking\n  ([af0c4e7](https://github.com/amplitude/Amplitude-TypeScript/commit/af0c4e7e9ab9e4d5dea0844260e411a97883693b))\n- **session replay:** fix event tagging\n  ([1373265](https://github.com/amplitude/Amplitude-TypeScript/commit/1373265b6e6ada9b354646aa5118d3eefa791511))\n- **session replay:** improve initialization\n  ([dbdd2fd](https://github.com/amplitude/Amplitude-TypeScript/commit/dbdd2fd82fa9e5d222d6ac83b8ec2cbeb5acc071))\n- **session replay:** rename option to forceSessionRecording\n  ([4a8c7b1](https://github.com/amplitude/Amplitude-TypeScript/commit/4a8c7b1d47c3de24f6e0d9e4daf2ffedf8bd3a87))\n- **session replay:** update dependency versioning\n  ([17e8649](https://github.com/amplitude/Amplitude-TypeScript/commit/17e86493753f95f0720a17d5a0deea03941fda1f))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.0.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@1.0.1...@amplitude/plugin-session-replay-browser@1.0.2) (2024-02-10)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.0.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.11.0-beta.0...@amplitude/plugin-session-replay-browser@1.0.1) (2024-02-07)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.11.0-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.10.2...@amplitude/plugin-session-replay-browser@0.11.0-beta.0) (2024-02-05)\n\n### Features\n\n- session seplay debug mode\n  ([98654dd](https://github.com/amplitude/Amplitude-TypeScript/commit/98654dd7358b393c542fada1b46d570d8fe213f7))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.10.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.10.1...@amplitude/plugin-session-replay-browser@0.10.2) (2024-01-05)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.10.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.10.0...@amplitude/plugin-session-replay-browser@0.10.1) (2023-12-19)\n\n### Bug Fixes\n\n- Amp 90629 remove sr enrichment plugin on teardown\n  ([#637](https://github.com/amplitude/Amplitude-TypeScript/issues/637))\n  ([e353e09](https://github.com/amplitude/Amplitude-TypeScript/commit/e353e095b82f5abda9f988b58a5fcfd051ef61f5))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.10.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.9.0...@amplitude/plugin-session-replay-browser@0.10.0) (2023-12-06)\n\n### Features\n\n- convert session replay plugin to be a destination plugin with flush support\n  ([#633](https://github.com/amplitude/Amplitude-TypeScript/issues/633))\n  ([bfa643f](https://github.com/amplitude/Amplitude-TypeScript/commit/bfa643fa92d3cc6b84e924d7a22f502cee289035))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.9.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.8.1...@amplitude/plugin-session-replay-browser@0.9.0) (2023-12-05)\n\n### Features\n\n- expose rrweb blockselector\n  ([09b33b7](https://github.com/amplitude/Amplitude-TypeScript/commit/09b33b71ab885e8c954fe28c1e1e54360784755b))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.8.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.7.1...@amplitude/plugin-session-replay-browser@0.8.1) (2023-11-16)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.7.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.7.1-beta.0...@amplitude/plugin-session-replay-browser@0.7.1) (2023-11-16)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.7.1-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.7.0...@amplitude/plugin-session-replay-browser@0.7.1-beta.0) (2023-11-10)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.7.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.6.16...@amplitude/plugin-session-replay-browser@0.7.0) (2023-11-02)\n\n### Features\n\n- **session replay:** parse sessionReplayId for sessionId and deviceId\n  ([990ddaf](https://github.com/amplitude/Amplitude-TypeScript/commit/990ddaf102465e52d84e496d280c8aada5f94944))\n- **session replay:** remove session replay id interface and expose sr properties to plugin\n  ([a7ea04a](https://github.com/amplitude/Amplitude-TypeScript/commit/a7ea04a9c03a0b69a1cab4462d8e1cae2656c79f))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.16](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.6.15...@amplitude/plugin-session-replay-browser@0.6.16) (2023-10-26)\n\n### Bug Fixes\n\n- **session replay:** use internal fork of rrweb\n  ([8f96d1c](https://github.com/amplitude/Amplitude-TypeScript/commit/8f96d1ceb7d31dabd2fc8c34aba3d01cfa886f79))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.15](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.6.14...@amplitude/plugin-session-replay-browser@0.6.15) (2023-10-17)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.14](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.6.13...@amplitude/plugin-session-replay-browser@0.6.14) (2023-09-27)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.6.12...@amplitude/plugin-session-replay-browser@0.6.13) (2023-09-21)\n\n### Bug Fixes\n\n- **session replay plugin:** update plugin to use the sessionReplayProperties fn\n  ([7330d49](https://github.com/amplitude/Amplitude-TypeScript/commit/7330d4912c719804a3a5082d6b75a976d68cbda0))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.6.11...@amplitude/plugin-session-replay-browser@0.6.12) (2023-09-21)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.6.10...@amplitude/plugin-session-replay-browser@0.6.11) (2023-09-18)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.6.9...@amplitude/plugin-session-replay-browser@0.6.10) (2023-09-12)\n\n### Bug Fixes\n\n- **session replay:** remove beta tag from package.json to update public facing version\n  ([fa72e9b](https://github.com/amplitude/Amplitude-TypeScript/commit/fa72e9bacc6132ef37122f0a63419150f2f690e2))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.6.8...@amplitude/plugin-session-replay-browser@0.6.9) (2023-09-12)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.6.7...@amplitude/plugin-session-replay-browser@0.6.8) (2023-09-11)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.6.6...@amplitude/plugin-session-replay-browser@0.6.7) (2023-09-08)\n\n### Bug Fixes\n\n- **session replay plugin:** delete unused file\n  ([41faedc](https://github.com/amplitude/Amplitude-TypeScript/commit/41faedceaba39ea743a83d734fc0462b2fb072df))\n- **session replay plugin:** remove use of client-common\n  ([f26ab9c](https://github.com/amplitude/Amplitude-TypeScript/commit/f26ab9cf2135f550eac91938a44d37972308339d))\n- **session replay plugin:** test\n  ([ada95d7](https://github.com/amplitude/Amplitude-TypeScript/commit/ada95d70bbafbb700d593579b8165e51916fa0c7))\n- **session replay plugin:** update dependencies and remove eslint override\n  ([2c63830](https://github.com/amplitude/Amplitude-TypeScript/commit/2c638300880234d3aaf784f72fc04e4deaaec221))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.6.5...@amplitude/plugin-session-replay-browser@0.6.6) (2023-08-22)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.6.4...@amplitude/plugin-session-replay-browser@0.6.5) (2023-08-22)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.6.3...@amplitude/plugin-session-replay-browser@0.6.4) (2023-08-17)\n\n### Bug Fixes\n\n- **plugins:** add error handling to session replay and bump rrweb version\n  ([651144f](https://github.com/amplitude/Amplitude-TypeScript/commit/651144fa515cb68e5a75751d99d8316ca648377b))\n- **plugins:** add test coverage\n  ([62bdf38](https://github.com/amplitude/Amplitude-TypeScript/commit/62bdf38a74779ad4a557cf2759164908b0e3edb6))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.6.2...@amplitude/plugin-session-replay-browser@0.6.3) (2023-08-11)\n\n### Bug Fixes\n\n- **plugins:** add analytics-core as dependency\n  ([4e8c567](https://github.com/amplitude/Amplitude-TypeScript/commit/4e8c5677e42ad4039fcb09aca0873da8f308a1ca))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.6.1...@amplitude/plugin-session-replay-browser@0.6.2) (2023-08-11)\n\n### Bug Fixes\n\n- **plugin:** override lerna autocorrect packages\n  ([4491652](https://github.com/amplitude/Amplitude-TypeScript/commit/44916522530868a9cffff0dad1468c08e12891b5))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.6.0...@amplitude/plugin-session-replay-browser@0.6.1) (2023-08-10)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.6.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.5.1...@amplitude/plugin-session-replay-browser@0.6.0) (2023-08-07)\n\n### Features\n\n- **plugins:** add teardown functionality to session replay plugin\n  ([8d4afd6](https://github.com/amplitude/Amplitude-TypeScript/commit/8d4afd64a2e90604f5c990a9a3df73082850b963))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.5.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.5.0...@amplitude/plugin-session-replay-browser@0.5.1) (2023-08-04)\n\n### Bug Fixes\n\n- **plugins:** use hash to calculate is session is included in sample\n  ([4c7e579](https://github.com/amplitude/Amplitude-TypeScript/commit/4c7e5791b02114caf5ae95d7612fef0f339fbfee))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.5.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.4.2...@amplitude/plugin-session-replay-browser@0.5.0) (2023-08-02)\n\n### Bug Fixes\n\n- **plugins:** fix edge case when opening tab in background\n  ([2857038](https://github.com/amplitude/Amplitude-TypeScript/commit/2857038310110b9bae57ad45295107895586a847))\n\n### Features\n\n- **session replay eu:** route rraffic to eu based on config\n  ([0168653](https://github.com/amplitude/Amplitude-TypeScript/commit/016865335d05371849738403817410e2afc0ca57))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.4.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.4.1...@amplitude/plugin-session-replay-browser@0.4.2) (2023-08-01)\n\n### Bug Fixes\n\n- **plugins:** correctly fetch shouldRecord from store and clean up old store entries\n  ([1e8317b](https://github.com/amplitude/Amplitude-TypeScript/commit/1e8317b64d8868bd4b5e584f50ffec4ca54dcadc))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.4.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.4.0...@amplitude/plugin-session-replay-browser@0.4.1) (2023-07-27)\n\n### Bug Fixes\n\n- **plugins:** prevent any activity from occurring if document does not have focus\n  ([675cb82](https://github.com/amplitude/Amplitude-TypeScript/commit/675cb82d248f5eb564150be479228469f12d4fc8))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.4.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.3.0...@amplitude/plugin-session-replay-browser@0.4.0) (2023-07-27)\n\n### Features\n\n- **plugins:** add option to block elements based on amp-block class in session replay\n  ([fb261b8](https://github.com/amplitude/Amplitude-TypeScript/commit/fb261b89db96e707de6509ccbf57f319c696ef27))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.3.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.2.1...@amplitude/plugin-session-replay-browser@0.3.0) (2023-07-27)\n\n### Bug Fixes\n\n- **plugins:** ensure config.optout takes priority over sample rate\n  ([5438a43](https://github.com/amplitude/Amplitude-TypeScript/commit/5438a438ec062b3011234b0fea82b54351a12864))\n- **plugins:** update README for session replay\n  ([ed20cf2](https://github.com/amplitude/Amplitude-TypeScript/commit/ed20cf22180b33f29fd71a1439de26706d6ec4ff))\n\n### Features\n\n- **plugins:** abide by global opt out for session recording\n  ([25bd516](https://github.com/amplitude/Amplitude-TypeScript/commit/25bd516849c9a7fc346c6a868c664e70cdeb5cba))\n- **plugins:** add a configuration option for sampling rate\n  ([bcabfa4](https://github.com/amplitude/Amplitude-TypeScript/commit/bcabfa4ea784187edc85a85bce9a2c68dde411e5))\n- **plugins:** add default tracking of sessions to session replay plugin\n  ([6aeb511](https://github.com/amplitude/Amplitude-TypeScript/commit/6aeb511e5a7db760ebaa86aee0d7756fb85e9020))\n- **plugins:** add masking controls to session replay and reorganize constants and helper fns\n  ([e46a42e](https://github.com/amplitude/Amplitude-TypeScript/commit/e46a42e430c7560a4e9da322b10238fdbf4f1bc5))\n- **plugins:** update config additions to store in idb\n  ([5c04c3c](https://github.com/amplitude/Amplitude-TypeScript/commit/5c04c3cc0e8ef287898f2571f8c2a3e9e00311be))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.2.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.2.0...@amplitude/plugin-session-replay-browser@0.2.1) (2023-07-26)\n\n### Bug Fixes\n\n- **plugins:** stop recording when document.hasFocus is false\n  ([7fb6059](https://github.com/amplitude/Amplitude-TypeScript/commit/7fb6059716a09fae3c62a238d100fecc06861e67))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.2.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.1.3...@amplitude/plugin-session-replay-browser@0.2.0) (2023-07-20)\n\n### Bug Fixes\n\n- **plugins:** reduce min interval to 500ms\n  ([b770d44](https://github.com/amplitude/Amplitude-TypeScript/commit/b770d44086306db15a378af6b1c3590afdb0ec58))\n\n### Features\n\n- **plugins:** solve timing issues with multiple tabs\n  ([d2e9a0c](https://github.com/amplitude/Amplitude-TypeScript/commit/d2e9a0cc7c455dcdf13ea2fa303d2fbd50911536))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.1.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.1.2...@amplitude/plugin-session-replay-browser@0.1.3) (2023-07-13)\n\n### Bug Fixes\n\n- **plugins:** change timing of record upon initialization for session replay plugin\n  ([1a55aee](https://github.com/amplitude/Amplitude-TypeScript/commit/1a55aeede742f688f87f128a13cf41f91bda5224))\n- **plugins:** should only initiate recording on session start if recording is not initiated\n  ([708d4b9](https://github.com/amplitude/Amplitude-TypeScript/commit/708d4b94d0d8714b35fe3984e604327e34b446f0))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.1.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.1.1...@amplitude/plugin-session-replay-browser@0.1.2) (2023-07-11)\n\n### Bug Fixes\n\n- **plugins:** need to send first two events immediately for replayer to work\n  ([721a399](https://github.com/amplitude/Amplitude-TypeScript/commit/721a3997673d700b6bda9302b076be0f3fab7c09))\n- **plugins:** pr feedback\n  ([59802fb](https://github.com/amplitude/Amplitude-TypeScript/commit/59802fbc0c949373a2fd3566ed3db6a871e442a4))\n- **plugins:** remove console log\n  ([fc263ed](https://github.com/amplitude/Amplitude-TypeScript/commit/fc263ed34a955f0bc987cf7281a374065f95045c))\n- **plugins:** update timing of sending batches of session replay events\n  ([fadd7c0](https://github.com/amplitude/Amplitude-TypeScript/commit/fadd7c0cd24f78c6dd317098fe6dfad951ce206e))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.1.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-browser@0.1.0...@amplitude/plugin-session-replay-browser@0.1.1) (2023-07-05)\n\n### Bug Fixes\n\n- allow literal values for plugin type ([#468](https://github.com/amplitude/Amplitude-TypeScript/issues/468))\n  ([603e3ef](https://github.com/amplitude/Amplitude-TypeScript/commit/603e3eff81a3d03082544541a673df955cf30118))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# 0.1.0 (2023-06-28)\n\n### Features\n\n- **plugins:** change file names\n  ([2c76247](https://github.com/amplitude/Amplitude-TypeScript/commit/2c76247f8b994a52650db26dca3603319d13857e))\n- **plugins:** expose function as external interface\n  ([61185ac](https://github.com/amplitude/Amplitude-TypeScript/commit/61185acc3504b96be9ea8144fc62967937235b37))\n"
  },
  {
    "path": "packages/plugin-session-replay-browser/README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://amplitude.com\" target=\"_blank\" align=\"center\">\n    <img src=\"https://static.amplitude.com/lightning/46c85bfd91905de8047f1ee65c7c93d6fa9ee6ea/static/media/amplitude-logo-with-text.4fb9e463.svg\" width=\"280\">\n  </a>\n  <br />\n</p>\n\n# @amplitude/plugin-session-replay-browser\n\nOfficial Browser SDK plugin for session replay\n\n## Installation\n\nThis package is published on NPM registry and is available to be installed using npm and yarn.\n\n```sh\n# npm\nnpm install @amplitude/plugin-session-replay-browser\n\n# yarn\nyarn add @amplitude/plugin-session-replay-browser\n```\n\n## Usage\n\nThis plugin works on top of Amplitude Browser SDK and adds session replay features to built-in features. To use this plugin, you need to install `@amplitude/analytics-browser` version `v1.9.1` or later.\n\nThis plugin requires that default tracking for sessions is enabled. If default tracking for sessions is not enabled in the config, the plugin will automatically enable it.\n\n### 1. Import Amplitude packages\n\n* `@amplitude/analytics-browser`\n* `@amplitude/plugin-session-replay-browser`\n\n```typescript\nimport * as amplitude from '@amplitude/analytics-browser';\nimport { sessionReplayPlugin } from '@amplitude/plugin-session-replay-browser';\n```\n\n### 2. Instantiate Session Replay plugin\n\nThe plugin must be registered with the amplitude instance via the following code. The plugin accepts an optional parameter which is an `Object` to configure the plugin based on your use case.\n\n```typescript\namplitude.init(API_KEY);\nconst sessionReplayTracking = sessionReplayPlugin({\n  sampleRate: undefined\n});\n```\n\n\n#### Options\n\n|Name|Type|Default|Required|Description|\n|-|-|-|-|-|\n|`sampleRate`|`number`|`undefined`|Yes|Use this option to control how many sessions will be selected for replay collection. A selected session will be collected for replay, while sessions that are not selected will not.  <br></br>The number should be a decimal between 0 and 1, ie `0.01`, representing the fraction of sessions you would like to have randomly selected for replay collection. Over a large number of sessions, `0.01` would select `1%` of those sessions.|\n|`privacyConfig`|`object`|`undefined`|No| Supports advanced masking configs with CSS selectors.|\n|`forceSessionTracking`|`boolean`|`false`|No|If this is enabled we will force the browser SDK to also send start and end session events.|\n|`debugMode`|`boolean`|`false`|No| Adds additional debug event property to help debug instrumentation issues (such as mismatching apps). Only recommended for debugging initial setup, and not recommended for production.|\n|`configServerUrl`|`string`|No|`undefined`|Specifies the endpoint URL to fetch remote configuration. If provided, it overrides the default server zone configuration.|\n|`trackServerUrl`|`string`|No|`undefined`|Specifies the endpoint URL for sending session replay data. If provided, it overrides the default server zone configuration.|\n|`shouldInlineStylesheet`|`boolean`|No|`true`|If stylesheets are inlined, the contents of the stylesheet will be stored. During replay, the stored stylesheet will be used instead of attempting to fetch it remotely. This prevents replays from appearing broken due to missing stylesheets. Note: Inlining stylesheets may not work in all cases. If this is `undefined` stylesheets will be inlined.|\n|`storeType`|`string`|No|`idb`|Specifies how replay events should be stored. `idb` uses IndexedDB to persist replay events when all events cannot be sent during capture. `memory` stores replay events only in memory, meaning events are lost when the page is closed. If IndexedDB is unavailable, the system falls back to `memory`.|\n|`performanceConfig.enabled`|`boolean`|No|`true`|If enabled, event compression will be deferred to occur during the browser's idle periods.|\n|`performanceConfig.timeout`|`number`|No|`undefined`|Optional timeout in milliseconds for the `requestIdleCallback` API. If specified, this value will be used to set a maximum time for the browser to wait before executing the deferred compression task, even if the browser is not idle.|\n|`experimental.useWebWorker`|`boolean`|No|`false`|If the SDK should compress the replay events using a webworker.|\n\n### 3. Install plugin to Amplitude SDK\n\n```typescript\namplitude.add(sessionReplayTracking);\n```\n\n## Privacy\nBy default, the session replay will mask all inputs, meaning the text in inputs will appear in a session replay as asterisks: `***`. You may require more specific masking controls based on your use case, so we offer the following controls:\n\n#### 1. Unmask inputs\nIn your application code, add the class `.amp-unmask` to any __input__ whose text you'd like to have unmasked in the replay. In the session replay, it will be possible to read the exact text entered into an input with this class, the text will not be converted to asterisks.\n\n#### 2. Mask non-input elements\nIn your application code, add the class `.amp-mask` to any __non-input element__ whose text you'd like to have masked from the replay. The text in the element, as well as it's children, will all be converted to asterisks.\n\n#### 3. Block non-text elements\nIn your application code, add the class `.amp-block` to any element you would like to have blocked from the collection of the replay. The element will appear in the replay as a placeholder with the same dimensions.\n\n#### 4. Block elements by CSS selectors. \nIn the SDK initialization code, you can configure the SDK to block elements based on CSS selectors.\n```typescript\nconst sessionReplayTracking = sessionReplayPlugin({\n  sampleRate: 0.01,\n  privacyConfig: {\n      blockSelector: ['.ignoreClass', '#ignoreId']\n  }\n});\n```\n\n## Debugging \n\n### Using debugMode when developing locally\nSince the Session Replay plugin only records and tags events when the page is in focus, this can sometimes be problematic when developing locally with the browser console open. If you are having issues with the replays not showing up (while your quota usage going up). Try turning setting `debugMode:true` to see if that helps with the issue.\n"
  },
  {
    "path": "packages/plugin-session-replay-browser/jest.config.js",
    "content": "const baseConfig = require('../../jest.config.js');\nconst package = require('./package');\n\nmodule.exports = {\n  ...baseConfig,\n  transform: {\n    ...baseConfig.transform,\n    '\\\\.[jt]sx?$': ['babel-jest', { plugins: ['@babel/plugin-transform-modules-commonjs'] }], // needed for @medv/finder\n  },\n  transformIgnorePatterns: [`../../node_modules/(?!@medv)`],\n  displayName: package.name,\n  rootDir: '.',\n  testEnvironment: 'jsdom',\n  coveragePathIgnorePatterns: ['index.ts'],\n  setupFilesAfterEnv: ['./test/jest-setup.js'],\n  testEnvironment: '<rootDir>/test/jsdom-extended.js',\n  testEnvironmentOptions: {\n    customExportConditions: [''],\n  },\n};\n"
  },
  {
    "path": "packages/plugin-session-replay-browser/package.json",
    "content": "{\n  \"name\": \"@amplitude/plugin-session-replay-browser\",\n  \"version\": \"1.30.4\",\n  \"description\": \"\",\n  \"author\": \"Amplitude Inc\",\n  \"homepage\": \"https://github.com/amplitude/Amplitude-TypeScript\",\n  \"license\": \"MIT\",\n  \"main\": \"lib/cjs/index.js\",\n  \"module\": \"lib/esm/index.js\",\n  \"types\": \"lib/esm/index.d.ts\",\n  \"sideEffects\": false,\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/amplitude/Amplitude-TypeScript.git\"\n  },\n  \"scripts\": {\n    \"build\": \"pnpm bundle && pnpm build:es5 && pnpm build:esm\",\n    \"bundle\": \"rollup --config rollup.config.js\",\n    \"build:es5\": \"tsc -p ./tsconfig.es5.json\",\n    \"build:esm\": \"tsc -p ./tsconfig.esm.json\",\n    \"watch\": \"tsc -p ./tsconfig.esm.json --watch\",\n    \"clean\": \"rimraf node_modules lib coverage\",\n    \"fix\": \"pnpm fix:eslint & pnpm fix:prettier\",\n    \"fix:eslint\": \"eslint '{src,test}/**/*.ts' --fix\",\n    \"fix:prettier\": \"prettier --write \\\"{src,test}/**/*.ts\\\"\",\n    \"lint\": \"pnpm lint:eslint & pnpm lint:prettier\",\n    \"lint:eslint\": \"eslint '{src,test}/**/*.ts'\",\n    \"lint:prettier\": \"prettier --check \\\"{src,test}/**/*.ts\\\"\",\n    \"publish\": \"node ./scripts/publish/upload-to-s3.js\",\n    \"test\": \"jest\",\n    \"typecheck\": \"tsc -p ./tsconfig.json\",\n    \"version\": \"pnpm version-file && GENERATE_SNIPPET=true pnpm build\",\n    \"version-file\": \"echo '// Autogenerated by `pnpm version-file`. DO NOT EDIT' > src/version.ts && node -p \\\"'export const VERSION = \\\\'' + require('./package.json').version + '\\\\';'\\\" >> src/version.ts\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/amplitude/Amplitude-TypeScript/issues\"\n  },\n  \"dependencies\": {\n    \"@amplitude/analytics-client-common\": \"workspace:*\",\n    \"@amplitude/analytics-core\": \"workspace:*\",\n    \"@amplitude/analytics-types\": \"workspace:*\",\n    \"@amplitude/rrweb-plugin-console-record\": \"2.0.0-alpha.40\",\n    \"@amplitude/rrweb-record\": \"2.0.0-alpha.40\",\n    \"@amplitude/session-replay-browser\": \"workspace:*\",\n    \"idb-keyval\": \"^6.2.1\",\n    \"tslib\": \"^2.4.1\"\n  },\n  \"devDependencies\": {\n    \"@aws-sdk/client-s3\": \"^3.229.0\",\n    \"@rollup/plugin-commonjs\": \"^23.0.4\",\n    \"@rollup/plugin-node-resolve\": \"^15.0.1\",\n    \"@rollup/plugin-typescript\": \"^10.0.1\",\n    \"fake-indexeddb\": \"4.0.2\",\n    \"msw\": \"^2.3.1\",\n    \"node-fetch\": \"^3.3.2\",\n    \"rollup\": \"^2.79.1\",\n    \"rollup-plugin-execute\": \"^1.1.1\",\n    \"rollup-plugin-gzip\": \"^3.1.0\",\n    \"rollup-plugin-sourcemaps\": \"^0.6.3\",\n    \"rollup-plugin-terser\": \"^7.0.2\"\n  },\n  \"files\": [\n    \"lib\"\n  ]\n}\n"
  },
  {
    "path": "packages/plugin-session-replay-browser/rollup.config.js",
    "content": "import { iife } from '../../scripts/build/rollup.config';\nimport { webWorkerPlugins } from '../session-replay-browser/rollup.config';\nimport typescript from '@rollup/plugin-typescript';\nimport resolve from '@rollup/plugin-node-resolve';\nimport commonjs from '@rollup/plugin-commonjs';\nimport { terser } from 'rollup-plugin-terser';\nimport gzip from 'rollup-plugin-gzip';\n\n// Configure ESM build\nconst esm = {\n  input: 'src/index.ts',\n  output: {\n    dir: 'lib/scripts',\n    format: 'es',\n    sourcemap: true,\n    entryFileNames: 'plugin-session-replay-browser-esm.js',\n    chunkFileNames: '[name]-min.js',\n    manualChunks: {\n      'console-plugin': ['@amplitude/rrweb-plugin-console-record'],\n      'rrweb-record': ['@amplitude/rrweb-record']\n    }\n  }\n};\n\n// Configure legacy build\niife.input = 'src/index.ts';\niife.output = {\n  ...iife.output,\n  format: 'iife',\n  file: 'lib/scripts/plugin-session-replay-browser-min.js',\n  name: 'sessionReplay',\n  sourcemap: true,\n  inlineDynamicImports: true\n};\n\n// Common plugins for both builds\nconst commonPlugins = [\n  typescript({\n    tsconfig: 'tsconfig.json',\n    compilerOptions: {\n      target: 'es2015',\n      module: 'es2020',\n      moduleResolution: 'node',\n      downlevelIteration: true,\n      declaration: false,\n      declarationMap: false,\n      outDir: 'lib/scripts',\n      baseUrl: '.',\n      paths: {\n        'src/*': ['src/*']\n      }\n    }\n  }),\n  resolve({\n    browser: true,\n  }),\n  commonjs(),\n  terser({\n    output: {\n      comments: false,\n    },\n  }),\n  gzip(),\n];\n\nexport default async () => {\n  const webWorkerPluginsList = await webWorkerPlugins();\n  \n  esm.plugins = [...webWorkerPluginsList, ...commonPlugins];\n  iife.plugins = [...webWorkerPluginsList, ...commonPlugins];\n\n  return [esm, iife];\n};\n\n"
  },
  {
    "path": "packages/plugin-session-replay-browser/scripts/publish/upload-to-s3.js",
    "content": "const fs = require('fs');\nconst path = require('path');\nconst { S3Client, PutObjectCommand, HeadObjectCommand } = require('@aws-sdk/client-s3');\nconst { getName, getVersion } = require('../../../../scripts/utils');\n\nconst bucket = process.env.S3_BUCKET_NAME;\nconst location = path.join(process.cwd(), 'lib', 'scripts');\nconst files = [\n  'plugin-session-replay-browser-esm.js.gz',  // ESM version\n  'plugin-session-replay-browser-min.js.gz',  // IIFE version\n  'console-plugin-min.js.gz',  // Console plugin chunk\n  'rrweb-record-min.js.gz'  // RRWeb record chunk\n];\n\nlet deployedCount = 0;\n\nconsole.log('[Publish Session Replay Browser to AWS S3] START');\nconst promises = files.map((file) => {\n  const body = fs.readFileSync(path.join(location, file));\n  const key = `libs/${file.replace('plugin-session-replay-browser', `${getName()}-${getVersion()}`)}`;\n  const client = new S3Client();\n\n  const headObject = new HeadObjectCommand({\n    Bucket: bucket,\n    Key: key,\n  });\n\n  console.log(`[Publish to AWS S3] Checking if ${key} exists in target bucket...`);\n  return client\n    .send(headObject)\n    .then(() => {\n      console.log(`[Publish to AWS S3] ${key} exists in target bucket. Skipping upload job.`);\n    })\n    .catch(() => {\n      console.log(`[Publish to AWS S3] ${key} does not exist in target bucket. Uploading to S3...`);\n      const putObject = new PutObjectCommand({\n        ACL: 'public-read',\n        Body: body,\n        Bucket: bucket,\n        CacheControl: 'max-age=31536000',\n        ContentType: 'application/javascript',\n        ContentEncoding: 'gzip',\n        Key: key,\n      });\n      return client\n        .send(putObject)\n        .then(() => {\n          console.log(`[Publish to AWS S3] Upload success for ${key}.`);\n          deployedCount += 1;\n        })\n        .catch(console.error);\n    });\n});\n\nPromise.all(promises)\n  .then(() => {\n    if (deployedCount === 0) {\n      console.log(`[Publish to AWS S3] Complete! Nothing to deploy.`);\n    } else {\n      console.log(`[Publish to AWS S3] Success! Deployed ${deployedCount}/${files.length} files.`);\n    }\n    console.log('[Publish to AWS S3] END');\n  })\n  .catch((err) => {\n    console.error(err);\n    process.exit(1);\n  }); "
  },
  {
    "path": "packages/plugin-session-replay-browser/src/constants.ts",
    "content": "import { IdentifyOperation } from '@amplitude/analytics-types';\n\nexport const PROPERTY_ADD_OPERATIONS = [\n  IdentifyOperation.SET,\n  IdentifyOperation.SET_ONCE,\n  IdentifyOperation.ADD,\n  IdentifyOperation.APPEND,\n  IdentifyOperation.PREPEND,\n  IdentifyOperation.POSTINSERT,\n];\n"
  },
  {
    "path": "packages/plugin-session-replay-browser/src/helpers.ts",
    "content": "import { Event, IdentifyOperation } from '@amplitude/analytics-types';\nimport { PROPERTY_ADD_OPERATIONS } from './constants';\n\nexport const parseUserProperties = (event: Event) => {\n  if (!event.user_properties) {\n    return;\n  }\n  let userPropertiesObj = {};\n  const userPropertyKeys = Object.keys(event.user_properties);\n\n  userPropertyKeys.forEach((identifyKey) => {\n    if (PROPERTY_ADD_OPERATIONS.includes(identifyKey as IdentifyOperation)) {\n      const typedUserPropertiesOperation =\n        event.user_properties && (event.user_properties[identifyKey as IdentifyOperation] as Record<string, any>);\n      userPropertiesObj = {\n        ...userPropertiesObj,\n        ...typedUserPropertiesOperation,\n      };\n    }\n  });\n  return userPropertiesObj;\n};\n"
  },
  {
    "path": "packages/plugin-session-replay-browser/src/index.ts",
    "content": "export { sessionReplayPlugin as plugin, sessionReplayPlugin, SessionReplayPlugin } from './session-replay';\nexport { AmplitudeSessionReplay, SessionReplayOptions } from '@amplitude/session-replay-browser';\n"
  },
  {
    "path": "packages/plugin-session-replay-browser/src/session-replay.ts",
    "content": "import {\n  BrowserClient,\n  BrowserConfig,\n  EnrichmentPlugin,\n  Event,\n  SpecialEventType,\n  getGlobalScope,\n} from '@amplitude/analytics-core';\nimport {\n  init,\n  setSessionId,\n  getSessionId,\n  getSessionReplayProperties,\n  flush,\n  shutdown,\n  evaluateTargetingAndCapture,\n  AmplitudeSessionReplay,\n  SessionReplayOptions as SessionReplayBrowserOptions,\n} from '@amplitude/session-replay-browser';\nimport { getAnalyticsConnector } from '@amplitude/analytics-client-common';\nimport { parseUserProperties } from './helpers';\nimport { SessionReplayOptions } from './typings/session-replay';\nimport { VERSION } from './version';\n\nexport const DEFAULT_EVENT_PROPERTY_PREFIX = '[Amplitude]';\nexport const DEFAULT_SESSION_REPLAY_PROPERTY = `${DEFAULT_EVENT_PROPERTY_PREFIX} Session Replay ID`;\nexport class SessionReplayPlugin implements EnrichmentPlugin<BrowserClient, BrowserConfig> {\n  static pluginName = '@amplitude/plugin-session-replay-browser';\n  name = SessionReplayPlugin.pluginName;\n  type = 'enrichment' as const;\n  // this.config is defined in setup() which will always be called first\n  // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n  // @ts-ignore\n  config: BrowserConfig | null = null;\n  options: SessionReplayOptions;\n  srInitOptions: SessionReplayBrowserOptions;\n  sessionReplay: AmplitudeSessionReplay = {\n    flush: flush,\n    getSessionId: getSessionId,\n    getSessionReplayProperties: getSessionReplayProperties,\n    init: init,\n    setSessionId: setSessionId,\n    shutdown: shutdown,\n    evaluateTargetingAndCapture: evaluateTargetingAndCapture,\n  };\n\n  constructor(options?: SessionReplayOptions) {\n    this.options = { forceSessionTracking: false, ...options };\n    this.srInitOptions = this.options;\n  }\n\n  async setup(config: BrowserConfig, _client: BrowserClient) {\n    try {\n      /* istanbul ignore next */\n      config?.loggerProvider.log(`Installing @amplitude/plugin-session-replay, version ${VERSION}.`);\n\n      this.config = config;\n\n      if (this.options.forceSessionTracking) {\n        if (typeof config.defaultTracking === 'boolean') {\n          if (config.defaultTracking === false) {\n            config.defaultTracking = {\n              pageViews: false,\n              formInteractions: false,\n              fileDownloads: false,\n              sessions: true,\n            };\n          }\n        } else {\n          config.defaultTracking = {\n            ...config.defaultTracking,\n            sessions: true,\n          };\n        }\n      }\n      const identityStore = getAnalyticsConnector(this.config.instanceName).identityStore;\n      const userProperties = identityStore.getIdentity().userProperties;\n\n      this.srInitOptions = {\n        instanceName: this.config.instanceName,\n        deviceId: this.options.deviceId ?? this.config.deviceId,\n        optOut: this.config.optOut,\n        sessionId: this.options.customSessionId ? undefined : this.config.sessionId,\n        loggerProvider: this.config.loggerProvider,\n        logLevel: this.config.logLevel,\n        flushMaxRetries: this.config.flushMaxRetries,\n        serverZone: this.config.serverZone,\n        configServerUrl: this.options.configServerUrl || this.config.remoteConfig?.serverUrl,\n        trackServerUrl: this.options.trackServerUrl,\n        sampleRate: this.options.sampleRate,\n        privacyConfig: {\n          blockSelector: this.options.privacyConfig?.blockSelector,\n          maskSelector: this.options.privacyConfig?.maskSelector,\n          unmaskSelector: this.options.privacyConfig?.unmaskSelector,\n          defaultMaskLevel: this.options.privacyConfig?.defaultMaskLevel,\n        },\n        debugMode: this.options.debugMode,\n        shouldInlineStylesheet: this.options.shouldInlineStylesheet,\n        version: { type: 'plugin', version: VERSION },\n        performanceConfig: this.options.performanceConfig,\n        storeType: this.options.storeType,\n        useWebWorker: this.options.useWebWorker ?? this.options.experimental?.useWebWorker,\n        userProperties: userProperties,\n        applyBackgroundColorToBlockedElements: this.options.applyBackgroundColorToBlockedElements,\n        interactionConfig: this.options.interactionConfig,\n        captureDocumentTitle: this.options.captureDocumentTitle,\n        enableUrlChangePolling: this.options.enableUrlChangePolling,\n        urlChangePollingInterval: this.options.urlChangePollingInterval,\n        captureAdoptedStyleSheets: this.options.captureAdoptedStyleSheets,\n        crossOriginIframes: this.options.crossOriginIframes,\n      };\n\n      await this.sessionReplay.init(config.apiKey, this.srInitOptions).promise;\n    } catch (error) {\n      /* istanbul ignore next */\n      config?.loggerProvider.error(`Session Replay: Failed to initialize due to ${(error as Error).message}`);\n    }\n  }\n\n  async onSessionIdChanged(sessionId: number): Promise<void> {\n    this.config?.loggerProvider.debug(\n      `Analytics session id is changed to ${sessionId}, SR session id is ${String(this.sessionReplay.getSessionId())}.`,\n    );\n    await this.sessionReplay.setSessionId(sessionId).promise;\n  }\n\n  async onOptOutChanged(optOut: boolean): Promise<void> {\n    this.config?.loggerProvider.debug(\n      `optOut is changed to ${String(optOut)}, calling ${\n        optOut ? 'sessionReplay.shutdown()' : 'sessionReplay.init()'\n      }.`,\n    );\n    // TODO: compare optOut with this.sessionReplay.getOptOut().\n    // Need to add getOptOut() to the interface AmplitudeSessionReplay first.\n    if (optOut) {\n      this.sessionReplay.shutdown();\n    } else {\n      this.config != null && (await this.sessionReplay.init(this.config.apiKey, this.srInitOptions).promise);\n    }\n  }\n\n  async execute(event: Event) {\n    try {\n      if (this.options.customSessionId) {\n        const sessionId = this.options.customSessionId(event);\n        if (sessionId) {\n          // On event, synchronize the session id to the custom session id from the event. This may\n          // suffer from offline/delayed events messing up the state stored\n          if (sessionId !== this.sessionReplay.getSessionId()) {\n            await this.sessionReplay.setSessionId(sessionId).promise;\n          }\n\n          const sessionRecordingProperties = this.sessionReplay.getSessionReplayProperties();\n          event.event_properties = {\n            ...event.event_properties,\n            ...sessionRecordingProperties,\n          };\n        }\n      } else {\n        // On event, synchronize the session id to the what's on the browserConfig (source of truth)\n        // Choosing not to read from event object here, concerned about offline/delayed events messing up the state stored\n        // in SR.\n        const sessionId: string | number | undefined = this.config?.sessionId;\n        if (sessionId && sessionId !== this.sessionReplay.getSessionId()) {\n          await this.sessionReplay.setSessionId(sessionId).promise;\n        }\n\n        // Treating config.sessionId as source of truth, if the event's session id doesn't match, the\n        // event is not of the current session (offline/late events). In that case, don't tag the events\n        if (sessionId && sessionId === event.session_id) {\n          let userProperties;\n          if (event.event_type === SpecialEventType.IDENTIFY) {\n            userProperties = parseUserProperties(event);\n          }\n          const globalScope = getGlobalScope();\n          await this.sessionReplay.evaluateTargetingAndCapture({\n            event,\n            userProperties,\n            page: globalScope?.location?.href != null ? { url: globalScope.location.href } : undefined,\n          });\n          const sessionRecordingProperties = this.sessionReplay.getSessionReplayProperties();\n          event.event_properties = {\n            ...event.event_properties,\n            ...sessionRecordingProperties,\n          };\n        }\n      }\n\n      if (event.event_type === SpecialEventType.IDENTIFY && event.event_properties) {\n        delete event.event_properties[DEFAULT_SESSION_REPLAY_PROPERTY];\n      }\n\n      return Promise.resolve(event);\n    } catch (error) {\n      /* istanbul ignore next */\n      this.config?.loggerProvider.error(`Session Replay: Failed to enrich event due to ${(error as Error).message}`);\n      return Promise.resolve(event);\n    }\n  }\n\n  async teardown(): Promise<void> {\n    try {\n      this.sessionReplay.shutdown();\n      // the following are initialized in setup() which will always be called first\n      // here we reset them to null to prevent memory leaks\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore\n      this.config = null;\n    } catch (error) {\n      /* istanbul ignore next */\n      this.config?.loggerProvider.error(`Session Replay: teardown failed due to ${(error as Error).message}`);\n    }\n  }\n\n  getSessionReplayProperties() {\n    return this.sessionReplay.getSessionReplayProperties();\n  }\n}\n\nexport const sessionReplayPlugin: (options?: SessionReplayOptions) => EnrichmentPlugin = (\n  options?: SessionReplayOptions,\n) => {\n  return new SessionReplayPlugin(options);\n};\n"
  },
  {
    "path": "packages/plugin-session-replay-browser/src/typings/session-replay.ts",
    "content": "import { Event } from '@amplitude/analytics-core';\nimport {\n  StoreType,\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  type SessionReplayOptions as StandaloneSessionReplayOptions, // used for documentation\n} from '@amplitude/session-replay-browser';\n\n/**\n * Configuration for cross-origin iframe support.\n * Extracted from the standalone SDK's SessionReplayOptions.\n */\nexport type CrossOriginIframesConfig = NonNullable<StandaloneSessionReplayOptions['crossOriginIframes']>;\n\nexport type MaskLevel =\n  | 'light' // only mask a subset of inputs that’s deemed sensitive - password, credit card, telephone #, email. These are information we never want to capture.\n  | 'medium' // mask all inputs\n  | 'conservative'; // mask all inputs and all texts\n\nexport interface SessionReplayPrivacyConfig {\n  blockSelector?: string | string[];\n  defaultMaskLevel?: MaskLevel;\n  maskSelector?: string[];\n  unmaskSelector?: string[];\n}\n\n/**\n * Performance configuration for interaction tracking, specifically for CSS selector generation.\n */\nexport interface InteractionPerformanceConfig {\n  /**\n   * Maximum time in milliseconds allowed for CSS selector generation.\n   * If selector generation takes longer than this, it will throw a timeout error.\n   * Default: undefined (no timeout limit)\n   */\n  timeoutMs?: number;\n  /**\n   * Maximum number of attempts to optimize/simplify the CSS selector path.\n   * Higher values may produce shorter selectors but take longer to compute.\n   * Default: 10000\n   */\n  maxNumberOfTries?: number;\n  /**\n   * Maximum number of CSS selector combinations to test for uniqueness.\n   * If more combinations would be generated, falls back to a simpler strategy.\n   * Default: 1000\n   */\n  threshold?: number;\n}\n\nexport interface SessionReplayPerformanceConfig {\n  enabled: boolean;\n  timeout?: number;\n  /**\n   * Performance configuration for interaction tracking (clicks, scrolls).\n   */\n  interaction?: InteractionPerformanceConfig;\n}\n\n/**\n * UGC filter rule.\n */\nexport type UGCFilterRule = {\n  /**\n   * The selector of the UGC element.\n   */\n  selector: string;\n  /**\n   * The replacement text for the UGC element.\n   */\n  replacement: string;\n};\n\nexport interface SessionReplayInteractionConfig {\n  trackEveryNms?: number;\n  enabled: boolean; // defaults to false\n  batch: boolean; // defaults to false\n  /**\n   * UGC filter rules.\n   */\n  ugcFilterRules?: UGCFilterRule[];\n}\n\nexport interface SessionReplayOptions {\n  /**\n   * @see {@link StandaloneSessionReplayOptions.sampleRate}\n   */\n  sampleRate?: number;\n  /**\n   * @see {@link StandaloneSessionReplayOptions.privacyConfig}\n   */\n  privacyConfig?: SessionReplayPrivacyConfig;\n  /**\n   * @see {@link StandaloneSessionReplayOptions.debugMode}\n   */\n  debugMode?: boolean;\n  /**\n   * If this is enabled we will force the browser SDK to also send start and end session events.\n   */\n  forceSessionTracking?: boolean;\n  /**\n   * @see {@link StandaloneSessionReplayOptions.configServerUrl}\n   */\n  configServerUrl?: string;\n  /**\n   * @see {@link StandaloneSessionReplayOptions.trackServerUrl}\n   */\n  trackServerUrl?: string;\n  /**\n   * @see {@link StandaloneSessionReplayOptions.shouldInlineStylesheet}\n   */\n  shouldInlineStylesheet?: boolean;\n  /**\n   * @see {@link StandaloneSessionReplayOptions.performanceConfig}\n   */\n  performanceConfig?: SessionReplayPerformanceConfig;\n  /**\n   * @see {@link StandaloneSessionReplayOptions.storeType}\n   */\n  storeType?: StoreType;\n  /**\n   * If true, the SDK will compress replay events using a web worker.\n   * This offloads compression to a separate thread, improving performance on the main thread.\n   *\n   * @defaultValue false\n   */\n  useWebWorker?: boolean;\n  /**\n   * Override the device ID for session replay.\n   */\n  deviceId?: string;\n  /**\n   * Dynamically overrides the session ID for replay. Ensure stability to avoid frequent restarts.\n   * @param event Browser SDK event\n   * @returns The session ID for the session replay.\n   */\n  customSessionId?: (event: Event) => string | undefined;\n  /**\n   * @deprecated Use `useWebWorker` instead. This will be removed in a future version.\n   * @see {@link StandaloneSessionReplayOptions.useWebWorker}\n   */\n  experimental?: {\n    useWebWorker: boolean;\n  };\n  /**\n   * If true, applies a background color to blocked elements for visual masking. Defaults to false.\n   */\n  applyBackgroundColorToBlockedElements?: boolean;\n\n  interactionConfig?: SessionReplayInteractionConfig;\n\n  /**\n   * Enables URL change polling as a fallback for SPA route tracking.\n   * When enabled, the SDK will periodically check for URL changes every second\n   * in addition to patching the History API. This is useful for edge cases where\n   * route changes might bypass the standard History API methods.\n   *\n   * @defaultValue false\n   */\n  enableUrlChangePolling?: boolean;\n  /**\n   * Specifies the interval in milliseconds for URL change polling when enableUrlChangePolling is true.\n   * The SDK will check for URL changes at this interval as a fallback for SPA route tracking.\n   *\n   * @defaultValue 1000\n   */\n  urlChangePollingInterval?: number;\n  /**\n   * Whether to capture document title in URL change events.\n   * When disabled, the title field will be empty in URL change events.\n   *\n   * @defaultValue false\n   */\n  captureDocumentTitle?: boolean;\n  /**\n   * @see {@link StandaloneSessionReplayOptions.captureAdoptedStyleSheets}\n   */\n  captureAdoptedStyleSheets?: boolean;\n  /**\n   * @see {@link StandaloneSessionReplayOptions.crossOriginIframes}\n   */\n  crossOriginIframes?: CrossOriginIframesConfig;\n}\n"
  },
  {
    "path": "packages/plugin-session-replay-browser/src/version.ts",
    "content": "// Autogenerated by `pnpm version-file`. DO NOT EDIT\nexport const VERSION = '1.30.4';\n"
  },
  {
    "path": "packages/plugin-session-replay-browser/test/integration/browser-sdk-integration.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\nimport * as amplitude from '@amplitude/analytics-browser';\nimport { sessionReplayPlugin } from '../../src/session-replay';\nimport { Event } from '@amplitude/analytics-core';\nimport { server } from './mockAPIHandlers';\nimport { matchRequestUrl } from 'msw';\n\nconst apiKey = 'static_key';\n\nfunction waitForRequest(method: string, url: string, bodyMatchingFn: (body: any) => boolean = () => true) {\n  return new Promise<Request>((resolve) => {\n    server.events.on('request:start', ({ request }) => {\n      const matchesMethod = request.method.toLowerCase() === method.toLowerCase();\n      const matchesUrl = matchRequestUrl(new URL(request.url), url).matches;\n      request\n        .clone()\n        .json()\n        .then((body) => {\n          const matchesBody = bodyMatchingFn(body);\n\n          if (matchesMethod && matchesUrl && matchesBody) {\n            resolve(request);\n          }\n        })\n        .catch(() => {\n          // do nothing\n        });\n    });\n  });\n}\n\nfunction eventRequestBodyMatchingFn(eventType: string, body: any) {\n  return (body.events as Event[]).some((event) => event.event_type === eventType);\n}\n\nconst setupPluginAndInit = async (args?: { browserSDKOptions?: amplitude.Types.BrowserOptions }) => {\n  const sr = sessionReplayPlugin({\n    sampleRate: 1,\n    debugMode: true,\n  });\n  await amplitude.add(sr).promise;\n  await amplitude.init(apiKey, undefined, {\n    flushMaxRetries: 1,\n    logLevel: 0, // Change this to 4 to debug the lifecycle\n    ...args?.browserSDKOptions,\n  }).promise;\n};\n\ndescribe('SessionReplayPlugin Integration with Browser SDK', () => {\n  beforeAll(() => server.listen());\n  beforeEach(() => {\n    server.resetHandlers();\n  });\n  afterEach(() => {\n    jest.resetAllMocks();\n  });\n  afterAll(() => {\n    server.close();\n  });\n  /**\n   * NOTE: These tests must be run together in succession to pass successfully,\n   * due to not being able to accurately reset the BrowserSDK to a pre-init state.\n   * Using .only on these tests will result in individual test failures\n   */\n  describe('tagging events', () => {\n    const pendingSessionStartRequest = waitForRequest(\n      'POST',\n      'https://api2.amplitude.com/2/httpapi',\n      eventRequestBodyMatchingFn.bind(undefined, 'session_start'),\n    );\n    beforeAll(async () => {\n      await setupPluginAndInit({\n        browserSDKOptions: {\n          defaultTracking: {\n            sessions: true,\n            pageViews: false,\n          },\n        },\n      });\n    });\n    test('should tag initial start session event with session replay id', async () => {\n      const request = await pendingSessionStartRequest;\n      const startSessionEventBody = await request.json();\n      const startSessionEvent = (startSessionEventBody.events as Event[]).find(\n        (event) => event.event_type === 'session_start',\n      );\n      const deviceId = startSessionEvent?.device_id as string;\n      const sessionId = startSessionEvent?.session_id as number;\n      expect(startSessionEvent).toEqual(\n        expect.objectContaining({\n          event_properties: expect.objectContaining({\n            '[Amplitude] Session Replay Debug': JSON.stringify({ appHash: '-109988594' }),\n            '[Amplitude] Session Replay ID': `${deviceId}/${sessionId}`,\n          }),\n        }),\n      );\n    });\n    test('should tag updated start session event with session replay id', async () => {\n      const pendingUpdatedSessionStartRequest = waitForRequest(\n        'POST',\n        'https://api2.amplitude.com/2/httpapi',\n        eventRequestBodyMatchingFn.bind(undefined, 'session_start'),\n      );\n      const newSessionId = 456;\n      amplitude.setSessionId(newSessionId);\n      const request = await pendingUpdatedSessionStartRequest;\n\n      const startSessionEventBody = await request.json();\n      const startSessionEvent = (startSessionEventBody.events as Event[]).find(\n        (event) => event.event_type === 'session_start',\n      );\n      const deviceId = startSessionEvent?.device_id as string;\n      expect(startSessionEvent).toEqual(\n        expect.objectContaining({\n          event_properties: expect.objectContaining({\n            '[Amplitude] Session Replay Debug': JSON.stringify({ appHash: '-109988594' }),\n            '[Amplitude] Session Replay ID': `${deviceId}/${newSessionId}`,\n          }),\n        }),\n      );\n    });\n    test('should tag an event with session replay id', async () => {\n      const eventType = 'My Event';\n      const pendingPageViewRequest = waitForRequest(\n        'POST',\n        'https://api2.amplitude.com/2/httpapi',\n        eventRequestBodyMatchingFn.bind(undefined, eventType),\n      );\n      amplitude.track(eventType);\n\n      const request = await pendingPageViewRequest;\n      const pageViewEventBody = await request.json();\n      const pageViewEvent = (pageViewEventBody.events as Event[]).find((event) => event.event_type === eventType);\n      const deviceId = pageViewEvent?.device_id as string;\n      const sessionId = pageViewEvent?.session_id as number;\n      expect(pageViewEvent).toEqual(\n        expect.objectContaining({\n          event_properties: expect.objectContaining({\n            '[Amplitude] Session Replay Debug': JSON.stringify({ appHash: '-109988594' }),\n            '[Amplitude] Session Replay ID': `${deviceId}/${sessionId}`,\n          }),\n        }),\n      );\n    });\n  });\n\n  // describe.skip('without existing session', () => {\n  //   test('should record events', () => {});\n  // });\n  // describe.skip('with existing session', () => {\n  //   test('should record events', () => {});\n  // });\n});\n"
  },
  {
    "path": "packages/plugin-session-replay-browser/test/integration/mockAPIHandlers.ts",
    "content": "import { http, HttpResponse } from 'msw';\n\nimport { setupServer } from 'msw/node';\n\nexport const handlers = [\n  http.post('https://api2.amplitude.com/2/httpapi', () => {\n    return HttpResponse.json({\n      code: 200,\n      events_ingested: 4,\n      payload_size_bytes: 2504,\n      server_upload_time: 1714522639863,\n    });\n  }),\n  http.get('https://sr-client-cfg.amplitude.com/config/:apiKey', () => {\n    return HttpResponse.json({\n      configs: {\n        sessionReplay: {\n          sr_sampling_config: {\n            sample_rate: 1,\n            capture_enabled: true,\n          },\n        },\n      },\n    });\n  }),\n  http.get('https://sr-client-cfg.amplitude.com/config/:apiKey', () => {\n    return HttpResponse.json({\n      configs: {\n        sessionReplay: {\n          sr_sampling_config: {\n            sample_rate: 1,\n            capture_enabled: true,\n          },\n        },\n      },\n    });\n  }),\n];\n\nexport const server = setupServer(...handlers);\n"
  },
  {
    "path": "packages/plugin-session-replay-browser/test/jest-setup.js",
    "content": "require('fake-indexeddb/auto');\nconst { IDBFactory } = require('fake-indexeddb');\nconst structuredClone = require('@ungap/structured-clone');\nconst nodeFetch = require('node-fetch');\n\nglobal.structuredClone = structuredClone.default;\nglobal.beforeEach(() => {\n  indexedDB = new IDBFactory();\n});\nglobal.Request = nodeFetch.Request;\nglobal.Response = nodeFetch.Response;\nglobal.fetch = nodeFetch;\n"
  },
  {
    "path": "packages/plugin-session-replay-browser/test/jsdom-extended.js",
    "content": "const JSDOMEnvironment = require('jest-environment-jsdom').default; // or import JSDOMEnvironment from 'jest-environment-jsdom' if you are using ESM modules\n\nclass JSDOMEnvironmentExtended extends JSDOMEnvironment {\n  constructor(...args) {\n    super(...args);\n\n    this.global.ReadableStream = ReadableStream;\n    this.global.WritableStream = WritableStream;\n    this.global.TextDecoder = TextDecoder;\n    this.global.TextEncoder = TextEncoder;\n    this.global.BroadcastChannel = BroadcastChannel;\n    this.global.TransformStream = TransformStream;\n\n    this.global.Blob = Blob;\n    this.global.structuredClone = structuredClone;\n  }\n}\n\nmodule.exports = JSDOMEnvironmentExtended;\n"
  },
  {
    "path": "packages/plugin-session-replay-browser/test/plugin-helpers.test.ts",
    "content": "import { parseUserProperties } from '../src/helpers';\nimport { Event, IdentifyOperation } from '@amplitude/analytics-types';\n\ndescribe('Plugin Helpers', () => {\n  describe('parseUserProperties', () => {\n    test('should return undefined when event has no user_properties', () => {\n      const event: Event = {\n        event_type: 'test_event',\n      };\n\n      const result = parseUserProperties(event);\n      expect(result).toBeUndefined();\n    });\n\n    test('should parse SET operation correctly', () => {\n      const event: Event = {\n        event_type: 'test_event',\n        user_properties: {\n          [IdentifyOperation.SET]: {\n            name: 'John',\n            age: 30,\n          },\n        },\n      };\n\n      const result = parseUserProperties(event);\n      expect(result).toEqual({\n        name: 'John',\n        age: 30,\n      });\n    });\n\n    test('should parse SET_ONCE operation correctly', () => {\n      const event: Event = {\n        event_type: 'test_event',\n        user_properties: {\n          [IdentifyOperation.SET_ONCE]: {\n            initial_signup: '2023-01-01',\n          },\n        },\n      };\n\n      const result = parseUserProperties(event);\n      expect(result).toEqual({\n        initial_signup: '2023-01-01',\n      });\n    });\n\n    test('should parse ADD operation correctly', () => {\n      const event: Event = {\n        event_type: 'test_event',\n        user_properties: {\n          [IdentifyOperation.ADD]: {\n            score: 100,\n          },\n        },\n      };\n\n      const result = parseUserProperties(event);\n      expect(result).toEqual({\n        score: 100,\n      });\n    });\n\n    test('should parse APPEND operation correctly', () => {\n      const event: Event = {\n        event_type: 'test_event',\n        user_properties: {\n          [IdentifyOperation.APPEND]: {\n            tags: 'new_tag',\n          },\n        },\n      };\n\n      const result = parseUserProperties(event);\n      expect(result).toEqual({\n        tags: 'new_tag',\n      });\n    });\n\n    test('should parse PREPEND operation correctly', () => {\n      const event: Event = {\n        event_type: 'test_event',\n        user_properties: {\n          [IdentifyOperation.PREPEND]: {\n            history: 'first_item',\n          },\n        },\n      };\n\n      const result = parseUserProperties(event);\n      expect(result).toEqual({\n        history: 'first_item',\n      });\n    });\n\n    test('should ignore PREINSERT operation (not in PROPERTY_ADD_OPERATIONS)', () => {\n      const event: Event = {\n        event_type: 'test_event',\n        user_properties: {\n          [IdentifyOperation.PREINSERT]: {\n            list: 'item',\n          },\n          [IdentifyOperation.SET]: {\n            name: 'John',\n          },\n        },\n      };\n\n      const result = parseUserProperties(event);\n      expect(result).toEqual({\n        name: 'John',\n      });\n    });\n\n    test('should parse POSTINSERT operation correctly', () => {\n      const event: Event = {\n        event_type: 'test_event',\n        user_properties: {\n          [IdentifyOperation.POSTINSERT]: {\n            queue: 'new_item',\n          },\n        },\n      };\n\n      const result = parseUserProperties(event);\n      expect(result).toEqual({\n        queue: 'new_item',\n      });\n    });\n\n    test('should parse multiple operations correctly', () => {\n      const event: Event = {\n        event_type: 'test_event',\n        user_properties: {\n          [IdentifyOperation.SET]: {\n            name: 'John',\n            age: 30,\n          },\n          [IdentifyOperation.ADD]: {\n            score: 100,\n          },\n          [IdentifyOperation.APPEND]: {\n            tags: 'premium',\n          },\n        },\n      };\n\n      const result = parseUserProperties(event);\n      expect(result).toEqual({\n        name: 'John',\n        age: 30,\n        score: 100,\n        tags: 'premium',\n      });\n    });\n\n    test('should ignore non-identify operations', () => {\n      const event: Event = {\n        event_type: 'test_event',\n        user_properties: {\n          [IdentifyOperation.SET]: {\n            name: 'John',\n          },\n          [IdentifyOperation.UNSET]: ['old_property'],\n          [IdentifyOperation.CLEAR_ALL]: true,\n          custom_property: 'should_be_ignored',\n        },\n      };\n\n      const result = parseUserProperties(event);\n      expect(result).toEqual({\n        name: 'John',\n      });\n    });\n\n    test('should handle empty operations object', () => {\n      const event: Event = {\n        event_type: 'test_event',\n        user_properties: {\n          [IdentifyOperation.SET]: {},\n        },\n      };\n\n      const result = parseUserProperties(event);\n      expect(result).toEqual({});\n    });\n  });\n});\n"
  },
  {
    "path": "packages/plugin-session-replay-browser/test/session-replay.test.ts",
    "content": "import * as AnalyticsCore from '@amplitude/analytics-core';\nimport {\n  BrowserClient,\n  BrowserConfig,\n  LogLevel,\n  ILogger,\n  Plugin,\n  Event,\n  SpecialEventType,\n} from '@amplitude/analytics-core';\nimport * as sessionReplayBrowser from '@amplitude/session-replay-browser';\nimport { SessionReplayPlugin, sessionReplayPlugin } from '../src/session-replay';\nimport { VERSION } from '../src/version';\nimport { randomUUID } from 'crypto';\n\njest.mock('@amplitude/session-replay-browser');\ntype MockedSessionReplayBrowser = jest.Mocked<typeof import('@amplitude/session-replay-browser')>;\n\ntype MockedLogger = jest.Mocked<ILogger>;\ntype MockedBrowserClient = jest.Mocked<BrowserClient>;\n\ndescribe('SessionReplayPlugin', () => {\n  const { init, setSessionId, getSessionReplayProperties, shutdown, getSessionId, evaluateTargetingAndCapture } =\n    sessionReplayBrowser as MockedSessionReplayBrowser;\n  const mockLoggerProviderDebug = jest.fn();\n  const mockLoggerProvider: MockedLogger = {\n    error: jest.fn(),\n    log: jest.fn(),\n    disable: jest.fn(),\n    enable: jest.fn(),\n    warn: jest.fn(),\n    debug: mockLoggerProviderDebug,\n  };\n  const mockConfig: BrowserConfig = {\n    apiKey: 'static_key',\n    flushIntervalMillis: 0,\n    flushMaxRetries: 1,\n    flushQueueSize: 0,\n    logLevel: LogLevel.None,\n    loggerProvider: mockLoggerProvider,\n    optOut: false,\n    deviceId: '1a2b3c',\n    serverUrl: 'url',\n    serverZone: 'US',\n    useBatch: false,\n    sessionId: 123,\n    cookieExpiration: 365,\n    cookieSameSite: 'Lax',\n    cookieSecure: false,\n    cookieUpgrade: true,\n    disableCookies: false,\n    domain: '.amplitude.com',\n    sessionTimeout: 30 * 60 * 1000,\n    trackingOptions: {\n      ipAddress: true,\n      language: true,\n      platform: true,\n    },\n  } as unknown as BrowserConfig;\n\n  const plugins: Plugin[] = [];\n  const mockAmplitude: MockedBrowserClient = {\n    add: jest.fn(),\n    remove: jest.fn(),\n  } as unknown as MockedBrowserClient;\n\n  beforeEach(() => {\n    init.mockReturnValue({\n      promise: Promise.resolve(),\n    });\n    setSessionId.mockReturnValue({\n      promise: Promise.resolve(),\n    });\n    getSessionReplayProperties.mockImplementation(() => {\n      return { '[Amplitude] Session Replay ID': 'foo/bar' };\n    });\n    plugins.splice(0, plugins.length);\n    mockAmplitude.add.mockImplementation((plugin) => {\n      plugins.push(plugin);\n      return {\n        promise: Promise.resolve(),\n      };\n    });\n    mockAmplitude.remove.mockImplementation((pluginName) => {\n      const pluginIndex = plugins.findIndex((plugin) => plugin.name === pluginName);\n      plugins.splice(pluginIndex, 1);\n      return {\n        promise: Promise.resolve(),\n      };\n    });\n    jest.useFakeTimers();\n  });\n\n  afterEach(() => {\n    jest.resetAllMocks();\n    jest.useRealTimers();\n  });\n\n  describe('setup', () => {\n    test('should setup plugin', async () => {\n      const customDeviceId = randomUUID();\n      const sessionReplay = new SessionReplayPlugin({\n        deviceId: customDeviceId,\n      });\n      await sessionReplay.setup?.(mockConfig, mockAmplitude);\n      expect(sessionReplay.config?.serverUrl).toBe('url');\n      expect(sessionReplay.config?.flushMaxRetries).toBe(1);\n      expect(sessionReplay.config?.flushQueueSize).toBe(0);\n      expect(sessionReplay.config?.flushIntervalMillis).toBe(0);\n\n      expect(init).toHaveBeenCalledWith('static_key', expect.objectContaining({ deviceId: customDeviceId }));\n    });\n\n    test('should handle errors during init', async () => {\n      const sessionReplay = new SessionReplayPlugin();\n      init.mockReturnValue({\n        promise: Promise.reject(new Error('Mock init error')),\n      });\n\n      await sessionReplay.setup?.(mockConfig, mockAmplitude);\n\n      expect(mockLoggerProvider['error']).toHaveBeenCalledTimes(1);\n      expect(mockLoggerProvider['error'].mock.calls[0][0]).toBe(\n        'Session Replay: Failed to initialize due to Mock init error',\n      );\n    });\n\n    test('should handle setup successfully with valid config', async () => {\n      const sessionReplay = new SessionReplayPlugin();\n\n      await sessionReplay.setup?.(mockConfig, mockAmplitude);\n\n      expect(init).toHaveBeenCalled();\n      expect(sessionReplay.config).toBeDefined();\n    });\n\n    test('should pass storeType through to session replay (undefined when not set)', async () => {\n      const sessionReplay = new SessionReplayPlugin();\n\n      await sessionReplay.setup?.(mockConfig, mockAmplitude);\n\n      expect(init).toHaveBeenCalledWith('static_key', expect.objectContaining({ storeType: undefined }));\n    });\n\n    test('should use explicitly provided storeType', async () => {\n      const sessionReplay = new SessionReplayPlugin({ storeType: 'idb' });\n\n      await sessionReplay.setup?.(mockConfig, mockAmplitude);\n\n      expect(init).toHaveBeenCalledWith('static_key', expect.objectContaining({ storeType: 'idb' }));\n    });\n\n    describe('defaultTracking', () => {\n      test('should not change defaultTracking when forceSessionTracking is not defined', async () => {\n        const sessionReplay = new SessionReplayPlugin();\n        await sessionReplay.setup?.(\n          {\n            ...mockConfig,\n            defaultTracking: true,\n          },\n          mockAmplitude,\n        );\n        expect(sessionReplay.config?.defaultTracking).toBe(true);\n      });\n\n      test('should not change defaultTracking if its set to true', async () => {\n        const sessionReplay = new SessionReplayPlugin({ forceSessionTracking: true });\n        await sessionReplay.setup?.(\n          {\n            ...mockConfig,\n            defaultTracking: true,\n          },\n          mockAmplitude,\n        );\n        expect(sessionReplay.config?.defaultTracking).toBe(true);\n      });\n\n      test('should modify defaultTracking to enable sessions if its set to false', async () => {\n        const sessionReplay = new SessionReplayPlugin({ forceSessionTracking: true });\n        await sessionReplay.setup?.(\n          {\n            ...mockConfig,\n            defaultTracking: false,\n          },\n          mockAmplitude,\n        );\n        expect(sessionReplay.config?.defaultTracking).toEqual({\n          pageViews: false,\n          formInteractions: false,\n          fileDownloads: false,\n          sessions: true,\n        });\n      });\n\n      test('should modify defaultTracking to enable sessions if it is an object', async () => {\n        const sessionReplay = new SessionReplayPlugin({ forceSessionTracking: true });\n        await sessionReplay.setup?.(\n          {\n            ...mockConfig,\n            defaultTracking: {\n              pageViews: false,\n            },\n          },\n          mockAmplitude,\n        );\n        expect(sessionReplay.config?.defaultTracking).toEqual({\n          pageViews: false,\n          sessions: true,\n        });\n      });\n\n      test('should not modify defaultTracking to enable sessions if session tracking is disbled', async () => {\n        const sessionReplay = new SessionReplayPlugin({ forceSessionTracking: false });\n        await sessionReplay.setup?.(\n          {\n            ...mockConfig,\n            defaultTracking: false,\n          },\n          mockAmplitude,\n        );\n        expect(sessionReplay.config?.defaultTracking).toEqual(false);\n      });\n\n      test('should not modify defaultTracking object to enable sessions if session tracking is disbled', async () => {\n        const sessionReplay = new SessionReplayPlugin({ forceSessionTracking: false });\n        await sessionReplay.setup?.(\n          {\n            ...mockConfig,\n            defaultTracking: {\n              pageViews: false,\n            },\n          },\n          mockAmplitude,\n        );\n        expect(sessionReplay.config?.defaultTracking).toEqual({\n          pageViews: false,\n        });\n      });\n    });\n\n    test('should call initialize on session replay sdk', async () => {\n      const sessionReplay = new SessionReplayPlugin({\n        sampleRate: 0.4,\n        privacyConfig: {\n          blockSelector: ['#id'],\n        },\n      });\n      await sessionReplay.setup?.(mockConfig, mockAmplitude);\n\n      expect(init).toHaveBeenCalledTimes(1);\n      expect(init.mock.calls[0][0]).toEqual(mockConfig.apiKey);\n      expect(init.mock.calls[0][1]).toEqual(\n        expect.objectContaining({\n          deviceId: mockConfig.deviceId,\n          flushMaxRetries: mockConfig.flushMaxRetries,\n          logLevel: mockConfig.logLevel,\n          loggerProvider: mockConfig.loggerProvider,\n          optOut: mockConfig.optOut,\n          sampleRate: 0.4,\n          serverZone: mockConfig.serverZone,\n          sessionId: mockConfig.sessionId,\n          privacyConfig: expect.objectContaining({\n            blockSelector: ['#id'],\n          }) as object,\n          version: {\n            type: 'plugin',\n            version: VERSION,\n          },\n        }),\n      );\n    });\n\n    test('should call initialize on session replay sdk with custom server urls', async () => {\n      const configServerUrl = 'http://localhost:3000';\n      const trackServerUrl = 'http://localhost:3001';\n\n      const sessionReplay = new SessionReplayPlugin({\n        sampleRate: 0.4,\n        privacyConfig: {\n          blockSelector: ['#id'],\n        },\n        configServerUrl,\n        trackServerUrl,\n      });\n      await sessionReplay.setup?.(mockConfig, mockAmplitude);\n\n      expect(init).toHaveBeenCalledTimes(1);\n      expect(init.mock.calls[0][0]).toEqual(mockConfig.apiKey);\n      expect(init.mock.calls[0][1]).toEqual(\n        expect.objectContaining({\n          deviceId: mockConfig.deviceId,\n          flushMaxRetries: mockConfig.flushMaxRetries,\n          logLevel: mockConfig.logLevel,\n          loggerProvider: mockConfig.loggerProvider,\n          optOut: mockConfig.optOut,\n          sampleRate: 0.4,\n          serverZone: mockConfig.serverZone,\n          configServerUrl,\n          trackServerUrl,\n          sessionId: mockConfig.sessionId,\n          privacyConfig: expect.objectContaining({\n            blockSelector: ['#id'],\n          }) as object,\n          version: {\n            type: 'plugin',\n            version: VERSION,\n          },\n        }),\n      );\n    });\n\n    test('should use remote config serverUrl from browser config', async () => {\n      const remoteConfigServerUrl = 'http://remote-config-server.com';\n\n      const sessionReplay = new SessionReplayPlugin({\n        sampleRate: 0.4,\n        privacyConfig: {\n          blockSelector: ['#id'],\n        },\n      });\n      await sessionReplay.setup?.(\n        {\n          ...mockConfig,\n          remoteConfig: {\n            serverUrl: remoteConfigServerUrl,\n          },\n        },\n        mockAmplitude,\n      );\n\n      expect(init).toHaveBeenCalledTimes(1);\n      expect(init.mock.calls[0][0]).toEqual(mockConfig.apiKey);\n      expect(init.mock.calls[0][1]).toEqual(\n        expect.objectContaining({\n          deviceId: mockConfig.deviceId,\n          flushMaxRetries: mockConfig.flushMaxRetries,\n          logLevel: mockConfig.logLevel,\n          loggerProvider: mockConfig.loggerProvider,\n          optOut: mockConfig.optOut,\n          sampleRate: 0.4,\n          serverZone: mockConfig.serverZone,\n          configServerUrl: remoteConfigServerUrl,\n          sessionId: mockConfig.sessionId,\n          privacyConfig: expect.objectContaining({\n            blockSelector: ['#id'],\n          }) as object,\n          version: {\n            type: 'plugin',\n            version: VERSION,\n          },\n        }),\n      );\n    });\n\n    test('should not set useWebWorker when not provided (default)', async () => {\n      const sessionReplay = new SessionReplayPlugin({\n        sampleRate: 0.5,\n      });\n      await sessionReplay.setup?.(mockConfig, mockAmplitude);\n\n      expect(init).toHaveBeenCalledTimes(1);\n      expect(init.mock.calls[0][1]).toEqual(\n        expect.objectContaining({\n          useWebWorker: undefined,\n        }),\n      );\n    });\n\n    test('should support useWebWorker config', async () => {\n      const sessionReplay = new SessionReplayPlugin({\n        useWebWorker: true,\n      });\n      await sessionReplay.setup?.(mockConfig, mockAmplitude);\n\n      expect(init).toHaveBeenCalledTimes(1);\n      expect(init.mock.calls[0][1]).toEqual(\n        expect.objectContaining({\n          useWebWorker: true,\n        }),\n      );\n    });\n\n    test('should support legacy experimental.useWebWorker config for backwards compatibility', async () => {\n      const sessionReplay = new SessionReplayPlugin({\n        experimental: {\n          useWebWorker: true,\n        },\n      });\n      await sessionReplay.setup?.(mockConfig, mockAmplitude);\n\n      expect(init).toHaveBeenCalledTimes(1);\n      expect(init.mock.calls[0][1]).toEqual(\n        expect.objectContaining({\n          useWebWorker: true,\n        }),\n      );\n    });\n\n    test('should forward crossOriginIframes to session-replay SDK', async () => {\n      const crossOriginIframes = { enabled: true, coordinateChildren: false };\n      const sessionReplay = new SessionReplayPlugin({ crossOriginIframes });\n      await sessionReplay.setup?.(mockConfig, mockAmplitude);\n\n      expect(init).toHaveBeenCalledTimes(1);\n      expect(init.mock.calls[0][1]).toEqual(\n        expect.objectContaining({\n          crossOriginIframes,\n        }),\n      );\n    });\n  });\n\n  describe('onSessionIdChanged', () => {\n    test('should call setSessionId()', async () => {\n      const sessionReplay = sessionReplayPlugin();\n      getSessionId.mockReturnValueOnce(123);\n      await sessionReplay.setup?.({ ...mockConfig }, mockAmplitude);\n\n      await sessionReplay.onSessionIdChanged?.(456);\n\n      expect(setSessionId).toHaveBeenCalledTimes(1);\n      expect(setSessionId).toHaveBeenCalledWith(456);\n      expect(mockLoggerProviderDebug).toHaveBeenCalledWith(\n        'Analytics session id is changed to 456, SR session id is 123.',\n      );\n    });\n\n    test('should handle call before setup gracefully', async () => {\n      const sessionReplay = new SessionReplayPlugin();\n      await sessionReplay.onSessionIdChanged?.(456);\n\n      expect(setSessionId).toHaveBeenCalledTimes(1);\n      expect(mockLoggerProviderDebug).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('onOptOutChanged', () => {\n    test('should shutdown when optOut is changed to true', async () => {\n      const sessionReplay = sessionReplayPlugin();\n      await sessionReplay.setup?.({ ...mockConfig }, mockAmplitude);\n\n      await sessionReplay.onOptOutChanged?.(true);\n\n      expect(shutdown).toHaveBeenCalledTimes(1);\n      expect(mockLoggerProviderDebug).toHaveBeenCalledWith(\n        'optOut is changed to true, calling sessionReplay.shutdown().',\n      );\n    });\n\n    test('should re init when optOut is changed to false', async () => {\n      const customDeviceId = randomUUID();\n      const sessionReplay = new SessionReplayPlugin({\n        deviceId: customDeviceId,\n      });\n      await sessionReplay.setup?.(mockConfig, mockAmplitude);\n      await sessionReplay.onOptOutChanged?.(false);\n\n      expect(init).toHaveBeenCalledTimes(2);\n      expect(mockLoggerProviderDebug).toHaveBeenCalledWith('optOut is changed to false, calling sessionReplay.init().');\n      expect(init).toHaveBeenCalledWith('static_key', expect.objectContaining({ deviceId: customDeviceId }));\n      expect(init).toHaveBeenNthCalledWith(2, 'static_key', expect.objectContaining({ deviceId: customDeviceId }));\n    });\n\n    test('should not re init when optOut is false but config is null', async () => {\n      const sessionReplay = new SessionReplayPlugin();\n      await sessionReplay.onOptOutChanged?.(false);\n\n      expect(init).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('execute', () => {\n    test('should add event property for [Amplitude] Session Replay ID', async () => {\n      const sessionReplay = sessionReplayPlugin();\n      await sessionReplay.setup?.({ ...mockConfig }, mockAmplitude);\n      getSessionReplayProperties.mockReturnValueOnce({\n        '[Amplitude] Session Replay ID': '123',\n      });\n      const event = {\n        event_type: 'event_type',\n        event_properties: {\n          property_a: true,\n          property_b: 123,\n        },\n        session_id: 123,\n      };\n\n      const enrichedEvent = await sessionReplay.execute?.(event);\n      expect(enrichedEvent?.event_properties).toEqual({\n        property_a: true,\n        property_b: 123,\n        '[Amplitude] Session Replay ID': '123',\n      });\n    });\n\n    test('should not add event property for event with mismatching session id', async () => {\n      const sessionReplay = sessionReplayPlugin();\n      await sessionReplay.setup?.({ ...mockConfig }, mockAmplitude);\n      getSessionReplayProperties.mockReturnValueOnce({\n        '[Amplitude] Session Replay ID': '123',\n      });\n      const event = {\n        event_type: 'event_type',\n        event_properties: {\n          property_a: true,\n          property_b: 123,\n        },\n        session_id: 124,\n      };\n      const enrichedEvent = await sessionReplay.execute?.(event);\n\n      expect(enrichedEvent?.event_properties).toEqual({\n        property_a: true,\n        property_b: 123,\n      });\n    });\n\n    test('should update the session id on any event', async () => {\n      const sessionReplay = new SessionReplayPlugin();\n      await sessionReplay.setup?.({ ...mockConfig, sessionId: 123 }, mockAmplitude);\n\n      const newEvent = {\n        event_type: 'session_start',\n      };\n      if (sessionReplay.config) {\n        sessionReplay.config.sessionId = 456;\n      }\n      await sessionReplay.execute(newEvent);\n      expect(setSessionId).toHaveBeenCalledTimes(1);\n      expect(setSessionId).toHaveBeenCalledWith(456);\n    });\n\n    test('should not update if session id unchanged', async () => {\n      const sessionReplay = new SessionReplayPlugin();\n      await sessionReplay.setup?.({ ...mockConfig, sessionId: 123 }, mockAmplitude);\n      getSessionId.mockReturnValueOnce(123);\n\n      const event = {\n        event_type: 'page view',\n        session_id: 123,\n      };\n      await sessionReplay.execute?.(event);\n      expect(setSessionId).not.toHaveBeenCalled();\n    });\n\n    test('should call evaluateTargetingAndCapture for IDENTIFY events', async () => {\n      const sessionReplay = new SessionReplayPlugin();\n      await sessionReplay.setup?.({ ...mockConfig, sessionId: 123 }, mockAmplitude);\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call\n      evaluateTargetingAndCapture.mockResolvedValue(undefined);\n\n      const event = {\n        event_type: SpecialEventType.IDENTIFY,\n        user_properties: {\n          $set: { name: 'John', age: 30 },\n        },\n        session_id: 123,\n      };\n      await sessionReplay.execute?.(event);\n\n      expect(evaluateTargetingAndCapture).toHaveBeenCalledWith(\n        expect.objectContaining({\n          event,\n          userProperties: { name: 'John', age: 30 },\n        }),\n      );\n    });\n\n    test('should call evaluateTargetingAndCapture with page from getGlobalScope when location.href is set', async () => {\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        location: { href: 'https://app.example.com/analytics' },\n      } as any);\n      const sessionReplay = new SessionReplayPlugin();\n      await sessionReplay.setup?.({ ...mockConfig, sessionId: 123 }, mockAmplitude);\n      evaluateTargetingAndCapture.mockResolvedValue(undefined);\n\n      const event = {\n        event_type: SpecialEventType.IDENTIFY,\n        user_properties: { $set: { name: 'Jane' } },\n        session_id: 123,\n      };\n      await sessionReplay.execute?.(event);\n\n      expect(evaluateTargetingAndCapture).toHaveBeenCalledWith(\n        expect.objectContaining({\n          event,\n          userProperties: { name: 'Jane' },\n          page: { url: 'https://app.example.com/analytics' },\n        }),\n      );\n    });\n\n    test('should call evaluateTargetingAndCapture with page undefined when getGlobalScope has no location or href', async () => {\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue(undefined);\n      const sessionReplay = new SessionReplayPlugin();\n      await sessionReplay.setup?.({ ...mockConfig, sessionId: 123 }, mockAmplitude);\n      evaluateTargetingAndCapture.mockResolvedValue(undefined);\n\n      const event = {\n        event_type: SpecialEventType.IDENTIFY,\n        user_properties: { $set: { name: 'Bob' } },\n        session_id: 123,\n      };\n      await sessionReplay.execute?.(event);\n\n      expect(evaluateTargetingAndCapture).toHaveBeenCalledWith(\n        expect.objectContaining({\n          event,\n          userProperties: { name: 'Bob' },\n          page: undefined,\n        }),\n      );\n    });\n\n    test('should return original event in case of errors', async () => {\n      const sessionReplay = sessionReplayPlugin();\n      await sessionReplay.setup?.({ ...mockConfig }, mockAmplitude);\n      getSessionReplayProperties.mockImplementation(() => {\n        throw new Error('Mock error');\n      });\n      const event = {\n        event_type: 'event_type',\n        event_properties: {\n          property_a: true,\n          property_b: 123,\n        },\n        session_id: 123,\n      };\n\n      const enrichedEvent = await sessionReplay.execute?.(event);\n      expect(enrichedEvent).toEqual(event);\n      expect(mockLoggerProvider['error']).toHaveBeenCalledTimes(1);\n      expect(mockLoggerProvider['error'].mock.calls[0][0]).toBe(\n        'Session Replay: Failed to enrich event due to Mock error',\n      );\n    });\n\n    test('should update the session id on any event when using custom session id', async () => {\n      const sessionReplay = sessionReplayPlugin({\n        customSessionId: (event: Event) => {\n          const event_properties = event.event_properties as { [key: string]: any };\n          if (!event_properties) {\n            return;\n          }\n          return event_properties['custom_session_id'] as string | undefined;\n        },\n      });\n      await sessionReplay.setup?.({ ...mockConfig }, mockAmplitude);\n      getSessionId.mockReturnValueOnce('test_122');\n      const event = {\n        event_type: 'event_type',\n        event_properties: {\n          property_a: true,\n          property_b: 123,\n          custom_session_id: 'test_123',\n        },\n        session_id: 124,\n      };\n\n      await sessionReplay.execute?.(event);\n      expect(setSessionId).toHaveBeenCalledTimes(1);\n      expect(setSessionId).toHaveBeenCalledWith('test_123');\n    });\n\n    test('should not update the session id when using custom session id and it does not change', async () => {\n      const sessionReplay = sessionReplayPlugin({\n        customSessionId: (event: Event) => {\n          const event_properties = event.event_properties as { [key: string]: any };\n          if (!event_properties) {\n            return;\n          }\n          return event_properties['custom_session_id'] as string | undefined;\n        },\n      });\n      await sessionReplay.setup?.({ ...mockConfig }, mockAmplitude);\n      getSessionId.mockReturnValueOnce('test_123');\n      const event = {\n        event_type: 'event_type',\n        event_properties: {\n          property_a: true,\n          property_b: 123,\n          custom_session_id: 'test_123',\n        },\n        session_id: 124,\n      };\n\n      await sessionReplay.execute?.(event);\n      expect(setSessionId).not.toHaveBeenCalled();\n    });\n\n    test('should do nothing when the custom session id cannot be found', async () => {\n      const sessionReplay = sessionReplayPlugin({\n        customSessionId: (event: Event) => {\n          const event_properties = event.event_properties as { [key: string]: any };\n          if (!event_properties) {\n            return;\n          }\n          return event_properties['custom_session_id'] as string | undefined;\n        },\n      });\n      await sessionReplay.setup?.({ ...mockConfig }, mockAmplitude);\n      const event = {\n        event_type: 'event_type',\n        event_properties: {\n          property_a: true,\n          property_b: 123,\n        },\n        session_id: 124,\n      };\n\n      const enrichedEvent = await sessionReplay.execute?.(event);\n      expect(setSessionId).not.toHaveBeenCalled();\n      expect(enrichedEvent).toEqual(event);\n    });\n\n    test('should handle execute before setup gracefully', async () => {\n      const sessionReplay = new SessionReplayPlugin();\n      const event = {\n        event_type: 'event_type',\n        event_properties: {\n          property_a: true,\n        },\n        session_id: 123,\n      };\n\n      const enrichedEvent = await sessionReplay.execute?.(event);\n      expect(enrichedEvent).toEqual(event);\n      expect(setSessionId).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('teardown', () => {\n    test('should call session replay teardown', async () => {\n      const sessionReplay = sessionReplayPlugin();\n      await sessionReplay.setup?.(mockConfig, mockAmplitude);\n      await sessionReplay.teardown?.();\n      expect(shutdown).toHaveBeenCalled();\n    });\n\n    test('should set config to null after teardown', async () => {\n      const sessionReplay = new SessionReplayPlugin();\n      await sessionReplay.setup?.(mockConfig, mockAmplitude);\n      expect(sessionReplay.config).not.toBeNull();\n      await sessionReplay.teardown?.();\n      expect(sessionReplay.config).toBeNull();\n    });\n\n    test('should handle teardown errors gracefully', async () => {\n      const sessionReplay = sessionReplayPlugin();\n      await sessionReplay.setup?.(mockConfig, mockAmplitude);\n\n      shutdown.mockImplementation(() => {\n        throw new Error('Mock shutdown error');\n      });\n\n      expect(async () => {\n        await sessionReplay.teardown?.();\n      }).not.toThrow();\n\n      expect(mockLoggerProvider['error']).toHaveBeenCalledTimes(1);\n      expect(mockLoggerProvider['error'].mock.calls[0][0]).toBe(\n        'Session Replay: teardown failed due to Mock shutdown error',\n      );\n    });\n  });\n\n  describe('getSessionReplayProperties', () => {\n    test('should return session replay properties', async () => {\n      const sessionReplay = sessionReplayPlugin() as SessionReplayPlugin;\n      await sessionReplay.setup?.(mockConfig, mockAmplitude);\n      getSessionReplayProperties.mockReturnValueOnce({\n        '[Amplitude] Session Recorded': true,\n        '[Amplitude] Session Replay ID': '123/456',\n      });\n      const sessionReplayProperties = sessionReplay.getSessionReplayProperties();\n      expect(sessionReplayProperties).toEqual({\n        '[Amplitude] Session Recorded': true,\n        '[Amplitude] Session Replay ID': '123/456',\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/plugin-session-replay-browser/tsconfig.es5.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/cjs\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-session-replay-browser/tsconfig.esm.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"es6\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/esm\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-session-replay-browser/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src/**/*\", \"test/**/*\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"esModuleInterop\": true,\n    \"lib\": [\"dom\"],\n    \"noEmit\": true,\n    \"rootDir\": \".\",\n  }\n}\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/.gitattributes",
    "content": "*.pbxproj -text\n# specific for windows script files\n*.bat text eol=crlf"
  },
  {
    "path": "packages/plugin-session-replay-react-native/.gitignore",
    "content": "# OSX\n#\n.DS_Store\n\n# XDE\n.expo/\n\n# VSCode\n.vscode/\njsconfig.json\n\n# Xcode\n#\nbuild/\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\nxcuserdata\n*.xccheckout\n*.moved-aside\nDerivedData\n*.hmap\n*.ipa\n*.xcuserstate\nproject.xcworkspace\n\n# Android/IJ\n#\n.classpath\n.cxx\n.gradle\n.idea\n.project\n.settings\nlocal.properties\nandroid.iml\n\n# Cocoapods\n#\nexample/ios/Pods\n\n# Ruby\nexample/vendor/\n\n# node.js\n#\nnode_modules/\nnpm-debug.log\nyarn-debug.log\nyarn-error.log\n\n# BUCK\nbuck-out/\n\\.buckd/\nandroid/app/libs\nandroid/keystores/debug.keystore\n\n# Yarn\n.yarn/*\n!.yarn/patches\n!.yarn/plugins\n!.yarn/releases\n!.yarn/sdks\n!.yarn/versions\n\n# Expo\n.expo/\n\n# Turborepo\n.turbo/\n\n# generated by bob\nlib/\n\n# React Native Codegen\nios/generated\nandroid/generated\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/.nvmrc",
    "content": "v18\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/.watchmanconfig",
    "content": "{}"
  },
  {
    "path": "packages/plugin-session-replay-react-native/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.4.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-react-native@0.4.9...@amplitude/plugin-session-replay-react-native@0.4.10) (2026-04-14)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-react-native\n\n\n\n\n\n## [0.4.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-react-native@0.4.8...@amplitude/plugin-session-replay-react-native@0.4.9) (2026-04-01)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-react-native\n\n\n\n\n\n## [0.4.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-react-native@0.4.7...@amplitude/plugin-session-replay-react-native@0.4.8) (2026-03-26)\n\n\n### Bug Fixes\n\n* **react-native:** remove buildscript block to prevent AGP conflicts with host app ([#1631](https://github.com/amplitude/Amplitude-TypeScript/issues/1631)) ([2f2319e](https://github.com/amplitude/Amplitude-TypeScript/commit/2f2319eff97c4bb4e1d4ff29c1732f0244c1cab6))\n\n\n\n\n\n## [0.4.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-react-native@0.4.6...@amplitude/plugin-session-replay-react-native@0.4.7) (2026-02-26)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-react-native\n\n\n\n\n\n## [0.4.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-react-native@0.4.5...@amplitude/plugin-session-replay-react-native@0.4.6) (2026-01-14)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-react-native\n\n\n\n\n\n## [0.4.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-react-native@0.4.4...@amplitude/plugin-session-replay-react-native@0.4.5) (2025-12-05)\n\n\n### Bug Fixes\n\n* use the value of optOut  ([#1418](https://github.com/amplitude/Amplitude-TypeScript/issues/1418)) ([c6c41c6](https://github.com/amplitude/Amplitude-TypeScript/commit/c6c41c6d7dd13a692a9e2f173773f08a74a02deb))\n\n\n\n\n\n## [0.4.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-react-native@0.4.3...@amplitude/plugin-session-replay-react-native@0.4.4) (2025-11-21)\n\n\n### Bug Fixes\n\n* update analytics/kotlin sdk dependency to include Dexguard fix ([#1415](https://github.com/amplitude/Amplitude-TypeScript/issues/1415)) ([a19836a](https://github.com/amplitude/Amplitude-TypeScript/commit/a19836a7b54089b37a5219dda3adee03bee605e8))\n\n\n\n\n\n## [0.4.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-react-native@0.4.2...@amplitude/plugin-session-replay-react-native@0.4.3) (2025-08-08)\n\n\n### Bug Fixes\n\n* make session replay optional on android ([#1239](https://github.com/amplitude/Amplitude-TypeScript/issues/1239)) ([5c34bf6](https://github.com/amplitude/Amplitude-TypeScript/commit/5c34bf687ad0b2f29cfa5eb3a2338a80c17db065))\n\n\n\n\n\n## [0.4.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-react-native@0.4.1...@amplitude/plugin-session-replay-react-native@0.4.2) (2025-06-25)\n\n\n### Bug Fixes\n\n* [SR RN] LogCatLogger missing error ([#1169](https://github.com/amplitude/Amplitude-TypeScript/issues/1169)) ([48766b4](https://github.com/amplitude/Amplitude-TypeScript/commit/48766b4b1249a885b2f59fcb31e6e8ab8c15f124))\n\n\n\n\n\n## [0.4.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-react-native@0.4.0...@amplitude/plugin-session-replay-react-native@0.4.1) (2025-05-15)\n\n\n### Bug Fixes\n\n* **react-native-session-replay:** prevent crash on Android with old architecture  ([#1086](https://github.com/amplitude/Amplitude-TypeScript/issues/1086)) ([0a7c985](https://github.com/amplitude/Amplitude-TypeScript/commit/0a7c9854a5bb909018a9549fe496927f0a163008))\n\n\n\n\n\n# [0.4.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-react-native@0.3.3...@amplitude/plugin-session-replay-react-native@0.4.0) (2025-05-13)\n\n\n### Features\n\n* **session-replay:** add autoStart configuration option ([#1076](https://github.com/amplitude/Amplitude-TypeScript/issues/1076)) ([0865e8b](https://github.com/amplitude/Amplitude-TypeScript/commit/0865e8b760b19bc6e1d816747d220a04a6787049))\n\n\n\n\n\n## [0.3.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-react-native@0.3.2...@amplitude/plugin-session-replay-react-native@0.3.3) (2025-05-09)\n\n\n### Bug Fixes\n\n* use correct logger ([#1072](https://github.com/amplitude/Amplitude-TypeScript/issues/1072)) ([8004464](https://github.com/amplitude/Amplitude-TypeScript/commit/8004464cf8f3263a53966954ff9335f517c201db))\n\n\n\n\n\n## [0.3.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-react-native@0.3.1...@amplitude/plugin-session-replay-react-native@0.3.2) (2025-04-03)\n\n\n### Bug Fixes\n\n* **SessionReplay-RN:** inherit ServerZone from Amplitude-RN ([#1015](https://github.com/amplitude/Amplitude-TypeScript/issues/1015)) ([f7ca1b4](https://github.com/amplitude/Amplitude-TypeScript/commit/f7ca1b4e5c49f7f2d17b3ff383d37804ef4ca352))\n\n\n\n\n\n## [0.3.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-react-native@0.3.0...@amplitude/plugin-session-replay-react-native@0.3.1) (2025-04-02)\n\n**Note:** Version bump only for package @amplitude/plugin-session-replay-react-native\n\n\n\n\n\n# [0.3.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-react-native@0.2.9...@amplitude/plugin-session-replay-react-native@0.3.0) (2025-03-21)\n\n\n### Features\n\n* **session replay rn:** add log level config to session replay rn plugin ([#1002](https://github.com/amplitude/Amplitude-TypeScript/issues/1002)) ([46d2854](https://github.com/amplitude/Amplitude-TypeScript/commit/46d2854cb8126ca0d67d7345c060ce3060a1d322))\n\n\n\n\n\n## [0.2.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-react-native@0.2.8...@amplitude/plugin-session-replay-react-native@0.2.9) (2025-03-17)\n\n\n### Bug Fixes\n\n* add start and stop functions and fix lateinit crash on Android ([#995](https://github.com/amplitude/Amplitude-TypeScript/issues/995)) ([84c1084](https://github.com/amplitude/Amplitude-TypeScript/commit/84c1084fb38b2bedd5ccf344a7d0fa44a011bc29))\n\n\n\n\n\n## 0.2.8 (2025-02-28)\n\n\n### Reverts\n\n* Revert \"ci: remove noImplicitUseStrict as it's deprecated in ts 5.5 (#974)\" ([29df7ea](https://github.com/amplitude/Amplitude-TypeScript/commit/29df7ea187a414ddbd1894f89f996a67a3c5c36c)), closes [#974](https://github.com/amplitude/Amplitude-TypeScript/issues/974)\n* Revert \"chore(release): publish\" ([d392f62](https://github.com/amplitude/Amplitude-TypeScript/commit/d392f6290b8bb4dd955d6e6f20b00191679489c4))\n\n\n\n\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.2.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-react-native@0.2.6...@amplitude/plugin-session-replay-react-native@0.2.7) (2025-02-05)\n\n### Bug Fixes\n\n- update Session Replay RN webview docs\n  ([78e7392](https://github.com/amplitude/Amplitude-TypeScript/commit/78e73922a1045a334b0b1563e9804b12ba1baa35))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.2.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-react-native@0.2.5...@amplitude/plugin-session-replay-react-native@0.2.6) (2025-01-10)\n\n### Bug Fixes\n\n- update SR sdk versions and update test app\n  ([4664d6f](https://github.com/amplitude/Amplitude-TypeScript/commit/4664d6f7cdff61884519b42422eb8595770ad42b))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.2.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-react-native@0.2.4...@amplitude/plugin-session-replay-react-native@0.2.5) (2024-12-13)\n\n### Bug Fixes\n\n- update ios session replay version for react native\n  ([070a71c](https://github.com/amplitude/Amplitude-TypeScript/commit/070a71c7e93f8dd9a83999bb3f60f87c7460b1b1))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.2.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-react-native@0.2.3...@amplitude/plugin-session-replay-react-native@0.2.4) (2024-11-26)\n\n### Bug Fixes\n\n- updating android library version\n  ([b6fe40d](https://github.com/amplitude/Amplitude-TypeScript/commit/b6fe40d187fa1e8e9723bfedb2f67aa52f298bcb))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.2.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-react-native@0.2.2...@amplitude/plugin-session-replay-react-native@0.2.3) (2024-11-26)\n\n### Bug Fixes\n\n- updating underlying iOS and Android dependencies\n  ([33f03ca](https://github.com/amplitude/Amplitude-TypeScript/commit/33f03ca8e3f824cae767495e7c52ab5f7de02ac4))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.2.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-react-native@0.2.1...@amplitude/plugin-session-replay-react-native@0.2.2) (2024-11-16)\n\n### Bug Fixes\n\n- update android sdk version to fix r8 gson issue\n  ([54cdf6a](https://github.com/amplitude/Amplitude-TypeScript/commit/54cdf6a56caa94b6fe5493923febf131fea54872))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.2.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-session-replay-react-native@0.2.0...@amplitude/plugin-session-replay-react-native@0.2.1) (2024-10-31)\n\n### Bug Fixes\n\n- allow passing sample rate and remote config fetching\n  ([5f31002](https://github.com/amplitude/Amplitude-TypeScript/commit/5f310022e97d78dcd9500b7849ffc2cbd5616572))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# 0.2.0 (2024-10-30)\n\n### Features\n\n- session replay plugin for react native\n  ([23ab05e](https://github.com/amplitude/Amplitude-TypeScript/commit/23ab05e5ae8bdc76dddd272aface9783d410f299))\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2024 Amplitude, Inc.\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/README.md",
    "content": "# @amplitude/plugin-session-replay-react-native\n\nAmplitude Session Replay plugin for React Native\n\n## Installation\n\n```sh\nnpm install @amplitude/plugin-session-replay-react-native\n```\n\n## Usage\nAdd the session replay plugin to your Amplitude instance as follows\n\n```js\nimport { SessionReplayPlugin } from '@amplitude/plugin-session-replay-react-native';\n\n// ...\n\nconst config: SessionReplayConfig = {\n    enableRemoteConfig: true, // default true\n    sampleRate: 1, // default 0\n    logLevel: LogLevel.Warn, // default LogLevel.Warn\n};\nawait init('YOUR_API_KEY').promise;\nawait add(new SessionReplayPlugin(config)).promise;\n\n```\n\n\n## Masking views\nTo maks certain views, add the `AmpMaskView` tag with the mask property `amp-mask` around the section to be masked\n\n```js\nimport { AmpMaskView } from '@amplitude/plugin-session-replay-react-native';\n\n// ...\n\n<AmpMaskView mask=\"amp-mask\">\n    <Text\n    style={[\n        styles.sectionTitle,\n        {\n        color: isDarkMode ? Colors.white : Colors.black,\n        },\n    ]}\n    >\n    {title}\n    </Text>\n</AmpMaskView>\n```\n\n## Unmasking views\nTo unmask views, add the `AmpMaskView` tag with the mask property `amp-unmask` around the section to be unmasked\n\n```js\nimport { AmpMaskView } from '@amplitude/plugin-session-replay-react-native';\n\n// ...\n\n<AmpMaskView mask=\"amp-unmask\">\n    <Text\n    style={[\n        styles.sectionTitle,\n        {\n        color: isDarkMode ? Colors.white : Colors.black,\n        },\n    ]}\n    >\n    {title}\n    </Text>\n</AmpMaskView>\n```\n\n## Tracking Web Views (Beta)\nWeb views are blocked by default and will not be tracked. If you'd like webviews to be tracked, you can manually unmask them by doing the following\n\n```js\n<AmpMaskView mask=\"amp-unmask\" style={{ flex: 1 }}>\n    <WebView source={{ uri: 'https://reactnative.dev/' }} style={{ flex: 1 }} />\n</AmpMaskView>\n```"
  },
  {
    "path": "packages/plugin-session-replay-react-native/amplitude-plugin-session-replay-react-native.podspec",
    "content": "require \"json\"\n\npackage = JSON.parse(File.read(File.join(__dir__, \"package.json\")))\nfolly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'\n\nPod::Spec.new do |s|\n  s.name         = \"amplitude-plugin-session-replay-react-native\"\n  s.version      = package[\"version\"]\n  s.summary      = package[\"description\"]\n  s.homepage     = package[\"homepage\"]\n  s.license      = package[\"license\"]\n  s.authors      = package[\"author\"]\n\n  s.platforms    = { :ios => min_ios_version_supported }\n  s.source       = { :git => \"https://github.com/amplitude/Amplitude-TypeScript.git\", :tag => \"#{s.version}\" }\n\n  s.source_files = \"ios/**/*.{h,m,mm,swift}\"\n\n  s.dependency 'AmplitudeSessionReplay', '>=0.9.5'\n\n  # Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.\n  # See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.\n  if respond_to?(:install_modules_dependencies, true)\n    install_modules_dependencies(s)\n  else\n    s.dependency \"React-Core\"\n\n    # Don't install the dependencies when we run `pod install` in the old architecture.\n    if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then\n      s.compiler_flags = folly_compiler_flags + \" -DRCT_NEW_ARCH_ENABLED=1\"\n      s.pod_target_xcconfig    = {\n          \"HEADER_SEARCH_PATHS\" => \"\\\"$(PODS_ROOT)/boost\\\"\",\n          \"OTHER_CPLUSPLUSFLAGS\" => \"-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1\",\n          \"CLANG_CXX_LANGUAGE_STANDARD\" => \"c++17\"\n      }\n      s.dependency \"React-Codegen\"\n      s.dependency \"RCT-Folly\"\n      s.dependency \"RCTRequired\"\n      s.dependency \"RCTTypeSafety\"\n      s.dependency \"ReactCommon/turbomodule/core\"\n    end\n  end\nend\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/android/build.gradle",
    "content": "def reactNativeArchitectures() {\n  def value = rootProject.getProperties().get(\"reactNativeArchitectures\")\n  return value ? value.split(\",\") : [\"armeabi-v7a\", \"x86\", \"x86_64\", \"arm64-v8a\"]\n}\n\ndef isNewArchitectureEnabled() {\n  return rootProject.hasProperty(\"newArchEnabled\") && rootProject.getProperty(\"newArchEnabled\") == \"true\"\n}\n\napply plugin: \"com.android.library\"\napply plugin: \"kotlin-android\"\n\nif (isNewArchitectureEnabled()) {\n  apply plugin: \"com.facebook.react\"\n}\n\ndef getExtOrDefault(name) {\n  return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties[\"PluginSessionReplayReactNative_\" + name]\n}\n\ndef getExtOrIntegerDefault(name) {\n  return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties[\"PluginSessionReplayReactNative_\" + name]).toInteger()\n}\n\ndef supportsNamespace() {\n  def parsed = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')\n  def major = parsed[0].toInteger()\n  def minor = parsed[1].toInteger()\n\n  // Namespace support was added in 7.3.0\n  return (major == 7 && minor >= 3) || major >= 8\n}\n\nandroid {\n  if (supportsNamespace()) {\n    namespace \"com.amplitude.pluginsessionreplayreactnative\"\n\n    sourceSets {\n      main {\n        manifest.srcFile \"src/main/AndroidManifestNew.xml\"\n      }\n    }\n  }\n\n  compileSdkVersion getExtOrIntegerDefault(\"compileSdkVersion\")\n\n  defaultConfig {\n    minSdkVersion getExtOrIntegerDefault(\"minSdkVersion\")\n    targetSdkVersion getExtOrIntegerDefault(\"targetSdkVersion\")\n\n  }\n\n  buildTypes {\n    release {\n      minifyEnabled false\n    }\n  }\n\n  lintOptions {\n    disable \"GradleCompatible\"\n  }\n\n  compileOptions {\n    sourceCompatibility JavaVersion.VERSION_1_8\n    targetCompatibility JavaVersion.VERSION_1_8\n  }\n}\n\nrepositories {\n  mavenCentral()\n  google()\n}\n\ndef kotlin_version = getExtOrDefault(\"kotlinVersion\")\n\ndependencies {\n    implementation(\"com.amplitude:session-replay-android:[0.24.0,0.25.0)\")\n    implementation(\"com.amplitude:analytics-android:[1.25.0,1.26.0)\")\n\n  // For < 0.71, this will be from the local maven repo\n  // For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin\n  //noinspection GradleDynamicVersion\n  implementation \"com.facebook.react:react-native:+\"\n  implementation \"org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version\"\n}\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/android/gradle.properties",
    "content": "PluginSessionReplayReactNative_kotlinVersion=1.7.0\nPluginSessionReplayReactNative_minSdkVersion=21\nPluginSessionReplayReactNative_targetSdkVersion=31\nPluginSessionReplayReactNative_compileSdkVersion=31\nPluginSessionReplayReactNative_ndkversion=21.4.7075529\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/android/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n          package=\"com.amplitude.pluginsessionreplayreactnative\">\n</manifest>\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/android/src/main/AndroidManifestNew.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n</manifest>\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/android/src/main/java/com/amplitude/pluginsessionreplayreactnative/PluginSessionReplayReactNativeModule.kt",
    "content": "package com.amplitude.pluginsessionreplayreactnative\n\nimport com.amplitude.android.sessionreplay.SessionReplay\nimport com.amplitude.common.Logger\nimport com.amplitude.common.android.LogcatLogger\nimport com.amplitude.core.ServerZone\nimport com.facebook.react.bridge.ReactApplicationContext\nimport com.facebook.react.bridge.ReactContextBaseJavaModule\nimport com.facebook.react.bridge.ReactMethod\nimport com.facebook.react.bridge.Promise\nimport com.facebook.react.bridge.WritableMap\nimport com.facebook.react.bridge.WritableNativeMap\n\nclass PluginSessionReplayReactNativeModule(private val reactContext: ReactApplicationContext) :\n  ReactContextBaseJavaModule(reactContext) {\n  private lateinit var sessionReplay: SessionReplay\n\n  override fun getName(): String {\n    return \"PluginSessionReplayReactNative\"\n  }\n\n  @ReactMethod\n  fun setup(apiKey: String, deviceId: String?, sessionId: Double, serverZone: String?, sampleRate: Double, enableRemoteConfig: Boolean, logLevel: Int, autoStart: Boolean) {\n    LogcatLogger.logger.logMode = when (logLevel) {\n        0 -> Logger.LogMode.OFF\n        1 -> Logger.LogMode.ERROR\n        2 -> Logger.LogMode.WARN\n        3 -> Logger.LogMode.INFO\n        4 -> Logger.LogMode.DEBUG\n        else -> Logger.LogMode.WARN\n    }\n\n    LogcatLogger.logger.debug(\"\"\"\n        setup:\n        API Key: $apiKey\n        Device Id: $deviceId\n        Session Id: $sessionId\n        Server Zone: ${serverZone ?: \"NULL\"}\n        Sample Rate: $sampleRate\n        Enable Remote Config: $enableRemoteConfig\n        Log Level: $logLevel\n        Auto Start: $autoStart\n    \"\"\".trimIndent())\n\n    sessionReplay = SessionReplay(\n      apiKey,\n      reactContext.applicationContext,\n      deviceId ?: \"\",\n      sessionId.toLong(),\n      logger = LogcatLogger.logger,\n      sampleRate = sampleRate,\n      enableRemoteConfig = enableRemoteConfig,\n      serverZone = when (serverZone) {\n        \"EU\" -> ServerZone.EU\n        else -> ServerZone.US\n      },\n      autoStart = autoStart\n    )\n  }\n\n  @ReactMethod\n  fun setSessionId(sessionId: Double) {\n    sessionReplay.setSessionId(sessionId.toLong())\n  }\n\n  @ReactMethod\n  fun getSessionId(promise: Promise) {\n    promise.resolve(sessionReplay.getSessionId().toDouble())\n  }\n\n  @ReactMethod\n  fun getSessionReplayProperties(promise: Promise) {\n    val properties: Map<String, Any> = sessionReplay.getSessionReplayProperties()\n    val map: WritableMap = WritableNativeMap()\n    for ((key, value) in properties) {\n      if (value is String) {\n        map.putString(key, value)\n      } else if (value is Int) {\n        map.putInt(key, value)\n      } else if (value is Long) {\n        map.putDouble(key, value.toDouble())\n      } else if (value is Double) {\n        map.putDouble(key, value)\n      } else if (value is Boolean) {\n        map.putBoolean(key, value)\n      }\n    }\n    promise.resolve(map)\n  }\n  \n  @ReactMethod\n  fun start() {\n    sessionReplay.start()\n  }\n\n  @ReactMethod\n  fun stop() {\n    sessionReplay.stop()\n  }\n\n  @ReactMethod\n  fun flush() {\n    sessionReplay.flush()\n  }\n\n  @ReactMethod\n  fun teardown() {\n    sessionReplay.shutdown()\n  }\n\n  override fun invalidate() {\n    if (::sessionReplay.isInitialized) {\n      sessionReplay.shutdown()\n    }\n  }\n}\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/android/src/main/java/com/amplitude/pluginsessionreplayreactnative/PluginSessionReplayReactNativePackage.kt",
    "content": "package com.amplitude.pluginsessionreplayreactnative\n\nimport com.facebook.react.ReactPackage\nimport com.facebook.react.bridge.NativeModule\nimport com.facebook.react.bridge.ReactApplicationContext\nimport com.facebook.react.uimanager.ViewManager\n\n\nclass PluginSessionReplayReactNativePackage : ReactPackage {\n  override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {\n    return listOf(PluginSessionReplayReactNativeModule(reactContext))\n  }\n\n  override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {\n    return listOf(PluginSessionReplayViewManager())\n  }\n}\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/android/src/main/java/com/amplitude/pluginsessionreplayreactnative/PluginSessionReplayViewManager.kt",
    "content": "package com.amplitude.pluginsessionreplayreactnative\n\nimport android.view.ViewGroup\nimport com.amplitude.android.sessionreplay.SessionReplay\nimport com.facebook.react.uimanager.annotations.ReactProp\nimport com.facebook.react.views.view.ReactViewManager\n\nclass PluginSessionReplayViewManager : ReactViewManager() {\n\n    override fun getName(): String {\n        return \"RCTAmpMaskView\"\n    }\n\n    @ReactProp(name = \"mask\")\n    fun setMask(view: ViewGroup, ampMask: String) {\n        when (ampMask) {\n            \"amp-mask\" -> SessionReplay.mask(view)\n            \"amp-unmask\" -> SessionReplay.unmask(view)\n            \"amp-block\" -> SessionReplay.block(view)\n        }\n    }\n}\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/babel.config.js",
    "content": "module.exports = {\n  presets: ['module:metro-react-native-babel-preset'],\n};\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/.bundle/config",
    "content": "BUNDLE_PATH: \"vendor/bundle\"\nBUNDLE_FORCE_RUBY_PLATFORM: 1\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/.eslintrc.js",
    "content": "module.exports = {\n  root: true,\n  extends: '@react-native',\n};\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/.gitignore",
    "content": "# OSX\n#\n.DS_Store\n\n# Xcode\n#\nbuild/\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\nxcuserdata\n*.xccheckout\n*.moved-aside\nDerivedData\n*.hmap\n*.ipa\n*.xcuserstate\n**/.xcode.env.local\n\n# Android/IntelliJ\n#\nbuild/\n.idea\n.gradle\nlocal.properties\n*.iml\n*.hprof\n.cxx/\n*.keystore\n!debug.keystore\n\n# node.js\n#\nnode_modules/\nnpm-debug.log\nyarn-error.log\n\n# fastlane\n#\n# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the\n# screenshots whenever they are needed.\n# For more information about the recommended setup visit:\n# https://docs.fastlane.tools/best-practices/source-control/\n\n**/fastlane/report.xml\n**/fastlane/Preview.html\n**/fastlane/screenshots\n**/fastlane/test_output\n\n# Bundle artifact\n*.jsbundle\n\n# Ruby / CocoaPods\n**/Pods/\n/vendor/bundle/\n\n# Temporary files created by Metro to check the health of the file watcher\n.metro-health-check*\n\n# testing\n/coverage\n\n# Yarn\n.yarn/*\n!.yarn/patches\n!.yarn/plugins\n!.yarn/releases\n!.yarn/sdks\n!.yarn/versions\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/.prettierrc.js",
    "content": "module.exports = {\n  arrowParens: 'avoid',\n  bracketSameLine: true,\n  bracketSpacing: false,\n  singleQuote: true,\n  trailingComma: 'all',\n};\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/.watchmanconfig",
    "content": "{}\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/App.tsx",
    "content": "/**\n * Sample React Native App\n * https://github.com/facebook/react-native\n *\n * @format\n */\n\nimport React, { useEffect, useState } from 'react';\nimport type { PropsWithChildren } from 'react';\nimport {\n  Button,\n  Image,\n  ImageBackground,\n  SafeAreaView,\n  ScrollView,\n  StatusBar,\n  StyleSheet,\n  Switch,\n  Text,\n  TextInput,\n  TouchableWithoutFeedback,\n  useColorScheme,\n  View,\n} from 'react-native';\nimport { WebView } from 'react-native-webview';\n\nimport {\n  Colors,\n  DebugInstructions,\n  Header,\n  LearnMoreLinks,\n  ReloadInstructions,\n} from 'react-native/Libraries/NewAppScreen';\n\nimport {\n  add,\n  Identify,\n  identify,\n  init,\n  track,\n} from '@amplitude/analytics-react-native';\nimport { LogLevel } from '@amplitude/analytics-types';\nimport { NavigationContainer } from '@react-navigation/native';\n\nimport { SessionReplayPlugin, AmpMaskView, SessionReplayConfig } from '@amplitude/plugin-session-replay-react-native';\nimport {\n  createNativeStackNavigator,\n  type NativeStackScreenProps,\n} from '@react-navigation/native-stack';\n\ntype SectionProps = PropsWithChildren<{\n  title: string;\n}>;\n\nlet sessionReplayPlugin: SessionReplayPlugin | undefined = undefined;\n\nfunction Section({ children, title }: SectionProps): React.JSX.Element {\n  const isDarkMode = useColorScheme() === 'dark';\n  return (\n    <View style={styles.sectionContainer}>\n      <TouchableWithoutFeedback\n        onPress={() => {\n          console.log('tap');\n          track('tap');\n        }}\n      >\n        <AmpMaskView mask=\"amp-mask\">\n          <Text\n            style={[\n              styles.sectionTitle,\n              {\n                color: isDarkMode ? Colors.white : Colors.black,\n              },\n            ]}\n          >\n            {title}\n          </Text>\n        </AmpMaskView>\n      </TouchableWithoutFeedback>\n      <Text\n        style={[\n          styles.sectionDescription,\n          {\n            color: isDarkMode ? Colors.light : Colors.dark,\n          },\n        ]}\n      >\n        {children}\n      </Text>\n    </View>\n  );\n}\n\ntype HomeScreenNavigationProps = NativeStackScreenProps<\n  RootStackParamList,\n  'Home'\n>;\ntype ViewGalleryScreenNavigationProps = NativeStackScreenProps<\n  RootStackParamList,\n  'ViewGallery'\n>;\ntype WebViewScreenNavigationProps = NativeStackScreenProps<\n  RootStackParamList,\n  'WebView'\n>;\n\nfunction HomeScreen({ navigation }: HomeScreenNavigationProps) {\n  const isDarkMode = useColorScheme() === 'dark';\n\n  const backgroundStyle = {\n    backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,\n  };\n\n  return (\n    <SafeAreaView style={backgroundStyle}>\n      <StatusBar\n        barStyle={isDarkMode ? 'light-content' : 'dark-content'}\n        backgroundColor={backgroundStyle.backgroundColor}\n      />\n      <ScrollView\n        contentInsetAdjustmentBehavior=\"automatic\"\n        style={backgroundStyle}\n      >\n        <Header />\n        <View\n          style={{\n            backgroundColor: isDarkMode ? Colors.black : Colors.white,\n          }}\n        >\n          <Section title=\"View Gallery\">\n            <Button\n              title=\"Go to Details\"\n              onPress={() => navigation.navigate('ViewGallery')}\n            />\n          </Section>\n          <Section title=\"Go to web view\">\n            <Button\n              title=\"Go to Web View\"\n              onPress={() => navigation.navigate('WebView')}\n            />\n          </Section>\n          <Section title=\"Session Replay Controls\">\n            <Button\n              title=\"Start Recording\"\n              onPress={async () => {\n                if (sessionReplayPlugin) {\n                  await sessionReplayPlugin.start();\n                  track(\"session-replay-started\");\n                  console.log('Session replay recording started');\n                }\n              }}\n            />\n            <Button\n              title=\"Stop Recording\"\n              onPress={async () => {\n                if (sessionReplayPlugin) {\n                  await sessionReplayPlugin.stop();\n                  track(\"session-replay-stopped\");\n                  console.log('Session replay recording stopped');\n                }\n              }}\n            />\n          </Section>\n          <Section title=\"Step One\">\n            Edit <Text style={styles.highlight}>App.tsx</Text> to change this\n            screen and then come back to see your edits.\n          </Section>\n          <Section title=\"See Your Changes\">\n            <ReloadInstructions />\n          </Section>\n          <Section title=\"Debug\">\n            <DebugInstructions />\n          </Section>\n          <Section title=\"Learn More\">\n            Read the docs to discover what to do next:\n          </Section>\n          <LearnMoreLinks />\n        </View>\n      </ScrollView>\n    </SafeAreaView>\n  );\n}\n\nconst ViewGalleryScreen = ({\n  navigation,\n}: ViewGalleryScreenNavigationProps) => {\n  const isDarkMode = useColorScheme() === 'dark';\n\n  const backgroundStyle = {\n    backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,\n  };\n\n  return (\n    <ScrollView\n      contentInsetAdjustmentBehavior=\"automatic\"\n      style={backgroundStyle}\n    >\n      <View\n        style={{\n          backgroundColor: isDarkMode ? Colors.black : Colors.white,\n        }}\n      >\n        <Text>Text View</Text>\n        <Image\n          source={{\n            uri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADMAAAAzCAYAAAA6oTAqAAAAEXRFWHRTb2Z0d2FyZQBwbmdjcnVzaEB1SfMAAABQSURBVGje7dSxCQBACARB+2/ab8BEeQNhFi6WSYzYLYudDQYGBgYGBgYGBgYGBgYGBgZmcvDqYGBgmhivGQYGBgYGBgYGBgYGBgYGBgbmQw+P/eMrC5UTVAAAAABJRU5ErkJggg==',\n          }}\n          style={styles.image}\n        />\n        <Button\n          title=\"Button View (Go to Home)\"\n          onPress={() => navigation.navigate('Home')}\n        />\n        <ImageBackground\n          source={{\n            uri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADMAAAAzCAYAAAA6oTAqAAAAEXRFWHRTb2Z0d2FyZQBwbmdjcnVzaEB1SfMAAABQSURBVGje7dSxCQBACARB+2/ab8BEeQNhFi6WSYzYLYudDQYGBgYGBgYGBgYGBgYGBgZmcvDqYGBgmhivGQYGBgYGBgYGBgYGBgYGBgbmQw+P/eMrC5UTVAAAAABJRU5ErkJggg==',\n          }}\n          resizeMode=\"cover\"\n          style={styles.imageBackground}\n        >\n          <Text style={styles.imageBackgroundText}>ImageBackground</Text>\n        </ImageBackground>\n        <SwitchExample />\n        <TextInputExample />\n      </View>\n    </ScrollView>\n  );\n};\n\nconst WebViewScreen = () => {\n  return (\n    <AmpMaskView mask=\"amp-unmask\" style={{ flex: 1 }}>\n      <WebView source={{ uri: 'https://reactnative.dev/' }} style={{ flex: 1 }} />\n    </AmpMaskView>\n  );\n}\n\nconst SwitchExample = () => {\n  const [isEnabled, setIsEnabled] = useState(false);\n  const toggleSwitch = () => setIsEnabled((previousState) => !previousState);\n\n  return (\n    <Switch\n      trackColor={{ false: '#767577', true: '#81b0ff' }}\n      thumbColor={isEnabled ? '#f5dd4b' : '#f4f3f4'}\n      ios_backgroundColor=\"#3e3e3e\"\n      onValueChange={toggleSwitch}\n      value={isEnabled}\n    />\n  );\n};\n\nconst TextInputExample = () => {\n  const [text, onChangeText] = React.useState('Useless Text');\n  const [number, onChangeNumber] = React.useState('');\n\n  return (\n    <SafeAreaView>\n      <TextInput\n        style={styles.input}\n        onChangeText={onChangeText}\n        value={text}\n      />\n      <TextInput\n        style={styles.input}\n        onChangeText={onChangeNumber}\n        value={number}\n        placeholder=\"useless placeholder\"\n        keyboardType=\"numeric\"\n      />\n    </SafeAreaView>\n  );\n};\n\ntype RootStackParamList = {\n  Home: undefined;\n  ViewGallery: undefined;\n  WebView: undefined;\n};\n\nconst Stack = createNativeStackNavigator<RootStackParamList>();\n\nfunction App(): React.JSX.Element {\n  useEffect(() => {\n    const config: SessionReplayConfig = {\n      enableRemoteConfig: false,\n      sampleRate: 1,\n      logLevel: LogLevel.Debug\n    };\n    (async () => {\n      await init('YOUR-API-KEY', 'example_user_id', {\n        logLevel: LogLevel.Verbose,\n      }).promise;\n      sessionReplayPlugin = new SessionReplayPlugin(config);\n      await add(sessionReplayPlugin).promise;\n      track('test');\n      await identify(new Identify().set('react-native-test', 'yes')).promise;\n    })();\n  }, []);\n\n  return (\n    <NavigationContainer>\n      <Stack.Navigator initialRouteName=\"Home\">\n        <Stack.Screen\n          name=\"Home\"\n          component={HomeScreen}\n          options={{ title: 'Welcome' }}\n        />\n        <Stack.Screen\n          name=\"ViewGallery\"\n          options={{ title: 'View Gallery' }}\n          component={ViewGalleryScreen}\n        />\n        <Stack.Screen\n          name=\"WebView\"\n          options={{ title: 'Web View' }}\n          component={WebViewScreen}\n        />\n      </Stack.Navigator>\n    </NavigationContainer>\n  );\n}\n\nconst styles = StyleSheet.create({\n  sectionContainer: {\n    marginTop: 32,\n    paddingHorizontal: 24,\n  },\n  sectionTitle: {\n    fontSize: 24,\n    fontWeight: '600',\n  },\n  sectionDescription: {\n    marginTop: 8,\n    fontSize: 18,\n    fontWeight: '400',\n  },\n  highlight: {\n    fontWeight: '700',\n  },\n  image: {\n    flex: 1,\n    height: 200,\n    justifyContent: 'center',\n  },\n  imageBackground: {\n    flex: 1,\n    height: 200,\n    justifyContent: 'center',\n  },\n  imageBackgroundText: {\n    color: 'white',\n    fontSize: 20,\n    fontWeight: 'bold',\n    textAlign: 'center',\n  },\n  input: {\n    height: 40,\n    margin: 12,\n    borderWidth: 1,\n    padding: 10,\n  },\n  buttonContainer: {\n    flexDirection: 'row',\n    justifyContent: 'center',\n    alignItems: 'center',\n  },\n  buttonSpacer: {\n    width: 20,\n  },\n});\n\nexport default App;\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/Gemfile",
    "content": "source 'https://rubygems.org'\n\n# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version\nruby \">= 2.6.10\"\n\n# Exclude problematic versions of cocoapods and activesupport that causes build failures.\ngem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1'\ngem 'activesupport', '>= 6.1.7.5', '!= 7.1.0'\ngem 'xcodeproj', '< 1.26.0'\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/README.md",
    "content": "This is a new [**React Native**](https://reactnative.dev) project, bootstrapped using [`@react-native-community/cli`](https://github.com/react-native-community/cli).\n# Getting Started\n>**Note**: Make sure you have completed the [React Native - Environment Setup](https://reactnative.dev/docs/environment-setup) instructions till \"Creating a new application\" step, before proceeding.\n\n## Step 1: Start the Metro Server\nFirst, you will need to start **Metro**, the JavaScript _bundler_ that ships _with_ React Native.\nTo start Metro, run the following command from the _root_ of your React Native project:\n```bash\nUsing Yarn\nyarn start\n```\n\nNote: The test app points to the RN plugin folder directly instead of getting it from npm repository. This functionality does not work with npm, so please only use yarn\n\n## Step 2: Start your Application\nOnce the dev server is ready, you'll see the following options\n\n```\ninfo Dev server ready\n\ni - run on iOS\na - run on Android\nd - open Dev Menu\nr - reload app\n```\n\n^ Follow the above instructions to test your app in the platform of your choice\n\n## Step 3: Modifying your App\n\nNow that you have successfully run the app, let's modify it.\n\n1. Open `App.tsx` in your text editor of choice and edit some lines.\n2. On the metro terminal, hit r to reload the app\n\n## Modifying the SDK\n\n1. Make changes to the SDK in the parent folder\n2. Hit `r` on the metro terminal to restart the app\n\n## Congratulations! :tada:\n\nYou've successfully run and modified your React Native App. :partying_face:\n\n## Troubleshooting\n\nWhen you run into issues, just run `yarn nuke` and then run `yarn start`"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/__tests__/App.test.tsx",
    "content": "/**\n * @format\n */\n\nimport 'react-native';\nimport React from 'react';\nimport App from '../App';\n\n// Note: import explicitly to use the types shipped with jest.\nimport {it} from '@jest/globals';\n\n// Note: test renderer must be required after react-native.\nimport renderer from 'react-test-renderer';\n\nit('renders correctly', () => {\n  renderer.create(<App />);\n});\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/android/app/build.gradle",
    "content": "apply plugin: \"com.android.application\"\napply plugin: \"org.jetbrains.kotlin.android\"\napply plugin: \"com.facebook.react\"\n\n/**\n * This is the configuration block to customize your React Native Android app.\n * By default you don't need to apply any configuration, just uncomment the lines you need.\n */\nreact {\n    /* Folders */\n    //   The root of your project, i.e. where \"package.json\" lives. Default is '../..'\n    // root = file(\"../../\")\n    //   The folder where the react-native NPM package is. Default is ../../node_modules/react-native\n    // reactNativeDir = file(\"../../node_modules/react-native\")\n    //   The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen\n    // codegenDir = file(\"../../node_modules/@react-native/codegen\")\n    //   The cli.js file which is the React Native CLI entrypoint. Default is ../../node_modules/react-native/cli.js\n    // cliFile = file(\"../../node_modules/react-native/cli.js\")\n\n    /* Variants */\n    //   The list of variants to that are debuggable. For those we're going to\n    //   skip the bundling of the JS bundle and the assets. By default is just 'debug'.\n    //   If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants.\n    // debuggableVariants = [\"liteDebug\", \"prodDebug\"]\n\n    /* Bundling */\n    //   A list containing the node command and its flags. Default is just 'node'.\n    // nodeExecutableAndArgs = [\"node\"]\n    //\n    //   The command to run when bundling. By default is 'bundle'\n    // bundleCommand = \"ram-bundle\"\n    //\n    //   The path to the CLI configuration file. Default is empty.\n    // bundleConfig = file(../rn-cli.config.js)\n    //\n    //   The name of the generated asset file containing your JS bundle\n    // bundleAssetName = \"MyApplication.android.bundle\"\n    //\n    //   The entry file for bundle generation. Default is 'index.android.js' or 'index.js'\n    // entryFile = file(\"../js/MyApplication.android.js\")\n    //\n    //   A list of extra flags to pass to the 'bundle' commands.\n    //   See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle\n    // extraPackagerArgs = []\n\n    /* Hermes Commands */\n    //   The hermes compiler command to run. By default it is 'hermesc'\n    // hermesCommand = \"$rootDir/my-custom-hermesc/bin/hermesc\"\n    //\n    //   The list of flags to pass to the Hermes compiler. By default is \"-O\", \"-output-source-map\"\n    // hermesFlags = [\"-O\", \"-output-source-map\"]\n\n    /* Autolinking */\n    autolinkLibrariesWithApp()\n}\n\n/**\n * Set this to true to Run Proguard on Release builds to minify the Java bytecode.\n */\ndef enableProguardInReleaseBuilds = false\n\n/**\n * The preferred build flavor of JavaScriptCore (JSC)\n *\n * For example, to use the international variant, you can use:\n * `def jscFlavor = 'org.webkit:android-jsc-intl:+'`\n *\n * The international variant includes ICU i18n library and necessary data\n * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that\n * give correct results when using with locales other than en-US. Note that\n * this variant is about 6MiB larger per architecture than default.\n */\ndef jscFlavor = 'org.webkit:android-jsc:+'\n\nandroid {\n    ndkVersion rootProject.ext.ndkVersion\n    buildToolsVersion rootProject.ext.buildToolsVersion\n    compileSdk rootProject.ext.compileSdkVersion\n\n    namespace \"com.example\"\n    defaultConfig {\n        applicationId \"com.example\"\n        minSdkVersion rootProject.ext.minSdkVersion\n        targetSdkVersion rootProject.ext.targetSdkVersion\n        versionCode 1\n        versionName \"1.0\"\n    }\n    signingConfigs {\n        debug {\n            storeFile file('debug.keystore')\n            storePassword 'android'\n            keyAlias 'androiddebugkey'\n            keyPassword 'android'\n        }\n    }\n    buildTypes {\n        debug {\n            signingConfig signingConfigs.debug\n        }\n        release {\n            // Caution! In production, you need to generate your own keystore file.\n            // see https://reactnative.dev/docs/signed-apk-android.\n            signingConfig signingConfigs.debug\n            minifyEnabled enableProguardInReleaseBuilds\n            proguardFiles getDefaultProguardFile(\"proguard-android.txt\"), \"proguard-rules.pro\"\n        }\n    }\n}\n\ndependencies {\n    // The version of react-native is set by the React Native Gradle Plugin\n    implementation(\"com.facebook.react:react-android\")\n\n    if (hermesEnabled.toBoolean()) {\n        implementation(\"com.facebook.react:hermes-android\")\n    } else {\n        implementation jscFlavor\n    }\n}\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/android/app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/android/app/src/debug/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <application\n        android:usesCleartextTraffic=\"true\"\n        tools:targetApi=\"28\"\n        tools:ignore=\"GoogleAppIndexingWarning\"/>\n</manifest>\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/android/app/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n\n    <application\n      android:name=\".MainApplication\"\n      android:label=\"@string/app_name\"\n      android:icon=\"@mipmap/ic_launcher\"\n      android:roundIcon=\"@mipmap/ic_launcher_round\"\n      android:allowBackup=\"false\"\n      android:theme=\"@style/AppTheme\"\n      android:supportsRtl=\"true\">\n      <activity\n        android:name=\".MainActivity\"\n        android:label=\"@string/app_name\"\n        android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode\"\n        android:launchMode=\"singleTask\"\n        android:windowSoftInputMode=\"adjustResize\"\n        android:exported=\"true\">\n        <intent-filter>\n            <action android:name=\"android.intent.action.MAIN\" />\n            <category android:name=\"android.intent.category.LAUNCHER\" />\n        </intent-filter>\n      </activity>\n    </application>\n</manifest>\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/android/app/src/main/java/com/example/MainActivity.kt",
    "content": "package com.example\n\nimport com.facebook.react.ReactActivity\nimport com.facebook.react.ReactActivityDelegate\nimport com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled\nimport com.facebook.react.defaults.DefaultReactActivityDelegate\n\nclass MainActivity : ReactActivity() {\n\n  /**\n   * Returns the name of the main component registered from JavaScript. This is used to schedule\n   * rendering of the component.\n   */\n  override fun getMainComponentName(): String = \"example\"\n\n  /**\n   * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate]\n   * which allows you to enable New Architecture with a single boolean flags [fabricEnabled]\n   */\n  override fun createReactActivityDelegate(): ReactActivityDelegate =\n      DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled)\n}\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/android/app/src/main/java/com/example/MainApplication.kt",
    "content": "package com.example\n\nimport android.app.Application\nimport com.facebook.react.PackageList\nimport com.facebook.react.ReactApplication\nimport com.facebook.react.ReactHost\nimport com.facebook.react.ReactNativeHost\nimport com.facebook.react.ReactPackage\nimport com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load\nimport com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost\nimport com.facebook.react.defaults.DefaultReactNativeHost\nimport com.facebook.react.soloader.OpenSourceMergedSoMapping\nimport com.facebook.soloader.SoLoader\n\nclass MainApplication : Application(), ReactApplication {\n\n  override val reactNativeHost: ReactNativeHost =\n      object : DefaultReactNativeHost(this) {\n        override fun getPackages(): List<ReactPackage> =\n            PackageList(this).packages.apply {\n              // Packages that cannot be autolinked yet can be added manually here, for example:\n              // add(MyReactNativePackage())\n            }\n\n        override fun getJSMainModuleName(): String = \"index\"\n\n        override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG\n\n        override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED\n        override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED\n      }\n\n  override val reactHost: ReactHost\n    get() = getDefaultReactHost(applicationContext, reactNativeHost)\n\n  override fun onCreate() {\n    super.onCreate()\n    SoLoader.init(this, OpenSourceMergedSoMapping)\n    if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {\n      // If you opted-in for the New Architecture, we load the native entry point for this app.\n      load()\n    }\n  }\n}\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/android/app/src/main/res/drawable/rn_edit_text_material.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Copyright (C) 2014 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n<inset xmlns:android=\"http://schemas.android.com/apk/res/android\"\n       android:insetLeft=\"@dimen/abc_edit_text_inset_horizontal_material\"\n       android:insetRight=\"@dimen/abc_edit_text_inset_horizontal_material\"\n       android:insetTop=\"@dimen/abc_edit_text_inset_top_material\"\n       android:insetBottom=\"@dimen/abc_edit_text_inset_bottom_material\"\n       >\n\n    <selector>\n        <!--\n          This file is a copy of abc_edit_text_material (https://bit.ly/3k8fX7I).\n          The item below with state_pressed=\"false\" and state_focused=\"false\" causes a NullPointerException.\n          NullPointerException:tempt to invoke virtual method 'android.graphics.drawable.Drawable android.graphics.drawable.Drawable$ConstantState.newDrawable(android.content.res.Resources)'\n\n          <item android:state_pressed=\"false\" android:state_focused=\"false\" android:drawable=\"@drawable/abc_textfield_default_mtrl_alpha\"/>\n\n          For more info, see https://bit.ly/3CdLStv (react-native/pull/29452) and https://bit.ly/3nxOMoR.\n        -->\n        <item android:state_enabled=\"false\" android:drawable=\"@drawable/abc_textfield_default_mtrl_alpha\"/>\n        <item android:drawable=\"@drawable/abc_textfield_activated_mtrl_alpha\"/>\n    </selector>\n\n</inset>\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/android/app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">example</string>\n</resources>\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/android/app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.DayNight.NoActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"android:editTextBackground\">@drawable/rn_edit_text_material</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/android/build.gradle",
    "content": "buildscript {\n    ext {\n        buildToolsVersion = \"35.0.0\"\n        minSdkVersion = 24\n        compileSdkVersion = 35\n        targetSdkVersion = 34\n        ndkVersion = \"26.1.10909125\"\n        kotlinVersion = \"1.9.24\"\n    }\n    repositories {\n        google()\n        mavenCentral()\n    }\n    dependencies {\n        classpath(\"com.android.tools.build:gradle\")\n        classpath(\"com.facebook.react:react-native-gradle-plugin\")\n        classpath(\"org.jetbrains.kotlin:kotlin-gradle-plugin\")\n    }\n}\n\napply plugin: \"com.facebook.react.rootproject\"\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/android/gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-8.10.2-all.zip\nnetworkTimeout=10000\nvalidateDistributionUrl=true\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/android/gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\n# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m\norg.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m\n\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n\n# AndroidX package structure to make it clearer which packages are bundled with the\n# Android operating system, and which are packaged with your app's APK\n# https://developer.android.com/topic/libraries/support-library/androidx-rn\nandroid.useAndroidX=true\n\n# Use this property to specify which architecture you want to build.\n# You can also override it from the CLI using\n# ./gradlew <task> -PreactNativeArchitectures=x86_64\nreactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64\n\n# Use this property to enable support to the new architecture.\n# This will allow you to use TurboModules and the Fabric render in\n# your application. You should enable this flag either if you want\n# to write custom TurboModules/Fabric components OR use libraries that\n# are providing them.\nnewArchEnabled=true\n\n# Use this property to enable or disable the Hermes JS engine.\n# If set to false, you will be using JSC instead.\nhermesEnabled=true\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/android/gradlew",
    "content": "#!/bin/sh\n\n#\n# Copyright © 2015-2021 the original authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n# SPDX-License-Identifier: Apache-2.0\n#\n\n##############################################################################\n#\n#   Gradle start up script for POSIX generated by Gradle.\n#\n#   Important for running:\n#\n#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is\n#       noncompliant, but you have some other compliant shell such as ksh or\n#       bash, then to run this script, type that shell name before the whole\n#       command line, like:\n#\n#           ksh Gradle\n#\n#       Busybox and similar reduced shells will NOT work, because this script\n#       requires all of these POSIX shell features:\n#         * functions;\n#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,\n#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;\n#         * compound commands having a testable exit status, especially «case»;\n#         * various built-in commands including «command», «set», and «ulimit».\n#\n#   Important for patching:\n#\n#   (2) This script targets any POSIX shell, so it avoids extensions provided\n#       by Bash, Ksh, etc; in particular arrays are avoided.\n#\n#       The \"traditional\" practice of packing multiple parameters into a\n#       space-separated string is a well documented source of bugs and security\n#       problems, so this is (mostly) avoided, by progressively accumulating\n#       options in \"$@\", and eventually passing that to Java.\n#\n#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,\n#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;\n#       see the in-line comments for details.\n#\n#       There are tweaks for specific operating systems such as AIX, CygWin,\n#       Darwin, MinGW, and NonStop.\n#\n#   (3) This script is generated from the Groovy template\n#       https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt\n#       within the Gradle project.\n#\n#       You can find Gradle at https://github.com/gradle/gradle/.\n#\n##############################################################################\n\n# Attempt to set APP_HOME\n\n# Resolve links: $0 may be a link\napp_path=$0\n\n# Need this for daisy-chained symlinks.\nwhile\n    APP_HOME=${app_path%\"${app_path##*/}\"}  # leaves a trailing /; empty if no leading path\n    [ -h \"$app_path\" ]\ndo\n    ls=$( ls -ld \"$app_path\" )\n    link=${ls#*' -> '}\n    case $link in             #(\n      /*)   app_path=$link ;; #(\n      *)    app_path=$APP_HOME$link ;;\n    esac\ndone\n\n# This is normally unused\n# shellcheck disable=SC2034\nAPP_BASE_NAME=${0##*/}\n# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)\nAPP_HOME=$( cd -P \"${APP_HOME:-./}\" > /dev/null && printf '%s\n' \"$PWD\" ) || exit\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=maximum\n\nwarn () {\n    echo \"$*\"\n} >&2\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n} >&2\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"$( uname )\" in                #(\n  CYGWIN* )         cygwin=true  ;; #(\n  Darwin* )         darwin=true  ;; #(\n  MSYS* | MINGW* )  msys=true    ;; #(\n  NONSTOP* )        nonstop=true ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=$JAVA_HOME/jre/sh/java\n    else\n        JAVACMD=$JAVA_HOME/bin/java\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=java\n    if ! command -v java >/dev/null 2>&1\n    then\n        die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nfi\n\n# Increase the maximum file descriptors if we can.\nif ! \"$cygwin\" && ! \"$darwin\" && ! \"$nonstop\" ; then\n    case $MAX_FD in #(\n      max*)\n        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.\n        # shellcheck disable=SC2039,SC3045\n        MAX_FD=$( ulimit -H -n ) ||\n            warn \"Could not query maximum file descriptor limit\"\n    esac\n    case $MAX_FD in  #(\n      '' | soft) :;; #(\n      *)\n        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.\n        # shellcheck disable=SC2039,SC3045\n        ulimit -n \"$MAX_FD\" ||\n            warn \"Could not set maximum file descriptor limit to $MAX_FD\"\n    esac\nfi\n\n# Collect all arguments for the java command, stacking in reverse order:\n#   * args from the command line\n#   * the main class name\n#   * -classpath\n#   * -D...appname settings\n#   * --module-path (only if needed)\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.\n\n# For Cygwin or MSYS, switch paths to Windows format before running java\nif \"$cygwin\" || \"$msys\" ; then\n    APP_HOME=$( cygpath --path --mixed \"$APP_HOME\" )\n    CLASSPATH=$( cygpath --path --mixed \"$CLASSPATH\" )\n\n    JAVACMD=$( cygpath --unix \"$JAVACMD\" )\n\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    for arg do\n        if\n            case $arg in                                #(\n              -*)   false ;;                            # don't mess with options #(\n              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath\n                    [ -e \"$t\" ] ;;                      #(\n              *)    false ;;\n            esac\n        then\n            arg=$( cygpath --path --ignore --mixed \"$arg\" )\n        fi\n        # Roll the args list around exactly as many times as the number of\n        # args, so each arg winds up back in the position where it started, but\n        # possibly modified.\n        #\n        # NB: a `for` loop captures its iteration list before it begins, so\n        # changing the positional parameters here affects neither the number of\n        # iterations, nor the values presented in `arg`.\n        shift                   # remove old arg\n        set -- \"$@\" \"$arg\"      # push replacement arg\n    done\nfi\n\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Collect all arguments for the java command:\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,\n#     and any embedded shellness will be escaped.\n#   * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be\n#     treated as '${Hostname}' itself on the command line.\n\nset -- \\\n        \"-Dorg.gradle.appname=$APP_BASE_NAME\" \\\n        -classpath \"$CLASSPATH\" \\\n        org.gradle.wrapper.GradleWrapperMain \\\n        \"$@\"\n\n# Stop when \"xargs\" is not available.\nif ! command -v xargs >/dev/null 2>&1\nthen\n    die \"xargs is not available\"\nfi\n\n# Use \"xargs\" to parse quoted args.\n#\n# With -n1 it outputs one arg per line, with the quotes and backslashes removed.\n#\n# In Bash we could simply go:\n#\n#   readarray ARGS < <( xargs -n1 <<<\"$var\" ) &&\n#   set -- \"${ARGS[@]}\" \"$@\"\n#\n# but POSIX shell has neither arrays nor command substitution, so instead we\n# post-process each arg (as a line of input to sed) to backslash-escape any\n# character that might be a shell metacharacter, then use eval to reverse\n# that process (while maintaining the separation between arguments), and wrap\n# the whole thing up as a single \"set\" statement.\n#\n# This will of course break if any of these variables contains a newline or\n# an unmatched quote.\n#\n\neval \"set -- $(\n        printf '%s\\n' \"$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\" |\n        xargs -n1 |\n        sed ' s~[^-[:alnum:]+,./:=@_]~\\\\&~g; ' |\n        tr '\\n' ' '\n    )\" '\"$@\"'\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/android/gradlew.bat",
    "content": "@rem\r\n@rem Copyright 2015 the original author or authors.\r\n@rem\r\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\r\n@rem you may not use this file except in compliance with the License.\r\n@rem You may obtain a copy of the License at\r\n@rem\r\n@rem      https://www.apache.org/licenses/LICENSE-2.0\r\n@rem\r\n@rem Unless required by applicable law or agreed to in writing, software\r\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\r\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n@rem See the License for the specific language governing permissions and\r\n@rem limitations under the License.\r\n@rem\r\n@rem SPDX-License-Identifier: Apache-2.0\r\n@rem\r\n\r\n@if \"%DEBUG%\"==\"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\"==\"\" set DIRNAME=.\r\n@rem This is normally unused\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Resolve any \".\" and \"..\" in APP_HOME to make it shorter.\r\nfor %%i in (\"%APP_HOME%\") do set APP_HOME=%%~fi\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif %ERRORLEVEL% equ 0 goto execute\r\n\r\necho. 1>&2\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2\r\necho. 1>&2\r\necho Please set the JAVA_HOME variable in your environment to match the 1>&2\r\necho location of your Java installation. 1>&2\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto execute\r\n\r\necho. 1>&2\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2\r\necho. 1>&2\r\necho Please set the JAVA_HOME variable in your environment to match the 1>&2\r\necho location of your Java installation. 1>&2\r\n\r\ngoto fail\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %*\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif %ERRORLEVEL% equ 0 goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nset EXIT_CODE=%ERRORLEVEL%\r\nif %EXIT_CODE% equ 0 set EXIT_CODE=1\r\nif not \"\"==\"%GRADLE_EXIT_CONSOLE%\" exit %EXIT_CODE%\r\nexit /b %EXIT_CODE%\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/android/settings.gradle",
    "content": "pluginManagement { includeBuild(\"../node_modules/@react-native/gradle-plugin\") }\nplugins { id(\"com.facebook.react.settings\") }\nextensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() }\nrootProject.name = 'example'\ninclude ':app'\nincludeBuild('../node_modules/@react-native/gradle-plugin')\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/app.json",
    "content": "{\n  \"name\": \"example\",\n  \"displayName\": \"example\"\n}\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/babel.config.js",
    "content": "module.exports = {\n  presets: ['module:@react-native/babel-preset'],\n};\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/index.js",
    "content": "/**\n * @format\n */\n\nimport {AppRegistry} from 'react-native';\nimport App from './App';\nimport {name as appName} from './app.json';\n\nAppRegistry.registerComponent(appName, () => App);\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/ios/.xcode.env",
    "content": "# This `.xcode.env` file is versioned and is used to source the environment\n# used when running script phases inside Xcode.\n# To customize your local environment, you can create an `.xcode.env.local`\n# file that is not versioned.\n\n# NODE_BINARY variable contains the PATH to the node executable.\n#\n# Customize the NODE_BINARY variable here.\n# For example, to use nvm with brew, add the following line\n# . \"$(brew --prefix nvm)/nvm.sh\" --no-use\nexport NODE_BINARY=$(command -v node)\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/ios/Podfile",
    "content": "# Resolve react_native_pods.rb with node to allow for hoisting\nrequire Pod::Executable.execute_command('node', ['-p',\n  'require.resolve(\n    \"react-native/scripts/react_native_pods.rb\",\n    {paths: [process.argv[1]]},\n  )', __dir__]).strip\n\nplatform :ios, min_ios_version_supported\nprepare_react_native_project!\n\nlinkage = ENV['USE_FRAMEWORKS']\nif linkage != nil\n  Pod::UI.puts \"Configuring Pod with #{linkage}ally linked Frameworks\".green\n  use_frameworks! :linkage => linkage.to_sym\nend\n\ntarget 'example' do\n  config = use_native_modules!\n\n  use_react_native!(\n    :path => config[:reactNativePath],\n    # An absolute path to your application root.\n    :app_path => \"#{Pod::Config.instance.installation_root}/..\"\n  )\n\n  target 'exampleTests' do\n    inherit! :complete\n    # Pods for testing\n  end\n\n  post_install do |installer|\n    # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202\n    react_native_post_install(\n      installer,\n      config[:reactNativePath],\n      :mac_catalyst_enabled => false,\n      # :ccache_enabled => true\n    )\n  end\nend\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/ios/example/AppDelegate.h",
    "content": "#import <RCTAppDelegate.h>\n#import <UIKit/UIKit.h>\n\n@interface AppDelegate : RCTAppDelegate\n\n@end\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/ios/example/AppDelegate.mm",
    "content": "#import \"AppDelegate.h\"\n\n#import <React/RCTBundleURLProvider.h>\n#import <ReactAppDependencyProvider/RCTAppDependencyProvider.h>\n\n@implementation AppDelegate\n\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions\n{\n  self.moduleName = @\"example\";\n  // You can add your custom initial props in the dictionary below.\n  // They will be passed down to the ViewController used by React Native.\n\n  // patch for crash on RN 0.77\n  // https://github.com/facebook/react-native/issues/49323#issuecomment-2759127287\n  self.dependencyProvider = [[RCTAppDependencyProvider alloc] init];\n\n  self.initialProps = @{};\n\n  return [super application:application didFinishLaunchingWithOptions:launchOptions];\n}\n\n- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge\n{\n  return [self bundleURL];\n}\n\n- (NSURL *)bundleURL\n{\n#if DEBUG\n  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@\"index\"];\n#else\n  return [[NSBundle mainBundle] URLForResource:@\"main\" withExtension:@\"jsbundle\"];\n#endif\n}\n\n@end\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/ios/example/Images.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"2x\",\n      \"size\" : \"20x20\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"3x\",\n      \"size\" : \"20x20\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"2x\",\n      \"size\" : \"29x29\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"3x\",\n      \"size\" : \"29x29\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"2x\",\n      \"size\" : \"40x40\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"3x\",\n      \"size\" : \"40x40\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"2x\",\n      \"size\" : \"60x60\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"scale\" : \"3x\",\n      \"size\" : \"60x60\"\n    },\n    {\n      \"idiom\" : \"ios-marketing\",\n      \"scale\" : \"1x\",\n      \"size\" : \"1024x1024\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/ios/example/Images.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/ios/example/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>example</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>$(MARKETING_VERSION)</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>NSAppTransportSecurity</key>\n\t<dict>\n\t\t<key>NSAllowsArbitraryLoads</key>\n\t\t<false/>\n\t\t<key>NSAllowsLocalNetworking</key>\n\t\t<true/>\n\t</dict>\n\t<key>NSLocationWhenInUseUsageDescription</key>\n\t<string></string>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>arm64</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UIViewControllerBasedStatusBarAppearance</key>\n\t<false/>\n</dict>\n</plist>\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/ios/example/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"15702\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <device id=\"retina4_7\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"15704\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <label opaque=\"NO\" clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"example\" textAlignment=\"center\" lineBreakMode=\"middleTruncation\" baselineAdjustment=\"alignBaselines\" minimumFontSize=\"18\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"GJd-Yh-RWb\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"202\" width=\"375\" height=\"43\"/>\n                                <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"36\"/>\n                                <nil key=\"highlightedColor\"/>\n                            </label>\n                            <label opaque=\"NO\" clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Powered by React Native\" textAlignment=\"center\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" minimumFontSize=\"9\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"MN2-I3-ftu\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"626\" width=\"375\" height=\"21\"/>\n                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                <nil key=\"highlightedColor\"/>\n                            </label>\n                        </subviews>\n                        <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\" cocoaTouchSystemColor=\"whiteColor\"/>\n                        <constraints>\n                            <constraint firstItem=\"Bcu-3y-fUS\" firstAttribute=\"bottom\" secondItem=\"MN2-I3-ftu\" secondAttribute=\"bottom\" constant=\"20\" id=\"OZV-Vh-mqD\"/>\n                            <constraint firstItem=\"Bcu-3y-fUS\" firstAttribute=\"centerX\" secondItem=\"GJd-Yh-RWb\" secondAttribute=\"centerX\" id=\"Q3B-4B-g5h\"/>\n                            <constraint firstItem=\"MN2-I3-ftu\" firstAttribute=\"centerX\" secondItem=\"Bcu-3y-fUS\" secondAttribute=\"centerX\" id=\"akx-eg-2ui\"/>\n                            <constraint firstItem=\"MN2-I3-ftu\" firstAttribute=\"leading\" secondItem=\"Bcu-3y-fUS\" secondAttribute=\"leading\" id=\"i1E-0Y-4RG\"/>\n                            <constraint firstItem=\"GJd-Yh-RWb\" firstAttribute=\"centerY\" secondItem=\"Ze5-6b-2t3\" secondAttribute=\"bottom\" multiplier=\"1/3\" constant=\"1\" id=\"moa-c2-u7t\"/>\n                            <constraint firstItem=\"GJd-Yh-RWb\" firstAttribute=\"leading\" secondItem=\"Bcu-3y-fUS\" secondAttribute=\"leading\" symbolic=\"YES\" id=\"x7j-FC-K8j\"/>\n                        </constraints>\n                        <viewLayoutGuide key=\"safeArea\" id=\"Bcu-3y-fUS\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"52.173913043478265\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/ios/example/PrivacyInfo.xcprivacy",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>NSPrivacyAccessedAPITypes</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>NSPrivacyAccessedAPIType</key>\n\t\t\t<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>\n\t\t\t<key>NSPrivacyAccessedAPITypeReasons</key>\n\t\t\t<array>\n\t\t\t\t<string>C617.1</string>\n\t\t\t</array>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>NSPrivacyAccessedAPIType</key>\n\t\t\t<string>NSPrivacyAccessedAPICategoryUserDefaults</string>\n\t\t\t<key>NSPrivacyAccessedAPITypeReasons</key>\n\t\t\t<array>\n\t\t\t\t<string>CA92.1</string>\n\t\t\t</array>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>NSPrivacyAccessedAPIType</key>\n\t\t\t<string>NSPrivacyAccessedAPICategorySystemBootTime</string>\n\t\t\t<key>NSPrivacyAccessedAPITypeReasons</key>\n\t\t\t<array>\n\t\t\t\t<string>35F9.1</string>\n\t\t\t</array>\n\t\t</dict>\n\t</array>\n\t<key>NSPrivacyCollectedDataTypes</key>\n\t<array/>\n\t<key>NSPrivacyTracking</key>\n\t<false/>\n</dict>\n</plist>\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/ios/example/main.m",
    "content": "#import <UIKit/UIKit.h>\n\n#import \"AppDelegate.h\"\n\nint main(int argc, char *argv[])\n{\n  @autoreleasepool {\n    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));\n  }\n}\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/ios/example.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t00E356F31AD99517003FC87E /* exampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* exampleTests.m */; };\n\t\t13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; };\n\t\t13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };\n\t\t13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };\n\t\t322981B30E924E639762153E /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */; };\n\t\t34623BD523082BDD78AB9C1A /* libPods-example.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 25353B01D3F85F2146CE0CF1 /* libPods-example.a */; };\n\t\t81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };\n\t\tE9FAB128BD14FFEB562F1D7C /* libPods-example-exampleTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 32DAD93772010729404CA6D2 /* libPods-example-exampleTests.a */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\t00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 13B07F861A680F5B00A75B9A;\n\t\t\tremoteInfo = example;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXFileReference section */\n\t\t00E356EE1AD99517003FC87E /* exampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = exampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t00E356F21AD99517003FC87E /* exampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = exampleTests.m; sourceTree = \"<group>\"; };\n\t\t13B07F961A680F5B00A75B9A /* example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = example.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = example/AppDelegate.h; sourceTree = \"<group>\"; };\n\t\t13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = example/AppDelegate.mm; sourceTree = \"<group>\"; };\n\t\t13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = example/Images.xcassets; sourceTree = \"<group>\"; };\n\t\t13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = example/Info.plist; sourceTree = \"<group>\"; };\n\t\t13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = example/main.m; sourceTree = \"<group>\"; };\n\t\t13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = PrivacyInfo.xcprivacy; path = example/PrivacyInfo.xcprivacy; sourceTree = \"<group>\"; };\n\t\t22B0B2BD787F432973CC0578 /* Pods-example-exampleTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-example-exampleTests.release.xcconfig\"; path = \"Target Support Files/Pods-example-exampleTests/Pods-example-exampleTests.release.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t25353B01D3F85F2146CE0CF1 /* libPods-example.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = \"libPods-example.a\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t32DAD93772010729404CA6D2 /* libPods-example-exampleTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = \"libPods-example-exampleTests.a\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t6D91BECB0331C06B109A303A /* Pods-example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-example.debug.xcconfig\"; path = \"Target Support Files/Pods-example/Pods-example.debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = example/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\tA98B834136E69D8AEE6F9CB5 /* Pods-example-exampleTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-example-exampleTests.debug.xcconfig\"; path = \"Target Support Files/Pods-example-exampleTests/Pods-example-exampleTests.debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\tB11B173E9049856FF732A405 /* Pods-example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-example.release.xcconfig\"; path = \"Target Support Files/Pods-example/Pods-example.release.xcconfig\"; sourceTree = \"<group>\"; };\n\t\tED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t00E356EB1AD99517003FC87E /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tE9FAB128BD14FFEB562F1D7C /* libPods-example-exampleTests.a in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t13B07F8C1A680F5B00A75B9A /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t34623BD523082BDD78AB9C1A /* libPods-example.a in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t00E356EF1AD99517003FC87E /* exampleTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t00E356F21AD99517003FC87E /* exampleTests.m */,\n\t\t\t\t00E356F01AD99517003FC87E /* Supporting Files */,\n\t\t\t);\n\t\t\tpath = exampleTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t00E356F01AD99517003FC87E /* Supporting Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t00E356F11AD99517003FC87E /* Info.plist */,\n\t\t\t);\n\t\t\tname = \"Supporting Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t13B07FAE1A68108700A75B9A /* example */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t13B07FAF1A68108700A75B9A /* AppDelegate.h */,\n\t\t\t\t13B07FB01A68108700A75B9A /* AppDelegate.mm */,\n\t\t\t\t13B07FB51A68108700A75B9A /* Images.xcassets */,\n\t\t\t\t13B07FB61A68108700A75B9A /* Info.plist */,\n\t\t\t\t81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */,\n\t\t\t\t13B07FB71A68108700A75B9A /* main.m */,\n\t\t\t\t13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */,\n\t\t\t);\n\t\t\tname = example;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2D16E6871FA4F8E400B85C8A /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tED297162215061F000B7C4FE /* JavaScriptCore.framework */,\n\t\t\t\t25353B01D3F85F2146CE0CF1 /* libPods-example.a */,\n\t\t\t\t32DAD93772010729404CA6D2 /* libPods-example-exampleTests.a */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t832341AE1AAA6A7D00B99B32 /* Libraries */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t);\n\t\t\tname = Libraries;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t83CBB9F61A601CBA00E9B192 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t13B07FAE1A68108700A75B9A /* example */,\n\t\t\t\t832341AE1AAA6A7D00B99B32 /* Libraries */,\n\t\t\t\t00E356EF1AD99517003FC87E /* exampleTests */,\n\t\t\t\t83CBBA001A601CBA00E9B192 /* Products */,\n\t\t\t\t2D16E6871FA4F8E400B85C8A /* Frameworks */,\n\t\t\t\tBBD78D7AC51CEA395F1C20DB /* Pods */,\n\t\t\t);\n\t\t\tindentWidth = 2;\n\t\t\tsourceTree = \"<group>\";\n\t\t\ttabWidth = 2;\n\t\t\tusesTabs = 0;\n\t\t};\n\t\t83CBBA001A601CBA00E9B192 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t13B07F961A680F5B00A75B9A /* example.app */,\n\t\t\t\t00E356EE1AD99517003FC87E /* exampleTests.xctest */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tBBD78D7AC51CEA395F1C20DB /* Pods */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t6D91BECB0331C06B109A303A /* Pods-example.debug.xcconfig */,\n\t\t\t\tB11B173E9049856FF732A405 /* Pods-example.release.xcconfig */,\n\t\t\t\tA98B834136E69D8AEE6F9CB5 /* Pods-example-exampleTests.debug.xcconfig */,\n\t\t\t\t22B0B2BD787F432973CC0578 /* Pods-example-exampleTests.release.xcconfig */,\n\t\t\t);\n\t\t\tpath = Pods;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t00E356ED1AD99517003FC87E /* exampleTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget \"exampleTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tB58130DF85FC8FFE28569F5A /* [CP] Check Pods Manifest.lock */,\n\t\t\t\t00E356EA1AD99517003FC87E /* Sources */,\n\t\t\t\t00E356EB1AD99517003FC87E /* Frameworks */,\n\t\t\t\t00E356EC1AD99517003FC87E /* Resources */,\n\t\t\t\tE3AF445B0F6971AFDE8AD879 /* [CP] Embed Pods Frameworks */,\n\t\t\t\t1F07C9949E3B122A0AB714FA /* [CP] Copy Pods Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t00E356F51AD99517003FC87E /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = exampleTests;\n\t\t\tproductName = exampleTests;\n\t\t\tproductReference = 00E356EE1AD99517003FC87E /* exampleTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n\t\t13B07F861A680F5B00A75B9A /* example */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget \"example\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t658A70D324CA3968B56426EA /* [CP] Check Pods Manifest.lock */,\n\t\t\t\t13B07F871A680F5B00A75B9A /* Sources */,\n\t\t\t\t13B07F8C1A680F5B00A75B9A /* Frameworks */,\n\t\t\t\t13B07F8E1A680F5B00A75B9A /* Resources */,\n\t\t\t\t00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,\n\t\t\t\t9EC7D92021082DFD2D50A843 /* [CP] Embed Pods Frameworks */,\n\t\t\t\tC4A752DC1C0E148A994B6AFE /* [CP] Copy Pods Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = example;\n\t\t\tproductName = example;\n\t\t\tproductReference = 13B07F961A680F5B00A75B9A /* example.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t83CBB9F71A601CBA00E9B192 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastUpgradeCheck = 1210;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t00E356ED1AD99517003FC87E = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 6.2;\n\t\t\t\t\t\tTestTargetID = 13B07F861A680F5B00A75B9A;\n\t\t\t\t\t};\n\t\t\t\t\t13B07F861A680F5B00A75B9A = {\n\t\t\t\t\t\tLastSwiftMigration = 1120;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject \"example\" */;\n\t\t\tcompatibilityVersion = \"Xcode 12.0\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 83CBB9F61A601CBA00E9B192;\n\t\t\tproductRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t13B07F861A680F5B00A75B9A /* example */,\n\t\t\t\t00E356ED1AD99517003FC87E /* exampleTests */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t00E356EC1AD99517003FC87E /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t13B07F8E1A680F5B00A75B9A /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */,\n\t\t\t\t13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,\n\t\t\t\t322981B30E924E639762153E /* PrivacyInfo.xcprivacy in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\t00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"$(SRCROOT)/.xcode.env.local\",\n\t\t\t\t\"$(SRCROOT)/.xcode.env\",\n\t\t\t);\n\t\t\tname = \"Bundle React Native code and images\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"set -e\\n\\nWITH_ENVIRONMENT=\\\"$REACT_NATIVE_PATH/scripts/xcode/with-environment.sh\\\"\\nREACT_NATIVE_XCODE=\\\"$REACT_NATIVE_PATH/scripts/react-native-xcode.sh\\\"\\n\\n/bin/sh -c \\\"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\\\"\\n\";\n\t\t};\n\t\t1F07C9949E3B122A0AB714FA /* [CP] Copy Pods Resources */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-example-exampleTests/Pods-example-exampleTests-resources-${CONFIGURATION}-input-files.xcfilelist\",\n\t\t\t);\n\t\t\tname = \"[CP] Copy Pods Resources\";\n\t\t\toutputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-example-exampleTests/Pods-example-exampleTests-resources-${CONFIGURATION}-output-files.xcfilelist\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-example-exampleTests/Pods-example-exampleTests-resources.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\t658A70D324CA3968B56426EA /* [CP] Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\",\n\t\t\t\t\"${PODS_ROOT}/Manifest.lock\",\n\t\t\t);\n\t\t\tname = \"[CP] Check Pods Manifest.lock\";\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t\t\"$(DERIVED_FILE_DIR)/Pods-example-checkManifestLockResult.txt\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [ $? != 0 ] ; then\\n    # print error to STDERR\\n    echo \\\"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\\" >&2\\n    exit 1\\nfi\\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\\necho \\\"SUCCESS\\\" > \\\"${SCRIPT_OUTPUT_FILE_0}\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\t9EC7D92021082DFD2D50A843 /* [CP] Embed Pods Frameworks */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-frameworks-${CONFIGURATION}-input-files.xcfilelist\",\n\t\t\t);\n\t\t\tname = \"[CP] Embed Pods Frameworks\";\n\t\t\toutputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-frameworks-${CONFIGURATION}-output-files.xcfilelist\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-frameworks.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tB58130DF85FC8FFE28569F5A /* [CP] Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\",\n\t\t\t\t\"${PODS_ROOT}/Manifest.lock\",\n\t\t\t);\n\t\t\tname = \"[CP] Check Pods Manifest.lock\";\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t\t\"$(DERIVED_FILE_DIR)/Pods-example-exampleTests-checkManifestLockResult.txt\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [ $? != 0 ] ; then\\n    # print error to STDERR\\n    echo \\\"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\\" >&2\\n    exit 1\\nfi\\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\\necho \\\"SUCCESS\\\" > \\\"${SCRIPT_OUTPUT_FILE_0}\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tC4A752DC1C0E148A994B6AFE /* [CP] Copy Pods Resources */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-resources-${CONFIGURATION}-input-files.xcfilelist\",\n\t\t\t);\n\t\t\tname = \"[CP] Copy Pods Resources\";\n\t\t\toutputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-resources-${CONFIGURATION}-output-files.xcfilelist\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-example/Pods-example-resources.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\tE3AF445B0F6971AFDE8AD879 /* [CP] Embed Pods Frameworks */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-example-exampleTests/Pods-example-exampleTests-frameworks-${CONFIGURATION}-input-files.xcfilelist\",\n\t\t\t);\n\t\t\tname = \"[CP] Embed Pods Frameworks\";\n\t\t\toutputFileListPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-example-exampleTests/Pods-example-exampleTests-frameworks-${CONFIGURATION}-output-files.xcfilelist\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-example-exampleTests/Pods-example-exampleTests-frameworks.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t00E356EA1AD99517003FC87E /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t00E356F31AD99517003FC87E /* exampleTests.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t13B07F871A680F5B00A75B9A /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */,\n\t\t\t\t13B07FC11A68108700A75B9A /* main.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\t00E356F51AD99517003FC87E /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 13B07F861A680F5B00A75B9A /* example */;\n\t\t\ttargetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin XCBuildConfiguration section */\n\t\t00E356F61AD99517003FC87E /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = A98B834136E69D8AEE6F9CB5 /* Pods-example-exampleTests.debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = exampleTests/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.1;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t\t\"@loader_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tOTHER_LDFLAGS = (\n\t\t\t\t\t\"-ObjC\",\n\t\t\t\t\t\"-lc++\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/example.app/example\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t00E356F71AD99517003FC87E /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 22B0B2BD787F432973CC0578 /* Pods-example-exampleTests.release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tINFOPLIST_FILE = exampleTests/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.1;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t\t\"@loader_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tOTHER_LDFLAGS = (\n\t\t\t\t\t\"-ObjC\",\n\t\t\t\t\t\"-lc++\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/example.app/example\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t13B07F941A680F5B00A75B9A /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 6D91BECB0331C06B109A303A /* Pods-example.debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_TEAM = 7CA8BGS9U9;\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tINFOPLIST_FILE = example/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.1;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tOTHER_LDFLAGS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"-ObjC\",\n\t\t\t\t\t\"-lc++\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\t\"PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]\" = org.reactjs.native.example.example.izaaz;\n\t\t\t\tPRODUCT_NAME = example;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t13B07F951A680F5B00A75B9A /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = B11B173E9049856FF732A405 /* Pods-example.release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_TEAM = 7CA8BGS9U9;\n\t\t\t\tINFOPLIST_FILE = example/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.1;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tOTHER_LDFLAGS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"-ObjC\",\n\t\t\t\t\t\"-lc++\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\t\"PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]\" = org.reactjs.native.example.example.izaaz;\n\t\t\t\tPRODUCT_NAME = example;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t83CBBA201A601CBA00E9B192 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"c++20\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\t\"EXCLUDED_ARCHS[sdk=iphonesimulator*]\" = \"\";\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_SYMBOLS_PRIVATE_EXTERN = NO;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.1;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t/usr/lib/swift,\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tLIBRARY_SEARCH_PATHS = (\n\t\t\t\t\t\"\\\"$(SDKROOT)/usr/lib/swift\\\"\",\n\t\t\t\t\t\"\\\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\\\"\",\n\t\t\t\t\t\"\\\"$(inherited)\\\"\",\n\t\t\t\t);\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tOTHER_CPLUSPLUSFLAGS = (\n\t\t\t\t\t\"$(OTHER_CFLAGS)\",\n\t\t\t\t\t\"-DFOLLY_NO_CONFIG\",\n\t\t\t\t\t\"-DFOLLY_MOBILE=1\",\n\t\t\t\t\t\"-DFOLLY_USE_LIBCPP=1\",\n\t\t\t\t\t\"-DFOLLY_CFG_NO_COROUTINES=1\",\n\t\t\t\t\t\"-DFOLLY_HAVE_CLOCK_GETTIME=1\",\n\t\t\t\t);\n\t\t\t\tOTHER_LDFLAGS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\" \",\n\t\t\t\t);\n\t\t\t\tREACT_NATIVE_PATH = \"${PODS_ROOT}/../../node_modules/react-native\";\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"$(inherited) DEBUG\";\n\t\t\t\tUSE_HERMES = true;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t83CBBA211A601CBA00E9B192 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"c++20\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = YES;\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\t\"EXCLUDED_ARCHS[sdk=iphonesimulator*]\" = \"\";\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.1;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t/usr/lib/swift,\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tLIBRARY_SEARCH_PATHS = (\n\t\t\t\t\t\"\\\"$(SDKROOT)/usr/lib/swift\\\"\",\n\t\t\t\t\t\"\\\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\\\"\",\n\t\t\t\t\t\"\\\"$(inherited)\\\"\",\n\t\t\t\t);\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tOTHER_CPLUSPLUSFLAGS = (\n\t\t\t\t\t\"$(OTHER_CFLAGS)\",\n\t\t\t\t\t\"-DFOLLY_NO_CONFIG\",\n\t\t\t\t\t\"-DFOLLY_MOBILE=1\",\n\t\t\t\t\t\"-DFOLLY_USE_LIBCPP=1\",\n\t\t\t\t\t\"-DFOLLY_CFG_NO_COROUTINES=1\",\n\t\t\t\t\t\"-DFOLLY_HAVE_CLOCK_GETTIME=1\",\n\t\t\t\t);\n\t\t\t\tOTHER_LDFLAGS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\" \",\n\t\t\t\t);\n\t\t\t\tREACT_NATIVE_PATH = \"${PODS_ROOT}/../../node_modules/react-native\";\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tUSE_HERMES = true;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget \"exampleTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t00E356F61AD99517003FC87E /* Debug */,\n\t\t\t\t00E356F71AD99517003FC87E /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget \"example\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t13B07F941A680F5B00A75B9A /* Debug */,\n\t\t\t\t13B07F951A680F5B00A75B9A /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject \"example\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t83CBBA201A601CBA00E9B192 /* Debug */,\n\t\t\t\t83CBBA211A601CBA00E9B192 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;\n}\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/ios/example.xcodeproj/xcshareddata/xcschemes/example.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1210\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"13B07F861A680F5B00A75B9A\"\n               BuildableName = \"example.app\"\n               BlueprintName = \"example\"\n               ReferencedContainer = \"container:example.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"00E356ED1AD99517003FC87E\"\n               BuildableName = \"exampleTests.xctest\"\n               BlueprintName = \"exampleTests\"\n               ReferencedContainer = \"container:example.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"13B07F861A680F5B00A75B9A\"\n            BuildableName = \"example.app\"\n            BlueprintName = \"example\"\n            ReferencedContainer = \"container:example.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"13B07F861A680F5B00A75B9A\"\n            BuildableName = \"example.app\"\n            BlueprintName = \"example\"\n            ReferencedContainer = \"container:example.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/ios/example.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"group:example.xcodeproj\">\n   </FileRef>\n   <FileRef\n      location = \"group:Pods/Pods.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/ios/exampleTests/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/ios/exampleTests/exampleTests.m",
    "content": "#import <UIKit/UIKit.h>\n#import <XCTest/XCTest.h>\n\n#import <React/RCTLog.h>\n#import <React/RCTRootView.h>\n\n#define TIMEOUT_SECONDS 600\n#define TEXT_TO_LOOK_FOR @\"Welcome to React\"\n\n@interface exampleTests : XCTestCase\n\n@end\n\n@implementation exampleTests\n\n- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL (^)(UIView *view))test\n{\n  if (test(view)) {\n    return YES;\n  }\n  for (UIView *subview in [view subviews]) {\n    if ([self findSubviewInView:subview matching:test]) {\n      return YES;\n    }\n  }\n  return NO;\n}\n\n- (void)testRendersWelcomeScreen\n{\n  UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController];\n  NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];\n  BOOL foundElement = NO;\n\n  __block NSString *redboxError = nil;\n#ifdef DEBUG\n  RCTSetLogFunction(\n      ^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {\n        if (level >= RCTLogLevelError) {\n          redboxError = message;\n        }\n      });\n#endif\n\n  while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {\n    [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];\n    [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];\n\n    foundElement = [self findSubviewInView:vc.view\n                                  matching:^BOOL(UIView *view) {\n                                    if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {\n                                      return YES;\n                                    }\n                                    return NO;\n                                  }];\n  }\n\n#ifdef DEBUG\n  RCTSetLogFunction(RCTDefaultLogFunction);\n#endif\n\n  XCTAssertNil(redboxError, @\"RedBox error: %@\", redboxError);\n  XCTAssertTrue(foundElement, @\"Couldn't find element with text '%@' in %d seconds\", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);\n}\n\n@end\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/jest.config.js",
    "content": "module.exports = {\n  preset: 'react-native',\n};\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/metro.config.js",
    "content": "const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');\n\n/**\n * Metro configuration\n * https://reactnative.dev/docs/metro\n *\n * @type {import('metro-config').MetroConfig}\n */\nconst config = {};\n\nmodule.exports = mergeConfig(getDefaultConfig(__dirname), config);\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/package.json",
    "content": "{\n  \"name\": \"example\",\n  \"version\": \"0.0.1\",\n  \"private\": true,\n  \"scripts\": {\n    \"clean\": \"rimraf node_modules\",\n    \"android\": \"react-native run-android\",\n    \"ios\": \"react-native run-ios\",\n    \"lint\": \"eslint .\",\n    \"start\": \"react-native start\",\n    \"test\": \"jest\",\n    \"nuke\": \"yarn clean && yarn install && rm -rf node_modules/@amplitude/plugin-session-replay-react-native/node_modules\"\n  },\n  \"dependencies\": {\n    \"@amplitude/analytics-react-native\": \"^1.4.11\",\n    \"@amplitude/plugin-session-replay-react-native\": \"file:../\",\n    \"@react-native-async-storage/async-storage\": \"^2.1.0\",\n    \"@react-navigation/native\": \"^7.0.14\",\n    \"@react-navigation/native-stack\": \"^7.2.0\",\n    \"deprecated-react-native-prop-types\": \"^5.0.0\",\n    \"react\": \"18.3.1\",\n    \"react-native\": \"0.77.2\",\n    \"react-native-safe-area-context\": \"^5.0.0\",\n    \"react-native-screens\": \"^4.4.0\",\n    \"react-native-webview\": \"^13.12.5\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.25.2\",\n    \"@babel/preset-env\": \"^7.25.3\",\n    \"@babel/runtime\": \"^7.25.0\",\n    \"@react-native-community/cli\": \"15.0.1\",\n    \"@react-native-community/cli-platform-android\": \"15.0.1\",\n    \"@react-native-community/cli-platform-ios\": \"15.0.1\",\n    \"@react-native/babel-preset\": \"0.76.5\",\n    \"@react-native/eslint-config\": \"0.76.5\",\n    \"@react-native/metro-config\": \"0.76.5\",\n    \"@react-native/typescript-config\": \"0.76.5\",\n    \"@types/react\": \"^18.2.6\",\n    \"@types/react-test-renderer\": \"^18.0.0\",\n    \"babel-jest\": \"^29.6.3\",\n    \"eslint\": \"^8.19.0\",\n    \"jest\": \"^29.6.3\",\n    \"prettier\": \"2.8.8\",\n    \"react-test-renderer\": \"18.3.1\",\n    \"typescript\": \"5.0.4\"\n  },\n  \"engines\": {\n    \"node\": \">=18\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/example/tsconfig.json",
    "content": "{\n  \"extends\": \"@react-native/typescript-config/tsconfig.json\"\n}\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/ios/ConsoleLogger.swift",
    "content": "import Foundation\nimport os.log\nimport AmplitudeSessionReplay\n\n\n@objc(AMPLogLevel)\npublic enum LogLevelEnum: Int {\n    case OFF\n    case ERROR\n    case WARN\n    case LOG\n    case DEBUG\n}\n\npublic class ConsoleLogger: CoreLogger {\n    public typealias LogLevel = LogLevelEnum\n\n    public var logLevel: Int\n    private var logger: OSLog\n\n    public init(logLevel: Int = LogLevelEnum.OFF.rawValue) {\n        self.logLevel = logLevel\n        self.logger = OSLog(subsystem: \"Amplitude\", category: \"Logging\")\n    }\n\n    public func error(message: String) {\n        if logLevel >= LogLevel.ERROR.rawValue {\n            os_log(\"Error: %@\", log: logger, type: .error, message)\n        }\n    }\n\n    public func warn(message: String) {\n        if logLevel >= LogLevel.WARN.rawValue {\n            os_log(\"Warn: %@\", log: logger, type: .default, message)\n        }\n    }\n\n    public func log(message: String) {\n        if logLevel >= LogLevel.LOG.rawValue {\n            os_log(\"Log: %@\", log: logger, type: .info, message)\n        }\n    }\n\n    public func debug(message: String) {\n        if logLevel >= LogLevel.DEBUG.rawValue {\n            os_log(\"Debug: %@\", log: logger, type: .debug, message)\n        }\n    }\n}\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/ios/PluginSessionReplayReactNative-Bridging-Header.h",
    "content": "#import <React/RCTBridgeModule.h>\n#import <React/RCTViewManager.h>\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/ios/PluginSessionReplayReactNative.mm",
    "content": "#import <React/RCTBridgeModule.h>\n\n@interface RCT_EXTERN_MODULE(PluginSessionReplayReactNative, NSObject)\n\nRCT_EXTERN_METHOD(setup:(NSString)apiKey deviceId:(NSString)deviceId sessionId:(nonnull NSNumber)sessionId serverZone:(NSString)serverZone sampleRate:(float)sampleRate enableRemoteConfig:(BOOL)enableRemoteConfig logLevel:(int)logLevel autoStart:(BOOL)autoStart resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)\n\nRCT_EXTERN_METHOD(setSessionId:(nonnull NSNumber)sessionId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)\n\nRCT_EXTERN_METHOD(getSessionId:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)\n\nRCT_EXTERN_METHOD(getSessionReplayProperties:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)\n\nRCT_EXTERN_METHOD(start:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)\n\nRCT_EXTERN_METHOD(stop:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)\n\nRCT_EXTERN_METHOD(flush:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)\n\nRCT_EXTERN_METHOD(teardown:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)\n\n@end\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/ios/PluginSessionReplayReactNative.swift",
    "content": "import Foundation\nimport AmplitudeSessionReplay\n\n@objc(PluginSessionReplayReactNative)\nclass PluginSessionReplayReactNative: NSObject {\n    \n    var sessionReplay: SessionReplay!\n    \n    @objc(setup:deviceId:sessionId:serverZone:sampleRate:enableRemoteConfig:logLevel:autoStart:resolve:reject:)\n    func setup(_ apiKey: String,\n               deviceId: String,\n               sessionId: NSNumber,\n               serverZone: String,\n               sampleRate: Float,\n               enableRemoteConfig: Bool,\n               logLevel: Int,\n               autoStart: Bool,\n               resolve: RCTPromiseResolveBlock,\n               reject: RCTPromiseRejectBlock) -> Void {\n        print(\n            \"\"\"\n            setup:\n            API Key: \\(apiKey)\n            Device Id: \\(deviceId)\n            Session Id: \\(sessionId)\n            Server Zone: \\(serverZone)\n            Sample Rate: \\(sampleRate)\n            Enable Remote Config: \\(enableRemoteConfig)\n            Log Level: \\(logLevel)\n            Auto Start: \\(autoStart)\n            \"\"\"\n        )\n        sessionReplay = SessionReplay(apiKey:apiKey,\n                                      deviceId: deviceId,\n                                      sessionId: sessionId.int64Value,\n                                      sampleRate: sampleRate,\n                                      logger:ConsoleLogger(logLevel: logLevel),\n                                      serverZone: serverZone == \"EU\" ? .EU : .US,\n                                      enableRemoteConfig: enableRemoteConfig)\n        if (autoStart) {\n            sessionReplay.start()\n        }\n        resolve(nil)\n    }\n    \n    @objc(setSessionId:resolve:reject:)\n    func setSessionId(_ sessionId: NSNumber, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {\n      print(\"setSessionId: \\(sessionId)\")\n      sessionReplay.sessionId = sessionId.int64Value\n      resolve(nil)\n    }\n    \n    @objc(getSessionId:reject:)\n    func getSessionId(_ resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {\n      print(\"getSessionId\")\n      resolve(NSNumber(value:sessionReplay.sessionId))\n    }\n    \n    @objc(getSessionReplayProperties:reject:)\n    func getSessionReplayProperties(_ resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) {\n      print(\"getSessionReplayProperties\")\n      resolve(sessionReplay.additionalEventProperties)\n    }\n    \n    @objc(start:reject:)\n    func start(_ resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {\n      print(\"start\")\n      sessionReplay.start()\n      resolve(nil)\n    }\n    \n    @objc(stop:reject:)\n    func stop(_ resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {\n      print(\"stop\")\n      sessionReplay.stop()\n      resolve(nil)\n    }\n    \n    @objc(flush:reject:)\n    func flush(_ resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {\n      print(\"flush\")\n      sessionReplay.flush()\n      resolve(nil)\n    }\n    \n    @objc(teardown:reject:)\n    func teardown(_ resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {\n      print(\"teardown\")\n      sessionReplay.stop()\n      resolve(nil)\n    }\n}\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/ios/RCTAmpMaskViewManager.m",
    "content": "#import <React/RCTViewManager.h>\n#import <React/RCTView.h>\n@import AmplitudeSessionReplay;\n\n@interface RCTAmpMaskViewManager : RCTViewManager\n@end\n\n@implementation RCTAmpMaskViewManager\n\nRCT_EXPORT_MODULE(RCTAmpMaskView)\n\n- (UIView *)view\n{\n  return [[RCTView alloc] init];\n}\n\nRCT_CUSTOM_VIEW_PROPERTY(mask, NSString, RCTView)\n{\n  NSString* mask = [RCTConvert NSString:json];\n  if ([mask isEqualToString:@\"amp-mask\"]) {\n    view.amp_isBlocked = true;\n  } else if ([mask isEqualToString:@\"amp-block\"]) {\n    view.amp_isBlocked = true;\n  } else if ([mask isEqualToString:@\"amp-unmask\"]) {\n    view.amp_isBlocked = false;\n  }\n}\n\n@end\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/jest.config.js",
    "content": "const baseConfig = require('../../jest.config.js');\nconst package = require('./package');\n\nmodule.exports = {\n  ...baseConfig,\n  displayName: package.name,\n  rootDir: '.',\n  preset: 'react-native',\n  testEnvironment: 'jsdom',\n  modulePathIgnorePatterns: [\n    \"<rootDir>/lib/\"\n  ],\n  transformIgnorePatterns: [\n    'node_modules/(?!(.pnpm|@react-native|react-native|@segment)/)',\n  ],\n  // TODO: get full coverage\n  coverageThreshold: {\n    global: {\n      branches: 0,\n      functions: 0,\n      lines: 0,\n      statements: 0,\n    }\n  },\n};\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/package.json",
    "content": "{\n  \"name\": \"@amplitude/plugin-session-replay-react-native\",\n  \"version\": \"0.4.10\",\n  \"description\": \"Amplitude Session Replay plugin for React Native\",\n  \"keywords\": [\n    \"analytics\",\n    \"amplitude\",\n    \"react-native\",\n    \"ios\",\n    \"android\",\n    \"session-replay\"\n  ],\n  \"author\": \"Amplitude Inc\",\n  \"homepage\": \"https://github.com/amplitude/Amplitude-TypeScript\",\n  \"license\": \"MIT\",\n  \"main\": \"lib/commonjs/index\",\n  \"module\": \"lib/module/index\",\n  \"types\": \"lib/typescript/index.d.ts\",\n  \"react-native\": \"src/index\",\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"tag\": \"latest\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/amplitude/Amplitude-TypeScript.git\"\n  },\n  \"scripts\": {\n    \"build\": \"bob build\",\n    \"clean\": \"rimraf node_modules lib coverage\",\n    \"fix\": \"pnpm fix:eslint & pnpm fix:prettier\",\n    \"fix:eslint\": \"eslint '{src,test}/**/*.ts' --fix\",\n    \"fix:prettier\": \"prettier --write \\\"{src,test}/**/*.ts\\\"\",\n    \"lint\": \"pnpm lint:eslint & pnpm lint:prettier\",\n    \"lint:eslint\": \"eslint '{src,test}/**/*.ts'\",\n    \"lint:prettier\": \"prettier --check \\\"{src,test}/**/*.ts\\\"\",\n    \"test\": \"jest\",\n    \"typecheck\": \"tsc -p ./tsconfig.json\",\n    \"version\": \"pnpm version-file && pnpm build\",\n    \"version-file\": \"node -p \\\"'export const VERSION = \\\\'' + require('./package.json').version + '\\\\';'\\\" > src/version.ts\",\n    \"typescript\": \"tsc --noEmit\",\n    \"example\": \"yarn workspace @amplitude/plugin-session-replay-react-native-example\",\n    \"pods\": \"cd example && pod-install --quiet\"\n  },\n  \"source\": \"src/index\",\n  \"files\": [\n    \"src\",\n    \"lib\",\n    \"android\",\n    \"ios\",\n    \"cpp\",\n    \"*.podspec\",\n    \"!ios/build\",\n    \"!android/build\",\n    \"!android/gradle\",\n    \"!android/gradlew\",\n    \"!android/gradlew.bat\",\n    \"!android/local.properties\",\n    \"!test\",\n    \"!**/__tests__\",\n    \"!**/__fixtures__\",\n    \"!**/__mocks__\",\n    \"!**/.*\"\n  ],\n  \"bugs\": {\n    \"url\": \"https://github.com/amplitude/Amplitude-TypeScript/issues\"\n  },\n  \"dependencies\": {\n    \"@amplitude/analytics-types\": \"^1.3.4\"\n  },\n  \"devDependencies\": {\n    \"@types/react\": \"^18.0.26\",\n    \"react\": \"18.2.0\",\n    \"react-native\": \"0.73.0\",\n    \"react-native-builder-bob\": \"^0.20.3\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"*\",\n    \"react-native\": \"*\"\n  },\n  \"react-native-builder-bob\": {\n    \"source\": \"src\",\n    \"output\": \"lib\",\n    \"targets\": [\n      \"commonjs\",\n      \"module\",\n      [\n        \"typescript\",\n        {\n          \"project\": \"tsconfig.build.json\"\n        }\n      ]\n    ]\n  }\n}\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/src/app-mask-view.tsx",
    "content": "import { requireNativeComponent, type ViewProps } from 'react-native';\n\ninterface AmpMaskViewProps extends ViewProps {\n  mask: 'amp-mask' | 'amp-unmask' | 'amp-block';\n}\n\nexport const AmpMaskView =\n  requireNativeComponent<AmpMaskViewProps>('RCTAmpMaskView');\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/src/index.tsx",
    "content": "export { SessionReplayPlugin } from './session-replay';\n\nexport { AmpMaskView } from './app-mask-view';\n\nexport { SessionReplayConfig } from './session-replay-config';\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/src/native-module.tsx",
    "content": "import { NativeModules, Platform } from 'react-native';\n\nconst LINKING_ERROR =\n  `The package '@amplitude/plugin-session-replay-react-native' doesn't seem to be linked. Make sure: \\n\\n` +\n  Platform.select({ ios: \"- You have run 'pod install'\\n\", default: '' }) +\n  '- You rebuilt the app after installing the package\\n' +\n  '- You are not using Expo Go\\n';\n\nexport const PluginSessionReplayReactNative =\n  NativeModules.PluginSessionReplayReactNative\n    ? NativeModules.PluginSessionReplayReactNative\n    : new Proxy(\n        {},\n        {\n          get() {\n            throw new Error(LINKING_ERROR);\n          },\n        }\n      );\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/src/session-replay-config.ts",
    "content": "import { LogLevel } from '@amplitude/analytics-types';\n\nexport interface SessionReplayConfig {\n  sampleRate?: number;\n  enableRemoteConfig?: boolean;\n  logLevel?: LogLevel;\n  autoStart?: boolean;\n}\n\nexport const getDefaultConfig: () => SessionReplayConfig = () => {\n  return {\n    sampleRate: 0,\n    enableRemoteConfig: true,\n    logLevel: LogLevel.Warn,\n    autoStart: true,\n  };\n};\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/src/session-replay.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unsafe-call */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/ban-ts-comment */\n/* eslint-disable @typescript-eslint/no-unsafe-return */\nimport type { EnrichmentPlugin, Event, ReactNativeClient, ReactNativeConfig } from '@amplitude/analytics-types';\n\nimport { PluginSessionReplayReactNative } from './native-module';\nimport { VERSION } from './version';\nimport { SessionReplayConfig, getDefaultConfig } from './session-replay-config';\nimport { LogLevel } from '@amplitude/analytics-types';\n\nexport class SessionReplayPlugin implements EnrichmentPlugin<ReactNativeClient, ReactNativeConfig> {\n  name = '@amplitude/plugin-session-replay-react-native';\n  type = 'enrichment' as const;\n  // this.config is defined in setup() which will always be called first\n\n  // @ts-ignore\n  config: ReactNativeConfig;\n  isInitialized = false;\n\n  sessionReplayConfig: SessionReplayConfig;\n\n  constructor(config: SessionReplayConfig = {}) {\n    this.sessionReplayConfig = {\n      ...getDefaultConfig(),\n      ...config,\n    };\n    console.log('Initializing SessionReplayPlugin with config: ', this.sessionReplayConfig);\n  }\n\n  async setup(config: ReactNativeConfig, _: ReactNativeClient): Promise<void> {\n    this.config = config;\n    console.log(`Installing @amplitude/plugin-session-replay-react-native, version ${VERSION}.`);\n    await PluginSessionReplayReactNative.setup(\n      config.apiKey,\n      config.deviceId,\n      config.sessionId,\n      config.serverZone,\n      this.sessionReplayConfig.sampleRate ?? 1,\n      this.sessionReplayConfig.enableRemoteConfig ?? true,\n      this.sessionReplayConfig.logLevel ?? LogLevel.Warn,\n      this.sessionReplayConfig.autoStart ?? true,\n    );\n    this.isInitialized = true;\n  }\n\n  async execute(event: Event): Promise<Event | null> {\n    if (!this.isInitialized) {\n      return Promise.resolve(event);\n    }\n\n    // On event, synchronize the session id to the what's on the browserConfig (source of truth)\n    // Choosing not to read from event object here, concerned about offline/delayed events messing up the state stored\n    // in SR.\n    if (this.config.sessionId && this.config.sessionId !== (await PluginSessionReplayReactNative.getSessionId())) {\n      await PluginSessionReplayReactNative.setSessionId(this.config.sessionId);\n    }\n    // Treating config.sessionId as source of truth, if the event's session id doesn't match, the\n    // event is not of the current session (offline/late events). In that case, don't tag the events\n    if (this.config.sessionId && this.config.sessionId === event.session_id) {\n      const sessionRecordingProperties = await PluginSessionReplayReactNative.getSessionReplayProperties();\n      event.event_properties = {\n        ...event.event_properties,\n        ...sessionRecordingProperties,\n      };\n    }\n    return Promise.resolve(event);\n  }\n\n  async start(): Promise<void> {\n    if (this.isInitialized) {\n      await PluginSessionReplayReactNative.start();\n    }\n  }\n\n  async stop(): Promise<void> {\n    if (this.isInitialized) {\n      await PluginSessionReplayReactNative.stop();\n    }\n  }\n\n  async teardown(): Promise<void> {\n    if (this.isInitialized) {\n      await PluginSessionReplayReactNative.teardown();\n    }\n    // the following are initialized in setup() which will always be called first\n    // here we reset them to null to prevent memory leaks\n\n    // @ts-ignore\n    this.config = null;\n    this.isInitialized = false;\n  }\n\n  async getSessionReplayProperties() {\n    if (!this.isInitialized) {\n      return {};\n    }\n    return PluginSessionReplayReactNative.getSessionReplayProperties();\n  }\n}\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/src/version.ts",
    "content": "export const VERSION = '0.4.10';\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/test/index.test.ts",
    "content": "import { getDefaultConfig } from '../src/session-replay-config';\n\ndescribe('Session Replay default config', () => {\n  // write a test that would check the default config for session replay plugin\n  it('should have autostart default to true', () => {\n    const config = getDefaultConfig();\n    expect(config.autoStart).toBe(true);\n  });\n});\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/test/tsconfig.json",
    "content": "{\n  \"extends\": \"../tsconfig.json\",\n  \"compilerOptions\": {\n    \"types\": [\"jest\", \"node\"]\n  }\n}\n\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig\",\n  \"exclude\": [\"test\",\"example\", \"lib\"]\n}\n"
  },
  {
    "path": "packages/plugin-session-replay-react-native/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"paths\": {\n      \"@amplitude/plugin-session-replay-react-native\": [\"./src/index\"]\n    },\n    \"allowUnreachableCode\": false,\n    \"allowUnusedLabels\": false,\n    \"esModuleInterop\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"jsx\": \"react\",\n    \"lib\": [\"esnext\", \"dom\"],\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"noStrictGenericChecks\": false,\n    \"skipLibCheck\": true,\n    \"target\": \"es6\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-stub-browser/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n"
  },
  {
    "path": "packages/plugin-stub-browser/README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://amplitude.com\" target=\"_blank\" align=\"center\">\n    <img src=\"https://static.amplitude.com/lightning/46c85bfd91905de8047f1ee65c7c93d6fa9ee6ea/static/media/amplitude-logo-with-text.4fb9e463.svg\" width=\"280\">\n  </a>\n  <br />\n</p>\n\n# @amplitude/plugin-stub-browser (beta)\n**This plugin is in beta at the moment, naming and interface might change in the future.**\n\nA stub plugin. Copy and paste this and rename to make a new plugin.\n\nAnd remove the \"private: true\" attribute from package.json\n\n## Installation\n\nThis package is not published on NPM registry and is available to be installed using npm and yarn.\n\n```sh\n# npm\nnpm install @amplitude/plugin-stub-browser@beta\n\n# yarn\nyarn add @amplitude/plugin-stub-browser@beta\n```\n\n## Usage\n\n```typescript\nimport * as amplitude from '@amplitude/analytics-browser';\nimport { stubPlugin } from '@amplitude/plugin-stub-browser';\n```\n\n### 2. Instantiate the plugin\n\n```typescript\nconst plugin = stubPlugin();\n```\n\n### 3. Install plugin to Amplitude SDK\n\n```typescript\namplitude.add(plugin);\n```\n\n### 4. Initialize Amplitude SDK\n\n```typescript\namplitude.init('API_KEY');\n```\n"
  },
  {
    "path": "packages/plugin-stub-browser/jest.config.js",
    "content": "const baseConfig = require('../../jest.config.js');\nconst package = require('./package');\n\nmodule.exports = {\n  ...baseConfig,\n  displayName: package.name,\n  rootDir: '.',\n  testEnvironment: 'jsdom',\n  coveragePathIgnorePatterns: ['index.ts'],\n};\n\n"
  },
  {
    "path": "packages/plugin-stub-browser/package.json",
    "content": "{\n  \"name\": \"@amplitude/plugin-stub-browser\",\n  \"private\": true,\n  \"version\": \"0.0.1-alpha.1\",\n  \"description\": \"\",\n  \"author\": \"Amplitude Inc\",\n  \"homepage\": \"https://github.com/amplitude/Amplitude-TypeScript\",\n  \"license\": \"MIT\",\n  \"main\": \"lib/cjs/index.js\",\n  \"module\": \"lib/esm/index.js\",\n  \"types\": \"lib/esm/index.d.ts\",\n  \"sideEffects\": false,\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"tag\": \"alpha\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/amplitude/Amplitude-TypeScript.git\"\n  },\n  \"scripts\": {\n    \"build\": \"pnpm bundle && pnpm build:es5 && pnpm build:esm\",\n    \"bundle\": \"rollup --config rollup.config.js\",\n    \"build:es5\": \"tsc -p ./tsconfig.es5.json\",\n    \"build:esm\": \"tsc -p ./tsconfig.esm.json\",\n    \"watch\": \"tsc -p ./tsconfig.esm.json --watch\",\n    \"clean\": \"rimraf node_modules lib coverage\",\n    \"fix\": \"pnpm fix:eslint & pnpm fix:prettier\",\n    \"fix:eslint\": \"eslint '{src,test}/**/*.ts' --fix\",\n    \"fix:prettier\": \"prettier --write \\\"{src,test}/**/*.ts\\\"\",\n    \"lint\": \"pnpm lint:eslint & pnpm lint:prettier\",\n    \"lint:eslint\": \"eslint '{src,test}/**/*.ts'\",\n    \"lint:prettier\": \"prettier --check \\\"{src,test}/**/*.ts\\\"\",\n    \"publish\": \"node ../../scripts/publish/upload-to-s3.js\",\n    \"test\": \"jest\",\n    \"typecheck\": \"tsc -p ./tsconfig.json\",\n    \"version\": \"pnpm version-file && pnpm build\",\n    \"version-file\": \"node -p \\\"'export const VERSION = \\\\'' + require('./package.json').version + '\\\\';'\\\" > src/version.ts\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/amplitude/Amplitude-TypeScript/issues\"\n  },\n  \"dependencies\": {\n    \"@amplitude/analytics-core\": \"workspace:*\",\n    \"tslib\": \"^2.4.1\"\n  },\n  \"devDependencies\": {\n    \"@amplitude/analytics-browser\": \"workspace:*\",\n    \"@aws-sdk/client-s3\": \"^3.229.0\",\n    \"@rollup/plugin-commonjs\": \"^23.0.4\",\n    \"@rollup/plugin-node-resolve\": \"^15.0.1\",\n    \"@rollup/plugin-typescript\": \"^10.0.1\",\n    \"css.escape\": \"^1.5.1\",\n    \"rollup\": \"^2.79.1\",\n    \"rollup-plugin-execute\": \"^1.1.1\",\n    \"rollup-plugin-gzip\": \"^3.1.0\",\n    \"rollup-plugin-sourcemaps\": \"^0.6.3\",\n    \"rollup-plugin-terser\": \"^7.0.2\"\n  },\n  \"files\": [\n    \"lib\"\n  ]\n}\n"
  },
  {
    "path": "packages/plugin-stub-browser/rollup.config.js",
    "content": "import { iife, umd } from '../../scripts/build/rollup.config';\n\niife.input = umd.input;\niife.output.name = 'amplitudeStubPlugin';\n\nexport default [umd, iife];\n"
  },
  {
    "path": "packages/plugin-stub-browser/src/constants.ts",
    "content": "export const PLUGIN_NAME = 'stub-browser';\n"
  },
  {
    "path": "packages/plugin-stub-browser/src/index.ts",
    "content": "export { stubPlugin as plugin, stubPlugin } from './stub-plugin';\nexport { VERSION } from './version';\n"
  },
  {
    "path": "packages/plugin-stub-browser/src/stub-plugin.ts",
    "content": "/* eslint-disable no-restricted-globals */\nimport { BrowserClient, BrowserConfig, EnrichmentPlugin } from '@amplitude/analytics-core';\nimport { PLUGIN_NAME } from './constants';\n\nexport type BrowserEnrichmentPlugin = EnrichmentPlugin<BrowserClient, BrowserConfig>;\n\nexport const stubPlugin = (): BrowserEnrichmentPlugin => {\n  const setup: BrowserEnrichmentPlugin['setup'] = async (/*config, amplitude*/) => {\n    // add logic here to setup any resources\n  };\n\n  /* istanbul ignore next */\n  const execute: BrowserEnrichmentPlugin['execute'] = async (event) => {\n    return event;\n  };\n\n  const teardown = async () => {\n    // add logic here to clean up any resources\n  };\n\n  return {\n    name: PLUGIN_NAME,\n    type: 'enrichment',\n    setup,\n    execute,\n    teardown,\n  };\n};\n"
  },
  {
    "path": "packages/plugin-stub-browser/src/version.ts",
    "content": "export const VERSION = '0.0.1-alpha.1';\n"
  },
  {
    "path": "packages/plugin-stub-browser/test/index.test.ts",
    "content": "import { stubPlugin } from '../src/index';\n\ndescribe('stub-browser', () => {\n  it('should be defined', () => {\n    expect(stubPlugin).toBeDefined();\n  });\n  it('should call setup and teardown without errors', async () => {\n    const plugin = stubPlugin();\n    /* eslint-disable-next-line @typescript-eslint/no-unsafe-argument */\n    await plugin?.setup?.({} as unknown as any, {} as unknown as any);\n    await plugin?.teardown?.();\n  });\n});\n"
  },
  {
    "path": "packages/plugin-stub-browser/tsconfig.es5.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/cjs\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-stub-browser/tsconfig.esm.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"es6\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/esm\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-stub-browser/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src/**/*\", \"test/**/*\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"esModuleInterop\": true,\n    \"lib\": [\"dom\"],\n    \"noEmit\": true,\n    \"rootDir\": \".\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-web-attribution-browser/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.2.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.2.9...@amplitude/plugin-web-attribution-browser@2.2.10) (2026-04-28)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.2.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.2.8...@amplitude/plugin-web-attribution-browser@2.2.9) (2026-04-22)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.2.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.2.7...@amplitude/plugin-web-attribution-browser@2.2.8) (2026-04-21)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.2.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.2.6...@amplitude/plugin-web-attribution-browser@2.2.7) (2026-04-14)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.2.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.2.5...@amplitude/plugin-web-attribution-browser@2.2.6) (2026-04-09)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.2.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.2.4...@amplitude/plugin-web-attribution-browser@2.2.5) (2026-04-01)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.2.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.2.3...@amplitude/plugin-web-attribution-browser@2.2.4) (2026-03-26)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.2.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.2.2...@amplitude/plugin-web-attribution-browser@2.2.3) (2026-03-24)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.2.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.2.1...@amplitude/plugin-web-attribution-browser@2.2.2) (2026-03-23)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.2.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.2.0...@amplitude/plugin-web-attribution-browser@2.2.1) (2026-03-20)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n# [2.2.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.122...@amplitude/plugin-web-attribution-browser@2.2.0) (2026-03-19)\n\n\n### Features\n\n* **autocapture:** zoning beta  ([#1589](https://github.com/amplitude/Amplitude-TypeScript/issues/1589)) ([2bb3608](https://github.com/amplitude/Amplitude-TypeScript/commit/2bb36088dc1342512ba0289fb1108ed8a61361f6))\n\n\n\n\n\n## [2.1.122](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.121...@amplitude/plugin-web-attribution-browser@2.1.122) (2026-03-17)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.121](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.120...@amplitude/plugin-web-attribution-browser@2.1.121) (2026-03-16)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.120](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.119...@amplitude/plugin-web-attribution-browser@2.1.120) (2026-03-13)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.119](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.118...@amplitude/plugin-web-attribution-browser@2.1.119) (2026-03-12)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.118](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.117...@amplitude/plugin-web-attribution-browser@2.1.118) (2026-03-09)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.117](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.116...@amplitude/plugin-web-attribution-browser@2.1.117) (2026-03-05)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.116](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.115...@amplitude/plugin-web-attribution-browser@2.1.116) (2026-03-03)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.115](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.114...@amplitude/plugin-web-attribution-browser@2.1.115) (2026-03-03)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.114](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.113...@amplitude/plugin-web-attribution-browser@2.1.114) (2026-02-26)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.113](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.112...@amplitude/plugin-web-attribution-browser@2.1.113) (2026-02-24)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.112](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.111...@amplitude/plugin-web-attribution-browser@2.1.112) (2026-02-20)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.111](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.110...@amplitude/plugin-web-attribution-browser@2.1.111) (2026-02-19)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.110](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.109...@amplitude/plugin-web-attribution-browser@2.1.110) (2026-02-17)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.109](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.108...@amplitude/plugin-web-attribution-browser@2.1.109) (2026-02-10)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.108](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.107...@amplitude/plugin-web-attribution-browser@2.1.108) (2026-01-26)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.107](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.106...@amplitude/plugin-web-attribution-browser@2.1.107) (2026-01-21)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.106](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.105...@amplitude/plugin-web-attribution-browser@2.1.106) (2026-01-15)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.105](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.104...@amplitude/plugin-web-attribution-browser@2.1.105) (2026-01-14)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.104](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.103...@amplitude/plugin-web-attribution-browser@2.1.104) (2026-01-14)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.103](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.102...@amplitude/plugin-web-attribution-browser@2.1.103) (2025-12-30)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.102](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.101...@amplitude/plugin-web-attribution-browser@2.1.102) (2025-12-24)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.101](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.100...@amplitude/plugin-web-attribution-browser@2.1.101) (2025-12-16)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.100](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.99...@amplitude/plugin-web-attribution-browser@2.1.100) (2025-12-12)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.99](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.98...@amplitude/plugin-web-attribution-browser@2.1.99) (2025-12-09)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.98](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.97...@amplitude/plugin-web-attribution-browser@2.1.98) (2025-12-08)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.97](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.96...@amplitude/plugin-web-attribution-browser@2.1.97) (2025-11-21)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.96](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.95...@amplitude/plugin-web-attribution-browser@2.1.96) (2025-11-20)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.95](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.94...@amplitude/plugin-web-attribution-browser@2.1.95) (2025-11-17)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.94](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.93...@amplitude/plugin-web-attribution-browser@2.1.94) (2025-11-17)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.93](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.92...@amplitude/plugin-web-attribution-browser@2.1.93) (2025-11-05)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.92](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.91...@amplitude/plugin-web-attribution-browser@2.1.92) (2025-10-29)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.91](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.90...@amplitude/plugin-web-attribution-browser@2.1.91) (2025-10-23)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.90](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.89...@amplitude/plugin-web-attribution-browser@2.1.90) (2025-10-23)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.89](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.88...@amplitude/plugin-web-attribution-browser@2.1.89) (2025-10-21)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.88](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.87...@amplitude/plugin-web-attribution-browser@2.1.88) (2025-10-17)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.87](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.86...@amplitude/plugin-web-attribution-browser@2.1.87) (2025-10-15)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.86](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.85...@amplitude/plugin-web-attribution-browser@2.1.86) (2025-10-14)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.85](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.84...@amplitude/plugin-web-attribution-browser@2.1.85) (2025-10-14)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.84](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.83...@amplitude/plugin-web-attribution-browser@2.1.84) (2025-10-07)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.83](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.82...@amplitude/plugin-web-attribution-browser@2.1.83) (2025-10-06)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.82](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.81...@amplitude/plugin-web-attribution-browser@2.1.82) (2025-10-03)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.81](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.80...@amplitude/plugin-web-attribution-browser@2.1.81) (2025-10-01)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.80](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.79...@amplitude/plugin-web-attribution-browser@2.1.80) (2025-09-25)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.79](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.78...@amplitude/plugin-web-attribution-browser@2.1.79) (2025-09-23)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.78](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.77...@amplitude/plugin-web-attribution-browser@2.1.78) (2025-09-18)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.77](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.76...@amplitude/plugin-web-attribution-browser@2.1.77) (2025-09-12)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.76](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.75...@amplitude/plugin-web-attribution-browser@2.1.76) (2025-09-09)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.75](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.74...@amplitude/plugin-web-attribution-browser@2.1.75) (2025-09-05)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.74](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.73...@amplitude/plugin-web-attribution-browser@2.1.74) (2025-08-28)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.73](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.72...@amplitude/plugin-web-attribution-browser@2.1.73) (2025-08-26)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.72](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.71...@amplitude/plugin-web-attribution-browser@2.1.72) (2025-08-25)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.71](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.70...@amplitude/plugin-web-attribution-browser@2.1.71) (2025-08-25)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.70](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.69...@amplitude/plugin-web-attribution-browser@2.1.70) (2025-08-22)\n\n\n### Bug Fixes\n\n* **analytics-core:** fix typo in Reddit click-id ([#1267](https://github.com/amplitude/Amplitude-TypeScript/issues/1267)) ([43e581d](https://github.com/amplitude/Amplitude-TypeScript/commit/43e581d6465546a38373f758f179eee103172755))\n\n\n\n\n\n## [2.1.69](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.68...@amplitude/plugin-web-attribution-browser@2.1.69) (2025-08-21)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.68](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.67...@amplitude/plugin-web-attribution-browser@2.1.68) (2025-08-13)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.67](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.66...@amplitude/plugin-web-attribution-browser@2.1.67) (2025-08-08)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.66](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.65...@amplitude/plugin-web-attribution-browser@2.1.66) (2025-08-05)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.65](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.64...@amplitude/plugin-web-attribution-browser@2.1.65) (2025-07-30)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.64](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.63...@amplitude/plugin-web-attribution-browser@2.1.64) (2025-07-29)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.63](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.62...@amplitude/plugin-web-attribution-browser@2.1.63) (2025-07-18)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.62](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.61...@amplitude/plugin-web-attribution-browser@2.1.62) (2025-07-17)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.61](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.60...@amplitude/plugin-web-attribution-browser@2.1.61) (2025-07-15)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.60](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.59...@amplitude/plugin-web-attribution-browser@2.1.60) (2025-07-11)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.59](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.58...@amplitude/plugin-web-attribution-browser@2.1.59) (2025-07-08)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.58](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.57...@amplitude/plugin-web-attribution-browser@2.1.58) (2025-06-30)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.57](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.56...@amplitude/plugin-web-attribution-browser@2.1.57) (2025-06-26)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.56](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.55...@amplitude/plugin-web-attribution-browser@2.1.56) (2025-06-25)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.55](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.54...@amplitude/plugin-web-attribution-browser@2.1.55) (2025-06-16)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.54](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.53...@amplitude/plugin-web-attribution-browser@2.1.54) (2025-06-11)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.53](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.52...@amplitude/plugin-web-attribution-browser@2.1.53) (2025-06-03)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.52](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.52-main.0...@amplitude/plugin-web-attribution-browser@2.1.52) (2025-05-27)\n\n\n### Reverts\n\n* \"chore(release): publish\" ([#1094](https://github.com/amplitude/Amplitude-TypeScript/issues/1094)) ([f6db1ee](https://github.com/amplitude/Amplitude-TypeScript/commit/f6db1eed32ed77c7ce626624dc55972971f3b27d))\n\n\n\n\n\n## [2.1.51](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.50...@amplitude/plugin-web-attribution-browser@2.1.51) (2025-05-14)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.50](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.49...@amplitude/plugin-web-attribution-browser@2.1.50) (2025-05-13)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.49](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.48...@amplitude/plugin-web-attribution-browser@2.1.49) (2025-05-07)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.48](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.47...@amplitude/plugin-web-attribution-browser@2.1.48) (2025-05-05)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.47](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.46...@amplitude/plugin-web-attribution-browser@2.1.47) (2025-05-02)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.46](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.45...@amplitude/plugin-web-attribution-browser@2.1.46) (2025-05-02)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.45](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.44...@amplitude/plugin-web-attribution-browser@2.1.45) (2025-05-02)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.44](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.43...@amplitude/plugin-web-attribution-browser@2.1.44) (2025-04-30)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.43](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.42...@amplitude/plugin-web-attribution-browser@2.1.43) (2025-04-22)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.42](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.41...@amplitude/plugin-web-attribution-browser@2.1.42) (2025-04-17)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.41](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.40...@amplitude/plugin-web-attribution-browser@2.1.41) (2025-04-15)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.40](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.39...@amplitude/plugin-web-attribution-browser@2.1.40) (2025-04-10)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.39](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.38...@amplitude/plugin-web-attribution-browser@2.1.39) (2025-04-07)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.38](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.37...@amplitude/plugin-web-attribution-browser@2.1.38) (2025-04-07)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.37](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.36...@amplitude/plugin-web-attribution-browser@2.1.37) (2025-04-02)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.36](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.35...@amplitude/plugin-web-attribution-browser@2.1.36) (2025-03-24)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.35](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.34...@amplitude/plugin-web-attribution-browser@2.1.35) (2025-03-21)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.34](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.33...@amplitude/plugin-web-attribution-browser@2.1.34) (2025-03-14)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.33](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.32...@amplitude/plugin-web-attribution-browser@2.1.33) (2025-02-28)\n\n\n### Reverts\n\n* Revert \"chore(release): publish\" ([d392f62](https://github.com/amplitude/Amplitude-TypeScript/commit/d392f6290b8bb4dd955d6e6f20b00191679489c4))\n\n\n\n\n\n## [2.1.32](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.31...@amplitude/plugin-web-attribution-browser@2.1.32) (2025-02-14)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.31](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.30...@amplitude/plugin-web-attribution-browser@2.1.31) (2024-12-31)\n\n\n### Bug Fixes\n\n* add comments in isNewCampaign() ([#941](https://github.com/amplitude/Amplitude-TypeScript/issues/941)) ([a14a68c](https://github.com/amplitude/Amplitude-TypeScript/commit/a14a68c65cea7a4bf8a842761ff7a81830e5d3ba))\n\n\n\n\n\n## [2.1.30](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.29...@amplitude/plugin-web-attribution-browser@2.1.30) (2024-12-17)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.29](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.28...@amplitude/plugin-web-attribution-browser@2.1.29) (2024-11-05)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.28](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.27...@amplitude/plugin-web-attribution-browser@2.1.28) (2024-10-21)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.27](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.26...@amplitude/plugin-web-attribution-browser@2.1.27) (2024-09-26)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.26](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.25...@amplitude/plugin-web-attribution-browser@2.1.26) (2024-09-18)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.25](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.24...@amplitude/plugin-web-attribution-browser@2.1.25) (2024-09-17)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.24](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.23...@amplitude/plugin-web-attribution-browser@2.1.24) (2024-09-16)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.23](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.22...@amplitude/plugin-web-attribution-browser@2.1.23) (2024-09-10)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.22](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.21...@amplitude/plugin-web-attribution-browser@2.1.22) (2024-09-05)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.21](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.20...@amplitude/plugin-web-attribution-browser@2.1.21) (2024-08-23)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.20](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.19...@amplitude/plugin-web-attribution-browser@2.1.20) (2024-08-13)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.19](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.18...@amplitude/plugin-web-attribution-browser@2.1.19) (2024-08-02)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n## [2.1.18](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.17...@amplitude/plugin-web-attribution-browser@2.1.18) (2024-06-26)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n\n\n\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.17](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.16...@amplitude/plugin-web-attribution-browser@2.1.17) (2024-06-24)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.16](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.15...@amplitude/plugin-web-attribution-browser@2.1.16) (2024-06-24)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.15](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.14...@amplitude/plugin-web-attribution-browser@2.1.15) (2024-06-17)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.14](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.13...@amplitude/plugin-web-attribution-browser@2.1.14) (2024-05-24)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.12...@amplitude/plugin-web-attribution-browser@2.1.13) (2024-05-21)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.11...@amplitude/plugin-web-attribution-browser@2.1.12) (2024-05-17)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.10...@amplitude/plugin-web-attribution-browser@2.1.11) (2024-05-15)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.9...@amplitude/plugin-web-attribution-browser@2.1.10) (2024-05-07)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.8...@amplitude/plugin-web-attribution-browser@2.1.9) (2024-05-03)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.8-beta.0...@amplitude/plugin-web-attribution-browser@2.1.8) (2024-04-29)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.8-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.7...@amplitude/plugin-web-attribution-browser@2.1.8-beta.0) (2024-04-19)\n\n### Bug Fixes\n\n- fix web attribution identify and session start order\n  ([#696](https://github.com/amplitude/Amplitude-TypeScript/issues/696))\n  ([2f077da](https://github.com/amplitude/Amplitude-TypeScript/commit/2f077da7b528ed6f23f7459b7c961c099dbcb1bb))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.7-beta.0...@amplitude/plugin-web-attribution-browser@2.1.7) (2024-04-09)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.7-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.6...@amplitude/plugin-web-attribution-browser@2.1.7-beta.0) (2024-03-28)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.5...@amplitude/plugin-web-attribution-browser@2.1.6) (2024-03-27)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.4...@amplitude/plugin-web-attribution-browser@2.1.5) (2024-03-23)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.3...@amplitude/plugin-web-attribution-browser@2.1.4) (2024-03-12)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.2...@amplitude/plugin-web-attribution-browser@2.1.3) (2024-02-23)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.1...@amplitude/plugin-web-attribution-browser@2.1.2) (2024-02-23)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.1.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.1.0...@amplitude/plugin-web-attribution-browser@2.1.1) (2024-02-13)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.1.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.0.18...@amplitude/plugin-web-attribution-browser@2.1.0) (2024-01-24)\n\n### Features\n\n- add offline mode ([#644](https://github.com/amplitude/Amplitude-TypeScript/issues/644))\n  ([f2cd717](https://github.com/amplitude/Amplitude-TypeScript/commit/f2cd717316eef66b101153cb8eedf37fadc6de0c))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.18](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.0.17...@amplitude/plugin-web-attribution-browser@2.0.18) (2023-12-20)\n\n### Reverts\n\n- update attribution plugin to apply utm params to the `session_start` event\n  ([#638](https://github.com/amplitude/Amplitude-TypeScript/issues/638))\n  ([c820279](https://github.com/amplitude/Amplitude-TypeScript/commit/c820279cbef2123d890beb7861d7edbbc3926f6e))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.17](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.0.16...@amplitude/plugin-web-attribution-browser@2.0.17) (2023-12-12)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.16](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.0.16-beta.0...@amplitude/plugin-web-attribution-browser@2.0.16) (2023-12-01)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.16-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.0.15...@amplitude/plugin-web-attribution-browser@2.0.16-beta.0) (2023-11-22)\n\n### Bug Fixes\n\n- update attribution plugin to apply utm params to the `session_start` event\n  ([#619](https://github.com/amplitude/Amplitude-TypeScript/issues/619))\n  ([bf45ca6](https://github.com/amplitude/Amplitude-TypeScript/commit/bf45ca6c17ac8d656cb6c5bb4f4fa19ff344ac85))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.15](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.0.14...@amplitude/plugin-web-attribution-browser@2.0.15) (2023-11-16)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.14](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.0.13...@amplitude/plugin-web-attribution-browser@2.0.14) (2023-11-16)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.0.12...@amplitude/plugin-web-attribution-browser@2.0.13) (2023-10-18)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.0.11...@amplitude/plugin-web-attribution-browser@2.0.12) (2023-09-26)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.0.10...@amplitude/plugin-web-attribution-browser@2.0.11) (2023-09-18)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.0.9...@amplitude/plugin-web-attribution-browser@2.0.10) (2023-09-15)\n\n### Bug Fixes\n\n- fix attribution to capture UTMs even if there is no referral info\n  ([#584](https://github.com/amplitude/Amplitude-TypeScript/issues/584))\n  ([a1f03a5](https://github.com/amplitude/Amplitude-TypeScript/commit/a1f03a5c2c69cdbb7af9a5fb03cd81d35c51ecd4))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.0.8...@amplitude/plugin-web-attribution-browser@2.0.9) (2023-08-31)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.0.7...@amplitude/plugin-web-attribution-browser@2.0.8) (2023-08-29)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.0.6...@amplitude/plugin-web-attribution-browser@2.0.7) (2023-08-24)\n\n### Bug Fixes\n\n- fix web attribution behavior for no referrer in the same session\n  ([#554](https://github.com/amplitude/Amplitude-TypeScript/issues/554))\n  ([ed54eb2](https://github.com/amplitude/Amplitude-TypeScript/commit/ed54eb28810a3edb3326f82bdd7aed901ec9452f))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.0.5...@amplitude/plugin-web-attribution-browser@2.0.6) (2023-08-15)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.0.4...@amplitude/plugin-web-attribution-browser@2.0.5) (2023-07-27)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.0.3...@amplitude/plugin-web-attribution-browser@2.0.4) (2023-07-03)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.0.2...@amplitude/plugin-web-attribution-browser@2.0.3) (2023-06-30)\n\n### Bug Fixes\n\n- missing core dependency for web attribution ([#461](https://github.com/amplitude/Amplitude-TypeScript/issues/461))\n  ([3c5e6f2](https://github.com/amplitude/Amplitude-TypeScript/commit/3c5e6f2b13e55bf645c185649688867a69f6b0da))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.0.1...@amplitude/plugin-web-attribution-browser@2.0.2) (2023-06-22)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [2.0.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.0.0...@amplitude/plugin-web-attribution-browser@2.0.1) (2023-06-21)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.0.0-beta.10...@amplitude/plugin-web-attribution-browser@2.0.0) (2023-06-14)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.0.0-beta.9...@amplitude/plugin-web-attribution-browser@2.0.0-beta.10) (2023-06-14)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.0.0-beta.8...@amplitude/plugin-web-attribution-browser@2.0.0-beta.9) (2023-06-14)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.0.0-beta.7...@amplitude/plugin-web-attribution-browser@2.0.0-beta.8) (2023-06-13)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.0.0-beta.6...@amplitude/plugin-web-attribution-browser@2.0.0-beta.7) (2023-06-13)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.0.0-beta.5...@amplitude/plugin-web-attribution-browser@2.0.0-beta.6) (2023-06-09)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.0.0-beta.4...@amplitude/plugin-web-attribution-browser@2.0.0-beta.5) (2023-06-08)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.0.0-beta.3...@amplitude/plugin-web-attribution-browser@2.0.0-beta.4) (2023-06-07)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.0.0-beta.2...@amplitude/plugin-web-attribution-browser@2.0.0-beta.3) (2023-06-07)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@2.0.0-beta.1...@amplitude/plugin-web-attribution-browser@2.0.0-beta.2) (2023-06-06)\n\n### Bug Fixes\n\n- simplify plugins and eliminate enums ([#407](https://github.com/amplitude/Amplitude-TypeScript/issues/407))\n  ([890ec66](https://github.com/amplitude/Amplitude-TypeScript/commit/890ec6695a8b25cd6988e9f7ae584d4ba2835f67))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [2.0.0-beta.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.7.0...@amplitude/plugin-web-attribution-browser@2.0.0-beta.1) (2023-06-06)\n\n### Bug Fixes\n\n- dependency tree\n  ([d7ce659](https://github.com/amplitude/Amplitude-TypeScript/commit/d7ce659c72321c373346bab0f4c0e6d23304e1b6))\n\n### Features\n\n- allow cross subdomain excluded referrer ([#391](https://github.com/amplitude/Amplitude-TypeScript/issues/391))\n  ([f34f64b](https://github.com/amplitude/Amplitude-TypeScript/commit/f34f64b68bbd328da354afae61ca416d7055a734))\n- simplify browser SDK options and plugin options interface\n  ([#384](https://github.com/amplitude/Amplitude-TypeScript/issues/384))\n  ([b464cfb](https://github.com/amplitude/Amplitude-TypeScript/commit/b464cfb8e09d722bf06ed3c11955f77465a23daf))\n- simplify user identity storage options/configuration\n  ([#390](https://github.com/amplitude/Amplitude-TypeScript/issues/390))\n  ([f8cf0cc](https://github.com/amplitude/Amplitude-TypeScript/commit/f8cf0cca8c2a17738f13878642fa5b37c0070f77))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.7.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.6.7...@amplitude/plugin-web-attribution-browser@0.7.0) (2023-05-04)\n\n### Features\n\n- add attribution tracking for linkedin click id li_fat_id\n  ([ca81f3d](https://github.com/amplitude/Amplitude-TypeScript/commit/ca81f3d75ece7e0e23a1bc1b6889107d53a60a86))\n- add rtd_cid for Reddit campaign tracking/attribution\n  ([784e080](https://github.com/amplitude/Amplitude-TypeScript/commit/784e080aa129c37e850d7f34115beb9770044e4e))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.6.6...@amplitude/plugin-web-attribution-browser@0.6.7) (2023-04-27)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.6.5...@amplitude/plugin-web-attribution-browser@0.6.6) (2023-04-27)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.6.4...@amplitude/plugin-web-attribution-browser@0.6.5) (2023-04-25)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.6.3...@amplitude/plugin-web-attribution-browser@0.6.4) (2023-04-06)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.6.2...@amplitude/plugin-web-attribution-browser@0.6.3) (2023-03-31)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.6.2-beta.0...@amplitude/plugin-web-attribution-browser@0.6.2) (2023-03-31)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.2-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.6.1...@amplitude/plugin-web-attribution-browser@0.6.2-beta.0) (2023-03-31)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.6.1-beta.1...@amplitude/plugin-web-attribution-browser@0.6.1) (2023-03-03)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.1-beta.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.6.1-beta.0...@amplitude/plugin-web-attribution-browser@0.6.1-beta.1) (2023-03-03)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.6.1-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.6.0...@amplitude/plugin-web-attribution-browser@0.6.1-beta.0) (2023-03-03)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.6.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.6.0-beta.4...@amplitude/plugin-web-attribution-browser@0.6.0) (2023-02-27)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.6.0-beta.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.6.0-beta.3...@amplitude/plugin-web-attribution-browser@0.6.0-beta.4) (2023-02-27)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.6.0-beta.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.6.0-beta.2...@amplitude/plugin-web-attribution-browser@0.6.0-beta.3) (2023-02-26)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.6.0-beta.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.6.0-beta.1...@amplitude/plugin-web-attribution-browser@0.6.0-beta.2) (2023-02-25)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.6.0-beta.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.6.0-beta.0...@amplitude/plugin-web-attribution-browser@0.6.0-beta.1) (2023-02-24)\n\n### Bug Fixes\n\n- improper cookie usage ([#330](https://github.com/amplitude/Amplitude-TypeScript/issues/330))\n  ([e670091](https://github.com/amplitude/Amplitude-TypeScript/commit/e670091e59014bb35bd9b3ec2a7192f259393575))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.6.0-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.5.7...@amplitude/plugin-web-attribution-browser@0.6.0-beta.0) (2023-02-24)\n\n### Bug Fixes\n\n- remove client parameter requirement for page view tracking plugin\n  ([#329](https://github.com/amplitude/Amplitude-TypeScript/issues/329))\n  ([1e01575](https://github.com/amplitude/Amplitude-TypeScript/commit/1e015750b52880ca63afa5162cb482995f04d1c6))\n\n### Features\n\n- pass amplitude instance to plugin.setup for enhanced plugin capabilities\n  ([#328](https://github.com/amplitude/Amplitude-TypeScript/issues/328))\n  ([91eeaa0](https://github.com/amplitude/Amplitude-TypeScript/commit/91eeaa0d6bff6bde39538bb54548a938df784462))\n- retrofit web attribution and page view plugins to browser SDK\n  ([#331](https://github.com/amplitude/Amplitude-TypeScript/issues/331))\n  ([ba845d3](https://github.com/amplitude/Amplitude-TypeScript/commit/ba845d3329bd6bebe3b89f24f4f316088c2d62b9))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.5.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.5.6...@amplitude/plugin-web-attribution-browser@0.5.7) (2023-02-09)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.5.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.5.5...@amplitude/plugin-web-attribution-browser@0.5.6) (2023-02-02)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.5.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.5.5-beta.0...@amplitude/plugin-web-attribution-browser@0.5.5) (2023-01-31)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.5.5-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.5.4...@amplitude/plugin-web-attribution-browser@0.5.5-beta.0) (2023-01-26)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.5.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.5.3...@amplitude/plugin-web-attribution-browser@0.5.4) (2023-01-11)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.5.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.5.2...@amplitude/plugin-web-attribution-browser@0.5.3) (2022-12-21)\n\n### Bug Fixes\n\n- upgrade dependencies to resolve dependabot vulnerability alerts\n  ([#299](https://github.com/amplitude/Amplitude-TypeScript/issues/299))\n  ([7dd1cd1](https://github.com/amplitude/Amplitude-TypeScript/commit/7dd1cd1b23a71981a4ad90b4b30cc9b7d28c4412))\n\n### Reverts\n\n- Revert \"Updated dependencies\"\n  ([7ca9964](https://github.com/amplitude/Amplitude-TypeScript/commit/7ca9964781e4b900c6c027bdddf2ae1e7428ba18))\n\n## [0.5.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.5.1...@amplitude/plugin-web-attribution-browser@0.5.2) (2022-12-06)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n## [0.5.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.5.0...@amplitude/plugin-web-attribution-browser@0.5.1) (2022-12-05)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# [0.5.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.4.2...@amplitude/plugin-web-attribution-browser@0.5.0) (2022-11-28)\n\n### Features\n\n- add utm_id tracking ([#284](https://github.com/amplitude/Amplitude-TypeScript/issues/284))\n  ([f72dcf1](https://github.com/amplitude/Amplitude-TypeScript/commit/f72dcf1788ebc84544aaee1dc41b1d1ba6e4c06e))\n\n## [0.4.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.4.1...@amplitude/plugin-web-attribution-browser@0.4.2) (2022-11-22)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n## [0.4.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.4.0...@amplitude/plugin-web-attribution-browser@0.4.1) (2022-11-15)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# [0.4.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.3.0...@amplitude/plugin-web-attribution-browser@0.4.0) (2022-11-01)\n\n### Features\n\n- ignore subdomains when comparing newness of campaigns\n  ([#260](https://github.com/amplitude/Amplitude-TypeScript/issues/260))\n  ([8bb2b76](https://github.com/amplitude/Amplitude-TypeScript/commit/8bb2b76faf37783a58e953391468bd31c089e3a3))\n\n# [0.3.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.2.5...@amplitude/plugin-web-attribution-browser@0.3.0) (2022-11-01)\n\n### Features\n\n- enhance logger with debug information ([#254](https://github.com/amplitude/Amplitude-TypeScript/issues/254))\n  ([5c6175e](https://github.com/amplitude/Amplitude-TypeScript/commit/5c6175e9372cbeea264ddb34c6cc68148063d4f7))\n\n## [0.2.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.2.4...@amplitude/plugin-web-attribution-browser@0.2.5) (2022-10-30)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n## [0.2.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.2.3...@amplitude/plugin-web-attribution-browser@0.2.4) (2022-10-26)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n## [0.2.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.2.3-beta.1...@amplitude/plugin-web-attribution-browser@0.2.3) (2022-10-25)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n## [0.2.3-beta.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.2.3-beta.0...@amplitude/plugin-web-attribution-browser@0.2.3-beta.1) (2022-10-25)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n## [0.2.3-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.2.2...@amplitude/plugin-web-attribution-browser@0.2.3-beta.0) (2022-10-25)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n## [0.2.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.2.1...@amplitude/plugin-web-attribution-browser@0.2.2) (2022-10-25)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n## [0.2.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.2.0...@amplitude/plugin-web-attribution-browser@0.2.1) (2022-10-14)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# [0.2.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.1.6...@amplitude/plugin-web-attribution-browser@0.2.0) (2022-10-04)\n\n### Features\n\n- add gbraid and wbraid as campaign parameters ([#242](https://github.com/amplitude/Amplitude-TypeScript/issues/242))\n  ([514b7cd](https://github.com/amplitude/Amplitude-TypeScript/commit/514b7cdea9fee0c4e61479b087f7acdfea889350))\n\n## [0.1.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.1.5...@amplitude/plugin-web-attribution-browser@0.1.6) (2022-09-30)\n\n### Bug Fixes\n\n- resolve web attribution is not tracking the first direct/organic traffic\n  ([#239](https://github.com/amplitude/Amplitude-TypeScript/issues/239))\n  ([98a3363](https://github.com/amplitude/Amplitude-TypeScript/commit/98a33633a7a6de7ee147c8cbf690e5546ce53163))\n\n## [0.1.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.1.4...@amplitude/plugin-web-attribution-browser@0.1.5) (2022-09-30)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n## [0.1.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.1.4-beta.2...@amplitude/plugin-web-attribution-browser@0.1.4) (2022-09-28)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n## [0.1.4-beta.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.1.4-beta.1...@amplitude/plugin-web-attribution-browser@0.1.4-beta.2) (2022-09-27)\n\n### Bug Fixes\n\n- js script export name for marketing analytics plugins\n  ([aa7b05c](https://github.com/amplitude/Amplitude-TypeScript/commit/aa7b05cb192e23924081a363f3567573f76a3b62))\n\n## [0.1.4-beta.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.1.4-beta.0...@amplitude/plugin-web-attribution-browser@0.1.4-beta.1) (2022-09-27)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n## [0.1.4-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.1.3...@amplitude/plugin-web-attribution-browser@0.1.4-beta.0) (2022-09-26)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n## [0.1.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.1.2...@amplitude/plugin-web-attribution-browser@0.1.3) (2022-09-26)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n## [0.1.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.1.1...@amplitude/plugin-web-attribution-browser@0.1.2) (2022-09-26)\n\n### Bug Fixes\n\n- update base config to include additional click ids\n  ([#229](https://github.com/amplitude/Amplitude-TypeScript/issues/229))\n  ([5596931](https://github.com/amplitude/Amplitude-TypeScript/commit/55969310714c43f138e1702ba285fd4dadcdcb44))\n\n## [0.1.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-attribution-browser@0.1.0...@amplitude/plugin-web-attribution-browser@0.1.1) (2022-09-22)\n\n**Note:** Version bump only for package @amplitude/plugin-web-attribution-browser\n\n# 0.1.0 (2022-09-16)\n\n### Features\n\n- new marketing analytics plugin ([#213](https://github.com/amplitude/Amplitude-TypeScript/issues/213))\n  ([02ff174](https://github.com/amplitude/Amplitude-TypeScript/commit/02ff174e3361173dbf15ed3acf72e950810e174f))\n"
  },
  {
    "path": "packages/plugin-web-attribution-browser/README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://amplitude.com\" target=\"_blank\" align=\"center\">\n    <img src=\"https://static.amplitude.com/lightning/46c85bfd91905de8047f1ee65c7c93d6fa9ee6ea/static/media/amplitude-logo-with-text.4fb9e463.svg\" width=\"280\">\n  </a>\n  <br />\n</p>\n\n# @amplitude/plugin-web-attribution-browser\n\nOfficial Browser SDK plugin for web attribution tracking\n\n## Installation\n\nThis package is published on NPM registry and is available to be installed using npm and yarn.\n\n```sh\n# npm\nnpm install @amplitude/plugin-web-attribution-browser\n\n# yarn\nyarn add @amplitude/plugin-web-attribution-browser\n```\n\n## Usage\n\nThis plugin works on top of Amplitude Browser SDK and adds web attribution tracking features to built-in features. To use this plugin, you need to install `@amplitude/analytics-browser` version `v2.0.0` or later.\n\n### 1. Import Amplitude packages\n\n* `@amplitude/plugin-web-attribution-browser`\n\n```typescript\nimport { webAttributionPlugin } from '@amplitude/plugin-web-attribution-browser';\n```\n\n### 2. Instantiate page view plugin\n\nThe plugin accepts an optional parameter of type `Object` to configure the plugin based on your use case.\n\n```typescript\nconst webAttributionTracking = webAttributionPlugin(amplitude, {\n  excludeReferrers: undefined,\n  initialEmptyValue: undefined,\n  resetSessionOnNewCampaign: undefined,\n});\n```\n\n#### Options\n\n|Name|Type|Default|Description|\n|-|-|-|-|\n|`excludeReferrers`|`(string \\| RegExp)[]`|`[]`|Use this option to prevent the plugin from tracking campaigns parameters from specific referrers. For example: `subdomain.domain.com`.|\n|`initialEmptyValue`|`string`|`\"EMPTY\"`|Use this option to specify empty values for [first-touch attribution](https://www.docs.developers.amplitude.com/data/sdks/marketing-analytics-browser/#first-touch-attribution).|\n|`resetSessionOnNewCampaign`|`boolean`|`false`|Use this option to control whether a new session should start on a new campaign.|\n\n### 3. Install plugin to Amplitude SDK\n\n```typescript\namplitude.add(webAttributionTracking);\n```\n\n### 4. Initialize Amplitude SDK\n\n```typescript\namplitude.init('API_KEY');\n```\n\n## Resulting web attribution event\n\nThis plugin tracks campaign parameters based on your configuration. A web attribution event is composed of the following values:\n\n#### Event type\n* `\"$idenfity\"`\n\n#### User properties\n\n|Property|Description|\n|-|-|\n|`utm_source`|URL query parameter value for `utm_source`|\n|`utm_medium`|URL query parameter value for `utm_medium`|\n|`utm_campaign`|URL query parameter value for `utm_campaign`|\n|`utm_term`|URL query parameter value for `utm_term`|\n|`utm_content`|URL query parameter value for `utm_content`|\n|`referrer`|Referring webstite or `document.referrer`|\n|`referring_domain`|Referring website's domain, including subdomain|\n|`dclid`|URL query parameter value for `dclid`|\n|`gbraid`|URL query parameter value for `gbraid`|\n|`gclid`|URL query parameter value for `gclid`|\n|`fbclid`|URL query parameter value for `fbclid`|\n|`ko_click_id`|URL query parameter value for `ko_click_id`|\n|`li_fat_id`|URL query parameter value for `li_fat_id`|\n|`msclkid`|URL query parameter value for `msclkid`|\n|`rdt_cid`|URL query parameter value for `rdt_cid`|\n|`ttclid`|URL query parameter value for `ttclid`|\n|`twclid`|URL query parameter value for `twclid`|\n|`wbraid`|URL query parameter value for `wbraid`|\n"
  },
  {
    "path": "packages/plugin-web-attribution-browser/jest.config.js",
    "content": "const baseConfig = require('../../jest.config.js');\nconst package = require('./package');\n\nmodule.exports = {\n  ...baseConfig,\n  displayName: package.name,\n  rootDir: '.',\n  testEnvironment: 'jsdom',\n  coveragePathIgnorePatterns: ['index.ts'],\n};\n"
  },
  {
    "path": "packages/plugin-web-attribution-browser/package.json",
    "content": "{\n  \"name\": \"@amplitude/plugin-web-attribution-browser\",\n  \"version\": \"2.2.10\",\n  \"description\": \"\",\n  \"author\": \"Amplitude Inc\",\n  \"homepage\": \"https://github.com/amplitude/Amplitude-TypeScript\",\n  \"license\": \"MIT\",\n  \"main\": \"lib/cjs/index.js\",\n  \"module\": \"lib/esm/index.js\",\n  \"types\": \"lib/esm/index.d.ts\",\n  \"sideEffects\": false,\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"tag\": \"latest\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/amplitude/Amplitude-TypeScript.git\"\n  },\n  \"scripts\": {\n    \"build\": \"pnpm bundle && pnpm build:es5 && pnpm build:esm\",\n    \"bundle\": \"rollup --config rollup.config.js\",\n    \"build:es5\": \"tsc -p ./tsconfig.es5.json\",\n    \"build:esm\": \"tsc -p ./tsconfig.esm.json\",\n    \"watch\": \"tsc -p ./tsconfig.esm.json --watch\",\n    \"clean\": \"rimraf node_modules lib coverage\",\n    \"fix\": \"pnpm fix:eslint & pnpm fix:prettier\",\n    \"fix:eslint\": \"eslint '{src,test}/**/*.ts' --fix\",\n    \"fix:prettier\": \"prettier --write \\\"{src,test}/**/*.ts\\\"\",\n    \"lint\": \"pnpm lint:eslint & pnpm lint:prettier\",\n    \"lint:eslint\": \"eslint '{src,test}/**/*.ts'\",\n    \"lint:prettier\": \"prettier --check \\\"{src,test}/**/*.ts\\\"\",\n    \"test\": \"jest\",\n    \"typecheck\": \"tsc -p ./tsconfig.json\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/amplitude/Amplitude-TypeScript/issues\"\n  },\n  \"dependencies\": {\n    \"@amplitude/analytics-client-common\": \"workspace:*\",\n    \"@amplitude/analytics-core\": \"workspace:*\",\n    \"@amplitude/analytics-types\": \"workspace:*\",\n    \"tslib\": \"^2.4.1\"\n  },\n  \"devDependencies\": {\n    \"@rollup/plugin-commonjs\": \"^23.0.4\",\n    \"@rollup/plugin-node-resolve\": \"^15.0.1\",\n    \"@rollup/plugin-typescript\": \"^10.0.1\",\n    \"rollup\": \"^2.79.1\",\n    \"rollup-plugin-execute\": \"^1.1.1\",\n    \"rollup-plugin-gzip\": \"^3.1.0\",\n    \"rollup-plugin-terser\": \"^7.0.2\"\n  },\n  \"files\": [\n    \"lib\"\n  ]\n}\n"
  },
  {
    "path": "packages/plugin-web-attribution-browser/rollup.config.js",
    "content": "import { umd } from '../../scripts/build/rollup.config';\n\nexport default [umd];\n"
  },
  {
    "path": "packages/plugin-web-attribution-browser/src/index.ts",
    "content": "export { webAttributionPlugin } from './web-attribution';\nexport { webAttributionPlugin as plugin } from './web-attribution';\n"
  },
  {
    "path": "packages/plugin-web-attribution-browser/src/typings/web-attribution.ts",
    "content": "import { BeforePlugin } from '@amplitude/analytics-types';\n\nexport interface Options {\n  excludeReferrers?: (string | RegExp)[];\n  initialEmptyValue?: string;\n  resetSessionOnNewCampaign?: boolean;\n}\n\nexport interface CreateWebAttributionPlugin {\n  (options?: Options): BeforePlugin;\n}\n"
  },
  {
    "path": "packages/plugin-web-attribution-browser/src/web-attribution.ts",
    "content": "import { WebAttribution, isNewCampaign, isNewSession } from '@amplitude/analytics-client-common';\nimport { BeforePlugin, BrowserClient, BrowserConfig, Event } from '@amplitude/analytics-types';\nimport { CreateWebAttributionPlugin, Options } from './typings/web-attribution';\n\n/* eslint-disable @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-assignment */\n\n/**\n * @deprecated\n * This plugin is not used by @amplitude/analytics-browser and\n * is replaced by WebAttribution in @amplitude/analytics-client-common to\n * be able to send identify events before session start.\n */\nexport const webAttributionPlugin: CreateWebAttributionPlugin = function (options: Options = {}) {\n  const plugin: BeforePlugin = {\n    name: '@amplitude/plugin-web-attribution-browser',\n    type: 'before',\n\n    setup: async function (config: BrowserConfig, amplitude: BrowserClient) {\n      const webAttribution = new WebAttribution(options, config);\n      await webAttribution.init();\n\n      const pluginConfig = webAttribution.options;\n      const currentCampaign = webAttribution.currentCampaign;\n      const previousCampaign = webAttribution.previousCampaign;\n\n      const isEventInNewSession = isNewSession(config.sessionTimeout, config.lastEventTime);\n\n      if (isNewCampaign(currentCampaign, previousCampaign, pluginConfig, config.loggerProvider, isEventInNewSession)) {\n        if (pluginConfig.resetSessionOnNewCampaign) {\n          amplitude.setSessionId(Date.now());\n          config.loggerProvider.log('Created a new session for new campaign.');\n        }\n        config.loggerProvider.log('Tracking attribution.');\n        const campaignEvent = webAttribution.generateCampaignEvent();\n        amplitude.track(campaignEvent);\n      }\n    },\n\n    execute: async (event: Event) => event,\n  };\n\n  return plugin;\n};\n"
  },
  {
    "path": "packages/plugin-web-attribution-browser/test/web-attribution.test.ts",
    "content": "import { createInstance } from '@amplitude/analytics-browser';\nimport { BASE_CAMPAIGN, CampaignParser, CookieStorage, FetchTransport } from '@amplitude/analytics-client-common';\nimport { webAttributionPlugin } from '../src/web-attribution';\nimport * as helpers from '@amplitude/analytics-client-common';\nimport { BrowserConfig, LogLevel, Logger, UUID } from '@amplitude/analytics-core';\n\ndescribe('webAttributionPlugin', () => {\n  const mockConfig: BrowserConfig = {\n    apiKey: UUID(),\n    flushIntervalMillis: 0,\n    flushMaxRetries: 0,\n    flushQueueSize: 0,\n    logLevel: LogLevel.None,\n    loggerProvider: new Logger(),\n    offline: false,\n    optOut: false,\n    serverUrl: undefined,\n    transportProvider: new FetchTransport(),\n    useBatch: false,\n\n    cookieOptions: {\n      domain: '.amplitude.com',\n      expiration: 365,\n      sameSite: 'Lax',\n      secure: false,\n      upgrade: true,\n    },\n    cookieStorage: new CookieStorage(),\n    sessionTimeout: 30 * 60 * 1000,\n    trackingOptions: {\n      ipAddress: true,\n      language: true,\n      platform: true,\n    },\n  };\n\n  describe('setup', () => {\n    describe('should send an identify event', () => {\n      test('when a campaign changes', async () => {\n        const amplitude = createInstance();\n        const setSessionId = jest.spyOn(amplitude, 'setSessionId');\n        const track = jest.spyOn(amplitude, 'track').mockReturnValueOnce({\n          promise: Promise.resolve({\n            code: 200,\n            message: '',\n            event: {\n              event_type: '$identify',\n            },\n          }),\n        });\n        jest.spyOn(helpers, 'isNewCampaign').mockReturnValue(true);\n        jest.spyOn(CampaignParser.prototype, 'parse').mockResolvedValueOnce({\n          ...BASE_CAMPAIGN,\n          utm_source: 'amp-test',\n        });\n\n        const plugin = webAttributionPlugin();\n        const overrideMockConfig = {\n          ...mockConfig,\n          cookieOptions: undefined,\n        };\n        await plugin.setup?.(overrideMockConfig, amplitude);\n        expect(track).toHaveBeenCalledWith({\n          event_type: '$identify',\n          user_properties: {\n            $set: {\n              utm_source: 'amp-test',\n            },\n            $setOnce: {\n              initial_dclid: 'EMPTY',\n              initial_fbclid: 'EMPTY',\n              initial_gbraid: 'EMPTY',\n              initial_gclid: 'EMPTY',\n              initial_ko_click_id: 'EMPTY',\n              initial_li_fat_id: 'EMPTY',\n              initial_msclkid: 'EMPTY',\n              initial_wbraid: 'EMPTY',\n              initial_referrer: 'EMPTY',\n              initial_referring_domain: 'EMPTY',\n              initial_rdt_cid: 'EMPTY',\n              initial_ttclid: 'EMPTY',\n              initial_twclid: 'EMPTY',\n              initial_utm_campaign: 'EMPTY',\n              initial_utm_content: 'EMPTY',\n              initial_utm_id: 'EMPTY',\n              initial_utm_medium: 'EMPTY',\n              initial_utm_source: 'amp-test',\n              initial_utm_term: 'EMPTY',\n            },\n            $unset: {\n              dclid: '-',\n              fbclid: '-',\n              gbraid: '-',\n              gclid: '-',\n              ko_click_id: '-',\n              li_fat_id: '-',\n              msclkid: '-',\n              wbraid: '-',\n              referrer: '-',\n              referring_domain: '-',\n              rdt_cid: '-',\n              ttclid: '-',\n              twclid: '-',\n              utm_campaign: '-',\n              utm_content: '-',\n              utm_id: '-',\n              utm_medium: '-',\n              utm_term: '-',\n            },\n          },\n        });\n        expect(track).toHaveBeenCalledTimes(1);\n        expect(setSessionId).toHaveBeenCalledTimes(0);\n      });\n\n      test('when a campaign changes and reset session id', async () => {\n        const amplitude = createInstance();\n        const setSessionId = jest.spyOn(amplitude, 'setSessionId');\n        const track = jest.spyOn(amplitude, 'track').mockReturnValueOnce({\n          promise: Promise.resolve({\n            code: 200,\n            message: '',\n            event: {\n              event_type: '$identify',\n            },\n          }),\n        });\n        jest.spyOn(helpers, 'isNewCampaign').mockReturnValue(true);\n        jest.spyOn(CampaignParser.prototype, 'parse').mockResolvedValueOnce({\n          ...BASE_CAMPAIGN,\n          utm_source: 'amp-test',\n        });\n\n        const plugin = webAttributionPlugin({\n          resetSessionOnNewCampaign: true,\n        });\n        await plugin.setup?.(mockConfig, amplitude);\n        expect(track).toHaveBeenCalledWith({\n          event_type: '$identify',\n          user_properties: {\n            $set: {\n              utm_source: 'amp-test',\n            },\n            $setOnce: {\n              initial_dclid: 'EMPTY',\n              initial_fbclid: 'EMPTY',\n              initial_gbraid: 'EMPTY',\n              initial_gclid: 'EMPTY',\n              initial_ko_click_id: 'EMPTY',\n              initial_li_fat_id: 'EMPTY',\n              initial_msclkid: 'EMPTY',\n              initial_wbraid: 'EMPTY',\n              initial_referrer: 'EMPTY',\n              initial_referring_domain: 'EMPTY',\n              initial_rdt_cid: 'EMPTY',\n              initial_ttclid: 'EMPTY',\n              initial_twclid: 'EMPTY',\n              initial_utm_campaign: 'EMPTY',\n              initial_utm_content: 'EMPTY',\n              initial_utm_id: 'EMPTY',\n              initial_utm_medium: 'EMPTY',\n              initial_utm_source: 'amp-test',\n              initial_utm_term: 'EMPTY',\n            },\n            $unset: {\n              dclid: '-',\n              fbclid: '-',\n              gbraid: '-',\n              gclid: '-',\n              ko_click_id: '-',\n              li_fat_id: '-',\n              msclkid: '-',\n              wbraid: '-',\n              referrer: '-',\n              referring_domain: '-',\n              rdt_cid: '-',\n              ttclid: '-',\n              twclid: '-',\n              utm_campaign: '-',\n              utm_content: '-',\n              utm_id: '-',\n              utm_medium: '-',\n              utm_term: '-',\n            },\n          },\n        });\n        expect(track).toHaveBeenCalledTimes(1);\n        expect(setSessionId).toHaveBeenCalledTimes(1);\n      });\n    });\n\n    describe('should not send an identify event', () => {\n      test('when a campaign does not change', async () => {\n        const amplitude = createInstance();\n        const track = jest.spyOn(amplitude, 'track').mockReturnValueOnce({\n          promise: Promise.resolve({\n            code: 200,\n            message: '',\n            event: {\n              event_type: '$identify',\n            },\n          }),\n        });\n        jest.spyOn(helpers, 'isNewCampaign').mockReturnValue(false);\n        jest.spyOn(CampaignParser.prototype, 'parse').mockResolvedValueOnce({\n          ...BASE_CAMPAIGN,\n          utm_source: 'amp-test',\n        });\n\n        const plugin = webAttributionPlugin({\n          excludeReferrers: [],\n        });\n        await plugin.setup?.(mockConfig, amplitude);\n        expect(track).toHaveBeenCalledTimes(0);\n      });\n    });\n  });\n\n  test('should not send attribution event on default excluded referrer', async () => {\n    const amplitude = createInstance();\n    const track = jest.spyOn(amplitude, 'track').mockReturnValueOnce({\n      promise: Promise.resolve({\n        code: 200,\n        message: '',\n        event: {\n          event_type: '$identify',\n        },\n      }),\n    });\n    jest.spyOn(CampaignParser.prototype, 'parse').mockResolvedValueOnce({\n      ...BASE_CAMPAIGN,\n      referring_domain: 'amplitude.com',\n    });\n\n    const overrideMockConfig = {\n      ...mockConfig,\n      cookieOptions: {\n        ...mockConfig.cookieOptions,\n        domain: '.amplitude.com',\n      },\n    };\n    const plugin = webAttributionPlugin();\n    await plugin.setup?.(overrideMockConfig, amplitude);\n    expect(track).toHaveBeenCalledTimes(0);\n  });\n\n  describe('execute', () => {\n    test('should return same event', async () => {\n      jest.spyOn(helpers, 'isNewCampaign').mockReturnValue(true);\n      jest.spyOn(CampaignParser.prototype, 'parse').mockResolvedValueOnce({\n        ...BASE_CAMPAIGN,\n        utm_source: 'amp-test',\n      });\n      const plugin = webAttributionPlugin({});\n      const event = {\n        event_properties: {\n          page_location: '',\n          page_path: '',\n          page_title: '',\n        },\n        event_type: '[Amplitude] Page Viewed',\n      };\n      const result = await plugin.execute?.(event);\n\n      expect(result).toBe(event);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/plugin-web-attribution-browser/tsconfig.es5.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/cjs\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-web-attribution-browser/tsconfig.esm.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"es6\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/esm\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-web-attribution-browser/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src/**/*\", \"test/**/*\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"esModuleInterop\": true,\n    \"lib\": [\"dom\"],\n    \"noEmit\": true,\n    \"rootDir\": \".\",\n  }\n}\n"
  },
  {
    "path": "packages/plugin-web-vitals-browser/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.32](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.31...@amplitude/plugin-web-vitals-browser@1.1.32) (2026-04-28)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.1.31](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.30...@amplitude/plugin-web-vitals-browser@1.1.31) (2026-04-22)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.1.30](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.29...@amplitude/plugin-web-vitals-browser@1.1.30) (2026-04-21)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.1.29](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.28...@amplitude/plugin-web-vitals-browser@1.1.29) (2026-04-14)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.1.28](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.27...@amplitude/plugin-web-vitals-browser@1.1.28) (2026-04-09)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.1.27](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.26...@amplitude/plugin-web-vitals-browser@1.1.27) (2026-04-01)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.1.26](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.25...@amplitude/plugin-web-vitals-browser@1.1.26) (2026-03-26)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.1.25](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.24...@amplitude/plugin-web-vitals-browser@1.1.25) (2026-03-23)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.1.24](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.23...@amplitude/plugin-web-vitals-browser@1.1.24) (2026-03-20)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.1.23](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.22...@amplitude/plugin-web-vitals-browser@1.1.23) (2026-03-19)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.1.22](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.21...@amplitude/plugin-web-vitals-browser@1.1.22) (2026-03-17)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.1.21](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.20...@amplitude/plugin-web-vitals-browser@1.1.21) (2026-03-16)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.1.20](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.19...@amplitude/plugin-web-vitals-browser@1.1.20) (2026-03-13)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.1.19](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.18...@amplitude/plugin-web-vitals-browser@1.1.19) (2026-03-12)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.1.18](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.17...@amplitude/plugin-web-vitals-browser@1.1.18) (2026-03-09)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.1.17](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.16...@amplitude/plugin-web-vitals-browser@1.1.17) (2026-03-05)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.1.16](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.15...@amplitude/plugin-web-vitals-browser@1.1.16) (2026-03-03)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.1.15](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.14...@amplitude/plugin-web-vitals-browser@1.1.15) (2026-03-03)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.1.14](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.13...@amplitude/plugin-web-vitals-browser@1.1.14) (2026-02-26)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.1.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.12...@amplitude/plugin-web-vitals-browser@1.1.13) (2026-02-24)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.1.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.11...@amplitude/plugin-web-vitals-browser@1.1.12) (2026-02-19)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.1.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.10...@amplitude/plugin-web-vitals-browser@1.1.11) (2026-02-17)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.1.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.9...@amplitude/plugin-web-vitals-browser@1.1.10) (2026-02-10)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.1.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.8...@amplitude/plugin-web-vitals-browser@1.1.9) (2026-01-26)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.1.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.7...@amplitude/plugin-web-vitals-browser@1.1.8) (2026-01-21)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.1.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.6...@amplitude/plugin-web-vitals-browser@1.1.7) (2026-01-15)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.1.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.5...@amplitude/plugin-web-vitals-browser@1.1.6) (2026-01-14)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.1.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.4...@amplitude/plugin-web-vitals-browser@1.1.5) (2026-01-14)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.1.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.3...@amplitude/plugin-web-vitals-browser@1.1.4) (2025-12-30)\n\n\n### Bug Fixes\n\n* upgrade web-vitals 5.0.1 -> 5.1.0 ([#1451](https://github.com/amplitude/Amplitude-TypeScript/issues/1451)) ([a2d7606](https://github.com/amplitude/Amplitude-TypeScript/commit/a2d7606ac3310a0467a825f9cb7b0ac8b7f34dab))\n\n\n\n\n\n## [1.1.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.2...@amplitude/plugin-web-vitals-browser@1.1.3) (2025-12-24)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.1.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.1...@amplitude/plugin-web-vitals-browser@1.1.2) (2025-12-16)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.1.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.1.0...@amplitude/plugin-web-vitals-browser@1.1.1) (2025-12-09)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [1.1.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.0.3...@amplitude/plugin-web-vitals-browser@1.1.0) (2025-11-21)\n\n\n### Features\n\n* **analytics-browser:** reduce bundle size via refactoring out rxjs ([#1391](https://github.com/amplitude/Amplitude-TypeScript/issues/1391)) ([09ade0b](https://github.com/amplitude/Amplitude-TypeScript/commit/09ade0b37cfdbaacb0e328cb812168d60dc25124))\n\n\n\n\n\n## [1.0.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.0.2...@amplitude/plugin-web-vitals-browser@1.0.3) (2025-11-20)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.0.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@1.0.1...@amplitude/plugin-web-vitals-browser@1.0.2) (2025-11-17)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n## [1.0.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.35...@amplitude/plugin-web-vitals-browser@1.0.1) (2025-11-17)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.35](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.34...@amplitude/plugin-web-vitals-browser@0.1.0-beta.35) (2025-11-05)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.34](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.33...@amplitude/plugin-web-vitals-browser@0.1.0-beta.34) (2025-10-29)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.33](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.32...@amplitude/plugin-web-vitals-browser@0.1.0-beta.33) (2025-10-23)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.32](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.31...@amplitude/plugin-web-vitals-browser@0.1.0-beta.32) (2025-10-23)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.31](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.30...@amplitude/plugin-web-vitals-browser@0.1.0-beta.31) (2025-10-17)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.30](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.29...@amplitude/plugin-web-vitals-browser@0.1.0-beta.30) (2025-10-15)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.29](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.28...@amplitude/plugin-web-vitals-browser@0.1.0-beta.29) (2025-10-14)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.28](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.27...@amplitude/plugin-web-vitals-browser@0.1.0-beta.28) (2025-10-14)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.27](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.26...@amplitude/plugin-web-vitals-browser@0.1.0-beta.27) (2025-10-03)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.26](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.25...@amplitude/plugin-web-vitals-browser@0.1.0-beta.26) (2025-10-01)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.25](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.24...@amplitude/plugin-web-vitals-browser@0.1.0-beta.25) (2025-09-25)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.24](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.23...@amplitude/plugin-web-vitals-browser@0.1.0-beta.24) (2025-09-23)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.23](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.22...@amplitude/plugin-web-vitals-browser@0.1.0-beta.23) (2025-09-18)\n\n\n### Bug Fixes\n\n* **analytics-browser:** add URI decoding to Element Clicked event attribute ([#1297](https://github.com/amplitude/Amplitude-TypeScript/issues/1297)) ([ebb2120](https://github.com/amplitude/Amplitude-TypeScript/commit/ebb212080948e8acbaeadbdc410580e04202f818))\n\n\n\n\n\n# [0.1.0-beta.22](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.21...@amplitude/plugin-web-vitals-browser@0.1.0-beta.22) (2025-09-12)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.21](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.20...@amplitude/plugin-web-vitals-browser@0.1.0-beta.21) (2025-09-05)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.20](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.19...@amplitude/plugin-web-vitals-browser@0.1.0-beta.20) (2025-08-28)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.19](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.18...@amplitude/plugin-web-vitals-browser@0.1.0-beta.19) (2025-08-26)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.18](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.17...@amplitude/plugin-web-vitals-browser@0.1.0-beta.18) (2025-08-25)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.17](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.16...@amplitude/plugin-web-vitals-browser@0.1.0-beta.17) (2025-08-22)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.16](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.15...@amplitude/plugin-web-vitals-browser@0.1.0-beta.16) (2025-08-21)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.15](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.14...@amplitude/plugin-web-vitals-browser@0.1.0-beta.15) (2025-08-13)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.14](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.13...@amplitude/plugin-web-vitals-browser@0.1.0-beta.14) (2025-08-08)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.12...@amplitude/plugin-web-vitals-browser@0.1.0-beta.13) (2025-08-05)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.11...@amplitude/plugin-web-vitals-browser@0.1.0-beta.12) (2025-07-29)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.10...@amplitude/plugin-web-vitals-browser@0.1.0-beta.11) (2025-07-17)\n\n\n### Features\n\n* **analytics-browser:** support autocapture.webVitals ([#1195](https://github.com/amplitude/Amplitude-TypeScript/issues/1195)) ([a186f52](https://github.com/amplitude/Amplitude-TypeScript/commit/a186f523a28d8a322842566b892f50bcf2643142))\n\n\n\n\n\n# [0.1.0-beta.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.9...@amplitude/plugin-web-vitals-browser@0.1.0-beta.10) (2025-07-15)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.8...@amplitude/plugin-web-vitals-browser@0.1.0-beta.9) (2025-07-11)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.7...@amplitude/plugin-web-vitals-browser@0.1.0-beta.8) (2025-07-08)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.6...@amplitude/plugin-web-vitals-browser@0.1.0-beta.7) (2025-06-30)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.5...@amplitude/plugin-web-vitals-browser@0.1.0-beta.6) (2025-06-26)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.4...@amplitude/plugin-web-vitals-browser@0.1.0-beta.5) (2025-06-25)\n\n\n### Bug Fixes\n\n* **plugin-web-vitals-browser:** add TTFB ([#1161](https://github.com/amplitude/Amplitude-TypeScript/issues/1161)) ([f758fc8](https://github.com/amplitude/Amplitude-TypeScript/commit/f758fc81948e393b449aa6b7acc03720bc497331))\n\n\n\n\n\n# [0.1.0-beta.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.3...@amplitude/plugin-web-vitals-browser@0.1.0-beta.4) (2025-06-16)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.2...@amplitude/plugin-web-vitals-browser@0.1.0-beta.3) (2025-06-12)\n\n\n### Bug Fixes\n\n* add more attributes to web-vitals ([#1152](https://github.com/amplitude/Amplitude-TypeScript/issues/1152)) ([6fb35bd](https://github.com/amplitude/Amplitude-TypeScript/commit/6fb35bd0684dda75ecc01b66a6fa94ba7a0cdc5a))\n\n\n\n\n\n# [0.1.0-beta.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.1...@amplitude/plugin-web-vitals-browser@0.1.0-beta.2) (2025-06-11)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0-beta.0...@amplitude/plugin-web-vitals-browser@0.1.0-beta.1) (2025-06-03)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# [0.1.0-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/plugin-web-vitals-browser@0.1.0...@amplitude/plugin-web-vitals-browser@0.1.0-beta.0) (2025-06-02)\n\n**Note:** Version bump only for package @amplitude/plugin-web-vitals-browser\n\n\n\n\n\n# 0.1.0 (2025-05-30)\n\n\n### Features\n\n* **plugin-web-vitals-browser:** alpha version of web-vitals plugin ([#1109](https://github.com/amplitude/Amplitude-TypeScript/issues/1109)) ([af488ca](https://github.com/amplitude/Amplitude-TypeScript/commit/af488cac3d5ee01e26fb0d88a7faedf11db83253))\n"
  },
  {
    "path": "packages/plugin-web-vitals-browser/README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://amplitude.com\" target=\"_blank\" align=\"center\">\n    <img src=\"https://static.amplitude.com/lightning/46c85bfd91905de8047f1ee65c7c93d6fa9ee6ea/static/media/amplitude-logo-with-text.4fb9e463.svg\" width=\"280\">\n  </a>\n  <br />\n</p>\n\n# @amplitude/plugin-web-vitals-browser (beta)\n**This plugin is in beta at the moment, naming and interface might change in the future.**\n\nAutocaptures [web-vitals](https://www.npmjs.com/package/web-vitals) metrics (INP, LCP, FCP, CLS)\n\n## Installation\n\nThis package is published on NPM registry and is available to be installed using npm and yarn.\n\n```sh\n# npm\nnpm install @amplitude/plugin-web-vitals-browser@beta\n\n# yarn\nyarn add @amplitude/plugin-web-vitals-browser@beta\n```\n\n## Usage\n\n```typescript\nimport * as amplitude from '@amplitude/analytics-browser';\nimport { webVitalsPlugin } from '@amplitude/plugin-web-vitals-browser';\n```\n\n### 2. Instantiate the plugin\n\n```typescript\nconst plugin = webVitalsPlugin();\n```\n\n### 3. Install plugin to Amplitude SDK\n\n```typescript\namplitude.add(plugin);\n```\n\n### 4. Initialize Amplitude SDK\n\n```typescript\namplitude.init('API_KEY');\n```\n"
  },
  {
    "path": "packages/plugin-web-vitals-browser/jest.config.js",
    "content": "const baseConfig = require('../../jest.config.js');\nconst package = require('./package');\n\nmodule.exports = {\n  ...baseConfig,\n  displayName: package.name,\n  rootDir: '.',\n  testEnvironment: 'jsdom',\n  coveragePathIgnorePatterns: ['index.ts'],\n};\n\n"
  },
  {
    "path": "packages/plugin-web-vitals-browser/package.json",
    "content": "{\n  \"name\": \"@amplitude/plugin-web-vitals-browser\",\n  \"version\": \"1.1.32\",\n  \"description\": \"\",\n  \"author\": \"Amplitude Inc\",\n  \"homepage\": \"https://github.com/amplitude/Amplitude-TypeScript\",\n  \"license\": \"MIT\",\n  \"main\": \"lib/cjs/index.js\",\n  \"module\": \"lib/esm/index.js\",\n  \"types\": \"lib/esm/index.d.ts\",\n  \"sideEffects\": false,\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"tag\": \"alpha\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/amplitude/Amplitude-TypeScript.git\"\n  },\n  \"scripts\": {\n    \"build\": \"pnpm bundle && pnpm build:es5 && pnpm build:esm\",\n    \"bundle\": \"rollup --config rollup.config.js\",\n    \"build:es5\": \"tsc -p ./tsconfig.es5.json\",\n    \"build:esm\": \"tsc -p ./tsconfig.esm.json\",\n    \"watch\": \"tsc -p ./tsconfig.esm.json --watch\",\n    \"clean\": \"rimraf node_modules lib coverage\",\n    \"fix\": \"pnpm fix:eslint & pnpm fix:prettier\",\n    \"fix:eslint\": \"eslint '{src,test}/**/*.ts' --fix\",\n    \"fix:prettier\": \"prettier --write \\\"{src,test}/**/*.ts\\\"\",\n    \"lint\": \"pnpm lint:eslint & pnpm lint:prettier\",\n    \"lint:eslint\": \"eslint '{src,test}/**/*.ts'\",\n    \"lint:prettier\": \"prettier --check \\\"{src,test}/**/*.ts\\\"\",\n    \"test\": \"jest\",\n    \"typecheck\": \"tsc -p ./tsconfig.json\",\n    \"version\": \"pnpm version-file && pnpm build\",\n    \"version-file\": \"node -p \\\"'export const VERSION = \\\\'' + require('./package.json').version + '\\\\';'\\\" > src/version.ts\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/amplitude/Amplitude-TypeScript/issues\"\n  },\n  \"dependencies\": {\n    \"@amplitude/analytics-core\": \"workspace:*\",\n    \"tslib\": \"^2.4.1\",\n    \"web-vitals\": \"5.1.0\"\n  },\n  \"devDependencies\": {\n    \"@rollup/plugin-commonjs\": \"^23.0.4\",\n    \"@rollup/plugin-node-resolve\": \"^15.0.1\",\n    \"@rollup/plugin-typescript\": \"^10.0.1\",\n    \"css.escape\": \"^1.5.1\",\n    \"rollup\": \"^2.79.1\",\n    \"rollup-plugin-execute\": \"^1.1.1\",\n    \"rollup-plugin-gzip\": \"^3.1.0\",\n    \"rollup-plugin-sourcemaps\": \"^0.6.3\",\n    \"rollup-plugin-terser\": \"^7.0.2\"\n  },\n  \"files\": [\n    \"lib\"\n  ]\n}\n"
  },
  {
    "path": "packages/plugin-web-vitals-browser/rollup.config.js",
    "content": "import { iife, umd } from '../../scripts/build/rollup.config';\n\niife.input = umd.input;\niife.output.name = 'amplitudeWebVitalsPlugin';\n\nexport default [umd, iife];\n"
  },
  {
    "path": "packages/plugin-web-vitals-browser/src/constants.ts",
    "content": "export const PLUGIN_NAME = 'web-vitals-browser';\nexport const WEB_VITALS_EVENT_NAME = '[Amplitude] Web Vitals';\n"
  },
  {
    "path": "packages/plugin-web-vitals-browser/src/index.ts",
    "content": "export { webVitalsPlugin as plugin, webVitalsPlugin } from './web-vitals-plugin';\nexport { VERSION } from './version';\n"
  },
  {
    "path": "packages/plugin-web-vitals-browser/src/version.ts",
    "content": "export const VERSION = '1.1.32';\n"
  },
  {
    "path": "packages/plugin-web-vitals-browser/src/web-vitals-plugin.ts",
    "content": "/* eslint-disable no-restricted-globals */\nimport {\n  BrowserClient,\n  BrowserConfig,\n  EnrichmentPlugin,\n  getGlobalScope,\n  getDecodeURI,\n} from '@amplitude/analytics-core';\nimport { PLUGIN_NAME, WEB_VITALS_EVENT_NAME } from './constants';\nimport { onLCP, onINP, onCLS, onFCP, onTTFB, Metric } from 'web-vitals';\n\nexport type BrowserEnrichmentPlugin = EnrichmentPlugin<BrowserClient, BrowserConfig>;\n\ntype WebVitalsMetricPayload = {\n  value: number;\n  rating: Metric['rating'];\n  delta: number;\n  navigationType: Metric['navigationType'];\n  id: string;\n  timestamp: number;\n  navigationStart: number;\n};\n\ntype WebVitalsEventPayload = {\n  '[Amplitude] LCP'?: WebVitalsMetricPayload;\n  '[Amplitude] FCP'?: WebVitalsMetricPayload;\n  '[Amplitude] INP'?: WebVitalsMetricPayload;\n  '[Amplitude] CLS'?: WebVitalsMetricPayload;\n  '[Amplitude] TTFB'?: WebVitalsMetricPayload;\n  '[Amplitude] Page Domain'?: string;\n  '[Amplitude] Page Location'?: string;\n  '[Amplitude] Page Path'?: string;\n  '[Amplitude] Page Title'?: string;\n  '[Amplitude] Page URL'?: string;\n};\n\nfunction getMetricStartTime(metric: Metric) {\n  /* istanbul ignore next */\n  const startTime = metric.entries[0]?.startTime || 0;\n  return performance.timeOrigin + startTime;\n}\n\nfunction processMetric(metric: Metric) {\n  return {\n    value: metric.value,\n    rating: metric.rating,\n    delta: metric.delta,\n    navigationType: metric.navigationType,\n    id: metric.id,\n    timestamp: Math.floor(getMetricStartTime(metric)),\n    navigationStart: Math.floor(performance.timeOrigin),\n  };\n}\n\nexport const webVitalsPlugin = (): BrowserEnrichmentPlugin => {\n  let visibilityListener: ((this: Document, ev: Event) => void) | null = null;\n  const globalScope = getGlobalScope();\n  const doc = globalScope?.document;\n  const location = globalScope?.location;\n  const setup: BrowserEnrichmentPlugin['setup'] = async (config, amplitude) => {\n    if (doc === undefined) {\n      return;\n    }\n    const locationHref = getDecodeURI(/* istanbul ignore next */ location?.href || '', config.loggerProvider);\n    const webVitalsPayload: WebVitalsEventPayload = {\n      '[Amplitude] Page Domain': /* istanbul ignore next */ location?.hostname || '',\n      '[Amplitude] Page Location': locationHref,\n      '[Amplitude] Page Path': getDecodeURI(/* istanbul ignore next */ location?.pathname || '', config.loggerProvider),\n      '[Amplitude] Page Title': /* istanbul ignore next */ (typeof document !== 'undefined' && document.title) || '',\n      '[Amplitude] Page URL': getDecodeURI(locationHref.split('?')[0], config.loggerProvider),\n    };\n\n    onLCP((metric) => {\n      webVitalsPayload['[Amplitude] LCP'] = processMetric(metric);\n    });\n\n    onFCP((metric) => {\n      webVitalsPayload['[Amplitude] FCP'] = processMetric(metric);\n    });\n\n    onINP((metric) => {\n      webVitalsPayload['[Amplitude] INP'] = processMetric(metric);\n    });\n\n    onCLS((metric) => {\n      webVitalsPayload['[Amplitude] CLS'] = processMetric(metric);\n    });\n\n    onTTFB((metric) => {\n      webVitalsPayload['[Amplitude] TTFB'] = processMetric(metric);\n    });\n\n    visibilityListener = () => {\n      if (doc.visibilityState === 'hidden' && visibilityListener) {\n        amplitude.track(WEB_VITALS_EVENT_NAME, webVitalsPayload);\n        doc.removeEventListener('visibilitychange', visibilityListener);\n        visibilityListener = null;\n      }\n    };\n    doc.addEventListener('visibilitychange', visibilityListener);\n  };\n\n  const execute: BrowserEnrichmentPlugin['execute'] = async (event) => {\n    return event;\n  };\n\n  const teardown = async () => {\n    if (visibilityListener) {\n      /* istanbul ignore next */\n      doc?.removeEventListener('visibilitychange', visibilityListener);\n    }\n  };\n\n  return {\n    name: PLUGIN_NAME,\n    type: 'enrichment',\n    setup,\n    execute,\n    teardown,\n  };\n};\n"
  },
  {
    "path": "packages/plugin-web-vitals-browser/test/web-vitals-plugin.test.ts",
    "content": "import { BrowserClient, getGlobalScope } from '@amplitude/analytics-core';\nimport { onLCP, onINP, onCLS, onFCP, onTTFB } from 'web-vitals';\nimport { webVitalsPlugin } from '../src';\nimport { PLUGIN_NAME, WEB_VITALS_EVENT_NAME } from '../src/constants';\n\n/* eslint-disable @typescript-eslint/unbound-method, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call */\n\n// Mock web-vitals\njest.mock('web-vitals', () => ({\n  onLCP: jest.fn(),\n  onINP: jest.fn(),\n  onCLS: jest.fn(),\n  onFCP: jest.fn(),\n  onTTFB: jest.fn(),\n}));\n\n// Mock getGlobalScope\njest.mock('@amplitude/analytics-core', () => ({\n  ...jest.requireActual('@amplitude/analytics-core'),\n  getGlobalScope: jest.fn(),\n}));\n\ndescribe('webVitalsPlugin', () => {\n  let amplitude: BrowserClient;\n  let config: any;\n  let mockDocument: Document;\n  let mockPerformance: Performance;\n  let mockGlobalScope: typeof globalThis;\n\n  beforeEach(() => {\n    // Reset all mocks\n    jest.clearAllMocks();\n\n    // Mock document and performance\n    mockDocument = {\n      addEventListener: jest.fn(),\n      removeEventListener: jest.fn(),\n      visibilityState: 'visible',\n    } as unknown as Document;\n\n    mockPerformance = {\n      timeOrigin: 1000,\n    } as unknown as Performance;\n\n    // Mock global scope with document\n    mockGlobalScope = {\n      document: mockDocument,\n      performance: mockPerformance,\n      location: {\n        href: 'https://www.example.com/path/to?query=value#hash',\n      },\n    } as unknown as typeof globalThis;\n\n    // Mock getGlobalScope function to return our mock global scope\n    (getGlobalScope as jest.Mock).mockReturnValue(mockGlobalScope);\n\n    // Setup amplitude mock\n    amplitude = {\n      track: jest.fn(),\n    } as unknown as BrowserClient;\n\n    config = {\n      loggerProvider: {\n        log: jest.fn(),\n      },\n    };\n  });\n\n  it('should be defined', () => {\n    expect(webVitalsPlugin).toBeDefined();\n  });\n\n  it('should have the correct name and type', () => {\n    const plugin = webVitalsPlugin();\n    expect(plugin.name).toBe(PLUGIN_NAME);\n    expect(plugin.type).toBe('enrichment');\n  });\n\n  it('should not setup if document is not available', async () => {\n    // Mock getGlobalScope to return an object without document\n    (getGlobalScope as jest.Mock).mockReturnValue({});\n    const plugin = webVitalsPlugin();\n    await plugin?.setup?.(config, amplitude);\n    expect(onLCP).not.toHaveBeenCalled();\n    expect(onFCP).not.toHaveBeenCalled();\n    expect(onINP).not.toHaveBeenCalled();\n    expect(onCLS).not.toHaveBeenCalled();\n    expect(onTTFB).not.toHaveBeenCalled();\n  });\n\n  it('should not setup if globalScope is not available', async () => {\n    // Mock getGlobalScope to return undefined\n    (getGlobalScope as jest.Mock).mockReturnValue(undefined);\n    const plugin = webVitalsPlugin();\n    await plugin?.setup?.(config, amplitude);\n\n    // Verify getGlobalScope was called and returned undefined\n    expect(getGlobalScope).toHaveBeenCalled();\n    expect(getGlobalScope()).toBeUndefined();\n\n    // Verify no web vitals listeners were set up\n    expect(onLCP).not.toHaveBeenCalled();\n    expect(onFCP).not.toHaveBeenCalled();\n    expect(onINP).not.toHaveBeenCalled();\n    expect(onCLS).not.toHaveBeenCalled();\n    expect(onTTFB).not.toHaveBeenCalled();\n  });\n\n  it('should setup web vitals listeners', async () => {\n    const plugin = webVitalsPlugin();\n    await plugin?.setup?.(config, amplitude);\n\n    // Verify getGlobalScope was called and returned our mock document\n    expect(getGlobalScope).toHaveBeenCalled();\n    expect(getGlobalScope()).toBe(mockGlobalScope);\n    expect(getGlobalScope()?.document).toBe(mockDocument);\n\n    expect(onLCP).toHaveBeenCalled();\n    expect(onFCP).toHaveBeenCalled();\n    expect(onINP).toHaveBeenCalled();\n    expect(onCLS).toHaveBeenCalled();\n    expect(onTTFB).toHaveBeenCalled();\n    expect(mockDocument.addEventListener).toHaveBeenCalledWith('visibilitychange', expect.any(Function));\n  });\n\n  it('should track web vitals when visibility changes to hidden', async () => {\n    const plugin = webVitalsPlugin();\n    await plugin?.setup?.(config, amplitude);\n\n    // Get the visibility change listener\n    const visibilityListener = (mockDocument.addEventListener as jest.Mock).mock.calls[0][1];\n\n    // Mock web vitals callbacks\n    const mockMetric = {\n      value: 100,\n      rating: 'good',\n      delta: 0,\n      navigationType: 'navigate',\n      id: 'test-id',\n      entries: [{ startTime: 0 }],\n    };\n\n    // Simulate web vitals being collected\n    const lcpCallback = (onLCP as jest.Mock).mock.calls[0][0];\n    const fcpCallback = (onFCP as jest.Mock).mock.calls[0][0];\n    const inpCallback = (onINP as jest.Mock).mock.calls[0][0];\n    const clsCallback = (onCLS as jest.Mock).mock.calls[0][0];\n    const ttfbCallback = (onTTFB as jest.Mock).mock.calls[0][0];\n\n    if (lcpCallback && fcpCallback && inpCallback && clsCallback && ttfbCallback) {\n      lcpCallback(mockMetric);\n      fcpCallback(mockMetric);\n      inpCallback(mockMetric);\n      clsCallback(mockMetric);\n      ttfbCallback(mockMetric);\n    }\n\n    // Change visibility to hidden\n    Object.defineProperty(mockDocument, 'visibilityState', { value: 'hidden' });\n    visibilityListener();\n\n    // Verify track was called with correct payload\n    const [eventName, eventObject] = (amplitude.track as jest.Mock).mock.calls[0];\n    expect(eventName).toBe(WEB_VITALS_EVENT_NAME);\n    const expectedMetric = {\n      value: 100,\n      rating: 'good',\n      delta: 0,\n      navigationType: 'navigate',\n      id: 'test-id',\n      timestamp: expect.any(Number),\n      navigationStart: expect.any(Number),\n    };\n    expect(eventObject['[Amplitude] LCP']).toMatchObject(expectedMetric);\n    expect(eventObject['[Amplitude] FCP']).toMatchObject(expectedMetric);\n    expect(eventObject['[Amplitude] INP']).toMatchObject(expectedMetric);\n    expect(eventObject['[Amplitude] CLS']).toMatchObject(expectedMetric);\n    expect(eventObject['[Amplitude] TTFB']).toMatchObject(expectedMetric);\n  });\n\n  it('should cleanup event listeners on teardown', async () => {\n    const plugin = webVitalsPlugin();\n    await plugin?.setup?.(config, amplitude);\n    await plugin?.teardown?.();\n\n    expect(mockDocument.removeEventListener).toHaveBeenCalledWith('visibilitychange', expect.any(Function));\n  });\n\n  it('should pass through events in execute', async () => {\n    const plugin = webVitalsPlugin();\n    const event = { event_type: 'test' };\n    const result = await plugin?.execute?.(event);\n    expect(result).toBe(event);\n  });\n});\n"
  },
  {
    "path": "packages/plugin-web-vitals-browser/tsconfig.es5.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/cjs\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-web-vitals-browser/tsconfig.esm.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"es6\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/esm\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/plugin-web-vitals-browser/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src/**/*\", \"test/**/*\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"esModuleInterop\": true,\n    \"lib\": [\"dom\"],\n    \"noEmit\": true,\n    \"rootDir\": \".\"\n  }\n}\n"
  },
  {
    "path": "packages/segment-session-replay-plugin/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.0.24](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.23...@amplitude/segment-session-replay-plugin@0.0.24) (2026-05-14)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n## [0.0.23](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.22...@amplitude/segment-session-replay-plugin@0.0.23) (2026-05-11)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n## [0.0.22](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.21...@amplitude/segment-session-replay-plugin@0.0.22) (2026-05-08)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n## [0.0.21](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.20...@amplitude/segment-session-replay-plugin@0.0.21) (2026-05-07)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n## [0.0.20](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.19...@amplitude/segment-session-replay-plugin@0.0.20) (2026-05-06)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n## [0.0.19](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.18...@amplitude/segment-session-replay-plugin@0.0.19) (2026-04-28)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n## [0.0.18](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.17...@amplitude/segment-session-replay-plugin@0.0.18) (2026-04-22)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n## [0.0.17](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.16...@amplitude/segment-session-replay-plugin@0.0.17) (2026-04-21)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n## [0.0.16](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.15...@amplitude/segment-session-replay-plugin@0.0.16) (2026-04-16)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n## [0.0.15](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.14...@amplitude/segment-session-replay-plugin@0.0.15) (2026-04-14)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n## [0.0.14](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.13...@amplitude/segment-session-replay-plugin@0.0.14) (2026-04-09)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n## [0.0.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.12...@amplitude/segment-session-replay-plugin@0.0.13) (2026-04-01)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n## [0.0.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.11...@amplitude/segment-session-replay-plugin@0.0.12) (2026-03-26)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n## [0.0.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.10...@amplitude/segment-session-replay-plugin@0.0.11) (2026-03-24)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n## [0.0.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.9...@amplitude/segment-session-replay-plugin@0.0.10) (2026-03-23)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n## [0.0.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.8...@amplitude/segment-session-replay-plugin@0.0.9) (2026-03-20)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n## [0.0.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.7...@amplitude/segment-session-replay-plugin@0.0.8) (2026-03-19)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n## [0.0.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.6...@amplitude/segment-session-replay-plugin@0.0.7) (2026-03-17)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n## [0.0.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.5...@amplitude/segment-session-replay-plugin@0.0.6) (2026-03-16)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n## [0.0.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.4...@amplitude/segment-session-replay-plugin@0.0.5) (2026-03-13)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n## [0.0.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.3...@amplitude/segment-session-replay-plugin@0.0.4) (2026-03-12)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n## [0.0.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.2...@amplitude/segment-session-replay-plugin@0.0.3) (2026-03-11)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n## [0.0.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.1...@amplitude/segment-session-replay-plugin@0.0.2) (2026-03-09)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n## [0.0.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.67...@amplitude/segment-session-replay-plugin@0.0.1) (2026-03-06)\n\n\n### Bug Fixes\n\n* **session-replay:** guarantee in-order batch delivery including retries ([#1576](https://github.com/amplitude/Amplitude-TypeScript/issues/1576)) ([0afcac6](https://github.com/amplitude/Amplitude-TypeScript/commit/0afcac6cd42b999b74ba797717f7cf0d447029ef))\n\n\n\n\n\n# [0.0.0-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.67...@amplitude/segment-session-replay-plugin@0.0.0-beta.0) (2026-03-06)\n\n\n### Bug Fixes\n\n* **session-replay:** guarantee in-order batch delivery including retries ([#1576](https://github.com/amplitude/Amplitude-TypeScript/issues/1576)) ([0afcac6](https://github.com/amplitude/Amplitude-TypeScript/commit/0afcac6cd42b999b74ba797717f7cf0d447029ef))\n\n\n\n\n\n# [0.0.0-in-order.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.67...@amplitude/segment-session-replay-plugin@0.0.0-in-order.0) (2026-03-06)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.67](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.66...@amplitude/segment-session-replay-plugin@0.0.0-beta.67) (2026-03-05)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.66](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.65...@amplitude/segment-session-replay-plugin@0.0.0-beta.66) (2026-03-03)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.65](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.64...@amplitude/segment-session-replay-plugin@0.0.0-beta.65) (2026-03-03)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.64](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.63...@amplitude/segment-session-replay-plugin@0.0.0-beta.64) (2026-02-26)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.63](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.62...@amplitude/segment-session-replay-plugin@0.0.0-beta.63) (2026-02-24)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.62](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.61...@amplitude/segment-session-replay-plugin@0.0.0-beta.62) (2026-02-19)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.61](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.60...@amplitude/segment-session-replay-plugin@0.0.0-beta.61) (2026-02-17)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.60](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.59...@amplitude/segment-session-replay-plugin@0.0.0-beta.60) (2026-02-10)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.59](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.58...@amplitude/segment-session-replay-plugin@0.0.0-beta.59) (2026-01-26)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.58](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.57...@amplitude/segment-session-replay-plugin@0.0.0-beta.58) (2026-01-21)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.57](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.56...@amplitude/segment-session-replay-plugin@0.0.0-beta.57) (2026-01-15)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.56](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.55...@amplitude/segment-session-replay-plugin@0.0.0-beta.56) (2026-01-14)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.55](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.54...@amplitude/segment-session-replay-plugin@0.0.0-beta.55) (2026-01-14)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.54](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.53...@amplitude/segment-session-replay-plugin@0.0.0-beta.54) (2025-12-24)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.53](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.52...@amplitude/segment-session-replay-plugin@0.0.0-beta.53) (2025-12-22)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.52](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.51...@amplitude/segment-session-replay-plugin@0.0.0-beta.52) (2025-12-16)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.51](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.50...@amplitude/segment-session-replay-plugin@0.0.0-beta.51) (2025-12-09)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.50](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.49...@amplitude/segment-session-replay-plugin@0.0.0-beta.50) (2025-12-05)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.49](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.48...@amplitude/segment-session-replay-plugin@0.0.0-beta.49) (2025-11-21)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.48](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.47...@amplitude/segment-session-replay-plugin@0.0.0-beta.48) (2025-11-20)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.47](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.46...@amplitude/segment-session-replay-plugin@0.0.0-beta.47) (2025-11-17)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.46](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.45...@amplitude/segment-session-replay-plugin@0.0.0-beta.46) (2025-11-17)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.45](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.44...@amplitude/segment-session-replay-plugin@0.0.0-beta.45) (2025-11-05)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.44](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.43...@amplitude/segment-session-replay-plugin@0.0.0-beta.44) (2025-10-29)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.43](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.42...@amplitude/segment-session-replay-plugin@0.0.0-beta.43) (2025-10-23)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.42](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.41...@amplitude/segment-session-replay-plugin@0.0.0-beta.42) (2025-10-23)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.41](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.40...@amplitude/segment-session-replay-plugin@0.0.0-beta.41) (2025-10-21)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.40](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.39...@amplitude/segment-session-replay-plugin@0.0.0-beta.40) (2025-10-17)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.39](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.38...@amplitude/segment-session-replay-plugin@0.0.0-beta.39) (2025-10-15)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.38](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.37...@amplitude/segment-session-replay-plugin@0.0.0-beta.38) (2025-10-14)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.37](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.36...@amplitude/segment-session-replay-plugin@0.0.0-beta.37) (2025-10-14)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.36](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.35...@amplitude/segment-session-replay-plugin@0.0.0-beta.36) (2025-10-07)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.35](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.34...@amplitude/segment-session-replay-plugin@0.0.0-beta.35) (2025-10-03)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.34](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.33...@amplitude/segment-session-replay-plugin@0.0.0-beta.34) (2025-10-01)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.33](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.32...@amplitude/segment-session-replay-plugin@0.0.0-beta.33) (2025-09-25)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.32](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.31...@amplitude/segment-session-replay-plugin@0.0.0-beta.32) (2025-09-25)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.31](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.30...@amplitude/segment-session-replay-plugin@0.0.0-beta.31) (2025-09-23)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.30](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.29...@amplitude/segment-session-replay-plugin@0.0.0-beta.30) (2025-09-18)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.29](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.28...@amplitude/segment-session-replay-plugin@0.0.0-beta.29) (2025-09-12)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.28](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.27...@amplitude/segment-session-replay-plugin@0.0.0-beta.28) (2025-09-05)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.27](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.26...@amplitude/segment-session-replay-plugin@0.0.0-beta.27) (2025-08-28)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.26](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.25...@amplitude/segment-session-replay-plugin@0.0.0-beta.26) (2025-08-26)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.25](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.24...@amplitude/segment-session-replay-plugin@0.0.0-beta.25) (2025-08-25)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.24](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.23...@amplitude/segment-session-replay-plugin@0.0.0-beta.24) (2025-08-22)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.23](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.22...@amplitude/segment-session-replay-plugin@0.0.0-beta.23) (2025-08-21)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.22](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.21...@amplitude/segment-session-replay-plugin@0.0.0-beta.22) (2025-08-13)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.21](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.20...@amplitude/segment-session-replay-plugin@0.0.0-beta.21) (2025-08-08)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.20](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.19...@amplitude/segment-session-replay-plugin@0.0.0-beta.20) (2025-08-05)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.19](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.18...@amplitude/segment-session-replay-plugin@0.0.0-beta.19) (2025-07-29)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.18](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.17...@amplitude/segment-session-replay-plugin@0.0.0-beta.18) (2025-07-17)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.17](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.16...@amplitude/segment-session-replay-plugin@0.0.0-beta.17) (2025-07-15)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.16](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.15...@amplitude/segment-session-replay-plugin@0.0.0-beta.16) (2025-07-11)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.15](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.14...@amplitude/segment-session-replay-plugin@0.0.0-beta.15) (2025-07-08)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.14](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.13...@amplitude/segment-session-replay-plugin@0.0.0-beta.14) (2025-06-30)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.12...@amplitude/segment-session-replay-plugin@0.0.0-beta.13) (2025-06-26)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.11...@amplitude/segment-session-replay-plugin@0.0.0-beta.12) (2025-06-25)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.10...@amplitude/segment-session-replay-plugin@0.0.0-beta.11) (2025-06-17)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.9...@amplitude/segment-session-replay-plugin@0.0.0-beta.10) (2025-06-17)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.8...@amplitude/segment-session-replay-plugin@0.0.0-beta.9) (2025-06-13)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.7...@amplitude/segment-session-replay-plugin@0.0.0-beta.8) (2025-06-12)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.6...@amplitude/segment-session-replay-plugin@0.0.0-beta.7) (2025-06-11)\n\n\n### Bug Fixes\n\n* **session replay:** add gzip to cdn ([#1150](https://github.com/amplitude/Amplitude-TypeScript/issues/1150)) ([f61e38f](https://github.com/amplitude/Amplitude-TypeScript/commit/f61e38fc37d9a825a0c3f31147631eb1a16546a4))\n\n\n\n\n\n# [0.0.0-beta.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.5...@amplitude/segment-session-replay-plugin@0.0.0-beta.6) (2025-06-03)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.4...@amplitude/segment-session-replay-plugin@0.0.0-beta.5) (2025-06-02)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.3...@amplitude/segment-session-replay-plugin@0.0.0-beta.4) (2025-05-30)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.2...@amplitude/segment-session-replay-plugin@0.0.0-beta.3) (2025-05-27)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n\n\n\n\n\n# [0.0.0-beta.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/segment-session-replay-plugin@0.0.0-beta.1...@amplitude/segment-session-replay-plugin@0.0.0-beta.2) (2025-05-15)\n\n\n### Bug Fixes\n\n* **docs:** correct installation command syntax in README for segment-session-replay-plugin ([#1085](https://github.com/amplitude/Amplitude-TypeScript/issues/1085)) ([f675577](https://github.com/amplitude/Amplitude-TypeScript/commit/f675577d55d4c21a9e3a8f309ab97089f50a04f6))\n\n\n\n\n\n# 0.0.0-beta.1 (2025-05-14)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin\n"
  },
  {
    "path": "packages/segment-session-replay-plugin/README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://amplitude.com\" target=\"_blank\" align=\"center\">\n    <img src=\"https://static.amplitude.com/lightning/46c85bfd91905de8047f1ee65c7c93d6fa9ee6ea/static/media/amplitude-logo-with-text.4fb9e463.svg\" width=\"280\">\n  </a>\n  <br />\n</p>\n\n# @amplitude/segment-session-replay-plugin\n\nThis package is a wrapper to facilitate integration between Segment and [Amplitude's Session Replay SDK](https://amplitude.com/docs/session-replay/session-replay-standalone-sdk). This package currently only supports the [Segment Amplitude (Actions) destination](https://segment.com/docs/connections/destinations/catalog/actions-amplitude/).\n\n## Installation\n\nThis package is published on NPM registry and is available to be installed using `npm` and `yarn`. Amplitude's Session\nReplay SDK is included in this package, and does not need to be installed separately.\n\n```sh\n# npm\nnpm install @amplitude/segment-session-replay-plugin --save\n\n# yarn\nyarn add @amplitude/segment-session-replay-plugin\n```\n\n## Usage\n\n```typescript\nimport { AnalyticsBrowser } from '@segment/analytics-next';\nimport { createSegmentActionsPlugin } from '@amplitude/segment-session-replay-plugin';\n\nexport const SegmentAnalytics = AnalyticsBrowser.load({\n  writeKey: SEGMENT_API_KEY,\n});\n\ncreateSegmentActionsPlugin({\n    segmentInstance: SegmentAnalytics,\n    amplitudeApiKey: AMPLITUDE_API_KEY,\n    sessionReplayOptions: {\n        logLevel: 4,\n        sampleRate: 1,\n        debugMode: true,\n    },\n    enableWrapperDebug: true,\n});\n\nSegmentAnalytics.track(\"Immediate Event\");\n```\n\nThe `sessionReplayOptions` parameter properties match those documented for the [Session Replay Standalone SDK](https://amplitude.com/docs/session-replay/session-replay-standalone-sdk#configuration).\n\n## Segment Plugin Architecture\n\nThis wrapper makes use of Segment's plugin architecture, which ensures that all `track` and `page` events are decorated\nwith the Session Replay ID event property.\n\n## User ID to Device ID mapping\n\nFollowing Segment's documentation, the wrapper maps the Segment user id to the Amplitude device id. To determine the device id for session replay captures, the wrapper uses the `anonymousId` unless `sessionReplayOptions.deviceId` is provided.\n"
  },
  {
    "path": "packages/segment-session-replay-plugin/jest.config.js",
    "content": "const baseConfig = require('../../jest.config.js');\nconst package = require('./package');\n\nmodule.exports = {\n  ...baseConfig,\n  displayName: package.name,\n  rootDir: '.',\n  testEnvironment: 'jsdom',\n  coveragePathIgnorePatterns: ['index.ts'],\n};\n"
  },
  {
    "path": "packages/segment-session-replay-plugin/package.json",
    "content": "{\n  \"name\": \"@amplitude/segment-session-replay-plugin\",\n  \"version\": \"0.0.24\",\n  \"description\": \"Plugin for Segment's analytics.js library to support Amplitude's Session Replay.\",\n  \"keywords\": [\n    \"amplitude\",\n    \"analytics\",\n    \"session replay\",\n    \"segment\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/amplitude/Amplitude-TypeScript.git\"\n  },\n  \"author\": \"Amplitude Inc\",\n  \"license\": \"MIT\",\n  \"main\": \"lib/cjs/index.js\",\n  \"module\": \"lib/esm/index.js\",\n  \"types\": \"lib/esm/index.d.ts\",\n  \"sideEffects\": false,\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/amplitude/Amplitude-TypeScript/issues\"\n  },\n  \"files\": [\n    \"lib\"\n  ],\n  \"scripts\": {\n    \"build\": \"pnpm bundle && pnpm build:es5 && pnpm build:esm\",\n    \"bundle\": \"rollup --config rollup.config.js\",\n    \"build:es5\": \"tsc -p ./tsconfig.es5.json\",\n    \"build:esm\": \"tsc -p ./tsconfig.esm.json\",\n    \"watch\": \"tsc -p ./tsconfig.esm.json --watch\",\n    \"clean\": \"rimraf node_modules lib coverage\",\n    \"fix\": \"pnpm fix:eslint & pnpm fix:prettier\",\n    \"fix:eslint\": \"eslint '{src,test}/**/*.ts' --fix\",\n    \"fix:prettier\": \"prettier --write \\\"{src,test}/**/*.ts\\\"\",\n    \"lint\": \"pnpm lint:eslint & pnpm lint:prettier\",\n    \"lint:eslint\": \"eslint '{src,test}/**/*.ts'\",\n    \"lint:prettier\": \"prettier --check \\\"{src,test}/**/*.ts\\\"\",\n    \"publish\": \"node ./scripts/publish/upload-to-s3.js\",\n    \"test\": \"jest\",\n    \"typecheck\": \"tsc -p ./tsconfig.json\",\n    \"version\": \"pnpm version-file && GENERATE_SNIPPET=true pnpm build\",\n    \"version-file\": \"echo '// Autogenerated by `pnpm version-file`. DO NOT EDIT' > src/version.ts && node -p \\\"'export const VERSION = \\\\'' + require('./package.json').version + '\\\\';'\\\" >> src/version.ts\"\n  },\n  \"dependencies\": {\n    \"@amplitude/session-replay-browser\": \"workspace:*\",\n    \"@segment/analytics-next\": \"^1.81.0\",\n    \"js-cookie\": \"^3.0.5\"\n  },\n  \"devDependencies\": {\n    \"@aws-sdk/client-s3\": \"^3.229.0\",\n    \"@rollup/plugin-commonjs\": \"^23.0.4\",\n    \"@rollup/plugin-node-resolve\": \"^15.0.1\",\n    \"@rollup/plugin-typescript\": \"^10.0.1\",\n    \"@types/js-cookie\": \"^3.0.6\",\n    \"rollup\": \"^2.79.1\",\n    \"rollup-plugin-execute\": \"^1.1.1\",\n    \"rollup-plugin-gzip\": \"^3.1.0\",\n    \"rollup-plugin-terser\": \"^7.0.2\"\n  }\n}\n"
  },
  {
    "path": "packages/segment-session-replay-plugin/rollup.config.js",
    "content": "import commonjs from '@rollup/plugin-commonjs';\nimport resolve from '@rollup/plugin-node-resolve';\nimport typescript from '@rollup/plugin-typescript';\nimport gzip from 'rollup-plugin-gzip';\nimport { terser } from 'rollup-plugin-terser';\n\n// Configure ESM build\nconst esm = {\n  input: 'src/index.ts',\n  output: {\n    dir: 'lib/scripts',\n    format: 'es',\n    sourcemap: true,\n    entryFileNames: 'segment-session-replay-wrapper-esm.js',\n    chunkFileNames: '[name]-min.js',\n  },\n  plugins: [\n    typescript({\n      tsconfig: 'tsconfig.json',\n      compilerOptions: {\n        target: 'es2015',\n        module: 'es2020',\n        moduleResolution: 'node',\n        downlevelIteration: true,\n        declaration: false,\n        declarationMap: false,\n        outDir: 'lib/scripts',\n        baseUrl: '.',\n        paths: {\n          'src/*': ['src/*'],\n        },\n      },\n    }),\n    resolve({\n      browser: true,\n    }),\n    commonjs(),\n    terser({\n      output: {\n        comments: false,\n      },\n    }),\n    gzip(),\n  ],\n};\n\nexport default [esm];\n"
  },
  {
    "path": "packages/segment-session-replay-plugin/scripts/publish/upload-to-s3.js",
    "content": "const fs = require('fs');\nconst path = require('path');\nconst { S3Client, PutObjectCommand, HeadObjectCommand } = require('@aws-sdk/client-s3');\nconst { getName, getVersion } = require('../../../../scripts/utils');\n\nconst bucket = process.env.S3_BUCKET_NAME;\nconst location = path.join(process.cwd(), 'lib', 'scripts');\nconst files = [\n  'segment-session-replay-wrapper-esm.js.gz', // ESM version\n];\n\nlet deployedCount = 0;\n\nconsole.log('[Publish Segment Session Replay Wrapper to AWS S3] START');\nconst promises = files.map((file) => {\n  const body = fs.readFileSync(path.join(location, file));\n  const key = `libs/${file.replace('segment-session-replay-wrapper', `${getName()}-${getVersion()}`)}`;\n  const client = new S3Client();\n\n  const headObject = new HeadObjectCommand({\n    Bucket: bucket,\n    Key: key,\n  });\n  console.log(`[Publish to AWS S3] Checking if ${key} exists in target bucket...`);\n  return client\n    .send(headObject)\n    .then(() => {\n      console.log(`[Publish to AWS S3] ${key} exists in target bucket. Skipping upload job.`);\n    })\n    .catch(() => {\n      console.log(`[Publish to AWS S3] ${key} does not exist in target bucket. Uploading to S3...`);\n      const putObject = new PutObjectCommand({\n        ACL: 'public-read',\n        Body: body,\n        Bucket: bucket,\n        CacheControl: 'max-age=31536000',\n        ContentType: 'application/javascript',\n        ContentEncoding: 'gzip',\n        Key: key,\n      });\n      return client\n        .send(putObject)\n        .then(() => {\n          console.log(`[Publish to AWS S3] Upload success for ${key}.`);\n          deployedCount += 1;\n        })\n        .catch(console.error);\n    });\n});\n\nPromise.all(promises)\n  .then(() => {\n    if (deployedCount === 0) {\n      console.log(`[Publish to AWS S3] Complete! Nothing to deploy.`);\n    } else {\n      console.log(`[Publish to AWS S3] Success! Deployed ${deployedCount}/${files.length} files.`);\n    }\n    console.log('[Publish to AWS S3] END');\n  })\n  .catch(console.log);\n"
  },
  {
    "path": "packages/segment-session-replay-plugin/src/constants.ts",
    "content": "export const COOKIE_NAME = 'amp_session_id';\nexport const DEBUG_LOG_PREFIX = 'Amplitude Session Replay Segment Plugin [Debug]:';\nexport const INITIAL_EVENT_NAME = 'Immediate Event';\nexport const PLUGIN_NAME = 'Session Replay Events';\nexport const PLUGIN_TYPE = 'enrichment'; // https://github.com/segmentio/analytics-next/blob/c45d445/packages/core/src/plugins/index.ts#L11\n"
  },
  {
    "path": "packages/segment-session-replay-plugin/src/helpers.ts",
    "content": "import * as sessionReplay from '@amplitude/session-replay-browser';\nimport { Context } from '@segment/analytics-next';\nimport Cookie from 'js-cookie';\nimport { COOKIE_NAME } from './constants';\nimport { AmplitudeIntegrationData } from './typings/wrapper';\n\nexport const getSessionId = (): number | undefined => {\n  // First try to get the sessionId from the Session Replay SDK\n  // If that fails, try to get the sessionId from the persistent storage\n  const sessionId: string | number | undefined = sessionReplay.getSessionId() || Cookie.get(COOKIE_NAME);\n  if (sessionId) {\n    const result = parseInt(sessionId.toString(), 10);\n    if (isNaN(result)) {\n      return undefined;\n    }\n    return result;\n  }\n\n  // If sessionId is not found in either the Session Replay SDK nor persistent storage, return undefined\n  return undefined;\n};\n\nexport const setSessionId = (sessionId: number, deviceId: string | undefined): Promise<void> => {\n  // Set the sessionId in the persistent storage\n  Cookie.set(COOKIE_NAME, sessionId.toString());\n\n  // Set the sessionId in the Session Replay SDK\n  return sessionReplay.setSessionId(sessionId, deviceId).promise;\n};\n\nexport const updateSessionIdAndAddProperties = async (ctx: Context, deviceId: string | undefined): Promise<Context> => {\n  // Get the current session id or default to 0 if it does not exist\n  const sessionId: number = getSessionId() || 0;\n\n  // Get the next session id from the event, if it exists\n  let nextSessionId: number | undefined;\n  if (ctx.event.integrations && (ctx.event.integrations['Actions Amplitude'] as AmplitudeIntegrationData)) {\n    nextSessionId = (ctx.event.integrations['Actions Amplitude'] as AmplitudeIntegrationData).session_id;\n  }\n\n  // Update the session id if it is new\n  if (nextSessionId && sessionId < nextSessionId) {\n    await setSessionId(nextSessionId, deviceId);\n  }\n\n  // Enrich the event with the session replay properties\n  // NOTE: This is what will add the `[Amplitude] Session Replay ID` attribute to the event\n  const sessionReplayProperties = sessionReplay.getSessionReplayProperties();\n  const properties = {\n    ...sessionReplayProperties,\n    ...ctx.event.properties,\n  };\n\n  ctx.updateEvent('properties', properties);\n\n  return ctx;\n};\n"
  },
  {
    "path": "packages/segment-session-replay-plugin/src/index.ts",
    "content": "import * as sessionReplay from '@amplitude/session-replay-browser';\nimport { Analytics, Context, Plugin, User } from '@segment/analytics-next';\n\nimport { DEBUG_LOG_PREFIX, PLUGIN_NAME, PLUGIN_TYPE } from './constants';\nimport { getSessionId, setSessionId, updateSessionIdAndAddProperties } from './helpers';\nimport { PluginOptions } from './typings/wrapper';\nimport { VERSION } from './version';\n\nexport const createSegmentActionsPlugin = async ({\n  amplitudeApiKey,\n  sessionReplayOptions,\n  segmentInstance,\n  enableWrapperDebug = false,\n}: PluginOptions): Promise<void> => {\n  let initPromise: Promise<void>;\n  let isInitialized = false;\n  let deviceId: string | undefined = sessionReplayOptions?.deviceId;\n\n  const _plugin: Plugin = {\n    name: PLUGIN_NAME,\n    type: PLUGIN_TYPE,\n    version: VERSION,\n\n    isLoaded: (): boolean => isInitialized,\n\n    load: async (_ctx: Context, ajs: Analytics): Promise<void> => {\n      // If the deviceId is not provided via the plugin parameters,\n      // default to use the anonymousId from the user\n      if (!deviceId) {\n        const user: User = ajs.user();\n        deviceId = user.anonymousId() || undefined;\n      }\n\n      const sessionId: number | undefined = getSessionId();\n\n      // Initialize the session replay plugin\n      enableWrapperDebug &&\n        console.log(\n          `${DEBUG_LOG_PREFIX} initializing session replay with sessionId=${sessionId ?? 'undefined'} and deviceId=${\n            deviceId ?? 'undefined'\n          }`,\n        );\n\n      initPromise = sessionReplay.init(amplitudeApiKey, {\n        ...sessionReplayOptions,\n        sessionId,\n        deviceId: deviceId || undefined,\n        version: { type: 'segment', version: VERSION },\n      }).promise;\n\n      await initPromise;\n      isInitialized = true;\n    },\n\n    track: async (ctx: Context): Promise<Context> => {\n      await initPromise;\n      return await updateSessionIdAndAddProperties(ctx, deviceId);\n    },\n\n    page: async (ctx: Context): Promise<Context> => {\n      await initPromise;\n      return await updateSessionIdAndAddProperties(ctx, deviceId);\n    },\n\n    identify: async (ctx: Context): Promise<Context> => {\n      await initPromise;\n\n      const sessionId: number | undefined = getSessionId();\n\n      if (sessionId) {\n        enableWrapperDebug &&\n          console.log(\n            `${DEBUG_LOG_PREFIX} calling setSessionId() with sessionId=${sessionId} and deviceId=${\n              deviceId ?? 'undefined'\n            }`,\n          );\n        await setSessionId(sessionId, deviceId);\n      }\n\n      return ctx;\n    },\n  };\n\n  await segmentInstance.register(_plugin);\n};\n"
  },
  {
    "path": "packages/segment-session-replay-plugin/src/typings/wrapper.ts",
    "content": "import { SessionReplayOptions } from '@amplitude/session-replay-browser';\nimport { AnalyticsBrowser } from '@segment/analytics-next';\n\nexport interface PluginOptions {\n  segmentInstance: AnalyticsBrowser;\n  amplitudeApiKey: string;\n  sessionReplayOptions?: SessionReplayOptions;\n  enableWrapperDebug?: boolean;\n}\n\nexport type AmplitudeIntegrationData = {\n  // https://github.com/segmentio/analytics-next/blob/3f15dfae034d101fb1847bc7228c0354b414d68a/packages/browser-integration-tests/src/index.test.ts#L64-L66\n  session_id: number;\n};\n"
  },
  {
    "path": "packages/segment-session-replay-plugin/src/version.ts",
    "content": "// Autogenerated by `pnpm version-file`. DO NOT EDIT\nexport const VERSION = '0.0.24';\n"
  },
  {
    "path": "packages/segment-session-replay-plugin/test/helpers.test.ts",
    "content": "import { getSessionId, setSessionId, updateSessionIdAndAddProperties } from '../src/helpers';\nimport Cookie from 'js-cookie';\nimport * as sessionReplay from '@amplitude/session-replay-browser';\nimport { COOKIE_NAME } from '../src/constants';\nimport { Context } from '@segment/analytics-next';\nimport * as helpers from '../src/helpers';\n\njest.mock('@amplitude/session-replay-browser');\njest.mock('js-cookie');\n\ndescribe('getSessionId()', () => {\n  beforeEach(() => {\n    jest.clearAllMocks();\n  });\n\n  it.each([\n    // When the SDK returns a sessionId, return that sessionId even if the cookie returns a different sessionId\n    {\n      sessionReplaySdkSessionId: 1,\n      cookieSessionId: '2',\n      expectedReturn: 1,\n      expectedSdkCalls: 1,\n      expectedCookieCalls: 0,\n    },\n    // When the SDK returns undefined, fall back to fetching the sessionId from the cookie\n    {\n      sessionReplaySdkSessionId: undefined,\n      cookieSessionId: '2',\n      expectedReturn: 2,\n      expectedSdkCalls: 1,\n      expectedCookieCalls: 1,\n    },\n    // When the SDK returns undefined and the cookie returns undefined, return undefined\n    {\n      sessionReplaySdkSessionId: undefined,\n      cookieSessionId: undefined,\n      expectedReturn: undefined,\n      expectedSdkCalls: 1,\n      expectedCookieCalls: 1,\n    },\n    // When the SDK returns a non-number sessionId, return undefined\n    {\n      sessionReplaySdkSessionId: 'not a number',\n      cookieSessionId: '2',\n      expectedReturn: undefined,\n      expectedSdkCalls: 1,\n      expectedCookieCalls: 0,\n    },\n    // When the cookie returns a non-number sessionId, return undefined\n    {\n      sessionReplaySdkSessionId: undefined,\n      cookieSessionId: 'not a number',\n      expectedReturn: undefined,\n      expectedSdkCalls: 1,\n      expectedCookieCalls: 1,\n    },\n  ])(\n    'should return $expectedReturn when the SDK returns $sessionReplaySdkSessionId and the stored sessionId returns $cookieSessionId',\n    ({ sessionReplaySdkSessionId, cookieSessionId, expectedReturn, expectedSdkCalls, expectedCookieCalls }) => {\n      // Arrange\n      const cookieGetMock = jest.fn().mockReturnValue(cookieSessionId);\n      (Cookie.get as jest.Mock) = cookieGetMock;\n      (sessionReplay.getSessionId as jest.Mock).mockReturnValue(sessionReplaySdkSessionId);\n\n      // Act\n      const result = getSessionId();\n\n      // Assert\n      expect(cookieGetMock).toHaveBeenCalledTimes(expectedCookieCalls);\n      expect(sessionReplay.getSessionId).toHaveBeenCalledTimes(expectedSdkCalls);\n      expect(result).toEqual(expectedReturn);\n    },\n  );\n});\n\ndescribe('setSessionId()', () => {\n  beforeEach(() => {\n    jest.clearAllMocks();\n  });\n\n  it.each([\n    {\n      sessionId: 1,\n      deviceId: 'deviceId',\n    },\n    {\n      sessionId: 1,\n      deviceId: undefined,\n    },\n  ])(\n    'should set the sessionId in the Session Replay SDK and store the sessionId in the cookie',\n    async ({ sessionId, deviceId }) => {\n      // Arrange\n      const cookieSetMock = jest.fn().mockReturnValue(sessionId);\n      (Cookie.set as jest.Mock) = cookieSetMock;\n      (sessionReplay.setSessionId as jest.Mock).mockResolvedValue(sessionId);\n\n      // Act\n      await setSessionId(sessionId, deviceId);\n\n      // Assert\n      expect(cookieSetMock).toHaveBeenCalledTimes(1);\n      expect(cookieSetMock).toHaveBeenCalledWith(COOKIE_NAME, sessionId.toString());\n\n      expect(sessionReplay.setSessionId).toHaveBeenCalledTimes(1);\n      expect(sessionReplay.setSessionId).toHaveBeenCalledWith(sessionId, deviceId);\n    },\n  );\n});\n\ndescribe('updateSessionIdAndAddProperties()', () => {\n  let getSessionIdSpy: jest.SpyInstance;\n  let setSessionIdSpy: jest.SpyInstance;\n\n  beforeEach(() => {\n    jest.clearAllMocks();\n\n    getSessionIdSpy = jest.spyOn(helpers, 'getSessionId').mockReturnValue(undefined);\n    setSessionIdSpy = jest.spyOn(helpers, 'setSessionId').mockResolvedValue(undefined);\n  });\n\n  afterEach(() => {\n    getSessionIdSpy.mockRestore();\n    setSessionIdSpy.mockRestore();\n  });\n\n  it.each([\n    // Combine context properties and session replay properties\n    {\n      contextProperties: { 'context-property': 'context-value' },\n      sessionReplayProperties: { 'session-replay-property': 'session-replay-value' },\n      expectedProperties: { 'context-property': 'context-value', 'session-replay-property': 'session-replay-value' },\n    },\n    // Empty context properties\n    {\n      contextProperties: {},\n      sessionReplayProperties: { 'session-replay-property': 'session-replay-value' },\n      expectedProperties: { 'session-replay-property': 'session-replay-value' },\n    },\n    // Empty session replay properties\n    {\n      contextProperties: { 'context-property': 'context-value' },\n      sessionReplayProperties: {},\n      expectedProperties: { 'context-property': 'context-value' },\n    },\n    // Empty context properties and session replay properties\n    {\n      contextProperties: {},\n      sessionReplayProperties: {},\n      expectedProperties: {},\n    },\n    // Overlapping context properties and session replay properties should use the context properties\n    {\n      contextProperties: { 'test-property': 'context-value' },\n      sessionReplayProperties: { 'test-property': 'session-replay-value' },\n      expectedProperties: { 'test-property': 'context-value' },\n    },\n  ])(\n    'should call context.updateEvent() with the event properties and session replay properties',\n    async ({ contextProperties, sessionReplayProperties, expectedProperties }) => {\n      // Arrange\n      const updateEventMock = jest.fn();\n      const context = {\n        event: {\n          properties: contextProperties,\n          integrations: {\n            'Actions Amplitude': {\n              session_id: 1,\n            },\n          },\n        },\n        updateEvent: updateEventMock,\n      } as unknown as Context;\n\n      (sessionReplay.getSessionReplayProperties as jest.Mock).mockReturnValue(sessionReplayProperties);\n\n      // Act\n      await updateSessionIdAndAddProperties(context, 'deviceId');\n\n      // Assert\n      expect(updateEventMock).toHaveBeenCalledTimes(1);\n      expect(updateEventMock).toHaveBeenCalledWith('properties', expectedProperties);\n    },\n  );\n\n  it('should call setSessionId() with the Segment event.integrations.Actions Amplitude.session_id if it is greater than the current sessionId', async () => {\n    // Arrange\n    const nextSessionId = 2;\n    const currentSessionId = 1;\n\n    const updateEventMock = jest.fn();\n    const context = {\n      event: {\n        properties: {},\n        integrations: {\n          'Actions Amplitude': {\n            session_id: nextSessionId,\n          },\n        },\n      },\n      updateEvent: updateEventMock,\n    } as unknown as Context;\n\n    getSessionIdSpy.mockReturnValue(currentSessionId);\n    setSessionIdSpy.mockResolvedValue(null);\n\n    // Act\n    await updateSessionIdAndAddProperties(context, 'deviceId');\n\n    // Assert\n    expect(setSessionIdSpy).toHaveBeenCalledTimes(1);\n    expect(setSessionIdSpy).toHaveBeenCalledWith(nextSessionId, 'deviceId');\n  });\n\n  it.each([\n    {\n      description: 'if the nextSessionId is less than the current sessionId',\n      currentSessionId: 1,\n      nextSessionId: 0,\n      expectedSessionId: 1,\n      expectedCallsToSetSessionId: 0,\n    },\n    {\n      description: 'if the nextSessionId is equal to the current sessionId',\n      currentSessionId: 1,\n      nextSessionId: 1,\n      expectedSessionId: 1,\n      expectedCallsToSetSessionId: 0,\n    },\n    {\n      description: 'if the session_id is not defined in the event integrations',\n      currentSessionId: 1,\n      nextSessionId: undefined,\n      expectedSessionId: 1,\n    },\n  ])('should not call setSessionId() $description', async ({ currentSessionId, nextSessionId }) => {\n    // Arrange\n    const updateEventMock = jest.fn();\n    const context = {\n      event: {\n        properties: {},\n        integrations: {\n          'Actions Amplitude': {\n            session_id: nextSessionId,\n          },\n        },\n      },\n      updateEvent: updateEventMock,\n    } as unknown as Context;\n\n    getSessionIdSpy.mockReturnValue(currentSessionId);\n    setSessionIdSpy.mockResolvedValue(null);\n\n    // Act\n    await updateSessionIdAndAddProperties(context, 'deviceId');\n\n    // Assert\n    expect(setSessionIdSpy).toHaveBeenCalledTimes(0);\n  });\n});\n"
  },
  {
    "path": "packages/segment-session-replay-plugin/test/index.test.ts",
    "content": "import { Analytics, Context, Plugin, AnalyticsBrowser } from '@segment/analytics-next';\nimport { createSegmentActionsPlugin } from '../src';\nimport { VERSION } from '../src/version';\nimport * as sessionReplay from '@amplitude/session-replay-browser';\nimport { getSessionId, updateSessionIdAndAddProperties, setSessionId } from '../src/helpers';\n\njest.mock('@amplitude/session-replay-browser');\njest.mock('js-cookie');\njest.mock('../src/helpers');\n\ndescribe('createSegmentActionsPlugin()', () => {\n  const API_KEY = 'test-api-key';\n  const ANONYMOUS_ID = 'test-anonymous-id';\n  const DEVICE_ID = 'test-device-id';\n  const SESSION_ID = 'test-session-id';\n  const DEFAULT_SESSION_REPLAY_OPTIONS = {\n    sampleRate: 1,\n  };\n\n  const DEFAULT_CONTEXT: Context = {\n    event: {\n      properties: {},\n      integrations: {},\n    },\n    updateEvent: jest.fn(),\n  } as unknown as Context;\n\n  const DEFAULT_ANALYTICS: Analytics = {\n    user: jest.fn().mockReturnValue({\n      anonymousId: jest.fn().mockReturnValue(ANONYMOUS_ID),\n    }),\n  } as unknown as Analytics;\n\n  const DEFAULT_SEGMENT_INSTANCE: AnalyticsBrowser = {\n    register: jest.fn(),\n  } as unknown as AnalyticsBrowser;\n\n  const getPlugin = (mockSegmentInstance: AnalyticsBrowser): Plugin => {\n    if (!mockSegmentInstance.register || !(mockSegmentInstance.register as jest.Mock).mock.calls[0]) {\n      throw new Error('Segment instance is not properly initialized');\n    }\n    const calls = (mockSegmentInstance.register as jest.Mock).mock.calls as Array<[Plugin]>;\n    return calls[0][0];\n  };\n\n  beforeEach(() => {\n    jest.clearAllMocks();\n\n    (sessionReplay.init as jest.Mock).mockResolvedValue({ promise: Promise.resolve() });\n  });\n\n  it('should call segmentInstance.register() with the plugin', async () => {\n    // Arrange & Act\n    await createSegmentActionsPlugin({\n      segmentInstance: DEFAULT_SEGMENT_INSTANCE,\n      amplitudeApiKey: API_KEY,\n    });\n\n    // Assert\n    expect(DEFAULT_SEGMENT_INSTANCE.register).toHaveBeenCalledWith({\n      name: 'Session Replay Events',\n      type: 'enrichment',\n      version: VERSION,\n      isLoaded: expect.any(Function) as unknown as () => boolean,\n      load: expect.any(Function) as unknown as (ctx: Context, ajs: Analytics) => Promise<void>,\n      track: expect.any(Function) as unknown as (ctx: Context) => Promise<Context>,\n      page: expect.any(Function) as unknown as (ctx: Context) => Promise<Context>,\n      identify: expect.any(Function) as unknown as (ctx: Context) => Promise<Context>,\n    });\n  });\n\n  describe('load()', () => {\n    it('should call sessionReplay.init() with the correct parameters', async () => {\n      // Arrange\n      (getSessionId as jest.Mock).mockReturnValue(SESSION_ID);\n      await createSegmentActionsPlugin({\n        segmentInstance: DEFAULT_SEGMENT_INSTANCE,\n        amplitudeApiKey: API_KEY,\n        sessionReplayOptions: DEFAULT_SESSION_REPLAY_OPTIONS,\n      });\n\n      const plugin = getPlugin(DEFAULT_SEGMENT_INSTANCE);\n\n      // Act\n      await plugin.load(DEFAULT_CONTEXT, DEFAULT_ANALYTICS);\n\n      // Assert\n      expect(sessionReplay.init).toHaveBeenCalledWith(API_KEY, {\n        ...DEFAULT_SESSION_REPLAY_OPTIONS,\n        sessionId: SESSION_ID,\n        deviceId: ANONYMOUS_ID,\n        version: {\n          type: 'segment',\n          version: VERSION,\n        },\n      });\n    });\n\n    it('should call init() with the provided deviceId', async () => {\n      // Arrange\n      const sessionReplayOptions = {\n        ...DEFAULT_SESSION_REPLAY_OPTIONS,\n        deviceId: DEVICE_ID,\n      };\n\n      await createSegmentActionsPlugin({\n        segmentInstance: DEFAULT_SEGMENT_INSTANCE,\n        amplitudeApiKey: API_KEY,\n        sessionReplayOptions,\n      });\n\n      const plugin = getPlugin(DEFAULT_SEGMENT_INSTANCE);\n\n      // Act\n      await plugin.load(DEFAULT_CONTEXT, DEFAULT_ANALYTICS);\n\n      // Assert\n      expect(sessionReplay.init).toHaveBeenCalledWith(API_KEY, {\n        ...DEFAULT_SESSION_REPLAY_OPTIONS,\n        sessionId: SESSION_ID,\n        deviceId: DEVICE_ID,\n        version: {\n          type: 'segment',\n          version: VERSION,\n        },\n      });\n    });\n\n    it('should call init() with the anonymousId if no deviceId is provided', async () => {\n      await createSegmentActionsPlugin({\n        segmentInstance: DEFAULT_SEGMENT_INSTANCE,\n        amplitudeApiKey: API_KEY,\n        sessionReplayOptions: DEFAULT_SESSION_REPLAY_OPTIONS,\n      });\n\n      const plugin = getPlugin(DEFAULT_SEGMENT_INSTANCE);\n      await plugin.load(DEFAULT_CONTEXT, DEFAULT_ANALYTICS);\n\n      // Assert\n      expect(sessionReplay.init).toHaveBeenCalledWith(API_KEY, {\n        ...DEFAULT_SESSION_REPLAY_OPTIONS,\n        sessionId: SESSION_ID,\n        deviceId: ANONYMOUS_ID,\n        version: {\n          type: 'segment',\n          version: VERSION,\n        },\n      });\n    });\n\n    it.each([123, undefined])('should call init() with the sessionId', async (sessionId) => {\n      // Arrange\n      (getSessionId as jest.Mock).mockReturnValue(sessionId);\n\n      await createSegmentActionsPlugin({\n        segmentInstance: DEFAULT_SEGMENT_INSTANCE,\n        amplitudeApiKey: API_KEY,\n        sessionReplayOptions: DEFAULT_SESSION_REPLAY_OPTIONS,\n      });\n\n      const plugin = getPlugin(DEFAULT_SEGMENT_INSTANCE);\n\n      // Act\n      await plugin.load(DEFAULT_CONTEXT, DEFAULT_ANALYTICS);\n\n      // Assert\n      expect(sessionReplay.init).toHaveBeenCalledWith(API_KEY, {\n        ...DEFAULT_SESSION_REPLAY_OPTIONS,\n        sessionId,\n        deviceId: ANONYMOUS_ID,\n        version: {\n          type: 'segment',\n          version: VERSION,\n        },\n      });\n    });\n  });\n\n  describe('track()', () => {\n    it.each([\n      {\n        description: 'with the provided deviceId',\n        providedDeviceId: 'provided-device-id',\n        expectedDeviceId: 'provided-device-id',\n      },\n      {\n        description: 'with the anonymousId if deviceId is not provided',\n        providedDeviceId: undefined,\n        expectedDeviceId: ANONYMOUS_ID,\n      },\n    ])(\n      'should call updateSessionIdAndAddProperties() with the context and $description',\n      async ({ providedDeviceId, expectedDeviceId }) => {\n        // Arrange\n        (updateSessionIdAndAddProperties as jest.Mock).mockResolvedValue(null);\n\n        await createSegmentActionsPlugin({\n          segmentInstance: DEFAULT_SEGMENT_INSTANCE,\n          amplitudeApiKey: API_KEY,\n          sessionReplayOptions: {\n            ...DEFAULT_SESSION_REPLAY_OPTIONS,\n            deviceId: providedDeviceId,\n          },\n        });\n\n        const plugin = getPlugin(DEFAULT_SEGMENT_INSTANCE);\n\n        // NOTE: load() must be called before track()\n        await plugin.load(DEFAULT_CONTEXT, DEFAULT_ANALYTICS);\n\n        // Act\n        plugin.track && (await plugin.track(DEFAULT_CONTEXT));\n\n        // Assert\n        expect(updateSessionIdAndAddProperties).toHaveBeenCalledWith(DEFAULT_CONTEXT, expectedDeviceId);\n      },\n    );\n  });\n\n  describe('page()', () => {\n    it.each([\n      {\n        description: 'with the provided deviceId',\n        providedDeviceId: 'provided-device-id',\n        expectedDeviceId: 'provided-device-id',\n      },\n      {\n        description: 'with the anonymousId if deviceId is not provided',\n        providedDeviceId: undefined,\n        expectedDeviceId: ANONYMOUS_ID,\n      },\n    ])(\n      'should call updateSessionIdAndAddProperties() with the context and $description',\n      async ({ providedDeviceId, expectedDeviceId }) => {\n        // Arrange\n        (updateSessionIdAndAddProperties as jest.Mock).mockResolvedValue(null);\n\n        await createSegmentActionsPlugin({\n          segmentInstance: DEFAULT_SEGMENT_INSTANCE,\n          amplitudeApiKey: API_KEY,\n          sessionReplayOptions: {\n            ...DEFAULT_SESSION_REPLAY_OPTIONS,\n            deviceId: providedDeviceId,\n          },\n        });\n\n        const plugin = getPlugin(DEFAULT_SEGMENT_INSTANCE);\n\n        // NOTE: load() must be called before page()\n        await plugin.load(DEFAULT_CONTEXT, DEFAULT_ANALYTICS);\n\n        // Act\n        plugin.page && (await plugin.page(DEFAULT_CONTEXT));\n\n        // Assert\n        expect(updateSessionIdAndAddProperties).toHaveBeenCalledWith(DEFAULT_CONTEXT, expectedDeviceId);\n      },\n    );\n  });\n\n  describe('identify()', () => {\n    it.each([\n      {\n        description: 'with a valid session ID and provided deviceId',\n        sessionId: 'test-session-id',\n        deviceId: 'provided-device-id',\n        expectedDeviceId: 'provided-device-id',\n      },\n      {\n        description: 'with a valid session ID and anonymousId as deviceId',\n        sessionId: 'test-session-id',\n        deviceId: undefined,\n        expectedDeviceId: ANONYMOUS_ID,\n      },\n    ])('should call setSessionId() $description', async ({ sessionId, deviceId, expectedDeviceId }) => {\n      // Arrange\n      (getSessionId as jest.Mock).mockReturnValue(sessionId);\n\n      await createSegmentActionsPlugin({\n        segmentInstance: DEFAULT_SEGMENT_INSTANCE,\n        amplitudeApiKey: API_KEY,\n        sessionReplayOptions: {\n          ...DEFAULT_SESSION_REPLAY_OPTIONS,\n          deviceId,\n        },\n      });\n\n      const plugin = getPlugin(DEFAULT_SEGMENT_INSTANCE);\n\n      // NOTE: load() must be called before identify()\n      await plugin.load(DEFAULT_CONTEXT, DEFAULT_ANALYTICS);\n\n      // Act\n      plugin.identify && (await plugin.identify(DEFAULT_CONTEXT));\n\n      // Assert\n      expect(setSessionId).toHaveBeenCalledWith(sessionId, expectedDeviceId);\n    });\n\n    it('should not call setSessionId() when getSessionId() returns undefined', async () => {\n      // Arrange\n      (getSessionId as jest.Mock).mockReturnValue(undefined);\n\n      await createSegmentActionsPlugin({\n        segmentInstance: DEFAULT_SEGMENT_INSTANCE,\n        amplitudeApiKey: API_KEY,\n        sessionReplayOptions: {\n          ...DEFAULT_SESSION_REPLAY_OPTIONS,\n          deviceId: DEVICE_ID,\n        },\n      });\n\n      const plugin = getPlugin(DEFAULT_SEGMENT_INSTANCE);\n\n      // NOTE: load() must be called before identify()\n      await plugin.load(DEFAULT_CONTEXT, DEFAULT_ANALYTICS);\n\n      // Act\n      plugin.identify && (await plugin.identify(DEFAULT_CONTEXT));\n\n      // Assert\n      expect(setSessionId).not.toHaveBeenCalled();\n    });\n  });\n});\n"
  },
  {
    "path": "packages/segment-session-replay-plugin/tsconfig.es5.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/cjs\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/segment-session-replay-plugin/tsconfig.esm.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"es6\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/esm\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/segment-session-replay-plugin/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src/**/*\", \"test/**/*\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"esModuleInterop\": true,\n    \"lib\": [\"dom\"],\n    \"noEmit\": true,\n    \"rootDir\": \".\",\n  }\n}\n"
  },
  {
    "path": "packages/segment-session-replay-plugin-react-native/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## 0.0.1-beta.2 (2025-07-08)\n\n**Note:** Version bump only for package @amplitude/segment-session-replay-plugin-react-native\n"
  },
  {
    "path": "packages/segment-session-replay-plugin-react-native/README.md",
    "content": "# @amplitude/segment-session-replay-plugin-react-native\n\nAmplitude Segment Session Replay Plugin for React Native\n\n## Installation\n\n```sh\nnpm install @amplitude/segment-session-replay-plugin-react-native\n```\n\n### Dependencies\n\nThis plugin requires the following dependencies to be installed:\n\n```sh\nnpm install @amplitude/session-replay-react-native @segment/analytics-react-native\n```\n\n**Important**: This plugin requires the `@segment/analytics-react-native-plugin-amplitude-session` plugin to extract session IDs from Amplitude integration data. Make sure to add this plugin to your Segment client **before** adding the session replay plugin.\n\n## Usage\n\n### Segment Session Replay Plugin\n\nAdd the segment session replay plugin to your Segment Analytics instance to automatically integrate Amplitude Session Replay with your Segment events.\n\n```js\nimport { createSegmentSessionReplayPlugin } from '@amplitude/segment-session-replay-plugin-react-native';\nimport { createClient } from '@segment/analytics-react-native';\nimport { AmplitudeSessionPlugin } from '@segment/analytics-react-native-plugin-amplitude-session';\n\n// Initialize Segment client\nconst segmentClient = createClient({\n  writeKey: 'YOUR_SEGMENT_WRITE_KEY',\n});\n\n// Configure session replay plugin\nconst sessionReplayConfig = {\n  apiKey: 'YOUR_AMPLITUDE_API_KEY',\n  deviceId: 'YOUR_DEVICE_ID'\n};\n\n// Add the Amplitude session plugin first (required for session ID extraction)\nawait segmentClient.add({ plugin: new AmplitudeSessionPlugin() });\n\n// Add the session replay plugin to Segment\nawait segmentClient.add(createSegmentSessionReplayPlugin(sessionReplayConfig));\n```\n\n### Plugin Configuration\n\nThe plugin accepts a `SessionReplayConfig` object\n\n### Automatic Integration\n\nThe plugin automatically:\n\n1. **Initializes Session Replay**: Sets up Amplitude Session Replay with your configuration\n2. **Syncs Session Data**: Updates session ID and device ID for each Segment event\n3. **Enriches Events**: Adds session replay properties to track and screen events\n4. **Manages Lifecycle**: Handles start/stop operations for session replay\n\n### Event Processing\n\nThe plugin processes the following Segment event types:\n- `TrackEvent`: Adds session replay properties to track events\n- `ScreenEvent`: Adds session replay properties to screen events\n\nFor these events, the plugin:\n- Extracts session ID from event properties or Amplitude integration data\n- Extracts device ID from event context or anonymous ID\n- Adds session replay properties to the event before sending to Segment\n\n"
  },
  {
    "path": "packages/segment-session-replay-plugin-react-native/babel.config.js",
    "content": "module.exports = {\n  presets: ['module:metro-react-native-babel-preset'],\n};\n"
  },
  {
    "path": "packages/segment-session-replay-plugin-react-native/jest.config.js",
    "content": "const baseConfig = require('../../jest.config.js');\nconst package = require('./package');\n\nmodule.exports = {\n  ...baseConfig,\n  displayName: package.name,\n  rootDir: '.',\n  preset: 'react-native',\n  testEnvironment: 'jsdom',\n  modulePathIgnorePatterns: ['<rootDir>/lib/'],\n  moduleFileExtensions: ['tsx', 'ts', 'js', 'jsx', 'json'],\n  transformIgnorePatterns: [\n    'node_modules/(?!(.pnpm|@react-native|react-native|@segment)/)',\n  ],\n  // TODO do 100% coverage\n  coverageThreshold: {\n    global: {\n      branches: 80,\n      functions: 80,\n      lines: 80,\n      statements: 80,\n    },\n  },\n};\n"
  },
  {
    "path": "packages/segment-session-replay-plugin-react-native/jest.setup.js",
    "content": "// Mock React Native modules that cause issues in Jest\njest.mock('react-native', () => ({\n  Platform: {\n    OS: 'ios',\n    select: jest.fn(),\n  },\n  NativeModules: {},\n  NativeEventEmitter: jest.fn(),\n}));\n\n// Mock @react-native/polyfills\njest.mock('@react-native/polyfills', () => ({}));\n\n// Mock any other React Native related modules that might cause issues\njest.mock('@react-native-async-storage/async-storage', () => ({\n  getItem: jest.fn(),\n  setItem: jest.fn(),\n  removeItem: jest.fn(),\n  clear: jest.fn(),\n})); "
  },
  {
    "path": "packages/segment-session-replay-plugin-react-native/package.json",
    "content": "{\n  \"name\": \"@amplitude/segment-session-replay-plugin-react-native\",\n  \"version\": \"0.0.1-beta.2\",\n  \"description\": \"Amplitude Segment Session Replay Plugin for React Native\",\n  \"keywords\": [\n    \"analytics\",\n    \"amplitude\",\n    \"react-native\",\n    \"ios\",\n    \"android\",\n    \"session-replay\"\n  ],\n  \"author\": \"Amplitude Inc\",\n  \"homepage\": \"https://github.com/amplitude/Amplitude-TypeScript\",\n  \"license\": \"MIT\",\n  \"main\": \"lib/commonjs/index\",\n  \"module\": \"lib/module/index\",\n  \"types\": \"lib/typescript/index.d.ts\",\n  \"react-native\": \"src/index.ts\",\n  \"source\": \"src/index.ts\",\n  \"private\": true,\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"tag\": \"latest\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/amplitude/Amplitude-TypeScript.git\"\n  },\n  \"scripts\": {\n    \"build\": \"bob build\",\n    \"fix\": \"pnpm fix:eslint & pnpm fix:prettier\",\n    \"fix:eslint\": \"eslint '{src,test}/**/*.ts' --fix\",\n    \"fix:prettier\": \"prettier --write \\\"{src,test}/**/*.ts\\\"\",\n    \"lint\": \"pnpm lint:prettier && pnpm lint:eslint\",\n    \"lint:eslint\": \"eslint '{src,test}/**/*.ts'\",\n    \"lint:prettier\": \"prettier --check \\\"{src,test}/**/*.ts\\\"\",\n    \"test\": \"jest\",\n    \"typecheck\": \"tsc -p ./tsconfig.json\",\n    \"version\": \"pnpm version-file && pnpm build\",\n    \"version-file\": \"node -p \\\"'export const VERSION = \\\\'' + require('./package.json').version + '\\\\';'\\\" > src/version.ts\",\n    \"typescript\": \"tsc --noEmit\"\n  },\n  \"files\": [\n    \"src\",\n    \"!test\",\n    \"!**/__tests__\",\n    \"!**/__fixtures__\",\n    \"!**/__mocks__\",\n    \"!**/.*\"\n  ],\n  \"bugs\": {\n    \"url\": \"https://github.com/amplitude/Amplitude-TypeScript/issues\"\n  },\n  \"devDependencies\": {\n    \"@amplitude/session-replay-react-native\": \"workspace:*\",\n    \"@segment/analytics-react-native\": \"2.15.0\",\n    \"react-native-builder-bob\": \"^0.20.3\"\n  },\n  \"peerDependencies\": {\n    \"@amplitude/session-replay-react-native\": \"*\",\n    \"@segment/analytics-react-native\": \">= 2.2.0 < 3\"\n  },\n  \"react-native-builder-bob\": {\n    \"source\": \"src\",\n    \"output\": \"lib\",\n    \"targets\": [\n      \"commonjs\",\n      \"module\",\n      [\n        \"typescript\",\n        {\n          \"project\": \"tsconfig.build.json\"\n        }\n      ]\n    ]\n  }\n}\n"
  },
  {
    "path": "packages/segment-session-replay-plugin-react-native/src/index.ts",
    "content": "export { createSegmentSessionReplayPlugin } from './segment-session-replay-plugin';\n"
  },
  {
    "path": "packages/segment-session-replay-plugin-react-native/src/segment-session-replay-plugin.ts",
    "content": "import { Plugin, PluginType, type SegmentEvent, EventType, SegmentClient } from '@segment/analytics-react-native';\n\nimport {\n  type SessionReplayConfig,\n  getSessionReplayProperties,\n  init,\n  setDeviceId,\n  setSessionId,\n  start,\n  stop,\n} from '@amplitude/session-replay-react-native';\nimport { VERSION } from './version';\n\nfunction getSessionId(event: SegmentEvent): number {\n  const amplitudeSessionId =\n    (event.integrations?.['Actions Amplitude'] as { session_id: number })?.['session_id'] ?? null;\n  if (amplitudeSessionId !== null) {\n    return amplitudeSessionId;\n  }\n\n  if (event.type === EventType.TrackEvent || event.type === EventType.ScreenEvent) {\n    const sessionIdRaw = event.properties?.['session_id'];\n    const sessionId = Number(sessionIdRaw);\n    return Number.isNaN(sessionId) ? -1 : sessionId;\n  }\n  return -1;\n}\n\nfunction getDeviceId(event: SegmentEvent): string | null {\n  return event.context?.device?.id ?? event.anonymousId ?? null;\n}\n\nexport class SegmentSessionReplayPlugin extends Plugin {\n  name = 'amplitude-segment-session-replay-plugin-react-native';\n  version: string = VERSION;\n  type: PluginType = PluginType.enrichment;\n\n  private sessionReplayConfig: SessionReplayConfig;\n\n  // @review: This is to ensure the plugin is initialized before the first event is processed.\n  // because `configure` is not asynchronous\n  private initPromise: Promise<void> | null = null;\n\n  constructor(config: SessionReplayConfig) {\n    super();\n    this.sessionReplayConfig = config;\n  }\n\n  async configure(analytics: SegmentClient): Promise<void> {\n    super.configure(analytics);\n    this.initPromise = init({\n      deviceId: analytics.userInfo.get().anonymousId,\n      ...this.sessionReplayConfig,\n    });\n    await this.initPromise;\n  }\n\n  async execute(event: SegmentEvent): Promise<SegmentEvent> {\n    await this.initPromise;\n\n    const sessionId = getSessionId(event);\n    const deviceId = getDeviceId(event);\n\n    await setSessionId(sessionId);\n    await setDeviceId(deviceId);\n\n    if (event.type === EventType.TrackEvent || event.type === EventType.ScreenEvent) {\n      const properties = await getSessionReplayProperties();\n      event.properties = { ...event.properties, ...properties };\n    }\n\n    return event;\n  }\n\n  async shutdown(): Promise<void> {\n    await this.initPromise;\n    await stop();\n  }\n\n  async start(): Promise<void> {\n    await this.initPromise;\n    await start();\n  }\n\n  async stop(): Promise<void> {\n    await this.initPromise;\n    await stop();\n  }\n}\n\nexport function createSegmentSessionReplayPlugin(config: SessionReplayConfig): Plugin {\n  return new SegmentSessionReplayPlugin(config);\n}\n"
  },
  {
    "path": "packages/segment-session-replay-plugin-react-native/src/version.ts",
    "content": "export const VERSION = '0.0.1-beta.2';\n"
  },
  {
    "path": "packages/segment-session-replay-plugin-react-native/test/segment-session-replay-plugin.test.ts",
    "content": "// FIXME: remove these eslint rules\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-unsafe-call */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-unsafe-argument */\n\n// Mock @segment/analytics-react-native to prevent native module initialization\njest.mock('@segment/analytics-react-native', () => ({\n  PluginType: {\n    enrichment: 'enrichment',\n    destination: 'destination',\n    utility: 'utility',\n    before: 'before',\n    after: 'after',\n  },\n  EventType: {\n    TrackEvent: 'track',\n    ScreenEvent: 'screen',\n    IdentifyEvent: 'identify',\n    GroupEvent: 'group',\n    AliasEvent: 'alias',\n  },\n  Plugin: class Plugin {\n    analytics: unknown;\n    configure(analytics: unknown) {\n      this.analytics = analytics;\n    }\n  },\n}));\n\nimport { PluginType, EventType, SegmentEvent, SegmentClient } from '@segment/analytics-react-native';\nimport { SegmentSessionReplayPlugin, createSegmentSessionReplayPlugin } from '../src/segment-session-replay-plugin';\nimport {\n  init,\n  setDeviceId,\n  setSessionId,\n  getSessionReplayProperties,\n  start,\n  stop,\n} from '@amplitude/session-replay-react-native';\nimport { VERSION } from '../src/version';\n\n// Mock the session replay module\njest.mock('@amplitude/session-replay-react-native', () => ({\n  init: jest.fn(),\n  setDeviceId: jest.fn(),\n  setSessionId: jest.fn(),\n  getSessionReplayProperties: jest.fn(),\n  start: jest.fn(),\n  stop: jest.fn(),\n}));\n\ndescribe('SegmentSessionReplayPlugin', () => {\n  let plugin: SegmentSessionReplayPlugin;\n  let mockAnalytics: jest.Mocked<SegmentClient>;\n  let mockConfig: any;\n\n  beforeEach(() => {\n    jest.clearAllMocks();\n\n    mockConfig = {\n      apiKey: 'test-api-key',\n    };\n\n    mockAnalytics = {\n      track: jest.fn(),\n      identify: jest.fn(),\n      screen: jest.fn(),\n      group: jest.fn(),\n      alias: jest.fn(),\n      reset: jest.fn(),\n      flush: jest.fn(),\n      userInfo: {\n        get: jest.fn().mockReturnValue({ anonymousId: 'test-anonymous-id' }),\n      },\n    } as any;\n\n    plugin = new SegmentSessionReplayPlugin(mockConfig);\n  });\n\n  describe('constructor', () => {\n    it('should initialize with correct properties', () => {\n      expect(plugin.name).toBe('amplitude-segment-session-replay-plugin-react-native');\n      expect(plugin.version).toBe(VERSION);\n      expect(plugin.type).toBe(PluginType.enrichment);\n    });\n  });\n\n  describe('configure', () => {\n    it('should call super.configure and init with config', async () => {\n      await plugin.configure(mockAnalytics);\n\n      expect(init).toHaveBeenCalledWith({ ...mockConfig, deviceId: 'test-anonymous-id' });\n    });\n  });\n\n  describe('execute', () => {\n    it('should set session ID and device ID for track events', async () => {\n      const mockEvent = {\n        type: EventType.TrackEvent,\n        event: 'test_event',\n        properties: { session_id: '123' },\n        context: {\n          device: { id: 'device-123' },\n        },\n      } as SegmentEvent;\n\n      const mockProperties = { replay_session_id: 'replay-123' };\n      (getSessionReplayProperties as jest.Mock).mockResolvedValue(mockProperties);\n\n      const result = await plugin.execute(mockEvent);\n\n      expect(setSessionId).toHaveBeenCalledWith(123);\n      expect(setDeviceId).toHaveBeenCalledWith('device-123');\n      expect(getSessionReplayProperties).toHaveBeenCalled();\n      expect((result as any).properties).toEqual({\n        session_id: '123',\n        replay_session_id: 'replay-123',\n      });\n    });\n\n    it('should set session ID and device ID for screen events', async () => {\n      const mockEvent = {\n        type: EventType.ScreenEvent,\n        name: 'test_screen',\n        properties: { session_id: '456' },\n        context: {\n          device: { id: 'device-456' },\n        },\n      } as SegmentEvent;\n\n      const mockProperties = { replay_session_id: 'replay-456' };\n      (getSessionReplayProperties as jest.Mock).mockResolvedValue(mockProperties);\n\n      const result = await plugin.execute(mockEvent);\n\n      expect(setSessionId).toHaveBeenCalledWith(456);\n      expect(setDeviceId).toHaveBeenCalledWith('device-456');\n      expect(getSessionReplayProperties).toHaveBeenCalled();\n      expect((result as any).properties).toEqual({\n        session_id: '456',\n        replay_session_id: 'replay-456',\n      });\n    });\n\n    it('should use anonymousId when device.id is not available', async () => {\n      const mockEvent: SegmentEvent = {\n        type: EventType.TrackEvent,\n        event: 'test_event',\n        properties: {},\n        context: {},\n        anonymousId: 'anon-123',\n      } as any;\n\n      await plugin.execute(mockEvent);\n\n      expect(setDeviceId).toHaveBeenCalledWith('anon-123');\n    });\n\n    it('should use -1 for session ID when not available', async () => {\n      const mockEvent: SegmentEvent = {\n        type: EventType.TrackEvent,\n        event: 'test_event',\n        properties: {},\n        context: {\n          device: { id: 'device-123' },\n        },\n      } as any;\n\n      await plugin.execute(mockEvent);\n\n      expect(setSessionId).toHaveBeenCalledWith(-1);\n    });\n\n    it('should extract session ID from Amplitude integration', async () => {\n      const mockEvent: SegmentEvent = {\n        type: EventType.TrackEvent,\n        event: 'test_event',\n        properties: {},\n        context: {\n          device: { id: 'device-123' },\n        },\n        integrations: {\n          'Actions Amplitude': {\n            session_id: 789,\n          },\n        },\n      } as any;\n\n      await plugin.execute(mockEvent);\n\n      expect(setSessionId).toHaveBeenCalledWith(789);\n    });\n\n    it('should not call getSessionReplayProperties for non-track/screen events', async () => {\n      const mockEvent: SegmentEvent = {\n        type: EventType.IdentifyEvent,\n        userId: 'user-123',\n        traits: {},\n      } as any;\n\n      await plugin.execute(mockEvent);\n\n      expect(getSessionReplayProperties).not.toHaveBeenCalled();\n    });\n\n    it('should handle null device ID gracefully', async () => {\n      const mockEvent: SegmentEvent = {\n        type: EventType.TrackEvent,\n        event: 'test_event',\n        properties: {},\n        context: {},\n      } as any;\n\n      await plugin.execute(mockEvent);\n\n      expect(setDeviceId).toHaveBeenCalledWith(null);\n    });\n\n    it('should handle invalid session_id string gracefully', async () => {\n      const mockEvent: SegmentEvent = {\n        type: EventType.TrackEvent,\n        event: 'test_event',\n        properties: { session_id: 'invalid-number' },\n        context: {\n          device: { id: 'device-123' },\n        },\n      } as any;\n\n      await plugin.execute(mockEvent);\n\n      expect(setSessionId).toHaveBeenCalledWith(-1);\n    });\n\n    it('should preserve existing properties when adding session replay properties', async () => {\n      const mockEvent = {\n        type: EventType.TrackEvent,\n        event: 'test_event',\n        properties: {\n          existing_prop: 'value',\n          session_id: '123',\n        },\n        context: {\n          device: { id: 'device-123' },\n        },\n      } as SegmentEvent;\n\n      const mockProperties = { replay_session_id: 'replay-123' };\n      (getSessionReplayProperties as jest.Mock).mockResolvedValue(mockProperties);\n\n      const result = await plugin.execute(mockEvent);\n\n      expect((result as any).properties).toEqual({\n        existing_prop: 'value',\n        session_id: '123',\n        replay_session_id: 'replay-123',\n      });\n    });\n  });\n\n  describe('shutdown', () => {\n    it('should call stop', async () => {\n      await plugin.shutdown();\n      expect(stop).toHaveBeenCalled();\n    });\n  });\n\n  describe('start', () => {\n    it('should call start', async () => {\n      await plugin.start();\n      expect(start).toHaveBeenCalled();\n    });\n  });\n\n  describe('stop', () => {\n    it('should call stop', async () => {\n      await plugin.stop();\n      expect(stop).toHaveBeenCalled();\n    });\n  });\n});\n\ndescribe('createSegmentSessionReplayPlugin', () => {\n  it('should create a new SegmentSessionReplayPlugin instance', () => {\n    const config = { apiKey: 'test-key' };\n    const plugin = createSegmentSessionReplayPlugin(config);\n\n    expect(plugin).toBeInstanceOf(SegmentSessionReplayPlugin);\n    expect((plugin as any).sessionReplayConfig).toBe(config);\n  });\n});\n"
  },
  {
    "path": "packages/segment-session-replay-plugin-react-native/test/tsconfig.json",
    "content": "{\n  \"extends\": \"../tsconfig.json\",\n  \"compilerOptions\": {\n    \"types\": [\"jest\", \"node\"]\n  }\n}\n\n"
  },
  {
    "path": "packages/segment-session-replay-plugin-react-native/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig\",\n  \"exclude\": [\"test\", \"example\", \"lib\"]\n}\n"
  },
  {
    "path": "packages/segment-session-replay-plugin-react-native/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"paths\": {\n      \"@amplitude/segment-session-replay-plugin-react-native\": [\"./src/index\"]\n    },\n    \"allowUnreachableCode\": false,\n    \"allowUnusedLabels\": false,\n    \"esModuleInterop\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"jsx\": \"react\",\n    \"lib\": [\"esnext\", \"dom\"],\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"noStrictGenericChecks\": false,\n    \"skipLibCheck\": true,\n    \"target\": \"es6\"\n  }\n}\n"
  },
  {
    "path": "packages/session-replay-browser/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.43.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.42.3...@amplitude/session-replay-browser@1.43.0) (2026-05-14)\n\n\n### Bug Fixes\n\n* **session-replay-browser:** light mask level leaves text visible under urlMaskLevels (SR-3176 follow-up) ([#1752](https://github.com/amplitude/Amplitude-TypeScript/issues/1752)) ([5d449c9](https://github.com/amplitude/Amplitude-TypeScript/commit/5d449c9f6f58e33da31b9df6a9fdea28deefb81c))\n\n\n### Features\n\n* **session-replay:** enforce min_session_duration_ms from remote config ([#1725](https://github.com/amplitude/Amplitude-TypeScript/issues/1725)) ([317bbfd](https://github.com/amplitude/Amplitude-TypeScript/commit/317bbfdf2fff3bf1321ea3f6dac34dfd328cc09d))\n\n\n\n\n\n## [1.42.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.42.2...@amplitude/session-replay-browser@1.42.3) (2026-05-11)\n\n\n### Bug Fixes\n\n* **session-replay-browser:** wait for remote config to avoid stale cache race (SR-4234) ([#1739](https://github.com/amplitude/Amplitude-TypeScript/issues/1739)) ([cf8f806](https://github.com/amplitude/Amplitude-TypeScript/commit/cf8f8067bdee16951ade4501e0d89b98881df75f))\n\n\n\n\n\n## [1.42.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.42.1...@amplitude/session-replay-browser@1.42.2) (2026-05-08)\n\n\n### Bug Fixes\n\n* **session-replay-browser:** honor X-Session-Replay-Event-Skipped server back-pressure (SR-4280) ([#1741](https://github.com/amplitude/Amplitude-TypeScript/issues/1741)) ([1ef7bc8](https://github.com/amplitude/Amplitude-TypeScript/commit/1ef7bc889d69f24c4b5690164b72d88b12a88303))\n\n\n\n\n\n## [1.42.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.42.0...@amplitude/session-replay-browser@1.42.1) (2026-05-07)\n\n\n### Bug Fixes\n\n* **session-replay-browser:** add fullSnapshotIntervalMs and flush queue on page unload (SR-3324) ([#1681](https://github.com/amplitude/Amplitude-TypeScript/issues/1681)) ([463ba0f](https://github.com/amplitude/Amplitude-TypeScript/commit/463ba0f72064bbc7265151a112874014f78318ab))\n* **session-replay-browser:** prevent 413 PAYLOAD_TOO_LARGE errors from losing event data ([#1703](https://github.com/amplitude/Amplitude-TypeScript/issues/1703)) ([52354c1](https://github.com/amplitude/Amplitude-TypeScript/commit/52354c1d5497637f34eb35110cb76600b4e6d147))\n* **session-replay-browser:** reduce snapshot size and handle 413s ([#1685](https://github.com/amplitude/Amplitude-TypeScript/issues/1685)) ([36db705](https://github.com/amplitude/Amplitude-TypeScript/commit/36db705d3b4b648aeab09c9e4dc89cf6b8dbf64b))\n* **session-replay-browser:** wire amp-unmask as default unmaskSelector (SR-2945) ([#1650](https://github.com/amplitude/Amplitude-TypeScript/issues/1650)) ([7a43014](https://github.com/amplitude/Amplitude-TypeScript/commit/7a430146c019044a9dcabe89d8b6865817efc53e))\n\n\n\n\n\n# [1.42.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.41.0...@amplitude/session-replay-browser@1.42.0) (2026-05-06)\n\n\n### Bug Fixes\n\n* **session-replay-browser:** buffer emit events when eventCompressor not yet ready ([#1706](https://github.com/amplitude/Amplitude-TypeScript/issues/1706)) ([fa4d38b](https://github.com/amplitude/Amplitude-TypeScript/commit/fa4d38b1f05c5ae7051cd74869a99495b38a094b))\n\n\n### Features\n\n* **session-replay-browser:** default storeType to memory (SR-3878 experiment) ([#1704](https://github.com/amplitude/Amplitude-TypeScript/issues/1704)) ([a893023](https://github.com/amplitude/Amplitude-TypeScript/commit/a8930230a7822fb2ae1fb5150d98f9c150a617bb))\n\n\n\n\n\n# [1.41.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.40.0...@amplitude/session-replay-browser@1.41.0) (2026-05-05)\n\n\n### Bug Fixes\n\n* **session-replay:** multi-tab IDB correctness, hang protection, memory fallback ([#1705](https://github.com/amplitude/Amplitude-TypeScript/issues/1705)) ([4133398](https://github.com/amplitude/Amplitude-TypeScript/commit/413339817b7c377f3a68c15243a09a99eaf46f0d))\n\n\n### Features\n\n* **session-replay-browser:** cross-origin iframe recording (SR-4094) ([#1715](https://github.com/amplitude/Amplitude-TypeScript/issues/1715)) ([26cb847](https://github.com/amplitude/Amplitude-TypeScript/commit/26cb847199014ceab5d921184af7b58f95ac7d0d))\n* **session-replay:** add fetch keepalive to reduce 499 errors on page navigation ([#1729](https://github.com/amplitude/Amplitude-TypeScript/issues/1729)) ([fa5f84a](https://github.com/amplitude/Amplitude-TypeScript/commit/fa5f84af9a499e7bc12fbd5a1b8ab06ac89c2271))\n\n\n\n\n\n# [1.40.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.39.0...@amplitude/session-replay-browser@1.40.0) (2026-05-05)\n\n\n### Features\n\n* **session-replay:** upgrade rrweb to 2.0.0-alpha.40 ([#1714](https://github.com/amplitude/Amplitude-TypeScript/issues/1714)) ([8474dd5](https://github.com/amplitude/Amplitude-TypeScript/commit/8474dd52448ddb9190f1b8b8ac96f11a371807be))\n\n\n\n\n\n# [1.39.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.38.0...@amplitude/session-replay-browser@1.39.0) (2026-04-28)\n\n\n### Features\n\n* **session-replay-browser:** merge consecutive mutation incremental snapshots ([#1698](https://github.com/amplitude/Amplitude-TypeScript/issues/1698)) ([634ac97](https://github.com/amplitude/Amplitude-TypeScript/commit/634ac979d3b700295b43aa65fb9e70ada45ddd7d))\n\n\n\n\n\n# [1.38.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.37.0...@amplitude/session-replay-browser@1.38.0) (2026-04-22)\n\n\n### Features\n\n* **session-replay-browser:** expose captureAdoptedStyleSheets option ([#1695](https://github.com/amplitude/Amplitude-TypeScript/issues/1695)) ([9cec47c](https://github.com/amplitude/Amplitude-TypeScript/commit/9cec47c14b6e8f9057309922e36fb4c0714f06e1))\n\n\n\n\n\n# [1.37.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.36.2...@amplitude/session-replay-browser@1.37.0) (2026-04-21)\n\n\n### Bug Fixes\n\n* **session-replay-browser:** add in-flight guard to recordEvents() to prevent concurrent rrweb races ([#1686](https://github.com/amplitude/Amplitude-TypeScript/issues/1686)) ([7d96a75](https://github.com/amplitude/Amplitude-TypeScript/commit/7d96a752f175976cb7ecc87cff3e79c718ac46dd))\n* **session-replay-browser:** restore medium mask level to mask all text (SR-3176) ([#1690](https://github.com/amplitude/Amplitude-TypeScript/issues/1690)) ([3b8a774](https://github.com/amplitude/Amplitude-TypeScript/commit/3b8a774b910cd4921153a5a6a31dc67308a6598f))\n* **session-replay-browser:** retry on 408, 429, and 499 status codes (SR-3581) ([#1691](https://github.com/amplitude/Amplitude-TypeScript/issues/1691)) ([62db518](https://github.com/amplitude/Amplitude-TypeScript/commit/62db518d3515916a1fc8f4c608a858ed408791f7))\n* **session-replay-browser:** use takeFullSnapshot on focus instead of full rrweb restart (SR-3531) ([#1689](https://github.com/amplitude/Amplitude-TypeScript/issues/1689)) ([48f38da](https://github.com/amplitude/Amplitude-TypeScript/commit/48f38dad155c810c85acf684bbc70e97fbe2ce82))\n\n\n### Features\n\n* **session-replay-browser:** fall back to in-memory store when IDB repeatedly fails ([#1684](https://github.com/amplitude/Amplitude-TypeScript/issues/1684)) ([a901f48](https://github.com/amplitude/Amplitude-TypeScript/commit/a901f48579ff8c7b7d0078b7b67f161d83eab314))\n* **session-replay-browser:** URL-aware masking via urlMaskLevels (SR-3176) ([#1679](https://github.com/amplitude/Amplitude-TypeScript/issues/1679)) ([aebc6fa](https://github.com/amplitude/Amplitude-TypeScript/commit/aebc6fa77164011022a909c5db835de7150d9a91))\n\n\n\n\n\n## [1.36.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.36.1...@amplitude/session-replay-browser@1.36.2) (2026-04-16)\n\n\n### Bug Fixes\n\n* **session-replay-browser:** handle IDB tx.done AbortError as debug not warn ([#1683](https://github.com/amplitude/Amplitude-TypeScript/issues/1683)) ([cd4aaed](https://github.com/amplitude/Amplitude-TypeScript/commit/cd4aaed237ad38d91b4d7491292069207aaeabeb))\n\n\n\n\n\n## [1.36.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.36.0...@amplitude/session-replay-browser@1.36.1) (2026-04-14)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n# [1.36.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.35.1...@amplitude/session-replay-browser@1.36.0) (2026-04-09)\n\n\n### Features\n\n* **session-replay-browser:** improve replay data delivery (SR-3115) ([#1637](https://github.com/amplitude/Amplitude-TypeScript/issues/1637)) ([21bd1c8](https://github.com/amplitude/Amplitude-TypeScript/commit/21bd1c870eea801878aea0fc4e952fe2b8908675))\n\n\n\n\n\n## [1.35.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.35.0...@amplitude/session-replay-browser@1.35.1) (2026-04-01)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n# [1.35.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.34.3...@amplitude/session-replay-browser@1.35.0) (2026-03-26)\n\n\n### Bug Fixes\n\n* **session-replay-browser:** read window.scrollY on page leave to capture final scroll position ([#1626](https://github.com/amplitude/Amplitude-TypeScript/issues/1626)) ([fa924a2](https://github.com/amplitude/Amplitude-TypeScript/commit/fa924a23479ce150c8239a4c94ddff7009a2e8b9))\n\n\n### Features\n\n* **session-replay-browser:** migrate sampling from Java hashCode to xxHash32 ([#1629](https://github.com/amplitude/Amplitude-TypeScript/issues/1629)) ([eb15e44](https://github.com/amplitude/Amplitude-TypeScript/commit/eb15e4466594206c27a2ff38686921016588a12b))\n\n\n\n\n\n## [1.34.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.34.2...@amplitude/session-replay-browser@1.34.3) (2026-03-24)\n\n\n### Bug Fixes\n\n* **session-replay-browser:** inline targeting types to fix TS2344 for consumers ([#1627](https://github.com/amplitude/Amplitude-TypeScript/issues/1627)) ([f219575](https://github.com/amplitude/Amplitude-TypeScript/commit/f219575152ef029589345e17b6c27bc8c7f05a24))\n\n\n\n\n\n## [1.34.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.34.1...@amplitude/session-replay-browser@1.34.2) (2026-03-23)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.34.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.34.0...@amplitude/session-replay-browser@1.34.1) (2026-03-20)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n# [1.34.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.33.1...@amplitude/session-replay-browser@1.34.0) (2026-03-19)\n\n\n### Features\n\n* **session-replay-browser:** implement attribute masking functionality ([#1602](https://github.com/amplitude/Amplitude-TypeScript/issues/1602)) ([ad8b8ac](https://github.com/amplitude/Amplitude-TypeScript/commit/ad8b8ac383a698ab6727b3bff8147323eef3d36e))\n\n\n\n\n\n## [1.33.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.33.0...@amplitude/session-replay-browser@1.33.1) (2026-03-17)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n# [1.33.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.32.2...@amplitude/session-replay-browser@1.33.0) (2026-03-16)\n\n\n### Features\n\n* **session-replay-browser:** add opt-in request and response body capture to network events ([#1582](https://github.com/amplitude/Amplitude-TypeScript/issues/1582)) ([3a67cf9](https://github.com/amplitude/Amplitude-TypeScript/commit/3a67cf91b0b07293f46405b33790bd5596d8d56d))\n\n\n\n\n\n## [1.32.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.32.1...@amplitude/session-replay-browser@1.32.2) (2026-03-13)\n\n\n### Bug Fixes\n\n* **session-replay:** add user-property targeting for session recording ([#1593](https://github.com/amplitude/Amplitude-TypeScript/issues/1593)) ([123b4a5](https://github.com/amplitude/Amplitude-TypeScript/commit/123b4a521e6f35353c09b60f1e3ab619e06e5f3b))\n\n\n\n\n\n## [1.32.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.32.0...@amplitude/session-replay-browser@1.32.1) (2026-03-12)\n\n\n### Bug Fixes\n\n* **session-replay:** prevent blob worker errors from surfacing as uncaught ([#1561](https://github.com/amplitude/Amplitude-TypeScript/issues/1561)) ([e55ca38](https://github.com/amplitude/Amplitude-TypeScript/commit/e55ca382e29ece3e7b5df6304d34258b460e91fe))\n\n\n\n\n\n# [1.32.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.31.7...@amplitude/session-replay-browser@1.32.0) (2026-03-11)\n\n\n### Features\n\n* **session-replay:** enhance targeting evaluation with page URL ([#1571](https://github.com/amplitude/Amplitude-TypeScript/issues/1571)) ([509bec0](https://github.com/amplitude/Amplitude-TypeScript/commit/509bec01ccdb795c0f9dbf83a99e585c6d16ee63))\n\n\n\n\n\n## [1.31.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.31.6...@amplitude/session-replay-browser@1.31.7) (2026-03-09)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.31.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.31.5...@amplitude/session-replay-browser@1.31.6) (2026-03-06)\n\n\n### Bug Fixes\n\n* **session-replay:** guarantee in-order batch delivery including retries ([#1576](https://github.com/amplitude/Amplitude-TypeScript/issues/1576)) ([0afcac6](https://github.com/amplitude/Amplitude-TypeScript/commit/0afcac6cd42b999b74ba797717f7cf0d447029ef))\n\n\n\n\n\n## [1.31.6-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.31.5...@amplitude/session-replay-browser@1.31.6-beta.0) (2026-03-06)\n\n\n### Bug Fixes\n\n* **session-replay:** guarantee in-order batch delivery including retries ([#1576](https://github.com/amplitude/Amplitude-TypeScript/issues/1576)) ([0afcac6](https://github.com/amplitude/Amplitude-TypeScript/commit/0afcac6cd42b999b74ba797717f7cf0d447029ef))\n\n\n\n\n\n## [1.31.6-in-order.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.31.5...@amplitude/session-replay-browser@1.31.6-in-order.0) (2026-03-06)\n\n\n### Bug Fixes\n\n* **session-replay:** remove dead timeout-queue code and restore 100% coverage ([aa0703c](https://github.com/amplitude/Amplitude-TypeScript/commit/aa0703c8b5da571cb32485f870ee3532d9069a02))\n* **session-replay:** send batches and retries in order ([94bf37b](https://github.com/amplitude/Amplitude-TypeScript/commit/94bf37b1aa3404147089db9bc81c489a77f7544a))\n\n\n\n\n\n## [1.31.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.31.4...@amplitude/session-replay-browser@1.31.5) (2026-03-05)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.31.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.31.3...@amplitude/session-replay-browser@1.31.4) (2026-03-03)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.31.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.31.2...@amplitude/session-replay-browser@1.31.3) (2026-03-03)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.31.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.31.1...@amplitude/session-replay-browser@1.31.2) (2026-02-26)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.31.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.31.0...@amplitude/session-replay-browser@1.31.1) (2026-02-24)\n\n\n### Bug Fixes\n\n* **session-replay:** avoid creating keyval-store DB when checking for legacy data ([#1551](https://github.com/amplitude/Amplitude-TypeScript/issues/1551)) ([73450e2](https://github.com/amplitude/Amplitude-TypeScript/commit/73450e29f21bd06e8932f387571af3bd6bb1b022))\n* **session-replay:** remove keyval-store migration to avoid collisions with app code ([#1553](https://github.com/amplitude/Amplitude-TypeScript/issues/1553)) ([165164a](https://github.com/amplitude/Amplitude-TypeScript/commit/165164a13045e4b5a5a226a91174054b36309bcc))\n\n\n\n\n\n# [1.31.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.30.11...@amplitude/session-replay-browser@1.31.0) (2026-02-19)\n\n\n### Features\n\n* screenshot capture messenger ([#1535](https://github.com/amplitude/Amplitude-TypeScript/issues/1535)) ([93ef551](https://github.com/amplitude/Amplitude-TypeScript/commit/93ef551ff0ab7dc48014aa5fa25841437d641993))\n\n\n\n\n\n## [1.30.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.30.10...@amplitude/session-replay-browser@1.30.11) (2026-02-17)\n\n\n### Bug Fixes\n\n* **session-replay-browser:** prevent worker script load failure from blob URLs ([#1522](https://github.com/amplitude/Amplitude-TypeScript/issues/1522)) ([decccae](https://github.com/amplitude/Amplitude-TypeScript/commit/decccaea363c3f88c1bee7b3629435a07268d699))\n\n\n\n\n\n## [1.30.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.30.9...@amplitude/session-replay-browser@1.30.10) (2026-02-10)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.30.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.30.8...@amplitude/session-replay-browser@1.30.9) (2026-01-26)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.30.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.30.7...@amplitude/session-replay-browser@1.30.8) (2026-01-21)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.30.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.30.6...@amplitude/session-replay-browser@1.30.7) (2026-01-15)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.30.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.30.5...@amplitude/session-replay-browser@1.30.6) (2026-01-14)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.30.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.30.4...@amplitude/session-replay-browser@1.30.5) (2026-01-14)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.30.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.30.3...@amplitude/session-replay-browser@1.30.4) (2025-12-24)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.30.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.30.2...@amplitude/session-replay-browser@1.30.3) (2025-12-22)\n\n\n### Bug Fixes\n\n* **session-replay:** gracefully handle idb abort ([#1430](https://github.com/amplitude/Amplitude-TypeScript/issues/1430)) ([fe71fc9](https://github.com/amplitude/Amplitude-TypeScript/commit/fe71fc95258d2a85c7129b9628aac346f123aed9))\n\n\n\n\n\n## [1.30.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.30.1...@amplitude/session-replay-browser@1.30.2) (2025-12-16)\n\n\n### Bug Fixes\n\n* **session-replay-browser:** upgrades to @amplitude/rrweb-*[@2](https://github.com/2).0.0-alpha.34 to pull in vite changes ([#1437](https://github.com/amplitude/Amplitude-TypeScript/issues/1437)) ([83a1403](https://github.com/amplitude/Amplitude-TypeScript/commit/83a140311ff23d72105604f6a6bc3de0dd43402c))\n\n\n\n\n\n## [1.30.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.30.0...@amplitude/session-replay-browser@1.30.1) (2025-12-09)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n# [1.30.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.29.8...@amplitude/session-replay-browser@1.30.0) (2025-12-05)\n\n\n### Features\n\n* **session-replay-browser:** add performance config for selector generation ([#1422](https://github.com/amplitude/Amplitude-TypeScript/issues/1422)) ([9723f77](https://github.com/amplitude/Amplitude-TypeScript/commit/9723f7739dd70c869d73119ad2c145575cbe9fc9))\n* **session-replay-browser:** move web worker out of experimental ([#1416](https://github.com/amplitude/Amplitude-TypeScript/issues/1416)) ([50e3063](https://github.com/amplitude/Amplitude-TypeScript/commit/50e30636fb00f98989a2085b8b79d1792e1705d4))\n\n\n\n\n\n## [1.29.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.29.7...@amplitude/session-replay-browser@1.29.8) (2025-11-21)\n\n\n### Bug Fixes\n\n* handle null remote config cases for session capture ([#1396](https://github.com/amplitude/Amplitude-TypeScript/issues/1396)) ([18e98d0](https://github.com/amplitude/Amplitude-TypeScript/commit/18e98d0b9a561cf30c241197e9627c49b75cd00f))\n\n\n\n\n\n## [1.29.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.29.6...@amplitude/session-replay-browser@1.29.7) (2025-11-20)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.29.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.29.5...@amplitude/session-replay-browser@1.29.6) (2025-11-17)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.29.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.29.4...@amplitude/session-replay-browser@1.29.5) (2025-11-17)\n\n\n### Bug Fixes\n\n* remove the reset history ([#1388](https://github.com/amplitude/Amplitude-TypeScript/issues/1388)) ([841c9ce](https://github.com/amplitude/Amplitude-TypeScript/commit/841c9ce1f93fb19dcd2e620e7e4f776db5982a09))\n\n\n\n\n\n## [1.29.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.29.3...@amplitude/session-replay-browser@1.29.4) (2025-11-05)\n\n\n### Bug Fixes\n\n* **session-replay-browser:** fix heatmap click x/y ([#1385](https://github.com/amplitude/Amplitude-TypeScript/issues/1385)) ([0e3d097](https://github.com/amplitude/Amplitude-TypeScript/commit/0e3d097397cea0493d39a0a4b005cfe069b4e14c))\n\n\n\n\n\n## [1.29.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.29.2...@amplitude/session-replay-browser@1.29.3) (2025-10-29)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.29.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.29.1...@amplitude/session-replay-browser@1.29.2) (2025-10-23)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.29.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.29.0...@amplitude/session-replay-browser@1.29.1) (2025-10-23)\n\n\n### Bug Fixes\n\n* **session-replay-browser:** should respect configServerUrl ([#1362](https://github.com/amplitude/Amplitude-TypeScript/issues/1362)) ([a452d6e](https://github.com/amplitude/Amplitude-TypeScript/commit/a452d6e2f58bf5b1fe1ee01353a2680403a71d8b))\n\n\n\n\n\n# [1.29.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.28.21...@amplitude/session-replay-browser@1.29.0) (2025-10-21)\n\n\n### Features\n\n* **session-replay-browser:** migrate to new remote config client ([#1351](https://github.com/amplitude/Amplitude-TypeScript/issues/1351)) ([d9e0c2c](https://github.com/amplitude/Amplitude-TypeScript/commit/d9e0c2c5df47147bd89c6bfd5e5d2fe3254c8b27))\n\n\n### Performance Improvements\n\n* **session-replay:** reduce recording initialization when trc enabled ([#1353](https://github.com/amplitude/Amplitude-TypeScript/issues/1353)) ([9cedb92](https://github.com/amplitude/Amplitude-TypeScript/commit/9cedb9297be3a0f59f17402c011ada8d940cbe0e))\n\n\n\n\n\n## [1.28.21](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.28.20...@amplitude/session-replay-browser@1.28.21) (2025-10-17)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.28.20](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.28.19...@amplitude/session-replay-browser@1.28.20) (2025-10-15)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.28.19](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.28.18...@amplitude/session-replay-browser@1.28.19) (2025-10-14)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.28.18](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.28.17...@amplitude/session-replay-browser@1.28.18) (2025-10-14)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.28.17](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.28.16...@amplitude/session-replay-browser@1.28.17) (2025-10-07)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.28.16](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.28.15...@amplitude/session-replay-browser@1.28.16) (2025-10-03)\n\n\n### Bug Fixes\n\n* add diagnostics to client and track autocapture getHierachy block time ([#1312](https://github.com/amplitude/Amplitude-TypeScript/issues/1312)) ([a919e22](https://github.com/amplitude/Amplitude-TypeScript/commit/a919e223428083a87954cffa50bc765baa5360b0))\n\n\n\n\n\n## [1.28.15](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.28.14...@amplitude/session-replay-browser@1.28.15) (2025-10-01)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.28.14](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.28.13...@amplitude/session-replay-browser@1.28.14) (2025-09-25)\n\n\n### Bug Fixes\n\n* **session-replay-browser:** Fix webworker packaging for ESM ([#1300](https://github.com/amplitude/Amplitude-TypeScript/issues/1300)) ([9cf8cd9](https://github.com/amplitude/Amplitude-TypeScript/commit/9cf8cd90f1c96c0c03670fb1fc96f8d2d1dde605))\n\n\n\n\n\n## [1.28.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.28.12...@amplitude/session-replay-browser@1.28.13) (2025-09-25)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.28.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.28.11...@amplitude/session-replay-browser@1.28.12) (2025-09-23)\n\n\n### Bug Fixes\n\n* **session-replay:** fix builds for iife ([#1302](https://github.com/amplitude/Amplitude-TypeScript/issues/1302)) ([b5f5af7](https://github.com/amplitude/Amplitude-TypeScript/commit/b5f5af780e4db91f8ffb7885f670a6d2f5036f76))\n\n\n\n\n\n## [1.28.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.28.10...@amplitude/session-replay-browser@1.28.11) (2025-09-18)\n\n\n### Performance Improvements\n\n* **session-replay:** reduce record initializations for targeting  ([#1295](https://github.com/amplitude/Amplitude-TypeScript/issues/1295)) ([aebe52e](https://github.com/amplitude/Amplitude-TypeScript/commit/aebe52ed0eb6b036cff4dcbecc1eea296237f767))\n\n\n\n\n\n## [1.28.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.28.9...@amplitude/session-replay-browser@1.28.10) (2025-09-12)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.28.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.28.8...@amplitude/session-replay-browser@1.28.9) (2025-09-05)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.28.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.28.7...@amplitude/session-replay-browser@1.28.8) (2025-08-28)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.28.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.28.6...@amplitude/session-replay-browser@1.28.7) (2025-08-26)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.28.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.28.5...@amplitude/session-replay-browser@1.28.6) (2025-08-25)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.28.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.28.4...@amplitude/session-replay-browser@1.28.5) (2025-08-22)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.28.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.28.3...@amplitude/session-replay-browser@1.28.4) (2025-08-21)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.28.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.28.2...@amplitude/session-replay-browser@1.28.3) (2025-08-13)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.28.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.28.1...@amplitude/session-replay-browser@1.28.2) (2025-08-08)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.28.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.28.0...@amplitude/session-replay-browser@1.28.1) (2025-08-05)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n# [1.28.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.27.0...@amplitude/session-replay-browser@1.28.0) (2025-07-29)\n\n\n### Features\n\n* targeting replay capture ([#1203](https://github.com/amplitude/Amplitude-TypeScript/issues/1203)) ([a1fc5b7](https://github.com/amplitude/Amplitude-TypeScript/commit/a1fc5b71cd71b33e6c6cd578cee4d0a17576e576))\n\n\n\n\n\n# [1.27.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.26.2...@amplitude/session-replay-browser@1.27.0) (2025-07-17)\n\n\n### Features\n\n* detect URL changes ([#1192](https://github.com/amplitude/Amplitude-TypeScript/issues/1192)) ([4957c16](https://github.com/amplitude/Amplitude-TypeScript/commit/4957c16df1f1b102cb2420d72b8f60847f49424a))\n\n\n\n\n\n## [1.26.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.26.1...@amplitude/session-replay-browser@1.26.2) (2025-07-15)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.26.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.26.0...@amplitude/session-replay-browser@1.26.1) (2025-07-11)\n\n\n### Bug Fixes\n\n* **session replay:** better Angular zone detection ([#1205](https://github.com/amplitude/Amplitude-TypeScript/issues/1205)) ([7d88d29](https://github.com/amplitude/Amplitude-TypeScript/commit/7d88d29671810d294f809a87d642eec825959759))\n\n\n\n\n\n# [1.26.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.25.3...@amplitude/session-replay-browser@1.26.0) (2025-07-08)\n\n\n### Features\n\n* **session-replay-browser:** allows users to omit scripts and comments from being captured ([#1179](https://github.com/amplitude/Amplitude-TypeScript/issues/1179)) ([4a705bc](https://github.com/amplitude/Amplitude-TypeScript/commit/4a705bc21eaae7e3319042701d6e2b0dbef971aa))\n\n\n### Performance Improvements\n\n* **session replay:** use text encoder instead of blob for size calc ([#1176](https://github.com/amplitude/Amplitude-TypeScript/issues/1176)) ([9a37bc3](https://github.com/amplitude/Amplitude-TypeScript/commit/9a37bc3a5844f6f56fef238faec4cf506e58b198))\n* **session-replay:** enable compression performance by default ([#1181](https://github.com/amplitude/Amplitude-TypeScript/issues/1181)) ([c91e192](https://github.com/amplitude/Amplitude-TypeScript/commit/c91e1927a81e4c87b1d25a3494749ce5820a231c))\n\n\n\n\n\n## [1.25.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.25.2...@amplitude/session-replay-browser@1.25.3) (2025-06-30)\n\n\n### Bug Fixes\n\n* **session-replay-browser:** reduces network calls to remote config from many to 1 ([#1175](https://github.com/amplitude/Amplitude-TypeScript/issues/1175)) ([17452c2](https://github.com/amplitude/Amplitude-TypeScript/commit/17452c28e76a4dc7415d634599e30bbb0075dd43))\n\n\n\n\n\n## [1.25.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.25.1...@amplitude/session-replay-browser@1.25.2) (2025-06-26)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.25.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.25.0...@amplitude/session-replay-browser@1.25.1) (2025-06-25)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n# [1.25.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.24.1...@amplitude/session-replay-browser@1.25.0) (2025-06-17)\n\n\n### Features\n\n* **session replay:** dynamically import rrweb ([#1156](https://github.com/amplitude/Amplitude-TypeScript/issues/1156)) ([510cc67](https://github.com/amplitude/Amplitude-TypeScript/commit/510cc67bf04f740940504e3351c39c05d54c5c32))\n\n\n\n\n\n## [1.24.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.24.0...@amplitude/session-replay-browser@1.24.1) (2025-06-17)\n\n\n### Bug Fixes\n\n* **session-replay-browser:** indexeddb open error handling ([#1155](https://github.com/amplitude/Amplitude-TypeScript/issues/1155)) ([cbbda90](https://github.com/amplitude/Amplitude-TypeScript/commit/cbbda90b94426ad9413c935e7298cd4dd1adcc38))\n\n\n\n\n\n# [1.24.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.23.0...@amplitude/session-replay-browser@1.24.0) (2025-06-13)\n\n\n### Features\n\n* **session-replay:** support background colors on blocked elements ([#1153](https://github.com/amplitude/Amplitude-TypeScript/issues/1153)) ([36fcd40](https://github.com/amplitude/Amplitude-TypeScript/commit/36fcd409b996c3c898bedd04ed77c9057ebbf994))\n\n\n\n\n\n# [1.23.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.22.11...@amplitude/session-replay-browser@1.23.0) (2025-06-12)\n\n\n### Features\n\n* **session-replay-browser:** ugc removal poc ([#1062](https://github.com/amplitude/Amplitude-TypeScript/issues/1062)) ([c63fafd](https://github.com/amplitude/Amplitude-TypeScript/commit/c63fafdaea2507a273cd23d8ef56dbe43c5aa1c3))\n\n\n\n\n\n## [1.22.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.22.10...@amplitude/session-replay-browser@1.22.11) (2025-06-11)\n\n\n### Bug Fixes\n\n* **session replay:** add gzip to cdn ([#1150](https://github.com/amplitude/Amplitude-TypeScript/issues/1150)) ([f61e38f](https://github.com/amplitude/Amplitude-TypeScript/commit/f61e38fc37d9a825a0c3f31147631eb1a16546a4))\n\n\n\n\n\n## [1.22.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.22.9...@amplitude/session-replay-browser@1.22.10) (2025-06-03)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.22.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.22.8...@amplitude/session-replay-browser@1.22.9) (2025-06-02)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.22.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.22.7...@amplitude/session-replay-browser@1.22.8) (2025-05-30)\n\n\n### Bug Fixes\n\n* **session-replay:** map the type to the correct sdk plugin ([#1099](https://github.com/amplitude/Amplitude-TypeScript/issues/1099)) ([d1c79c5](https://github.com/amplitude/Amplitude-TypeScript/commit/d1c79c5633c956cbf6599a4b9af83d3ee460df1d))\n\n\n\n\n\n## [1.22.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.22.6...@amplitude/session-replay-browser@1.22.7) (2025-05-27)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.22.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.22.5...@amplitude/session-replay-browser@1.22.6) (2025-05-13)\n\n\n### Bug Fixes\n\n* **analytics-core:** make network observer event callbacks handle exceptions ([#1071](https://github.com/amplitude/Amplitude-TypeScript/issues/1071)) ([baf46e2](https://github.com/amplitude/Amplitude-TypeScript/commit/baf46e22585f58924b801e301db78c7aecda1b4a))\n\n\n### Reverts\n\n* PR 1058 ([#1077](https://github.com/amplitude/Amplitude-TypeScript/issues/1077)) ([e72835e](https://github.com/amplitude/Amplitude-TypeScript/commit/e72835e07ec0318d564439a7ddd47f37b156c6c3))\n\n\n\n\n\n## [1.22.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.22.4...@amplitude/session-replay-browser@1.22.5) (2025-05-07)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.22.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.22.3...@amplitude/session-replay-browser@1.22.4) (2025-05-07)\n\n\n### Bug Fixes\n\n* **session replay:** dynamically import plugin-console-record ([#983](https://github.com/amplitude/Amplitude-TypeScript/issues/983)) ([990def9](https://github.com/amplitude/Amplitude-TypeScript/commit/990def985a06b462ad16b33b811d46bde6f66b01))\n\n\n\n\n\n## [1.22.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.22.2...@amplitude/session-replay-browser@1.22.3) (2025-05-05)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.22.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.22.1...@amplitude/session-replay-browser@1.22.2) (2025-05-02)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.22.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.22.0...@amplitude/session-replay-browser@1.22.1) (2025-05-02)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n# [1.22.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.21.1...@amplitude/session-replay-browser@1.22.0) (2025-04-22)\n\n\n### Features\n\n* **plugin-session-replay-browser:** add an sr instance property ([#1034](https://github.com/amplitude/Amplitude-TypeScript/issues/1034)) ([7159658](https://github.com/amplitude/Amplitude-TypeScript/commit/7159658916008faec6cefacab615cb535dd2562b))\n\n\n\n\n\n## [1.21.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.21.0...@amplitude/session-replay-browser@1.21.1) (2025-04-17)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n# [1.21.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.20.2...@amplitude/session-replay-browser@1.21.0) (2025-04-15)\n\n\n### Features\n\n* **session-replay-browser:** migrate to core v2.x ([#1022](https://github.com/amplitude/Amplitude-TypeScript/issues/1022)) ([7a665d5](https://github.com/amplitude/Amplitude-TypeScript/commit/7a665d55fff89092ed5f2bb94caa1eb2c7efe5b1))\n\n\n\n\n\n## [1.20.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.20.1...@amplitude/session-replay-browser@1.20.2) (2025-04-10)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n## [1.20.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.20.0...@amplitude/session-replay-browser@1.20.1) (2025-03-25)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n\n\n\n\n# [1.20.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.19.4...@amplitude/session-replay-browser@1.20.0) (2025-03-21)\n\n\n### Features\n\n* **session replay:** initial network observers ([#987](https://github.com/amplitude/Amplitude-TypeScript/issues/987)) ([5c648de](https://github.com/amplitude/Amplitude-TypeScript/commit/5c648debbfafbd1ad0721d4b3008a84c1a6eeffe))\n\n\n\n\n\n## [1.19.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.19.3...@amplitude/session-replay-browser@1.19.4) (2025-03-06)\n\n\n### Bug Fixes\n\n* **session replay:** truncate the X-Client-Url to avoid ELB 400 error ([#984](https://github.com/amplitude/Amplitude-TypeScript/issues/984)) ([9cbbb09](https://github.com/amplitude/Amplitude-TypeScript/commit/9cbbb094190a3296e1abff0e2167ee9a8dbc0805))\n\n\n\n\n\n## [1.19.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.19.2...@amplitude/session-replay-browser@1.19.3) (2025-03-04)\n\n\n### Bug Fixes\n\n* **session replay:** reduce chance of recursive loop with console tracking ([a118511](https://github.com/amplitude/Amplitude-TypeScript/commit/a1185118446b6305154c59319f5d947c78315e94))\n\n\n\n\n\n## 1.19.2 (2025-02-28)\n\n\n### Reverts\n\n* Revert \"chore(release): publish\" ([d392f62](https://github.com/amplitude/Amplitude-TypeScript/commit/d392f6290b8bb4dd955d6e6f20b00191679489c4))\n\n\n\n\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.19.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.19.1-beta.0...@amplitude/session-replay-browser@1.19.1) (2025-02-14)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.19.1-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.19.0...@amplitude/session-replay-browser@1.19.1-beta.0) (2025-02-14)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.19.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.18.1...@amplitude/session-replay-browser@1.19.0) (2024-12-17)\n\n### Features\n\n- **session-replay-browser:** WebWorker support for compression\n  ([#932](https://github.com/amplitude/Amplitude-TypeScript/issues/932))\n  ([4ebe04a](https://github.com/amplitude/Amplitude-TypeScript/commit/4ebe04adda714ae02851835c49e6bc224df7f4af))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.18.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.18.0...@amplitude/session-replay-browser@1.18.1) (2024-12-16)\n\n### Bug Fixes\n\n- **session-replay-browser:** prevent finder errors from affecting session replay\n  ([#934](https://github.com/amplitude/Amplitude-TypeScript/issues/934))\n  ([cd5bdfd](https://github.com/amplitude/Amplitude-TypeScript/commit/cd5bdfd534b2b0c824fbb8b9035eaf976c14fdec))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.18.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.17.0...@amplitude/session-replay-browser@1.18.0) (2024-12-13)\n\n### Features\n\n- **session-replay-browser:** support custom urls for remote config and track endpoints.\n  ([#931](https://github.com/amplitude/Amplitude-TypeScript/issues/931))\n  ([af6aa43](https://github.com/amplitude/Amplitude-TypeScript/commit/af6aa43b12fa577b5fa8434065b43e4e94668f0e))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.17.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.16.0...@amplitude/session-replay-browser@1.17.0) (2024-12-06)\n\n### Features\n\n- **session-replay:** supporting string session id\n  ([deecad4](https://github.com/amplitude/Amplitude-TypeScript/commit/deecad4f6a9e5522b5d567f5ff48513c7e2ae880))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.16.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.15.1...@amplitude/session-replay-browser@1.16.0) (2024-12-06)\n\n### Bug Fixes\n\n- **session-replay-browser:** use correct server urls\n  ([b37da79](https://github.com/amplitude/Amplitude-TypeScript/commit/b37da79bfd2a68849194e5bd1bd6e6ed49ae55e5))\n\n### Features\n\n- **analytics-remote-config:** add string type to sessionId for custom session id\n  ([45e131c](https://github.com/amplitude/Amplitude-TypeScript/commit/45e131c8aec630c9db8b9de0059c88cafd519583))\n- **session-replay-browser:** supporting string session id\n  ([633aa04](https://github.com/amplitude/Amplitude-TypeScript/commit/633aa048c7794660eef6b538dfe3b1cecd93b020))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.15.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.15.1-beta.0...@amplitude/session-replay-browser@1.15.1) (2024-10-30)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.15.1-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.15.0...@amplitude/session-replay-browser@1.15.1-beta.0) (2024-10-29)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.15.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.14.3...@amplitude/session-replay-browser@1.15.0) (2024-10-10)\n\n### Features\n\n- **session-replay-browser:** in memory events storage\n  ([#895](https://github.com/amplitude/Amplitude-TypeScript/issues/895))\n  ([85f4fd1](https://github.com/amplitude/Amplitude-TypeScript/commit/85f4fd1adcbc9cdde8d1ea97ead9655acca15461))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.14.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.14.2...@amplitude/session-replay-browser@1.14.3) (2024-10-08)\n\n### Bug Fixes\n\n- **session replay:** add error handling for store\n  ([e7741f9](https://github.com/amplitude/Amplitude-TypeScript/commit/e7741f962322624a4472bc249cedfba6baeea7b4))\n- **session replay:** tests for try/catch on initialize\n  ([8cc09b7](https://github.com/amplitude/Amplitude-TypeScript/commit/8cc09b79fd259572bdd59b4395420daf8a2d0e87))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.14.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.14.1...@amplitude/session-replay-browser@1.14.2) (2024-10-04)\n\n### Bug Fixes\n\n- **session-replay-browser:** make joined config generator immutable\n  ([#890](https://github.com/amplitude/Amplitude-TypeScript/issues/890))\n  ([2489b20](https://github.com/amplitude/Amplitude-TypeScript/commit/2489b20f8453b104427b3cb88127dc643f872c65))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.14.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.14.0...@amplitude/session-replay-browser@1.14.1) (2024-10-02)\n\n### Bug Fixes\n\n- **session-replay-browser:** paranoia fixes for edge cases\n  ([#889](https://github.com/amplitude/Amplitude-TypeScript/issues/889))\n  ([299e22b](https://github.com/amplitude/Amplitude-TypeScript/commit/299e22b382760b411af40180c6d6c64f4286f0fe))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.14.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.13.9...@amplitude/session-replay-browser@1.14.0) (2024-09-24)\n\n### Bug Fixes\n\n- **session replay:** add version option into local config generation\n  ([7993104](https://github.com/amplitude/Amplitude-TypeScript/commit/7993104aa194ffe2282b6640a12a2e6a80089665))\n- **session replay:** only check requestIdleCallback on initialization of recording\n  ([d337e2f](https://github.com/amplitude/Amplitude-TypeScript/commit/d337e2f61563d0d5db3739f05102901e096090d5))\n- **session replay:** update and consolidate tests\n  ([000c2cc](https://github.com/amplitude/Amplitude-TypeScript/commit/000c2cc2678d8ce15a63adeeb2367a2ca335ab29))\n\n### Features\n\n- **session replay:** adding timeout into config\n  ([fd67792](https://github.com/amplitude/Amplitude-TypeScript/commit/fd677929ef772b46e103d002230e87fa2d3b587d))\n- **session replay:** performance config for requestIdleCallback\n  ([df7983e](https://github.com/amplitude/Amplitude-TypeScript/commit/df7983ea1d1a255cdb770a0e8cab23f875b5a2ea))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.13.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.13.8...@amplitude/session-replay-browser@1.13.9) (2024-09-18)\n\n### Bug Fixes\n\n- **session-replay-browser:** add tests to cover the fix\n  ([41984c2](https://github.com/amplitude/Amplitude-TypeScript/commit/41984c2ee8384d93ba9d32d3a4fabd3cf75220bf))\n- **session-replay-browser:** handle exceptions when creating an events manager\n  ([0d1043f](https://github.com/amplitude/Amplitude-TypeScript/commit/0d1043fe5db454e45fd7d3b28fcf9bfb247fa445))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.13.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.13.7...@amplitude/session-replay-browser@1.13.8) (2024-09-10)\n\n### Bug Fixes\n\n- **session-replay-browser:** add api key for scroll call\n  ([#867](https://github.com/amplitude/Amplitude-TypeScript/issues/867))\n  ([9042d2f](https://github.com/amplitude/Amplitude-TypeScript/commit/9042d2fed5db266a03d88e6563c29a33a42d85a3))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.13.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.13.6...@amplitude/session-replay-browser@1.13.7) (2024-08-27)\n\n### Bug Fixes\n\n- **session-replay-browser:** always get device id from the current session identifiers\n  ([a21a99c](https://github.com/amplitude/Amplitude-TypeScript/commit/a21a99c736683194d07bedfde64dde7a8d0a634b))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.13.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.13.5...@amplitude/session-replay-browser@1.13.6) (2024-08-23)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.13.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.13.4...@amplitude/session-replay-browser@1.13.5) (2024-08-19)\n\n### Bug Fixes\n\n- **session-replay-browser:** send proper interaction response\n  ([#854](https://github.com/amplitude/Amplitude-TypeScript/issues/854))\n  ([ffea30a](https://github.com/amplitude/Amplitude-TypeScript/commit/ffea30a0665922d795ab92c666d745e8202ae314))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.13.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.13.3...@amplitude/session-replay-browser@1.13.4) (2024-08-14)\n\n### Bug Fixes\n\n- **session-replay-browser:** support disabling batching for interaction events\n  ([#853](https://github.com/amplitude/Amplitude-TypeScript/issues/853))\n  ([a9a926b](https://github.com/amplitude/Amplitude-TypeScript/commit/a9a926b35f33c11d471fd6102292ae7f101b8f3a))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.13.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.13.2...@amplitude/session-replay-browser@1.13.3) (2024-08-13)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.13.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.13.1...@amplitude/session-replay-browser@1.13.2) (2024-08-13)\n\n### Bug Fixes\n\n- **session replay:** change log level of init warning\n  ([542e10a](https://github.com/amplitude/Amplitude-TypeScript/commit/542e10a054f2dda4d41b12c81fc66a96b500f59f))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.13.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.13.0...@amplitude/session-replay-browser@1.13.1) (2024-08-12)\n\n### Bug Fixes\n\n- add metrics field to remote config fetcher ([#847](https://github.com/amplitude/Amplitude-TypeScript/issues/847))\n  ([2098ca1](https://github.com/amplitude/Amplitude-TypeScript/commit/2098ca1c67b315f322ee3bf6e9720a765e1825d6))\n- **session replay:** increment event count\n  ([6cce459](https://github.com/amplitude/Amplitude-TypeScript/commit/6cce459beefd5b6425dfa89bfed55cdaa30dcf94))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.13.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.12.3...@amplitude/session-replay-browser@1.13.0) (2024-08-06)\n\n### Bug Fixes\n\n- **session replay:** add version and sdk type\n  ([803c8f9](https://github.com/amplitude/Amplitude-TypeScript/commit/803c8f9e99a418939c1793d0106d9c7404c0e22d))\n- **session replay:** allow config for session replay sdk type\n  ([08036c9](https://github.com/amplitude/Amplitude-TypeScript/commit/08036c9e841ceb784473782566254db3bef5c76f))\n- **session replay:** ensure api key is obfuscated in local logs\n  ([e79948c](https://github.com/amplitude/Amplitude-TypeScript/commit/e79948c0301afee45186ecdafa42fcc25bdee065))\n- **session replay:** move removeInvalidSelectorsFromPrivacyConfig to joined config class\n  ([5eb5f4f](https://github.com/amplitude/Amplitude-TypeScript/commit/5eb5f4f9a7445399b799cae705bb0cd36aefbacd))\n- **session replay:** pr feedback\n  ([48c2ffb](https://github.com/amplitude/Amplitude-TypeScript/commit/48c2ffb50bf01393a4512cb4a59200577d6df019))\n- **session replay:** send library header for version and type of sdk\n  ([b2fedfc](https://github.com/amplitude/Amplitude-TypeScript/commit/b2fedfce3284cc436e9c87d829dc127b88d047b5))\n\n### Features\n\n- **session replay:** add more logging to record and event lifecycle\n  ([20ddaa6](https://github.com/amplitude/Amplitude-TypeScript/commit/20ddaa6a0426c1fa9755b9cde4b1f6110d39d130))\n- **session replay:** adding storage size to rrweb custom event\n  ([c53ab46](https://github.com/amplitude/Amplitude-TypeScript/commit/c53ab46892b109aae7c96cf7cd14e13c47e14b53))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.12.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.12.2...@amplitude/session-replay-browser@1.12.3) (2024-08-02)\n\n### Bug Fixes\n\n- **session-replay-browser:** update rrweb version to 2.0.0-alpha.19 to fix duplicate text\n  ([#836](https://github.com/amplitude/Amplitude-TypeScript/issues/836))\n  ([4ca6078](https://github.com/amplitude/Amplitude-TypeScript/commit/4ca607848ec8b114f9a8c21e840430f52d81d438))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.12.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.12.1...@amplitude/session-replay-browser@1.12.2) (2024-08-01)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.12.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.12.0...@amplitude/session-replay-browser@1.12.1) (2024-07-30)\n\n### Bug Fixes\n\n- **session-replay-browser:** we need to rerun build for the plugin or the version changes won't update\n  ([#826](https://github.com/amplitude/Amplitude-TypeScript/issues/826))\n  ([61deb3b](https://github.com/amplitude/Amplitude-TypeScript/commit/61deb3bd5e2e72353066bc4c16ab4139984a3f7d))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.12.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.11.5...@amplitude/session-replay-browser@1.12.0) (2024-07-29)\n\n### Features\n\n- **session-replay-browser:** support debug info in session replay SDK\n  ([#825](https://github.com/amplitude/Amplitude-TypeScript/issues/825))\n  ([0da5bfa](https://github.com/amplitude/Amplitude-TypeScript/commit/0da5bfaadd6db0efff9d4562b610ecbf841ac24e))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.11.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.11.4...@amplitude/session-replay-browser@1.11.5) (2024-07-25)\n\n### Bug Fixes\n\n- **session replay:** restart recording on focus\n  ([deec404](https://github.com/amplitude/Amplitude-TypeScript/commit/deec4043f22086ab7f71c9585549d18fc36cb9a9))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.11.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.11.3...@amplitude/session-replay-browser@1.11.4) (2024-07-25)\n\n### Bug Fixes\n\n- **session replay:** remove focus/blur handling\n  ([b759a96](https://github.com/amplitude/Amplitude-TypeScript/commit/b759a96c9dda9bef5780978b36f98196e331a69f))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.11.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.11.2...@amplitude/session-replay-browser@1.11.3) (2024-07-24)\n\n### Bug Fixes\n\n- **session replay:** ignore focus should allow recording to continue as well\n  ([0dd3480](https://github.com/amplitude/Amplitude-TypeScript/commit/0dd34805d12c00c93a5e3d26e054f50bdbe1f96d))\n- **session replay:** set sample rate if it is 0 as well\n  ([37cb163](https://github.com/amplitude/Amplitude-TypeScript/commit/37cb163c98fb7c692eb8e00556f21c2402044f61))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.11.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.11.1...@amplitude/session-replay-browser@1.11.2) (2024-07-23)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.11.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.11.0...@amplitude/session-replay-browser@1.11.1) (2024-07-23)\n\n### Bug Fixes\n\n- **session-replay-browser:** remote config failure handling\n  ([#816](https://github.com/amplitude/Amplitude-TypeScript/issues/816))\n  ([1adc3a4](https://github.com/amplitude/Amplitude-TypeScript/commit/1adc3a471c61b034b1c58cd96357040af41bf5a4))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.11.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.10.0...@amplitude/session-replay-browser@1.11.0) (2024-07-05)\n\n### Features\n\n- **session-replay-browser:** scroll events support\n  ([#798](https://github.com/amplitude/Amplitude-TypeScript/issues/798))\n  ([60741ec](https://github.com/amplitude/Amplitude-TypeScript/commit/60741ec17fd38263658897450ac297f55c329c35))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.10.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.9.4...@amplitude/session-replay-browser@1.10.0) (2024-07-01)\n\n### Features\n\n- **session-replay-browser:** support higher granularity sample rate\n  ([#797](https://github.com/amplitude/Amplitude-TypeScript/issues/797))\n  ([9dead38](https://github.com/amplitude/Amplitude-TypeScript/commit/9dead38a017a74f20608fa1a7c23ed3a4857f29f))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.9.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.9.3...@amplitude/session-replay-browser@1.9.4) (2024-06-25)\n\n### Bug Fixes\n\n- **session replay:** export options type and change log to warn\n  ([156d6b1](https://github.com/amplitude/Amplitude-TypeScript/commit/156d6b14975e03e68effb967fcb6899f1b7448a9))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.9.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.9.2...@amplitude/session-replay-browser@1.9.3) (2024-06-24)\n\n### Bug Fixes\n\n- **session replay:** ensure enable is called with logLevel=0\n  ([cf37c04](https://github.com/amplitude/Amplitude-TypeScript/commit/cf37c042520dbd64e20f77ef6c345ad20ac0a7b5))\n- **session replay:** fix logger for standalone\n  ([cc9cbef](https://github.com/amplitude/Amplitude-TypeScript/commit/cc9cbefa19a9305a85743015e2fc21fdfe457716))\n- **session-replay-browser:** remove @medv/finder as a dependency\n  ([#791](https://github.com/amplitude/Amplitude-TypeScript/issues/791))\n  ([7617929](https://github.com/amplitude/Amplitude-TypeScript/commit/761792925fa0abb7b879fc3deb0c23d2ff23fca0))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.9.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.9.1...@amplitude/session-replay-browser@1.9.2) (2024-06-24)\n\n### Bug Fixes\n\n- **session-replay-browser:** add scroll to click event\n  ([#789](https://github.com/amplitude/Amplitude-TypeScript/issues/789))\n  ([74a720a](https://github.com/amplitude/Amplitude-TypeScript/commit/74a720a9c4787374c0fdcc85e85cd389269d5b4f))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.9.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.9.0...@amplitude/session-replay-browser@1.9.1) (2024-06-17)\n\n### Bug Fixes\n\n- **session-replay-browser:** move rimraf from postinstall to build\n  ([#777](https://github.com/amplitude/Amplitude-TypeScript/issues/777))\n  ([9df2a6c](https://github.com/amplitude/Amplitude-TypeScript/commit/9df2a6c97b860b6b964b9178b5dbea9a8c514cd1))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.9.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.8.0...@amplitude/session-replay-browser@1.9.0) (2024-06-17)\n\n### Features\n\n- **session-replay-browser:** adds capability to track click events in session replay\n  ([#776](https://github.com/amplitude/Amplitude-TypeScript/issues/776))\n  ([6eee2b9](https://github.com/amplitude/Amplitude-TypeScript/commit/6eee2b9b9970ebaf18525f71b82de96ea9687862))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.8.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.7.0...@amplitude/session-replay-browser@1.8.0) (2024-06-12)\n\n### Features\n\n- **session replay:** add ability to set inline stylesheets to false\n  ([f78b0c9](https://github.com/amplitude/Amplitude-TypeScript/commit/f78b0c9a5bdd6803119292e54acf6b1b1c3c7524))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.7.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.6.1...@amplitude/session-replay-browser@1.7.0) (2024-06-11)\n\n### Features\n\n- **analytics-remote-config:** add fetchTime ([#768](https://github.com/amplitude/Amplitude-TypeScript/issues/768))\n  ([a334676](https://github.com/amplitude/Amplitude-TypeScript/commit/a334676da68d58dc04d23723bc0252c53919beeb))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.6.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.6.0...@amplitude/session-replay-browser@1.6.1) (2024-06-07)\n\n### Bug Fixes\n\n- **session replay:** add tests and address comments\n  ([e8cd8cf](https://github.com/amplitude/Amplitude-TypeScript/commit/e8cd8cfd598a3d43193505398b0639c8c11e0135))\n- **session replay:** rethrow external errors and fix block selectors\n  ([031afdb](https://github.com/amplitude/Amplitude-TypeScript/commit/031afdbbd46fd011fd32d7d2216e7df1a3a6c6ac))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.6.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.5.2...@amplitude/session-replay-browser@1.6.0) (2024-06-07)\n\n### Features\n\n- **session-replay-browser:** additional privacy configs\n  ([#756](https://github.com/amplitude/Amplitude-TypeScript/issues/756))\n  ([4812beb](https://github.com/amplitude/Amplitude-TypeScript/commit/4812bebeb5c31c1a37eef77687ed50051f170959))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.5.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.5.2-beta.0...@amplitude/session-replay-browser@1.5.2) (2024-06-06)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.5.2-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.5.1...@amplitude/session-replay-browser@1.5.2-beta.0) (2024-06-06)\n\n### Bug Fixes\n\n- **session replay:** add error handling for indexeddb\n  ([bffa884](https://github.com/amplitude/Amplitude-TypeScript/commit/bffa8848a6bcb2ed20c9dd4a64559546f918991b))\n- **session replay:** try catch for keyval errors\n  ([92b071c](https://github.com/amplitude/Amplitude-TypeScript/commit/92b071cf0b3b85df78aeef8a0276070474471c41))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.5.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.5.0...@amplitude/session-replay-browser@1.5.1) (2024-05-28)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.5.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.4.0...@amplitude/session-replay-browser@1.5.0) (2024-05-16)\n\n### Features\n\n- **session-replay-browser:** fetch privacy configs remotely and join with local\n  ([c224041](https://github.com/amplitude/Amplitude-TypeScript/commit/c22404195e894c85d1d463b3b6d14e52beeeef50))\n- **session-replay-browser:** typing fixes and PR changes\n  ([882d4dc](https://github.com/amplitude/Amplitude-TypeScript/commit/882d4dc3702dd833cfb6c9a4d0941d2955c44389))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.4.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.3.2...@amplitude/session-replay-browser@1.4.0) (2024-05-16)\n\n### Bug Fixes\n\n- **session replay:** add batching logic for promises\n  ([602f0c9](https://github.com/amplitude/Amplitude-TypeScript/commit/602f0c99729cf038a1b97a78cff8c4d4dc3ee74a))\n\n### Features\n\n- **session replay:** implement custom store using idb package\n  ([b92d511](https://github.com/amplitude/Amplitude-TypeScript/commit/b92d511af7c58e1e3d51c7e950c1965f224b7d37))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.3.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.3.1...@amplitude/session-replay-browser@1.3.2) (2024-05-15)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.3.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.3.0...@amplitude/session-replay-browser@1.3.1) (2024-05-10)\n\n### Bug Fixes\n\n- **session replay:** add a timeout to remote config fetch\n  ([66ca51e](https://github.com/amplitude/Amplitude-TypeScript/commit/66ca51e22e2a9fc54bed18efb68398a29c158794))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.3.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.2.8...@amplitude/session-replay-browser@1.3.0) (2024-05-06)\n\n### Bug Fixes\n\n- **session replay:** add eu remote config url\n  ([6fc92ce](https://github.com/amplitude/Amplitude-TypeScript/commit/6fc92ceb8404635ab27a94e44bc26b8b82226b13))\n- **session replay:** set captureEnabled to true if api fails\n  ([51b4c87](https://github.com/amplitude/Amplitude-TypeScript/commit/51b4c879b633daf4c21b558965179a28faefdaca))\n- **session replay:** support undefined session id in initialization\n  ([8befdc1](https://github.com/amplitude/Amplitude-TypeScript/commit/8befdc1e982356c217bc5c2f9b50c11e6415072a))\n- **session replay:** use correct url and other fixes from bug bash\n  ([438d692](https://github.com/amplitude/Amplitude-TypeScript/commit/438d692b96d04ba945aaf4b1d44d58d7f040cb35))\n\n### Features\n\n- **session replay:** add ability to wait for setSessionId process to complete\n  ([a60b0c9](https://github.com/amplitude/Amplitude-TypeScript/commit/a60b0c9f3fe668c87d82d75a4f566262107e748c))\n- **session replay:** create joined config class and generate config upon init and setSessionId\n  ([90b341b](https://github.com/amplitude/Amplitude-TypeScript/commit/90b341bf545877401d34eaf0b46b77167ced3c1f))\n- **session replay:** introduce remote config fetch class\n  ([5c0e038](https://github.com/amplitude/Amplitude-TypeScript/commit/5c0e038a8a1a53408ae582e2acbe12d7d27b773b))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.2.7...@amplitude/session-replay-browser@1.2.8) (2024-04-23)\n\n### Bug Fixes\n\n- **session replay:** throw error for styled-components\n  ([0a53e33](https://github.com/amplitude/Amplitude-TypeScript/commit/0a53e33cf7fb50f5c8bde7bc6627625660ae9a4d))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.2.6...@amplitude/session-replay-browser@1.2.7) (2024-04-22)\n\n### Bug Fixes\n\n- **session replay:** staging URL remove extra slash\n  ([15550fb](https://github.com/amplitude/Amplitude-TypeScript/commit/15550fb732ed3d65cd645c3acb3b11260b401cb8))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.2.5...@amplitude/session-replay-browser@1.2.6) (2024-04-18)\n\n### Bug Fixes\n\n- **session replay:** prevent multiple of the same sequences from being added to send queue\n  ([2c73dfd](https://github.com/amplitude/Amplitude-TypeScript/commit/2c73dfdf5c2d6d6a8dc9ae958a767394d4e5e341))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.2.4...@amplitude/session-replay-browser@1.2.5) (2024-04-15)\n\n### Bug Fixes\n\n- **session replay:** remove event listeners on init)\n  ([67064c0](https://github.com/amplitude/Amplitude-TypeScript/commit/67064c0e0e160d1d8d89016b9e804d311168d217))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.2.3...@amplitude/session-replay-browser@1.2.4) (2024-04-12)\n\n### Bug Fixes\n\n- **session replay:** always stop recording before starting anew\n  ([e4f6033](https://github.com/amplitude/Amplitude-TypeScript/commit/e4f6033a473a74b671b60469ecf612f4351547f9))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.2.2...@amplitude/session-replay-browser@1.2.3) (2024-04-09)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.2.1...@amplitude/session-replay-browser@1.2.2) (2024-04-08)\n\n### Bug Fixes\n\n- **session replay:** fix this binding for cleanup store\n  ([d368b6a](https://github.com/amplitude/Amplitude-TypeScript/commit/d368b6a306ffb085485fd9a2e0a3139272168e15))\n- **session replay:** remove unused comments\n  ([d535c45](https://github.com/amplitude/Amplitude-TypeScript/commit/d535c4509e6d19de3fc7575ca6d97725e6adfb47))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.2.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.2.0...@amplitude/session-replay-browser@1.2.1) (2024-04-02)\n\n### Bug Fixes\n\n- **session replay:** expose deviceid on setSessionId type\n  ([4b7dd56](https://github.com/amplitude/Amplitude-TypeScript/commit/4b7dd56572aefc14ba597fba6420a05c23c950c9))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.2.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.1.0...@amplitude/session-replay-browser@1.2.0) (2024-03-26)\n\n### Features\n\n- **session replay:** add argument to setSessionId to allow for updating deviceId\n  ([5e5099e](https://github.com/amplitude/Amplitude-TypeScript/commit/5e5099eac768c1243f858a6be185db2ada8c8358))\n- **session replay:** update README\n  ([4c99e3d](https://github.com/amplitude/Amplitude-TypeScript/commit/4c99e3d0a00e2409101cf654a67e8a5420ccc447))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.1.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.1.0-beta.0...@amplitude/session-replay-browser@1.1.0) (2024-03-14)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [1.1.0-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.0.2...@amplitude/session-replay-browser@1.1.0-beta.0) (2024-03-13)\n\n### Features\n\n- **session replay:** fix event tagging\n  ([1373265](https://github.com/amplitude/Amplitude-TypeScript/commit/1373265b6e6ada9b354646aa5118d3eefa791511))\n- **session replay:** improve initialization\n  ([dbdd2fd](https://github.com/amplitude/Amplitude-TypeScript/commit/dbdd2fd82fa9e5d222d6ac83b8ec2cbeb5acc071))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.0.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@1.0.1...@amplitude/session-replay-browser@1.0.2) (2024-02-10)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.0.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@0.8.0-beta.0...@amplitude/session-replay-browser@1.0.1) (2024-02-07)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.8.0-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@0.7.2...@amplitude/session-replay-browser@0.8.0-beta.0) (2024-02-05)\n\n### Bug Fixes\n\n- **session replay:** strict undefined and type check for sample\n  ([d9b96ba](https://github.com/amplitude/Amplitude-TypeScript/commit/d9b96bac0a4550aa02a8e038bdd0d14a963b1ebc))\n\n### Features\n\n- session seplay debug mode\n  ([98654dd](https://github.com/amplitude/Amplitude-TypeScript/commit/98654dd7358b393c542fada1b46d570d8fe213f7))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.7.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@0.7.1...@amplitude/session-replay-browser@0.7.2) (2024-01-05)\n\n### Bug Fixes\n\n- **session replay:** additional undefined check for events\n  ([7525152](https://github.com/amplitude/Amplitude-TypeScript/commit/7525152254edccc590cee26a4752e8fe4bff594c))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.7.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@0.7.0...@amplitude/session-replay-browser@0.7.1) (2023-12-19)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.7.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@0.6.0...@amplitude/session-replay-browser@0.7.0) (2023-12-06)\n\n### Features\n\n- convert session replay plugin to be a destination plugin with flush support\n  ([#633](https://github.com/amplitude/Amplitude-TypeScript/issues/633))\n  ([bfa643f](https://github.com/amplitude/Amplitude-TypeScript/commit/bfa643fa92d3cc6b84e924d7a22f502cee289035))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.6.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@0.5.0...@amplitude/session-replay-browser@0.6.0) (2023-12-05)\n\n### Features\n\n- expose rrweb blockselector\n  ([09b33b7](https://github.com/amplitude/Amplitude-TypeScript/commit/09b33b71ab885e8c954fe28c1e1e54360784755b))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.5.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@0.5.0-beta.0...@amplitude/session-replay-browser@0.5.0) (2023-11-16)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.5.0-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@0.4.0...@amplitude/session-replay-browser@0.5.0-beta.0) (2023-11-10)\n\n### Features\n\n- **session replay:** remove recording terms\n  ([83d156a](https://github.com/amplitude/Amplitude-TypeScript/commit/83d156a4d2bf077fa023faad0ef514a4dd074b6f))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.4.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@0.3.1...@amplitude/session-replay-browser@0.4.0) (2023-11-02)\n\n### Bug Fixes\n\n- **session replay:** testing changes for sessionReplayId\n  ([60f6b04](https://github.com/amplitude/Amplitude-TypeScript/commit/60f6b04bbe5069f97279c67098ef6a8df259b678))\n\n### Features\n\n- add session replay ID generic identifier to init/turnover\n  ([03a67c9](https://github.com/amplitude/Amplitude-TypeScript/commit/03a67c97e6c5589662be0a1a7e4cd7a725774d85))\n- **session replay:** error check for session replay id generation\n  ([b602627](https://github.com/amplitude/Amplitude-TypeScript/commit/b60262785f7adc02eb89e3f7e6df2e31641fe54f))\n- **session replay:** parse sessionReplayId for sessionId and deviceId\n  ([990ddaf](https://github.com/amplitude/Amplitude-TypeScript/commit/990ddaf102465e52d84e496d280c8aada5f94944))\n- **session replay:** remove session replay id interface and expose sr properties to plugin\n  ([a7ea04a](https://github.com/amplitude/Amplitude-TypeScript/commit/a7ea04a9c03a0b69a1cab4462d8e1cae2656c79f))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.3.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@0.3.0...@amplitude/session-replay-browser@0.3.1) (2023-10-26)\n\n### Bug Fixes\n\n- **session replay:** use internal fork of rrweb\n  ([8f96d1c](https://github.com/amplitude/Amplitude-TypeScript/commit/8f96d1ceb7d31dabd2fc8c34aba3d01cfa886f79))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.3.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@0.2.5...@amplitude/session-replay-browser@0.3.0) (2023-10-17)\n\n### Features\n\n- **session replay:** add metadata to headers\n  ([222920a](https://github.com/amplitude/Amplitude-TypeScript/commit/222920a52c34cce5f4b111f9f2768836b248dcdb))\n- **session replay:** add metadata to headers\n  ([6d15bfb](https://github.com/amplitude/Amplitude-TypeScript/commit/6d15bfb5daccd52d1dc4f7ae1ead8d5f4b2bf6a2))\n- **session replay:** add metadata to headers\n  ([d4a1b33](https://github.com/amplitude/Amplitude-TypeScript/commit/d4a1b33930bb8d20dd28a10ff9075854348b5272))\n- **session replay:** change non-actionable errors to warnings\n  ([e4debe2](https://github.com/amplitude/Amplitude-TypeScript/commit/e4debe25165311199f69b95a765fb6de3852f219))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.2.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@0.2.4...@amplitude/session-replay-browser@0.2.5) (2023-09-27)\n\n### Bug Fixes\n\n- **session replay:** opt out should take effect immediately\n  ([7b3b571](https://github.com/amplitude/Amplitude-TypeScript/commit/7b3b571e38a9bf968581cabbff50c6c1fff7251f))\n- **session replay:** test identity store false case and opt out in middle of recording\n  ([938b5d5](https://github.com/amplitude/Amplitude-TypeScript/commit/938b5d524780385bff04d5a51588407712d6db66))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.2.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@0.2.3...@amplitude/session-replay-browser@0.2.4) (2023-09-21)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.2.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@0.2.2...@amplitude/session-replay-browser@0.2.3) (2023-09-18)\n\n### Bug Fixes\n\n- **session replay:** Update endpoint for session replay and only retry for 5xx responses\n  ([60df827](https://github.com/amplitude/Amplitude-TypeScript/commit/60df827d56f773d919eba09e1d70132ff3ed6670))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.2.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@0.2.1...@amplitude/session-replay-browser@0.2.2) (2023-09-12)\n\n### Bug Fixes\n\n- **session replay:** remove beta tag from package.json to update public facing version\n  ([fa72e9b](https://github.com/amplitude/Amplitude-TypeScript/commit/fa72e9bacc6132ef37122f0a63419150f2f690e2))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.2.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@0.2.0...@amplitude/session-replay-browser@0.2.1) (2023-09-12)\n\n### Bug Fixes\n\n- **session replay:** expose getSessionReplayProperties externally\n  ([597201a](https://github.com/amplitude/Amplitude-TypeScript/commit/597201a04b5c7c51b3f047caaf39986af6fb6534))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.2.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@0.1.1...@amplitude/session-replay-browser@0.2.0) (2023-09-11)\n\n### Features\n\n- **session replay:** add getSessionReplayProperties method\n  ([ab6c064](https://github.com/amplitude/Amplitude-TypeScript/commit/ab6c0643e6a2b869cc10a719c2edec25b2de2e25))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.1.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/session-replay-browser@0.1.0...@amplitude/session-replay-browser@0.1.1) (2023-09-08)\n\n**Note:** Version bump only for package @amplitude/session-replay-browser\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# 0.1.0 (2023-08-25)\n\n### Bug Fixes\n\n- **session replay:** pr feedback\n  ([4fb16f8](https://github.com/amplitude/Amplitude-TypeScript/commit/4fb16f8b15082af6db1d01ebc05c0c1f7b2800d2))\n- **session replay:** update documentation\n  ([78ad90a](https://github.com/amplitude/Amplitude-TypeScript/commit/78ad90a58053d4971bf54231bcf96b42ff90b6b1))\n- **session replay:** update log message\n  ([777e3d8](https://github.com/amplitude/Amplitude-TypeScript/commit/777e3d85f3bd6c15dce9a6ba536a4fa211000372))\n- **session replay:** use AmplitudeReturn type for async init\n  ([5b332e4](https://github.com/amplitude/Amplitude-TypeScript/commit/5b332e44eeec0c016390501ebf87c42b679baa52))\n\n### Features\n\n- **session replay:** introduce standalone version of session replay package\n  ([8c53ef1](https://github.com/amplitude/Amplitude-TypeScript/commit/8c53ef1f792e597bbe497dfe6c668e53702586bf))\n"
  },
  {
    "path": "packages/session-replay-browser/README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://amplitude.com\" target=\"_blank\" align=\"center\">\n    <img src=\"https://static.amplitude.com/lightning/46c85bfd91905de8047f1ee65c7c93d6fa9ee6ea/static/media/amplitude-logo-with-text.4fb9e463.svg\" width=\"280\">\n  </a>\n  <br />\n</p>\n\n# @amplitude/session-replay-browser\n\nOfficial Session Replay SDK\n\n## Installation\n\nThis package is published on NPM registry and is available to be installed using npm and yarn.\n\n```sh\n# npm\nnpm install @amplitude/session-replay-browser\n\n# yarn\nyarn add @amplitude/session-replay-browser\n```\n\n## Usage\n\nThis SDK provides access to the Amplitude Session Replay product.\n\nThis plugin requires that default tracking for sessions is enabled. If default tracking for sessions is not enabled in the config, the plugin will automatically enable it.\n\n### 1. Import Amplitude packages\n\n* `@amplitude/session-replay-browser`\n\n```typescript\nimport * as sessionReplay from '@amplitude/session-replay-browser';\n```\n\n### 2. Initialize session replay collection\n\nThe SDK must be configured via the following code. This call kicks off collection of replays for the user.\n\n```typescript\nsessionReplay.init(API_KEY, {\n  deviceId: DEVICE_ID,\n  sessionId: SESSION_ID,\n  sampleRate: 0.5,\n});\n```\n\n### 3. Evaluate targeting (optional)\nAny event that occurs within the span of a session replay must be passed to the SDK to evaluate against targeting conditions. This should be done *before* step 4, getting the event properties. If you are not using the targeting condition logic provided via the Amplitude UI, this step is not required.\n```typescript\nconst sessionTargetingMatch = sessionReplay.evaluateTargetingAndCapture({ event: {\n  event_type: EVENT_NAME,\n  time: EVENT_TIMESTAMP,\n  event_properties: eventProperties\n} });\n```\n\n### 4. Get session replay event properties\nAny event that occurs within the span of a session replay must be tagged with properties that signal to Amplitude to include it in the scope of the replay. The following shows an example of how to use the properties\n```typescript\nconst sessionReplayProperties = sessionReplay.getSessionReplayProperties();\ntrack(EVENT_NAME, {\n  ...eventProperties,\n  ...sessionReplayProperties\n})\n```\n\n### 5. Update session id\nAny time that the session id for the user changes, the session replay SDK must be notified of that change. Update the session id via the following method:\n```typescript\nsessionReplay.setSessionId(UNIX_TIMESTAMP)\n```\nYou can optionally pass a new device id as a second argument as well:\n```typescript\nsessionReplay.setSessionId(UNIX_TIMESTAMP, deviceId)\n```\n\n### 6. Shutdown (optional)\nIf at any point you would like to discontinue collection of session replays, for example in a part of your application where you would not like sessions to be collected, you can use the following method to stop collection and remove collection event listeners.\n```typescript\nsessionReplay.shutdown()\n```\n\n#### Options\n\n|Name|Type|Required|Default|Description|\n|-|-|-|-|-|\n|`deviceId`|`string`|Yes|`undefined`|Sets an identifier for the device running your application.|\n|`sessionId`|`number`|Yes|`undefined`|Sets an identifier for the users current session. The value must be in milliseconds since epoch (Unix Timestamp).|\n|`sampleRate`|`number`|No|`0`|Use this option to control how many sessions will be selected for replay collection. A selected session will be collected for replay, while sessions that are not selected will not.  <br></br>The number should be a decimal between 0 and 1, ie `0.01`, representing the fraction of sessions you would like to have randomly selected for replay collection. Over a large number of sessions, `0.01` would select `1%` of those sessions.|\n|`optOut`|`boolean`|No|`false`|Sets permission to collect replays for sessions. Setting a value of true prevents Amplitude from collecting session replays.|\n|`flushMaxRetries`|`number`|No|`2`|Sets the maximum number of retries for failed upload attempts. This is only applicable to retryable errors.|\n|`logLevel`|`number`|No|`LogLevel.Warn`|`LogLevel.None` or `LogLevel.Error` or `LogLevel.Warn` or `LogLevel.Verbose` or `LogLevel.Debug`. Sets the log level.|\n|`loggerProvider`|`Logger`|No|`Logger`|Sets a custom loggerProvider class from the Logger to emit log messages to desired destination.|\n|`serverZone`|`string`|No|`US`|EU or US. Sets the Amplitude server zone. Set this to EU for Amplitude projects created in EU data center.|\n|`privacyConfig`|`object`|No|`undefined`|Supports advanced masking configs with CSS selectors.|\n|`debugMode`|`boolean`|No|`false`|Adds additional debug event property to help debug instrumentation issues (such as mismatching apps). Only recommended for debugging initial setup, and not recommended for production.|\n|`configServerUrl`|`string`|No|`undefined`|Specifies the endpoint URL to fetch remote configuration. If provided, it overrides the default server zone configuration.|\n|`trackServerUrl`|`string`|No|`undefined`|Specifies the endpoint URL for sending session replay data. If provided, it overrides the default server zone configuration.|\n|`shouldInlineStylesheet`|`boolean`|No|`true`|If stylesheets are inlined, the contents of the stylesheet will be stored. During replay, the stored stylesheet will be used instead of attempting to fetch it remotely. This prevents replays from appearing broken due to missing stylesheets. Note: Inlining stylesheets may not work in all cases. If this is `undefined` stylesheets will be inlined.|\n|`storeType`|`string`|No|`idb`|Specifies how replay events should be stored. `idb` uses IndexedDB to persist replay events when all events cannot be sent during capture. `memory` stores replay events only in memory, meaning events are lost when the page is closed. If IndexedDB is unavailable, the system falls back to `memory`.|\n|`performanceConfig.enabled`|`boolean`|No|`true`|If enabled, event compression will be deferred to occur during the browser's idle periods.|\n|`performanceConfig.timeout`|`number`|No|`undefined`|Optional timeout in milliseconds for the `requestIdleCallback` API. If specified, this value will be used to set a maximum time for the browser to wait before executing the deferred compression task, even if the browser is not idle.|\n|`useWebWorker`|`boolean`|No|`false`|If true, the SDK will compress replay events using a web worker. This offloads compression to a separate thread, improving performance on the main thread.|\n|`crossOriginIframes.enabled`|`boolean`|No|`false`|Enables cross-origin iframe recording. Must be set to `true` on both the parent page and each child iframe page. See [Cross-Origin Iframe Recording](#cross-origin-iframe-recording).|\n|`crossOriginIframes.coordinateChildren`|`boolean`|No|`true`|When `true`, the parent SDK automatically sends start/stop signals to child iframes via `postMessage`. Set to `false` to manage child recording lifecycle yourself.|\n\n## Cross-Origin Iframe Recording\n\nThe SDK can capture events inside cross-origin `<iframe>` elements and merge them into the parent page's session replay.\n\n### How it works\n\nBoth the parent page and each iframe page must load the SDK with `crossOriginIframes.enabled: true`. The parent SDK coordinates recording across all child iframes using `postMessage` signals and rrweb's built-in cross-origin relay.\n\n```\nParent page (yoursite.com)\n┌─────────────────────────────────────────────────────────────────┐\n│  sessionReplay.init(API_KEY, { crossOriginIframes: { enabled: true } })\n│                                                                   │\n│  CrossOriginIframeCoordinator                                     │\n│  ┌────────────────────────┐                                       │\n│  │ MutationObserver       │  postMessage(\"start\") ──────────────► │\n│  │ watches for <iframe>   │                                       │\n│  │ additions/removals     │  postMessage(\"stop\")  ──────────────► │\n│  └────────────────────────┘                                       │\n│                                                                   │\n│  rrweb (recordCrossOriginIframes: true)                           │\n│  ◄─────────────── child rrweb events relayed via postMessage ──── │\n│  Merges child events into parent snapshot stream                  │\n└─────────────────────────────────────────────────────────────────┘\n         │ postMessage(\"start\" / \"stop\")\n         ▼\nChild iframe page (payments.example.com)\n┌─────────────────────────────────────────────────────────────────┐\n│  sessionReplay.init(API_KEY, { crossOriginIframes: { enabled: true } })\n│                                                                   │\n│  isInIframe() === true → child mode                               │\n│  listenForParentSignals()                                         │\n│  ┌──────────────────────────────────┐                            │\n│  │ Waits for \"start\" signal         │                            │\n│  │   → initialises rrweb recording  │                            │\n│  │ On \"stop\" signal                 │                            │\n│  │   → stops rrweb, flushes events  │                            │\n│  └──────────────────────────────────┘                            │\n│                                                                   │\n│  rrweb events ──► postMessage relay ──► parent rrweb             │\n└─────────────────────────────────────────────────────────────────┘\n```\n\nChild events are serialized by the child page's own rrweb instance and relayed to the parent via `postMessage`. The parent rrweb stream stores them inline, so the replay viewer can reconstruct both frames from a single session.\n\n### Setup\n\n**Parent page:**\n```typescript\nsessionReplay.init(API_KEY, {\n  deviceId: DEVICE_ID,\n  sessionId: SESSION_ID,\n  crossOriginIframes: { enabled: true },\n});\n```\n\n**Child iframe page** (must also load the SDK):\n```typescript\nsessionReplay.init(API_KEY, {\n  deviceId: DEVICE_ID,\n  sessionId: SESSION_ID,\n  crossOriginIframes: { enabled: true },\n});\n```\n\nThe child SDK detects it is running inside an iframe and automatically enters child mode — it will wait for a start signal from the parent rather than begin recording immediately.\n\n### Options\n\n| Name | Type | Required | Default | Description |\n|-|-|-|-|-|\n| `crossOriginIframes.enabled` | `boolean` | Yes | — | Enables cross-origin iframe recording on both parent and child pages. |\n| `crossOriginIframes.coordinateChildren` | `boolean` | No | `true` | When `true`, the parent SDK sends start/stop signals to child iframes and keeps their recording lifecycle in sync. Set to `false` to manage child recording yourself. |\n\n### Privacy\n\nThe child page's rrweb instance performs its own DOM serialisation. The parent's privacy config (mask levels, block selectors, etc.) does **not** automatically apply inside the iframe — configure privacy settings independently on the child page.\n\n### Limitations\n\n- **Third-party iframes** (e.g. Stripe, Google Maps) cannot be captured. Both the parent and child pages must load the SDK with `crossOriginIframes.enabled: true`.\n- `coordinateChildren: false` opts out of the coordinator; in this mode the child SDK will not start recording until you manage its lifecycle directly.\n\n## Network Request Capture\n\nThe SDK can capture network requests made via `fetch` and include them as events in the session replay. This is opt-in and disabled by default.\n\n### Basic setup\n\nEnable network capture via remote configuration by setting `sr_logging_config.network.enabled: true`. No code changes are required beyond the standard SDK initialization.\n\n### Capturing request and response bodies\n\nBody capture is a separate opt-in within network capture. To enable it, set `body.request` and/or `body.response` in the network config:\n\n```typescript\n// This is configured server-side via sr_logging_config, not in the SDK init call.\n// The shape of the remote config that enables body capture:\n{\n  sr_logging_config: {\n    network: {\n      enabled: true,\n      body: {\n        request: true,   // capture fetch request bodies\n        response: true,  // capture fetch response bodies\n        maxBodySizeBytes: 10240, // optional, defaults to 10KB\n      }\n    }\n  }\n}\n```\n\n#### Behavior\n\n- **Request bodies**: Captured for `string`, `URLSearchParams`, and `FormData` body types. `Blob`, `ArrayBuffer`, and `ReadableStream` bodies are skipped.\n- **Response bodies**: Captured after the response is received. Binary content types (`image/*`, `audio/*`, `video/*`, `application/octet-stream`, `font/*`) are skipped and the event will have `responseBodyStatus: 'skipped_binary'`.\n- **Truncation**: Bodies exceeding `maxBodySizeBytes` are truncated to fit within the limit (byte-accurate for multi-byte characters). The event will have `responseBodyStatus: 'truncated'`.\n- **Errors**: If reading the response body fails, the event will have `responseBodyStatus: 'error'`.\n\n#### Network event fields\n\n| Field | Type | Description |\n|-|-|-|\n| `url` | `string` | Request URL |\n| `method` | `string` | HTTP method |\n| `status` | `number` | Response status code |\n| `duration` | `number` | Round-trip time in milliseconds |\n| `requestHeaders` | `object` | Request headers |\n| `responseHeaders` | `object` | Response headers |\n| `requestBody` | `string` | Request body (if body capture enabled) |\n| `responseBody` | `string` | Response body (if body capture enabled) |\n| `responseBodyStatus` | `string` | `'captured'`, `'truncated'`, `'skipped_binary'`, or `'error'` |\n| `error` | `object` | Error name and message if the request failed |\n\n## Releasing a Prerelease\n\nPrereleases are published to npm via the **Publish v2.x** GitHub Actions workflow. The published package will be tagged with the branch name (e.g. `@amplitude/session-replay-browser@SR-2728`) so it doesn't affect the `latest` dist-tag.\n\n### Steps\n\n1. Go to **Actions → Publish v2.x** in the GitHub repo\n2. Click **Run workflow**\n3. Set the inputs:\n   - **Use workflow from**: `main` (required — the workflow enforces this)\n   - **Release type**: `prerelease`\n   - **Branch to create pre-release from**: your feature branch (e.g. `SR-2728`)\n4. Click **Run workflow**\n\nThe workflow will:\n- Check out your feature branch\n- Build and run tests\n- Bump the version using conventional commits with your branch name as the preid (e.g. `1.33.0-SR-2728.0`)\n- Publish to npm with `--tag <branch-name>`\n\n### Installing a prerelease\n\n```sh\nnpm install @amplitude/session-replay-browser@SR-2728\n# or a specific version:\nnpm install @amplitude/session-replay-browser@1.33.0-SR-2728.0\n```\n\n### Notes\n\n- The `--tag` value is derived from the branch name with non-alphanumeric characters (except `-`) stripped, so `SR-2728` → tag `SR-2728`, `feature/my-branch` → tag `featuremy-branch`\n- Triggering from a branch other than `main` will fail the authorization check — always use `main` in the \"Use workflow from\" dropdown\n\n## Bundle Size Optimization\nThe Session Replay SDK uses dynamic imports to optimize bundle size and improve initial page load performance. Key modules are loaded on-demand rather than being included in the initial bundle:\n\n- **`@amplitude/rrweb-record`**: The core recording functionality is dynamically imported when `sessionReplay.init()` is called and capture should begin. In cases where users are not sampled or have opted out, then the Session Replay SDK will not import these dependencies. \n\nThis approach ensures that:\n- Your application's initial JavaScript bundle remains as small as possible.\n- Only the necessary Session Replay dependencies are loaded.\n\nThe dynamic imports happen asynchronously and won't block your application's initialization. If the imports fail for any reason, the SDK will not initiate capture.\n\n## Privacy\nBy default, the session replay will mask all inputs, meaning the text in inputs will appear in a session replay as asterisks: `***`. You may require more specific masking controls based on your use case, so we offer the following controls:\n\n#### 1. Unmask inputs\nIn your application code, add the class `.amp-unmask` to any __input__ whose text you'd like to have unmasked in the replay. In the session replay, it will be possible to read the exact text entered into an input with this class, the text will not be converted to asterisks.\n\n#### 2. Mask non-input elements\nIn your application code, add the class `.amp-mask` to any __non-input element__ whose text you'd like to have masked from the replay. The text in the element, as well as it's children, will all be converted to asterisks.\n\n#### 3. Block non-text elements\nIn your application code, add the class `.amp-block` to any element you would like to have blocked from the collection of the replay. The element will appear in the replay as a placeholder with the same dimensions.\n\n#### 4. Block elements by CSS selectors. \nIn the SDK initialization code, you can configure the SDK to block elements based on CSS selectors.\n```typescript\nsessionReplay.init(AMPLITUDE_API_KEY, {\n  sampleRate: 0.01, \n  privacyConfig: {\n      blockSelector: ['.ignoreClass', '#ignoreId']\n  }\n})\n```\n\n"
  },
  {
    "path": "packages/session-replay-browser/e2e/README.md",
    "content": "# Session Replay Browser — E2E Tests\n\nPlaywright end-to-end tests that verify the session replay capture lifecycle against a real browser.\n\n## Prerequisites\n\n1. **Install dependencies** from the repo root:\n   ```sh\n   pnpm i\n   ```\n\n2. **Build the session-replay-browser package** (and its dependencies). The test\n   page imports the SDK from the workspace, so the `dist/` output must exist:\n   ```sh\n   pnpm --filter @amplitude/session-replay-browser... build\n   ```\n   Or use the focused build script if you have it:\n   ```sh\n   ~/scripts/sr-build.sh\n   ```\n\n3. **Install Playwright browsers** (one-time, or after upgrading `@playwright/test`):\n   ```sh\n   npx playwright install\n   ```\n\n## Running the tests\n\nStart the Vite dev server in one terminal (from the repo root):\n```sh\nvite dev\n```\n\nThen in another terminal, run the e2e tests:\n```sh\n# All SR capture tests\nnpx playwright test packages/session-replay-browser/e2e/capture.spec.ts\n\n# Single test by name\nnpx playwright test -g \"records with 100% sample rate\"\n\n# Chromium only (faster iteration)\nnpx playwright test --project=chromium packages/session-replay-browser/e2e/capture.spec.ts\n```\n\n## Viewing results\n\n```sh\n# Open the HTML report (generated after each run)\nnpx playwright show-report\n\n# Run in headed mode to watch the browser\nnpx playwright test --headed packages/session-replay-browser/e2e/capture.spec.ts\n\n# Interactive UI mode (great for debugging)\nnpx playwright test --ui\n```\n\n## Test structure\n\nAll tests live in `capture.spec.ts` and are grouped into two `describe` blocks:\n\n| Block | What it covers |\n|---|---|\n| `session replay capture` | Sampling (100% / 0%), opt-out, flush-to-API, session ID rotation |\n| `URL-based targeting` | Recording starts/stays on URL match; does not start without a match; SPA pushState navigation triggers re-evaluation |\n\n### How network mocking works\n\nTests intercept two endpoints before navigating to the test page:\n\n- **`https://sr-client-cfg.amplitude.com/**`** — returns a fake remote config that controls sampling rate and/or URL targeting rules\n- **`https://api-sr.amplitude.com/**`** — returns `{ code: 200 }` and optionally records which requests were made\n\nThis lets tests run without hitting real Amplitude servers and without needing a valid API key for network traffic (the HTML page uses a test key for initialization only).\n\n### Test page\n\nThe test page is at `test-server/session-replay-browser/sr-capture-test.html`. It\naccepts URL params to configure the SDK:\n\n| Param | Default | Description |\n|---|---|---|\n| `sessionId` | `Date.now()` | Session ID passed to `init()` |\n| `optOut` | `false` | Passes `optOut: true` to `init()` |\n| `sampleRate` | `1.0` | Overrides the SDK-level sample rate (remote config mock takes precedence) |\n| `deviceId` | `test-device-id` | Device ID |\n| `logLevel` | `0` | SDK log level (4 = DEBUG, useful for troubleshooting) |\n| `useWebWorker` | `false` | Passes `useWebWorker: true` to `init()`, enabling the web worker send path |\n\nAfter `init()` resolves, the page sets `window.srReady = true`. Tests wait on this\nbefore asserting anything. The SDK instance is exposed as `window.sessionReplay`.\n\n## Troubleshooting\n\n**Tests time out waiting for `srReady`**\n- Make sure the Vite dev server is running on port 5173.\n- Make sure the packages are built — a missing `dist/` causes a silent import error.\n- Set `logLevel=4` in the URL to see SDK logs in the browser console (`--headed`).\n\n**`flush()` doesn't send any requests**\nEvents are buffered in IndexedDB by default. A `blur` event must fire first to move\nthem into the send queue before `flush()` will dispatch them:\n```ts\nawait page.evaluate(() => window.dispatchEvent(new Event('blur')));\nawait page.evaluate(() => (window as any).sessionReplay.flush(false));\n```\n\n**Remote config mock isn't taking effect**\nThe mock must be set up *before* `page.goto()`. The response shape must be nested:\n```ts\n// correct\n{ configs: { sessionReplay: { sr_sampling_config: { ... } } } }\n\n// wrong — RemoteConfigClient splits the key on '.' and traverses it\n{ 'configs.sessionReplay': { sr_sampling_config: { ... } } }\n```\n"
  },
  {
    "path": "packages/session-replay-browser/e2e/back-pressure.spec.ts",
    "content": "import { test, expect, Route } from '@playwright/test';\nimport {\n  TEST_SESSION_ID,\n  SNAPSHOT_SETTLE_MS,\n  remoteConfigRecording,\n  mockRemoteConfig,\n  buildUrl,\n  waitForReady,\n} from './helpers';\n\n/**\n * Mocks the track API with a configurable response — used to simulate the server's\n * 200 + X-Session-Replay-Event-Skipped header (the no-retry signal for throttle /\n * capture-disabled / session-out-of-range). See SR-4280.\n */\nfunction mockTrackApiWithSkipHeader(\n  page: import('@playwright/test').Page,\n  options: {\n    skipCode?: string | null; // null = clean 200 (no header)\n    onRequest?: (route: Route) => void;\n  },\n) {\n  const headers: Record<string, string> = options.skipCode\n    ? { 'X-Session-Replay-Event-Skipped': options.skipCode }\n    : {};\n  return page.route('https://api-sr.amplitude.com/**', (route: Route) => {\n    options.onRequest?.(route);\n    return route.fulfill({\n      status: 200,\n      headers: { 'Content-Type': 'application/json', ...headers },\n      body: 'success',\n    });\n  });\n}\n\nasync function flushSessionReplay(page: import('@playwright/test').Page) {\n  await page.evaluate(() => window.dispatchEvent(new Event('blur')) as unknown as void);\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n  await page.evaluate(() => (window as any).sessionReplay.flush(false) as Promise<void>);\n  await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n}\n\ntest.describe('server back-pressure (X-Session-Replay-Event-Skipped header)', () => {\n  // Real-browser kill-switch race-window detection is covered deterministically by the\n  // module-level integration test (test/integration.test.ts) and the unit test suite —\n  // those use fake timers to eliminate timing flake. This e2e is a baseline sanity\n  // check that the network mock + SDK plumbing wire up correctly: with no skip header,\n  // the SDK keeps POSTing as expected, which guards against future regressions where\n  // the header parsing accidentally affects the no-header path.\n  test('clean 200 (no skip header): SDK continues to POST normally', async ({ page }) => {\n    const sentUrls: string[] = [];\n    await mockRemoteConfig(page, remoteConfigRecording);\n    await mockTrackApiWithSkipHeader(page, {\n      skipCode: null,\n      onRequest: (route) => sentUrls.push(route.request().url()),\n    });\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    await flushSessionReplay(page);\n    const sentAfterFirst = sentUrls.length;\n    expect(sentAfterFirst).toBeGreaterThan(0);\n\n    // Trigger a fresh event and another flush — should produce additional POSTs\n    // because no back-pressure directive was issued.\n    await page.evaluate(() => {\n      document.getElementById('test-button')?.click();\n      document.getElementById('test-input')?.focus();\n    });\n    await flushSessionReplay(page);\n\n    expect(sentUrls.length).toBeGreaterThan(sentAfterFirst);\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/e2e/capture.spec.ts",
    "content": "import { test, expect, Route } from '@playwright/test';\nimport {\n  SR_API_SUCCESS,\n  TEST_SESSION_ID,\n  SNAPSHOT_SETTLE_MS,\n  remoteConfigRecording,\n  mockRemoteConfig,\n  buildUrl,\n  waitForReady,\n  readRouteBody,\n  captureTrackRequests,\n} from './helpers';\n\nconst SR_PROPERTY_KEY = '[Amplitude] Session Replay ID';\n// Fake origin used for fetch calls made from the test page during network body capture tests.\nconst TEST_FETCH_ORIGIN = 'https://test-fetch.amplitude.test';\nconst remoteConfigNotRecording = {\n  configs: { sessionReplay: { sr_sampling_config: { capture_enabled: true, sample_rate: 0.0 } } },\n};\n\n/**\n * Remote config with network logging and opt-in body capture enabled.\n */\nfunction remoteConfigWithNetworkBody(opts: { request?: boolean; response?: boolean; maxBodySizeBytes?: number } = {}) {\n  return {\n    configs: {\n      sessionReplay: {\n        sr_sampling_config: { capture_enabled: true, sample_rate: 1.0 },\n        sr_logging_config: {\n          network: {\n            enabled: true,\n            body: { request: true, response: true, ...opts },\n          },\n        },\n      },\n    },\n  };\n}\n\n/**\n * Decodes all rrweb events out of a raw track-API request body.\n * Events are now plain JSON strings (no packing).\n */\nfunction decodeAllEvents(rawBody: string): Array<Record<string, unknown>> {\n  if (!rawBody) return [];\n  let payload: { events?: unknown[] };\n  try {\n    payload = JSON.parse(rawBody) as { events?: unknown[] };\n  } catch {\n    return [];\n  }\n  if (!Array.isArray(payload.events)) return [];\n  const results: Array<Record<string, unknown>> = [];\n  for (const eventStr of payload.events) {\n    if (typeof eventStr !== 'string') continue;\n    try {\n      results.push(JSON.parse(eventStr) as Record<string, unknown>);\n    } catch {\n      // skip unparseable events\n    }\n  }\n  return results;\n}\n\n/**\n * Recursively searches a serialized rrweb node tree for an element with the given\n * `id` attribute and returns the value of `attr` on that element, or undefined.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction findAttrInNodeTree(node: any, id: string, attr: string): string | undefined {\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n  if (node?.attributes?.id === id) {\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n    return node.attributes[attr] as string | undefined;\n  }\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n  for (const child of node?.childNodes ?? []) {\n    const result = findAttrInNodeTree(child, id, attr);\n    if (result !== undefined) return result;\n  }\n  return undefined;\n}\n\n/**\n * Decodes all custom 'fetch-request' events out of a raw track-API request body.\n * Each event string in payload.events is a plain JSON string.\n */\nfunction decodeFetchRequestEvents(rawBody: string): Array<Record<string, unknown>> {\n  if (!rawBody) return [];\n  let payload: { events?: unknown[] };\n  try {\n    payload = JSON.parse(rawBody) as { events?: unknown[] };\n  } catch {\n    return [];\n  }\n  if (!Array.isArray(payload.events)) return [];\n  const results: Array<Record<string, unknown>> = [];\n  for (const eventStr of payload.events) {\n    if (typeof eventStr !== 'string') continue;\n    try {\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      const event = JSON.parse(eventStr);\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n      if (event.type === 5 && event.data?.tag === 'fetch-request') {\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n        results.push(event.data.payload as Record<string, unknown>);\n      }\n    } catch {\n      // skip unparseable events\n    }\n  }\n  return results;\n}\n\n/**\n * Builds a remote config that includes a privacy config (e.g. maskAttributes).\n */\nfunction remoteConfigWithPrivacy(privacyConfig: object): object {\n  return {\n    configs: {\n      sessionReplay: {\n        sr_sampling_config: { capture_enabled: true, sample_rate: 1.0 },\n        sr_privacy_config: privacyConfig,\n      },\n    },\n  };\n}\n\n/**\n * Builds a remote config with URL-based targeting: records when the page URL\n * contains `matchStr`, skips otherwise. capture_enabled is true, no sample_rate\n * (sampling is handled by the targeting decision).\n */\nfunction remoteConfigWithUrlTargeting(matchStr: string): object {\n  return {\n    configs: {\n      sessionReplay: {\n        sr_sampling_config: { capture_enabled: true },\n        sr_targeting_config: {\n          key: 'sr_targeting_config',\n          variants: { on: { key: 'on' }, off: { key: 'off' } },\n          segments: [\n            {\n              metadata: { segmentName: 'url_match' },\n              bucket: {\n                selector: ['context', 'session_id'],\n                salt: 'pw_test_salt',\n                allocations: [\n                  {\n                    range: [0, 99],\n                    distributions: [{ variant: 'on', range: [0, 42949672] }],\n                  },\n                ],\n              },\n              conditions: [[{ selector: ['context', 'page', 'url'], op: 'contains', values: [matchStr] }]],\n            },\n            { variant: 'off' },\n          ],\n        },\n      },\n    },\n  };\n}\n\nfunction mockTrackApi(page: import('@playwright/test').Page, onRequest?: (route: Route) => void) {\n  return page.route('https://api-sr.amplitude.com/**', (route: Route) => {\n    onRequest?.(route);\n    return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(SR_API_SUCCESS) });\n  });\n}\n\n/**\n * Waits until the SDK's NetworkObservers have patched window.fetch.\n * The SDK replaces the native fetch with an async wrapper; once replaced,\n * fetch.toString() no longer contains '[native code]'.\n *\n * Must be called AFTER waitForReady because the SDK patches fetch\n * asynchronously (via `void initialize()`) after init() resolves.\n */\nasync function waitForNetworkObservers(page: import('@playwright/test').Page): Promise<void> {\n  await page.waitForFunction(() => !window.fetch.toString().includes('[native code]'), { timeout: 10_000 });\n}\n\nasync function getProperties(page: import('@playwright/test').Page): Promise<Record<string, unknown>> {\n  return page.evaluate(() => (window as any).sessionReplay.getSessionReplayProperties() as Record<string, unknown>);\n}\n\n// ─── Tests ───────────────────────────────────────────────────────────────────\n\ntest.describe('session replay capture', () => {\n  test('records with 100% sample rate', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigRecording);\n    await mockTrackApi(page);\n\n    await page.goto(\n      buildUrl('/session-replay-browser/sr-capture-test.html', {\n        sessionId: TEST_SESSION_ID,\n      }),\n    );\n    await waitForReady(page);\n\n    const props = await getProperties(page);\n    expect(props[SR_PROPERTY_KEY]).toBeTruthy();\n    expect(String(props[SR_PROPERTY_KEY])).toContain(`/${TEST_SESSION_ID}`); // \"<deviceId>/<sessionId>\"\n  });\n\n  test('does not record with 0% sample rate', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigNotRecording);\n    await mockTrackApi(page);\n\n    await page.goto(\n      buildUrl('/session-replay-browser/sr-capture-test.html', {\n        sessionId: TEST_SESSION_ID,\n      }),\n    );\n    await waitForReady(page);\n\n    const props = await getProperties(page);\n    // When not recording, getSessionReplayProperties() returns {} — key is absent\n    expect(props[SR_PROPERTY_KEY]).toBeFalsy();\n  });\n\n  test('does not record when opted out', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigRecording);\n    await mockTrackApi(page);\n\n    await page.goto(\n      buildUrl('/session-replay-browser/sr-capture-test.html', {\n        sessionId: TEST_SESSION_ID,\n        optOut: true,\n      }),\n    );\n    await waitForReady(page);\n\n    const props = await getProperties(page);\n    expect(props[SR_PROPERTY_KEY]).toBeFalsy();\n  });\n\n  test('sends events to the track API when flushed', async ({ page }) => {\n    const sentUrls: string[] = [];\n    await mockRemoteConfig(page, remoteConfigRecording);\n    await mockTrackApi(page, (route) => sentUrls.push(route.request().url()));\n\n    await page.goto(\n      buildUrl('/session-replay-browser/sr-capture-test.html', {\n        sessionId: TEST_SESSION_ID,\n      }),\n    );\n    await waitForReady(page);\n    // recordEvents() is fire-and-forget inside init; give rrweb time to start and capture snapshot\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    // Blur moves buffered rrweb events from the store into trackDestination; flush sends them\n    await page.evaluate(() => window.dispatchEvent(new Event('blur')) as unknown as void);\n    await page.evaluate(() => (window as any).sessionReplay.flush(false) as Promise<void>);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    expect(sentUrls.length).toBeGreaterThan(0);\n  });\n\n  test('does not send events to the track API when not recording', async ({ page }) => {\n    const sentUrls: string[] = [];\n    await mockRemoteConfig(page, remoteConfigNotRecording);\n    await mockTrackApi(page, (route) => sentUrls.push(route.request().url()));\n\n    await page.goto(\n      buildUrl('/session-replay-browser/sr-capture-test.html', {\n        sessionId: TEST_SESSION_ID,\n      }),\n    );\n    await waitForReady(page);\n\n    await page.evaluate(() => (window as any).sessionReplay.flush(false) as Promise<void>);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    expect(sentUrls.length).toBe(0);\n  });\n\n  test('starts recording for a new session after setSessionId', async ({ page }) => {\n    const NEW_SESSION_ID = TEST_SESSION_ID + 60_000;\n    await mockRemoteConfig(page, remoteConfigRecording);\n    await mockTrackApi(page);\n\n    await page.goto(\n      buildUrl('/session-replay-browser/sr-capture-test.html', {\n        sessionId: TEST_SESSION_ID,\n      }),\n    );\n    await waitForReady(page);\n\n    await page.evaluate(\n      (newId) => (window as any).sessionReplay.setSessionId(newId).promise as Promise<void>,\n      NEW_SESSION_ID,\n    );\n\n    const props = await getProperties(page);\n    expect(String(props[SR_PROPERTY_KEY])).toContain(`/${NEW_SESSION_ID}`);\n  });\n\n  test('flushes previous session events on setSessionId', async ({ page }) => {\n    const NEW_SESSION_ID = TEST_SESSION_ID + 60_000;\n    await mockRemoteConfig(page, remoteConfigRecording);\n    await mockTrackApi(page);\n\n    await page.goto(\n      buildUrl('/session-replay-browser/sr-capture-test.html', {\n        sessionId: TEST_SESSION_ID,\n      }),\n    );\n    await waitForReady(page);\n    // Give rrweb time to start recording and capture the initial snapshot\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    // waitForRequest verifies that events were actually flushed to the API\n    const trackRequestPromise = page.waitForRequest('https://api-sr.amplitude.com/**', { timeout: 5_000 });\n    void page.evaluate(\n      (newId) => (window as any).sessionReplay.setSessionId(newId).promise as Promise<void>,\n      NEW_SESSION_ID,\n    );\n    await trackRequestPromise; // will throw if no request is made in time\n\n    // New session is now active\n    const props = await getProperties(page);\n    expect(String(props[SR_PROPERTY_KEY])).toContain(`/${NEW_SESSION_ID}`);\n  });\n});\n\n// ─── URL-based targeting ──────────────────────────────────────────────────────\n\ntest.describe('URL-based targeting', () => {\n  // The test page URL contains 'sr-capture-test', so this string always matches on init.\n  const MATCH_STRING = 'sr-capture-test';\n  // This string only matches after an explicit pushState navigation.\n  const NAV_MATCH_STRING = '/matching-route';\n\n  test('starts recording when page URL matches targeting condition on init', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigWithUrlTargeting(MATCH_STRING));\n    await mockTrackApi(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    // Give targeting evaluation (async IDB + rrweb start) time to complete\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    const props = await getProperties(page);\n    expect(props[SR_PROPERTY_KEY]).toBeTruthy();\n    expect(String(props[SR_PROPERTY_KEY])).toContain(`/${TEST_SESSION_ID}`);\n  });\n\n  test('starts recording when user navigates to a matching URL (SPA pushState)', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigWithUrlTargeting(NAV_MATCH_STRING));\n    await mockTrackApi(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n\n    // Current URL doesn't match — not recording yet\n    const propsBefore = await getProperties(page);\n    expect(propsBefore[SR_PROPERTY_KEY]).toBeFalsy();\n\n    // SPA navigation to matching route\n    await page.evaluate((path) => history.pushState({}, '', path), NAV_MATCH_STRING);\n\n    // Wait for targeting re-evaluation to kick in and recording to start\n    await page.waitForFunction(\n      (key) => !!(window as any).sessionReplay.getSessionReplayProperties()[key],\n      SR_PROPERTY_KEY,\n      { timeout: 5_000 },\n    );\n\n    const propsAfter = await getProperties(page);\n    expect(propsAfter[SR_PROPERTY_KEY]).toBeTruthy();\n    expect(String(propsAfter[SR_PROPERTY_KEY])).toContain(`/${TEST_SESSION_ID}`);\n  });\n\n  test('does not record when page URL never matches targeting condition', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigWithUrlTargeting(NAV_MATCH_STRING));\n    await mockTrackApi(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    // URL never matched — should not be recording\n    const props = await getProperties(page);\n    expect(props[SR_PROPERTY_KEY]).toBeFalsy();\n  });\n\n  test('does not send events to the track API when URL never matches', async ({ page }) => {\n    const sentUrls: string[] = [];\n    await mockRemoteConfig(page, remoteConfigWithUrlTargeting(NAV_MATCH_STRING));\n    await mockTrackApi(page, (route) => sentUrls.push(route.request().url()));\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    await page.evaluate(() => window.dispatchEvent(new Event('blur')) as unknown as void);\n    await page.evaluate(() => (window as any).sessionReplay.flush(false) as Promise<void>);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    expect(sentUrls.length).toBe(0);\n  });\n\n  test('continues recording after navigating away from matched URL (monotonic match)', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigWithUrlTargeting(MATCH_STRING));\n    await mockTrackApi(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    // Verify recording started on the matching URL\n    const propsBefore = await getProperties(page);\n    expect(propsBefore[SR_PROPERTY_KEY]).toBeTruthy();\n\n    // Navigate away to a non-matching URL\n    await page.evaluate(() => history.pushState({}, '', '/some-other-route'));\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    // Should still be recording — targeting match is monotonic within a session\n    const propsAfter = await getProperties(page);\n    expect(propsAfter[SR_PROPERTY_KEY]).toBeTruthy();\n    expect(String(propsAfter[SR_PROPERTY_KEY])).toContain(`/${TEST_SESSION_ID}`);\n  });\n\n  test('starts recording when replaceState navigates to matching URL', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigWithUrlTargeting(NAV_MATCH_STRING));\n    await mockTrackApi(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n\n    // Current URL doesn't match — not recording yet\n    expect((await getProperties(page))[SR_PROPERTY_KEY]).toBeFalsy();\n\n    // SPA navigation via replaceState (replaces history entry rather than pushing)\n    await page.evaluate((path) => history.replaceState({}, '', path), NAV_MATCH_STRING);\n\n    await page.waitForFunction(\n      (key) => !!(window as any).sessionReplay.getSessionReplayProperties()[key],\n      SR_PROPERTY_KEY,\n      { timeout: 5_000 },\n    );\n\n    const propsAfter = await getProperties(page);\n    expect(propsAfter[SR_PROPERTY_KEY]).toBeTruthy();\n    expect(String(propsAfter[SR_PROPERTY_KEY])).toContain(`/${TEST_SESSION_ID}`);\n  });\n\n  test('starts recording when a hash change results in a URL containing the match string', async ({ page }) => {\n    // Setting location.hash to NAV_MATCH_STRING fires a hashchange event;\n    // the full URL becomes \"...#/matching-route\" which contains NAV_MATCH_STRING.\n    await mockRemoteConfig(page, remoteConfigWithUrlTargeting(NAV_MATCH_STRING));\n    await mockTrackApi(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n\n    expect((await getProperties(page))[SR_PROPERTY_KEY]).toBeFalsy();\n\n    // Trigger a hashchange — URL becomes \"...#/matching-route\"\n    await page.evaluate((hash) => {\n      window.location.hash = hash;\n    }, NAV_MATCH_STRING);\n\n    await page.waitForFunction(\n      (key) => !!(window as any).sessionReplay.getSessionReplayProperties()[key],\n      SR_PROPERTY_KEY,\n      { timeout: 5_000 },\n    );\n\n    const propsAfter = await getProperties(page);\n    expect(propsAfter[SR_PROPERTY_KEY]).toBeTruthy();\n    expect(String(propsAfter[SR_PROPERTY_KEY])).toContain(`/${TEST_SESSION_ID}`);\n  });\n\n  test('does not record until a navigation produces a matching URL', async ({ page }) => {\n    // Verifies that non-matching navigations do not start recording and that recording\n    // begins only on the first navigation whose URL satisfies the targeting condition.\n    await mockRemoteConfig(page, remoteConfigWithUrlTargeting(NAV_MATCH_STRING));\n    await mockTrackApi(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n\n    // First navigation: non-matching\n    await page.evaluate(() => history.pushState({}, '', '/non-matching-step'));\n    await page.waitForTimeout(300);\n    expect((await getProperties(page))[SR_PROPERTY_KEY]).toBeFalsy();\n\n    // Second navigation: still non-matching\n    await page.evaluate(() => history.pushState({}, '', '/also-not-matching'));\n    await page.waitForTimeout(300);\n    expect((await getProperties(page))[SR_PROPERTY_KEY]).toBeFalsy();\n\n    // Third navigation: matching — recording should now start\n    await page.evaluate((path) => history.pushState({}, '', path), NAV_MATCH_STRING);\n\n    await page.waitForFunction(\n      (key) => !!(window as any).sessionReplay.getSessionReplayProperties()[key],\n      SR_PROPERTY_KEY,\n      { timeout: 5_000 },\n    );\n\n    expect(String((await getProperties(page))[SR_PROPERTY_KEY])).toContain(`/${TEST_SESSION_ID}`);\n  });\n\n  test('sends events to the track API after URL-triggered recording starts', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigWithUrlTargeting(NAV_MATCH_STRING));\n    await mockTrackApi(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n\n    // Navigate to the matching URL to start recording. The SDK fires a full snapshot\n    // immediately when recording begins; register waitForRequest before the navigation\n    // so the immediate-flush request doesn't race past the listener.\n    const trackRequestPromise = page.waitForRequest('https://api-sr.amplitude.com/**', { timeout: 10_000 });\n    await page.evaluate((path) => history.pushState({}, '', path), NAV_MATCH_STRING);\n    await page.waitForFunction(\n      (key) => !!(window as any).sessionReplay.getSessionReplayProperties()[key],\n      SR_PROPERTY_KEY,\n      { timeout: 5_000 },\n    );\n\n    await trackRequestPromise;\n  });\n\n  test('records new session when setSessionId is called while URL matches targeting', async ({ page }) => {\n    const NEW_SESSION_ID = TEST_SESSION_ID + 60_000;\n    await mockRemoteConfig(page, remoteConfigWithUrlTargeting(NAV_MATCH_STRING));\n    await mockTrackApi(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n\n    // Navigate to the matching URL so it's current when setSessionId is called\n    await page.evaluate((path) => history.pushState({}, '', path), NAV_MATCH_STRING);\n    await page.waitForFunction(\n      (key) => !!(window as any).sessionReplay.getSessionReplayProperties()[key],\n      SR_PROPERTY_KEY,\n      { timeout: 5_000 },\n    );\n\n    // Start a new session — targeting re-evaluates with the current (matching) URL\n    await page.evaluate(\n      (newId) => (window as any).sessionReplay.setSessionId(newId).promise as Promise<void>,\n      NEW_SESSION_ID,\n    );\n\n    const props = await getProperties(page);\n    expect(props[SR_PROPERTY_KEY]).toBeTruthy();\n    expect(String(props[SR_PROPERTY_KEY])).toContain(`/${NEW_SESSION_ID}`);\n  });\n\n  test('does not record new session when setSessionId is called at a non-matching URL', async ({ page }) => {\n    const NEW_SESSION_ID = TEST_SESSION_ID + 60_000;\n    // MATCH_STRING is in the initial page URL, so the first session records\n    await mockRemoteConfig(page, remoteConfigWithUrlTargeting(MATCH_STRING));\n    await mockTrackApi(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    // Initial session is recording (URL matches)\n    expect((await getProperties(page))[SR_PROPERTY_KEY]).toBeTruthy();\n\n    // Navigate away so the current URL no longer matches\n    await page.evaluate(() => history.pushState({}, '', '/some-other-route'));\n\n    // Start a new session — targeting re-evaluates with the current (non-matching) URL\n    await page.evaluate(\n      (newId) => (window as any).sessionReplay.setSessionId(newId).promise as Promise<void>,\n      NEW_SESSION_ID,\n    );\n\n    const propsAfter = await getProperties(page);\n    expect(propsAfter[SR_PROPERTY_KEY]).toBeFalsy();\n  });\n});\n\n// ─── URL-based targeting — URL pattern matching ───────────────────────────────\n\ntest.describe('URL-based targeting — URL pattern matching', () => {\n  const NAV_MATCH_STRING = '/matching-route';\n  const MATCH_STRING = 'sr-capture-test';\n\n  test('matches targeting condition against a value in the URL query string', async ({ page }) => {\n    // The match string appears as a query parameter value in the initial page URL,\n    // so init-time evaluation should match and start recording.\n    const QUERY_MATCH = 'capture-target';\n    await mockRemoteConfig(page, remoteConfigWithUrlTargeting(QUERY_MATCH));\n    await mockTrackApi(page);\n\n    await page.goto(\n      buildUrl('/session-replay-browser/sr-capture-test.html', {\n        sessionId: TEST_SESSION_ID,\n        testParam: QUERY_MATCH,\n      }),\n    );\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    const props = await getProperties(page);\n    expect(props[SR_PROPERTY_KEY]).toBeTruthy();\n    expect(String(props[SR_PROPERTY_KEY])).toContain(`/${TEST_SESSION_ID}`);\n  });\n\n  test('does not record when query string value is present but condition targets a different string', async ({\n    page,\n  }) => {\n    await mockRemoteConfig(page, remoteConfigWithUrlTargeting(NAV_MATCH_STRING));\n    await mockTrackApi(page);\n\n    // URL has testParam but its value does not contain NAV_MATCH_STRING\n    await page.goto(\n      buildUrl('/session-replay-browser/sr-capture-test.html', {\n        sessionId: TEST_SESSION_ID,\n        testParam: 'some-other-value',\n      }),\n    );\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    expect((await getProperties(page))[SR_PROPERTY_KEY]).toBeFalsy();\n  });\n\n  test('URL contains matching is case-insensitive', async ({ page }) => {\n    // Targeting condition uses uppercase; page URL has lowercase — the EvaluationEngine\n    // treats 'contains' as case-insensitive, so this should still match and record.\n    const UPPER_MATCH = MATCH_STRING.toUpperCase(); // 'SR-CAPTURE-TEST'\n    await mockRemoteConfig(page, remoteConfigWithUrlTargeting(UPPER_MATCH));\n    await mockTrackApi(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    // URL contains 'sr-capture-test' and condition is 'SR-CAPTURE-TEST' — case-insensitive match\n    const props = await getProperties(page);\n    expect(props[SR_PROPERTY_KEY]).toBeTruthy();\n    expect(String(props[SR_PROPERTY_KEY])).toContain(`/${TEST_SESSION_ID}`);\n  });\n\n  test('does not record when no targeting config is set and sample rate is 0', async ({ page }) => {\n    // Ensures the absence of sr_targeting_config falls back to sample-rate logic,\n    // not a blanket match. Uses remoteConfigNotRecording (0% sample rate).\n    await mockRemoteConfig(page, {\n      configs: { sessionReplay: { sr_sampling_config: { capture_enabled: true, sample_rate: 0.0 } } },\n    });\n    await mockTrackApi(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    expect((await getProperties(page))[SR_PROPERTY_KEY]).toBeFalsy();\n  });\n});\n\n/**\n * Sets up a track-API mock that also captures POST bodies via page.route().\n * Call BEFORE page.goto. Returns a function that decodes all captured\n * fetch-request event payloads.\n */\nasync function mockTrackApiWithCapture(page: import('@playwright/test').Page) {\n  const rawBodies: string[] = [];\n  await page.route('https://api-sr.amplitude.com/**', async (route: Route) => {\n    rawBodies.push(readRouteBody(route));\n    await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(SR_API_SUCCESS) });\n  });\n  return () => rawBodies.flatMap((body) => decodeFetchRequestEvents(body));\n}\n\n// ─── Network body capture ─────────────────────────────────────────────────────\n\ntest.describe('network body capture', () => {\n  test('captures request and response body for a JSON fetch', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigWithNetworkBody());\n    const getFetchEvents = await mockTrackApiWithCapture(page);\n    await page.route(`${TEST_FETCH_ORIGIN}/**`, (route) =>\n      route.fulfill({\n        status: 200,\n        contentType: 'application/json',\n        body: JSON.stringify({ result: 'ok' }),\n      }),\n    );\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await waitForNetworkObservers(page);\n\n    // Make a POST fetch from within the page\n    await page.evaluate(\n      (url) =>\n        fetch(url, {\n          method: 'POST',\n          headers: { 'Content-Type': 'application/json' },\n          body: JSON.stringify({ action: 'test' }),\n        }),\n      `${TEST_FETCH_ORIGIN}/data`,\n    );\n    // Give the SDK time to read the cloned response body (detached async)\n    await page.waitForTimeout(200);\n\n    await page.evaluate(() => window.dispatchEvent(new Event('blur')));\n    await page.evaluate(() => (window as any).sessionReplay.flush(false) as Promise<void>);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    const fetchEvents = getFetchEvents();\n    expect(fetchEvents.length).toBeGreaterThan(0);\n    const evt = fetchEvents.find((e) => String(e.url).includes(TEST_FETCH_ORIGIN));\n    expect(evt).toBeDefined();\n    expect(evt!.requestBody).toBe('{\"action\":\"test\"}');\n    expect(evt!.responseBody).toBe('{\"result\":\"ok\"}');\n    expect(evt!.responseBodyStatus).toBe('captured');\n  });\n\n  test('sets responseBodyStatus to \"skipped_binary\" for image responses', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigWithNetworkBody());\n    const getFetchEvents = await mockTrackApiWithCapture(page);\n    const PNG_1X1 = Buffer.from(\n      'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==',\n      'base64',\n    );\n    await page.route(`${TEST_FETCH_ORIGIN}/**`, (route) =>\n      route.fulfill({ status: 200, contentType: 'image/png', body: PNG_1X1 }),\n    );\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await waitForNetworkObservers(page);\n\n    await page.evaluate((url) => fetch(url), `${TEST_FETCH_ORIGIN}/image.png`);\n    await page.waitForTimeout(200);\n\n    await page.evaluate(() => window.dispatchEvent(new Event('blur')));\n    await page.evaluate(() => (window as any).sessionReplay.flush(false) as Promise<void>);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    const fetchEvents = getFetchEvents();\n    const evt = fetchEvents.find((e) => String(e.url).includes(TEST_FETCH_ORIGIN));\n    expect(evt).toBeDefined();\n    expect(evt!.responseBodyStatus).toBe('skipped_binary');\n    expect(evt!.responseBody).toBeUndefined();\n  });\n\n  test('does not capture bodies when body config is absent', async ({ page }) => {\n    await mockRemoteConfig(page, {\n      configs: {\n        sessionReplay: {\n          sr_sampling_config: { capture_enabled: true, sample_rate: 1.0 },\n          sr_logging_config: { network: { enabled: true } },\n        },\n      },\n    });\n    const getFetchEvents = await mockTrackApiWithCapture(page);\n    await page.route(`${TEST_FETCH_ORIGIN}/**`, (route) =>\n      route.fulfill({ status: 200, contentType: 'application/json', body: '{\"x\":1}' }),\n    );\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await waitForNetworkObservers(page);\n\n    await page.evaluate((url) => fetch(url, { method: 'POST', body: 'hello' }), `${TEST_FETCH_ORIGIN}/data`);\n    await page.waitForTimeout(200);\n\n    await page.evaluate(() => window.dispatchEvent(new Event('blur')));\n    await page.evaluate(() => (window as any).sessionReplay.flush(false) as Promise<void>);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    const fetchEvents = getFetchEvents();\n    const evt = fetchEvents.find((e) => String(e.url).includes(TEST_FETCH_ORIGIN));\n    expect(evt).toBeDefined();\n    expect(evt!.requestBody).toBeUndefined();\n    expect(evt!.responseBody).toBeUndefined();\n    expect(evt!.responseBodyStatus).toBeUndefined();\n  });\n\n  test('does not capture fetch-request events for Amplitude track API calls', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigWithNetworkBody());\n    const getFetchEvents = await mockTrackApiWithCapture(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await waitForNetworkObservers(page);\n\n    // Trigger a flush, which causes the SDK to POST to api-sr.amplitude.com\n    await page.evaluate(() => window.dispatchEvent(new Event('blur')));\n    await page.evaluate(() => (window as any).sessionReplay.flush(false) as Promise<void>);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    const fetchEvents = getFetchEvents();\n    const trackApiEvent = fetchEvents.find((e) => String(e.url).includes('api-sr.amplitude.com'));\n    expect(trackApiEvent).toBeUndefined();\n  });\n\n  test('truncates response body exceeding maxBodySizeBytes', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigWithNetworkBody({ maxBodySizeBytes: 5 }));\n    const getFetchEvents = await mockTrackApiWithCapture(page);\n    await page.route(`${TEST_FETCH_ORIGIN}/**`, (route) =>\n      route.fulfill({ status: 200, contentType: 'text/plain', body: 'hello world' }),\n    );\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await waitForNetworkObservers(page);\n\n    await page.evaluate((url) => fetch(url), `${TEST_FETCH_ORIGIN}/data`);\n    await page.waitForTimeout(200);\n\n    await page.evaluate(() => window.dispatchEvent(new Event('blur')));\n    await page.evaluate(() => (window as any).sessionReplay.flush(false) as Promise<void>);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    const fetchEvents = getFetchEvents();\n    const evt = fetchEvents.find((e) => String(e.url).includes(TEST_FETCH_ORIGIN));\n    expect(evt).toBeDefined();\n    expect(evt!.responseBody).toBe('hello');\n    expect(evt!.responseBodyStatus).toBe('truncated');\n  });\n});\n\n// ─── Attribute masking ────────────────────────────────────────────────────────\n\ntest.describe('attribute masking', () => {\n  /**\n   * Sets up a track-API mock that captures POST bodies. Returns an async function\n   * that flushes buffered events and decodes all rrweb events from the captured bodies.\n   */\n  async function mockTrackApiAndCaptureEvents(page: import('@playwright/test').Page) {\n    const rawBodies: string[] = [];\n    await page.route('https://api-sr.amplitude.com/**', async (route: Route) => {\n      rawBodies.push(readRouteBody(route));\n      await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(SR_API_SUCCESS) });\n    });\n    return async (): Promise<Array<Record<string, unknown>>> => {\n      await page.evaluate(() => window.dispatchEvent(new Event('blur')));\n      await page.evaluate(() => (window as any).sessionReplay.flush(false) as Promise<void>);\n      await page.waitForTimeout(500);\n      return rawBodies.flatMap(decodeAllEvents);\n    };\n  }\n\n  test('masks attribute listed in maskAttributes in rrweb full snapshot', async ({ page }) => {\n    // placeholder=\"Enter your email\" → \"***** **** *****\"\n    await mockRemoteConfig(page, remoteConfigWithPrivacy({ maskAttributes: ['placeholder'] }));\n    const flushAndGetEvents = await mockTrackApiAndCaptureEvents(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(500);\n\n    const events = await flushAndGetEvents();\n    const snapshot = events.find((e) => e.type === 2);\n    expect(snapshot).toBeDefined();\n\n    const placeholderValue = findAttrInNodeTree((snapshot!.data as any).node, 'test-input', 'placeholder');\n    expect(placeholderValue).toBe('***** **** *****');\n  });\n\n  test('does not mask attribute not listed in maskAttributes', async ({ page }) => {\n    // 'type' is not in maskAttributes — should remain \"text\"\n    await mockRemoteConfig(page, remoteConfigWithPrivacy({ maskAttributes: ['placeholder'] }));\n    const flushAndGetEvents = await mockTrackApiAndCaptureEvents(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(500);\n\n    const events = await flushAndGetEvents();\n    const snapshot = events.find((e) => e.type === 2);\n    expect(snapshot).toBeDefined();\n\n    const typeValue = findAttrInNodeTree((snapshot!.data as any).node, 'test-input', 'type');\n    expect(typeValue).toBe('text');\n  });\n\n  test('does not mask attribute when maskAttributes is empty', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigWithPrivacy({ maskAttributes: [] }));\n    const flushAndGetEvents = await mockTrackApiAndCaptureEvents(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(500);\n\n    const events = await flushAndGetEvents();\n    const snapshot = events.find((e) => e.type === 2);\n    expect(snapshot).toBeDefined();\n\n    const placeholderValue = findAttrInNodeTree((snapshot!.data as any).node, 'test-input', 'placeholder');\n    expect(placeholderValue).toBe('Enter your email');\n  });\n\n  test('masks aria-label on non-form element under conservative', async ({ page }) => {\n    // Under conservative, aria-label=\"Submit form\" on a <button> is masked → \"****** ****\"\n    await mockRemoteConfig(\n      page,\n      remoteConfigWithPrivacy({ defaultMaskLevel: 'conservative', maskAttributes: ['aria-label'] }),\n    );\n    const flushAndGetEvents = await mockTrackApiAndCaptureEvents(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(500);\n\n    const events = await flushAndGetEvents();\n    const snapshot = events.find((e) => e.type === 2);\n    expect(snapshot).toBeDefined();\n\n    const ariaLabelValue = findAttrInNodeTree((snapshot!.data as any).node, 'test-button', 'aria-label');\n    expect(ariaLabelValue).toBe('****** ****');\n  });\n\n  test('does NOT mask aria-label on non-form element under medium', async ({ page }) => {\n    // Per public docs, medium masks form fields but captures other text as-is.\n    // A <button>'s aria-label is treated as text → not masked under medium.\n    await mockRemoteConfig(\n      page,\n      remoteConfigWithPrivacy({ defaultMaskLevel: 'medium', maskAttributes: ['aria-label'] }),\n    );\n    const flushAndGetEvents = await mockTrackApiAndCaptureEvents(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(500);\n\n    const events = await flushAndGetEvents();\n    const snapshot = events.find((e) => e.type === 2);\n    expect(snapshot).toBeDefined();\n\n    const ariaLabelValue = findAttrInNodeTree((snapshot!.data as any).node, 'test-button', 'aria-label');\n    expect(ariaLabelValue).toBe('Submit form');\n  });\n\n  test('does not mask style attribute even when listed in maskAttributes', async ({ page }) => {\n    // style is explicitly excluded from maskAttributeFn because rrweb handles style diffs separately\n    await mockRemoteConfig(page, remoteConfigWithPrivacy({ maskAttributes: ['style'] }));\n    const flushAndGetEvents = await mockTrackApiAndCaptureEvents(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(500);\n\n    const events = await flushAndGetEvents();\n    const snapshot = events.find((e) => e.type === 2);\n    expect(snapshot).toBeDefined();\n\n    // test-input has style=\"display:block\" — should be present and never replaced with stars\n    const styleValue = findAttrInNodeTree((snapshot!.data as any).node, 'test-input', 'style');\n    expect(typeof styleValue).toBe('string');\n    expect(styleValue).not.toMatch(/^\\*+/);\n  });\n});\n\n// ─── shutdown ─────────────────────────────────────────────────────────────────\n\ntest.describe('shutdown', () => {\n  test('flushes buffered events when shutdown is called', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigRecording);\n    // Register waitForRequest before goto so the immediate full-snapshot flush\n    // (which fires as soon as rrweb captures the snapshot) can satisfy it.\n    const trackRequestPromise = page.waitForRequest('https://api-sr.amplitude.com/**', { timeout: 10_000 });\n    await mockTrackApi(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    // The immediate flush should already have sent the full snapshot. Confirm at\n    // least one request was made, then call shutdown to flush any remaining events.\n    await trackRequestPromise; // throws if no request is made within timeout\n    await page.evaluate(() => (window as any).sessionReplay.shutdown() as void);\n  });\n\n  test('blur no longer triggers a flush after shutdown', async ({ page }) => {\n    const sentUrls: string[] = [];\n    await mockRemoteConfig(page, remoteConfigRecording);\n    await mockTrackApi(page, (route) => sentUrls.push(route.request().url()));\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    // shutdown() removes the blur event listener and flushes pending events\n    await page.evaluate(() => (window as any).sessionReplay.shutdown() as void);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS); // let shutdown's own sendEvents() complete\n\n    const countAfterShutdown = sentUrls.length;\n\n    // Blur should no longer trigger a flush (listener was removed during shutdown)\n    await page.evaluate(() => window.dispatchEvent(new Event('blur')));\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    expect(sentUrls.length).toBe(countAfterShutdown);\n  });\n});\n\n// ─── capture_enabled ──────────────────────────────────────────────────────────\n\ntest.describe('capture_enabled', () => {\n  test('does not record when capture_enabled is false in remote config', async ({ page }) => {\n    await mockRemoteConfig(page, {\n      configs: { sessionReplay: { sr_sampling_config: { capture_enabled: false } } },\n    });\n    await mockTrackApi(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    expect((await getProperties(page))[SR_PROPERTY_KEY]).toBeFalsy();\n  });\n\n  test('does not send events to the track API when capture_enabled is false', async ({ page }) => {\n    const sentUrls: string[] = [];\n    await mockRemoteConfig(page, {\n      configs: { sessionReplay: { sr_sampling_config: { capture_enabled: false } } },\n    });\n    await mockTrackApi(page, (route) => sentUrls.push(route.request().url()));\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n\n    await page.evaluate(() => (window as any).sessionReplay.flush(false) as Promise<void>);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    expect(sentUrls.length).toBe(0);\n  });\n});\n\n// ─── blur auto-flush ──────────────────────────────────────────────────────────\n\ntest.describe('blur auto-flush', () => {\n  test('sends buffered events to the track API without an explicit flush', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigRecording);\n    // Register waitForRequest before goto. The full snapshot is flushed immediately\n    // after rrweb captures it (no explicit flush() call needed); the listener must\n    // be in place before that happens.\n    const trackRequestPromise = page.waitForRequest('https://api-sr.amplitude.com/**', { timeout: 10_000 });\n    await mockTrackApi(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n\n    await trackRequestPromise; // throws if no request is made within the timeout\n  });\n});\n\n// ─── session replay property format ──────────────────────────────────────────\n\ntest.describe('session replay property format', () => {\n  test('property value is formatted as deviceId/sessionId', async ({ page }) => {\n    const CUSTOM_DEVICE_ID = 'my-custom-device-id';\n    await mockRemoteConfig(page, remoteConfigRecording);\n    await mockTrackApi(page);\n\n    await page.goto(\n      buildUrl('/session-replay-browser/sr-capture-test.html', {\n        sessionId: TEST_SESSION_ID,\n        deviceId: CUSTOM_DEVICE_ID,\n      }),\n    );\n    await waitForReady(page);\n\n    const props = await getProperties(page);\n    expect(props[SR_PROPERTY_KEY]).toBeTruthy();\n    expect(props[SR_PROPERTY_KEY]).toBe(`${CUSTOM_DEVICE_ID}/${TEST_SESSION_ID}`);\n  });\n\n  test('property reflects new deviceId after setSessionId with explicit deviceId', async ({ page }) => {\n    const NEW_SESSION_ID = TEST_SESSION_ID + 60_000;\n    const NEW_DEVICE_ID = 'new-device-id';\n    await mockRemoteConfig(page, remoteConfigRecording);\n    await mockTrackApi(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n\n    await page.evaluate(\n      ({ newId, newDevice }) => (window as any).sessionReplay.setSessionId(newId, newDevice).promise as Promise<void>,\n      { newId: NEW_SESSION_ID, newDevice: NEW_DEVICE_ID },\n    );\n\n    const props = await getProperties(page);\n    expect(props[SR_PROPERTY_KEY]).toBe(`${NEW_DEVICE_ID}/${NEW_SESSION_ID}`);\n  });\n});\n\n// ─── network logging — fields ─────────────────────────────────────────────────\n\ntest.describe('network logging — fields', () => {\n  test('captures method and HTTP status for a POST fetch', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigWithNetworkBody());\n    const getFetchEvents = await mockTrackApiWithCapture(page);\n    await page.route(`${TEST_FETCH_ORIGIN}/**`, (route) =>\n      route.fulfill({ status: 201, contentType: 'application/json', body: '{\"ok\":true}' }),\n    );\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await waitForNetworkObservers(page);\n\n    await page.evaluate(\n      (url) => fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{}' }),\n      `${TEST_FETCH_ORIGIN}/submit`,\n    );\n    await page.waitForTimeout(200);\n\n    await page.evaluate(() => window.dispatchEvent(new Event('blur')));\n    await page.evaluate(() => (window as any).sessionReplay.flush(false) as Promise<void>);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    const fetchEvents = getFetchEvents();\n    const evt = fetchEvents.find((e) => String(e.url).includes(TEST_FETCH_ORIGIN));\n    expect(evt).toBeDefined();\n    expect(evt!.method).toBe('POST');\n    expect(evt!.status).toBe(201);\n  });\n\n  test('defaults method to GET when no method is specified', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigWithNetworkBody());\n    const getFetchEvents = await mockTrackApiWithCapture(page);\n    await page.route(`${TEST_FETCH_ORIGIN}/**`, (route) =>\n      route.fulfill({ status: 200, contentType: 'application/json', body: '{}' }),\n    );\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await waitForNetworkObservers(page);\n\n    await page.evaluate((url) => fetch(url), `${TEST_FETCH_ORIGIN}/data`);\n    await page.waitForTimeout(200);\n\n    await page.evaluate(() => window.dispatchEvent(new Event('blur')));\n    await page.evaluate(() => (window as any).sessionReplay.flush(false) as Promise<void>);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    const fetchEvents = getFetchEvents();\n    const evt = fetchEvents.find((e) => String(e.url).includes(TEST_FETCH_ORIGIN));\n    expect(evt).toBeDefined();\n    expect(evt!.method).toBe('GET');\n    expect(evt!.status).toBe(200);\n  });\n\n  test('captures request body but not response body when response capture is disabled', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigWithNetworkBody({ response: false }));\n    const getFetchEvents = await mockTrackApiWithCapture(page);\n    await page.route(`${TEST_FETCH_ORIGIN}/**`, (route) =>\n      route.fulfill({ status: 200, contentType: 'application/json', body: '{\"res\":\"data\"}' }),\n    );\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await waitForNetworkObservers(page);\n\n    await page.evaluate(\n      (url) =>\n        fetch(url, {\n          method: 'POST',\n          headers: { 'Content-Type': 'application/json' },\n          body: JSON.stringify({ req: 'data' }),\n        }),\n      `${TEST_FETCH_ORIGIN}/data`,\n    );\n    await page.waitForTimeout(200);\n\n    await page.evaluate(() => window.dispatchEvent(new Event('blur')));\n    await page.evaluate(() => (window as any).sessionReplay.flush(false) as Promise<void>);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    const fetchEvents = getFetchEvents();\n    const evt = fetchEvents.find((e) => String(e.url).includes(TEST_FETCH_ORIGIN));\n    expect(evt).toBeDefined();\n    expect(evt!.requestBody).toBe('{\"req\":\"data\"}');\n    expect(evt!.responseBody).toBeUndefined();\n    expect(evt!.responseBodyStatus).toBeUndefined();\n  });\n\n  test('captures response body but not request body when request capture is disabled', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigWithNetworkBody({ request: false }));\n    const getFetchEvents = await mockTrackApiWithCapture(page);\n    await page.route(`${TEST_FETCH_ORIGIN}/**`, (route) =>\n      route.fulfill({ status: 200, contentType: 'application/json', body: '{\"res\":\"data\"}' }),\n    );\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await waitForNetworkObservers(page);\n\n    await page.evaluate(\n      (url) =>\n        fetch(url, {\n          method: 'POST',\n          headers: { 'Content-Type': 'application/json' },\n          body: JSON.stringify({ req: 'data' }),\n        }),\n      `${TEST_FETCH_ORIGIN}/data`,\n    );\n    await page.waitForTimeout(200);\n\n    await page.evaluate(() => window.dispatchEvent(new Event('blur')));\n    await page.evaluate(() => (window as any).sessionReplay.flush(false) as Promise<void>);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    const fetchEvents = getFetchEvents();\n    const evt = fetchEvents.find((e) => String(e.url).includes(TEST_FETCH_ORIGIN));\n    expect(evt).toBeDefined();\n    expect(evt!.requestBody).toBeUndefined();\n    expect(evt!.responseBody).toBe('{\"res\":\"data\"}');\n    expect(evt!.responseBodyStatus).toBe('captured');\n  });\n\n  test('does not capture network events when network logging is disabled', async ({ page }) => {\n    await mockRemoteConfig(page, {\n      configs: {\n        sessionReplay: {\n          sr_sampling_config: { capture_enabled: true, sample_rate: 1.0 },\n          sr_logging_config: { network: { enabled: false } },\n        },\n      },\n    });\n    const getFetchEvents = await mockTrackApiWithCapture(page);\n    await page.route(`${TEST_FETCH_ORIGIN}/**`, (route) =>\n      route.fulfill({ status: 200, contentType: 'application/json', body: '{}' }),\n    );\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    // Network logging is disabled — fetch is not patched, so skip waitForNetworkObservers\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    await page.evaluate((url) => fetch(url), `${TEST_FETCH_ORIGIN}/data`);\n    await page.waitForTimeout(200);\n\n    await page.evaluate(() => window.dispatchEvent(new Event('blur')));\n    await page.evaluate(() => (window as any).sessionReplay.flush(false) as Promise<void>);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    const fetchEvents = getFetchEvents();\n    const evt = fetchEvents.find((e) => String(e.url).includes(TEST_FETCH_ORIGIN));\n    expect(evt).toBeUndefined();\n  });\n});\n\n// ─── web worker mode ─────────────────────────────────────────────────────────\n\ntest.describe('web worker mode', () => {\n  test('sends full snapshot immediately without worker errors', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigRecording);\n\n    // Capture any SDK error logs — a worker crash emits an Amplitude Logger [Error] line\n    const workerErrors: string[] = [];\n    page.on('console', (msg) => {\n      if (msg.type() === 'error' && msg.text().includes('worker')) {\n        workerErrors.push(msg.text());\n      }\n    });\n\n    const requestPromise = page.waitForRequest('https://api-sr.amplitude.com/**', { timeout: 10_000 });\n    await mockTrackApi(page);\n\n    await page.goto(\n      buildUrl('/session-replay-browser/sr-capture-test.html', {\n        sessionId: TEST_SESSION_ID,\n        useWebWorker: true,\n      }),\n    );\n    await waitForReady(page);\n\n    // Full snapshot should be sent immediately (worker delivers it)\n    await requestPromise;\n    expect(workerErrors).toHaveLength(0);\n  });\n\n  test('sends events to the track API via worker when flushed', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigRecording);\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(\n      buildUrl('/session-replay-browser/sr-capture-test.html', {\n        sessionId: TEST_SESSION_ID,\n        useWebWorker: true,\n      }),\n    );\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    await page.evaluate(() => window.dispatchEvent(new Event('blur')));\n    await page.evaluate(() => (window as any).sessionReplay.flush(false) as Promise<void>);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    const bodies = getBodies();\n    expect(bodies.length).toBeGreaterThan(0);\n    const events = bodies.flatMap((b) => decodeAllEvents(b));\n    const fullSnapshot = events.find((e) => e['type'] === 2);\n    expect(fullSnapshot).toBeDefined();\n  });\n\n  test('sends payload with gzip Content-Encoding via worker', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigRecording);\n    const { getHeaders } = await captureTrackRequests(page);\n\n    await page.goto(\n      buildUrl('/session-replay-browser/sr-capture-test.html', {\n        sessionId: TEST_SESSION_ID,\n        useWebWorker: true,\n      }),\n    );\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    const headers = getHeaders();\n    expect(headers.length).toBeGreaterThan(0);\n    expect(headers[0]['content-encoding']).toBe('gzip');\n  });\n});\n\n// ─── 413 payload-too-large handling ──────────────────────────────────────────\n\ntest.describe('413 payload-too-large handling', () => {\n  test('retries with a split batch after receiving a 413', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigRecording);\n\n    let callCount = 0;\n    const deliveredBodies: string[] = [];\n\n    await page.route('https://api-sr.amplitude.com/**', async (route: Route) => {\n      callCount++;\n      if (callCount === 1) {\n        // Simulate the server rejecting the initial payload as too large\n        await route.fulfill({\n          status: 413,\n          contentType: 'application/json',\n          body: '{\"error\":\"Payload exceeds the maximum allowed size of 10MB\"}',\n        });\n      } else {\n        deliveredBodies.push(readRouteBody(route));\n        await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(SR_API_SUCCESS) });\n      }\n    });\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    await page.evaluate(() => window.dispatchEvent(new Event('blur')));\n    await page.evaluate(() => (window as any).sessionReplay.flush(false) as Promise<void>);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS * 4);\n\n    // After a 413 the SDK must retry — more than one request should be made\n    expect(callCount).toBeGreaterThan(1);\n    // Events must ultimately be delivered in the retry attempts\n    const events = deliveredBodies.flatMap((b) => decodeAllEvents(b));\n    expect(events.length).toBeGreaterThan(0);\n  });\n\n  test('does not enter a broken state after a 413 — subsequent flushes still deliver events', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigRecording);\n\n    let callCount = 0;\n    const deliveredBodies: string[] = [];\n\n    await page.route('https://api-sr.amplitude.com/**', async (route: Route) => {\n      callCount++;\n      if (callCount <= 2) {\n        await route.fulfill({\n          status: 413,\n          contentType: 'application/json',\n          body: '{\"error\":\"Payload exceeds the maximum allowed size of 10MB\"}',\n        });\n      } else {\n        deliveredBodies.push(readRouteBody(route));\n        await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(SR_API_SUCCESS) });\n      }\n    });\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    // First flush — will hit 413s\n    await page.evaluate(() => window.dispatchEvent(new Event('blur')));\n    await page.evaluate(() => (window as any).sessionReplay.flush(false) as Promise<void>);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS * 2);\n\n    // Add DOM activity and flush again — SDK must still be operational\n    await page.evaluate(() => {\n      const div = document.createElement('div');\n      div.textContent = 'post-413 activity';\n      document.body.appendChild(div);\n    });\n    await page.waitForTimeout(200);\n    await page.evaluate(() => (window as any).sessionReplay.flush(false) as Promise<void>);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS * 2);\n\n    // SDK should have made requests after the 413s and delivered events\n    expect(callCount).toBeGreaterThan(2);\n    expect(deliveredBodies.length).toBeGreaterThan(0);\n  });\n});\n\n// ─── SR-3115: improved replay data delivery ───────────────────────────────────\n\ntest.describe('SR-3115: improved replay data delivery', () => {\n  test('sends full snapshot immediately without waiting for explicit flush', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigRecording);\n\n    // Wait for the API request to be made automatically — no explicit flush()\n    const requestPromise = page.waitForRequest('https://api-sr.amplitude.com/**', { timeout: 10_000 });\n    await page.route('https://api-sr.amplitude.com/**', (route: Route) =>\n      route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(SR_API_SUCCESS) }),\n    );\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n\n    // The full snapshot should be sent immediately (no blur/flush needed)\n    const request = await requestPromise;\n    expect(request).toBeDefined();\n    expect(request.url()).toContain('api-sr.amplitude.com');\n  });\n\n  test('full snapshot request contains type 2 rrweb event', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigRecording);\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    // Give rrweb a moment to send the immediate full-snapshot flush\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    const bodies = getBodies();\n    expect(bodies.length).toBeGreaterThan(0);\n    const events = bodies.flatMap((b) => decodeAllEvents(b));\n    const fullSnapshot = events.find((e) => e['type'] === 2);\n    expect(fullSnapshot).toBeDefined();\n  });\n\n  test('sends payload with gzip Content-Encoding', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigRecording);\n    const { getHeaders } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    const headers = getHeaders();\n    expect(headers.length).toBeGreaterThan(0);\n    // Chromium supports CompressionStream, so all requests should be gzip-encoded\n    expect(headers[0]['content-encoding']).toBe('gzip');\n  });\n\n  test('sendBeacon is called on page hide with pending events', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigRecording);\n    // Intercept track API but intentionally delay responses so events accumulate\n    await page.route('https://api-sr.amplitude.com/**', async (route: Route) => {\n      await new Promise((r) => setTimeout(r, 5_000)); // hold response\n      await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(SR_API_SUCCESS) });\n    });\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    // Spy on navigator.sendBeacon before triggering page hide\n    await page.evaluate(() => {\n      (window as any).__beaconCalls = [] as string[];\n      const orig = navigator.sendBeacon.bind(navigator);\n      navigator.sendBeacon = (url: string, data?: BodyInit | null) => {\n        (window as any).__beaconCalls.push(url);\n        return orig(url, data);\n      };\n    });\n\n    // Trigger page hide to invoke the beacon fallback\n    await page.evaluate(() => window.dispatchEvent(new Event('pagehide')));\n    await page.waitForTimeout(200);\n\n    const beaconCalls = await page.evaluate(() => (window as any).__beaconCalls as string[]);\n    // The beacon should have been called with the track API URL\n    expect(beaconCalls.some((url: string) => url.includes('api-sr.amplitude.com'))).toBe(true);\n  });\n});\n\n// ─── retry behavior ───────────────────────────────────────────────────────────\n\ntest.describe('retry behavior', () => {\n  for (const statusCode of [408, 429, 499]) {\n    test(`retries and delivers events after initial ${statusCode}`, async ({ page }) => {\n      await mockRemoteConfig(page, remoteConfigRecording);\n\n      let callCount = 0;\n      const receivedBodies: string[] = [];\n      // Resolved by the route handler when the retry succeeds — avoids predicate race conditions.\n      let resolveRetry!: () => void;\n      const retryPromise = new Promise<void>((resolve) => {\n        resolveRetry = resolve;\n      });\n\n      await page.route('https://api-sr.amplitude.com/**', async (route: Route) => {\n        callCount++;\n        if (callCount === 1) {\n          await route.fulfill({ status: statusCode, body: '' });\n        } else {\n          receivedBodies.push(readRouteBody(route));\n          await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(SR_API_SUCCESS) });\n          resolveRetry();\n        }\n      });\n\n      await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n      await waitForReady(page);\n      await retryPromise;\n\n      expect(callCount).toBeGreaterThanOrEqual(2);\n      expect(receivedBodies.length).toBeGreaterThan(0);\n    });\n\n    test(`retries and delivers events after initial ${statusCode} (web worker)`, async ({ page }) => {\n      await mockRemoteConfig(page, remoteConfigRecording);\n\n      let callCount = 0;\n      const receivedBodies: string[] = [];\n      let resolveRetry!: () => void;\n      const retryPromise = new Promise<void>((resolve) => {\n        resolveRetry = resolve;\n      });\n\n      await page.route('https://api-sr.amplitude.com/**', async (route: Route) => {\n        callCount++;\n        if (callCount === 1) {\n          await route.fulfill({ status: statusCode, body: '' });\n        } else {\n          receivedBodies.push(readRouteBody(route));\n          await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(SR_API_SUCCESS) });\n          resolveRetry();\n        }\n      });\n\n      await page.goto(\n        buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID, useWebWorker: true }),\n      );\n      await waitForReady(page);\n      await retryPromise;\n\n      expect(callCount).toBeGreaterThanOrEqual(2);\n      expect(receivedBodies.length).toBeGreaterThan(0);\n    });\n  }\n});\n"
  },
  {
    "path": "packages/session-replay-browser/e2e/cross-origin-iframe.spec.ts",
    "content": "import { test, expect } from '@playwright/test';\nimport {\n  TEST_SESSION_ID,\n  SNAPSHOT_SETTLE_MS,\n  remoteConfigRecording,\n  mockRemoteConfig,\n  buildUrl,\n  waitForReady,\n  captureTrackRequests,\n  flushRecording,\n  getSnapshotRoot,\n  findById,\n} from './helpers';\n\nconst PARENT_PAGE = '/session-replay-browser/sr-cross-origin-iframe-parent.html';\nconst CHILD_PAGE = '/session-replay-browser/sr-cross-origin-iframe-child.html';\n\n/** Wait for the child iframe to appear and return the matching Playwright Frame. */\nasync function getChildFrame(page: import('@playwright/test').Page) {\n  await page.waitForSelector('#child-frame');\n  await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n  const childFrame = page.frames().find((f) => f.url().includes('sr-cross-origin-iframe-child'));\n  if (!childFrame) throw new Error('Child frame not found');\n  return childFrame;\n}\n\ntest.describe('cross-origin iframe recording', () => {\n  test.beforeEach(async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigRecording);\n  });\n\n  test('parent initializes without error with crossOriginIframes enabled', async ({ page }) => {\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PARENT_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n\n    const srError = await page.evaluate(() => (window as any).srError as string | undefined);\n    expect(srError).toBeUndefined();\n\n    await flushRecording(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    expect(getBodies().length).toBeGreaterThan(0);\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n    expect(findById(root!, 'parent-content')).toBeDefined();\n  });\n\n  test('coordinator sends start signal to dynamically-added child iframe', async ({ page }) => {\n    await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PARENT_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n\n    const childFrame = await getChildFrame(page);\n\n    // The child's raw onmessage listener (set before the SDK loads) must have\n    // received the start postMessage from the parent's CrossOriginIframeCoordinator.\n    const receivedStart = await childFrame.evaluate(() => (window as any).receivedStartSignal as boolean);\n    expect(receivedStart).toBe(true);\n  });\n\n  test('child page detects it is inside an iframe', async ({ page }) => {\n    await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PARENT_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n\n    const childFrame = await getChildFrame(page);\n\n    const childModeDetected = await childFrame.evaluate(() => (window as any).childModeDetected as boolean);\n    expect(childModeDetected).toBe(true);\n  });\n\n  test('coordinateChildren: false — child iframe does not receive start signal', async ({ page }) => {\n    await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PARENT_PAGE, { sessionId: TEST_SESSION_ID, coordinateChildren: 'false' }));\n    await waitForReady(page);\n\n    const childFrame = await getChildFrame(page);\n\n    // No start signal expected: coordinator is not started when coordinateChildren=false.\n    const receivedStart = await childFrame.evaluate(() => (window as any).receivedStartSignal as boolean);\n    expect(receivedStart).toBe(false);\n  });\n\n  test('child page initializes without error when loaded directly (not in an iframe)', async ({ page }) => {\n    await captureTrackRequests(page);\n\n    await page.goto(buildUrl(CHILD_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n\n    const srError = await page.evaluate(() => (window as any).srError as string | undefined);\n    expect(srError).toBeUndefined();\n\n    // Not in an iframe context, so child mode should not be detected.\n    const childModeDetected = await page.evaluate(() => (window as any).childModeDetected as boolean);\n    expect(childModeDetected).toBe(false);\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/e2e/guard.spec.ts",
    "content": "import { test, expect, Route } from '@playwright/test';\nimport {\n  SR_API_SUCCESS,\n  TEST_SESSION_ID,\n  SNAPSHOT_SETTLE_MS,\n  remoteConfigRecording,\n  mockRemoteConfig,\n  buildUrl,\n  waitForReady,\n  readRouteBody,\n} from './helpers';\n\nconst EVENT_FULL_SNAPSHOT = 2;\n\nfunction decodeAllEvents(rawBody: string): Array<Record<string, unknown>> {\n  if (!rawBody) return [];\n  let payload: { events?: unknown[] };\n  try {\n    payload = JSON.parse(rawBody) as { events?: unknown[] };\n  } catch {\n    return [];\n  }\n  if (!Array.isArray(payload.events)) return [];\n  const results: Array<Record<string, unknown>> = [];\n  for (const eventStr of payload.events) {\n    if (typeof eventStr !== 'string') continue;\n    try {\n      results.push(JSON.parse(eventStr) as Record<string, unknown>);\n    } catch {\n      // skip unparseable events\n    }\n  }\n  return results;\n}\n\nfunction countFullSnapshots(bodies: string[]): number {\n  return bodies.flatMap((b) => decodeAllEvents(b)).filter((e) => e['type'] === EVENT_FULL_SNAPSHOT).length;\n}\n\n// ─── recordEventsInFlight guard ───────────────────────────────────────────────\n\ntest.describe('recordEventsInFlight guard (SR-3531)', () => {\n  /**\n   * Baseline: a normal page load produces exactly one FullSnapshot.\n   * This verifies that the guard doesn't suppress the initial recording.\n   */\n  test('normal init produces exactly one FullSnapshot', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigRecording);\n\n    const rawBodies: string[] = [];\n    await page.route('https://api-sr.amplitude.com/**', async (route: Route) => {\n      rawBodies.push(readRouteBody(route));\n      await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(SR_API_SUCCESS) });\n    });\n\n    // Register waitForRequest before goto so the immediate full-snapshot flush\n    // (fired as soon as rrweb captures the snapshot) doesn't race past the listener.\n    const requestPromise = page.waitForRequest('https://api-sr.amplitude.com/**', { timeout: 10_000 });\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n\n    await requestPromise;\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    const count = countFullSnapshots(rawBodies);\n    expect(count).toBe(1);\n  });\n\n  /**\n   * Guard test: dispatch a focus event immediately after page load (while the\n   * async init chain — getRecordFunction / initializeNetworkObservers — is still\n   * in flight). The focusListener calls recordEvents(false), which should be\n   * dropped by the in-flight guard so that only one FullSnapshot is emitted.\n   */\n  test('focus event during async init does not produce a duplicate FullSnapshot', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigRecording);\n\n    const rawBodies: string[] = [];\n    await page.route('https://api-sr.amplitude.com/**', async (route: Route) => {\n      rawBodies.push(readRouteBody(route));\n      await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(SR_API_SUCCESS) });\n    });\n\n    // Register the listener early so the immediate flush doesn't escape.\n    const requestPromise = page.waitForRequest('https://api-sr.amplitude.com/**', { timeout: 10_000 });\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n\n    // Fire focus immediately — before waitForReady — to race with the async init chain.\n    await page.evaluate(() => window.dispatchEvent(new Event('focus')));\n\n    await waitForReady(page);\n    await requestPromise;\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    // Extra flush to capture any delayed events\n    await page.evaluate(() => window.dispatchEvent(new Event('blur')));\n    await page.evaluate(() => (window as any).sessionReplay.flush(false) as Promise<void>);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    const count = countFullSnapshots(rawBodies);\n    expect(count).toBe(1);\n  });\n\n  /**\n   * Known limitation (follow-up PR): a focus event fired AFTER recording is\n   * fully stable causes focusListener to call recordEvents(false), which stops\n   * and restarts rrweb — producing a second FullSnapshot. The guard does NOT\n   * suppress this because the first recordEvents() has already completed by the\n   * time focus fires. This test documents the current behavior so regressions are\n   * visible; it should be updated when the focusListener is made smarter.\n   */\n  test('focus event after stable recording produces a second FullSnapshot (known limitation)', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigRecording);\n\n    const rawBodies: string[] = [];\n    await page.route('https://api-sr.amplitude.com/**', async (route: Route) => {\n      rawBodies.push(readRouteBody(route));\n      await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(SR_API_SUCCESS) });\n    });\n\n    const requestPromise = page.waitForRequest('https://api-sr.amplitude.com/**', { timeout: 10_000 });\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await requestPromise;\n    // Let the initial recording fully stabilize\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    // Now fire focus — recording is idle so the guard allows a new recordEvents() through\n    await page.evaluate(() => window.dispatchEvent(new Event('focus')));\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    await page.evaluate(() => window.dispatchEvent(new Event('blur')));\n    await page.evaluate(() => (window as any).sessionReplay.flush(false) as Promise<void>);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    // Two FullSnapshots: one from init, one from the focus-triggered restart\n    const count = countFullSnapshots(rawBodies);\n    expect(count).toBe(2);\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/e2e/helpers.ts",
    "content": "import { gunzipSync } from 'zlib';\nimport { Route, Page } from '@playwright/test';\n\nexport const SR_API_SUCCESS = { code: 200 };\nexport const TEST_SESSION_ID = 1700000000000; // fixed timestamp always in sample at 100%\nexport const SNAPSHOT_SETTLE_MS = 500; // time for rrweb to capture its initial full snapshot\n\nexport const remoteConfigRecording = {\n  configs: { sessionReplay: { sr_sampling_config: { capture_enabled: true, sample_rate: 1.0 } } },\n};\n\nexport function mockRemoteConfig(page: Page, body: object) {\n  return page.route('https://sr-client-cfg.amplitude.com/**', (route: Route) =>\n    route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(body) }),\n  );\n}\n\nexport function buildUrl(path: string, params: Record<string, string | number | boolean> = {}): string {\n  const qs = new URLSearchParams(Object.entries(params).map(([k, v]) => [k, String(v)]));\n  return `${path}?${qs.toString()}`;\n}\n\nexport async function waitForReady(page: Page): Promise<void> {\n  await page.waitForFunction(() => (window as any).srReady === true, { timeout: 10_000 });\n}\n\n// ─── RRweb snapshot helpers ───────────────────────────────────────────────────\n\nexport type SnapNode = {\n  type: number;\n  tagName?: string;\n  attributes?: Record<string, string | boolean | null>;\n  textContent?: string;\n  childNodes?: SnapNode[];\n  needBlock?: boolean;\n};\n\nexport const NODE_ELEMENT = 2;\nexport const NODE_TEXT = 3;\nexport const EVENT_FULL_SNAPSHOT = 2;\n\nfunction decodeRrwebEvents(rawBody: string): unknown[] {\n  if (!rawBody) return [];\n  try {\n    const payload = JSON.parse(rawBody) as { events?: unknown[] };\n    if (!Array.isArray(payload.events)) return [];\n    return payload.events.flatMap((eventStr) => {\n      if (typeof eventStr !== 'string') return [];\n      try {\n        return [JSON.parse(eventStr) as unknown];\n      } catch {\n        return [];\n      }\n    });\n  } catch {\n    return [];\n  }\n}\n\nexport function getSnapshotRoot(rawBodies: string[]): SnapNode | null {\n  const events = rawBodies.flatMap(decodeRrwebEvents) as Array<{ type: number; data: { node: SnapNode } }>;\n  const snap = events.find((e) => e.type === EVENT_FULL_SNAPSHOT);\n  return snap ? snap.data.node : null;\n}\n\n/** Returns the root of the LAST full snapshot across all collected bodies. */\nexport function getLastSnapshotRoot(rawBodies: string[]): SnapNode | null {\n  const events = rawBodies.flatMap(decodeRrwebEvents) as Array<{ type: number; data: { node: SnapNode } }>;\n  const snaps = events.filter((e) => e.type === EVENT_FULL_SNAPSHOT);\n  const last = snaps[snaps.length - 1];\n  return last ? last.data.node : null;\n}\n\nexport function findNode(node: SnapNode, predicate: (n: SnapNode) => boolean): SnapNode | undefined {\n  if (predicate(node)) return node;\n  for (const child of node.childNodes ?? []) {\n    const found = findNode(child, predicate);\n    if (found) return found;\n  }\n  return undefined;\n}\n\nexport function findById(root: SnapNode, id: string): SnapNode | undefined {\n  return findNode(root, (n) => n.type === NODE_ELEMENT && n.attributes?.id === id);\n}\n\n/** Recursively concatenates all text node content under a node. */\nexport function getTextContent(node: SnapNode): string {\n  if (node.type === NODE_TEXT) return node.textContent ?? '';\n  return (node.childNodes ?? []).map(getTextContent).join('');\n}\n\n/**\n * Returns true if the text consists only of asterisks (and whitespace).\n * maskFn replaces every non-whitespace char with '*', preserving spaces.\n */\nexport function isMaskedText(text: string): boolean {\n  const stripped = text.replace(/\\s/g, '');\n  return stripped.length > 0 && /^\\*+$/.test(stripped);\n}\n\n/**\n * Reads the POST body from a Playwright Route, decompressing gzip if needed.\n * Use this inside page.route() handlers for the track API.\n */\nexport function readRouteBody(route: Route): string {\n  const headers = route.request().headers();\n  if (headers['content-encoding'] === 'gzip') {\n    const buf = route.request().postDataBuffer();\n    return buf ? gunzipSync(buf).toString('utf-8') : '';\n  }\n  return route.request().postData() ?? '';\n}\n\n/** Mocks the track API and returns getters for the raw POST bodies and request headers received. */\nexport async function captureTrackRequests(\n  page: Page,\n): Promise<{ getBodies: () => string[]; getHeaders: () => Record<string, string>[] }> {\n  const rawBodies: string[] = [];\n  const requestHeaders: Record<string, string>[] = [];\n  await page.route('https://api-sr.amplitude.com/**', async (route: Route) => {\n    requestHeaders.push(route.request().headers());\n    rawBodies.push(readRouteBody(route));\n    await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(SR_API_SUCCESS) });\n  });\n  return { getBodies: () => rawBodies, getHeaders: () => requestHeaders };\n}\n\n/** Triggers a blur-flush cycle and waits for events to be delivered. */\nexport async function flushRecording(page: Page): Promise<void> {\n  await page.evaluate(() => window.dispatchEvent(new Event('blur')));\n  await page.evaluate(() => (window as any).sessionReplay.flush(false) as Promise<void>);\n  await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n}\n"
  },
  {
    "path": "packages/session-replay-browser/e2e/idb.spec.ts",
    "content": "/**\n * E2E tests for IndexedDB transaction abort handling.\n *\n * These tests repro the scenario described in the \"indexed-db-transaction-aborted\" branch:\n *   \"Failed to store session replay events in IndexedDB: AbortError: The transaction was\n *    aborted, so the request cannot be fulfilled.\"\n *\n * Three root causes were fixed:\n *\n * 1. `addEventToCurrentSequence` — first-event path (`!sequenceEvents`): used to `return`\n *    immediately after `await tx.store.put(...)`, leaving `tx.done` rejection unhandled.\n *    Fix: attach `tx.done.catch(logIdbError)` before any await.\n *\n * 2. `getSequencesToSend` — inline transaction had no saved reference, so `tx.done` was\n *    never caught. An abort after cursor exhaustion produced an unhandled rejection.\n *    Fix: save `tx` and attach `tx.done.catch(logIdbError)` before any await.\n *\n * 3. `addEventToCurrentSequence` — split path: used to call `storeSendingEvents` in a\n *    separate transaction after the `sessionCurrentSequence` transaction, breaking\n *    atomicity. If the first transaction aborted, events could end up in both stores.\n *    Fix: use a single multi-store transaction (`splitTx`) covering both stores so both\n *    writes commit or roll back atomically.\n *\n * All AbortErrors are routed through `logIdbError`, which downgrades them from\n * `warn` → `debug` (transient browser-initiated aborts, not actionable).\n *\n * Technique: `page.addInitScript` patches `IDBObjectStore.prototype.put` and\n * `.openCursor` before the SDK loads. `window.__armIdbAbort(storeName)` arms a\n * one-shot abort on the next write/cursor-open for that store; `window.__idbAbortFired`\n * confirms it triggered.\n *\n * Log-level note: tests use `logLevel: 4` (Debug) so both `[Warn]` and `[Debug]`\n * messages are visible. Assertions check:\n *   - `[Warn]: Failed to store session replay events in IndexedDB` → must NOT appear\n *   - `[Debug]: Failed to store session replay events in IndexedDB` → must appear exactly once\n *   - `page.on('pageerror', …)` → must stay empty (the core unhandled-rejection guard)\n */\n\nimport { test, expect } from '@playwright/test';\nimport {\n  mockRemoteConfig,\n  buildUrl,\n  waitForReady,\n  remoteConfigRecording,\n  captureTrackRequests,\n  TEST_SESSION_ID,\n  SR_API_SUCCESS,\n} from './helpers';\n\n// ─── Constants ───────────────────────────────────────────────────────────────\n\nconst STORAGE_FAILURE = 'Failed to store session replay events in IndexedDB';\nconst LOG_LEVEL_DEBUG = 4; // LogLevel.Debug — shows all messages including debug + warn\n// DB name derived from apiKey in sr-capture-test.html: 'd90c5cf09ca2546a1626272906b99a76'\nconst IDB_NAME = 'd90c5cf09c_amp_session_replay_events';\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\n/**\n * Injects a one-shot IDB abort interceptor into the page before any scripts run.\n *\n * Arm via `window.__armIdbAbort(storeName)` — the next write (`put`) or cursor open\n * (`openCursor`) on that store will be allowed to complete, then the surrounding\n * transaction is immediately aborted. `window.__idbAbortFired` is set to `true`\n * once the abort fires.\n *\n * Patches only `IDBObjectStore.prototype.put` and `.openCursor`.\n */\nfunction injectIdbAbortInterceptor(page: import('@playwright/test').Page) {\n  return page.addInitScript(() => {\n    let _store: string | null = null;\n    (window as any).__armIdbAbort = (store: string) => {\n      _store = store;\n    };\n    (window as any).__idbAbortFired = false;\n\n    function patchRequest(req: IDBRequest, storeName: string, tx: IDBTransaction) {\n      if (_store !== storeName) return;\n      _store = null; // one-shot\n      req.addEventListener(\n        'success',\n        () => {\n          (window as any).__idbAbortFired = true;\n          try {\n            tx.abort();\n          } catch {\n            // already committed — ignore\n          }\n        },\n        { once: true },\n      );\n    }\n\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    const origPut = IDBObjectStore.prototype.put;\n    IDBObjectStore.prototype.put = function (v, k) {\n      const req = origPut.call(this, v, k);\n      patchRequest(req, this.name, this.transaction);\n      return req;\n    };\n\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    const origCursor = IDBObjectStore.prototype.openCursor;\n    IDBObjectStore.prototype.openCursor = function (q, d) {\n      const req = origCursor.call(this, q, d);\n      patchRequest(req, this.name, this.transaction);\n      return req;\n    };\n  });\n}\n\n/**\n * Sets up listeners for IDB-related errors and log messages.\n *\n * Returns live arrays that fill as the page runs:\n *   pageErrors — unhandled Promise rejections (the core regression guard; before the\n *                fix, AbortErrors from tx.done surfaced here)\n *   idbWarns   — console.warn lines containing STORAGE_FAILURE\n *   idbDebug   — console.log lines containing STORAGE_FAILURE (Amplitude logs debug\n *                via console.log at LogLevel.Debug)\n */\nfunction listenForIdbErrors(page: import('@playwright/test').Page) {\n  const pageErrors: Error[] = [];\n  const idbWarns: string[] = [];\n  const idbDebug: string[] = [];\n  page.on('pageerror', (err) => pageErrors.push(err));\n  page.on('console', (msg) => {\n    if (!msg.text().includes(STORAGE_FAILURE)) return;\n    if (msg.type() === 'warning') idbWarns.push(msg.text());\n    if (msg.type() === 'log') idbDebug.push(msg.text());\n  });\n  return { pageErrors, idbWarns, idbDebug };\n}\n\n/**\n * Reads row counts from the two IDB object stores used by the session replay SDK.\n * Used to verify atomicity: a rolled-back split transaction must leave neither store\n * partially written.\n */\nfunction getIdbStoreCounts(page: import('@playwright/test').Page) {\n  return page.evaluate(\n    (dbName: string): Promise<{ sequencesToSend: number; currentSequence: number }> =>\n      new Promise((resolve, reject) => {\n        const req = indexedDB.open(dbName);\n        req.onerror = () => reject(req.error);\n        req.onsuccess = () => {\n          const db = req.result;\n          const tx = db.transaction(['sequencesToSend', 'sessionCurrentSequence'], 'readonly');\n          const c1 = tx.objectStore('sequencesToSend').count();\n          const c2 = tx.objectStore('sessionCurrentSequence').count();\n          tx.oncomplete = () => resolve({ sequencesToSend: c1.result, currentSequence: c2.result });\n          tx.onerror = () => reject(tx.error);\n        };\n      }),\n    IDB_NAME,\n  );\n}\n\n/** Navigate to the SR test page and wait for the SDK to be ready. */\nasync function loadPage(page: import('@playwright/test').Page, sessionId = TEST_SESSION_ID) {\n  await mockRemoteConfig(page, remoteConfigRecording);\n  await page.route('https://api-sr.amplitude.com/**', (route) =>\n    route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(SR_API_SUCCESS) }),\n  );\n  await page.goto(\n    buildUrl('/session-replay-browser/sr-capture-test.html', {\n      sessionId,\n      logLevel: LOG_LEVEL_DEBUG,\n      storeType: 'idb',\n    }),\n  );\n  await waitForReady(page);\n}\n\n// ─── Tests ───────────────────────────────────────────────────────────────────\n\ntest.describe('IDB transaction abort handling', () => {\n  /**\n   * Repro: addEventToCurrentSequence — first-event path (no existing sequence).\n   *\n   * The first rrweb event for a session takes the `!sequenceEvents` branch:\n   *   tx.store.get(sessionId)  → undefined\n   *   tx.store.put(...)        → put succeeds\n   *   [old code] return;       ← tx.done rejection was unhandled\n   *   [new code] tx.done.catch(logIdbError) ← attached before any await → debug\n   *\n   * We arm the interceptor before page load so the abort fires on the very first\n   * put to `sessionCurrentSequence` (the rrweb full snapshot).\n   */\n  test('addEventToCurrentSequence first-event path: AbortError logged at debug not warn', async ({ page }) => {\n    await injectIdbAbortInterceptor(page);\n    // Arm before navigation — catches the first IDB write (rrweb full snapshot)\n    await page.addInitScript(() => {\n      (window as any).__armIdbAbort('sessionCurrentSequence');\n    });\n\n    const { pageErrors, idbWarns, idbDebug } = listenForIdbErrors(page);\n    await loadPage(page);\n    await page.waitForTimeout(300);\n\n    expect(await page.evaluate(() => (window as any).__idbAbortFired as boolean)).toBe(true);\n    // tx.done rejection must be handled — the core regression guard\n    expect(pageErrors).toHaveLength(0);\n    // Error must reach logIdbError → debug, not warn; exactly once (errorLogged flag)\n    expect(idbWarns).toHaveLength(0);\n    expect(idbDebug).toHaveLength(1);\n  });\n\n  /**\n   * Repro: addEventToCurrentSequence — existing-events path (append, no split).\n   *\n   * After the first event is stored, subsequent events take the else branch:\n   *   tx.store.get(sessionId)  → existing sequence\n   *   tx.store.put(...)        → append + put succeeds, then tx aborts\n   *\n   * We arm the interceptor after page load (snapshot already stored) and trigger\n   * a new event via a click, while staying within the 500 ms split interval so\n   * the append (not split) path is taken.\n   */\n  test('addEventToCurrentSequence existing-events path: AbortError logged at debug not warn', async ({ page }) => {\n    await injectIdbAbortInterceptor(page);\n    const { pageErrors, idbWarns, idbDebug } = listenForIdbErrors(page);\n\n    await loadPage(page);\n    // Arm after load — snapshot already stored; next write is an append\n    await page.evaluate(() => void (window as any).__armIdbAbort('sessionCurrentSequence'));\n    await page.click('#test-button');\n    await page.waitForTimeout(300);\n\n    expect(await page.evaluate(() => (window as any).__idbAbortFired as boolean)).toBe(true);\n    expect(pageErrors).toHaveLength(0);\n    expect(idbWarns).toHaveLength(0);\n    expect(idbDebug).toHaveLength(1);\n  });\n\n  /**\n   * Repro: addEventToCurrentSequence — split path (shouldSplitEventsList = true).\n   *\n   * After MIN_INTERVAL (500 ms) elapses, the next event triggers a time-based split.\n   * The split uses a single multi-store transaction (`splitTx`) that writes to both\n   * `sessionCurrentSequence` (reset) and `sequencesToSend` (new sequence).\n   * We arm the abort on `sequencesToSend` to catch the split transaction.\n   *\n   * Fix: `splitTx.done.catch(logIdbError)` is attached before any await, so the\n   * AbortError is always routed through logIdbError → debug level.\n   */\n  test('addEventToCurrentSequence split path: AbortError logged at debug not warn', async ({ page }) => {\n    await injectIdbAbortInterceptor(page);\n    const { pageErrors, idbWarns, idbDebug } = listenForIdbErrors(page);\n\n    await loadPage(page);\n    // Wait for the time-based split interval to elapse (MIN_INTERVAL = 500 ms)\n    await page.waitForTimeout(600);\n\n    // Arm abort on 'sequencesToSend' — the store the split transaction writes to last.\n    // The next click will trigger shouldSplitEventsList = true (time-based), opening\n    // splitTx; the interceptor aborts splitTx after the sequencesToSend put succeeds.\n    await page.evaluate(() => void (window as any).__armIdbAbort('sequencesToSend'));\n    await page.click('#test-button');\n    await page.waitForTimeout(300);\n\n    expect(await page.evaluate(() => (window as any).__idbAbortFired as boolean)).toBe(true);\n    expect(pageErrors).toHaveLength(0);\n    expect(idbWarns).toHaveLength(0);\n    expect(idbDebug).toHaveLength(1);\n  });\n\n  /**\n   * Atomicity: split-path abort leaves no partial writes in IDB.\n   *\n   * When `splitTx` aborts, both the `sessionCurrentSequence` reset and the\n   * `sequencesToSend` insert must roll back atomically:\n   *   - sequencesToSend.count() === 0  (write rolled back — no orphaned sequence)\n   *   - sessionCurrentSequence.count() === 1  (not cleared — events still present)\n   *\n   * If atomicity were broken (e.g. two separate transactions), `sequencesToSend`\n   * would hold a partial write and the same events would be sent twice on the next\n   * flush.\n   */\n  test('addEventToCurrentSequence split path: atomic abort leaves no partial writes', async ({ page }) => {\n    await injectIdbAbortInterceptor(page);\n\n    await loadPage(page);\n    await page.waitForTimeout(600); // wait for MIN_INTERVAL to elapse\n\n    await page.evaluate(() => void (window as any).__armIdbAbort('sequencesToSend'));\n    await page.click('#test-button');\n    await page.waitForTimeout(300);\n\n    expect(await page.evaluate(() => (window as any).__idbAbortFired as boolean)).toBe(true);\n\n    const counts = await getIdbStoreCounts(page);\n    expect(counts.sequencesToSend).toBe(0); // write rolled back — no orphaned sequence\n    expect(counts.currentSequence).toBe(1); // not cleared — pre-split events still present\n  });\n\n  /**\n   * Repro: getSequencesToSend — cursor abort mid-traversal.\n   *\n   * `getSequencesToSend` is called by `sendStoredEvents` during SDK initialisation.\n   * It reads stored sequences via a cursor on `sequencesToSend`. An abort while the\n   * cursor is open causes `tx.done` to reject with AbortError.\n   *\n   * Fix: save `tx` and attach `tx.done.catch(logIdbError)` before any await.\n   *\n   * Because `getSequencesToSend` is only triggered on page load, this test uses a\n   * two-navigation approach:\n   *   1. Load normally so IDB is populated.\n   *   2. Arm via sessionStorage (persists across reloads).\n   *   3. Reload — init() → sendStoredEvents → getSequencesToSend → cursor abort.\n   */\n  test('getSequencesToSend cursor abort: AbortError logged at debug not warn', async ({ page }) => {\n    await injectIdbAbortInterceptor(page);\n    // Second init script: arm the cursor abort on reload if the sessionStorage flag is set.\n    // Runs after injectIdbAbortInterceptor so __armIdbAbort is already defined.\n    await page.addInitScript(() => {\n      if (sessionStorage.getItem('__armCursorAbort') === '1') {\n        sessionStorage.removeItem('__armCursorAbort');\n        (window as any).__armIdbAbort('sequencesToSend');\n      }\n    });\n\n    const { pageErrors, idbWarns, idbDebug } = listenForIdbErrors(page);\n\n    // First load: SDK initialises and records normally (cursor abort not yet armed)\n    await loadPage(page);\n\n    // Arm for the next navigation via sessionStorage\n    await page.evaluate(() => sessionStorage.setItem('__armCursorAbort', '1'));\n\n    // Reload: init() → initialize(true) → sendStoredEvents → getSequencesToSend → abort\n    await page.reload();\n    await waitForReady(page);\n    await page.waitForTimeout(300);\n\n    expect(await page.evaluate(() => (window as any).__idbAbortFired as boolean)).toBe(true);\n    expect(pageErrors).toHaveLength(0);\n    expect(idbWarns).toHaveLength(0);\n    expect(idbDebug).toHaveLength(1);\n  });\n\n  /**\n   * Resilience: the SDK continues recording after an IDB abort.\n   *\n   * An IDB transaction abort is transient — the SDK should recover and be able to\n   * record and flush subsequent events. Verifies:\n   *   1. Abort is handled gracefully (no crash, no unhandled rejection, no warn)\n   *   2. After the abort, the SDK can still receive new events and flush them\n   */\n  test('SDK continues recording after IDB abort', async ({ page }) => {\n    await injectIdbAbortInterceptor(page);\n    // Arm before load → aborts the very first IDB write (rrweb full snapshot)\n    await page.addInitScript(() => {\n      (window as any).__armIdbAbort('sessionCurrentSequence');\n    });\n\n    const { pageErrors, idbWarns, idbDebug } = listenForIdbErrors(page);\n    const { getBodies } = await captureTrackRequests(page);\n\n    await mockRemoteConfig(page, remoteConfigRecording);\n    await page.goto(\n      buildUrl('/session-replay-browser/sr-capture-test.html', {\n        sessionId: TEST_SESSION_ID,\n        logLevel: LOG_LEVEL_DEBUG,\n        storeType: 'idb',\n      }),\n    );\n    await waitForReady(page);\n    await page.waitForTimeout(200);\n\n    // Generate new events after the abort\n    await page.click('#test-button');\n    await page.click('#test-input');\n\n    // Flush and verify events are delivered\n    await page.evaluate(() => window.dispatchEvent(new Event('blur')));\n    await page.evaluate(() => void (window as any).sessionReplay.flush(false));\n    await page.waitForTimeout(500);\n\n    // SDK should have recovered and sent at least one batch of events\n    expect(getBodies().length).toBeGreaterThan(0);\n\n    // Abort must be handled and logged at debug (not warn), exactly once\n    expect(pageErrors).toHaveLength(0);\n    expect(idbWarns).toHaveLength(0);\n    expect(idbDebug).toHaveLength(1);\n  });\n\n  /**\n   * Baseline: no IDB errors during normal operation.\n   *\n   * Sanity check that in a normal recording session (no forced aborts) there are\n   * no IDB-related warnings, debug-level storage errors, or page errors at all.\n   */\n  test('normal recording: no IDB errors', async ({ page }) => {\n    const { pageErrors, idbWarns, idbDebug } = listenForIdbErrors(page);\n\n    await loadPage(page);\n    await page.click('#test-button');\n    await page.click('#test-input');\n    await page.evaluate(() => window.dispatchEvent(new Event('blur')));\n    await page.evaluate(() => void (window as any).sessionReplay.flush(false));\n    await page.waitForTimeout(300);\n\n    expect(pageErrors).toHaveLength(0);\n    expect(idbWarns).toHaveLength(0);\n    expect(idbDebug).toHaveLength(0);\n  });\n});\n\n// ─── Multi-tab and fallback tests ─────────────────────────────────────────────\n\n/**\n * Reads the unique event-string contents of every record across both IDB stores\n * (sequencesToSend.events + sessionCurrentSequence.events), regardless of tabId.\n * Used to verify that no events were dropped across a multi-tab interleaving.\n */\nfunction getAllPersistedEvents(page: import('@playwright/test').Page) {\n  return page.evaluate(\n    (dbName: string): Promise<string[]> =>\n      new Promise((resolve, reject) => {\n        const req = indexedDB.open(dbName);\n        req.onerror = () => reject(req.error);\n        req.onsuccess = () => {\n          const db = req.result;\n          const tx = db.transaction(['sequencesToSend', 'sessionCurrentSequence'], 'readonly');\n          const all: string[] = [];\n          const onCursor = (req: IDBRequest<IDBCursorWithValue | null>) => {\n            req.onsuccess = () => {\n              const cursor = req.result;\n              if (cursor) {\n                const value = cursor.value as { events: string[] };\n                for (const ev of value.events ?? []) all.push(ev);\n                cursor.continue();\n              }\n            };\n          };\n          onCursor(tx.objectStore('sequencesToSend').openCursor());\n          onCursor(tx.objectStore('sessionCurrentSequence').openCursor());\n          tx.oncomplete = () => resolve(all);\n          tx.onerror = () => reject(tx.error);\n        };\n      }),\n    IDB_NAME,\n  );\n}\n\n/**\n * Tags each rrweb event with a unique marker before it is sent to the SDK by\n * monkey-patching `sessionReplay.addEvent` is too invasive — instead we inject\n * synthetic events via the public API.  A simpler approach: emit user events\n * (clicks) which the SDK captures with timestamps — we count unique events.\n */\n\ntest.describe('IDB multi-tab and fallback behaviour', () => {\n  /**\n   * Multi-tab invariant: when two tabs in the same browser context record events\n   * for the same sessionId, ALL events from both tabs eventually appear in the\n   * shared IndexedDB across the two stores.  Pre-fix, Tab A's\n   * addEventToCurrentSequence would silently overwrite Tab B's in-progress events.\n   * Post-fix, Tab A promotes Tab B's events to sequencesToSend before claiming\n   * the slot, so nothing is dropped.\n   *\n   * We can't easily count rrweb events one-by-one because rrweb captures large\n   * sets of mutation events asynchronously.  Instead we count the total number\n   * of stored events across both tabs and verify it matches the sum of what each\n   * tab generated independently — within a small tolerance for non-deterministic\n   * snapshot timing.  More importantly we tag tab-B events with a deterministic\n   * marker (a blur trigger after a known click) and verify those events SURVIVE\n   * the cross-tab claim.\n   */\n  test('multi-tab: events from both tabs survive in shared IDB (cross-tab promote)', async ({ browser }) => {\n    // Single context = shared origin, shared IndexedDB.  Each `page` in the\n    // context is a real browser tab from the SDK's perspective (each gets a\n    // distinct in-memory UUID as its tabId).\n    const context = await browser.newContext();\n    const tabA = await context.newPage();\n    const tabB = await context.newPage();\n\n    try {\n      const allErrorsA: Error[] = [];\n      const allErrorsB: Error[] = [];\n      tabA.on('pageerror', (e) => allErrorsA.push(e));\n      tabB.on('pageerror', (e) => allErrorsB.push(e));\n\n      // Mock remote config and SR API on each tab.\n      for (const p of [tabA, tabB]) {\n        await mockRemoteConfig(p, remoteConfigRecording);\n        await p.route('https://api-sr.amplitude.com/**', (route) =>\n          route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(SR_API_SUCCESS) }),\n        );\n      }\n\n      // Load Tab A, then Tab B with the same sessionId.  They will share the\n      // same IDB database (same origin) and pick up unique in-memory tabIds.\n      const url = buildUrl('/session-replay-browser/sr-capture-test.html', {\n        sessionId: TEST_SESSION_ID,\n        logLevel: LOG_LEVEL_DEBUG,\n        storeType: 'idb',\n      });\n\n      await tabA.goto(url);\n      await waitForReady(tabA);\n\n      await tabB.goto(url);\n      await waitForReady(tabB);\n\n      // Generate events on each tab. Interleave clicks so the two tabs ping-pong\n      // writes to the shared sessionCurrentSequence slot.\n      for (let i = 0; i < 3; i++) {\n        await tabA.click('#test-button');\n        await tabB.click('#test-button');\n        await tabA.click('#test-input');\n        await tabB.click('#test-input');\n      }\n\n      // Give rrweb time to flush captured mutations into IDB.\n      await tabA.waitForTimeout(300);\n      await tabB.waitForTimeout(300);\n\n      // Read the union of all persisted events from both stores.  Use either\n      // tab — both see the same database.\n      const allEvents = await getAllPersistedEvents(tabA);\n\n      // Pre-fix this would lose most cross-tab events.  We can't count exact\n      // numbers because rrweb is asynchronous, but the total must be reasonably\n      // large (tens of events from two tabs of clicks + snapshots).  We assert a\n      // floor that is comfortably above what a single tab alone would produce\n      // had cross-tab events been dropped.\n      // (Each click triggers multiple rrweb events; with 6 clicks per tab and\n      //  full snapshots we expect >> 10 total.)\n      expect(allEvents.length).toBeGreaterThan(10);\n\n      // No unhandled promise rejections from either tab.\n      expect(allErrorsA).toHaveLength(0);\n      expect(allErrorsB).toHaveLength(0);\n    } finally {\n      await tabA.close();\n      await tabB.close();\n      await context.close();\n    }\n  });\n\n  /**\n   * Multi-tab atomicity: storeCurrentSequence + concurrent addEventToCurrentSequence.\n   *\n   * Verifies that a flush in Tab A and a recording in Tab B do not lose events\n   * even when they race.  We trigger Tab A's flush (which calls\n   * sendCurrentSequenceEvents → store.storeCurrentSequence) at the same time as\n   * Tab B is generating events.  Pre-fix this could lose Tab B's events because\n   * storeCurrentSequence was three separate transactions.  Post-fix the entire\n   * promote+reset is atomic, so events appended after the read either land in\n   * the next sequence or in a new current sequence — never dropped.\n   */\n  test('multi-tab: storeCurrentSequence atomicity under concurrent addEvent', async ({ browser }) => {\n    const context = await browser.newContext();\n    const tabA = await context.newPage();\n    const tabB = await context.newPage();\n\n    try {\n      const errors: Error[] = [];\n      tabA.on('pageerror', (e) => errors.push(e));\n      tabB.on('pageerror', (e) => errors.push(e));\n\n      // Capture all events delivered to the track API across both tabs.  Counting\n      // sent events (rather than persisted-but-unsent) is the right invariant: a\n      // non-atomic storeCurrentSequence would drop events that were appended after\n      // the read but before the reset, so they would never be sent at all.  With\n      // the fix, every appended event either lands in the flushed sequence (sent)\n      // or the next current-sequence (persisted), and overall throughput is\n      // preserved.\n      const trackBodies: string[] = [];\n      for (const p of [tabA, tabB]) {\n        await mockRemoteConfig(p, remoteConfigRecording);\n        await p.route('https://api-sr.amplitude.com/**', async (route) => {\n          const body = route.request().postData() ?? '';\n          trackBodies.push(body);\n          await route.fulfill({\n            status: 200,\n            contentType: 'application/json',\n            body: JSON.stringify(SR_API_SUCCESS),\n          });\n        });\n      }\n\n      const url = buildUrl('/session-replay-browser/sr-capture-test.html', {\n        sessionId: TEST_SESSION_ID,\n        logLevel: LOG_LEVEL_DEBUG,\n        storeType: 'idb',\n      });\n\n      await tabA.goto(url);\n      await waitForReady(tabA);\n      await tabB.goto(url);\n      await waitForReady(tabB);\n\n      // Race: Tab A flushes (which triggers sendCurrentSequenceEvents →\n      // storeCurrentSequence) at the same time that Tab B is generating events\n      // for the same sessionId.  IDB serialises overlapping readwrite transactions,\n      // so atomic storeCurrentSequence guarantees no event is dropped between the\n      // read and the slot reset.\n      const racy = Promise.all([\n        (async () => {\n          for (let i = 0; i < 5; i++) {\n            await tabB.click('#test-button');\n          }\n        })(),\n        tabA.evaluate(() => window.dispatchEvent(new Event('blur'))),\n        tabA.evaluate(() => void (window as any).sessionReplay.flush(false)),\n      ]);\n      await racy;\n      await tabA.waitForTimeout(300);\n      await tabB.waitForTimeout(300);\n\n      // Force both tabs to flush remaining events to the track API.\n      await tabB.evaluate(() => window.dispatchEvent(new Event('blur')));\n      await tabB.evaluate(() => void (window as any).sessionReplay.flush(false));\n      await tabA.waitForTimeout(300);\n      await tabB.waitForTimeout(300);\n\n      // Combined view: storeCurrentSequence atomicity + sent events from both tabs\n      // should have produced multiple non-empty track API requests.  Pre-fix, a\n      // race between storeCurrentSequence on Tab A and addEventToCurrentSequence\n      // on Tab B could silently lose events.\n      expect(trackBodies.length).toBeGreaterThan(0);\n\n      // Verify the bodies actually contain rrweb events (non-empty payloads).\n      const totalPayloadBytes = trackBodies.reduce((acc, b) => acc + b.length, 0);\n      expect(totalPayloadBytes).toBeGreaterThan(100);\n\n      // No unhandled rejections from the concurrent storeCurrentSequence path.\n      expect(errors).toHaveLength(0);\n    } finally {\n      await tabA.close();\n      await tabB.close();\n      await context.close();\n    }\n  });\n\n  /**\n   * IDB-fail-and-fallback: when IDB fails persistently, the SDK should fall back\n   * to the in-memory store on the FIRST failure (consecutiveFailureThreshold\n   * defaults to 1) and continue recording without crashing or losing future events.\n   *\n   * Strategy: patch IDBObjectStore.prototype.put to throw synchronously on EVERY\n   * call (not just one).  The first IDB write throws, recordFailure() runs,\n   * onPersistentFailure → switchToMemoryStore is invoked, and the in-memory store\n   * takes over.  Subsequent events are recorded in memory and successfully sent\n   * to the track API.\n   */\n  test('IDB persistent failure: SDK falls back to memory store immediately on first error', async ({ page }) => {\n    // Patch IDB before any SDK code runs.  Every put() throws a synthetic error;\n    // openCursor is left alone so getSequencesToSend (called once at init) can\n    // still complete with an empty cursor.\n    await page.addInitScript(() => {\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      const origPut = IDBObjectStore.prototype.put;\n      let putCallCount = 0;\n      (window as any).__idbPutCalls = () => putCallCount;\n      IDBObjectStore.prototype.put = function (...args: unknown[]) {\n        putCallCount++;\n        // Throw synchronously — same effect as a real IDB QuotaExceededError.\n        throw new DOMException('Simulated IDB put failure', 'QuotaExceededError');\n        // unreachable, but keeps types happy\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n        return (origPut as any).apply(this, args);\n      } as typeof IDBObjectStore.prototype.put;\n    });\n\n    const { pageErrors } = listenForIdbErrors(page);\n    const { getBodies } = await captureTrackRequests(page);\n\n    // Look for the explicit fallback warn from events-manager.ts.\n    const fallbackWarns: string[] = [];\n    page.on('console', (msg) => {\n      if (msg.text().includes('falling back to in-memory event store')) {\n        fallbackWarns.push(msg.text());\n      }\n    });\n\n    // Manual setup (not loadPage) so captureTrackRequests' route handler stays\n    // active — loadPage installs a second route on the same URL which would\n    // intercept before captureTrackRequests can record bodies.\n    await mockRemoteConfig(page, remoteConfigRecording);\n    await page.goto(\n      buildUrl('/session-replay-browser/sr-capture-test.html', {\n        sessionId: TEST_SESSION_ID,\n        logLevel: LOG_LEVEL_DEBUG,\n        storeType: 'idb',\n      }),\n    );\n    await waitForReady(page);\n    await page.waitForTimeout(300);\n\n    // Generate events AFTER the fallback has been triggered.\n    await page.click('#test-button');\n    await page.click('#test-input');\n    await page.click('#test-button');\n\n    // Flush.  Memory store is now active so events should be sent successfully.\n    await page.evaluate(() => window.dispatchEvent(new Event('blur')));\n    await page.evaluate(() => void (window as any).sessionReplay.flush(false));\n    await page.waitForTimeout(500);\n\n    // 1. The fallback warn was logged exactly once (or at least once — repeated\n    //    failures should not spam if hasTriggeredFallback guards it).\n    expect(fallbackWarns.length).toBeGreaterThanOrEqual(1);\n\n    // 2. At least one batch of events was delivered to the track API after\n    //    fallback — proves the SDK kept recording in memory.\n    expect(getBodies().length).toBeGreaterThan(0);\n\n    // 3. Zero unhandled promise rejections — the IDB failures must all be caught.\n    expect(pageErrors).toHaveLength(0);\n\n    // 4. IDB put was attempted at least once (proving we exercised the failure\n    //    path) — but not many times, because fallback should occur immediately.\n    const putCalls = await page.evaluate(() => (window as any).__idbPutCalls() as number);\n    expect(putCalls).toBeGreaterThanOrEqual(1);\n  });\n\n  /**\n   * Hang-protection regression guard: if `indexedDB.open()` never fires\n   * `onsuccess`/`onerror` (the documented Chrome-blocked-by-other-tab and\n   * \"closing\" scenarios), the SDK must NOT hang waiting for IDB.  The 2s\n   * timeout in `createStore` rejects, `SessionReplayEventsIDBStore.new()`\n   * returns undefined, and the events-manager falls back to the in-memory\n   * store.  Recording must continue normally.\n   *\n   * Strategy: monkey-patch `indexedDB.open` before any SDK code runs so the\n   * returned IDBOpenDBRequest never settles.  Then verify:\n   *   1. The SDK initialises within ~3s (well below the 10s `waitForReady`\n   *      and below the 2s timeout + a small grace margin)\n   *   2. Recording produces events that get delivered to the track API\n   *   3. No unhandled promise rejections leak\n   */\n  test('IDB openDB hang: SDK initialises within 3s and falls back to memory store', async ({ page }) => {\n    // Patch indexedDB.open BEFORE any SDK code runs.  The returned request\n    // never fires onsuccess or onerror — the open hangs indefinitely, simulating\n    // a foreign tab holding an open connection during a version upgrade.\n    // Pass the prefix as an arg so the serialized browser-context function can\n    // access it — addInitScript closures do not capture Node-side variables.\n    await page.addInitScript((idbPrefix: string) => {\n      const stuckOpen = () => {\n        // Construct a fake IDBOpenDBRequest-like object.  Since real\n        // IDBOpenDBRequest cannot be instantiated directly, we return a duck\n        // that supports the `onsuccess` / `onerror` pattern — but never fires\n        // either callback.  The idb wrapper library awaits the promise of\n        // success; with no callback ever firing, that promise never settles.\n        const req: any = {\n          // Fake event-target shim — addEventListener never invokes anything.\n          addEventListener: () => {\n            /* never resolves */\n          },\n          removeEventListener: () => {\n            /* no-op */\n          },\n          dispatchEvent: () => true,\n          onsuccess: null,\n          onerror: null,\n          onblocked: null,\n          onupgradeneeded: null,\n          readyState: 'pending',\n          result: null,\n          error: null,\n          source: null,\n          transaction: null,\n        };\n        return req as IDBOpenDBRequest;\n      };\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      const origOpen = indexedDB.open.bind(indexedDB);\n      // Only stall the SDK's IDB open; let any internal Playwright/page IDB\n      // calls go through.  The SDK's DB name is derived from the API key\n      // (first 10 chars).  Match anything starting with our test key prefix.\n      indexedDB.open = function (name: string, version?: number): IDBOpenDBRequest {\n        if (name.startsWith(idbPrefix)) {\n          return stuckOpen();\n        }\n        return origOpen(name, version);\n      } as typeof indexedDB.open;\n    }, IDB_NAME.substring(0, 10));\n\n    const { pageErrors } = listenForIdbErrors(page);\n    const { getBodies } = await captureTrackRequests(page);\n\n    const start = Date.now();\n    await mockRemoteConfig(page, remoteConfigRecording);\n    await page.goto(\n      buildUrl('/session-replay-browser/sr-capture-test.html', {\n        sessionId: TEST_SESSION_ID,\n        logLevel: LOG_LEVEL_DEBUG,\n        storeType: 'idb',\n      }),\n    );\n    await waitForReady(page);\n    const elapsed = Date.now() - start;\n\n    // The 2s openDB timeout + small init overhead must complete well under 3s.\n    // Pre-fix this would hang until waitForReady's 10s limit and time out.\n    expect(elapsed).toBeLessThan(3000);\n\n    // Generate events and verify they're delivered (memory store works).\n    await page.click('#test-button');\n    await page.click('#test-input');\n    await page.evaluate(() => window.dispatchEvent(new Event('blur')));\n    await page.evaluate(() => void (window as any).sessionReplay.flush(false));\n    await page.waitForTimeout(500);\n\n    expect(getBodies().length).toBeGreaterThan(0);\n    expect(pageErrors).toHaveLength(0);\n  });\n\n  /**\n   * Regression guard: zero unhandled promise rejections during a normal multi-tab\n   * recording session.  Closes the loop on the original AbortError \"Failed to\n   * store session replay events in IndexedDB\" defect — neither tab should leak\n   * unhandled rejections from any of the IDB store paths.\n   */\n  test('multi-tab: no unhandled promise rejections during normal recording', async ({ browser }) => {\n    const context = await browser.newContext();\n    const tabA = await context.newPage();\n    const tabB = await context.newPage();\n\n    try {\n      const errors: Error[] = [];\n      tabA.on('pageerror', (e) => errors.push(e));\n      tabB.on('pageerror', (e) => errors.push(e));\n\n      for (const p of [tabA, tabB]) {\n        await mockRemoteConfig(p, remoteConfigRecording);\n        await p.route('https://api-sr.amplitude.com/**', (route) =>\n          route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(SR_API_SUCCESS) }),\n        );\n      }\n\n      const url = buildUrl('/session-replay-browser/sr-capture-test.html', {\n        sessionId: TEST_SESSION_ID,\n        logLevel: LOG_LEVEL_DEBUG,\n        storeType: 'idb',\n      });\n\n      await tabA.goto(url);\n      await waitForReady(tabA);\n      await tabB.goto(url);\n      await waitForReady(tabB);\n\n      // Interleave clicks across tabs.\n      for (let i = 0; i < 3; i++) {\n        await tabA.click('#test-button');\n        await tabB.click('#test-button');\n      }\n\n      // Both tabs flush.\n      await tabA.evaluate(() => window.dispatchEvent(new Event('blur')));\n      await tabB.evaluate(() => window.dispatchEvent(new Event('blur')));\n      await tabA.evaluate(() => void (window as any).sessionReplay.flush(false));\n      await tabB.evaluate(() => void (window as any).sessionReplay.flush(false));\n      await tabA.waitForTimeout(300);\n      await tabB.waitForTimeout(300);\n\n      expect(errors).toHaveLength(0);\n    } finally {\n      await tabA.close();\n      await tabB.close();\n      await context.close();\n    }\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/e2e/mutation-merge.spec.ts",
    "content": "/**\n * End-to-end tests for the mutation-merge feature (SR-3752).\n *\n * DRAIN STRATEGY\n * ──────────────\n * The EventCompressor routes non-snapshot events through a pendingQueue that\n * is processed (merged) only by two paths:\n *   1. An idle-callback call to processQueue()\n *   2. A FullSnapshot event, which synchronously drains pendingQueue via\n *      mergeMutationTasks() before emitting the snapshot.\n *\n * Relying on path 1 is inherently timing-sensitive: requestIdleCallback can\n * fire between Playwright evaluate() calls (during the ~2 ms CDP roundtrip),\n * splitting events into separate merge windows.  All tests here instead\n * trigger a focus event — which causes the SDK to take a FullSnapshot — to\n * reliably flush pendingQueue through the merge path before calling flush().\n *\n * MO BATCH NOTES\n * ──────────────\n * Mutations made synchronously within a single evaluate() call all land in\n * one MutationObserver batch → one rrweb event.  Tests that exercise the\n * multi-event merge path (cross-batch) use separate evaluate() calls so MO\n * fires between them.  The pre-existing-transient test freezes\n * requestIdleCallback before the mutations to guarantee all three events\n * accumulate in pendingQueue and are merged in a single window.\n */\n\nimport { test, expect, Page } from '@playwright/test';\nimport {\n  TEST_SESSION_ID,\n  SNAPSHOT_SETTLE_MS,\n  remoteConfigRecording,\n  mockRemoteConfig,\n  buildUrl,\n  waitForReady,\n  captureTrackRequests,\n} from './helpers';\n\nconst MUTATION_SOURCE = 0; // IncrementalSource.Mutation\nconst EVENT_INCREMENTAL_SNAPSHOT = 3;\n\ninterface RrwebAdd {\n  parentId: number;\n  nextId: number | null;\n  node: {\n    id: number;\n    attributes?: Record<string, string>;\n    [key: string]: unknown;\n  };\n}\n\ninterface RrwebRemove {\n  parentId: number;\n  id: number;\n}\n\ninterface MutationData {\n  source: number;\n  adds: RrwebAdd[];\n  removes: RrwebRemove[];\n  texts: unknown[];\n  attributes: unknown[];\n}\n\nfunction decodeMutationEvents(rawBodies: string[]): MutationData[] {\n  const results: MutationData[] = [];\n  for (const body of rawBodies) {\n    if (!body) continue;\n    let payload: { events?: unknown[] };\n    try {\n      payload = JSON.parse(body) as { events?: unknown[] };\n    } catch {\n      continue;\n    }\n    if (!Array.isArray(payload.events)) continue;\n    for (const eventStr of payload.events) {\n      if (typeof eventStr !== 'string') continue;\n      try {\n        const event = JSON.parse(eventStr) as { type: number; data: MutationData };\n        if (event.type === EVENT_INCREMENTAL_SNAPSHOT && event.data.source === MUTATION_SOURCE) {\n          results.push(event.data);\n        }\n      } catch {\n        // skip unparseable\n      }\n    }\n  }\n  return results;\n}\n\n/**\n * Triggers a window focus event, causing the SDK to take a FullSnapshot.\n * The FullSnapshot path in EventCompressor synchronously drains pendingQueue\n * through mergeMutationTasks(), so all pending mutation events are processed\n * (and merged) before this call returns.\n */\nasync function drainPendingMutations(page: Page): Promise<void> {\n  await page.evaluate(() => window.dispatchEvent(new Event('focus')));\n}\n\nasync function flushAndCapture(page: Page): Promise<void> {\n  await page.evaluate(() => (window as any).sessionReplay.flush(false) as Promise<void>);\n  await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n}\n\n// ─── mutation merge — SR-3752 ──────────────────────────────────────────────────\n\ntest.describe('mutation merge', () => {\n  /**\n   * Basic capture smoke test: multiple synchronous DOM mutations (one MO batch →\n   * one rrweb event) are captured and delivered to the track API.\n   */\n  test('captures synchronous DOM mutations and delivers them to the API', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigRecording);\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    // All three mutations are synchronous → one MO batch → one rrweb event.\n    await page.evaluate(() => {\n      document.body.appendChild(Object.assign(document.createElement('div'), { id: 'mm-node-1' }));\n      document.body.appendChild(Object.assign(document.createElement('div'), { id: 'mm-node-2' }));\n      document.body.appendChild(Object.assign(document.createElement('div'), { id: 'mm-node-3' }));\n    });\n\n    await drainPendingMutations(page);\n    await flushAndCapture(page);\n\n    const allAdds = decodeMutationEvents(getBodies()).flatMap((e) => e.adds);\n\n    expect(allAdds.some((a) => a.node.attributes?.id === 'mm-node-1')).toBe(true);\n    expect(allAdds.some((a) => a.node.attributes?.id === 'mm-node-2')).toBe(true);\n    expect(allAdds.some((a) => a.node.attributes?.id === 'mm-node-3')).toBe(true);\n  });\n\n  /**\n   * A node added and removed within the same MO batch is purely transient.\n   * rrweb's own mutation handler elides same-batch transient nodes, so no add\n   * or remove for the node should appear in the captured events.\n   */\n  test('elides transient node added and removed in the same MO batch', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigRecording);\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    // Synchronous add then remove → same MO batch; rrweb sees net zero for this node.\n    await page.evaluate(() => {\n      const el = Object.assign(document.createElement('div'), { id: 'mm-transient' });\n      document.body.appendChild(el);\n      document.body.removeChild(el);\n    });\n\n    await drainPendingMutations(page);\n    await flushAndCapture(page);\n\n    const mutationEvents = decodeMutationEvents(getBodies());\n    const allAdds = mutationEvents.flatMap((e) => e.adds);\n    const allRemoves = mutationEvents.flatMap((e) => e.removes);\n\n    // Transient node must not appear in adds or removes.\n    expect(allAdds.some((a) => a.node.attributes?.id === 'mm-transient')).toBe(false);\n    // No other mutations occurred; removes should be empty too.\n    expect(allRemoves).toHaveLength(0);\n  });\n\n  /**\n   * A pre-existing DOM node (present in the initial full snapshot) that is\n   * removed, re-added, then removed again: our merge code should cancel the\n   * re-add cycle while preserving the original removal.\n   *\n   * This test uses three separate evaluate() calls so that each mutation lands\n   * in its own MO batch (→ separate rrweb events), exercising the cross-event\n   * merge path.\n   *\n   * requestIdleCallback is frozen before the mutations so that all three events\n   * accumulate in pendingQueue rather than being split across multiple merge\n   * windows by the idle scheduler firing between evaluate() calls.\n   * drainPendingMutations then flushes the complete window via the FullSnapshot\n   * path, which synchronously merges all three events together.\n   */\n  test('preserves pre-existing node original removal when re-add is cancelled', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigRecording);\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(\n      buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID, mergeMutations: true }),\n    );\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    // Freeze idle processing so all three mutation events accumulate in\n    // pendingQueue and are merged together by drainPendingMutations below.\n    // Without this, requestIdleCallback can fire in the ~2 ms CDP gap between\n    // evaluate() calls, processing events 1+2 as a partial window and\n    // misclassifying test-input as \"ultimately present\".\n    await page.evaluate(() => {\n      window.requestIdleCallback = () => 0;\n    });\n\n    // Stash a reference to the pre-existing element so it survives removal from the DOM.\n    await page.evaluate(() => {\n      (window as any).__preEl = document.getElementById('test-input') as HTMLElement;\n      document.body.removeChild((window as any).__preEl as Node); // original remove\n    });\n    await page.evaluate(() => {\n      document.body.appendChild((window as any).__preEl as Node);\n    }); // re-add\n    await page.evaluate(() => {\n      document.body.removeChild((window as any).__preEl as Node);\n    }); // final remove\n\n    // drainPendingMutations triggers a FullSnapshot which synchronously flushes\n    // pendingQueue through mergeMutationTasks(), merging the three events.\n    await drainPendingMutations(page);\n    await flushAndCapture(page);\n\n    const mutationEvents = decodeMutationEvents(getBodies());\n    const allAdds = mutationEvents.flatMap((e) => e.adds);\n    const allRemoves = mutationEvents.flatMap((e) => e.removes);\n\n    // The re-add should be cancelled — test-input must not appear in any adds.\n    expect(allAdds.some((a) => a.node.attributes?.id === 'test-input')).toBe(false);\n    // The original removal should be preserved — exactly one remove entry.\n    expect(allRemoves).toHaveLength(1);\n  });\n\n  /**\n   * A DOM move (remove from one parent, add under a different parent) is not\n   * a transient operation: both the remove and the re-add must be preserved so\n   * the replayer can reproduce the move.\n   */\n  test('preserves DOM moves (remove from one parent, add under another)', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigRecording);\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    // All mutations synchronous → one MO batch → one rrweb event containing\n    // both the new container (add) and the moved node (remove + add).\n    await page.evaluate(() => {\n      const container = Object.assign(document.createElement('div'), { id: 'mm-move-target' });\n      document.body.appendChild(container);\n      const el = document.getElementById('test-input') as HTMLElement;\n      document.body.removeChild(el);\n      container.appendChild(el);\n    });\n\n    await drainPendingMutations(page);\n    await flushAndCapture(page);\n\n    const mutationEvents = decodeMutationEvents(getBodies());\n    const allAdds = mutationEvents.flatMap((e) => e.adds);\n    const allRemoves = mutationEvents.flatMap((e) => e.removes);\n\n    // New container should be in adds.\n    expect(allAdds.some((a) => a.node.attributes?.id === 'mm-move-target')).toBe(true);\n    // Moved node should appear in both adds (new location) and removes (old location).\n    expect(allAdds.some((a) => a.node.attributes?.id === 'test-input')).toBe(true);\n    expect(allRemoves.length).toBeGreaterThanOrEqual(1);\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/e2e/playwright.config.ts",
    "content": "import { defineConfig, devices } from '@playwright/test';\n\nexport default defineConfig({\n  testDir: '.',\n  testMatch: '*.spec.ts',\n  use: {\n    baseURL: 'http://localhost:5173',\n    trace: 'on-first-retry',\n    actionTimeout: 30_000,\n    navigationTimeout: 30_000,\n    ignoreHTTPSErrors: true,\n    screenshot: 'only-on-failure',\n    video: 'retain-on-failure',\n  },\n  projects: [\n    {\n      name: 'chromium',\n      use: { ...devices['Desktop Chrome'] },\n    },\n  ],\n  timeout: 30_000,\n});\n"
  },
  {
    "path": "packages/session-replay-browser/e2e/privacy.spec.ts",
    "content": "import { test, expect } from '@playwright/test';\nimport {\n  TEST_SESSION_ID,\n  SNAPSHOT_SETTLE_MS,\n  remoteConfigRecording,\n  mockRemoteConfig,\n  buildUrl,\n  waitForReady,\n  captureTrackRequests,\n  flushRecording,\n  getSnapshotRoot,\n  getLastSnapshotRoot,\n  findById,\n  getTextContent,\n  isMaskedText,\n} from './helpers';\n\nfunction remoteConfigWithPrivacy(privacy: object) {\n  return {\n    configs: {\n      sessionReplay: {\n        sr_sampling_config: { capture_enabled: true, sample_rate: 1.0 },\n        sr_privacy_config: privacy,\n      },\n    },\n  };\n}\n\nconst PRIVACY_PAGE = '/session-replay-browser/sr-privacy-test.html';\n\n// ─── CSS class-based privacy ──────────────────────────────────────────────────\n\ntest.describe('privacy — CSS classes', () => {\n  test('amp-block class removes element from the snapshot entirely', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigRecording);\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    // rrweb removes blocked elements from the serialized tree entirely\n    expect(findById(root!, 'amp-block-element')).toBeUndefined();\n  });\n\n  test('amp-mask class replaces text content with asterisks in the snapshot', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigRecording);\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    const el = findById(root!, 'amp-mask-text');\n    expect(el).toBeDefined();\n    expect(isMaskedText(getTextContent(el!))).toBe(true);\n  });\n});\n\n// ─── privacyConfig option ─────────────────────────────────────────────────────\n\ntest.describe('privacy — privacyConfig option', () => {\n  test('blockSelector removes matching element from the snapshot entirely', async ({ page }) => {\n    const privacyConfig = JSON.stringify({ blockSelector: ['#selector-blocked'] });\n    await mockRemoteConfig(page, remoteConfigRecording);\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID, privacyConfig }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    // rrweb removes selector-blocked elements from the serialized tree entirely\n    expect(findById(root!, 'selector-blocked')).toBeUndefined();\n  });\n\n  test('defaultMaskLevel conservative masks plain text content', async ({ page }) => {\n    const privacyConfig = JSON.stringify({ defaultMaskLevel: 'conservative' });\n    await mockRemoteConfig(page, remoteConfigRecording);\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID, privacyConfig }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    // Under conservative mode, even plain unhinted text is masked\n    const el = findById(root!, 'plain-text');\n    expect(el).toBeDefined();\n    expect(isMaskedText(getTextContent(el!))).toBe(true);\n  });\n\n  test('defaultMaskLevel light does not mask plain text input values', async ({ page }) => {\n    const privacyConfig = JSON.stringify({ defaultMaskLevel: 'light' });\n    await mockRemoteConfig(page, remoteConfigRecording);\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID, privacyConfig }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    // Under light mode, a plain text input is NOT masked (only sensitive types are)\n    const textInput = findById(root!, 'text-input');\n    expect(textInput).toBeDefined();\n    const value = String(textInput!.attributes?.value ?? '');\n    expect(value).toBe('visible input value');\n    expect(isMaskedText(value)).toBe(false);\n  });\n\n  test('defaultMaskLevel light → plain body text is visible (no urlMaskLevels)', async ({ page }) => {\n    // Bug repro #1: with no urlMaskLevels, getMaskTextSelectors() returns undefined for\n    // light/medium effective levels, so rrweb never routes text through maskTextFn. Text\n    // should be visible in the snapshot regardless of isMaskedForLevel.\n    const privacyConfig = JSON.stringify({ defaultMaskLevel: 'light' });\n    await mockRemoteConfig(page, remoteConfigRecording);\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID, privacyConfig }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    const plainEl = findById(root!, 'plain-text');\n    expect(plainEl).toBeDefined();\n    expect(getTextContent(plainEl!)).toContain('Hello visible world');\n    expect(isMaskedText(getTextContent(plainEl!))).toBe(false);\n  });\n\n  test('defaultMaskLevel medium → plain body text is visible (no urlMaskLevels)', async ({ page }) => {\n    // Bug repro #2: same as above for medium. The unit-test \"medium masks text\" assertion\n    // does not reflect the actual rrweb flow when urlMaskLevels is absent — rrweb is\n    // never told to route text through maskTextFn.\n    const privacyConfig = JSON.stringify({ defaultMaskLevel: 'medium' });\n    await mockRemoteConfig(page, remoteConfigRecording);\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID, privacyConfig }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    const plainEl = findById(root!, 'plain-text');\n    expect(plainEl).toBeDefined();\n    expect(getTextContent(plainEl!)).toContain('Hello visible world');\n    expect(isMaskedText(getTextContent(plainEl!))).toBe(false);\n  });\n\n  test('defaultMaskLevel medium masks textarea and select values', async ({ page }) => {\n    // Per public docs, medium masks all form fields including <textarea> and <select>.\n    // rrweb routes their values through maskInputFn → isMaskedForLevel('input', medium) = true.\n    const privacyConfig = JSON.stringify({\n      defaultMaskLevel: 'conservative',\n      urlMaskLevels: [{ match: 'http://localhost:5173/session-replay-browser/*', maskLevel: 'medium' }],\n    });\n    await mockRemoteConfig(page, remoteConfigRecording);\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID, privacyConfig }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    const textarea = findById(root!, 'text-area');\n    expect(textarea).toBeDefined();\n    expect(isMaskedText(String(textarea!.attributes?.value ?? ''))).toBe(true);\n\n    const select = findById(root!, 'select-input');\n    expect(select).toBeDefined();\n    expect(isMaskedText(String(select!.attributes?.value ?? ''))).toBe(true);\n  });\n\n  test('defaultMaskLevel light still masks password input values', async ({ page }) => {\n    const privacyConfig = JSON.stringify({ defaultMaskLevel: 'light' });\n    await mockRemoteConfig(page, remoteConfigRecording);\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID, privacyConfig }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    // Under light mode, password inputs are still masked (they are sensitive)\n    const passwordInput = findById(root!, 'password-input');\n    expect(passwordInput).toBeDefined();\n    const value = String(passwordInput!.attributes?.value ?? '');\n    expect(isMaskedText(value)).toBe(true);\n  });\n\n  test('unmaskSelector overrides conservative masking for a specific element', async ({ page }) => {\n    // defaultMaskLevel:'conservative' routes masking through maskTextFn (via maskTextSelector:'*').\n    // unmaskSelector can override this for specific elements. Note: amp-mask CSS class masking is\n    // applied natively by rrweb before maskTextFn is called and cannot be overridden this way.\n    const privacyConfig = JSON.stringify({\n      defaultMaskLevel: 'conservative',\n      unmaskSelector: ['#plain-text'],\n    });\n    await mockRemoteConfig(page, remoteConfigRecording);\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID, privacyConfig }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    // #plain-text is in unmaskSelector — its text should be visible\n    const plainEl = findById(root!, 'plain-text');\n    expect(plainEl).toBeDefined();\n    expect(getTextContent(plainEl!)).toContain('Hello visible world');\n    expect(isMaskedText(getTextContent(plainEl!))).toBe(false);\n\n    // amp-mask-text is NOT in unmaskSelector — its text should still be masked\n    const maskedEl = findById(root!, 'amp-mask-text');\n    expect(maskedEl).toBeDefined();\n    expect(isMaskedText(getTextContent(maskedEl!))).toBe(true);\n  });\n});\n\n// ─── amp-unmask CSS class (SR-2945) ──────────────────────────────────────────\n\ntest.describe('privacy — amp-unmask CSS class', () => {\n  test('amp-unmask class unmasks text under conservative masking from remote config without explicit unmaskSelector', async ({\n    page,\n  }) => {\n    // Before SR-2945, .amp-unmask had no effect unless the user explicitly added\n    // '.amp-unmask' to privacyConfig.unmaskSelector. Now it's wired as a default.\n    await mockRemoteConfig(page, remoteConfigWithPrivacy({ defaultMaskLevel: 'conservative' }));\n    const { getBodies } = await captureTrackRequests(page);\n\n    // No local privacyConfig — masking comes entirely from remote config\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    // #amp-unmask-text has the .amp-unmask class — should NOT be masked\n    const unmaskEl = findById(root!, 'amp-unmask-text');\n    expect(unmaskEl).toBeDefined();\n    expect(getTextContent(unmaskEl!)).toContain('Unmask class visible text');\n    expect(isMaskedText(getTextContent(unmaskEl!))).toBe(false);\n\n    // #plain-text has no special class — should be masked under conservative\n    const plainEl = findById(root!, 'plain-text');\n    expect(plainEl).toBeDefined();\n    expect(isMaskedText(getTextContent(plainEl!))).toBe(true);\n  });\n\n  test('amp-unmask class unmasks text under conservative masking from local privacyConfig without explicit unmaskSelector', async ({\n    page,\n  }) => {\n    const privacyConfig = JSON.stringify({ defaultMaskLevel: 'conservative' });\n    await mockRemoteConfig(page, remoteConfigRecording);\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID, privacyConfig }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    // #amp-unmask-text has the .amp-unmask class — should NOT be masked\n    const unmaskEl = findById(root!, 'amp-unmask-text');\n    expect(unmaskEl).toBeDefined();\n    expect(getTextContent(unmaskEl!)).toContain('Unmask class visible text');\n    expect(isMaskedText(getTextContent(unmaskEl!))).toBe(false);\n\n    // #plain-text has no special class — should be masked under conservative\n    const plainEl = findById(root!, 'plain-text');\n    expect(plainEl).toBeDefined();\n    expect(isMaskedText(getTextContent(plainEl!))).toBe(true);\n  });\n});\n\n// ─── Remote privacy config ────────────────────────────────────────────────────\n\ntest.describe('privacy — remote sr_privacy_config', () => {\n  test('sr_privacy_config in remote config applies masking to plain text', async ({ page }) => {\n    // No local privacyConfig — masking comes entirely from remote config\n    await mockRemoteConfig(page, remoteConfigWithPrivacy({ defaultMaskLevel: 'conservative' }));\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    const el = findById(root!, 'plain-text');\n    expect(el).toBeDefined();\n    expect(isMaskedText(getTextContent(el!))).toBe(true);\n  });\n\n  test('remote urlMaskLevels conservative rule masks plain text end-to-end', async ({ page }) => {\n    // P0: exercises the full remote → join → apply pipeline for urlMaskLevels.\n    // No local privacyConfig — the conservative urlMaskLevels rule comes entirely from\n    // sr_privacy_config. defaultMaskLevel is left at the default (medium) so text masking\n    // is driven solely by the URL rule matching the test page.\n    await mockRemoteConfig(\n      page,\n      remoteConfigWithPrivacy({\n        urlMaskLevels: [{ match: 'http://localhost:5173/session-replay-browser/*', maskLevel: 'conservative' }],\n      }),\n    );\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    // The conservative urlMaskLevels rule matches this page — plain text must be masked.\n    const el = findById(root!, 'plain-text');\n    expect(el).toBeDefined();\n    expect(isMaskedText(getTextContent(el!))).toBe(true);\n  });\n});\n\n// ─── urlMaskLevels — page-level masking overrides ─────────────────────────────\n//\n// The test page runs at http://localhost:5173/session-replay-browser/sr-privacy-test.html\n// Glob patterns are anchored full-URL matches (globToRegex wraps with ^...$).\n\ntest.describe('privacy — urlMaskLevels (page-level masking)', () => {\n  // Pattern that matches the test page URL.\n  const MATCHING_PATTERN = 'http://localhost:5173/session-replay-browser/*';\n  // Pattern that does NOT match the test page URL.\n  const NON_MATCHING_PATTERN = 'http://localhost:5173/other-page/*';\n\n  test('URL matches rule with conservative → plain text is masked', async ({ page }) => {\n    // defaultMaskLevel is left at its default (medium) — the urlMaskLevels rule\n    // overrides it to conservative for this specific page.\n    await mockRemoteConfig(\n      page,\n      remoteConfigWithPrivacy({\n        urlMaskLevels: [{ match: MATCHING_PATTERN, maskLevel: 'conservative' }],\n      }),\n    );\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    // conservative mode masks all plain text\n    const el = findById(root!, 'plain-text');\n    expect(el).toBeDefined();\n    expect(isMaskedText(getTextContent(el!))).toBe(true);\n  });\n\n  test('URL matches rule with light → plain text input is not masked', async ({ page }) => {\n    // defaultMaskLevel is left at its default (medium) — the urlMaskLevels rule\n    // overrides it to light for this specific page.\n    await mockRemoteConfig(\n      page,\n      remoteConfigWithPrivacy({\n        urlMaskLevels: [{ match: MATCHING_PATTERN, maskLevel: 'light' }],\n      }),\n    );\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    // light mode does NOT mask plain text inputs\n    const textInput = findById(root!, 'text-input');\n    expect(textInput).toBeDefined();\n    const value = String(textInput!.attributes?.value ?? '');\n    expect(value).toBe('visible input value');\n    expect(isMaskedText(value)).toBe(false);\n  });\n\n  test('URL does not match any rule → defaultMaskLevel (conservative) masks plain text', async ({ page }) => {\n    // The urlMaskLevels rule targets a different page, so it never fires.\n    // defaultMaskLevel is 'conservative': plain text must still be masked even though\n    // no URL rule matched. Mirrors the redis.io homepage scenario where the homepage\n    // URL matches no rule and should fall back to conservative.\n    await mockRemoteConfig(\n      page,\n      remoteConfigWithPrivacy({\n        defaultMaskLevel: 'conservative',\n        urlMaskLevels: [{ match: NON_MATCHING_PATTERN, maskLevel: 'light' }],\n      }),\n    );\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    // Under conservative (the unmatched fallback), plain text IS masked\n    const el = findById(root!, 'plain-text');\n    expect(el).toBeDefined();\n    expect(isMaskedText(getTextContent(el!))).toBe(true);\n  });\n\n  test('URL does not match any rule → defaultMaskLevel (light) applies to plain text input', async ({ page }) => {\n    // The urlMaskLevels rule targets a different page, so it never fires.\n    // defaultMaskLevel is 'light': plain text inputs are NOT masked, but password\n    // inputs remain masked. This distinguishes light from the no-match-at-all case.\n    await mockRemoteConfig(\n      page,\n      remoteConfigWithPrivacy({\n        defaultMaskLevel: 'light',\n        urlMaskLevels: [{ match: NON_MATCHING_PATTERN, maskLevel: 'conservative' }],\n      }),\n    );\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    // Under light (the unmatched fallback), a plain text input is NOT masked\n    const textInput = findById(root!, 'text-input');\n    expect(textInput).toBeDefined();\n    const value = String(textInput!.attributes?.value ?? '');\n    expect(value).toBe('visible input value');\n    expect(isMaskedText(value)).toBe(false);\n\n    // password inputs are still masked under light\n    const passwordInput = findById(root!, 'password-input');\n    expect(passwordInput).toBeDefined();\n    expect(isMaskedText(String(passwordInput!.attributes?.value ?? ''))).toBe(true);\n  });\n\n  test('urlMaskLevels light rule wins over defaultMaskLevel conservative', async ({ page }) => {\n    // defaultMaskLevel is conservative but the urlMaskLevels rule overrides it to\n    // light for this specific page — the per-URL rule takes precedence.\n    await mockRemoteConfig(\n      page,\n      remoteConfigWithPrivacy({\n        defaultMaskLevel: 'conservative',\n        urlMaskLevels: [{ match: MATCHING_PATTERN, maskLevel: 'light' }],\n      }),\n    );\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    // The urlMaskLevels light override wins: plain text input is NOT masked\n    const textInput = findById(root!, 'text-input');\n    expect(textInput).toBeDefined();\n    const value = String(textInput!.attributes?.value ?? '');\n    expect(value).toBe('visible input value');\n    expect(isMaskedText(value)).toBe(false);\n\n    // password inputs are always masked regardless of mask level\n    const passwordInput = findById(root!, 'password-input');\n    expect(passwordInput).toBeDefined();\n    expect(isMaskedText(String(passwordInput!.attributes?.value ?? ''))).toBe(true);\n  });\n\n  test('SPA navigation to unmatched URL falls back to conservative default and masks text', async ({ page }) => {\n    // Regression test for the bugbot-identified privacy gap:\n    // defaultMaskLevel:'conservative' + a non-conservative URL rule. Session starts on the test\n    // page (MATCHING_PATTERN → light). After a SPA pushState to an unmatched URL, the effective\n    // level falls back to 'conservative'. Because getMaskTextSelectors() now returns '*' in this\n    // config (fix applied), rrweb routes all text through maskTextFn — which picks up the new URL\n    // via the dynamic getter and masks text accordingly.\n    await mockRemoteConfig(\n      page,\n      remoteConfigWithPrivacy({\n        defaultMaskLevel: 'conservative',\n        urlMaskLevels: [{ match: MATCHING_PATTERN, maskLevel: 'light' }],\n      }),\n    );\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    // Simulate SPA navigation to a URL that matches no urlMaskLevels rule.\n    // NOTE: MATCHING_PATTERN covers /session-replay-browser/*, so navigate outside that path.\n    // The SDK's URL-change listener updates currentPageUrl; subsequent maskTextFn\n    // calls then resolve to the conservative fallback.\n    await page.evaluate(() => {\n      history.pushState({}, '', '/other-section/dashboard');\n      // Dispatch a focus event to make rrweb take a new full snapshot with the updated URL context.\n      window.dispatchEvent(new Event('focus'));\n    });\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    // The LAST full snapshot was taken after the URL change — plain text must be masked.\n    const root = getLastSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    const el = findById(root!, 'plain-text');\n    expect(el).toBeDefined();\n    expect(isMaskedText(getTextContent(el!))).toBe(true);\n  });\n\n  test('SPA navigation from conservative URL to light URL leaves text visible', async ({ page }) => {\n    // Verifies maskFn URL-awareness: session starts on a conservative URL rule, then navigates\n    // to a light URL rule. Light leaves text nodes visible, so plain text becomes unmasked\n    // after navigation.\n    // Use exact URL patterns to avoid first-match-wins overlap with the wildcard MATCHING_PATTERN.\n    const CONSERVATIVE_PATTERN = 'http://localhost:5173/session-replay-browser/sr-privacy-test.html*';\n    const LIGHT_PATTERN = 'http://localhost:5173/section-light/*';\n    await mockRemoteConfig(\n      page,\n      remoteConfigWithPrivacy({\n        defaultMaskLevel: 'medium',\n        urlMaskLevels: [\n          { match: CONSERVATIVE_PATTERN, maskLevel: 'conservative' },\n          { match: LIGHT_PATTERN, maskLevel: 'light' },\n        ],\n      }),\n    );\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    // Initial snapshot: on the conservative URL — plain text should be masked.\n    await flushRecording(page);\n    const firstRoot = getSnapshotRoot(getBodies());\n    expect(firstRoot).not.toBeNull();\n    expect(isMaskedText(getTextContent(findById(firstRoot!, 'plain-text')!))).toBe(true);\n\n    // Navigate to the light URL rule page via SPA pushState.\n    await page.evaluate(() => {\n      history.pushState({}, '', '/section-light/dashboard');\n      window.dispatchEvent(new Event('focus'));\n    });\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    // The LAST full snapshot was taken on the light URL — plain text is NOT masked under light.\n    const lastRoot = getLastSnapshotRoot(getBodies());\n    expect(lastRoot).not.toBeNull();\n    const plainEl = findById(lastRoot!, 'plain-text');\n    expect(plainEl).toBeDefined();\n    expect(isMaskedText(getTextContent(plainEl!))).toBe(false);\n  });\n\n  test('SPA navigation from light URL to conservative URL masks text', async ({ page }) => {\n    // Verifies maskFn URL-awareness in the other direction: session starts on a light URL,\n    // navigates to a conservative URL — maskTextFn should pick up the new URL and mask text.\n    // Use exact URL patterns to avoid first-match-wins overlap.\n    const LIGHT_PATTERN = 'http://localhost:5173/session-replay-browser/sr-privacy-test.html*';\n    const CONSERVATIVE_PATTERN = 'http://localhost:5173/section-secure/*';\n    await mockRemoteConfig(\n      page,\n      remoteConfigWithPrivacy({\n        defaultMaskLevel: 'medium',\n        urlMaskLevels: [\n          { match: LIGHT_PATTERN, maskLevel: 'light' },\n          { match: CONSERVATIVE_PATTERN, maskLevel: 'conservative' },\n        ],\n      }),\n    );\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    // Navigate to the conservative URL rule page via SPA pushState.\n    await page.evaluate(() => {\n      history.pushState({}, '', '/section-secure/checkout');\n      window.dispatchEvent(new Event('focus'));\n    });\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    // The LAST full snapshot was taken on the conservative URL — plain text must be masked.\n    const lastRoot = getLastSnapshotRoot(getBodies());\n    expect(lastRoot).not.toBeNull();\n    const plainEl = findById(lastRoot!, 'plain-text');\n    expect(plainEl).toBeDefined();\n    expect(isMaskedText(getTextContent(plainEl!))).toBe(true);\n  });\n\n  // Repro for customer report (Slack C0AJHTHCB96 / 2026-05-12):\n  // defaultMaskLevel: conservative + a urlMaskLevels rule routing the page to 'light'.\n  // Under the light URL rule, plain <p> body text on the matched page is visible.\n  test('urlMaskLevels light rule leaves plain body text visible', async ({ page }) => {\n    await mockRemoteConfig(\n      page,\n      remoteConfigWithPrivacy({\n        defaultMaskLevel: 'conservative',\n        urlMaskLevels: [{ match: MATCHING_PATTERN, maskLevel: 'light' }],\n      }),\n    );\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    const plainEl = findById(root!, 'plain-text');\n    expect(plainEl).toBeDefined();\n    expect(getTextContent(plainEl!)).toContain('Hello visible world');\n    expect(isMaskedText(getTextContent(plainEl!))).toBe(false);\n  });\n\n  // urlMaskLevels medium rule leaves plain text visible (per public docs: medium\n  // \"masks all form fields and text inputs. Amplitude captures all other text as-is\").\n  test('urlMaskLevels medium rule leaves plain body text visible', async ({ page }) => {\n    await mockRemoteConfig(\n      page,\n      remoteConfigWithPrivacy({\n        defaultMaskLevel: 'conservative',\n        urlMaskLevels: [{ match: MATCHING_PATTERN, maskLevel: 'medium' }],\n      }),\n    );\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    const plainEl = findById(root!, 'plain-text');\n    expect(plainEl).toBeDefined();\n    expect(getTextContent(plainEl!)).toContain('Hello visible world');\n    expect(isMaskedText(getTextContent(plainEl!))).toBe(false);\n\n    // Under medium, inputs are still masked\n    const textInput = findById(root!, 'text-input');\n    expect(textInput).toBeDefined();\n    expect(isMaskedText(String(textInput!.attributes?.value ?? ''))).toBe(true);\n  });\n\n  test('first-match-wins: second rule (light) applies when first rule does not match', async ({ page }) => {\n    // P1: regression guard for rule evaluation order.\n    // Three rules; only the second matches the test page URL.\n    // Rule 1 (conservative): targets a different path — must NOT match.\n    // Rule 2 (light):        targets the test page — MUST match and apply.\n    // Rule 3 (conservative): also targets the test page but comes after rule 2 — must NOT be evaluated.\n    // Effective level must be 'light': plain text input is NOT masked.\n    // TC-07: covered — three rules, second wins.\n    await mockRemoteConfig(\n      page,\n      remoteConfigWithPrivacy({\n        defaultMaskLevel: 'medium',\n        urlMaskLevels: [\n          { match: 'http://localhost:5173/other-section/*', maskLevel: 'conservative' },\n          { match: 'http://localhost:5173/session-replay-browser/*', maskLevel: 'light' },\n          { match: 'http://localhost:5173/session-replay-browser/*', maskLevel: 'conservative' },\n        ],\n      }),\n    );\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    // Rule 2 (light) wins: plain text input is NOT masked.\n    const textInput = findById(root!, 'text-input');\n    expect(textInput).toBeDefined();\n    const value = String(textInput!.attributes?.value ?? '');\n    expect(value).toBe('visible input value');\n    expect(isMaskedText(value)).toBe(false);\n\n    // Password inputs are always masked regardless of mask level.\n    const passwordInput = findById(root!, 'password-input');\n    expect(passwordInput).toBeDefined();\n    expect(isMaskedText(String(passwordInput!.attributes?.value ?? ''))).toBe(true);\n  });\n\n  // TC-08: first-match-wins blocks more-specific later rules.\n  test('first-match-wins: broad /** rule fires before more-specific path rule', async ({ page }) => {\n    // TC-08: Rules in order: [1] matching conservative /**,  [2] matching light /path/*.\n    // Rule 1 fires first because it appears first — rule 2 must never be evaluated.\n    // Effective level must be 'conservative': plain text IS masked.\n    await mockRemoteConfig(\n      page,\n      remoteConfigWithPrivacy({\n        defaultMaskLevel: 'medium',\n        urlMaskLevels: [\n          // Rule 1: broad /** — matches the test page, conservative.\n          { match: 'http://localhost:5173/**', maskLevel: 'conservative' },\n          // Rule 2: more-specific path — also matches, but comes AFTER rule 1.\n          { match: 'http://localhost:5173/session-replay-browser/*', maskLevel: 'light' },\n        ],\n      }),\n    );\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    // Rule 1 (conservative) wins: plain text IS masked.\n    const el = findById(root!, 'plain-text');\n    expect(el).toBeDefined();\n    expect(isMaskedText(getTextContent(el!))).toBe(true);\n  });\n\n  // TC-09: trailing /** matches base path (no trailing slash on the URL).\n  test('trailing /** pattern matches the test page URL (no trailing slash)', async ({ page }) => {\n    // TC-09: The pattern http://localhost:5173/session-replay-browser/** should match\n    // the test page URL (which has a path but no trailing slash after the filename).\n    // globToRegex converts trailing /** to (/.*)?  — the optional group covers the\n    // /file.html portion of the URL.\n    await mockRemoteConfig(\n      page,\n      remoteConfigWithPrivacy({\n        defaultMaskLevel: 'light',\n        urlMaskLevels: [{ match: 'http://localhost:5173/session-replay-browser/**', maskLevel: 'conservative' }],\n      }),\n    );\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    // The conservative /** rule matched — plain text IS masked.\n    const el = findById(root!, 'plain-text');\n    expect(el).toBeDefined();\n    expect(isMaskedText(getTextContent(el!))).toBe(true);\n  });\n\n  // TC-10: middle /**/ matches zero intermediate segments.\n  test('middle /**/ glob matches URL with zero intermediate path segments', async ({ page }) => {\n    // TC-10: Pattern http://localhost:5173/**/sr-privacy-test.html should match\n    // the test page URL where there are no intermediate path segments between\n    // the origin and the filename (zero-segment match for /**/).\n    // globToRegex converts /**/ to /(.*\\/)?  — the optional group covers the zero-segment case.\n    await mockRemoteConfig(\n      page,\n      remoteConfigWithPrivacy({\n        defaultMaskLevel: 'light',\n        urlMaskLevels: [{ match: 'http://localhost:5173/**/sr-privacy-test.html*', maskLevel: 'conservative' }],\n      }),\n    );\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    // The conservative /**/ rule matched — plain text IS masked.\n    const el = findById(root!, 'plain-text');\n    expect(el).toBeDefined();\n    expect(isMaskedText(getTextContent(el!))).toBe(true);\n  });\n\n  // TC-13: blur + SPA nav to light URL + focus uses fresh URL — input visible in new snapshot.\n  test('SPA navigation to light URL: fresh snapshot shows text input not masked', async ({ page }) => {\n    // TC-13: Start on a conservative URL rule. SPA-pushState to a URL that matches a light\n    // rule. Dispatch blur then focus to force rrweb to take a new full snapshot.\n    // Verify the new snapshot captures the text input as NOT masked (light level for inputs).\n    // The existing conservative→light test only checks plain text (which is masked at both levels).\n    // This test specifically checks that the input masking decision uses the NEW URL.\n    const CONSERVATIVE_PATTERN = 'http://localhost:5173/session-replay-browser/sr-privacy-test.html*';\n    const LIGHT_PATTERN = 'http://localhost:5173/section-light-inputs/*';\n    await mockRemoteConfig(\n      page,\n      remoteConfigWithPrivacy({\n        defaultMaskLevel: 'medium',\n        urlMaskLevels: [\n          { match: CONSERVATIVE_PATTERN, maskLevel: 'conservative' },\n          { match: LIGHT_PATTERN, maskLevel: 'light' },\n        ],\n      }),\n    );\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    // Initial snapshot on the conservative URL: text input MUST be masked.\n    await flushRecording(page);\n    const firstRoot = getSnapshotRoot(getBodies());\n    expect(firstRoot).not.toBeNull();\n    expect(isMaskedText(String(findById(firstRoot!, 'text-input')!.attributes?.value ?? ''))).toBe(true);\n\n    // SPA navigate to the light URL and force a fresh full snapshot via blur→focus cycle.\n    await page.evaluate(() => {\n      history.pushState({}, '', '/section-light-inputs/page');\n      // blur flushes pending events; focus triggers rrweb's full-snapshot on re-focus.\n      window.dispatchEvent(new Event('blur'));\n      window.dispatchEvent(new Event('focus'));\n    });\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    // The LAST full snapshot was taken on the light URL — text input must NOT be masked.\n    const lastRoot = getLastSnapshotRoot(getBodies());\n    expect(lastRoot).not.toBeNull();\n    const textInput = findById(lastRoot!, 'text-input');\n    expect(textInput).toBeDefined();\n    const value = String(textInput!.attributes?.value ?? '');\n    expect(value).toBe('visible input value');\n    expect(isMaskedText(value)).toBe(false);\n  });\n});\n\n// ─── urlMaskLevels — glob pattern edge cases ──────────────────────────────────\n\ntest.describe('privacy — urlMaskLevels glob edge cases', () => {\n  // The exact (no-wildcard) URL of the test page, used for TC-01 and TC-03.\n  // buildUrl() appends ?sessionId=… so the actual browser URL always has a query string.\n  // An exact-match pattern (no glob chars) compiles to /^…\\.html$/ which does NOT match.\n  const EXACT_PATTERN = 'http://localhost:5173/session-replay-browser/sr-privacy-test.html';\n\n  // TC-01: exact pattern without wildcard does NOT match a URL that carries a query string.\n  test('TC-01: exact pattern (no wildcard) does not match URL with query string → text input visible', async ({\n    page,\n  }) => {\n    // The actual page URL from buildUrl() is http://…/sr-privacy-test.html?sessionId=…\n    // The exact EXACT_PATTERN has no wildcard, so it compiles to /^…\\.html$/ which\n    // fails to match the URL that includes ?sessionId=…  The rule does not fire, so\n    // the effective mask level falls back to defaultMaskLevel: light.\n    // Under light, plain text input values are NOT masked.\n    await mockRemoteConfig(\n      page,\n      remoteConfigWithPrivacy({\n        defaultMaskLevel: 'light',\n        urlMaskLevels: [{ match: EXACT_PATTERN, maskLevel: 'conservative' }],\n      }),\n    );\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    // The conservative rule did NOT match (query string present) — light fallback applies.\n    // Under light, text input values are NOT masked.\n    const textInput = findById(root!, 'text-input');\n    expect(textInput).toBeDefined();\n    const value = String(textInput!.attributes?.value ?? '');\n    expect(value).toBe('visible input value');\n    expect(isMaskedText(value)).toBe(false);\n  });\n\n  // TC-02: workaround — pattern ending in /** DOES match a URL with a query string.\n  test('TC-02: pattern ending in /** matches URL with query string → text input masked', async ({ page }) => {\n    // The /** suffix compiles to (/.*)?  which matches /sr-privacy-test.html?sessionId=…\n    // (the .* inside the group covers everything including the ? and query params).\n    // Rule fires → conservative → plain text inputs ARE masked.\n    // Contrast with TC-01 where the exact pattern misses and the light fallback leaves\n    // plain text inputs visible.\n    await mockRemoteConfig(\n      page,\n      remoteConfigWithPrivacy({\n        defaultMaskLevel: 'light',\n        urlMaskLevels: [{ match: 'http://localhost:5173/session-replay-browser/**', maskLevel: 'conservative' }],\n      }),\n    );\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    // The conservative /** rule matched — plain text input IS masked (conservative masks all inputs).\n    // Under light (the fallback if the rule had not matched) the text input would be visible.\n    const textInput = findById(root!, 'text-input');\n    expect(textInput).toBeDefined();\n    const value = String(textInput!.attributes?.value ?? '');\n    expect(isMaskedText(value)).toBe(true);\n  });\n\n  // TC-03: exact pattern without wildcard does NOT match a URL with a hash fragment.\n  test('TC-03: exact pattern (no wildcard) does not match URL with hash fragment → text input visible', async ({\n    page,\n  }) => {\n    // Navigate to the page appending a #fragment AFTER the query string.\n    // window.location.href includes the hash, so the SDK sees the full URL with #frag.\n    // The exact EXACT_PATTERN regex /^…\\.html$/ does NOT match — rule misses.\n    // Effective level falls back to defaultMaskLevel: light → text input NOT masked.\n    await mockRemoteConfig(\n      page,\n      remoteConfigWithPrivacy({\n        defaultMaskLevel: 'light',\n        urlMaskLevels: [{ match: EXACT_PATTERN, maskLevel: 'conservative' }],\n      }),\n    );\n    const { getBodies } = await captureTrackRequests(page);\n\n    // Append a hash fragment to the URL so the SDK's location.href differs from EXACT_PATTERN.\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID }) + '#myfragment');\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    // The conservative rule did NOT match (hash fragment present) — light fallback applies.\n    // Under light, text input values are NOT masked.\n    const textInput = findById(root!, 'text-input');\n    expect(textInput).toBeDefined();\n    const value = String(textInput!.attributes?.value ?? '');\n    expect(value).toBe('visible input value');\n    expect(isMaskedText(value)).toBe(false);\n  });\n});\n\n// ─── Remote-config / local-config merge priority ─────────────────────────────\n\ntest.describe('privacy — remote vs local config merge priority', () => {\n  // TC-04: remote-config-only conservative urlMaskLevels rule → already covered by\n  //   'remote urlMaskLevels conservative rule masks plain text end-to-end' above.\n  //   Skipped here to avoid duplication.\n\n  // TC-05: remote conservative rule + local light rule for same URL → remote wins.\n  test('TC-05: remote conservative urlMaskLevels rule wins over local light rule (remote prepended)', async ({\n    page,\n  }) => {\n    // joined-config prepends remote urlMaskLevels before local ones, so the remote\n    // conservative rule appears first in the merged list and fires first.\n    // The local light rule (passed via privacyConfig URL param) is never reached.\n    // Expected: plain text IS masked (conservative wins).\n    const localPrivacyConfig = JSON.stringify({\n      urlMaskLevels: [{ match: 'http://localhost:5173/session-replay-browser/*', maskLevel: 'light' }],\n    });\n\n    await mockRemoteConfig(\n      page,\n      remoteConfigWithPrivacy({\n        urlMaskLevels: [{ match: 'http://localhost:5173/session-replay-browser/*', maskLevel: 'conservative' }],\n      }),\n    );\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID, privacyConfig: localPrivacyConfig }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    // Remote conservative rule prepended → it matches first → plain text IS masked.\n    const el = findById(root!, 'plain-text');\n    expect(el).toBeDefined();\n    expect(isMaskedText(getTextContent(el!))).toBe(true);\n  });\n\n  // TC-06: remote defaultMaskLevel overrides local conservative.\n  test('TC-06: remote defaultMaskLevel medium overrides local conservative → text input not masked', async ({\n    page,\n  }) => {\n    // joined-config uses remote defaultMaskLevel when set, ignoring local.\n    // Remote says 'medium', local (via URL param) says 'conservative'.\n    // No URL rules match. Effective defaultMaskLevel is 'medium'.\n    //\n    // Under medium, getMaskTextSelectors() returns undefined (not '*') so rrweb does NOT\n    // route text nodes through maskTextFn — plain text is not masked at snapshot time.\n    // Text inputs ARE masked under medium (medium masks all inputs).\n    //\n    // We verify via text-input: under medium all inputs are masked (value = asterisks).\n    // We also verify no conservative over-masking occurred by checking text-input is masked\n    // (medium) rather than checking it's unmasked — the key assertion is that remote medium\n    // wins, not local conservative (which would also mask inputs). Instead we use the\n    // existing 'URL does not match any rule → defaultMaskLevel (light) applies' pattern and\n    // verify that the remote medium default does NOT mask the text input less than conservative:\n    // both mask inputs, so the distinguishing check is that remote medium beats local\n    // conservative by using the remote value and that getMaskTextSelectors does not\n    // set maskTextSelector='*' (which would mask plain text nodes).\n    //\n    // Practical assertion: plain text paragraph is NOT masked (medium doesn't use maskTextSelector='*').\n    const localPrivacyConfig = JSON.stringify({ defaultMaskLevel: 'conservative' });\n\n    await mockRemoteConfig(\n      page,\n      remoteConfigWithPrivacy({\n        defaultMaskLevel: 'medium',\n      }),\n    );\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(PRIVACY_PAGE, { sessionId: TEST_SESSION_ID, privacyConfig: localPrivacyConfig }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    // Remote medium wins over local conservative.\n    // getMaskTextSelectors() returns undefined under medium (no '*') → plain text NOT masked at snapshot.\n    const el = findById(root!, 'plain-text');\n    expect(el).toBeDefined();\n    expect(isMaskedText(getTextContent(el!))).toBe(false);\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/e2e/sampling.spec.ts",
    "content": "import { test, expect } from '@playwright/test';\nimport {\n  SR_API_SUCCESS,\n  SNAPSHOT_SETTLE_MS,\n  remoteConfigRecording,\n  mockRemoteConfig,\n  buildUrl,\n  waitForReady,\n  captureTrackRequests,\n  flushRecording,\n} from './helpers';\n\nconst SR_PROPERTY_KEY = '[Amplitude] Session Replay ID';\n\n// xxHash32('1719847315013') % 1_000_000 / 1_000_000 = 0.109684\n// In 20% sample (0.2 > 0.1097), NOT in 10% sample (0.1 < 0.1097)\nconst SESSION_ID_IN_20_SAMPLE = 1719847315013;\n\nfunction mockTrackApi(page: import('@playwright/test').Page) {\n  return page.route('https://api-sr.amplitude.com/**', (route) =>\n    route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(SR_API_SUCCESS) }),\n  );\n}\n\n// ─── Sampling header ──────────────────────────────────────────────────────────\n\ntest.describe('sampling hash algorithm header', () => {\n  test('sends X-Sampling-Hash-Alg: xxhash32 header on track API requests', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigRecording);\n    await page.route('https://api-sr.amplitude.com/**', (route) =>\n      route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(SR_API_SUCCESS) }),\n    );\n\n    // Register the listener before goto so the immediate full-snapshot flush\n    // (which fires without any explicit blur/flush call) can satisfy it.\n    const requestPromise = page.waitForRequest(\n      (req) => req.url().includes('api-sr.amplitude.com') && req.method() === 'POST',\n      { timeout: 10_000 },\n    );\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: SESSION_ID_IN_20_SAMPLE }));\n    await waitForReady(page);\n\n    const request = await requestPromise;\n    expect(request.headers()['x-sampling-hash-alg']).toBe('xxhash32');\n  });\n});\n\n// ─── xxHash32 sample rate decisions ──────────────────────────────────────────\n\ntest.describe('xxHash32 sampling decisions', () => {\n  test('records session when sample rate is above hash ratio', async ({ page }) => {\n    // SESSION_ID_IN_20_SAMPLE has ratio ~0.1097, so 20% sample rate includes it\n    await mockRemoteConfig(page, {\n      configs: { sessionReplay: { sr_sampling_config: { capture_enabled: true, sample_rate: 0.2 } } },\n    });\n    await mockTrackApi(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: SESSION_ID_IN_20_SAMPLE }));\n    await waitForReady(page);\n\n    const props = await page.evaluate(\n      () => (window as any).sessionReplay.getSessionReplayProperties() as Record<string, unknown>,\n    );\n    expect(props[SR_PROPERTY_KEY]).toBeTruthy();\n    expect(String(props[SR_PROPERTY_KEY])).toContain(`/${SESSION_ID_IN_20_SAMPLE}`);\n  });\n\n  test('does not record session when sample rate is below hash ratio', async ({ page }) => {\n    // SESSION_ID_IN_20_SAMPLE has ratio ~0.1097, so 10% sample rate excludes it\n    await mockRemoteConfig(page, {\n      configs: { sessionReplay: { sr_sampling_config: { capture_enabled: true, sample_rate: 0.1 } } },\n    });\n    await mockTrackApi(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: SESSION_ID_IN_20_SAMPLE }));\n    await waitForReady(page);\n\n    const props = await page.evaluate(\n      () => (window as any).sessionReplay.getSessionReplayProperties() as Record<string, unknown>,\n    );\n    expect(props[SR_PROPERTY_KEY]).toBeFalsy();\n  });\n\n  test('does not send events to track API when session is excluded by sample rate', async ({ page }) => {\n    const { getBodies: getRawBodies } = await captureTrackRequests(page);\n    await mockRemoteConfig(page, {\n      configs: { sessionReplay: { sr_sampling_config: { capture_enabled: true, sample_rate: 0.1 } } },\n    });\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: SESSION_ID_IN_20_SAMPLE }));\n    await waitForReady(page);\n    await flushRecording(page);\n\n    expect(getRawBodies().length).toBe(0);\n  });\n\n  test('sends events to track API when session is included by sample rate', async ({ page }) => {\n    const { getBodies: getRawBodies } = await captureTrackRequests(page);\n    await mockRemoteConfig(page, {\n      configs: { sessionReplay: { sr_sampling_config: { capture_enabled: true, sample_rate: 0.2 } } },\n    });\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: SESSION_ID_IN_20_SAMPLE }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n    await flushRecording(page);\n\n    expect(getRawBodies().length).toBeGreaterThan(0);\n  });\n\n  test('sampling decision is deterministic — same session ID always gets same result', async ({ page }) => {\n    await mockRemoteConfig(page, {\n      configs: { sessionReplay: { sr_sampling_config: { capture_enabled: true, sample_rate: 0.2 } } },\n    });\n    await mockTrackApi(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: SESSION_ID_IN_20_SAMPLE }));\n    await waitForReady(page);\n\n    const props1 = await page.evaluate(\n      () => (window as any).sessionReplay.getSessionReplayProperties() as Record<string, unknown>,\n    );\n    const props2 = await page.evaluate(\n      () => (window as any).sessionReplay.getSessionReplayProperties() as Record<string, unknown>,\n    );\n\n    expect(props1[SR_PROPERTY_KEY]).toBe(props2[SR_PROPERTY_KEY]);\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/e2e/shadow-dom.spec.ts",
    "content": "import { test, expect } from '@playwright/test';\nimport {\n  TEST_SESSION_ID,\n  SNAPSHOT_SETTLE_MS,\n  remoteConfigRecording,\n  mockRemoteConfig,\n  buildUrl,\n  waitForReady,\n  captureTrackRequests,\n  getSnapshotRoot,\n  findById,\n  flushRecording,\n} from './helpers';\n\n/**\n * E2E tests for captureAdoptedStyleSheets option.\n *\n * These tests verify that:\n *   1. The option is accepted by the SDK without error (both true and false).\n *   2. Shadow DOM elements are captured in the full snapshot regardless of the option value.\n *\n * Full inline-stylesheet assertion (verifying adoptedStyleSheets CSS rules appear\n * inline in the snapshot node rather than as incremental events) requires an rrweb\n * version that includes amplitude/rrweb#101. That assertion should be added here\n * once the @amplitude/rrweb-* packages are bumped to include that fix.\n */\n\nconst SHADOW_DOM_PAGE = '/session-replay-browser/sr-shadow-dom-test.html';\n\ntype SrWindow = Window & { srError?: string };\n\ntest.describe('captureAdoptedStyleSheets option', () => {\n  test.beforeEach(async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigRecording);\n  });\n\n  test('SDK initializes without error and captures shadow host with default (true)', async ({ page }) => {\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(SHADOW_DOM_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n\n    // Verify no initialization error\n    const srError = await page.evaluate(() => (window as SrWindow).srError);\n    expect(srError).toBeUndefined();\n\n    await flushRecording(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    // The shadow host div must appear in the snapshot\n    const shadowHost = findById(root!, 'shadow-host');\n    expect(shadowHost).toBeDefined();\n    // Shadow root childNodes are serialized as children of the host\n    expect((shadowHost?.childNodes ?? []).length).toBeGreaterThan(0);\n  });\n\n  test('SDK initializes without error and captures shadow host with captureAdoptedStyleSheets=false', async ({\n    page,\n  }) => {\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(\n      buildUrl(SHADOW_DOM_PAGE, {\n        sessionId: TEST_SESSION_ID,\n        captureAdoptedStyleSheets: 'false',\n      }),\n    );\n    await waitForReady(page);\n\n    // Verify no initialization error when opting out\n    const srError = await page.evaluate(() => (window as SrWindow).srError);\n    expect(srError).toBeUndefined();\n\n    await flushRecording(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    const root = getSnapshotRoot(getBodies());\n    expect(root).not.toBeNull();\n\n    const shadowHost = findById(root!, 'shadow-host');\n    expect(shadowHost).toBeDefined();\n    expect((shadowHost?.childNodes ?? []).length).toBeGreaterThan(0);\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/e2e/size-limits.spec.ts",
    "content": "import { test, expect, Route } from '@playwright/test';\nimport {\n  SR_API_SUCCESS,\n  TEST_SESSION_ID,\n  SNAPSHOT_SETTLE_MS,\n  remoteConfigRecording,\n  mockRemoteConfig,\n  buildUrl,\n  waitForReady,\n  readRouteBody,\n} from './helpers';\nimport { MAX_SINGLE_EVENT_SIZE } from '../src/constants';\n\n// Just over the byte cap so the next full snapshot is guaranteed oversized.\n// Derived from the constant so the test stays in sync if the threshold is bumped.\n// Passed as a number to page.evaluate so only the integer crosses CDP;\n// the browser generates the large string entirely in-process.\nconst OVERSIZED_ATTR_LENGTH = MAX_SINGLE_EVENT_SIZE + 100_000;\n\n/**\n * Appends a <div data-large=\"xxx...\"> whose single attribute value is\n * OVERSIZED_ATTR_LENGTH chars. When rrweb serialises the next full snapshot,\n * the resulting JSON string will exceed MAX_SINGLE_EVENT_SIZE and should be\n * dropped by the capture-time guard in EventCompressor.\n */\nasync function injectLargeNode(page: import('@playwright/test').Page): Promise<void> {\n  await page.evaluate((len) => {\n    const div = document.createElement('div');\n    div.setAttribute('data-large', 'x'.repeat(len));\n    document.body.appendChild(div);\n  }, OVERSIZED_ATTR_LENGTH);\n}\n\nfunction decodeEvents(rawBody: string): Array<Record<string, unknown>> {\n  if (!rawBody) return [];\n  try {\n    const payload = JSON.parse(rawBody) as { events?: unknown[] };\n    if (!Array.isArray(payload.events)) return [];\n    return payload.events.flatMap((s) => {\n      if (typeof s !== 'string') return [];\n      try {\n        return [JSON.parse(s) as Record<string, unknown>];\n      } catch {\n        return [];\n      }\n    });\n  } catch {\n    return [];\n  }\n}\n\n/** Mocks the track API, collecting (sessionId → events) pairs per request. */\nasync function captureBySession(page: import('@playwright/test').Page) {\n  const calls: { sessionId: string; events: Array<Record<string, unknown>> }[] = [];\n  await page.route('https://api-sr.amplitude.com/**', async (route: Route) => {\n    const url = new URL(route.request().url());\n    calls.push({\n      sessionId: url.searchParams.get('session_id') ?? '',\n      events: decodeEvents(readRouteBody(route)),\n    });\n    await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(SR_API_SUCCESS) });\n  });\n  return () => calls;\n}\n\n// ─── Oversized single event — capture-time guard ──────────────────────────────\n\ntest.describe('oversized single event — capture-time guard', () => {\n  test('oversized snapshot is not delivered to the track API', async ({ page }) => {\n    const NEW_SESSION_ID = TEST_SESSION_ID + 60_000;\n    await mockRemoteConfig(page, remoteConfigRecording);\n    const getCalls = await captureBySession(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    // Inject a node whose attribute forces the next full snapshot to exceed 9 MB.\n    await injectLargeNode(page);\n\n    // setSessionId flushes the old session and immediately starts recording the new\n    // one. rrweb takes a full snapshot of the now-large DOM synchronously during\n    // record(); the capture-time guard in EventCompressor must drop it.\n    await page.evaluate(\n      (id) => (window as any).sessionReplay.setSessionId(id).promise as Promise<void>,\n      NEW_SESSION_ID,\n    );\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS * 6);\n\n    // Every event that reached the server for the NEW session must be under the cap.\n    // If the guard failed, we'd see a JSON string > 9 M chars here.\n    const newSessionEvents = getCalls()\n      .filter((c) => c.sessionId === String(NEW_SESSION_ID))\n      .flatMap((c) => c.events);\n\n    for (const event of newSessionEvents) {\n      expect(new Blob([JSON.stringify(event)]).size).toBeLessThanOrEqual(MAX_SINGLE_EVENT_SIZE);\n    }\n\n    // The ORIGINAL session must have delivered a full snapshot, confirming that\n    // normal recording was working before the oversized DOM was injected.\n    const originalSessionEvents = getCalls()\n      .filter((c) => c.sessionId === String(TEST_SESSION_ID))\n      .flatMap((c) => c.events);\n    expect(originalSessionEvents.find((e) => e['type'] === 2)).toBeDefined();\n  });\n\n  test('SDK records normally after an oversized snapshot is dropped', async ({ page }) => {\n    const OVERSIZED_SESSION_ID = TEST_SESSION_ID + 60_000;\n    const RECOVERY_SESSION_ID = TEST_SESSION_ID + 120_000;\n    await mockRemoteConfig(page, remoteConfigRecording);\n    const getCalls = await captureBySession(page);\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    // Session 2: snapshot will be dropped (DOM is too large)\n    await injectLargeNode(page);\n    await page.evaluate(\n      (id) => (window as any).sessionReplay.setSessionId(id).promise as Promise<void>,\n      OVERSIZED_SESSION_ID,\n    );\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS * 2);\n\n    // Remove the large node so session 3 takes a normal-sized snapshot\n    await page.evaluate(() => document.querySelector('[data-large]')?.remove());\n    await page.evaluate(\n      (id) => (window as any).sessionReplay.setSessionId(id).promise as Promise<void>,\n      RECOVERY_SESSION_ID,\n    );\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS * 6);\n\n    // Session 3 must have delivered a full snapshot — SDK must still be operational\n    const recoveryEvents = getCalls()\n      .filter((c) => c.sessionId === String(RECOVERY_SESSION_ID))\n      .flatMap((c) => c.events);\n    expect(recoveryEvents.find((e) => e['type'] === 2)).toBeDefined();\n  });\n});\n\n// ─── WAF 413 bisect-retry ─────────────────────────────────────────────────────\n\ntest.describe('WAF 413 bisect-retry', () => {\n  test('splits batch on WAF 413 and delivers events via retry', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigRecording);\n\n    let callCount = 0;\n    const deliveredBodies: string[] = [];\n\n    await page.route('https://api-sr.amplitude.com/**', async (route: Route) => {\n      callCount++;\n      if (callCount === 1) {\n        // WAF 413 signature: JSON body containing \"Payload exceeds\"\n        await route.fulfill({\n          status: 413,\n          contentType: 'application/json',\n          body: '{\"error\":\"Payload exceeds the maximum allowed size of 10MB\"}',\n        });\n      } else {\n        deliveredBodies.push(readRouteBody(route));\n        await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(SR_API_SUCCESS) });\n      }\n    });\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    await page.evaluate(() => window.dispatchEvent(new Event('blur')));\n    await page.evaluate(() => (window as any).sessionReplay.flush(false) as Promise<void>);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS * 6);\n\n    // SDK must have bisected and retried after the WAF 413\n    expect(callCount).toBeGreaterThan(1);\n    // Events must ultimately have been delivered\n    expect(deliveredBodies.flatMap(decodeEvents).length).toBeGreaterThan(0);\n  });\n\n  test('app-layer 413 does not cause an infinite retry loop', async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigRecording);\n\n    let callCount = 0;\n    await page.route('https://api-sr.amplitude.com/**', async (route: Route) => {\n      callCount++;\n      // App-layer 413: plain text, no WAF body signature\n      await route.fulfill({ status: 413, contentType: 'text/plain', body: 'Payload Too Large' });\n    });\n\n    await page.goto(buildUrl('/session-replay-browser/sr-capture-test.html', { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    await page.evaluate(() => window.dispatchEvent(new Event('blur')));\n    await page.evaluate(() => (window as any).sessionReplay.flush(false) as Promise<void>);\n    // Wait long enough for an infinite loop to be detectable\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS * 10);\n\n    // Non-WAF 413 short-circuits to completeRequest without bisecting, so the batch\n    // produces at most one tracking call. Allow a small slack for an unrelated follow-up\n    // flush during the wait, but flag a regression that re-enables bisect on app-layer 413s.\n    expect(callCount).toBeLessThanOrEqual(2);\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/e2e/trc-url-rule.spec.ts",
    "content": "import { test, expect } from '@playwright/test';\nimport {\n  SNAPSHOT_SETTLE_MS,\n  TEST_SESSION_ID,\n  buildUrl,\n  waitForReady,\n  captureTrackRequests,\n  mockRemoteConfig,\n} from './helpers';\n\n/**\n * E2E tests for Targeted Recording Config (TRC) URL-rule enforcement.\n *\n * Scenario 1 — Happy path: fresh state, network returns URL-filtered TRC config.\n *   - Non-matching URL → no recording.\n *   - SPA navigation to matching URL → recording starts.\n *\n * Scenario 2 — Stale-cache behavior with the SR-4234 fix:\n *   joined-config now subscribes with { timeout } delivery mode, so the SDK waits for the\n *   remote response and uses it when it arrives. Two cases here:\n *     • Live network → SDK uses the fresh remote config, recording does NOT start on the\n *       non-matching URL (this is the primary bug the fix closes).\n *     • Network blocked (fast failure) → fetch resolves with a null result; joined-config\n *       rejects and captureEnabled becomes false, so no recording starts. This is the\n *       desirable fail-closed outcome.\n *   The residual gap is genuinely-slow networks (response > timeout) where the outer\n *   timeout fires and the SDK falls back to whatever cache exists. Cache TTL / fail-closed\n *   targeting are the defense-in-depth follow-ups that close that last case.\n */\n\nconst SR_PROPERTY_KEY = '[Amplitude] Session Replay ID';\nconst TEST_PAGE = '/session-replay-browser/sr-capture-test.html';\n\n// API key used by sr-capture-test.html\nconst TEST_API_KEY = 'd90c5cf09ca2546a1626272906b99a76';\n// localStorage cache key = 'AMP_remote_config_' + apiKey.substring(0, 10)\nconst CACHE_LS_KEY = `AMP_remote_config_${TEST_API_KEY.substring(0, 10)}`;\n\n// Remote config that captures ONLY when URL contains /should-capture.\n// Default segment is 0% (off).\nfunction remoteConfigWithTrcUrlRule() {\n  return {\n    configs: {\n      sessionReplay: {\n        sr_sampling_config: { capture_enabled: true, sample_rate: 0.0 },\n        sr_targeting_config: {\n          key: 'sr_targeting_config',\n          variants: { on: { key: 'on' }, off: { key: 'off' } },\n          segments: [\n            {\n              metadata: { segmentName: 'Should capture' },\n              bucket: {\n                selector: ['context', 'session_id'],\n                salt: 'trc_test_salt',\n                allocations: [\n                  {\n                    range: [0, 100],\n                    distributions: [{ variant: 'on', range: [0, 42949673] }],\n                  },\n                ],\n              },\n              conditions: [[{ selector: ['context', 'page', 'url'], op: 'contains', values: ['/should-capture'] }]],\n            },\n            {\n              bucket: {\n                selector: ['context', 'session_id'],\n                salt: 'trc_default_salt',\n                allocations: [\n                  {\n                    range: [0, 100],\n                    distributions: [{ variant: 'on', range: [0, 0] }],\n                  },\n                ],\n              },\n              metadata: { segmentName: 'default random sample', segmentId: '__internal_random_sample__' },\n            },\n            { variant: 'off' },\n          ],\n        },\n      },\n    },\n  };\n}\n\n// Stale remote config that captures everywhere (no URL condition, 100% rate).\nfunction staleRemoteConfigCaptureEverywhere() {\n  return {\n    remoteConfig: {\n      configs: {\n        sessionReplay: {\n          sr_sampling_config: { capture_enabled: true, sample_rate: 1.0 },\n          sr_targeting_config: {\n            key: 'sr_targeting_config',\n            variants: { on: { key: 'on' }, off: { key: 'off' } },\n            segments: [\n              {\n                metadata: { segmentName: 'capture_everywhere' },\n                bucket: {\n                  selector: ['context', 'session_id'],\n                  salt: 'stale_salt',\n                  allocations: [\n                    {\n                      range: [0, 100],\n                      distributions: [{ variant: 'on', range: [0, 42949672] }],\n                    },\n                  ],\n                },\n              },\n              { variant: 'off' },\n            ],\n          },\n        },\n      },\n    },\n    lastFetch: new Date(Date.now() - 60_000).toISOString(),\n  };\n}\n\nasync function seedStaleCache(page: import('@playwright/test').Page) {\n  await page.addInitScript(\n    (args: { key: string; value: string }) => {\n      localStorage.setItem(args.key, args.value);\n    },\n    { key: CACHE_LS_KEY, value: JSON.stringify(staleRemoteConfigCaptureEverywhere()) },\n  );\n}\n\nasync function getProperties(page: import('@playwright/test').Page): Promise<Record<string, unknown>> {\n  return page.evaluate(() => (window as any).sessionReplay.getSessionReplayProperties() as Record<string, unknown>);\n}\n\nfunction mockTrackApi(page: import('@playwright/test').Page) {\n  return page.route('https://api-sr.amplitude.com/**', (route) =>\n    route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ code: 200 }) }),\n  );\n}\n\n// ─── Scenario 1: Happy path (fresh state, TRC URL rule mocked) ───────────────\n\ntest.describe('TRC URL rule — happy path', () => {\n  test.beforeEach(async ({ page }) => {\n    await mockRemoteConfig(page, remoteConfigWithTrcUrlRule());\n    await mockTrackApi(page);\n  });\n\n  test('does not record on a non-matching URL', async ({ page }) => {\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(TEST_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    const props = await getProperties(page);\n    expect(props[SR_PROPERTY_KEY]).toBeFalsy();\n\n    await page.evaluate(() => window.dispatchEvent(new Event('blur')));\n    await page.evaluate(() => (window as any).sessionReplay.flush(false) as Promise<void>);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    expect(getBodies().length).toBe(0);\n  });\n\n  test('starts recording after SPA navigation to a matching URL', async ({ page }) => {\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(TEST_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    expect((await getProperties(page))[SR_PROPERTY_KEY]).toBeFalsy();\n\n    await page.evaluate(() => history.pushState({}, '', '/should-capture'));\n\n    await page.waitForFunction(\n      (key) => !!(window as any).sessionReplay.getSessionReplayProperties()[key],\n      SR_PROPERTY_KEY,\n      { timeout: 10_000 },\n    );\n\n    const propsAfter = await getProperties(page);\n    expect(propsAfter[SR_PROPERTY_KEY]).toBeTruthy();\n    expect(String(propsAfter[SR_PROPERTY_KEY])).toContain(`/${TEST_SESSION_ID}`);\n\n    await page.evaluate(() => window.dispatchEvent(new Event('blur')));\n    await page.evaluate(() => (window as any).sessionReplay.flush(false) as Promise<void>);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    expect(getBodies().length).toBeGreaterThan(0);\n  });\n});\n\n// ─── Scenario 2: Stale-cache bug repro ───────────────────────────────────────\n\ntest.describe('TRC URL rule — stale localStorage cache', () => {\n  test.setTimeout(30_000);\n\n  test('network blocked + stale cache: SDK fails closed (does not record)', async ({ page }) => {\n    await seedStaleCache(page);\n\n    // Block the remote-config fetch entirely. route.abort() fails the request fast,\n    // so analytics-core's `subscribeWaitForRemote` resolves on the failed-fetch result\n    // (remoteConfig=null) before the outer timeout fires — the cache-fallback path\n    // (which only triggers on outer timeout) is NOT taken. joined-config sees a null\n    // remote config and rejects, captureEnabled becomes false, and no recording starts.\n    // This is the desirable fail-closed outcome for firewalled/adblocked customers:\n    // no recording is strictly better than recording against a stale config.\n    //\n    // Caveat: a genuinely slow network (response > 1500ms but eventually returns) WOULD\n    // hit the outer timeout and fall back to (potentially stale) cache. That residual\n    // gap is what the defense-in-depth follow-ups (cache TTL, fail-closed targeting\n    // default) close. Not exercised here because page.route doesn't simulate slow\n    // success — only fast failure or fast success.\n    await page.route('https://sr-client-cfg.amplitude.com/**', (route) => route.abort());\n\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(TEST_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    const props = await getProperties(page);\n    const isRecording = !!props[SR_PROPERTY_KEY];\n\n    await page.evaluate(() => window.dispatchEvent(new Event('blur')));\n    await page.evaluate(() => (window as any).sessionReplay.flush(false) as Promise<void>);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    expect(isRecording).toBe(false);\n    expect(getBodies().length).toBe(0);\n  });\n\n  test('stale cache with live network: documents whether SDK self-corrects within the same session', async ({\n    page,\n  }) => {\n    await seedStaleCache(page);\n\n    // Allow the network to respond with the correct URL-filtered TRC config.\n    // In 'all' mode, joined-config resolves on the FIRST callback — so if the\n    // cache fires before the network response arrives, the session is already\n    // initialised with stale data. The network response only updates the cache\n    // for the NEXT session.\n    await mockRemoteConfig(page, remoteConfigWithTrcUrlRule());\n    await mockTrackApi(page);\n\n    const { getBodies } = await captureTrackRequests(page);\n\n    await page.goto(buildUrl(TEST_PAGE, { sessionId: TEST_SESSION_ID }));\n    await waitForReady(page);\n    // Give time for the network response to arrive and be processed.\n    await page.waitForTimeout(3_000);\n\n    const props = await getProperties(page);\n    const isRecording = !!props[SR_PROPERTY_KEY];\n\n    await page.evaluate(() => window.dispatchEvent(new Event('blur')));\n    await page.evaluate(() => (window as any).sessionReplay.flush(false) as Promise<void>);\n    await page.waitForTimeout(SNAPSHOT_SETTLE_MS);\n\n    // SR-4234 fixed: with { timeout } delivery mode, joined-config waits for the remote\n    // response and uses it instead of the stale cache. The fresh config excludes this URL,\n    // so the SDK does not record this session.\n    expect(isRecording).toBe(false);\n    expect(getBodies().length).toBe(0);\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/jest.config.js",
    "content": "const baseConfig = require('../../jest.config.js');\nconst package = require('./package');\n\nmodule.exports = {\n  ...baseConfig,\n  verbose: true,\n  transform: {\n    ...baseConfig.transform,\n    '\\\\.[jt]sx?$': ['babel-jest', { plugins: ['@babel/plugin-transform-modules-commonjs'] }], // needed for @medv/finder\n  },\n  transformIgnorePatterns: [`../../node_modules/(?!@medv)`],\n  displayName: package.name,\n  rootDir: '.',\n  testEnvironment: 'jsdom',\n  coveragePathIgnorePatterns: ['index.ts'],\n  setupFilesAfterEnv: ['./test/jest-setup.js'],\n};\n"
  },
  {
    "path": "packages/session-replay-browser/package.json",
    "content": "{\n  \"name\": \"@amplitude/session-replay-browser\",\n  \"version\": \"1.43.0\",\n  \"description\": \"\",\n  \"author\": \"Amplitude Inc\",\n  \"homepage\": \"https://github.com/amplitude/Amplitude-TypeScript\",\n  \"license\": \"MIT\",\n  \"main\": \"lib/cjs/index.js\",\n  \"module\": \"lib/esm/index.js\",\n  \"types\": \"lib/esm/index.d.ts\",\n  \"sideEffects\": false,\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/amplitude/Amplitude-TypeScript.git\"\n  },\n  \"scripts\": {\n    \"build\": \"pnpm build:es5 && pnpm build:esm && pnpm bundle\",\n    \"bundle\": \"rollup --config rollup.config.js\",\n    \"bundle:analyze\": \"ANALYZE=true rollup --config rollup.config.js\",\n    \"build:es5\": \"tsc -p ./tsconfig.es5.json\",\n    \"build:esm\": \"tsc -p ./tsconfig.esm.json\",\n    \"watch\": \"tsc -p ./tsconfig.esm.json --watch\",\n    \"clean\": \"rimraf node_modules lib coverage\",\n    \"fix\": \"pnpm fix:eslint & pnpm fix:prettier\",\n    \"fix:eslint\": \"eslint '{src,test}/**/*.ts' --fix\",\n    \"fix:prettier\": \"prettier --write \\\"{src,test}/**/*.ts\\\"\",\n    \"lint\": \"pnpm lint:eslint & pnpm lint:prettier\",\n    \"lint:eslint\": \"eslint '{src,test}/**/*.ts'\",\n    \"lint:prettier\": \"prettier --check \\\"{src,test}/**/*.ts\\\"\",\n    \"publish\": \"node ./scripts/publish/upload-to-s3.js\",\n    \"test\": \"jest\",\n    \"typecheck\": \"tsc -p ./tsconfig.json\",\n    \"version\": \"pnpm version-file && GENERATE_SNIPPET=true pnpm build\",\n    \"version-file\": \"echo '// Autogenerated by `pnpm version-file`. DO NOT EDIT' > src/version.ts && node -p \\\"'export const VERSION = \\\\'' + require('./package.json').version + '\\\\';'\\\" >> src/version.ts\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/amplitude/Amplitude-TypeScript/issues\"\n  },\n  \"dependencies\": {\n    \"@amplitude/analytics-client-common\": \"workspace:*\",\n    \"@amplitude/analytics-core\": \"workspace:*\",\n    \"@amplitude/analytics-types\": \"workspace:*\",\n    \"@amplitude/experiment-core\": \"0.7.2\",\n    \"@amplitude/rrweb-packer\": \"2.0.0-alpha.40\",\n    \"@amplitude/rrweb-plugin-console-record\": \"2.0.0-alpha.40\",\n    \"@amplitude/rrweb-record\": \"2.0.0-alpha.40\",\n    \"@amplitude/rrweb-types\": \"2.0.0-alpha.40\",\n    \"@amplitude/rrweb-utils\": \"2.0.0-alpha.40\",\n    \"@amplitude/targeting\": \"workspace:*\",\n    \"@rollup/plugin-replace\": \"^6.0.1\",\n    \"idb\": \"8.0.0\",\n    \"tslib\": \"^2.4.1\"\n  },\n  \"devDependencies\": {\n    \"@aws-sdk/client-s3\": \"^3.229.0\",\n    \"@babel/core\": \"^7.24.7\",\n    \"@babel/plugin-transform-modules-commonjs\": \"^7.24.7\",\n    \"@rollup/plugin-commonjs\": \"^23.0.4\",\n    \"@rollup/plugin-node-resolve\": \"^15.0.1\",\n    \"@rollup/plugin-typescript\": \"^10.0.1\",\n    \"@ungap/structured-clone\": \"^1.2.0\",\n    \"babel-jest\": \"^29.7.0\",\n    \"fake-indexeddb\": \"4.0.2\",\n    \"rollup\": \"^2.79.1\",\n    \"rollup-plugin-execute\": \"^1.1.1\",\n    \"rollup-plugin-gzip\": \"^3.1.0\",\n    \"rollup-plugin-sourcemaps\": \"^0.6.3\",\n    \"rollup-plugin-terser\": \"^7.0.2\"\n  },\n  \"files\": [\n    \"lib\"\n  ]\n}\n"
  },
  {
    "path": "packages/session-replay-browser/playwright.config.ts",
    "content": "import path from 'path';\nimport { defineConfig } from '@playwright/test';\nimport baseConfig from '../../playwright.config';\n\nexport default defineConfig({\n  ...baseConfig,\n  testMatch: '**/e2e/**/*.spec.ts',\n  testIgnore: [],\n  reporter: [\n    ['json', { outputFile: 'e2e/results.json' }],\n    ['html', { open: 'never' }],\n  ],\n  webServer: {\n    command: 'pnpm exec vite dev --port 5173 --clearScreen=false',\n    cwd: path.resolve(__dirname, '../..'),\n    url: 'http://localhost:5173',\n    reuseExistingServer: !process.env.CI,\n    timeout: 30000,\n  },\n});\n"
  },
  {
    "path": "packages/session-replay-browser/rollup.config.js",
    "content": "import { iife, umd } from '../../scripts/build/rollup.config';\n\nimport resolve from '@rollup/plugin-node-resolve';\nimport replace from '@rollup/plugin-replace';\nimport { terser } from 'rollup-plugin-terser';\nimport typescript from '@rollup/plugin-typescript';\nimport { rollup } from 'rollup';\nimport path from 'node:path';\nimport commonjs from '@rollup/plugin-commonjs';\nimport gzip from 'rollup-plugin-gzip';\n\n// Configure ES module build for chunks\nconst esmConfig = {\n  input: 'src/index.ts',\n  output: {\n    dir: 'lib/scripts',\n    format: 'es',\n    sourcemap: true,\n    entryFileNames: 'session-replay-browser-esm.js',\n    chunkFileNames: '[name]-min.js',\n    manualChunks: {\n      'console-plugin': ['@amplitude/rrweb-plugin-console-record'],\n      targeting: ['@amplitude/targeting'],\n      'rrweb-record': ['@amplitude/rrweb-record'],\n      worker: ['src/worker/index.ts'],\n    },\n  },\n  plugins: [\n    typescript({\n      tsconfig: 'tsconfig.esm.json',\n      compilerOptions: {\n        target: 'es2015',\n        module: 'es2020',\n        moduleResolution: 'node',\n        downlevelIteration: true,\n        declaration: false,\n        declarationMap: false,\n        outDir: 'lib/scripts',\n        baseUrl: '.',\n        paths: {\n          'src/*': ['src/*'],\n        },\n      },\n    }),\n    resolve({\n      browser: true,\n    }),\n    commonjs(),\n    terser({\n      output: {\n        comments: false,\n      },\n    }),\n    gzip(),\n  ],\n};\n\n// Keep original IIFE config for legacy browsers\nconst mainBundleConfig = {\n  input: 'src/index.ts',\n  output: {\n    format: 'iife',\n    file: 'lib/scripts/session-replay-browser-min.js',\n    name: 'sessionReplay',\n    sourcemap: true,\n    inlineDynamicImports: true,\n  },\n  plugins: [\n    typescript({\n      tsconfig: 'tsconfig.json',\n      compilerOptions: {\n        target: 'es2015',\n        module: 'es2020',\n        moduleResolution: 'node',\n        downlevelIteration: true,\n        declaration: false,\n        declarationMap: false,\n        outDir: 'lib/scripts',\n        baseUrl: '.',\n        paths: {\n          'src/*': ['src/*'],\n        },\n      },\n    }),\n    resolve({\n      browser: true,\n    }),\n    commonjs(),\n    terser({\n      output: {\n        comments: false,\n      },\n    }),\n    gzip(),\n  ],\n};\n\nconst webWorkerESMBundleConfig = {\n  input: 'src/worker/index.ts',\n  output: {\n    format: 'es',\n    file: 'lib/esm/worker/index.js',\n    sourcemap: false,\n    inlineDynamicImports: false,\n  },\n  plugins: [\n    typescript({\n      tsconfig: 'tsconfig.esm.json',\n      compilerOptions: {\n        declaration: false,\n        declarationMap: false,\n        removeComments: true,\n      },\n    }),\n  ],\n};\n\nconst webWorkerES5BundleConfig = {\n  input: 'src/worker/index.ts',\n  output: {\n    file: 'lib/cjs/worker/index.js',\n    format: 'cjs',\n    sourcemap: false,\n    inlineDynamicImports: false,\n    strict: true,\n  },\n  plugins: [\n    typescript({\n      tsconfig: 'tsconfig.es5.json',\n      compilerOptions: {\n        declaration: false,\n        declarationMap: false,\n        removeComments: true,\n        noImplicitUseStrict: false,\n      },\n    }),\n  ],\n};\n\nasync function buildWorkerBundle(entryFile) {\n  const packageDir = path.dirname(new URL(import.meta.url).pathname);\n  const input = path.join(packageDir, entryFile);\n  const bundle = await rollup({\n    input,\n    output: {\n      format: 'iife',\n      name: 'WebWorker',\n      inlineDynamicImports: true,\n      sourcemap: false,\n    },\n    plugins: [\n      typescript({\n        tsconfig: path.join(packageDir, 'tsconfig.worker.json'),\n        compilerOptions: {\n          module: 'esnext',\n        },\n      }),\n      resolve({\n        browser: true,\n      }),\n      commonjs(),\n      terser(),\n    ],\n  });\n\n  const { output } = await bundle.generate({\n    format: 'iife',\n    name: 'WebWorker',\n    inlineDynamicImports: true,\n    sourcemap: false,\n  });\n\n  return output[0].code;\n}\n\nexport async function webWorkerPlugins() {\n  const [compressionWorkerCode, trackDestinationWorkerCode] = await Promise.all([\n    buildWorkerBundle('./src/worker/compression.ts'),\n    buildWorkerBundle('./src/worker/track-destination.ts'),\n  ]);\n  return [\n    replace({\n      preventAssignment: true,\n      values: {\n        'replace.COMPRESSION_WEBWORKER_BODY': JSON.stringify(compressionWorkerCode),\n        'replace.TRACK_DESTINATION_WEBWORKER_BODY': JSON.stringify(trackDestinationWorkerCode),\n      },\n    }),\n  ];\n}\n\nexport default async () => {\n  const commonPlugins = await webWorkerPlugins();\n  mainBundleConfig.plugins = [...commonPlugins, ...mainBundleConfig.plugins];\n  esmConfig.plugins = [...commonPlugins, ...esmConfig.plugins];\n  webWorkerESMBundleConfig.plugins = [...commonPlugins, ...webWorkerESMBundleConfig.plugins];\n  webWorkerES5BundleConfig.plugins = [...commonPlugins, ...webWorkerES5BundleConfig.plugins];\n  return [mainBundleConfig, esmConfig, webWorkerESMBundleConfig, webWorkerES5BundleConfig];\n};"
  },
  {
    "path": "packages/session-replay-browser/scripts/publish/upload-to-s3.js",
    "content": "const fs = require('fs');\nconst path = require('path');\nconst { S3Client, PutObjectCommand, HeadObjectCommand } = require('@aws-sdk/client-s3');\nconst { getName, getVersion } = require('../../../../scripts/utils');\n\nconst bucket = process.env.S3_BUCKET_NAME;\nconst location = path.join(process.cwd(), 'lib', 'scripts');\nconst files = [\n  'session-replay-browser-esm.js.gz',  // ESM version\n  'session-replay-browser-min.js.gz',  // IIFE version\n  'console-plugin-min.js.gz',  // Console plugin chunk\n  'rrweb-record-min.js.gz',  // RRWeb record chunk\n  'targeting-min.js.gz'  // Targeting chunk\n];\n\nlet deployedCount = 0;\n\nconsole.log('[Publish Session Replay Browser to AWS S3] START');\nconst promises = files.map((file) => {\n  const body = fs.readFileSync(path.join(location, file));\n  const key = `libs/${file.replace('session-replay-browser', `${getName()}-${getVersion()}`)}`;\n  const client = new S3Client();\n\n  const headObject = new HeadObjectCommand({\n    Bucket: bucket,\n    Key: key,\n  });\n  console.log(`[Publish to AWS S3] Checking if ${key} exists in target bucket...`);\n  return client\n    .send(headObject)\n    .then(() => {\n      console.log(`[Publish to AWS S3] ${key} exists in target bucket. Skipping upload job.`);\n    })\n    .catch(() => {\n      console.log(`[Publish to AWS S3] ${key} does not exist in target bucket. Uploading to S3...`);\n      const putObject = new PutObjectCommand({\n        ACL: 'public-read',\n        Body: body,\n        Bucket: bucket,\n        CacheControl: 'max-age=31536000',\n        ContentType: 'application/javascript',\n        ContentEncoding: 'gzip',\n        Key: key,\n      });\n      return client\n        .send(putObject)\n        .then(() => {\n          console.log(`[Publish to AWS S3] Upload success for ${key}.`);\n          deployedCount += 1;\n        })\n        .catch(console.error);\n    });\n});\n\nPromise.all(promises)\n  .then(() => {\n    if (deployedCount === 0) {\n      console.log(`[Publish to AWS S3] Complete! Nothing to deploy.`);\n    } else {\n      console.log(`[Publish to AWS S3] Success! Deployed ${deployedCount}/${files.length} files.`);\n    }\n    console.log('[Publish to AWS S3] END');\n  })\n  .catch(console.log); "
  },
  {
    "path": "packages/session-replay-browser/src/beacon-transport.ts",
    "content": "import { getGlobalScope } from '@amplitude/analytics-core';\nimport { SessionReplayJoinedConfig } from './config/types';\nimport { SessionReplayDestinationSessionMetadata } from './typings/session-replay';\nimport { getServerUrl } from './helpers';\n\ntype BeaconSendFn<T> = (pageUrl: string, payload: T) => boolean;\n\n/**\n * For very small payloads it's preferable to use the [Beacon API](https://developer.mozilla.org/en-US/docs/Web/API/Beacon_API).\n * While it doesn't provide 100% guarantees on sends, it greatly helps with overall reliability and page load performance. As\n * the Beacon API has a potential to fail due to size constraints we want to fall back to XHR if need be. This is mostly to\n * be used with 'pagehide' or 'beforeunload' events.\n *\n * Note there are only 3 CORS safelisted Content-Types you can send:\n *\n * - application/x-www-form-urlencoded\n * - multipart/form-data\n * - text/plain\n *\n * If we do not send one of these, some browsers like Chrome may not send this at all. Also we incur the overhead of a preflight\n * request. In our case we will add no additional content-type header. If you are trying to ping a server that requires this\n * header, you may want to use the regular fetch API or a different mechanism.\n */\nexport class BeaconTransport<T> {\n  private sendBeacon: BeaconSendFn<T>;\n  private sendXhr: BeaconSendFn<T>;\n  private readonly basePageUrl: string;\n  private readonly context: Omit<SessionReplayDestinationSessionMetadata, 'deviceId'>;\n  private readonly apiKey: string;\n\n  constructor(context: Omit<SessionReplayDestinationSessionMetadata, 'deviceId'>, config: SessionReplayJoinedConfig) {\n    const globalScope = getGlobalScope();\n    if (globalScope && globalScope.navigator && typeof globalScope.navigator.sendBeacon === 'function') {\n      this.sendBeacon = (pageUrl, payload) => {\n        try {\n          if (globalScope.navigator.sendBeacon(pageUrl, JSON.stringify(payload))) {\n            return true;\n          }\n        } catch (e) {\n          // not logging error, since it would be hard to view and just adds overhead.\n        }\n        return false;\n      };\n    } else {\n      this.sendBeacon = () => false;\n    }\n\n    this.sendXhr = (pageUrl, payload) => {\n      const xhr = new XMLHttpRequest();\n      xhr.open('POST', pageUrl, true);\n      xhr.setRequestHeader('Accept', '*/*');\n      xhr.send(JSON.stringify(payload));\n      return true;\n    };\n\n    this.basePageUrl = getServerUrl(config.serverZone, config.trackServerUrl);\n    this.apiKey = config.apiKey;\n    this.context = context;\n  }\n\n  send(deviceId: string, payload: T) {\n    const { sessionId, type } = this.context;\n    const urlParams = new URLSearchParams({\n      device_id: deviceId,\n      session_id: String(sessionId),\n      type: String(type),\n      api_key: this.apiKey,\n    });\n\n    const pageUrl = `${this.basePageUrl}?${urlParams.toString()}`;\n\n    // ideally send using the beacon API, but there is a chance it may fail, possibly due to a payload\n    // size limit. in this case, try best effort to send using xhr.\n    this.sendBeacon(pageUrl, payload) || this.sendXhr(pageUrl, payload);\n  }\n}\n"
  },
  {
    "path": "packages/session-replay-browser/src/config/joined-config.ts",
    "content": "import { ILogger, IRemoteConfigClient, RemoteConfigClient, RemoteConfig, Source } from '@amplitude/analytics-core';\nimport { getDebugConfig } from '../helpers';\nimport { SessionReplayOptions } from '../typings/session-replay';\nimport { SessionReplayLocalConfig } from './local-config';\nimport {\n  SessionReplayLocalConfig as ISessionReplayLocalConfig,\n  PrivacyConfig,\n  SessionReplayConfigs,\n  SessionReplayJoinedConfig,\n  SessionReplayRemoteConfig,\n} from './types';\n\n// Budget for waiting on the remote config response before falling back to the local cache.\n// The inner fetch in analytics-core uses a 1000ms per-attempt AbortController timeout with\n// up to 3 retries — but this outer timeout is the only thing the SR plugin waits on, so\n// only the first attempt can possibly complete in time (attempt 2 starts at ~1000-1333ms\n// after backoff jitter and runs to ~2000-2333ms, well past any reasonable outer budget).\n// 1500ms is set above the 1000ms inner abort to avoid a tie with the inner cutoff and\n// give the first attempt's resolution path room to finish; everything else falls through\n// to the cache fallback. See SR-4234: prefer remote over a stale cache that would\n// otherwise win the synchronous race in 'all' mode.\nconst REMOTE_CONFIG_TIMEOUT_MS = 1500;\n\nexport const removeInvalidSelectorsFromPrivacyConfig = (privacyConfig: PrivacyConfig, loggerProvider: ILogger) => {\n  // This allows us to not search the DOM.\n  const fragment = document.createDocumentFragment();\n\n  const dropInvalidSelectors = (selectors: string[] | string = []): string[] | undefined => {\n    if (typeof selectors === 'string') {\n      selectors = [selectors];\n    }\n    selectors = selectors.filter((selector: string) => {\n      try {\n        fragment.querySelector(selector);\n      } catch {\n        loggerProvider.warn(`[session-replay-browser] omitting selector \"${selector}\" because it is invalid`);\n        return false;\n      }\n      return true;\n    });\n    if (selectors.length === 0) {\n      return undefined;\n    }\n    return selectors;\n  };\n  privacyConfig.blockSelector = dropInvalidSelectors(privacyConfig.blockSelector);\n  privacyConfig.maskSelector = dropInvalidSelectors(privacyConfig.maskSelector);\n  privacyConfig.unmaskSelector = dropInvalidSelectors(privacyConfig.unmaskSelector);\n  return privacyConfig;\n};\nexport class SessionReplayJoinedConfigGenerator {\n  private readonly localConfig: ISessionReplayLocalConfig;\n  private readonly remoteConfigClient: IRemoteConfigClient;\n\n  constructor(remoteConfigClient: IRemoteConfigClient, localConfig: ISessionReplayLocalConfig) {\n    this.localConfig = localConfig;\n    this.remoteConfigClient = remoteConfigClient;\n  }\n\n  async generateJoinedConfig(): Promise<SessionReplayConfigs> {\n    const config: SessionReplayJoinedConfig = { ...this.localConfig };\n    // Special case here as optOut is implemented via getter/setter\n    config.optOut = this.localConfig.optOut;\n    // We always want captureEnabled to be true, unless there's an override\n    // in the remote config.\n    config.captureEnabled = true;\n    let sessionReplayRemoteConfig: SessionReplayRemoteConfig | undefined;\n\n    try {\n      // Subscribe with a timeout so the SDK prefers the remote response and only falls back\n      // to cache after the budget elapses. 'all' mode would race a synchronous cache read\n      // against the network and resolve on whichever fires first — cache always wins, so a\n      // stale cache silently overrides the live config (SR-4234).\n      await new Promise<void>((resolve, reject) => {\n        this.remoteConfigClient.subscribe(\n          'configs.sessionReplay',\n          { timeout: REMOTE_CONFIG_TIMEOUT_MS },\n          (remoteConfig: RemoteConfig | null, source: Source) => {\n            this.localConfig.loggerProvider.debug(\n              `Session Replay remote configuration received from ${source}:`,\n              JSON.stringify(remoteConfig, null, 2),\n            );\n\n            if (!remoteConfig) {\n              reject(new Error('No remote config received'));\n              return;\n            }\n\n            // remoteConfig is already filtered to 'configs.sessionReplay' namespace\n            const namespaceConfig = remoteConfig as SessionReplayRemoteConfig;\n            const samplingConfig = namespaceConfig.sr_sampling_config;\n            const privacyConfig = namespaceConfig.sr_privacy_config;\n            const targetingConfig = namespaceConfig.sr_targeting_config;\n\n            const ugcFilterRules = config.interactionConfig?.ugcFilterRules;\n            // This is intentionally forced to only be set through the remote config.\n            config.interactionConfig = namespaceConfig.sr_interaction_config;\n            if (config.interactionConfig && ugcFilterRules) {\n              config.interactionConfig.ugcFilterRules = ugcFilterRules;\n            }\n\n            // This is intentionally forced to only be set through the remote config.\n            config.loggingConfig = namespaceConfig.sr_logging_config;\n\n            if (samplingConfig || privacyConfig || targetingConfig) {\n              sessionReplayRemoteConfig = {};\n              if (samplingConfig) {\n                sessionReplayRemoteConfig.sr_sampling_config = samplingConfig;\n              }\n              if (privacyConfig) {\n                sessionReplayRemoteConfig.sr_privacy_config = privacyConfig;\n              }\n              if (targetingConfig) {\n                sessionReplayRemoteConfig.sr_targeting_config = targetingConfig;\n              }\n            }\n\n            resolve();\n          },\n        );\n      });\n    } catch (error) {\n      this.localConfig.loggerProvider.error('Failed to generate joined config: ', error);\n      config.captureEnabled = false;\n      return {\n        localConfig: this.localConfig,\n        joinedConfig: config,\n        remoteConfig: undefined,\n      };\n    }\n\n    if (!sessionReplayRemoteConfig) {\n      return {\n        localConfig: this.localConfig,\n        joinedConfig: config,\n        remoteConfig: sessionReplayRemoteConfig,\n      };\n    }\n\n    const {\n      sr_sampling_config: samplingConfig,\n      sr_privacy_config: remotePrivacyConfig,\n      sr_targeting_config: targetingConfig,\n    } = sessionReplayRemoteConfig;\n    if (samplingConfig && Object.keys(samplingConfig).length > 0) {\n      if (Object.prototype.hasOwnProperty.call(samplingConfig, 'capture_enabled')) {\n        config.captureEnabled = samplingConfig.capture_enabled;\n      } else {\n        config.captureEnabled = false;\n      }\n\n      if (Object.prototype.hasOwnProperty.call(samplingConfig, 'sample_rate')) {\n        config.sampleRate = samplingConfig.sample_rate;\n      }\n\n      if (Object.prototype.hasOwnProperty.call(samplingConfig, 'min_session_duration_ms')) {\n        config.minSessionDurationMs = this.sanitizeMinSessionDurationMs(samplingConfig.min_session_duration_ms);\n      }\n    } else {\n      // If config API response was valid (ie 200), but no config returned, assume that\n      // customer has not yet set up config, and use sample rate from SDK options,\n      // allowing for immediate replay capture\n      config.captureEnabled = true;\n      this.localConfig.loggerProvider.debug(\n        'Remote config successfully fetched, but no values set for project, Session Replay capture enabled.',\n      );\n    }\n\n    // Remote config join acts somewhat like a left join between the remote and the local\n    // config. That is, remote config has precedence over local values as with sampling.\n    // However, non conflicting values will be added to the lists.\n    // Here's an example to illustrate:\n    //\n    // Remote config:   {'.selector1': 'MASK',   '.selector2': 'UNMASK'}\n    // Local config:    {'.selector1': 'UNMASK',                         '.selector3': 'MASK'}\n    //\n    // Resolved config: {'.selector1': 'MASK',   '.selector2': 'UNMASK', '.selector3': 'MASK'}\n    // config.privacyConfig = {\n    //   ...(config.privacyConfig ?? {}),\n    //   ...remotePrivacyConfig,\n    // };\n\n    if (remotePrivacyConfig) {\n      const localPrivacyConfig: PrivacyConfig = config.privacyConfig ?? {};\n\n      const joinedPrivacyConfig: Required<PrivacyConfig> & { blockSelector: string[] } = {\n        defaultMaskLevel: remotePrivacyConfig.defaultMaskLevel ?? localPrivacyConfig.defaultMaskLevel ?? 'medium',\n        blockSelector: [],\n        maskSelector: [],\n        unmaskSelector: [],\n        maskAttributes: [\n          ...new Set([...(localPrivacyConfig.maskAttributes ?? []), ...(remotePrivacyConfig.maskAttributes ?? [])]),\n        ],\n        urlMaskLevels: [...(remotePrivacyConfig.urlMaskLevels ?? []), ...(localPrivacyConfig.urlMaskLevels ?? [])],\n      };\n\n      const privacyConfigSelectorMap = (privacyConfig: PrivacyConfig): Record<string, 'mask' | 'unmask' | 'block'> => {\n        const selectorMap: Record<string, 'mask' | 'unmask' | 'block'> = {};\n        if (typeof privacyConfig.blockSelector === 'string') {\n          privacyConfig.blockSelector = [privacyConfig.blockSelector];\n        }\n\n        for (const selector of privacyConfig.blockSelector ?? []) {\n          selectorMap[selector] = 'block';\n        }\n        for (const selector of privacyConfig.maskSelector ?? []) {\n          selectorMap[selector] = 'mask';\n        }\n        for (const selector of privacyConfig.unmaskSelector ?? []) {\n          selectorMap[selector] = 'unmask';\n        }\n        return selectorMap;\n      };\n\n      const selectorMap: Record<string, 'mask' | 'unmask' | 'block'> = {\n        ...privacyConfigSelectorMap(localPrivacyConfig),\n        ...privacyConfigSelectorMap(remotePrivacyConfig),\n      };\n\n      for (const [selector, selectorType] of Object.entries(selectorMap)) {\n        if (selectorType === 'mask') {\n          joinedPrivacyConfig.maskSelector.push(selector);\n        } else if (selectorType === 'block') {\n          joinedPrivacyConfig.blockSelector.push(selector);\n        } else if (selectorType === 'unmask') {\n          joinedPrivacyConfig.unmaskSelector.push(selector);\n        }\n      }\n\n      config.privacyConfig = removeInvalidSelectorsFromPrivacyConfig(\n        joinedPrivacyConfig,\n        this.localConfig.loggerProvider,\n      );\n    }\n\n    if (targetingConfig && Object.keys(targetingConfig).length > 0) {\n      config.targetingConfig = targetingConfig;\n    }\n\n    this.localConfig.loggerProvider.debug(\n      JSON.stringify({ name: 'session replay joined config', config: getDebugConfig(config) }, null, 2),\n    );\n\n    return {\n      localConfig: this.localConfig,\n      joinedConfig: config,\n      remoteConfig: sessionReplayRemoteConfig,\n    };\n  }\n\n  /**\n   * Defensive bounds for the remote-supplied min_session_duration_ms. A misconfigured\n   * value (e.g. 30_000_000) would silently suppress every replay until the config is\n   * pushed again, so we clamp to a sane ceiling and warn on out-of-range inputs.\n   * Returns undefined for clearly invalid values so the gate falls back to disabled\n   * rather than carrying a NaN through downstream comparisons.\n   */\n  private sanitizeMinSessionDurationMs(raw: unknown): number | undefined {\n    if (typeof raw !== 'number' || !Number.isFinite(raw)) {\n      this.localConfig.loggerProvider.warn(\n        `min_session_duration_ms remote value is not a finite number (got ${String(raw)}); ignoring.`,\n      );\n      return undefined;\n    }\n    if (raw < 0) {\n      this.localConfig.loggerProvider.warn(`min_session_duration_ms remote value is negative (${raw}); ignoring.`);\n      return undefined;\n    }\n    if (raw > MAX_MIN_SESSION_DURATION_MS) {\n      this.localConfig.loggerProvider.warn(\n        `min_session_duration_ms remote value ${raw} exceeds ${MAX_MIN_SESSION_DURATION_MS}ms ceiling; clamping.`,\n      );\n      return MAX_MIN_SESSION_DURATION_MS;\n    }\n    return raw;\n  }\n}\n\n/**\n * Upper bound for the remote-configured replay min duration. 60 seconds is well above\n * any reasonable bounce threshold; values higher than this are almost certainly typos\n * (e.g. seconds confused for milliseconds, or an extra zero) and would otherwise\n * suppress every replay until the config is corrected.\n */\nexport const MAX_MIN_SESSION_DURATION_MS = 60_000;\n\nexport const createSessionReplayJoinedConfigGenerator = async (apiKey: string, options: SessionReplayOptions) => {\n  const localConfig = new SessionReplayLocalConfig(apiKey, options);\n\n  const remoteConfigClient = new RemoteConfigClient(\n    apiKey,\n    localConfig.loggerProvider,\n    localConfig.serverZone,\n    options.configServerUrl,\n  );\n\n  return new SessionReplayJoinedConfigGenerator(remoteConfigClient, localConfig);\n};\n"
  },
  {
    "path": "packages/session-replay-browser/src/config/local-config.ts",
    "content": "import { Config, Logger, FetchTransport, LogLevel } from '@amplitude/analytics-core';\nimport {\n  DEFAULT_PERFORMANCE_CONFIG,\n  DEFAULT_SAMPLE_RATE,\n  DEFAULT_SERVER_ZONE,\n  DEFAULT_URL_CHANGE_POLLING_INTERVAL,\n  UNMASK_TEXT_CLASS,\n} from '../constants';\nimport { SessionReplayOptions, StoreType } from '../typings/session-replay';\nimport {\n  SessionReplayLocalConfig as ISessionReplayLocalConfig,\n  CrossOriginIframesConfig,\n  InteractionConfig,\n  PrivacyConfig,\n  SessionReplayPerformanceConfig,\n  SessionReplayVersion,\n} from './types';\nimport { SafeLoggerProvider } from '../logger';\nimport { validateUGCFilterRules } from '../helpers';\n\nexport const getDefaultConfig = () => ({\n  flushMaxRetries: 2,\n  logLevel: LogLevel.Warn,\n  loggerProvider: new Logger(),\n  transportProvider: new FetchTransport(),\n});\n\nexport class SessionReplayLocalConfig extends Config implements ISessionReplayLocalConfig {\n  apiKey: string;\n  sampleRate: number;\n  privacyConfig?: PrivacyConfig;\n  interactionConfig?: InteractionConfig;\n  debugMode?: boolean;\n  configServerUrl?: string;\n  trackServerUrl?: string;\n  shouldInlineStylesheet?: boolean;\n  version?: SessionReplayVersion;\n  storeType: StoreType;\n  performanceConfig?: SessionReplayPerformanceConfig;\n  useWebWorker?: boolean;\n  applyBackgroundColorToBlockedElements?: boolean;\n  enableUrlChangePolling?: boolean;\n  urlChangePollingInterval?: number;\n  captureDocumentTitle?: boolean;\n  captureAdoptedStyleSheets?: boolean;\n  crossOriginIframes?: CrossOriginIframesConfig;\n  fullSnapshotIntervalMs?: number;\n\n  constructor(apiKey: string, options: SessionReplayOptions) {\n    const defaultConfig = getDefaultConfig();\n    super({\n      transportProvider: defaultConfig.transportProvider,\n      loggerProvider: new SafeLoggerProvider(options.loggerProvider || defaultConfig.loggerProvider),\n      ...options,\n      apiKey,\n    });\n    this.flushMaxRetries =\n      options.flushMaxRetries !== undefined && options.flushMaxRetries <= defaultConfig.flushMaxRetries\n        ? options.flushMaxRetries\n        : defaultConfig.flushMaxRetries;\n\n    this.apiKey = apiKey;\n    this.sampleRate = options.sampleRate || DEFAULT_SAMPLE_RATE;\n    this.serverZone = options.serverZone || DEFAULT_SERVER_ZONE;\n    this.configServerUrl = options.configServerUrl;\n    this.trackServerUrl = options.trackServerUrl;\n    this.shouldInlineStylesheet = options.shouldInlineStylesheet;\n    this.version = options.version;\n    this.performanceConfig = options.performanceConfig || DEFAULT_PERFORMANCE_CONFIG;\n    this.storeType = options.storeType ?? 'memory';\n    this.applyBackgroundColorToBlockedElements = options.applyBackgroundColorToBlockedElements ?? false;\n    this.enableUrlChangePolling = options.enableUrlChangePolling ?? false;\n    this.urlChangePollingInterval = options.urlChangePollingInterval ?? DEFAULT_URL_CHANGE_POLLING_INTERVAL;\n    this.captureDocumentTitle = options.captureDocumentTitle ?? false;\n    if (options.fullSnapshotIntervalMs !== undefined) {\n      this.fullSnapshotIntervalMs = options.fullSnapshotIntervalMs;\n    }\n\n    // Auto-include .amp-unmask as a default unmaskSelector entry so it works\n    // symmetrically with amp-mask/amp-block without requiring explicit config (SR-2945).\n    this.privacyConfig = {\n      ...(options.privacyConfig ?? {}),\n      unmaskSelector: Array.from(new Set([`.${UNMASK_TEXT_CLASS}`, ...(options.privacyConfig?.unmaskSelector ?? [])])),\n    };\n    if (options.interactionConfig) {\n      this.interactionConfig = options.interactionConfig;\n\n      // validate ugcFilterRules, throw error if invalid - throw error at the beginning of the config\n      if (this.interactionConfig.ugcFilterRules) {\n        validateUGCFilterRules(this.interactionConfig.ugcFilterRules);\n      }\n    }\n    if (options.debugMode) {\n      this.debugMode = options.debugMode;\n    }\n    // Support both new useWebWorker and legacy experimental.useWebWorker for backwards compatibility\n    if (options.useWebWorker !== undefined) {\n      this.useWebWorker = options.useWebWorker;\n    } else {\n      const legacyOptions = options as { experimental?: { useWebWorker?: boolean } };\n      if (legacyOptions.experimental?.useWebWorker !== undefined) {\n        this.useWebWorker = legacyOptions.experimental.useWebWorker;\n      }\n    }\n    this.captureAdoptedStyleSheets = options.captureAdoptedStyleSheets ?? true;\n    if (options.crossOriginIframes) {\n      this.crossOriginIframes = options.crossOriginIframes;\n    }\n  }\n}\n"
  },
  {
    "path": "packages/session-replay-browser/src/config/types.ts",
    "content": "import { IConfig, LogLevel, ILogger } from '@amplitude/analytics-core';\nimport { StoreType, ConsoleLogLevel } from '../typings/session-replay';\nimport { TargetingFlag } from '@amplitude/targeting';\n\nexport interface SamplingConfig {\n  sample_rate: number;\n  capture_enabled: boolean;\n  min_session_duration_ms?: number;\n}\n\nexport interface InteractionConfig {\n  trackEveryNms?: number;\n  enabled: boolean; // defaults to false\n  batch: boolean; // defaults to false\n  /**\n   * UGC filter rules.\n   */\n  ugcFilterRules?: UGCFilterRule[];\n}\n\nexport interface LoggingConfig {\n  console: {\n    enabled: boolean;\n    levels: ConsoleLogLevel[];\n  };\n  network?: {\n    enabled: boolean;\n    body?: {\n      request?: boolean;\n      response?: boolean;\n      maxBodySizeBytes?: number;\n    };\n  };\n}\n\nexport type TargetingConfig = TargetingFlag;\n\nexport type SessionReplayRemoteConfig = {\n  sr_sampling_config?: SamplingConfig;\n  sr_privacy_config?: PrivacyConfig;\n  sr_interaction_config?: InteractionConfig;\n  sr_logging_config?: LoggingConfig;\n  sr_targeting_config?: TargetingConfig;\n};\n\nexport interface SessionReplayRemoteConfigAPIResponse {\n  configs: {\n    sessionReplay: SessionReplayRemoteConfig;\n  };\n}\n\nexport type MaskLevel =\n  | 'light' // only mask a subset of inputs that's deemed sensitive - password, credit card, telephone #, email. These are information we never want to capture.\n  | 'medium' // mask all form fields (inputs); page text is captured as-is\n  | 'conservative'; // mask all inputs and all texts\n\nexport const DEFAULT_MASK_LEVEL = 'medium';\n\n// err on the side of excluding more\nexport type PrivacyConfig = {\n  blockSelector?: string | string[]; // exclude in the UI\n  defaultMaskLevel?: MaskLevel;\n  maskSelector?: string[];\n  unmaskSelector?: string[];\n  maskAttributes?: string[]; // HTML attribute names to mask (e.g. [\"placeholder\", \"aria-label\"])\n  /**\n   * Per-URL overrides for `defaultMaskLevel`. Each entry contains a glob pattern (`match`)\n   * and a `maskLevel` to apply when the current page URL matches that pattern.\n   * Rules are evaluated in order; the first match wins. Remote rules take precedence\n   * over local rules (remote entries are prepended before local entries).\n   *\n   * @example\n   * urlMaskLevels: [\n   *   { match: 'https://example.com/checkout/*', maskLevel: 'conservative' },\n   *   { match: 'https://example.com/public/*',   maskLevel: 'light' },\n   * ]\n   */\n  urlMaskLevels?: Array<{ match: string; maskLevel: MaskLevel }>;\n};\n\n/**\n * UGC filter rule.\n */\nexport type UGCFilterRule = {\n  /**\n   * The selector of the UGC element.\n   */\n  selector: string;\n  /**\n   * The replacement text for the UGC element.\n   */\n  replacement: string;\n};\n\nexport interface CrossOriginIframesConfig {\n  enabled: boolean;\n  /**\n   * When true (default), the parent SDK sends start/stop signals to child iframes via\n   * postMessage, keeping their recording lifecycle in sync with the parent.\n   *\n   * **Privacy note:** The child page's rrweb instance performs its own DOM serialization,\n   * so the parent's privacy config (mask levels, block selectors) does NOT automatically\n   * apply inside the iframe. Privacy settings must be configured independently on the child page.\n   *\n   * **Third-party iframes:** Cannot capture iframes you don't control (e.g. Stripe, Google\n   * Maps) — both parent and child pages must load the SDK with `crossOriginIframes.enabled: true`.\n   *\n   * Set to `false` to skip coordination and manage the child recording lifecycle yourself.\n   * @defaultValue true\n   */\n  coordinateChildren?: boolean;\n}\n\nexport interface SessionReplayLocalConfig extends IConfig {\n  apiKey: string;\n  loggerProvider: ILogger;\n  /**\n   * LogLevel.None or LogLevel.Error or LogLevel.Warn or LogLevel.Verbose or LogLevel.Debug.\n   * Sets the log level.\n   *\n   * @defaultValue LogLevel.Warn\n   */\n  logLevel: LogLevel;\n  /**\n   * The maximum number of retries allowed for sending replay events.\n   * Once this limit is reached, failed events will no longer be sent.\n   *\n   * @defaultValue 2\n   */\n  flushMaxRetries: number;\n  /**\n   * Use this option to control how many sessions to select for replay collection.\n   * The number should be a decimal between 0 and 1, for example 0.4, representing\n   * the fraction of sessions to have randomly selected for replay collection.\n   * Over a large number of sessions, 0.4 would select 40% of those sessions.\n   * Sample rates as small as six decimal places (0.000001) are supported.\n   *\n   * @defaultValue 0\n   */\n  sampleRate: number;\n  privacyConfig?: PrivacyConfig;\n  /**\n   * Adds additional debug event property to help debug instrumentation issues\n   * (such as mismatching apps). Only recommended for debugging initial setup,\n   * and not recommended for production.\n   */\n  debugMode?: boolean;\n  /**\n   * Specifies the endpoint URL to fetch remote configuration.\n   * If provided, it overrides the default server zone configuration.\n   */\n  configServerUrl?: string;\n  /**\n   * Specifies the endpoint URL for sending session replay data.\n   * If provided, it overrides the default server zone configuration.\n   */\n  trackServerUrl?: string;\n  /**\n   * If stylesheets are inlined, the contents of the stylesheet will be stored.\n   * During replay, the stored stylesheet will be used instead of attempting to fetch it remotely.\n   * This prevents replays from appearing broken due to missing stylesheets.\n   * Note: Inlining stylesheets may not work in all cases.\n   */\n  shouldInlineStylesheet?: boolean;\n  version?: SessionReplayVersion;\n  /**\n   * Performance configuration config. If enabled, we will defer compression\n   * to be done during the browser's idle periods.\n   */\n  performanceConfig?: SessionReplayPerformanceConfig;\n  /**\n   * Specifies how replay events should be stored. `idb` uses IndexedDB to persist replay events\n   * when all events cannot be sent during capture. `memory` stores replay events only in memory,\n   * meaning events are lost when the page is closed. If IndexedDB is unavailable, the system falls back to `memory`.\n   */\n  storeType: StoreType;\n\n  /**\n   * If true, the SDK will compress replay events using a web worker.\n   * This offloads compression to a separate thread, improving performance on the main thread.\n   *\n   * @defaultValue false\n   */\n  useWebWorker?: boolean;\n\n  userProperties?: { [key: string]: any };\n\n  /**\n   * If true, applies a background color to blocked elements in the replay.\n   * This helps visualize which elements are blocked from being captured.\n   */\n  applyBackgroundColorToBlockedElements?: boolean;\n  /**\n   * Enables URL change polling as a fallback for SPA route tracking.\n   * When enabled, the SDK will periodically check for URL changes every second\n   * in addition to patching the History API. This is useful for edge cases where\n   * route changes might bypass the standard History API methods.\n   *\n   * @defaultValue false\n   */\n  enableUrlChangePolling?: boolean;\n  /**\n   * Specifies the interval in milliseconds for URL change polling when enableUrlChangePolling is true.\n   * The SDK will check for URL changes at this interval as a fallback for SPA route tracking.\n   *\n   * @defaultValue 1000\n   */\n  urlChangePollingInterval?: number;\n  /**\n   * Whether to capture document title in URL change events.\n   * When disabled, the title field will be empty in URL change events.\n   *\n   * @defaultValue false\n   */\n  captureDocumentTitle?: boolean;\n  interactionConfig?: InteractionConfig;\n  /**\n   * When true (default), the CSS rules of any `adoptedStyleSheets` on shadow roots and\n   * the document are serialized **inline** within the full snapshot. This makes the snapshot\n   * self-contained so that shadow DOM styles are replayed correctly even if subsequent\n   * incremental `AdoptedStyleSheet` events are dropped in transit.\n   *\n   * Set to `false` to revert to the legacy behavior where adopted stylesheet rules are\n   * emitted as separate incremental events (which may be lost if delivery is unreliable).\n   * Only consider opting out if snapshot payload size is a critical concern.\n   *\n   * @defaultValue true\n   */\n  captureAdoptedStyleSheets?: boolean;\n  /**\n   * Enables recording of cross-origin iframes. Both the parent page and each child iframe\n   * page must load the Amplitude Session Replay SDK with this option enabled.\n   *\n   * When enabled, rrweb uses `postMessage` to relay child DOM events to the parent, which\n   * merges them into a single unified event stream.\n   */\n  crossOriginIframes?: CrossOriginIframesConfig;\n  /** Interval in ms at which the SDK takes a full DOM snapshot. Disabled by default — periodic snapshots are expensive. Recommended value: 300000 (5 min). */\n  fullSnapshotIntervalMs?: number;\n}\n\nexport interface SessionReplayJoinedConfig extends SessionReplayLocalConfig {\n  captureEnabled?: boolean;\n  interactionConfig?: InteractionConfig;\n  loggingConfig?: LoggingConfig;\n  targetingConfig?: TargetingConfig;\n  minSessionDurationMs?: number;\n}\n\nexport interface SessionReplayConfigs {\n  localConfig: SessionReplayLocalConfig;\n  joinedConfig: SessionReplayJoinedConfig;\n  remoteConfig: SessionReplayRemoteConfig | undefined;\n}\nexport interface SessionReplayJoinedConfigGenerator {\n  generateJoinedConfig: () => Promise<SessionReplayConfigs>;\n}\n\nexport interface SessionReplayMetadata {\n  remoteConfig: SessionReplayRemoteConfig | undefined;\n  localConfig: SessionReplayLocalConfig;\n  joinedConfig: SessionReplayJoinedConfig;\n  framework?: {\n    name: string;\n    version: string;\n  };\n  sessionId: string | number | undefined;\n  hashValue?: number;\n  sampleRate: number;\n  replaySDKType: string | null;\n  replaySDKVersion: string | undefined;\n  standaloneSDKType: string;\n  standaloneSDKVersion: string | undefined;\n}\n\nexport interface SessionReplayVersion {\n  version: string;\n  type: SessionReplayType;\n}\n\n/**\n * Configuration options for session replay performance.\n */\nexport interface SessionReplayPerformanceConfig {\n  /**\n   * If enabled, event compression will be deferred to occur during the browser's idle periods.\n   */\n  enabled: boolean;\n  /**\n   * Optional timeout in milliseconds for the `requestIdleCallback` API.\n   * If specified, this value will be used to set a maximum time for the browser to wait\n   * before executing the deferred compression task, even if the browser is not idle.\n   */\n  timeout?: number;\n  /**\n   * If enabled, consecutive mutation events will be merged into a single event before\n   * compression, reducing stored event count without changing replay semantics.\n   * Defaults to false.\n   */\n  mergeMutations?: boolean;\n  /**\n   * Performance configuration for interaction tracking (clicks, scrolls).\n   */\n  interaction?: InteractionPerformanceConfig;\n}\n\n/**\n * Performance configuration for interaction tracking, specifically for CSS selector generation.\n */\nexport interface InteractionPerformanceConfig {\n  /**\n   * Maximum time in milliseconds allowed for CSS selector generation.\n   * If selector generation takes longer than this, it will throw a timeout error.\n   * Default: undefined (no timeout limit)\n   */\n  timeoutMs?: number;\n  /**\n   * Maximum number of attempts to optimize/simplify the CSS selector path.\n   * Higher values may produce shorter selectors but take longer to compute.\n   * Default: 10000\n   */\n  maxNumberOfTries?: number;\n  /**\n   * Maximum number of CSS selector combinations to test for uniqueness.\n   * If more combinations would be generated, falls back to a simpler strategy.\n   * Default: 1000\n   */\n  threshold?: number;\n}\n\nexport type SessionReplayType = 'standalone' | 'plugin' | 'segment';\n"
  },
  {
    "path": "packages/session-replay-browser/src/constants.ts",
    "content": "import { AMPLITUDE_PREFIX, ServerZone } from '@amplitude/analytics-core';\n\nexport const DEFAULT_EVENT_PROPERTY_PREFIX = '[Amplitude]';\n\nexport const DEFAULT_SESSION_REPLAY_PROPERTY = `${DEFAULT_EVENT_PROPERTY_PREFIX} Session Replay ID`;\nexport const DEFAULT_SESSION_START_EVENT = 'session_start';\nexport const DEFAULT_SESSION_END_EVENT = 'session_end';\nexport const DEFAULT_SAMPLE_RATE = 0;\nexport const DEFAULT_SERVER_ZONE = ServerZone.US;\nexport const DEFAULT_PERFORMANCE_CONFIG = { enabled: true };\nexport const DEFAULT_URL_CHANGE_POLLING_INTERVAL = 1000;\n\nexport const SESSION_REPLAY_DEBUG_PROPERTY = `${DEFAULT_EVENT_PROPERTY_PREFIX} Session Replay Debug`;\n\nexport const BLOCK_CLASS = 'amp-block';\nexport const MASK_TEXT_CLASS = 'amp-mask';\nexport const UNMASK_TEXT_CLASS = 'amp-unmask';\nexport const SESSION_REPLAY_SERVER_URL = 'https://api-sr.amplitude.com/sessions/v2/track';\nexport const SESSION_REPLAY_EU_URL = 'https://api-sr.eu.amplitude.com/sessions/v2/track';\nexport const SESSION_REPLAY_STAGING_URL = 'https://api-sr.stag2.amplitude.com/sessions/v2/track';\nexport const STORAGE_PREFIX = `${AMPLITUDE_PREFIX}_replay_unsent`;\n// Reduced from 1,000,000 to leave headroom for double-JSON-encoding overhead and the\n// uncompressed fallback path. The HTTP body is ~10-30% larger than raw string length\n// because events are re-serialized inside the { version, events } wrapper at send time.\nexport const MAX_EVENT_LIST_SIZE = 700_000;\n// 9 MB UTF-8 bytes — just under the server's 10 MB per-event threshold. Compared against the\n// UTF-8 byte length of the serialized event (via Blob/TextEncoder), not the JS string length,\n// so multi-byte payloads (CJK, emoji) are gated correctly.\nexport const MAX_SINGLE_EVENT_SIZE = 9 * 1000000;\n// WAF rejects oversized compressed payloads with a body containing wording like\n// \"Payload exceeds the maximum allowed size of 10MB\". Match loosely so vendor wording\n// tweaks (rule updates, capitalization, etc.) don't silently disable bisect-retry.\nexport const WAF_PAYLOAD_TOO_LARGE_PATTERN = /payload.*exceed/i;\nexport const INTERACTION_MIN_INTERVAL = 30_000; // 30 seconds\nexport const INTERACTION_MAX_INTERVAL = 60_000; // 1 minute\nexport const MIN_INTERVAL = 500; // 500 ms\nexport const MAX_INTERVAL = 10 * 1000; // 10 seconds\nexport const MAX_IDB_STORAGE_LENGTH = 1000 * 60 * 60 * 24 * 3; // 3 days\nexport const KB_SIZE = 1024;\nexport const MAX_URL_LENGTH = 1000;\nexport const RETRY_TIMEOUT_MS = 1000;\nexport const MAX_KEEPALIVE_BYTES = 64 * 1024; // browser keepalive budget shared with sendBeacon\n\n// Server returns 200 + this header for \"no-retry\" drops (throttle / capture disabled / out-of-range).\n// See projects/sessionreplay/sessionreplay-ingestion/.../SessionReplayError.java.\n// Header value is the numeric error code as a string.\nexport const EVENT_SKIPPED_HEADER = 'X-Session-Replay-Event-Skipped';\nexport const EVENT_SKIP_CODE_THROTTLED = '429';\nexport const EVENT_SKIP_CODE_INVALID_RANGE = '4004';\nexport const EVENT_SKIP_CODE_CAPTURE_DISABLED = '4005';\n// How long to pause the flush schedule after the server signals a throttle.\nexport const THROTTLED_FLUSH_PAUSE_MS = 60_000;\n\nexport const CROSS_ORIGIN_IFRAME_MESSAGE_TYPE = 'amplitude-sr-iframe';\n\nexport enum CustomRRwebEvent {\n  GET_SR_PROPS = 'get-sr-props',\n  DEBUG_INFO = 'debug-info',\n  FETCH_REQUEST = 'fetch-request',\n  METADATA = 'metadata',\n  TARGETING_DECISION = 'targeting-decision',\n  /**\n   * Emitted once per session, on the first send that passes the min_session_duration_ms\n   * gate. Captures how many sends were suppressed before passing and the elapsed time\n   * spent below the threshold. Lets backend ingestion diff intended replay count vs\n   * actual ingestion so on-call can spot start-time-tracking regressions.\n   *\n   * Sessions that bounce before crossing the threshold never emit this event by design\n   * (the whole payload is suppressed); their absence is the signal.\n   */\n  REPLAY_GATE_DECISION = 'replay-gate-decision',\n}\n"
  },
  {
    "path": "packages/session-replay-browser/src/cross-origin-iframes.ts",
    "content": "import { getGlobalScope } from '@amplitude/analytics-core';\nimport { CROSS_ORIGIN_IFRAME_MESSAGE_TYPE } from './constants';\n\nexport function isInIframe(): boolean {\n  try {\n    const globalScope = getGlobalScope() as Window | undefined;\n    if (!globalScope) {\n      return false;\n    }\n    return globalScope.parent !== globalScope;\n  } catch {\n    // SecurityError accessing window.parent in some sandboxed environments\n    return true;\n  }\n}\n\ntype IframeMessage = { type: typeof CROSS_ORIGIN_IFRAME_MESSAGE_TYPE; action: 'start' | 'stop' };\n\n/**\n * Manages the parent side of cross-origin iframe recording coordination.\n *\n * When the parent starts recording, it sends a start signal to all current child\n * iframes and watches for dynamically added iframes via MutationObserver. When the\n * parent stops, it sends a stop signal.\n */\nexport class CrossOriginIframeCoordinator {\n  private mutationObserver: MutationObserver | undefined;\n  // Tracks pending load listeners for dynamically added iframes so stop() can cancel them.\n  private pendingLoadListeners = new Map<HTMLIFrameElement, () => void>();\n\n  start() {\n    this.mutationObserver?.disconnect(); // guard against double-start\n    const globalScope = getGlobalScope();\n    if (!globalScope) {\n      return;\n    }\n    this.sendToAllIframes({ type: CROSS_ORIGIN_IFRAME_MESSAGE_TYPE, action: 'start' });\n    this.mutationObserver = new MutationObserver((mutations) => {\n      for (const mutation of mutations) {\n        for (const node of Array.from(mutation.addedNodes)) {\n          if (node instanceof HTMLIFrameElement) {\n            // Send the start signal after the child page has loaded, not at insertion\n            // time. At insertion the contentWindow is still about:blank; the message\n            // sent there is discarded when the iframe navigates to its src, and the\n            // child SDK never receives it.\n            this.sendToIframeAfterLoad(node);\n          } else if (node instanceof Element) {\n            // A container element (e.g. a React-rendered div) may already have\n            // iframe descendants when it is inserted. These iframes do NOT appear\n            // in addedNodes — only the container does. Query the subtree so we\n            // don't miss them.\n            node.querySelectorAll<HTMLIFrameElement>('iframe').forEach((iframe) => {\n              this.sendToIframeAfterLoad(iframe);\n            });\n          }\n        }\n        for (const node of Array.from(mutation.removedNodes)) {\n          if (node instanceof HTMLIFrameElement) {\n            const listener = this.pendingLoadListeners.get(node);\n            if (listener) {\n              node.removeEventListener('load', listener);\n              this.pendingLoadListeners.delete(node);\n            }\n          }\n        }\n      }\n    });\n    this.mutationObserver.observe(document.documentElement, { childList: true, subtree: true });\n  }\n\n  stop() {\n    this.mutationObserver?.disconnect();\n    this.mutationObserver = undefined;\n    // Cancel any start signals that were waiting for a pending iframe load.\n    this.pendingLoadListeners.forEach((listener, iframe) => {\n      iframe.removeEventListener('load', listener);\n    });\n    this.pendingLoadListeners.clear();\n    this.sendToAllIframes({ type: CROSS_ORIGIN_IFRAME_MESSAGE_TYPE, action: 'stop' });\n  }\n\n  private sendToIframeAfterLoad(iframe: HTMLIFrameElement) {\n    const sendStart = () => {\n      this.pendingLoadListeners.delete(iframe);\n      this.sendToIframe(iframe, { type: CROSS_ORIGIN_IFRAME_MESSAGE_TYPE, action: 'start' });\n    };\n    this.pendingLoadListeners.set(iframe, sendStart);\n    iframe.addEventListener('load', sendStart, { once: true });\n  }\n\n  private sendToAllIframes(message: IframeMessage) {\n    const iframes = document.querySelectorAll<HTMLIFrameElement>('iframe');\n    iframes.forEach((iframe) => this.sendToIframe(iframe, message));\n  }\n\n  private sendToIframe(iframe: HTMLIFrameElement, message: IframeMessage) {\n    try {\n      iframe.contentWindow?.postMessage(message, '*');\n    } catch {\n      // Cross-origin postMessage can throw in some sandboxed environments; ignore.\n    }\n  }\n}\n\n/**\n * Listens for start/stop signals from the parent page and invokes the provided\n * callbacks. Only messages from `window.parent` are accepted.\n *\n * Returns a cleanup function that removes the message listener.\n */\nexport function listenForParentSignals(callbacks: { onStart: () => void; onStop: () => void }): () => void {\n  const globalScope = getGlobalScope() as Window | undefined;\n  if (!globalScope) {\n    return () => undefined;\n  }\n\n  const parentFrame = globalScope.parent;\n\n  function handler(event: MessageEvent) {\n    // Only accept messages from the direct parent frame.\n    if (event.source !== parentFrame) {\n      return;\n    }\n    const data = event.data as Partial<IframeMessage>;\n    if (data?.type !== CROSS_ORIGIN_IFRAME_MESSAGE_TYPE) {\n      return;\n    }\n    if (data.action === 'start') {\n      callbacks.onStart();\n    } else if (data.action === 'stop') {\n      callbacks.onStop();\n    }\n  }\n\n  globalScope.addEventListener('message', handler);\n  return () => globalScope.removeEventListener('message', handler);\n}\n"
  },
  {
    "path": "packages/session-replay-browser/src/events/base-events-store.ts",
    "content": "import { ILogger } from '@amplitude/analytics-core';\nimport { MAX_EVENT_LIST_SIZE, MAX_INTERVAL, MIN_INTERVAL } from '../constants';\nimport { Events, EventsStore, SendingSequencesReturn } from '../typings/session-replay';\n\nexport type InstanceArgs = {\n  loggerProvider: ILogger;\n  minInterval?: number;\n  maxInterval?: number;\n  maxPersistedEventsSize?: number;\n};\n\nexport abstract class BaseEventsStore<KeyType> implements EventsStore<KeyType> {\n  protected readonly loggerProvider: ILogger;\n  private minInterval = MIN_INTERVAL;\n  private maxInterval = MAX_INTERVAL;\n  private maxPersistedEventsSize = MAX_EVENT_LIST_SIZE;\n  private interval = this.minInterval;\n  private _timeAtLastSplit = Date.now(); // Initialize this so we have a point of comparison when events are recorded\n\n  public get timeAtLastSplit() {\n    return this._timeAtLastSplit;\n  }\n\n  constructor(args: InstanceArgs) {\n    this.loggerProvider = args.loggerProvider;\n    this.minInterval = args.minInterval ?? this.minInterval;\n    this.maxInterval = args.maxInterval ?? this.maxInterval;\n    this.maxPersistedEventsSize = args.maxPersistedEventsSize ?? this.maxPersistedEventsSize;\n  }\n\n  abstract addEventToCurrentSequence(\n    sessionId: string | number,\n    event: string,\n  ): Promise<SendingSequencesReturn<KeyType> | undefined>;\n  abstract getSequencesToSend(): Promise<SendingSequencesReturn<KeyType>[] | undefined>;\n  abstract storeCurrentSequence(sessionId: number): Promise<SendingSequencesReturn<KeyType> | undefined>;\n  abstract storeSendingEvents(sessionId: string | number, events: Events): Promise<KeyType | undefined>;\n  abstract cleanUpSessionEventsStore(sessionId: number, sequenceId: KeyType): Promise<void>;\n\n  /**\n   * Returns the UTF-8 byte size of a string without buffer allocation, matching the\n   * actual wire byte count for non-ASCII content (Base64 image data, emoji, etc.).\n   */\n  private getStringSize(str: string): number {\n    let bytes = 0;\n    for (let i = 0; i < str.length; i++) {\n      const code = str.charCodeAt(i);\n      if (code <= 0x7f) {\n        bytes++;\n      } else if (code <= 0x7ff) {\n        bytes += 2;\n      } else if (code >= 0xd800 && code <= 0xdbff) {\n        // High surrogate — check for a valid low surrogate before consuming the pair.\n        const next = i + 1 < str.length ? str.charCodeAt(i + 1) : NaN;\n        if (next >= 0xdc00 && next <= 0xdfff) {\n          // Valid surrogate pair → encodes a code point above U+FFFF (4 UTF-8 bytes).\n          bytes += 4;\n          i++;\n        } else {\n          // Orphaned high surrogate — treated as a replacement character (3 UTF-8 bytes).\n          bytes += 3;\n        }\n      } else if (code >= 0xdc00 && code <= 0xdfff) {\n        // Orphaned low surrogate — treated as a replacement character (3 UTF-8 bytes).\n        bytes += 3;\n      } else {\n        // Other BMP character (U+0800–U+FFFF, excluding surrogates): 3 UTF-8 bytes.\n        bytes += 3;\n      }\n    }\n    return bytes;\n  }\n\n  /**\n   * Calculates the total UTF-8 byte size of events array\n   * Accounts for JSON serialization overhead when sent to backend\n   */\n  private getEventsArraySize(events: Events): number {\n    let totalSize = 0;\n    for (const event of events) {\n      totalSize += this.getStringSize(event);\n    }\n\n    // Approximate overhead from the array portion of the JSON payload:\n    // - Array brackets: [] = 2 bytes\n    // - Commas between events: events.length - 1 bytes\n    // - Double quotes wrapping each event string: events.length * 2 bytes\n    // Note: does not include the outer { version, events } wrapper (~22 bytes) or\n    // per-event JSON-escaping of \" and \\ characters; the reduced MAX_EVENT_LIST_SIZE\n    // cap (700 KB vs 1 MB) provides headroom for those.\n    const overhead = 2 + Math.max(0, events.length - 1) + events.length * 2;\n\n    return totalSize + overhead;\n  }\n\n  /**\n   * Determines whether to send the events list to the backend and start a new\n   * empty events list, based on the size of the list as well as the last time sent\n   * @param nextEventString\n   * @returns boolean\n   */\n  shouldSplitEventsList = (events: Events, nextEventString: string): boolean => {\n    const sizeOfNextEvent = this.getStringSize(nextEventString);\n    const sizeOfEventsList = this.getEventsArraySize(events);\n\n    // Check size constraint first (most likely to trigger)\n    if (sizeOfEventsList + sizeOfNextEvent >= this.maxPersistedEventsSize) {\n      return true;\n    }\n    if (Date.now() - this.timeAtLastSplit > this.interval && events.length) {\n      this.interval = Math.min(this.maxInterval, this.interval + this.minInterval);\n      this._timeAtLastSplit = Date.now();\n      return true;\n    }\n    return false;\n  };\n}\n"
  },
  {
    "path": "packages/session-replay-browser/src/events/event-compressor.ts",
    "content": "import { getGlobalScope } from '@amplitude/analytics-core';\nimport { EventType as RRWebEventType } from '@amplitude/rrweb-types';\nimport type { eventWithTime } from '@amplitude/rrweb-types';\nimport { SessionReplayJoinedConfig } from '../config/types';\nimport { MAX_SINGLE_EVENT_SIZE } from '../constants';\nimport { SessionReplayEventsManager } from '../typings/session-replay';\nimport { mergeMutationEvents } from './merge-mutation-events';\n\ninterface TaskQueue {\n  event: eventWithTime;\n  sessionId: string | number;\n}\n\nconst DEFAULT_TIMEOUT = 2000;\nexport class EventCompressor {\n  taskQueue: TaskQueue[] = [];\n  pendingQueue: TaskQueue[] = [];\n  isProcessing = false;\n  eventsManager?: SessionReplayEventsManager<'replay' | 'interaction', string>;\n  config: SessionReplayJoinedConfig;\n  deviceId: string | undefined;\n  canUseIdleCallback: boolean | undefined;\n  timeout: number;\n  worker?: Worker;\n  onFullSnapshotProcessed?: () => void;\n\n  constructor(\n    eventsManager: SessionReplayEventsManager<'replay' | 'interaction', string>,\n    config: SessionReplayJoinedConfig,\n    deviceId: string | undefined,\n    workerScript?: string,\n    onFullSnapshotProcessed?: () => void,\n  ) {\n    const globalScope = getGlobalScope();\n    this.canUseIdleCallback = globalScope && 'requestIdleCallback' in globalScope;\n    this.eventsManager = eventsManager;\n    this.config = config;\n    this.deviceId = deviceId;\n    this.timeout = config.performanceConfig?.timeout || DEFAULT_TIMEOUT;\n    this.onFullSnapshotProcessed = onFullSnapshotProcessed;\n\n    if (workerScript) {\n      config.loggerProvider.log('Enabling web worker for compression');\n\n      try {\n        const blob = new Blob([workerScript], { type: 'application/javascript' });\n        const blobUrl = URL.createObjectURL(blob);\n        const worker = new Worker(blobUrl);\n\n        worker.onerror = (e) => {\n          e.preventDefault();\n          config.loggerProvider.error(\n            `Worker failed, falling back to non-worker compression: ${e.message} (${e.filename}:${e.lineno})`,\n          );\n          worker.terminate();\n          this.worker = undefined;\n        };\n        worker.onmessage = (e) => {\n          const { compressedEvent, sessionId } = e.data as Record<string, string>;\n          this.addCompressedEventToManager(compressedEvent, sessionId);\n        };\n\n        this.worker = worker;\n      } catch (error) {\n        config.loggerProvider.error('Failed to create worker, falling back to non-worker compression:', error);\n      }\n    }\n  }\n\n  // Schedule processing during idle time\n  public scheduleIdleProcessing(): void {\n    if (!this.isProcessing) {\n      this.isProcessing = true;\n      requestIdleCallback(\n        (idleDeadline) => {\n          this.processQueue(idleDeadline);\n        },\n        { timeout: this.timeout },\n      );\n    }\n  }\n\n  // Add an event to the task queue if idle callback is supported or compress the event directly\n  public enqueueEvent(event: eventWithTime, sessionId: string | number): void {\n    // Full snapshot (type 2) is the most critical event — a replay cannot be played without it.\n    // Process and flush immediately rather than waiting for the idle scheduler or web worker,\n    // maximising the chance it is delivered before the user exits the page.\n    if (event.type === RRWebEventType.FullSnapshot) {\n      this.config.loggerProvider.debug('Processing full snapshot immediately.');\n      // Drain any events still pending in the idle-callback queue first.\n      // Those events reference the pre-snapshot DOM and must be sent before\n      // the full snapshot; if we let them be processed later they'd arrive at\n      // the server after the snapshot and cause \"node not found\" replay errors.\n      if (this.taskQueue.length > 0 || this.pendingQueue.length > 0) {\n        const allTasks = [...this.taskQueue.splice(0), ...this.mergeMutationTasks(this.pendingQueue.splice(0))];\n        for (const task of allTasks) {\n          const compressed = this.compressEvent(task.event);\n          this.addCompressedEventToManager(compressed, task.sessionId);\n        }\n        this.isProcessing = false;\n      }\n      const compressedEvent = this.compressEvent(event);\n      this.addCompressedEventToManager(compressedEvent, sessionId);\n      this.onFullSnapshotProcessed?.();\n      return;\n    }\n\n    if (this.canUseIdleCallback && this.config.performanceConfig?.enabled) {\n      this.config.loggerProvider.debug('Enqueuing event for processing during idle time.');\n      this.pendingQueue.push({ event, sessionId });\n      this.scheduleIdleProcessing();\n    } else {\n      this.config.loggerProvider.debug('Processing event without idle callback.');\n      this.addCompressedEvent(event, sessionId);\n    }\n  }\n\n  // Process the task queue during idle time\n  public processQueue(idleDeadline: IdleDeadline): void {\n    // Merge newly-arrived pending events and append to the already-merged taskQueue.\n    // Keeping them separate prevents re-merging already-merged tasks on subsequent calls,\n    // which would corrupt move semantics for nodes that appear in multiple merge passes.\n    if (this.pendingQueue.length > 0) {\n      this.taskQueue.push(...this.mergeMutationTasks(this.pendingQueue.splice(0)));\n    }\n    // Process tasks while there's idle time or until the max number of tasks is reached\n    while (this.taskQueue.length > 0 && (idleDeadline.timeRemaining() > 0 || idleDeadline.didTimeout)) {\n      const task = this.taskQueue.shift();\n      if (task) {\n        const { event, sessionId } = task;\n        this.addCompressedEvent(event, sessionId);\n      }\n    }\n\n    // If there are still tasks in the queue, schedule the next idle callback\n    if (this.taskQueue.length > 0 || this.pendingQueue.length > 0) {\n      requestIdleCallback(\n        (idleDeadline) => {\n          this.processQueue(idleDeadline);\n        },\n        { timeout: this.timeout },\n      );\n    } else {\n      this.isProcessing = false;\n    }\n  }\n\n  compressEvent = (event: eventWithTime): string => {\n    // Serialize with type+timestamp first for streaming parser compatibility.\n    // JS engines serialize non-integer string keys in insertion order (ES2015 spec,\n    // reliable across V8/SpiderMonkey/JSC), so explicit construction controls key order.\n    // `delay` is an rrweb player field: an optional ms offset applied on top of\n    // `timestamp` during replay to smooth out batched/throttled events. Preserve\n    // it when present so playback timing is accurate.\n    const { type, timestamp, delay, data } = event as eventWithTime & { delay?: number };\n    return delay != null ? JSON.stringify({ type, timestamp, delay, data }) : JSON.stringify({ type, timestamp, data });\n  };\n\n  private addCompressedEventToManager = (compressedEvent: string, sessionId: string | number) => {\n    // UTF-8 byte size, not JS char count: a 9 M-char string of CJK/emoji can be 18–27 MB\n    // on the wire and would otherwise slip past a char-count guard.\n    const eventSizeBytes = new Blob([compressedEvent]).size;\n    if (eventSizeBytes > MAX_SINGLE_EVENT_SIZE) {\n      this.config.loggerProvider.warn(\n        `Session replay event dropped: serialized size ${Math.round(\n          eventSizeBytes / 1024,\n        )} KB exceeds maximum allowed event size. If this recurs, please open a GitHub issue at https://github.com/amplitude/Amplitude-TypeScript/issues or contact Amplitude support.`,\n      );\n      return;\n    }\n    if (this.eventsManager && this.deviceId) {\n      this.eventsManager.addEvent({\n        event: { type: 'replay', data: compressedEvent },\n        sessionId,\n        deviceId: this.deviceId,\n      });\n    }\n  };\n\n  public addCompressedEvent = (event: eventWithTime, sessionId: string | number) => {\n    if (this.worker) {\n      // This indirectly compresses the event.\n      try {\n        this.worker.postMessage({ event, sessionId });\n      } catch (err: any) {\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n        if (err.name === 'DataCloneError') {\n          // fallback: serialize\n          this.worker.postMessage(JSON.stringify({ event, sessionId }));\n        } else {\n          this.config.loggerProvider.warn('Unexpected error while posting message to worker:', err);\n        }\n      }\n    } else {\n      const compressedEvent = this.compressEvent(event);\n      this.addCompressedEventToManager(compressedEvent, sessionId);\n    }\n  };\n\n  /**\n   * Synchronously drain all queued events. Called during page unload to prevent\n   * data loss from events waiting in the requestIdleCallback queue.\n   */\n  public flushQueue = () => {\n    // Merge any events still in pendingQueue into taskQueue first.\n    // Events land in pendingQueue when the idle callback hasn't fired yet;\n    // without this step they would be silently lost on page unload.\n    if (this.pendingQueue.length > 0) {\n      this.taskQueue.push(...this.mergeMutationTasks(this.pendingQueue.splice(0)));\n    }\n    while (this.taskQueue.length > 0) {\n      const task = this.taskQueue.shift();\n      if (task) {\n        const { event, sessionId } = task;\n        // Bypass the web worker: compress synchronously on the main thread and\n        // write directly to the manager. postMessage is async — during page\n        // unload the worker response would never arrive and events would be\n        // silently dropped. This mirrors the pattern used for full snapshots in\n        // enqueueEvent().\n        const compressed = this.compressEvent(event);\n        this.addCompressedEventToManager(compressed, sessionId);\n      }\n    }\n    this.isProcessing = false;\n  };\n\n  // Merge consecutive mutation tasks with the same sessionId before processing,\n  // reducing the number of events serialized and stored without changing replay semantics.\n  // Only runs when performanceConfig.mergeMutations is explicitly enabled.\n  private mergeMutationTasks(tasks: TaskQueue[]): TaskQueue[] {\n    if (!this.config.performanceConfig?.mergeMutations) return tasks;\n    if (tasks.length <= 1) return tasks;\n\n    const result: TaskQueue[] = [];\n    let i = 0;\n\n    while (i < tasks.length) {\n      const sessionId = tasks[i].sessionId;\n\n      // Find the end of the current session run\n      let j = i + 1;\n      while (j < tasks.length && tasks[j].sessionId === sessionId) {\n        j++;\n      }\n\n      // Merge consecutive mutations within this session run; non-mutations pass through unchanged\n      const merged = mergeMutationEvents(tasks.slice(i, j).map((t) => t.event));\n      for (const event of merged) {\n        result.push({ event, sessionId });\n      }\n\n      i = j;\n    }\n\n    return result;\n  }\n\n  public terminate = () => {\n    this.worker?.terminate();\n  };\n}\n"
  },
  {
    "path": "packages/session-replay-browser/src/events/events-idb-store.ts",
    "content": "import { DBSchema, IDBPDatabase, openDB } from 'idb';\nimport { STORAGE_FAILURE } from '../messages';\nimport { EventType, Events, SendingSequencesReturn } from '../typings/session-replay';\nimport { BaseEventsStore, InstanceArgs as BaseInstanceArgs } from './base-events-store';\nimport { logIdbError } from '../utils/is-abort-error';\n\n// crypto.randomUUID() requires a secure context (https). Fall back to a\n// Math.random-based UUID for http origins or older browsers — tab IDs don't\n// need to be cryptographically secure, just unique within a session.\nexport function generateUUID(): string {\n  try {\n    return crypto.randomUUID();\n  } catch {\n    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n      const r = (Math.random() * 16) | 0;\n      return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16);\n    });\n  }\n}\n\nexport const currentSequenceKey = 'sessionCurrentSequence';\nexport const sequencesToSendKey = 'sequencesToSend';\nexport const remoteConfigKey = 'remoteConfig';\n\n// Timeout for openDB at init.  IDB openDB can hang forever when another tab\n// holds an open connection during a version upgrade, or when the DB is in a\n// \"closing\" state (documented Chrome behaviour).  When that happens we want\n// SessionReplayEventsIDBStore.new() to bail out so the caller can fall back\n// to the in-memory store.\nexport const OPEN_DB_TIMEOUT_MS = 2000;\n\n// Timeout for per-operation tx.done settlement.  Mid-recording a readwrite\n// transaction can stall (storage pressure in some browsers stalls instead of\n// throwing); without a timeout, recordFailure() is never called and the\n// memory fallback never triggers.  The transaction may still settle later;\n// the timedOut flag prevents double-counting alongside errorLogged.\nexport const TX_DONE_TIMEOUT_MS = 5000;\n\n/**\n * Race a promise against a timeout.  Resolves/rejects with the original\n * promise's value when it settles first; rejects with a timeout error if\n * `ms` elapses first.  Either way the timer is cleared so we don't leak\n * pending setTimeouts.\n */\nexport function withTimeout<T>(promise: Promise<T>, ms: number, message = 'IDB operation timed out'): Promise<T> {\n  return new Promise<T>((resolve, reject) => {\n    const timer = setTimeout(() => reject(new Error(`${message} after ${ms}ms`)), ms);\n    promise.then(\n      (v) => {\n        clearTimeout(timer);\n        resolve(v);\n      },\n      (e) => {\n        clearTimeout(timer);\n        reject(e);\n      },\n    );\n  });\n}\n\n/**\n * Arms a watchdog that fires `onTimeout` only if `tx.done` hasn't settled\n * within `ms`.  A \"soft cancel\" returned to the caller suppresses the timeout\n * if the synchronous operation body completes without exception — important\n * because in test environments fake timers can fire ahead of tx.done's commit\n * microtask.  Production behaviour is preserved: a genuinely stalled\n * transaction (no commit, no error, individual op promises never resolved)\n * cannot reach the soft-cancel call and the timeout fires as designed.\n *\n * Soft-cancel is only invoked once the awaits inside the operation's outer\n * try block have all returned — i.e. the IDB driver acknowledged each\n * individual put/get.  If the driver accepts a put but the underlying\n * transaction silently fails to commit (the production stall scenario),\n * tx.done still hasn't settled, and recordFailure must NOT have been\n * suppressed.  The fix for that scenario in production is the tx.done.catch\n * handler attached separately by callers, which catches the eventual abort.\n *\n * The soft-cancel pattern only suppresses the timeout for the \"all puts\n * resolved successfully\" case — a case where tx.done is overwhelmingly\n * likely to settle imminently in production.  If it doesn't, callers can\n * still detect the failure on the NEXT operation (which will fail to open\n * a transaction or hit the same pressure), because all three methods use\n * readwrite transactions on the same two stores, which IDB serializes:\n * if T1's tx.done never settles, T2 is blocked waiting for T1 to commit or\n * abort — T2's put/get requests never resolve, T2 never reaches its\n * soft-cancel, and T2's watchdog fires, calling recordFailure().\n */\nfunction armTxDoneTimeout(txDone: Promise<unknown>, ms: number, onTimeout: () => void): () => void {\n  const timer = setTimeout(onTimeout, ms);\n  // Belt-and-braces: clear the timer when tx.done settles, even though the\n  // primary cancel path is the caller's success-path cancel().  This covers\n  // the case where tx.done settles with no caller cancellation (shouldn't\n  // happen in current code paths, but cheap insurance).\n  txDone.then(\n    () => clearTimeout(timer),\n    () => clearTimeout(timer),\n  );\n  return () => clearTimeout(timer);\n}\n\nexport interface SessionReplayDB extends DBSchema {\n  sessionCurrentSequence: {\n    key: number;\n    value: Omit<SendingSequencesReturn<number>, 'sequenceId'> & { tabId?: string };\n  };\n  sequencesToSend: {\n    key: number;\n    value: Omit<SendingSequencesReturn<number>, 'sequenceId'> & { tabId?: string };\n    indexes: { sessionId: string | number };\n  };\n}\n\nexport const defineObjectStores = (db: IDBPDatabase<SessionReplayDB>) => {\n  let sequencesStore;\n  let currentSequenceStore;\n  if (!db.objectStoreNames.contains(currentSequenceKey)) {\n    currentSequenceStore = db.createObjectStore(currentSequenceKey, {\n      keyPath: 'sessionId',\n    });\n  }\n  if (!db.objectStoreNames.contains(sequencesToSendKey)) {\n    sequencesStore = db.createObjectStore(sequencesToSendKey, {\n      keyPath: 'sequenceId',\n      autoIncrement: true,\n    });\n    sequencesStore.createIndex('sessionId', 'sessionId');\n  }\n  return {\n    sequencesStore,\n    currentSequenceStore,\n  };\n};\n\nexport const createStore = async (dbName: string) => {\n  // Wrap openDB with a timeout so a hung connection (foreign tab holding an\n  // open handle during version upgrade, or \"closing\" DB) doesn't block the\n  // SDK from initialising.  On timeout this rejects, which propagates up to\n  // SessionReplayEventsIDBStore.new()'s catch block, returning undefined and\n  // triggering the memory fallback.\n  return await withTimeout(\n    openDB<SessionReplayDB>(dbName, 1, {\n      upgrade: defineObjectStores,\n    }),\n    OPEN_DB_TIMEOUT_MS,\n    'IDB openDB timed out',\n  );\n};\n\ntype InstanceArgs = {\n  apiKey: string;\n  db: IDBPDatabase<SessionReplayDB>;\n  tabId: string;\n  onPersistentFailure?: () => void;\n  consecutiveFailureThreshold?: number;\n} & BaseInstanceArgs;\n\nexport class SessionReplayEventsIDBStore extends BaseEventsStore<number> {\n  private readonly db: IDBPDatabase<SessionReplayDB>;\n  private readonly tabId: string;\n  private readonly onPersistentFailure?: () => void;\n  private readonly consecutiveFailureThreshold: number;\n  private consecutiveFailures = 0;\n  private hasTriggeredFallback = false;\n\n  constructor(args: InstanceArgs) {\n    super(args);\n    this.db = args.db;\n    this.tabId = args.tabId;\n    this.onPersistentFailure = args.onPersistentFailure;\n    // Default threshold of 1: fall back to memory immediately on the first IDB failure.\n    // Session replay correctness is far more important than persistence, and IDB errors\n    // are typically the symptom of a deeper problem (storage pressure, locked DB, broken\n    // browser implementation) that won't recover within a single session.  Memory store\n    // is always safe — fall back early.\n    this.consecutiveFailureThreshold = args.consecutiveFailureThreshold ?? 1;\n  }\n\n  private recordFailure() {\n    this.consecutiveFailures++;\n    if (!this.hasTriggeredFallback && this.consecutiveFailures >= this.consecutiveFailureThreshold) {\n      this.hasTriggeredFallback = true;\n      this.onPersistentFailure?.();\n    }\n  }\n\n  private recordSuccess() {\n    this.consecutiveFailures = 0;\n  }\n\n  static async new(\n    type: EventType,\n    args: Omit<InstanceArgs, 'db' | 'tabId'> & { tabId?: string },\n  ): Promise<SessionReplayEventsIDBStore | undefined> {\n    try {\n      const dbSuffix = type === 'replay' ? '' : `_${type}`;\n      const dbName = `${args.apiKey.substring(0, 10)}_amp_session_replay_events${dbSuffix}`;\n      const db = await createStore(dbName);\n      // Generate a fresh in-memory UUID per store instance.  sessionStorage is\n      // intentionally avoided: standalone session-replay customers (without the\n      // analytics-browser SDK) would be exposed to a new storage surface they\n      // did not consent to, and persistence across page reloads is not needed —\n      // completed sequences in sequencesToSend are flushed by any tab/instance.\n      const tabId = args.tabId ?? generateUUID();\n      return new SessionReplayEventsIDBStore({\n        ...args,\n        db,\n        tabId,\n      });\n    } catch (e) {\n      logIdbError(args.loggerProvider, `${STORAGE_FAILURE}: ${e as string}`, e);\n    }\n    return;\n  }\n\n  async getCurrentSequenceEvents(sessionId?: number) {\n    if (sessionId) {\n      const record = await this.db.get('sessionCurrentSequence', sessionId);\n      if (!record) {\n        return undefined;\n      }\n      // Only return our own tab's record (or legacy untagged records).\n      if (record.tabId && record.tabId !== this.tabId) {\n        return undefined;\n      }\n      const { tabId: _tabId, ...rest } = record;\n      return [rest];\n    }\n\n    const allEvents = [];\n    for (const record of await this.db.getAll('sessionCurrentSequence')) {\n      if (record.tabId && record.tabId !== this.tabId) {\n        continue;\n      }\n      const { tabId: _tabId, ...rest } = record;\n      allEvents.push(rest);\n    }\n\n    return allEvents;\n  }\n\n  getSequencesToSend = async (): Promise<SendingSequencesReturn<number>[] | undefined> => {\n    let errorLogged = false;\n    let timedOut = false;\n    try {\n      const sequences: SendingSequencesReturn<number>[] = [];\n      const tx = this.db.transaction('sequencesToSend');\n      // Attach a catch handler immediately so tx.done rejections (e.g. AbortError after\n      // cursor traversal completes) are always handled without blocking the return path.\n      // The errorLogged / timedOut flags prevent double-logging and double-recording\n      // when the outer catch (or the timeout race) already fired for the same abort.\n      tx.done.catch((e: unknown) => {\n        if (!errorLogged && !timedOut) {\n          logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: ${e as string}`, e);\n          this.recordFailure();\n        }\n      });\n      // Arm a watchdog so a stalled transaction (no error, no commit, e.g.\n      // storage pressure on some browsers) still trips the failure counter.\n      // The watchdog fires only when tx.done genuinely never settles AND the\n      // operation's success path didn't run; if tx.done rejects (abort), the\n      // tx.done.catch handler above is the sole recorder of failure.\n      const cancelTimeout = armTxDoneTimeout(tx.done, TX_DONE_TIMEOUT_MS, () => {\n        if (!errorLogged && !timedOut) {\n          timedOut = true;\n          logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: transaction timed out`);\n          this.recordFailure();\n        }\n      });\n      let cursor = await tx.store.openCursor();\n      while (cursor) {\n        const { sessionId, events } = cursor.value;\n        // Return all completed sequences regardless of tabId.  Filtering by tab\n        // would cause event loss on page reload: a new store instance gets a\n        // fresh in-memory UUID and would never see sequences written by the\n        // previous instance.  Completed sequences are safe to flush by any\n        // tab/instance; the server deduplicates, and cleanUpSessionEventsStore\n        // on an already-deleted key is a no-op.\n        sequences.push({\n          events,\n          sequenceId: cursor.key,\n          sessionId,\n        });\n        cursor = await cursor.continue();\n      }\n\n      this.recordSuccess();\n      cancelTimeout();\n      return sequences;\n    } catch (e) {\n      if (!timedOut) {\n        errorLogged = true;\n        logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: ${e as string}`, e);\n        this.recordFailure();\n      }\n    }\n    return undefined;\n  };\n\n  storeCurrentSequence = async (sessionId: number) => {\n    let errorLogged = false;\n    let timedOut = false;\n    try {\n      // Wrap the read of sessionCurrentSequence and the writes to sequencesToSend +\n      // sessionCurrentSequence in a single readwrite transaction so the three operations\n      // commit or roll back atomically.  Without this, a concurrent addEventToCurrentSequence\n      // call could interleave and either lose the events being promoted or duplicate them\n      // (storeCurrentSequence reads N events, addEvent appends an N+1th, storeCurrentSequence\n      // writes only the first N back to sequencesToSend, then resets the slot — losing N+1).\n      const tx = this.db.transaction([currentSequenceKey, sequencesToSendKey], 'readwrite');\n      tx.done.catch((e: unknown) => {\n        if (!errorLogged && !timedOut) {\n          logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: ${e as string}`, e);\n          this.recordFailure();\n        }\n      });\n      // Stalled-transaction protection: see armTxDoneTimeout in getSequencesToSend.\n      const cancelTimeout = armTxDoneTimeout(tx.done, TX_DONE_TIMEOUT_MS, () => {\n        if (!errorLogged && !timedOut) {\n          timedOut = true;\n          logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: transaction timed out`);\n          this.recordFailure();\n        }\n      });\n\n      const currentSequenceData = await tx.objectStore(currentSequenceKey).get(sessionId);\n      // Skip promotion if the slot is empty or owned by another tab — let the owning\n      // tab promote its own events on its next addEventToCurrentSequence/storeCurrentSequence\n      // call (via Bug 1's foreign-tab promotion path).\n      // Don't call recordSuccess() here: no write was performed, so this is not\n      // evidence the storage layer is healthy — leave the failure counter unchanged.\n      if (!currentSequenceData || (currentSequenceData.tabId && currentSequenceData.tabId !== this.tabId)) {\n        cancelTimeout();\n        return undefined;\n      }\n\n      // Skip empty sequences — no point writing a zero-event row to sequencesToSend.\n      if (currentSequenceData.events.length === 0) {\n        cancelTimeout();\n        return undefined;\n      }\n\n      const sequenceId = await tx.objectStore(sequencesToSendKey).put({\n        sessionId,\n        events: currentSequenceData.events,\n        tabId: this.tabId,\n      });\n\n      await tx.objectStore(currentSequenceKey).put({\n        sessionId,\n        events: [],\n        tabId: this.tabId,\n      });\n\n      this.recordSuccess();\n      cancelTimeout();\n      const { tabId: _tabId, ...rest } = currentSequenceData;\n      return {\n        ...rest,\n        sessionId,\n        sequenceId,\n      };\n    } catch (e) {\n      if (!timedOut) {\n        errorLogged = true;\n        logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: ${e as string}`, e);\n        this.recordFailure();\n      }\n    }\n    return undefined;\n  };\n\n  addEventToCurrentSequence = async (sessionId: number, event: string) => {\n    let errorLogged = false;\n    let timedOut = false;\n    try {\n      // Always open a readwrite transaction over both stores so that the read and\n      // any subsequent write are atomic.  IDB serializes readwrite transactions on\n      // overlapping stores, so concurrent fire-and-forget callers (events-manager\n      // does not await this method) are queued by the engine rather than interleaving\n      // — eliminating the TOCTOU race that a narrow-read + separate-write approach\n      // would introduce on the split path.\n      const tx = this.db.transaction([currentSequenceKey, sequencesToSendKey], 'readwrite');\n      // Attach a catch handler immediately so tx.done rejections (e.g. AbortError after\n      // put succeeds but before auto-commit) are always handled without blocking.\n      // The errorLogged / timedOut flags prevent double-logging when the outer catch\n      // (or the timeout) already fired for the same transaction.\n      tx.done.catch((e: unknown) => {\n        if (!errorLogged && !timedOut) {\n          logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: ${e as string}`, e);\n          this.recordFailure();\n        }\n      });\n      // Stalled-transaction protection: see armTxDoneTimeout in getSequencesToSend.\n      const cancelTimeout = armTxDoneTimeout(tx.done, TX_DONE_TIMEOUT_MS, () => {\n        if (!errorLogged && !timedOut) {\n          timedOut = true;\n          logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: transaction timed out`);\n          this.recordFailure();\n        }\n      });\n      const sequenceEvents = await tx.objectStore(currentSequenceKey).get(sessionId);\n\n      // Foreign-tab record path: another tab owns the current-sequence slot for this\n      // sessionId.  Don't silently overwrite — that would drop the foreign tab's\n      // in-progress events.  Promote them to sequencesToSend (tabId kept for forensics)\n      // before claiming the slot for ourselves.  getSequencesToSend no longer filters\n      // by tabId, so either tab may flush the promoted sequence; server deduplicates.\n      if (sequenceEvents?.tabId && sequenceEvents.tabId !== this.tabId) {\n        if (sequenceEvents.events.length > 0) {\n          await tx.objectStore(sequencesToSendKey).put({\n            sessionId,\n            events: sequenceEvents.events,\n            tabId: sequenceEvents.tabId,\n          });\n        }\n        await tx.objectStore(currentSequenceKey).put({ sessionId, events: [event], tabId: this.tabId });\n        this.recordSuccess();\n        cancelTimeout();\n        return undefined;\n      }\n\n      // ownedSequence is either undefined (no record yet) or this tab's record.\n      const ownedSequence = sequenceEvents;\n\n      if (!ownedSequence) {\n        await tx.objectStore(currentSequenceKey).put({ sessionId, events: [event], tabId: this.tabId });\n        this.recordSuccess();\n        cancelTimeout();\n        return undefined;\n      }\n\n      if (!this.shouldSplitEventsList(ownedSequence.events, event)) {\n        await tx\n          .objectStore(currentSequenceKey)\n          .put({ sessionId, events: ownedSequence.events.concat(event), tabId: this.tabId });\n        this.recordSuccess();\n        cancelTimeout();\n        return undefined;\n      }\n\n      // Split path: reset sessionCurrentSequence and write the old events to\n      // sequencesToSend atomically within the same transaction.\n      const eventsToSend = ownedSequence.events;\n      await tx.objectStore(currentSequenceKey).put({ sessionId, events: [event], tabId: this.tabId });\n      const sequenceId = await tx.objectStore(sequencesToSendKey).put({\n        sessionId,\n        events: eventsToSend,\n        tabId: this.tabId,\n      });\n\n      this.recordSuccess();\n      cancelTimeout();\n      return {\n        events: eventsToSend,\n        sessionId,\n        sequenceId,\n      };\n    } catch (e) {\n      if (!timedOut) {\n        errorLogged = true;\n        logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: ${e as string}`, e);\n        this.recordFailure();\n      }\n    }\n    return undefined;\n  };\n\n  storeSendingEvents = async (sessionId: number, events: Events) => {\n    try {\n      const sequenceId = await this.db.put<'sequencesToSend'>(sequencesToSendKey, {\n        sessionId: sessionId,\n        events: events,\n        tabId: this.tabId,\n      });\n      this.recordSuccess();\n      return sequenceId;\n    } catch (e) {\n      logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: ${e as string}`, e);\n      this.recordFailure();\n    }\n    return undefined;\n  };\n\n  cleanUpSessionEventsStore = async (_sessionId: number, sequenceId?: number) => {\n    if (!sequenceId) {\n      return;\n    }\n    try {\n      await this.db.delete<'sequencesToSend'>(sequencesToSendKey, sequenceId);\n      this.recordSuccess();\n    } catch (e) {\n      logIdbError(this.loggerProvider, `${STORAGE_FAILURE}: ${e as string}`, e);\n      this.recordFailure();\n    }\n  };\n}\n"
  },
  {
    "path": "packages/session-replay-browser/src/events/events-manager.ts",
    "content": "import {\n  SessionReplayEventsManager as AmplitudeSessionReplayEventsManager,\n  EventsStore,\n  EventType,\n  StoreType,\n} from '../typings/session-replay';\n\nimport { SessionReplayJoinedConfig } from '../config/types';\nimport { MAX_SINGLE_EVENT_SIZE } from '../constants';\nimport { getStorageSize } from '../helpers';\nimport { PayloadBatcher, SessionReplayTrackDestination } from '../track-destination';\nimport { SessionReplayEventsIDBStore } from './events-idb-store';\nimport { InMemoryEventsStore } from './events-memory-store';\n\nexport type EventsManagerWithBeacon<Type extends EventType> = AmplitudeSessionReplayEventsManager<Type, string> & {\n  /**\n   * Returns current pending events (since last flush) for synchronous access on page exit.\n   * Used to populate a sendBeacon payload when the page is unloading.\n   */\n  getBeaconEvents(): string[];\n  /**\n   * Drops all pending beacon events. Used when the session is decided to be below\n   * the min duration threshold so its events don't leak into a later session's beacon.\n   */\n  dropPendingBeaconEvents(): void;\n  trackDestination: SessionReplayTrackDestination;\n};\n\nexport const createEventsManager = async <Type extends EventType>({\n  config,\n  minInterval,\n  maxInterval,\n  type,\n  payloadBatcher,\n  storeType,\n  trackDestinationWorkerScript,\n  shouldSend,\n}: {\n  config: SessionReplayJoinedConfig;\n  type: Type;\n  minInterval?: number;\n  maxInterval?: number;\n  payloadBatcher?: PayloadBatcher;\n  storeType: StoreType;\n  trackDestinationWorkerScript?: string;\n  shouldSend?: () => boolean;\n}): Promise<EventsManagerWithBeacon<Type>> => {\n  const trackDestination = new SessionReplayTrackDestination({\n    ...config,\n    loggerProvider: config.loggerProvider,\n    payloadBatcher,\n    workerScript: trackDestinationWorkerScript,\n  });\n\n  const getMemoryStore = (): EventsStore<number> => {\n    return new InMemoryEventsStore({\n      loggerProvider: config.loggerProvider,\n      maxInterval,\n      minInterval,\n    });\n  };\n\n  let lastKnownDeviceId: string | undefined;\n  let usingIdbStore = false;\n  let store!: EventsStore<number>;\n\n  const switchToMemoryStore = async () => {\n    if (!usingIdbStore) return;\n    usingIdbStore = false;\n    config.loggerProvider.warn('IDB store is experiencing repeated failures; falling back to in-memory event store.');\n    const sequences = lastKnownDeviceId ? await store.getSequencesToSend() : undefined;\n    store = getMemoryStore();\n    if (sequences && lastKnownDeviceId) {\n      const deviceId = lastKnownDeviceId;\n      sequences.forEach((seq) => {\n        sendEventsList({ sequenceId: seq.sequenceId, events: seq.events, sessionId: seq.sessionId, deviceId });\n      });\n    }\n  };\n\n  const getIdbStoreOrFallback = async (): Promise<EventsStore<number>> => {\n    const idb = await SessionReplayEventsIDBStore.new(type, {\n      loggerProvider: config.loggerProvider,\n      minInterval,\n      maxInterval,\n      apiKey: config.apiKey,\n      onPersistentFailure: () => {\n        void switchToMemoryStore();\n      },\n    });\n    if (!idb) {\n      config.loggerProvider.log('Failed to initialize idb store, falling back to memory store.');\n      return getMemoryStore();\n    }\n    usingIdbStore = true;\n    return idb;\n  };\n\n  store = storeType === 'idb' ? await getIdbStoreOrFallback() : getMemoryStore();\n\n  // Beacon buffer: a sliding window of pending (unsent) event strings for synchronous\n  // access on page exit. Uses an absolute index counter to correctly handle concurrent\n  // async flushes without losing events added between the flush call and its resolution.\n  const beaconBuffer: string[] = [];\n  let beaconWindowStart = 0; // absolute index of the first element in beaconBuffer\n\n  const advanceBeaconWindow = (upToAbsoluteIdx: number) => {\n    if (upToAbsoluteIdx <= beaconWindowStart) return;\n    const trimCount = Math.min(upToAbsoluteIdx - beaconWindowStart, beaconBuffer.length);\n    if (trimCount > 0) {\n      beaconBuffer.splice(0, trimCount);\n      beaconWindowStart = upToAbsoluteIdx;\n    }\n  };\n\n  /**\n   * Immediately sends events to the track destination.\n   */\n  const sendEventsList = ({\n    events: rawEvents,\n    sessionId,\n    deviceId,\n    sequenceId,\n  }: {\n    events: string[];\n    sessionId: string | number;\n    deviceId: string;\n    sequenceId?: number;\n  }) => {\n    // Backstop for events that entered IDB before the per-event size guard in\n    // addCompressedEventToManager (e.g. stored by a previous SDK version or via\n    // storeCurrentSequence/sendStoredEvents which bypass the capture-time check).\n    // Compare UTF-8 byte size, not JS char count, to match the server-side limit.\n    const sizedEvents = rawEvents.map((e) => ({ event: e, bytes: new Blob([e]).size }));\n    const oversized = sizedEvents.filter((s) => s.bytes > MAX_SINGLE_EVENT_SIZE);\n    if (oversized.length > 0) {\n      config.loggerProvider.warn(\n        `Dropping ${oversized.length} oversized event(s) from session replay sequence before send. Sizes: ${oversized\n          .map((s) => `${Math.round(s.bytes / 1024)} KB`)\n          .join(\n            ', ',\n          )}. If this recurs, please open a GitHub issue at https://github.com/amplitude/Amplitude-TypeScript/issues or contact Amplitude support.`,\n      );\n    }\n    const events =\n      oversized.length > 0\n        ? sizedEvents.filter((s) => s.bytes <= MAX_SINGLE_EVENT_SIZE).map((s) => s.event)\n        : rawEvents;\n    if (events.length === 0) {\n      store.cleanUpSessionEventsStore(sessionId, sequenceId).catch((e) => {\n        config.loggerProvider.warn('Failed to clean up session replay events store:', e);\n      });\n      return;\n    }\n\n    if (config.debugMode) {\n      getStorageSize()\n        .then(({ totalStorageSize, percentOfQuota, usageDetails }) => {\n          config.loggerProvider.debug(\n            `Total storage size: ${totalStorageSize} KB, percentage of quota: ${percentOfQuota}%, usage details: ${usageDetails}`,\n          );\n        })\n        .catch(() => {\n          // swallow error\n        });\n    }\n\n    trackDestination.sendEventsList({\n      events: events,\n      sessionId: sessionId,\n      flushMaxRetries: config.flushMaxRetries,\n      apiKey: config.apiKey,\n      deviceId: deviceId,\n      sampleRate: config.sampleRate,\n      serverZone: config.serverZone,\n      version: config.version,\n      type,\n      onComplete: async () => {\n        await store.cleanUpSessionEventsStore(sessionId, sequenceId);\n        return;\n      },\n    });\n  };\n\n  const sendCurrentSequenceEvents = ({ sessionId, deviceId }: { sessionId: number; deviceId: string }) => {\n    lastKnownDeviceId = deviceId;\n    // Evaluate shouldSend synchronously before the async store read. asyncSetSessionId\n    // updates sessionStartTime immediately after calling sendEvents(), so by the time\n    // storeCurrentSequence resolves the start time would reflect the new session and\n    // the elapsed check would compute ~0ms, silently dropping the previous session's events.\n    if (shouldSend && !shouldSend()) return;\n    // Snapshot the absolute end-index before the async store read so that any events\n    // pushed after this point are NOT considered sent and remain in the beacon buffer.\n    const snapshotAbsIdx = beaconWindowStart + beaconBuffer.length;\n    store\n      .storeCurrentSequence(sessionId)\n      .then((currentSequence) => {\n        if (currentSequence) {\n          advanceBeaconWindow(snapshotAbsIdx);\n          sendEventsList({\n            sequenceId: currentSequence.sequenceId,\n            events: currentSequence.events,\n            sessionId: currentSequence.sessionId,\n            deviceId,\n          });\n        }\n      })\n      .catch((e) => {\n        config.loggerProvider.warn('Failed to get current sequence of session replay events for session:', e);\n      });\n  };\n\n  const sendStoredEvents = async ({ deviceId }: { deviceId: string }) => {\n    lastKnownDeviceId = deviceId;\n    const sequencesToSend = await store.getSequencesToSend();\n    if (!sequencesToSend?.length) {\n      return;\n    }\n    config.loggerProvider.log(`Draining ${sequencesToSend.length} stored sequence(s) from previous session.`);\n    sequencesToSend.forEach((sequence) => {\n      sendEventsList({\n        sequenceId: sequence.sequenceId,\n        events: sequence.events,\n        sessionId: sequence.sessionId,\n        deviceId,\n      });\n    });\n  };\n\n  const addEvent = ({\n    event,\n    sessionId,\n    deviceId,\n  }: {\n    event: { type: Type; data: string };\n    sessionId: number;\n    deviceId: string;\n  }) => {\n    lastKnownDeviceId = deviceId;\n    // Capture shouldSend synchronously before the async store write, for the same\n    // reason as sendCurrentSequenceEvents: asyncSetSessionId updates sessionStartTime\n    // synchronously, so evaluating inside the .then() would use the new session's\n    // start time and compute ~0ms elapsed, silently dropping a valid batch.\n    const canSend = !shouldSend || shouldSend();\n    // Record the absolute index of this event in the beacon buffer before the async\n    // store operation. If a batch split occurs, we advance the window up to (but not\n    // including) this event so that it starts the next pending window.\n    const absIdx = beaconWindowStart + beaconBuffer.length;\n    beaconBuffer.push(event.data);\n    store\n      .addEventToCurrentSequence(sessionId, event.data)\n      .then((sequenceToSend) => {\n        if (sequenceToSend) {\n          if (!canSend) {\n            // The split atomically moved events to sequencesToSend; without cleanup\n            // they would be unconditionally replayed on next page load via\n            // sendStoredEvents, bypassing the min session duration gate. The split\n            // batch must also be dropped from the beacon buffer so it isn't sent\n            // via sendBeacon on page unload (potentially attributed to a later session).\n            store.cleanUpSessionEventsStore(sequenceToSend.sessionId, sequenceToSend.sequenceId).catch((e) => {\n              config.loggerProvider.warn('Failed to clean up dropped session replay sequence:', e);\n            });\n            advanceBeaconWindow(absIdx);\n            return;\n          }\n          // Events before absIdx belong to the split batch being sent; advance window.\n          advanceBeaconWindow(absIdx);\n          sendEventsList({\n            sequenceId: sequenceToSend.sequenceId,\n            events: sequenceToSend.events,\n            sessionId: sequenceToSend.sessionId,\n            deviceId,\n          });\n        }\n      })\n      .catch((e) => {\n        config.loggerProvider.warn('Failed to add event to session replay capture:', e);\n      });\n  };\n\n  async function flush(useRetry = false) {\n    return trackDestination.flush(useRetry);\n  }\n\n  const getBeaconEvents = (): string[] => [...beaconBuffer];\n\n  const dropPendingBeaconEvents = () => {\n    advanceBeaconWindow(beaconWindowStart + beaconBuffer.length);\n  };\n\n  return {\n    sendCurrentSequenceEvents,\n    addEvent,\n    sendStoredEvents,\n    flush,\n    getBeaconEvents,\n    dropPendingBeaconEvents,\n    trackDestination,\n  };\n};\n"
  },
  {
    "path": "packages/session-replay-browser/src/events/events-memory-store.ts",
    "content": "import { Events, SendingSequencesReturn } from '../typings/session-replay';\nimport { BaseEventsStore } from './base-events-store';\n\nexport class InMemoryEventsStore extends BaseEventsStore<number> {\n  private finalizedSequences: Record<number, { sessionId: string | number; events: string[] }> = {};\n  private sequences: Record<string | number, string[]> = {};\n  private sequenceId = 0;\n\n  private resetCurrentSequence(sessionId: string | number) {\n    this.sequences[sessionId] = [];\n  }\n\n  private addSequence(sessionId: string | number): SendingSequencesReturn<number> {\n    const sequenceId = this.sequenceId++;\n    const events = [...this.sequences[sessionId]];\n    this.finalizedSequences[sequenceId] = { sessionId, events };\n    this.resetCurrentSequence(sessionId);\n    return { sequenceId, events, sessionId };\n  }\n\n  async getSequencesToSend(): Promise<SendingSequencesReturn<number>[] | undefined> {\n    return Object.entries(this.finalizedSequences).map(([sequenceId, { sessionId, events }]) => ({\n      sequenceId: Number(sequenceId),\n      sessionId,\n      events,\n    }));\n  }\n\n  async storeCurrentSequence(sessionId: string | number): Promise<SendingSequencesReturn<number> | undefined> {\n    if (!this.sequences[sessionId]) {\n      return undefined;\n    }\n    return this.addSequence(sessionId);\n  }\n\n  async addEventToCurrentSequence(\n    sessionId: number,\n    event: string,\n  ): Promise<SendingSequencesReturn<number> | undefined> {\n    if (!this.sequences[sessionId]) {\n      this.resetCurrentSequence(sessionId);\n    }\n\n    let sequenceReturn: SendingSequencesReturn<number> | undefined;\n    if (this.shouldSplitEventsList(this.sequences[sessionId], event)) {\n      sequenceReturn = this.addSequence(sessionId);\n    }\n\n    this.sequences[sessionId].push(event);\n\n    return sequenceReturn;\n  }\n\n  async storeSendingEvents(sessionId: number, events: Events): Promise<number | undefined> {\n    this.finalizedSequences[this.sequenceId] = { sessionId, events };\n\n    return this.sequenceId++;\n  }\n\n  async cleanUpSessionEventsStore(_sessionId: number, sequenceId?: number): Promise<void> {\n    if (sequenceId !== undefined) {\n      delete this.finalizedSequences[sequenceId];\n    }\n  }\n}\n"
  },
  {
    "path": "packages/session-replay-browser/src/events/merge-mutation-events.ts",
    "content": "import { EventType, IncrementalSource } from '@amplitude/rrweb-types';\nimport type { eventWithTime, mutationData } from '@amplitude/rrweb-types';\n\nfunction isMergeableMutation(event: eventWithTime): boolean {\n  if (event.type !== EventType.IncrementalSnapshot) return false;\n  const data = event.data as mutationData;\n  return data.source === IncrementalSource.Mutation && !data.isAttachIframe;\n}\n\nfunction mergeGroup(events: eventWithTime[]): eventWithTime {\n  const first = events[0];\n\n  // Track first/last event index for each node's adds and removes.\n  // lastParentById: final parent from most recent add (last-write-wins).\n  const firstAddEventIndex = new Map<number, number>();\n  const lastAddEventIndex = new Map<number, number>();\n  const firstRemoveEventIndex = new Map<number, number>();\n  const lastRemoveEventIndex = new Map<number, number>();\n  const lastParentById = new Map<number, number>();\n  events.forEach((e, i) => {\n    const data = e.data as mutationData;\n    for (const add of data.adds) {\n      if (!firstAddEventIndex.has(add.node.id)) firstAddEventIndex.set(add.node.id, i);\n      lastAddEventIndex.set(add.node.id, i);\n      lastParentById.set(add.node.id, add.parentId);\n    }\n    for (const remove of data.removes) {\n      if (!firstRemoveEventIndex.has(remove.id)) firstRemoveEventIndex.set(remove.id, i);\n      lastRemoveEventIndex.set(remove.id, i);\n    }\n  });\n\n  // Classify nodes that appear in both adds and removes within this window:\n  //\n  // Pure transient:          created here (firstAddIdx < firstRemoveIdx) and ultimately removed\n  //                          (lastAddIdx < lastRemoveIdx). Cancel all adds + all removes.\n  //\n  // Pre-existing transient:  pre-existed in DOM (firstRemoveIdx < firstAddIdx — removed before\n  //                          first add), then re-added, then removed again (lastAddIdx < lastRemoveIdx).\n  //                          The rrweb replayer processes all removes first: the re-add would still\n  //                          execute after both removes, leaving the node present when it should be\n  //                          absent. Fix: cancel the re-add and all post-add removes; keep only the\n  //                          pre-add removes (they represent the legitimate removal from the original\n  //                          location).\n  const transientIds = new Set<number>();\n  const preExistingTransientIds = new Set<number>();\n\n  for (const [id, firstAddIdx] of firstAddEventIndex) {\n    const firstRemoveIdx = firstRemoveEventIndex.get(id);\n    if (firstRemoveIdx === undefined) continue;\n    const lastAddIdx = lastAddEventIndex.get(id)!;\n    const lastRemoveIdx = lastRemoveEventIndex.get(id)!;\n    if (lastAddIdx >= lastRemoveIdx) continue; // ultimately present — keep as-is\n\n    if (firstAddIdx < firstRemoveIdx) {\n      transientIds.add(id);\n    } else if (firstRemoveIdx < firstAddIdx) {\n      // firstRemoveIdx < firstAddIdx: pre-existing node removed, re-added, then removed again\n      preExistingTransientIds.add(id);\n    }\n    // firstAddIdx === firstRemoveIdx: same-event move (remove+add in one rrweb event) followed\n    // by a later remove — keep all operations so the move and final removal survive\n  }\n\n  // Cascade: nodes whose FINAL parent is effectively cancelled (transient or pre-existing-transient)\n  // would be orphaned, so treat them as cancelled too.\n  // Use lastParentById so a node moved away from a cancelled parent to a live one is not wrongly elided.\n  //\n  // Three cascade outcomes mirror the main-loop classification:\n  //   transientIds:            no pre-existing removes (node created in window), or no remove/add overlap\n  //   preExistingTransientIds: nodeFirstRemoveIdx < nodeFirstAddIdx (pre-existing, removed before re-add)\n  //   cascadeDropAddsOnlyIds:  nodeFirstRemoveIdx === nodeFirstAddIdx (same-event move to cancelled parent)\n  //                            → drop adds but preserve removes from non-cancelled parents\n  const cascadeDropAddsOnlyIds = new Set<number>();\n  if (transientIds.size > 0 || preExistingTransientIds.size > 0) {\n    let changed = true;\n    while (changed) {\n      changed = false;\n      for (const [nodeId, parentId] of lastParentById) {\n        if (\n          !transientIds.has(nodeId) &&\n          !preExistingTransientIds.has(nodeId) &&\n          !cascadeDropAddsOnlyIds.has(nodeId) &&\n          (transientIds.has(parentId) || preExistingTransientIds.has(parentId) || cascadeDropAddsOnlyIds.has(parentId))\n        ) {\n          const nodeFirstRemoveIdx = firstRemoveEventIndex.get(nodeId);\n          const nodeFirstAddIdx = firstAddEventIndex.get(nodeId);\n          if (\n            nodeFirstRemoveIdx !== undefined &&\n            nodeFirstAddIdx !== undefined &&\n            nodeFirstRemoveIdx < nodeFirstAddIdx\n          ) {\n            preExistingTransientIds.add(nodeId);\n          } else if (\n            nodeFirstRemoveIdx !== undefined &&\n            nodeFirstAddIdx !== undefined &&\n            nodeFirstRemoveIdx === nodeFirstAddIdx\n          ) {\n            cascadeDropAddsOnlyIds.add(nodeId);\n          } else {\n            transientIds.add(nodeId);\n          }\n          changed = true;\n        }\n      }\n    }\n  }\n\n  const needsFilter = transientIds.size > 0 || preExistingTransientIds.size > 0 || cascadeDropAddsOnlyIds.size > 0;\n\n  // Build filtered removes by iterating per event so we know each remove's event index.\n  // Pure transients:          drop all removes.\n  // Pre-existing transients:  drop removes at eventIdx >= firstAddIdx (the cancelled re-add cycle);\n  //                           keep removes at eventIdx < firstAddIdx (legitimate pre-window removal).\n  // Cascade drop-adds-only:   keep removes from non-cancelled parents; drop removes from cancelled parents\n  //                           (the cancelled parent is never added in the replay, so a remove from it\n  //                           would reference a non-existent node in the replayer).\n  const filteredRemoves: mutationData['removes'][0][] = [];\n  events.forEach((e, eventIdx) => {\n    for (const r of (e.data as mutationData).removes) {\n      if (transientIds.has(r.id)) continue;\n      if (preExistingTransientIds.has(r.id) && eventIdx >= firstAddEventIndex.get(r.id)!) continue;\n      if (\n        cascadeDropAddsOnlyIds.has(r.id) &&\n        (transientIds.has(r.parentId) ||\n          preExistingTransientIds.has(r.parentId) ||\n          cascadeDropAddsOnlyIds.has(r.parentId))\n      )\n        continue;\n      filteredRemoves.push(r);\n    }\n  });\n\n  const allAdds = events.flatMap((e) => (e.data as mutationData).adds);\n  const allTexts = events.flatMap((e) => (e.data as mutationData).texts);\n  const allAttributes = events.flatMap((e) => (e.data as mutationData).attributes);\n\n  const merged: mutationData = {\n    source: IncrementalSource.Mutation,\n    removes: filteredRemoves,\n    adds: needsFilter\n      ? allAdds.filter(\n          (a) =>\n            !transientIds.has(a.node.id) &&\n            !preExistingTransientIds.has(a.node.id) &&\n            !cascadeDropAddsOnlyIds.has(a.node.id),\n        )\n      : allAdds,\n    texts: needsFilter\n      ? allTexts.filter(\n          (t) => !transientIds.has(t.id) && !preExistingTransientIds.has(t.id) && !cascadeDropAddsOnlyIds.has(t.id),\n        )\n      : allTexts,\n    attributes: needsFilter\n      ? allAttributes.filter(\n          (a) => !transientIds.has(a.id) && !preExistingTransientIds.has(a.id) && !cascadeDropAddsOnlyIds.has(a.id),\n        )\n      : allAttributes,\n  };\n  return { ...first, data: merged } as eventWithTime;\n}\n\n/**\n * Merges consecutive IncrementalSnapshot mutation events into a single event,\n * reducing overall event count without changing replay semantics.\n *\n * isAttachIframe events are never merged — they carry a full iframe document\n * tree and must remain isolated.\n */\nexport function mergeMutationEvents(events: eventWithTime[]): eventWithTime[] {\n  if (events.length <= 1) return events;\n\n  const result: eventWithTime[] = [];\n  let i = 0;\n\n  while (i < events.length) {\n    if (!isMergeableMutation(events[i])) {\n      result.push(events[i]);\n      i++;\n      continue;\n    }\n\n    let j = i + 1;\n    while (j < events.length && isMergeableMutation(events[j])) {\n      j++;\n    }\n\n    result.push(j > i + 1 ? mergeGroup(events.slice(i, j)) : events[i]);\n    i = j;\n  }\n\n  return result;\n}\n"
  },
  {
    "path": "packages/session-replay-browser/src/events/multi-manager.ts",
    "content": "import {\n  SessionReplayEventsManager as AmplitudeSessionReplayEventsManager,\n  EventsManagerWithType,\n} from '../typings/session-replay';\n\n/**\n * \"Registers\" events managers internally. When an event is added this class routes the event to the correct\n * manager. For all send or flush methods this will invoke the event for all registered managers.\n */\nexport class MultiEventManager<EventType, EventDataType>\n  implements AmplitudeSessionReplayEventsManager<EventType, EventDataType>\n{\n  private managers: Map<EventType, AmplitudeSessionReplayEventsManager<EventType, EventDataType>>;\n\n  constructor(...managers: EventsManagerWithType<EventType, EventDataType>[]) {\n    const managersMap = new Map<EventType, AmplitudeSessionReplayEventsManager<EventType, EventDataType>>();\n    managers.forEach((t) => {\n      managersMap.set(t.name, t.manager);\n    });\n    this.managers = managersMap;\n  }\n\n  async sendStoredEvents(opts: { deviceId: string }): Promise<void> {\n    const promises: Promise<void>[] = [];\n    this.managers.forEach((manager) => {\n      promises.push(manager.sendStoredEvents(opts));\n    });\n    await Promise.all(promises);\n  }\n\n  addEvent({\n    sessionId,\n    event,\n    deviceId,\n  }: {\n    sessionId: number;\n    event: { type: EventType; data: EventDataType };\n    deviceId: string;\n  }): void {\n    this.managers.get(event.type)?.addEvent({ sessionId, event, deviceId });\n  }\n\n  sendCurrentSequenceEvents({ sessionId, deviceId }: { sessionId: number; deviceId: string }): void {\n    this.managers.forEach((manager) => {\n      manager.sendCurrentSequenceEvents({ sessionId, deviceId });\n    });\n  }\n\n  async flush(useRetry?: boolean | undefined): Promise<void> {\n    const promises: Promise<void>[] = [];\n    this.managers.forEach((manager) => {\n      promises.push(manager.flush(useRetry));\n    });\n    await Promise.all(promises);\n  }\n}\n"
  },
  {
    "path": "packages/session-replay-browser/src/helpers.ts",
    "content": "import { getGlobalScope } from '@amplitude/analytics-core';\nimport { DEFAULT_MASK_LEVEL, MaskLevel, PrivacyConfig, SessionReplayJoinedConfig, UGCFilterRule } from './config/types';\nimport { KB_SIZE, MASK_TEXT_CLASS, UNMASK_TEXT_CLASS } from './constants';\nimport { StorageData } from './typings/session-replay';\nimport { getInputType } from './utils/get-input-type';\nexport { getServerUrl } from './utils/server-url';\n\ntype ChromeStorageEstimate = {\n  quota?: number;\n  usage?: number;\n  usageDetails?: { [key: string]: number };\n};\n\n/**\n * Light: Subset of inputs (sensitive types only — password, hidden, email, tel, cc-*)\n * Medium: All inputs (form fields), text is NOT masked\n * Conservative: All inputs and all texts\n */\nconst isMaskedForLevel = (elementType: 'input' | 'text', level: MaskLevel, element: HTMLElement | null): boolean => {\n  switch (level) {\n    case 'light': {\n      if (elementType !== 'input') {\n        return false;\n      }\n\n      const inputType = element ? getInputType(element) : '';\n      /* istanbul ignore if */ // TODO(lew): For some reason it's impossible to test this.\n      if (!inputType) {\n        return false;\n      }\n\n      if (['password', 'hidden', 'email', 'tel'].includes(inputType)) {\n        return true;\n      }\n\n      if ((element as HTMLInputElement).autocomplete.startsWith('cc-')) {\n        return true;\n      }\n\n      return false;\n    }\n    case 'medium':\n      return elementType === 'input';\n    case 'conservative':\n      return true;\n    default:\n      return isMaskedForLevel(elementType, DEFAULT_MASK_LEVEL, element);\n  }\n};\n\n/**\n * Returns the effective mask level for a given URL by checking `urlMaskLevels`\n * (first match wins) and falling back to `defaultMaskLevel`.\n */\nexport const getEffectiveMaskLevel = (url: string | undefined, config: PrivacyConfig): MaskLevel => {\n  if (url && config.urlMaskLevels) {\n    for (const rule of config.urlMaskLevels) {\n      if (globToRegex(rule.match).test(url)) {\n        return rule.maskLevel;\n      }\n    }\n  }\n  return config.defaultMaskLevel ?? DEFAULT_MASK_LEVEL;\n};\n\n/**\n * Checks if the given element set to be masked by rrweb\n *\n * Priority is:\n *  1. [In code] Element/class based masking/unmasking <> [Config based] Selector based masking/unmasking\n *  2. Use app defaults\n */\nexport const isMasked = (\n  elementType: 'input' | 'text',\n  config: PrivacyConfig = { defaultMaskLevel: DEFAULT_MASK_LEVEL },\n  element: HTMLElement | null,\n  currentUrl?: string,\n): boolean => {\n  if (element) {\n    // Element or parent is explicitly instrumented in code to mask\n    if (element.closest('.' + MASK_TEXT_CLASS)) {\n      return true;\n    }\n\n    // Config has override for mask\n    const shouldMask = (config.maskSelector ?? []).some((selector) => element.closest(selector));\n    if (shouldMask) {\n      return true;\n    }\n\n    // Code or config has override to unmask\n    if (element.closest('.' + UNMASK_TEXT_CLASS)) {\n      return false;\n    }\n\n    // Here we are probably sent an element, but we want to match if they have a\n    // parent with an unmask selector.\n    const shouldUnmask = (config.unmaskSelector ?? []).some((selector) => element.closest(selector));\n    if (shouldUnmask) {\n      return false;\n    }\n  }\n\n  return isMaskedForLevel(elementType, getEffectiveMaskLevel(currentUrl, config), element);\n};\n\nexport const maskFn =\n  (elementType: 'text' | 'input', config?: PrivacyConfig, getCurrentUrl?: () => string) =>\n  (text: string, element: HTMLElement | null): string => {\n    return isMasked(elementType, config, element, getCurrentUrl?.()) ? text.replace(/[^\\s]/g, '*') : text;\n  };\n\nexport const maskAttributeFn = (config?: PrivacyConfig, getCurrentUrl?: () => string) => {\n  return (key: string, value: string, element: HTMLElement): string => {\n    // Never mask style — rrweb has a separate styleDiff path for attribute mutations\n    // that reads directly from the DOM, bypassing maskAttributeFn.\n    if (key === 'style') return value;\n\n    // Short-circuit: only proceed if this attribute is in the allowlist.\n    if (!(config?.maskAttributes ?? []).includes(key)) return value;\n\n    // Use 'input' for form elements so that `medium` (which masks inputs but not text)\n    // still masks attributes on inputs/selects/textareas. For non-form elements, use\n    // 'text' so medium leaves them visible.\n    const elementType = ['INPUT', 'SELECT', 'TEXTAREA'].includes(element.tagName) ? 'input' : 'text';\n    return isMasked(elementType, config, element, getCurrentUrl?.()) ? value.replace(/[^\\s]/g, '*') : value;\n  };\n};\n\nexport const getCurrentUrl = () => {\n  const globalScope = getGlobalScope();\n  return globalScope?.location ? globalScope.location.href : '';\n};\n\nexport const generateSessionReplayId = (sessionId: string | number, deviceId: string): string => {\n  return `${deviceId}/${sessionId}`;\n};\n\nconst isValidGlobUrl = (globUrl: string): boolean => {\n  if (typeof globUrl !== 'string' || globUrl.trim() === '') return false;\n  const urlPattern = /^\\/|^https?:\\/\\/[^\\s]+$/;\n  if (!urlPattern.test(globUrl)) return false;\n  return true;\n};\n\nconst globRegexCache = new Map<string, RegExp>();\n\nconst globToRegex = (glob: string): RegExp => {\n  const cached = globRegexCache.get(glob);\n  if (cached) return cached;\n\n  // Glob → regex conversion. Glob substitution must happen BEFORE regex escaping so that\n  // the escaper does not corrupt the glob characters (e.g. turning `/**` into `/\\*\\*`).\n  // Placeholder tokens use null bytes, which are illegal in HTTP URLs and therefore can\n  // never collide with real pattern content.\n  //\n  // Substitution order (most-specific first):\n  //   trailing /**   → (/.*)?          — path with or without a trailing slash/subpath\n  //   middle  /**/   → /(.*\\/)?        — zero-or-more path segments (including zero)\n  //   bare    **     → .*              — graceful fallback for ** not adjacent to /\n  //   single  *      → .*              — any characters (preserves existing behaviour)\n  //   ?              → .               — single character wildcard\n  const T_TRAILING = '\\x00TRAIL\\x00';\n  const T_MIDDLE = '\\x00MID\\x00';\n  const T_DSTAR = '\\x00DS\\x00';\n  const T_STAR = '\\x00ST\\x00';\n  const T_QUEST = '\\x00QU\\x00';\n\n  let s = glob;\n  s = s.replace(/\\/\\*\\*$/, T_TRAILING); // trailing /**\n  s = s.replace(/\\/\\*\\*\\//g, T_MIDDLE); // /**/ in the middle\n  s = s.replace(/\\*\\*/g, T_DSTAR); // bare ** (e.g. **.example.com)\n  s = s.replace(/\\*/g, T_STAR); // single *\n  s = s.replace(/\\?/g, T_QUEST); // ?\n\n  // Escape all remaining regex special characters.\n  s = s.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&');\n\n  // Expand tokens into their regex equivalents.\n  // Use split/join (not regex) to avoid the no-control-regex lint rule on the token strings.\n  s = s.split(T_TRAILING).join('(/.*)?'); // /** → optional /anything\n  s = s.split(T_MIDDLE).join('/(.*\\\\/)?'); // /**/ → /zero-or-more-segments/\n  s = s.split(T_DSTAR).join('.*'); // bare ** → .*\n  s = s.split(T_STAR).join('.*'); // * → .*\n  s = s.split(T_QUEST).join('.'); // ? → .\n\n  const regex = new RegExp(`^${s}$`);\n  globRegexCache.set(glob, regex);\n  return regex;\n};\n\nexport const validateUGCFilterRules = (ugcFilterRules: UGCFilterRule[]) => {\n  // validate ugcFilterRules\n  if (!ugcFilterRules.every((rule) => typeof rule.selector === 'string' && typeof rule.replacement === 'string')) {\n    throw new Error('ugcFilterRules must be an array of objects with selector and replacement properties');\n  }\n\n  // validate ugcFilterRules are valid globs\n  if (!ugcFilterRules.every((rule) => isValidGlobUrl(rule.selector))) {\n    throw new Error('ugcFilterRules must be an array of objects with valid globs');\n  }\n};\n\nexport const getPageUrl = (pageUrl: string, ugcFilterRules: UGCFilterRule[]) => {\n  // apply ugcFilterRules, order is important, first rule wins\n  for (const rule of ugcFilterRules) {\n    const regex = globToRegex(rule.selector);\n\n    if (regex.test(pageUrl)) {\n      return pageUrl.replace(regex, rule.replacement);\n    }\n  }\n\n  return pageUrl;\n};\n\nexport const getStorageSize = async (): Promise<StorageData> => {\n  try {\n    const globalScope = getGlobalScope();\n    if (globalScope) {\n      const { usage, quota, usageDetails }: ChromeStorageEstimate = await globalScope.navigator.storage.estimate();\n      const totalStorageSize = usage ? Math.round(usage / KB_SIZE) : 0;\n      const percentOfQuota = usage && quota ? Math.round((usage / quota + Number.EPSILON) * 1000) / 1000 : 0;\n      return { totalStorageSize, percentOfQuota, usageDetails: JSON.stringify(usageDetails) };\n    }\n  } catch (e) {\n    // swallow\n  }\n  return { totalStorageSize: 0, percentOfQuota: 0, usageDetails: '' };\n};\n\nexport const getDebugConfig = (config: SessionReplayJoinedConfig): SessionReplayJoinedConfig => {\n  const debugConfig = {\n    ...config,\n  };\n  const { apiKey } = debugConfig;\n  debugConfig.apiKey = `****${apiKey.substring(apiKey.length - 4)}`;\n  return debugConfig;\n};\n"
  },
  {
    "path": "packages/session-replay-browser/src/hooks/click.ts",
    "content": "import type { mouseInteractionCallBack } from '@amplitude/rrweb-types';\nimport { MouseInteractions } from '@amplitude/rrweb-types';\nimport { Mirror } from '../utils/rrweb';\nimport { SessionReplayEventsManager as AmplitudeSessionReplayEventsManager } from '../typings/session-replay';\nimport { PayloadBatcher } from '../track-destination';\nimport { finder, Options as FinderOptions } from '../libs/finder';\nimport { getGlobalScope, ILogger } from '@amplitude/analytics-core';\nimport { UGCFilterRule, InteractionPerformanceConfig } from '../config/types';\nimport { getPageUrl } from '../helpers';\nimport { ScrollWatcher } from './scroll';\n\n// exported for testing\nexport type ClickEvent = {\n  timestamp: number;\n  x: number;\n  y: number;\n  viewportWidth: number;\n  viewportHeight: number;\n  pageUrl: string;\n  selector?: string;\n  type: 'click';\n};\n\n// exported for testing\nexport type ClickEventWithCount = ClickEvent & { count: number };\n\ntype Context = {\n  sessionId: string | number;\n  deviceIdFn: () => string | undefined;\n  eventsManager: AmplitudeSessionReplayEventsManager<'interaction', string>;\n  mirror: Mirror;\n  ugcFilterRules: UGCFilterRule[];\n  performanceOptions?: InteractionPerformanceConfig;\n};\n\nconst HOUR_IN_MILLISECONDS = 3_600_000;\n\nexport const clickNonBatcher: PayloadBatcher = ({ version, events }) => {\n  const clickEvents: ClickEvent[] = [];\n  events.forEach((evt: string) => {\n    const record = JSON.parse(evt) as Record<string, unknown>;\n    record.count = 1;\n    if (record.type === 'click') {\n      clickEvents.push(record as ClickEvent);\n    }\n  });\n  return { version, events: clickEvents };\n};\n\nexport const clickBatcher: PayloadBatcher = ({ version, events }) => {\n  const clickEvents: ClickEvent[] = [];\n  events.forEach((evt: string) => {\n    const record = JSON.parse(evt) as Record<string, unknown>;\n    if (record.type === 'click') {\n      clickEvents.push(record as ClickEvent);\n    }\n  });\n\n  const reduced = clickEvents.reduce<Record<string, ClickEventWithCount>>((prev, curr) => {\n    const { x, y, selector, timestamp } = curr;\n\n    // round down to nearest hour.\n    const hour = timestamp - (timestamp % HOUR_IN_MILLISECONDS);\n\n    const k = `${x}:${y}:${selector ?? ''}:${hour}`;\n    if (!prev[k]) {\n      prev[k] = { ...curr, timestamp: hour, count: 1 };\n    } else {\n      prev[k].count += 1;\n    }\n    return prev;\n  }, {});\n\n  return { version, events: Object.values(reduced) };\n};\n\nexport class ClickHandler {\n  private readonly logger: ILogger;\n  private readonly scrollWatcher: ScrollWatcher;\n\n  constructor(logger: ILogger, scrollWatcher: ScrollWatcher) {\n    this.logger = logger;\n    this.scrollWatcher = scrollWatcher;\n  }\n\n  createHook: (context: Context) => mouseInteractionCallBack = ({\n    eventsManager,\n    sessionId,\n    deviceIdFn,\n    mirror,\n    ugcFilterRules,\n    performanceOptions,\n  }) => {\n    return (e) => {\n      if (e.type !== MouseInteractions.Click) {\n        return;\n      }\n\n      const globalScope = getGlobalScope();\n      if (!globalScope) {\n        return;\n      }\n\n      const { location, innerHeight, innerWidth } = globalScope;\n      // it only makes sense to send events if a pageUrl exists\n      if (!location) {\n        return;\n      }\n\n      const { x, y } = e;\n      if (x === undefined || y === undefined) {\n        return;\n      }\n\n      const node = mirror.getNode(e.id);\n      let selector;\n      if (node) {\n        try {\n          selector = finder(\n            node as Element,\n            performanceOptions as Pick<FinderOptions, 'timeoutMs' | 'maxNumberOfTries' | 'threshold'>,\n          );\n        } catch (err) {\n          this.logger.debug('error resolving selector from finder');\n        }\n      }\n\n      const pageUrl = getPageUrl(location.href, ugcFilterRules);\n\n      const event: ClickEvent = {\n        x: x + this.scrollWatcher.currentScrollX,\n        y: y + this.scrollWatcher.currentScrollY,\n        selector,\n\n        viewportHeight: innerHeight,\n        viewportWidth: innerWidth,\n        pageUrl,\n        timestamp: Date.now(),\n        type: 'click',\n      };\n      const deviceId = deviceIdFn();\n      if (deviceId) {\n        eventsManager.addEvent({ sessionId, event: { type: 'interaction', data: JSON.stringify(event) }, deviceId });\n      }\n    };\n  };\n}\n"
  },
  {
    "path": "packages/session-replay-browser/src/hooks/scroll.ts",
    "content": "import { getViewportHeight, getViewportWidth } from '../utils/rrweb';\nimport type { scrollCallback, scrollPosition } from '@amplitude/rrweb-types';\nimport { BeaconTransport } from '../beacon-transport';\nimport { getGlobalScope } from '@amplitude/analytics-core';\nimport { SessionReplayJoinedConfig } from '../config/types';\nimport { SessionReplayDestinationSessionMetadata } from '../typings/session-replay';\nimport { getPageUrl } from '../helpers';\n\nexport type ScrollEvent = {\n  timestamp: number; // Timestamp the event occurred\n  maxScrollX: number; // Max window scroll X on a page\n  maxScrollY: number; // Max window scroll Y on a page\n  maxScrollHeight: number; // Max window scroll Y + window height on a page\n  maxScrollWidth: number; // Max window scroll X + window width on a page\n  viewportWidth: number;\n  viewportHeight: number;\n  pageUrl: string;\n  type: 'scroll';\n};\n\nexport type ScrollEventPayload = { version: number; events: ScrollEvent[] };\n\n/**\n * This is intended to watch and update max scroll activity when loaded for a particular page.\n * A new instance should be created if the page URL changes, since by default it does not reset\n * it's max scroll state. It is intended to send very few and very small events utilizing the\n * Beacon API.\n * @see {@link BeaconTransport} for more details on Beacon API usage.\n */\nexport class ScrollWatcher {\n  private timestamp = Date.now();\n  private _currentScrollX: number;\n  private _currentScrollY: number;\n  private _maxScrollX: number;\n  private _maxScrollY: number;\n  private _maxScrollWidth: number;\n  private _maxScrollHeight: number;\n  private readonly transport: BeaconTransport<ScrollEventPayload>;\n  private readonly config: Pick<SessionReplayJoinedConfig, 'loggerProvider' | 'interactionConfig'>;\n\n  static default(\n    context: Omit<SessionReplayDestinationSessionMetadata, 'deviceId'>,\n    config: SessionReplayJoinedConfig,\n  ): ScrollWatcher {\n    return new ScrollWatcher(new BeaconTransport<ScrollEventPayload>(context, config), config);\n  }\n\n  constructor(\n    transport: BeaconTransport<ScrollEventPayload>,\n    config: Pick<SessionReplayJoinedConfig, 'loggerProvider' | 'interactionConfig'>,\n  ) {\n    this._maxScrollX = 0;\n    this._maxScrollY = 0;\n    this._currentScrollX = 0;\n    this._currentScrollY = 0;\n    this._maxScrollWidth = getViewportWidth();\n    this._maxScrollHeight = getViewportHeight();\n    this.config = config;\n\n    this.transport = transport;\n  }\n\n  public get maxScrollX(): number {\n    return this._maxScrollX;\n  }\n\n  public get maxScrollY(): number {\n    return this._maxScrollY;\n  }\n\n  public get maxScrollWidth(): number {\n    return this._maxScrollWidth;\n  }\n\n  public get maxScrollHeight(): number {\n    return this._maxScrollHeight;\n  }\n\n  public get currentScrollX(): number {\n    return this._currentScrollX;\n  }\n\n  public get currentScrollY(): number {\n    return this._currentScrollY;\n  }\n\n  update(e: scrollPosition) {\n    const now = Date.now();\n    this._currentScrollX = e.x;\n    this._currentScrollY = e.y;\n    if (e.x > this._maxScrollX) {\n      const width = getViewportWidth();\n      this._maxScrollX = e.x;\n      const maxScrollWidth = e.x + width;\n      if (maxScrollWidth > this._maxScrollWidth) {\n        this._maxScrollWidth = maxScrollWidth;\n      }\n      this.timestamp = now;\n    }\n\n    if (e.y > this._maxScrollY) {\n      const height = getViewportHeight();\n      this._maxScrollY = e.y;\n      const maxScrollHeight = e.y + height;\n      if (maxScrollHeight > this._maxScrollHeight) {\n        this._maxScrollHeight = maxScrollHeight;\n      }\n      this.timestamp = now;\n    }\n  }\n\n  hook: scrollCallback = (e: scrollPosition) => {\n    this.update(e);\n  };\n\n  send: (deviceIdFn: () => string | undefined) => (_: PageTransitionEvent | Event) => void = (deviceIdFn) => (_) => {\n    const deviceId = deviceIdFn();\n    const globalScope = getGlobalScope();\n    if (globalScope && deviceId) {\n      // Capture the true final scroll position directly from the window.\n      // rrweb's scroll observer throttles callbacks to 100ms using setTimeout,\n      // so the most recent scroll position may not have been delivered to the hook yet.\n      const scrollX = globalScope.scrollX ?? 0;\n      const scrollY = globalScope.scrollY ?? 0;\n      if (scrollX > 0 || scrollY > 0) {\n        // id is required by the scrollPosition type but is not used by update() —\n        // only x and y are read. 1 is the conventional rrweb mirror ID for the document node.\n        this.update({ id: 1, x: scrollX, y: scrollY });\n      }\n      this.transport.send(deviceId, {\n        version: 1,\n        events: [\n          {\n            maxScrollX: this._maxScrollX,\n            maxScrollY: this._maxScrollY,\n            maxScrollWidth: this._maxScrollWidth,\n            maxScrollHeight: this._maxScrollHeight,\n\n            viewportHeight: getViewportHeight(),\n            viewportWidth: getViewportWidth(),\n            pageUrl: getPageUrl(globalScope.location.href, this.config.interactionConfig?.ugcFilterRules ?? []),\n            timestamp: this.timestamp,\n            type: 'scroll',\n          },\n        ],\n      });\n    }\n  };\n}\n"
  },
  {
    "path": "packages/session-replay-browser/src/identifiers.ts",
    "content": "import { generateSessionReplayId } from './helpers';\nimport { SessionIdentifiers as ISessionIdentifiers } from './typings/session-replay';\n\nexport class SessionIdentifiers implements ISessionIdentifiers {\n  deviceId?: string;\n  sessionId?: string | number;\n  sessionReplayId?: string;\n\n  constructor({ sessionId, deviceId }: { sessionId?: string | number; deviceId?: string }) {\n    this.deviceId = deviceId;\n    this.sessionId = sessionId;\n\n    if (sessionId && deviceId) {\n      this.sessionReplayId = generateSessionReplayId(sessionId, deviceId);\n    }\n  }\n}\n"
  },
  {
    "path": "packages/session-replay-browser/src/index.ts",
    "content": "import sessionReplay from './session-replay-factory';\nexport const {\n  init,\n  setSessionId,\n  getSessionId,\n  getSessionReplayProperties,\n  flush,\n  shutdown,\n  evaluateTargetingAndCapture,\n} = sessionReplay;\nexport { SessionReplayOptions, StoreType } from './typings/session-replay';\nexport { SafeLoggerProvider } from './logger';\nexport { AmplitudeSessionReplay } from './typings/session-replay';\n"
  },
  {
    "path": "packages/session-replay-browser/src/libs/finder.ts",
    "content": "/* istanbul ignore file */\n\n// DO NOT EDIT (unless you know what you're doing)\n// Taken directly from git@github.com:antonmedv/finder.git@77d33158440dfffee4a300d2975b43a5283004ab\n\n/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */\n/* eslint-disable prefer-const */\n\n// License: MIT\n// Author: Anton Medvedev <anton@medv.io>\n// Source: https://github.com/antonmedv/finder\n\ntype Knot = {\n  name: string;\n  penalty: number;\n  level?: number;\n};\n\ntype Path = Knot[];\n\nexport type Options = {\n  root: Element;\n  idName: (name: string) => boolean;\n  className: (name: string) => boolean;\n  tagName: (name: string) => boolean;\n  attr: (name: string, value: string) => boolean;\n  seedMinLength: number;\n  optimizedMinLength: number;\n  threshold: number;\n  maxNumberOfTries: number;\n  timeoutMs: number | undefined;\n};\n\nlet config: Options;\nlet rootDocument: Document | Element;\nlet start: Date;\n\nexport function finder(input: Element, options?: Partial<Options>): string {\n  start = new Date();\n  if (input.nodeType !== Node.ELEMENT_NODE) {\n    throw new Error(`Can't generate CSS selector for non-element node type.`);\n  }\n  if ('html' === input.tagName.toLowerCase()) {\n    return 'html';\n  }\n  const defaults: Options = {\n    root: document.body,\n    idName: (_name: string) => true,\n    className: (_name: string) => true,\n    tagName: (_name: string) => true,\n    attr: (_name: string, _value: string) => false,\n    seedMinLength: 1,\n    optimizedMinLength: 2,\n    threshold: 1000,\n    maxNumberOfTries: 10000,\n    timeoutMs: undefined,\n  };\n\n  config = { ...defaults, ...options };\n  rootDocument = findRootDocument(config.root, defaults);\n\n  let path = bottomUpSearch(input, 'all', () =>\n    bottomUpSearch(input, 'two', () => bottomUpSearch(input, 'one', () => bottomUpSearch(input, 'none'))),\n  );\n\n  if (path) {\n    const optimized = sort(optimize(path, input));\n    if (optimized.length > 0) {\n      path = optimized[0];\n    }\n    return selector(path);\n  } else {\n    throw new Error(`Selector was not found.`);\n  }\n}\n\nfunction findRootDocument(rootNode: Element | Document, defaults: Options) {\n  if (rootNode.nodeType === Node.DOCUMENT_NODE) {\n    return rootNode;\n  }\n  if (rootNode === defaults.root) {\n    return rootNode.ownerDocument as Document;\n  }\n  return rootNode;\n}\n\nfunction bottomUpSearch(\n  input: Element,\n  limit: 'all' | 'two' | 'one' | 'none',\n  fallback?: () => Path | null,\n): Path | null {\n  let path: Path | null = null;\n  let stack: Knot[][] = [];\n  let current: Element | null = input;\n  let i = 0;\n  while (current) {\n    const elapsedTime = new Date().getTime() - start.getTime();\n    if (config.timeoutMs !== undefined && elapsedTime > config.timeoutMs) {\n      throw new Error(`Timeout: Can't find a unique selector after ${elapsedTime}ms`);\n    }\n    let level: Knot[] = maybe(id(current)) ||\n      maybe(...attr(current)) ||\n      maybe(...classNames(current)) ||\n      maybe(tagName(current)) || [any()];\n    const nth = index(current);\n    if (limit == 'all') {\n      if (nth) {\n        level = level.concat(level.filter(dispensableNth).map((node) => nthChild(node, nth)));\n      }\n    } else if (limit == 'two') {\n      level = level.slice(0, 1);\n      if (nth) {\n        level = level.concat(level.filter(dispensableNth).map((node) => nthChild(node, nth)));\n      }\n    } else if (limit == 'one') {\n      const [node] = (level = level.slice(0, 1));\n      if (nth && dispensableNth(node)) {\n        level = [nthChild(node, nth)];\n      }\n    } else if (limit == 'none') {\n      level = [any()];\n      if (nth) {\n        level = [nthChild(level[0], nth)];\n      }\n    }\n    for (let node of level) {\n      node.level = i;\n    }\n    stack.push(level);\n    if (stack.length >= config.seedMinLength) {\n      path = findUniquePath(stack, fallback);\n      if (path) {\n        break;\n      }\n    }\n    current = current.parentElement;\n    i++;\n  }\n  if (!path) {\n    path = findUniquePath(stack, fallback);\n  }\n  if (!path && fallback) {\n    return fallback();\n  }\n  return path;\n}\n\nfunction findUniquePath(stack: Knot[][], fallback?: () => Path | null): Path | null {\n  const paths = sort(combinations(stack));\n  if (paths.length > config.threshold) {\n    return fallback ? fallback() : null;\n  }\n  for (let candidate of paths) {\n    if (unique(candidate)) {\n      return candidate;\n    }\n  }\n  return null;\n}\n\nfunction selector(path: Path): string {\n  let node = path[0];\n  let query = node.name;\n  for (let i = 1; i < path.length; i++) {\n    const level = path[i].level || 0;\n    if (node.level === level - 1) {\n      query = `${path[i].name} > ${query}`;\n    } else {\n      query = `${path[i].name} ${query}`;\n    }\n    node = path[i];\n  }\n  return query;\n}\n\nfunction penalty(path: Path): number {\n  return path.map((node) => node.penalty).reduce((acc, i) => acc + i, 0);\n}\n\nfunction unique(path: Path) {\n  const css = selector(path);\n  switch (rootDocument.querySelectorAll(css).length) {\n    case 0:\n      throw new Error(`Can't select any node with this selector: ${css}`);\n    case 1:\n      return true;\n    default:\n      return false;\n  }\n}\n\nfunction id(input: Element): Knot | null {\n  const elementId = input.getAttribute('id');\n  if (elementId && config.idName(elementId)) {\n    return {\n      name: '#' + CSS.escape(elementId),\n      penalty: 0,\n    };\n  }\n  return null;\n}\n\nfunction attr(input: Element): Knot[] {\n  const attrs = Array.from(input.attributes).filter((attr) => config.attr(attr.name, attr.value));\n  return attrs.map(\n    (attr): Knot => ({\n      name: `[${CSS.escape(attr.name)}=\"${CSS.escape(attr.value)}\"]`,\n      penalty: 0.5,\n    }),\n  );\n}\n\nfunction classNames(input: Element): Knot[] {\n  const names = Array.from(input.classList).filter(config.className);\n  return names.map(\n    (name): Knot => ({\n      name: '.' + CSS.escape(name),\n      penalty: 1,\n    }),\n  );\n}\n\nfunction tagName(input: Element): Knot | null {\n  const name = input.tagName.toLowerCase();\n  if (config.tagName(name)) {\n    return {\n      name,\n      penalty: 2,\n    };\n  }\n  return null;\n}\n\nfunction any(): Knot {\n  return {\n    name: '*',\n    penalty: 3,\n  };\n}\n\nfunction index(input: Element): number | null {\n  const parent = input.parentNode;\n  if (!parent) {\n    return null;\n  }\n  let child = parent.firstChild;\n  if (!child) {\n    return null;\n  }\n  let i = 0;\n  while (child) {\n    if (child.nodeType === Node.ELEMENT_NODE) {\n      i++;\n    }\n    if (child === input) {\n      break;\n    }\n    child = child.nextSibling;\n  }\n  return i;\n}\n\nfunction nthChild(node: Knot, i: number): Knot {\n  return {\n    name: node.name + `:nth-child(${i})`,\n    penalty: node.penalty + 1,\n  };\n}\n\nfunction dispensableNth(node: Knot) {\n  return node.name !== 'html' && !node.name.startsWith('#');\n}\n\nfunction maybe(...level: (Knot | null)[]): Knot[] | null {\n  const list = level.filter(notEmpty);\n  if (list.length > 0) {\n    return list;\n  }\n  return null;\n}\n\nfunction notEmpty<T>(value: T | null | undefined): value is T {\n  return value !== null && value !== undefined;\n}\n\nfunction* combinations(stack: Knot[][], path: Knot[] = []): Generator<Knot[]> {\n  if (stack.length > 0) {\n    for (let node of stack[0]) {\n      yield* combinations(stack.slice(1, stack.length), path.concat(node));\n    }\n  } else {\n    yield path;\n  }\n}\n\nfunction sort(paths: Iterable<Path>): Path[] {\n  return [...paths].sort((a, b) => penalty(a) - penalty(b));\n}\n\ntype Scope = {\n  counter: number;\n  visited: Map<string, boolean>;\n};\n\nfunction* optimize(\n  path: Path,\n  input: Element,\n  scope: Scope = {\n    counter: 0,\n    visited: new Map<string, boolean>(),\n  },\n): Generator<Knot[]> {\n  if (path.length > 2 && path.length > config.optimizedMinLength) {\n    for (let i = 1; i < path.length - 1; i++) {\n      if (scope.counter > config.maxNumberOfTries) {\n        return; // Okay At least I tried!\n      }\n      scope.counter += 1;\n      const newPath = [...path];\n      newPath.splice(i, 1);\n      const newPathKey = selector(newPath);\n      if (scope.visited.has(newPathKey)) {\n        return;\n      }\n      if (unique(newPath) && same(newPath, input)) {\n        yield newPath;\n        scope.visited.set(newPathKey, true);\n        yield* optimize(newPath, input, scope);\n      }\n    }\n  }\n}\n\nfunction same(path: Path, input: Element) {\n  return rootDocument.querySelector(selector(path)) === input;\n}\n"
  },
  {
    "path": "packages/session-replay-browser/src/logger.ts",
    "content": "import { ILogger, LogLevel } from '@amplitude/analytics-core';\n\nexport class SafeLoggerProvider implements ILogger {\n  private logger: ILogger;\n\n  log: typeof console.log;\n  warn: typeof console.warn;\n  error: typeof console.error;\n  debug: typeof console.debug;\n\n  constructor(loggerProvider: ILogger) {\n    this.logger = loggerProvider;\n    this.log = this.getSafeMethod('log');\n    this.warn = this.getSafeMethod('warn');\n    this.error = this.getSafeMethod('error');\n    this.debug = this.getSafeMethod('debug');\n  }\n\n  private getSafeMethod<K extends keyof ILogger>(method: K): ILogger[K] {\n    if (!this.logger) {\n      return (() => {\n        // No-op function fallback\n      }) as ILogger[K];\n    }\n\n    const fn = this.logger[method];\n    if (typeof fn === 'function') {\n      const originalFn = (fn as { __rrweb_original__?: ILogger[K] }).__rrweb_original__ ?? fn;\n      return originalFn.bind(this.logger) as ILogger[K];\n    }\n\n    return (() => {\n      // No-op function fallback\n    }) as ILogger[K];\n  }\n\n  enable(logLevel: LogLevel) {\n    this.logger.enable(logLevel);\n  }\n\n  disable() {\n    this.logger.disable();\n  }\n}\n"
  },
  {
    "path": "packages/session-replay-browser/src/messages.ts",
    "content": "export const UNEXPECTED_ERROR_MESSAGE = 'Unexpected error occurred';\nexport const UNEXPECTED_NETWORK_ERROR_MESSAGE = 'Network error occurred, event batch rejected';\nexport const MAX_RETRIES_EXCEEDED_MESSAGE = 'Session replay event batch rejected due to exceeded retry count';\nexport const STORAGE_FAILURE = 'Failed to store session replay events in IndexedDB';\nexport const MISSING_DEVICE_ID_MESSAGE = 'Session replay event batch not sent due to missing device ID';\nexport const MISSING_API_KEY_MESSAGE = 'Session replay event batch not sent due to missing api key';\nexport const SESSION_KILLED_MESSAGE =\n  'Session replay event batch dropped: server signalled capture disabled or session out of valid range for this session';\n"
  },
  {
    "path": "packages/session-replay-browser/src/observers/index.ts",
    "content": "// Re-export all observer types and classes\nexport * from '../observers';\n"
  },
  {
    "path": "packages/session-replay-browser/src/observers.ts",
    "content": "import { getGlobalScope } from '@amplitude/analytics-core';\n\nexport type ResponseBodyStatus = 'captured' | 'truncated' | 'skipped_binary' | 'error';\n\nexport interface NetworkRequestEvent {\n  timestamp: number;\n  type: 'fetch';\n  method: string;\n  url: string;\n  status?: number;\n  duration?: number;\n  requestHeaders?: Record<string, string>;\n  responseHeaders?: Record<string, string>;\n  requestBody?: string;\n  responseBody?: string;\n  responseBodyStatus?: ResponseBodyStatus;\n  error?: {\n    name: string;\n    message: string;\n  };\n}\n\nexport type NetworkEventCallback = (event: NetworkRequestEvent) => void;\n\nexport interface NetworkBodyConfig {\n  request?: boolean;\n  response?: boolean;\n  maxBodySizeBytes?: number;\n}\n\nexport interface NetworkConfig {\n  enabled: boolean;\n  body?: NetworkBodyConfig;\n}\n\nconst DEFAULT_MAX_BODY_SIZE_BYTES = 10240; // 10KB\n\nconst BINARY_CONTENT_TYPE_PREFIXES = ['image/', 'audio/', 'video/', 'application/octet-stream', 'font/'];\n\nfunction isBinaryContentType(contentType: string | null): boolean {\n  if (!contentType) return false;\n  return BINARY_CONTENT_TYPE_PREFIXES.some((prefix) => contentType.toLowerCase().startsWith(prefix));\n}\n\nfunction serializeRequestBody(body: BodyInit | null | undefined): string | undefined {\n  if (body === null || body === undefined) return undefined;\n  if (typeof body === 'string') return body;\n  if (body instanceof URLSearchParams) return body.toString();\n  if (body instanceof FormData) {\n    const parts: string[] = [];\n    body.forEach((value, key) => {\n      parts.push(`${key}=${typeof value === 'string' ? value : '[File]'}`);\n    });\n    return parts.join('&');\n  }\n  // Blob, ArrayBuffer, ArrayBufferView, ReadableStream — skip\n  return undefined;\n}\n\nfunction truncateToByteLimit(str: string, maxBytes: number): { value: string; truncated: boolean } {\n  if (new Blob([str]).size <= maxBytes) {\n    return { value: str, truncated: false };\n  }\n  // Binary search for the longest prefix whose UTF-8 byte length fits within maxBytes.\n  // Cap hi at maxBytes since each UTF-8 character is at least 1 byte, so no more than\n  // maxBytes characters can ever fit — this avoids large intermediate Blob allocations.\n  let lo = 0;\n  let hi = Math.min(str.length, maxBytes);\n  while (lo < hi) {\n    const mid = Math.ceil((lo + hi) / 2);\n    if (new Blob([str.slice(0, mid)]).size <= maxBytes) {\n      lo = mid;\n    } else {\n      hi = mid - 1;\n    }\n  }\n  // Avoid splitting a surrogate pair: if lo landed after a high surrogate, back up one position\n  if (lo > 0 && str.charCodeAt(lo - 1) >= 0xd800 && str.charCodeAt(lo - 1) <= 0xdbff) {\n    lo -= 1;\n  }\n  return { value: str.slice(0, lo), truncated: true };\n}\n\nexport class NetworkObservers {\n  private fetchObserver: (() => void) | null = null;\n  private eventCallback?: NetworkEventCallback;\n  private networkConfig?: NetworkConfig;\n\n  start(eventCallback: NetworkEventCallback, networkConfig?: NetworkConfig) {\n    this.eventCallback = eventCallback;\n    this.networkConfig = networkConfig;\n    this.observeFetch();\n  }\n\n  stop() {\n    this.fetchObserver?.();\n    this.fetchObserver = null;\n    this.eventCallback = undefined;\n    this.networkConfig = undefined;\n  }\n\n  protected notifyEvent(event: NetworkRequestEvent) {\n    this.eventCallback?.(event);\n  }\n\n  private observeFetch() {\n    const globalScope = getGlobalScope();\n    if (!globalScope) return;\n\n    const originalFetch = globalScope.fetch;\n    if (!originalFetch) return;\n\n    globalScope.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {\n      const startTime = Date.now();\n      const requestEvent: NetworkRequestEvent = {\n        timestamp: startTime,\n        type: 'fetch',\n        method: init?.method || 'GET', // Fetch API defaulted to GET when no method is provided\n        url: input.toString(),\n        requestHeaders: init?.headers as Record<string, string>,\n      };\n\n      // Capture request body if configured\n      const bodyConfig = this.networkConfig?.body;\n      if (bodyConfig?.request) {\n        const serialized = serializeRequestBody(init?.body);\n        if (serialized !== undefined) {\n          const maxBytes = bodyConfig.maxBodySizeBytes ?? DEFAULT_MAX_BODY_SIZE_BYTES;\n          requestEvent.requestBody = truncateToByteLimit(serialized, maxBytes).value;\n        }\n      }\n\n      try {\n        const response = await originalFetch(input, init);\n        const endTime = Date.now();\n\n        requestEvent.status = response.status;\n        requestEvent.duration = endTime - startTime;\n\n        // Convert Headers\n        const headers: Record<string, string> = {};\n        response.headers.forEach((value, key) => {\n          headers[key] = value;\n        });\n        requestEvent.responseHeaders = headers;\n\n        if (bodyConfig?.response) {\n          const contentType = headers['content-type'] || null;\n          if (isBinaryContentType(contentType)) {\n            requestEvent.responseBodyStatus = 'skipped_binary';\n            this.notifyEvent(requestEvent);\n          } else {\n            const cloned = response.clone();\n            // Read body without blocking the response return to the caller\n            cloned.text().then(\n              (text) => {\n                const maxBytes = bodyConfig.maxBodySizeBytes ?? DEFAULT_MAX_BODY_SIZE_BYTES;\n                const { value, truncated } = truncateToByteLimit(text, maxBytes);\n                requestEvent.responseBody = value;\n                requestEvent.responseBodyStatus = truncated ? 'truncated' : 'captured';\n                this.notifyEvent(requestEvent);\n              },\n              () => {\n                requestEvent.responseBodyStatus = 'error';\n                this.notifyEvent(requestEvent);\n              },\n            );\n          }\n        } else {\n          this.notifyEvent(requestEvent);\n        }\n\n        return response;\n      } catch (error) {\n        const endTime = Date.now();\n        requestEvent.duration = endTime - startTime;\n\n        // Capture error information\n        const typedError = error as Error;\n        requestEvent.error = {\n          name: typedError.name || 'UnknownError',\n          message: typedError.message || 'An unknown error occurred',\n        };\n\n        this.notifyEvent(requestEvent);\n        throw error;\n      }\n    };\n\n    this.fetchObserver = () => {\n      globalScope.fetch = originalFetch;\n    };\n  }\n}\n"
  },
  {
    "path": "packages/session-replay-browser/src/plugins/index.ts",
    "content": "export * from './url-tracking-plugin';\n"
  },
  {
    "path": "packages/session-replay-browser/src/plugins/url-tracking-plugin.ts",
    "content": "import { getPageUrl } from '../helpers';\nimport { UGCFilterRule } from '../config/types';\nimport { DEFAULT_URL_CHANGE_POLLING_INTERVAL } from '../constants';\nimport { RecordPlugin } from '@amplitude/rrweb-types';\n\n/**\n * Event emitted when URL changes are detected by the plugin\n * Contains the current page URL, title, and viewport dimensions\n */\nexport interface URLChangeEvent {\n  /** The current page URL (may be filtered if UGC rules are applied) */\n  href: string;\n  /** The current page title */\n  title: string;\n  /** Viewport height in pixels */\n  viewportHeight: number;\n  /** Viewport width in pixels */\n  viewportWidth: number;\n  /** The type of URL change event */\n  type: string;\n}\n\n/**\n * Configuration options for the URL tracking plugin\n */\nexport interface URLTrackingPluginOptions {\n  /** Rules for filtering sensitive URLs (User Generated Content) */\n  ugcFilterRules?: UGCFilterRule[];\n  /** Whether to use polling instead of history API events for URL detection */\n  enablePolling?: boolean;\n  /** Interval in milliseconds for polling URL changes (default: 1000ms) */\n  pollingInterval?: number;\n  /** Whether to capture document title in URL change events (default: false) */\n  captureDocumentTitle?: boolean;\n}\n\n/** Options for subscribeToUrlChanges (polling vs history + hash) */\nexport interface SubscribeToUrlChangesOptions {\n  /** Use polling instead of history/popstate/hashchange (e.g. when history is unreliable) */\n  enablePolling?: boolean;\n  /** Polling interval in ms when enablePolling is true (default: 1000) */\n  pollingInterval?: number;\n}\n\n/** Patch detection marker to prevent double-patching */\nconst PATCH_MARKER = '__amplitude_url_tracking_patched__';\n\ntype PatchableHistoryMethod<T extends (...args: any[]) => any> = T & { [PATCH_MARKER]?: boolean };\n\ninterface UrlChangeSubscriptionState {\n  callbacks: Set<(href: string) => void>;\n  onPopStateOrHashChange: () => void;\n  notify: () => void;\n  listenersAttached: boolean;\n}\n\n/** Per-globalScope subscription state; persists to avoid wrapper stacking across re-subscribe cycles */\nconst urlChangeSubscriptionsByScope = new WeakMap<Window, UrlChangeSubscriptionState>();\n\n/**\n * Single helper for URL change detection. Supports:\n * - History API (pushState/replaceState) + popstate + hashchange (shared patch per scope)\n * - Optional polling (setInterval on location.href)\n *\n * Used by session-replay targeting (re-evaluate on URL change) and the URL tracking plugin\n * (emit rrweb events). Call the returned function to unsubscribe.\n *\n * @param globalScope - window (or equivalent); no-op if undefined\n * @param onUrlChange - called when the URL changes, with the new href\n * @param options - optional polling (default: event-based only)\n * @returns cleanup function to remove this subscription\n */\nexport function subscribeToUrlChanges(\n  globalScope: Window | undefined,\n  onUrlChange: (href: string) => void,\n  options: SubscribeToUrlChangesOptions = {},\n): () => void {\n  if (!globalScope?.location) {\n    return (): void => {\n      return;\n    };\n  }\n\n  const { enablePolling = false, pollingInterval = DEFAULT_URL_CHANGE_POLLING_INTERVAL } = options;\n\n  if (enablePolling) {\n    const getHref = (): string => globalScope.location.href ?? '';\n    let lastHref = getHref();\n    const id = globalScope.setInterval(() => {\n      const href = getHref();\n      if (href === lastHref) {\n        return;\n      }\n      lastHref = href;\n      onUrlChange(href);\n    }, pollingInterval);\n    return (): void => {\n      if (id != null) {\n        globalScope.clearInterval(id);\n      }\n    };\n  }\n\n  let subscriptionState = urlChangeSubscriptionsByScope.get(globalScope);\n  if (!subscriptionState) {\n    let lastHref: string | undefined = undefined;\n    const callbacks = new Set<(href: string) => void>();\n\n    const getHref = (): string => globalScope.location.href ?? '';\n\n    const notify = (): void => {\n      const href = getHref();\n      if (lastHref !== undefined && href === lastHref) return;\n      lastHref = href;\n      callbacks.forEach((c) => c(href));\n    };\n\n    /**\n     * Creates a patched version of history methods (pushState/replaceState)\n     * that calls the original method and then emits a URL change event.\n     */\n    const createHistoryMethodPatch = <T extends typeof history.pushState | typeof history.replaceState>(\n      originalMethod: T,\n    ) => {\n      const patchedMethod = function (this: History, ...args: Parameters<T>) {\n        const result = originalMethod.apply(this, args);\n        // Read from location.href after history call so we always notify with resolved absolute URL.\n        notify();\n        return result;\n      } as PatchableHistoryMethod<T>;\n\n      patchedMethod[PATCH_MARKER] = true;\n      return patchedMethod;\n    };\n\n    const history = globalScope.history;\n    if (history?.pushState) {\n      const pushState = Reflect.get(history, 'pushState') as PatchableHistoryMethod<History['pushState']>;\n      if (!pushState[PATCH_MARKER]) {\n        history.pushState = createHistoryMethodPatch(pushState);\n      }\n    }\n    if (history?.replaceState) {\n      const replaceState = Reflect.get(history, 'replaceState') as PatchableHistoryMethod<History['replaceState']>;\n      if (!replaceState[PATCH_MARKER]) {\n        history.replaceState = createHistoryMethodPatch(replaceState);\n      }\n    }\n\n    subscriptionState = {\n      callbacks,\n      notify,\n      onPopStateOrHashChange: () => notify(),\n      listenersAttached: false,\n    };\n    urlChangeSubscriptionsByScope.set(globalScope, subscriptionState);\n  }\n\n  const state = subscriptionState;\n  if (!state.listenersAttached) {\n    globalScope.addEventListener('popstate', state.onPopStateOrHashChange);\n    globalScope.addEventListener('hashchange', state.onPopStateOrHashChange);\n    state.listenersAttached = true;\n  }\n\n  state.callbacks.add(onUrlChange);\n  return (): void => {\n    state.callbacks.delete(onUrlChange);\n    if (state.callbacks.size === 0) {\n      // Do not restore history methods: we are not aware of patches applied by other scripts.\n      if (state.listenersAttached) {\n        globalScope.removeEventListener('popstate', state.onPopStateOrHashChange);\n        globalScope.removeEventListener('hashchange', state.onPopStateOrHashChange);\n        state.listenersAttached = false;\n      }\n    }\n  };\n}\n\n/**\n * Creates a URL tracking plugin for rrweb record function\n *\n * This plugin monitors URL changes in the browser and emits events when the URL changes.\n * It supports three tracking modes:\n * 1. Polling (if explicitly enabled) - periodically checks for URL changes\n * 2. History API + Hash routing (default) - patches pushState/replaceState, listens to popstate and hashchange\n * 3. Hash routing only (fallback) - listens to hashchange events when History API is unavailable\n *\n * The plugin handles edge cases gracefully:\n * - Missing or null location objects\n * - Undefined, null, or empty location.href values\n * - Temporal dead zone issues with variable declarations\n * - Consistent URL normalization across all code paths\n *\n * @param options Configuration options for URL tracking\n * @returns RecordPlugin instance that can be used with rrweb\n */\nexport function createUrlTrackingPlugin(\n  options: URLTrackingPluginOptions = {},\n): RecordPlugin<URLTrackingPluginOptions> {\n  return {\n    name: 'amplitude/url-tracking@1',\n    observer(cb, globalScope, pluginOptions?: URLTrackingPluginOptions) {\n      // Merge options with plugin-level options taking precedence over constructor options\n      const config = { ...options, ...pluginOptions };\n      const ugcFilterRules = config.ugcFilterRules || [];\n      const enablePolling = config.enablePolling ?? false;\n      const pollingInterval = config.pollingInterval ?? DEFAULT_URL_CHANGE_POLLING_INTERVAL;\n      const captureDocumentTitle = config.captureDocumentTitle ?? false;\n\n      // Early return if no global scope is available\n      if (!globalScope) {\n        return () => {\n          // No cleanup needed if no global scope available\n        };\n      }\n\n      // Track the last URL to prevent duplicate events\n      // Initialize to undefined to ensure first call always emits an event\n      let lastTrackedUrl: string | undefined = undefined;\n\n      // Helper functions\n      /**\n       * Gets the current URL with proper normalization\n       * Handles edge cases where location.href might be undefined, null, or empty\n       * Ensures consistent behavior across all code paths\n       * @returns Normalized URL string (empty string if location unavailable)\n       */\n      const getCurrentUrl = (): string => {\n        if (!globalScope.location) return '';\n        return globalScope.location.href || '';\n      };\n\n      /**\n       * Creates a URL change event with current page information\n       * Applies UGC filtering if rules are configured\n       * Uses getCurrentUrl() for consistent URL normalization\n       * @returns URLChangeEvent with current page state\n       */\n      const createUrlChangeEvent = (): URLChangeEvent => {\n        const { innerHeight, innerWidth, document } = globalScope;\n        const currentUrl = getCurrentUrl();\n        let currentTitle = '';\n        if (captureDocumentTitle) {\n          currentTitle = document?.title || '';\n        }\n\n        // Apply UGC filtering if rules are provided, otherwise use original URL\n        const filteredUrl = ugcFilterRules.length > 0 ? getPageUrl(currentUrl, ugcFilterRules) : currentUrl;\n\n        return {\n          href: filteredUrl,\n          title: currentTitle,\n          viewportHeight: innerHeight,\n          viewportWidth: innerWidth,\n          type: 'url-change-event',\n        };\n      };\n\n      /**\n       * Emits a URL change event if the URL has actually changed\n       * Always emits on first call (when lastTrackedUrl is undefined)\n       */\n      const emitUrlChange = (): void => {\n        const currentUrl = getCurrentUrl();\n        if (lastTrackedUrl === undefined || currentUrl !== lastTrackedUrl) {\n          lastTrackedUrl = currentUrl;\n          const event = createUrlChangeEvent();\n          cb(event);\n        }\n      };\n\n      // Single helper: history + popstate + hashchange, or polling when enabled\n      const unsubscribe = subscribeToUrlChanges(\n        globalScope as Window,\n        () => emitUrlChange(),\n        enablePolling ? { enablePolling: true, pollingInterval } : {},\n      );\n      emitUrlChange();\n\n      return (): void => unsubscribe();\n    },\n    options,\n  };\n}\n\n/**\n * Default URL tracking plugin instance with default options\n * Can be used directly without custom configuration\n */\nexport const urlTrackingPlugin = createUrlTrackingPlugin();\n"
  },
  {
    "path": "packages/session-replay-browser/src/replay-start-time-store.ts",
    "content": "import { getGlobalScope, ILogger } from '@amplitude/analytics-core';\n\n/**\n * Persists the wall-clock time at which a session's replay first began capturing,\n * keyed by sessionId. The persisted value drives the `min_session_duration_ms` gate:\n * we measure elapsed *replay* time, not just current page-load time, so a session that\n * is paused and resumed (or that crosses a page navigation) is still gated correctly.\n *\n * All storage access is wrapped in try/catch — when localStorage is unavailable (Safari\n * private mode, quota exceeded, sandboxed iframe) callers fall back to `Date.now()` so\n * the gate degrades gracefully instead of throwing.\n */\n\nconst KEY_PREFIX = 'AMP_SR_START_';\nconst APIKEY_FINGERPRINT_LEN = 10;\n\n/**\n * TTL beyond which a stored start time is treated as stale and pruned on next init.\n * 24 hours covers the longest realistic single-session duration in Amplitude (default\n * inactivity timeout is 30 minutes; some configs extend sessions across resumes).\n */\nexport const REPLAY_START_TIME_TTL_MS = 24 * 60 * 60 * 1000;\n\nconst buildKeyPrefix = (apiKey: string) => `${KEY_PREFIX}${apiKey.substring(0, APIKEY_FINGERPRINT_LEN)}_`;\nconst buildKey = (apiKey: string, sessionId: string | number) => `${buildKeyPrefix(apiKey)}${sessionId}`;\n\nconst getLocalStorage = (): Storage | undefined => {\n  try {\n    const scope = getGlobalScope() as { localStorage?: Storage } | undefined;\n    return scope?.localStorage;\n  } catch {\n    // Accessing localStorage can throw in some sandboxed contexts.\n    return undefined;\n  }\n};\n\n/**\n * Returns the persisted replay start time for this sessionId if one exists and is fresh,\n * otherwise writes `now` and returns it. Returns undefined only if storage is unavailable\n * — callers should fall back to a transient `Date.now()` in that case.\n */\nexport const getOrInitReplayStartTime = (\n  apiKey: string,\n  sessionId: string | number,\n  now: number,\n  logger?: ILogger,\n): number | undefined => {\n  const storage = getLocalStorage();\n  if (!storage) return undefined;\n  const key = buildKey(apiKey, sessionId);\n  try {\n    const raw = storage.getItem(key);\n    if (raw !== null) {\n      const parsed = Number(raw);\n      // Treat NaN, non-finite, future-dated, and stale entries as missing.\n      if (Number.isFinite(parsed) && parsed > 0 && parsed <= now && now - parsed < REPLAY_START_TIME_TTL_MS) {\n        return parsed;\n      }\n    }\n    storage.setItem(key, String(now));\n    return now;\n  } catch (e) {\n    logger?.debug(`Failed to read/write replay start time from storage: ${String(e)}`);\n    return undefined;\n  }\n};\n\nexport const setReplayStartTime = (\n  apiKey: string,\n  sessionId: string | number,\n  startTime: number,\n  logger?: ILogger,\n): void => {\n  const storage = getLocalStorage();\n  if (!storage) return;\n  try {\n    storage.setItem(buildKey(apiKey, sessionId), String(startTime));\n  } catch (e) {\n    logger?.debug(`Failed to write replay start time to storage: ${String(e)}`);\n  }\n};\n\nexport const removeReplayStartTime = (apiKey: string, sessionId: string | number, logger?: ILogger): void => {\n  const storage = getLocalStorage();\n  if (!storage) return;\n  try {\n    storage.removeItem(buildKey(apiKey, sessionId));\n  } catch (e) {\n    logger?.debug(`Failed to remove replay start time from storage: ${String(e)}`);\n  }\n};\n\n/**\n * Drops stored start times older than {@link REPLAY_START_TIME_TTL_MS}. Cheap best-effort\n * sweep called on init — keeps localStorage from accumulating dead entries when sessions\n * end without a clean transition (browser close, crash). Scoped to this API key's keys\n * so multi-tenant pages don't churn through each other's entries.\n */\nexport const pruneStaleReplayStartTimes = (apiKey: string, now: number, logger?: ILogger): void => {\n  const storage = getLocalStorage();\n  if (!storage) return;\n  const prefix = buildKeyPrefix(apiKey);\n  try {\n    // Collect first; localStorage indices shift as we remove.\n    const stale: string[] = [];\n    for (let i = 0; i < storage.length; i++) {\n      const key = storage.key(i);\n      if (!key || !key.startsWith(prefix)) continue;\n      const raw = storage.getItem(key);\n      if (raw === null) continue;\n      const parsed = Number(raw);\n      if (!Number.isFinite(parsed) || parsed <= 0 || now - parsed >= REPLAY_START_TIME_TTL_MS) {\n        stale.push(key);\n      }\n    }\n    for (const key of stale) {\n      storage.removeItem(key);\n    }\n  } catch (e) {\n    logger?.debug(`Failed to prune stale replay start times: ${String(e)}`);\n  }\n};\n"
  },
  {
    "path": "packages/session-replay-browser/src/sampling.ts",
    "content": "// Pure JS xxHash32 implementation based on the official specification:\n// https://github.com/Cyan4973/xxHash/blob/dev/doc/xxhash_spec.md\nconst PRIME32_1 = 0x9e3779b1;\nconst PRIME32_2 = 0x85ebca77;\nconst PRIME32_3 = 0xc2b2ae3d;\nconst PRIME32_4 = 0x27d4eb2f;\nconst PRIME32_5 = 0x165667b1;\n\nfunction rotl32(x: number, r: number): number {\n  return ((x << r) | (x >>> (32 - r))) >>> 0;\n}\n\nfunction round(acc: number, input: number): number {\n  acc = (acc + Math.imul(input, PRIME32_2)) >>> 0;\n  acc = rotl32(acc, 13);\n  acc = Math.imul(acc, PRIME32_1) >>> 0;\n  return acc;\n}\n\nfunction readU32(bytes: Uint8Array, offset: number): number {\n  return (bytes[offset] | (bytes[offset + 1] << 8) | (bytes[offset + 2] << 16) | (bytes[offset + 3] << 24)) >>> 0;\n}\n\nfunction toUTF8Bytes(str: string): Uint8Array {\n  const bytes: number[] = [];\n  for (let i = 0; i < str.length; i++) {\n    let c = str.charCodeAt(i);\n    if (c >= 0xd800 && c <= 0xdbff && i + 1 < str.length) {\n      const next = str.charCodeAt(i + 1);\n      if (next >= 0xdc00 && next <= 0xdfff) {\n        c = ((c - 0xd800) << 10) + (next - 0xdc00) + 0x10000;\n        i++;\n      }\n    }\n    if (c < 0x80) {\n      bytes.push(c);\n    } else if (c < 0x800) {\n      bytes.push(0xc0 | (c >> 6), 0x80 | (c & 0x3f));\n    } else if (c < 0x10000) {\n      bytes.push(0xe0 | (c >> 12), 0x80 | ((c >> 6) & 0x3f), 0x80 | (c & 0x3f));\n    } else {\n      bytes.push(0xf0 | (c >> 18), 0x80 | ((c >> 12) & 0x3f), 0x80 | ((c >> 6) & 0x3f), 0x80 | (c & 0x3f));\n    }\n  }\n  return new Uint8Array(bytes);\n}\n\nexport function xxHash32(input: string, seed = 0): number {\n  const bytes = toUTF8Bytes(input);\n  const len = bytes.length;\n  let h32: number;\n  let offset = 0;\n\n  if (len >= 16) {\n    let v1 = (seed + PRIME32_1 + PRIME32_2) >>> 0;\n    let v2 = (seed + PRIME32_2) >>> 0;\n    let v3 = seed >>> 0;\n    let v4 = (seed - PRIME32_1) >>> 0;\n\n    while (offset <= len - 16) {\n      v1 = round(v1, readU32(bytes, offset));\n      offset += 4;\n      v2 = round(v2, readU32(bytes, offset));\n      offset += 4;\n      v3 = round(v3, readU32(bytes, offset));\n      offset += 4;\n      v4 = round(v4, readU32(bytes, offset));\n      offset += 4;\n    }\n\n    h32 = (rotl32(v1, 1) + rotl32(v2, 7) + rotl32(v3, 12) + rotl32(v4, 18)) >>> 0;\n  } else {\n    h32 = (seed + PRIME32_5) >>> 0;\n  }\n\n  h32 = (h32 + len) >>> 0;\n\n  while (offset <= len - 4) {\n    h32 = (h32 + Math.imul(readU32(bytes, offset), PRIME32_3)) >>> 0;\n    h32 = Math.imul(rotl32(h32, 17), PRIME32_4) >>> 0;\n    offset += 4;\n  }\n\n  while (offset < len) {\n    h32 = (h32 + Math.imul(bytes[offset], PRIME32_5)) >>> 0;\n    h32 = Math.imul(rotl32(h32, 11), PRIME32_1) >>> 0;\n    offset++;\n  }\n\n  h32 ^= h32 >>> 15;\n  h32 = Math.imul(h32, PRIME32_2) >>> 0;\n  h32 ^= h32 >>> 13;\n  h32 = Math.imul(h32, PRIME32_3) >>> 0;\n  h32 ^= h32 >>> 16;\n\n  return h32 >>> 0;\n}\n\nexport function isSessionInSample(sessionId: string | number, sampleRate: number): boolean {\n  const hash = xxHash32(sessionId.toString());\n  const mod = hash % 1_000_000;\n  return mod / 1_000_000 < sampleRate;\n}\n"
  },
  {
    "path": "packages/session-replay-browser/src/session-replay-factory.ts",
    "content": "import { debugWrapper, LogConfig } from '@amplitude/analytics-core';\nimport { getDefaultConfig } from './config/local-config';\nimport { SessionReplay } from './session-replay';\nimport { AmplitudeSessionReplay } from './typings/session-replay';\n\nexport const getLogConfig = (sessionReplay: SessionReplay) => (): LogConfig => {\n  const { config } = sessionReplay;\n  const { loggerProvider: logger, logLevel } = config || getDefaultConfig();\n  return {\n    logger,\n    logLevel,\n  };\n};\n\nconst createInstance: () => AmplitudeSessionReplay = () => {\n  const sessionReplay = new SessionReplay();\n  return {\n    init: debugWrapper(sessionReplay.init.bind(sessionReplay), 'init', getLogConfig(sessionReplay)),\n    evaluateTargetingAndCapture: debugWrapper(\n      sessionReplay.evaluateTargetingAndCapture.bind(sessionReplay),\n      'evaluateTargetingAndRecord',\n      getLogConfig(sessionReplay),\n    ),\n    setSessionId: debugWrapper(\n      sessionReplay.setSessionId.bind(sessionReplay),\n      'setSessionId',\n      getLogConfig(sessionReplay),\n    ),\n    getSessionId: debugWrapper(\n      sessionReplay.getSessionId.bind(sessionReplay),\n      'getSessionId',\n      getLogConfig(sessionReplay),\n    ),\n    getSessionReplayProperties: debugWrapper(\n      sessionReplay.getSessionReplayProperties.bind(sessionReplay),\n      'getSessionReplayProperties',\n      getLogConfig(sessionReplay),\n    ),\n    flush: debugWrapper(sessionReplay.flush.bind(sessionReplay), 'flush', getLogConfig(sessionReplay)),\n    shutdown: debugWrapper(sessionReplay.shutdown.bind(sessionReplay), 'shutdown', getLogConfig(sessionReplay)),\n  };\n};\n\nexport default createInstance();\n"
  },
  {
    "path": "packages/session-replay-browser/src/session-replay.ts",
    "content": "import {\n  getAnalyticsConnector,\n  getGlobalScope,\n  ILogger,\n  Logger,\n  LogLevel,\n  returnWrapper,\n  SpecialEventType,\n  generateHashCode,\n  getOrCreateWindowMessenger,\n  enableBackgroundCapture,\n  AMPLITUDE_ORIGINS_MAP,\n} from '@amplitude/analytics-core';\n\n// Import only specific types to avoid pulling in the entire rrweb-types package\nimport { eventWithTime, EventType as RRWebEventType, scrollCallback } from '@amplitude/rrweb-types';\nimport { createSessionReplayJoinedConfigGenerator } from './config/joined-config';\nimport {\n  LoggingConfig,\n  SessionReplayJoinedConfig,\n  SessionReplayJoinedConfigGenerator,\n  SessionReplayLocalConfig,\n  SessionReplayMetadata,\n  SessionReplayRemoteConfig,\n} from './config/types';\nimport {\n  BLOCK_CLASS,\n  CustomRRwebEvent,\n  DEFAULT_SESSION_REPLAY_PROPERTY,\n  INTERACTION_MAX_INTERVAL,\n  INTERACTION_MIN_INTERVAL,\n  MASK_TEXT_CLASS,\n  SESSION_REPLAY_DEBUG_PROPERTY,\n  SESSION_REPLAY_EU_URL,\n  SESSION_REPLAY_SERVER_URL,\n  SESSION_REPLAY_STAGING_URL,\n} from './constants';\nimport {\n  getServerUrl,\n  getDebugConfig,\n  getEffectiveMaskLevel,\n  getPageUrl,\n  getStorageSize,\n  getCurrentUrl,\n  maskFn,\n  maskAttributeFn,\n} from './helpers';\nimport { EventCompressor } from './events/event-compressor';\nimport { createEventsManager, EventsManagerWithBeacon } from './events/events-manager';\nimport { MultiEventManager } from './events/multi-manager';\nimport { clickBatcher, ClickHandler, clickNonBatcher } from './hooks/click';\nimport { ScrollWatcher } from './hooks/scroll';\nimport { SessionIdentifiers } from './identifiers';\nimport { SafeLoggerProvider } from './logger';\nimport {\n  getOrInitReplayStartTime,\n  pruneStaleReplayStartTimes,\n  removeReplayStartTime,\n  setReplayStartTime,\n} from './replay-start-time-store';\nimport { evaluateTargetingAndStore } from './targeting/targeting-manager';\nimport {\n  AmplitudeSessionReplay,\n  SessionReplayEventsManager as AmplitudeSessionReplayEventsManager,\n  DebugInfo,\n  EventsManagerWithType,\n  EventType,\n  SessionIdentifiers as ISessionIdentifiers,\n  SessionReplayOptions,\n  SessionReplayTargetingInput,\n} from './typings/session-replay';\nimport { isSessionInSample } from './sampling';\nimport { VERSION } from './version';\n\n// Import only the type for NetworkRequestEvent to keep type safety\nimport type { NetworkObservers, NetworkRequestEvent } from './observers';\nimport { createUrlTrackingPlugin, subscribeToUrlChanges } from './plugins/url-tracking-plugin';\nimport type { RecordFunction } from './utils/rrweb';\nimport { isInIframe, CrossOriginIframeCoordinator, listenForParentSignals } from './cross-origin-iframes';\n\ntype PageLeaveFn = (e: PageTransitionEvent | Event) => void;\n\nexport class SessionReplay implements AmplitudeSessionReplay {\n  name = '@amplitude/session-replay-browser';\n  config: SessionReplayJoinedConfig | undefined;\n  joinedConfigGenerator: SessionReplayJoinedConfigGenerator | undefined;\n  identifiers: ISessionIdentifiers | undefined;\n  eventsManager?: AmplitudeSessionReplayEventsManager<'replay' | 'interaction', string>;\n  loggerProvider: ILogger;\n  recordCancelCallback: ReturnType<RecordFunction> | null = null;\n  eventCount = 0;\n  eventCompressor: EventCompressor | undefined;\n  sessionTargetingMatch = false;\n  private lastTargetingParams?: SessionReplayTargetingInput;\n  private lastShouldRecordDecision?: boolean;\n\n  // Public on purpose. `pageLeaveFns` is iterated by `pageLeaveListener`,\n  // `rrwebEventManager` is dereferenced in `asyncSetSessionId` to drop the beacon buffer\n  // at a session boundary, and `sessionStartTime` drives `isBelowMinSessionDuration()`.\n  // Tests also stub/inspect these — privatizing them would break both production callers\n  // and the gate's test coverage.\n  pageLeaveFns: PageLeaveFn[] = [];\n  sessionStartTime: number | undefined;\n  rrwebEventManager: EventsManagerWithBeacon<'replay'> | undefined;\n  /**\n   * Count of sendEvents() calls suppressed by the min-session-duration gate for the\n   * current session. Drives the REPLAY_GATE_DECISION rrweb event on first send-after-pass.\n   */\n  private suppressedSendCount = 0;\n  /** True once REPLAY_GATE_DECISION has been emitted for the current session. */\n  private hasEmittedGateDecision = false;\n  private scrollHook?: scrollCallback;\n  private clickHandler?: ClickHandler;\n  private networkObservers?: NetworkObservers;\n  private metadata: SessionReplayMetadata | undefined;\n\n  // Cache the dynamically imported record function\n  private recordFunction: RecordFunction | null = null;\n  private recordEventsInFlight = false;\n  private pendingEmitEvents: Array<{ event: eventWithTime; sessionId: string | number }> = [];\n\n  /** Current page URL, kept in sync with SPA navigations for URL-based masking */\n  private currentPageUrl = '';\n\n  private recordEventsPendingShouldLogMetadata: boolean | null = null;\n\n  /** Cleanup for URL change listener used to re-evaluate targeting on SPA route changes */\n  private urlChangeCleanup: (() => void) | null = null;\n  private crossOriginIframeCoordinator: CrossOriginIframeCoordinator | null = null;\n  private crossOriginParentSignalCleanup: (() => void) | null = null;\n  /** Monotonic counter to ignore stale URL-change targeting results */\n  private latestUrlChangeTargetingEvaluationId = 0;\n\n  constructor() {\n    this.loggerProvider = new SafeLoggerProvider(new Logger());\n  }\n\n  init(apiKey: string, options: SessionReplayOptions) {\n    return returnWrapper(this._init(apiKey, options));\n  }\n\n  private teardownEventListeners = (teardown: boolean) => {\n    const globalScope = getGlobalScope();\n    if (globalScope) {\n      globalScope.removeEventListener('blur', this.blurListener);\n      globalScope.removeEventListener('focus', this.focusListener);\n      !teardown && globalScope.addEventListener('blur', this.blurListener);\n      !teardown && globalScope.addEventListener('focus', this.focusListener);\n      // prefer pagehide to unload events, this is the standard going forward. it is not\n      // 100% reliable, but is bfcache-compatible.\n      if (globalScope.self && 'onpagehide' in globalScope.self) {\n        globalScope.removeEventListener('pagehide', this.pageLeaveListener);\n        !teardown && globalScope.addEventListener('pagehide', this.pageLeaveListener);\n      } else {\n        // this has performance implications, but is the only way we can reliably send events\n        // in browser that don't support pagehide.\n        globalScope.removeEventListener('beforeunload', this.pageLeaveListener);\n        !teardown && globalScope.addEventListener('beforeunload', this.pageLeaveListener);\n      }\n    }\n  };\n\n  /**\n   * Subscribes to SPA URL changes via the URL tracking plugin. Always keeps\n   * `currentPageUrl` in sync (needed for URL-based masking). When a targeting\n   * config is present it also re-evaluates targeting on every navigation.\n   */\n  private setupUrlChangeListener(): void {\n    // If init() runs multiple times, remove the previous URL-change subscription first\n    // so we don't leak callbacks and trigger duplicate targeting evaluations.\n    this.urlChangeCleanup?.();\n\n    const globalScope = getGlobalScope() as Window | undefined;\n    if (!globalScope?.location) {\n      return;\n    }\n\n    const hasTargeting = !!this.config?.targetingConfig;\n\n    const onUrlChange = (href: string): void => {\n      this.currentPageUrl = href;\n\n      if (hasTargeting) {\n        const evaluationId = ++this.latestUrlChangeTargetingEvaluationId;\n        void this.evaluateTargetingAndCapture(\n          {\n            userProperties: {},\n            event: undefined,\n            page: { url: href },\n          },\n          false,\n          false,\n          true,\n        );\n        this.loggerProvider.debug(`Queued URL-change targeting re-evaluation #${evaluationId} for ${href}.`);\n      }\n    };\n    type UrlUnsubscribe = (scope: Window | undefined, cb: (href: string) => void) => () => void;\n    const unsubscribe = (subscribeToUrlChanges as UrlUnsubscribe)(globalScope, onUrlChange);\n\n    this.urlChangeCleanup = (): void => {\n      unsubscribe();\n      this.urlChangeCleanup = null;\n    };\n  }\n\n  /**\n   * Single source of truth for the min_session_duration_ms gate. Returns true when the\n   * current session has not yet reached the configured threshold (and we have both a\n   * configured value and a recorded start time). Returns false when there's no\n   * threshold, no recorded start time, or the threshold has been met — i.e. it\n   * answers \"should this batch be suppressed?\".\n   *\n   * Centralizing the check means future changes (clock-skew tolerance, switching to\n   * performance.now(), etc.) are one-line edits.\n   */\n  private isBelowMinSessionDuration(): boolean {\n    const minSessionDurationMs = this.config?.minSessionDurationMs;\n    if (minSessionDurationMs === undefined || this.sessionStartTime === undefined) {\n      return false;\n    }\n    return Date.now() - this.sessionStartTime < minSessionDurationMs;\n  }\n\n  private getCurrentPageForTargeting(): SessionReplayTargetingInput['page'] {\n    const currentUrl = getGlobalScope()?.location?.href;\n    return currentUrl != null ? { url: currentUrl } : undefined;\n  }\n\n  protected async _init(apiKey: string, options: SessionReplayOptions) {\n    // Re-init should always tear down any previous URL-change subscription, even when the\n    // next config has no targeting config and we don't subscribe again.\n    this.urlChangeCleanup?.();\n\n    this.loggerProvider = new SafeLoggerProvider(options.loggerProvider || new Logger());\n    Object.prototype.hasOwnProperty.call(options, 'logLevel') &&\n      this.loggerProvider.enable(options.logLevel as LogLevel);\n    this.currentPageUrl = getCurrentUrl();\n    this.identifiers = new SessionIdentifiers({ sessionId: options.sessionId, deviceId: options.deviceId });\n    // Persist replay start time per sessionId so the min_session_duration_ms gate\n    // measures replay duration (survives page reloads within a session) rather than\n    // page-load duration. Storage failures fall back to a transient Date.now().\n    const now = Date.now();\n    pruneStaleReplayStartTimes(apiKey, now, this.loggerProvider);\n    this.sessionStartTime =\n      options.sessionId !== undefined\n        ? getOrInitReplayStartTime(apiKey, options.sessionId, now, this.loggerProvider) ?? now\n        : now;\n    this.joinedConfigGenerator = await createSessionReplayJoinedConfigGenerator(apiKey, options);\n    const { joinedConfig, localConfig, remoteConfig } = await this.joinedConfigGenerator.generateJoinedConfig();\n    this.config = joinedConfig;\n\n    this.setMetadata(\n      options.sessionId,\n      joinedConfig,\n      localConfig,\n      remoteConfig,\n      options.version?.version,\n      VERSION,\n      options.version?.type,\n    );\n\n    this.pageLeaveFns = [];\n\n    if (options.sessionId && this.config.interactionConfig?.enabled) {\n      const scrollWatcher = ScrollWatcher.default(\n        {\n          sessionId: options.sessionId,\n          type: 'interaction',\n        },\n        this.config,\n      );\n      this.pageLeaveFns = [scrollWatcher.send(this.getDeviceId.bind(this)).bind(scrollWatcher)];\n      this.scrollHook = scrollWatcher.hook.bind(scrollWatcher);\n      this.clickHandler = new ClickHandler(this.loggerProvider, scrollWatcher);\n    }\n\n    const managers: EventsManagerWithType<EventType, string>[] = [];\n    let { storeType } = this.config;\n    if (storeType === 'idb' && !getGlobalScope()?.indexedDB) {\n      storeType = 'memory';\n      this.loggerProvider.warn('Could not use preferred indexedDB storage, reverting to in memory option.');\n    }\n    this.loggerProvider.log(`Using ${storeType} for event storage.`);\n    let compressionWorkerScript: string | undefined;\n    let trackDestinationWorkerScript: string | undefined;\n    const globalScope = getGlobalScope();\n    if (this.config.useWebWorker && globalScope && globalScope.Worker) {\n      const { compressionScript, trackDestinationScript } = await import('./worker');\n      compressionWorkerScript = compressionScript;\n      trackDestinationWorkerScript = trackDestinationScript;\n    }\n\n    let rrwebEventManager: EventsManagerWithBeacon<'replay'> | undefined;\n    try {\n      rrwebEventManager = await createEventsManager<'replay'>({\n        config: this.config,\n        type: 'replay',\n        storeType,\n        trackDestinationWorkerScript,\n        shouldSend: () => !this.isBelowMinSessionDuration(),\n      });\n      this.rrwebEventManager = rrwebEventManager;\n      managers.push({ name: 'replay', manager: rrwebEventManager });\n    } catch (error) {\n      const typedError = error as Error;\n      this.loggerProvider.warn(`Error occurred while creating replay events manager: ${typedError.toString()}`);\n    }\n\n    if (this.config.interactionConfig?.enabled) {\n      const payloadBatcher = this.config.interactionConfig.batch ? clickBatcher : clickNonBatcher;\n      try {\n        const interactionEventManager = await createEventsManager<'interaction'>({\n          config: this.config,\n          type: 'interaction',\n          minInterval: this.config.interactionConfig.trackEveryNms ?? INTERACTION_MIN_INTERVAL,\n          maxInterval: INTERACTION_MAX_INTERVAL,\n          payloadBatcher,\n          storeType,\n          trackDestinationWorkerScript,\n        });\n        managers.push({ name: 'interaction', manager: interactionEventManager });\n      } catch (error) {\n        const typedError = error as Error;\n        this.loggerProvider.warn(`Error occurred while creating interaction events manager: ${typedError.toString()}`);\n      }\n    }\n\n    this.eventsManager = new MultiEventManager<'replay' | 'interaction', string>(...managers);\n    // To prevent too many threads.\n    if (this.eventCompressor) {\n      this.eventCompressor.terminate();\n    }\n\n    this.eventCompressor = new EventCompressor(\n      this.eventsManager,\n      this.config,\n      this.getDeviceId(),\n      compressionWorkerScript,\n      () => this.sendEvents(),\n    );\n\n    // Flush any events that arrived while eventCompressor was not yet ready\n    // (e.g. a concurrent setSessionId() call that raced _init()'s async setup).\n    if (this.pendingEmitEvents.length > 0) {\n      const pending = this.pendingEmitEvents.splice(0);\n      for (const { event, sessionId } of pending) {\n        this.eventCompressor.enqueueEvent(event, sessionId);\n      }\n    }\n\n    // Register beacon fallback for page exit. sendBeacon survives page unload\n    // and delivers any incremental events that haven't been flushed via fetch yet.\n    //\n    // Known cross-session race: if asyncSetSessionId fired and its async\n    // storeCurrentSequence hasn't resolved before unload, the beacon buffer can still\n    // hold previous-session events. The gate below reads the *new* session's\n    // sessionStartTime, so legitimately-sendable old-session events get suppressed.\n    // Follow-up: track start time per buffered batch instead of globally.\n    this.pageLeaveFns = [\n      ...this.pageLeaveFns,\n      () => {\n        if (!this.config || !this.identifiers?.sessionId || !rrwebEventManager) return;\n        const events = rrwebEventManager.getBeaconEvents();\n        if (!events.length) return;\n        const deviceId = this.getDeviceId();\n        if (!deviceId) return;\n        if (this.isBelowMinSessionDuration()) return;\n        rrwebEventManager.trackDestination.sendBeacon({\n          events,\n          sessionId: this.identifiers.sessionId,\n          deviceId,\n          apiKey: this.config.apiKey,\n          serverZone: this.config.serverZone,\n        });\n      },\n    ];\n\n    await this.initializeNetworkObservers();\n\n    // Enable background capture when this page is opened by the Amplitude app\n    // (window.opener exists). Uses the shared messenger singleton so that if\n    // autocapture is also loaded, both share a single messenger and script load.\n    if (getGlobalScope()?.opener) {\n      const messenger = getOrCreateWindowMessenger();\n      enableBackgroundCapture(messenger);\n      messenger.setup({\n        logger: this.loggerProvider,\n        ...(this.config.serverZone && { endpoint: AMPLITUDE_ORIGINS_MAP[this.config.serverZone] }),\n      });\n    }\n\n    this.loggerProvider.log('Installing @amplitude/session-replay-browser.');\n\n    this.teardownEventListeners(false);\n\n    await this.evaluateTargetingAndCapture(\n      { userProperties: options.userProperties, page: this.getCurrentPageForTargeting() },\n      true,\n    );\n\n    const needsUrlTracking = this.config.targetingConfig || (this.config.privacyConfig?.urlMaskLevels?.length ?? 0) > 0;\n    if (needsUrlTracking) {\n      this.setupUrlChangeListener();\n    }\n  }\n\n  setSessionId(sessionId: string | number, deviceId?: string) {\n    return returnWrapper(this.asyncSetSessionId(sessionId, deviceId));\n  }\n\n  async asyncSetSessionId(\n    sessionId: string | number,\n    deviceId?: string,\n    options?: { userProperties?: { [key: string]: any } },\n  ) {\n    // Invalidate any in-flight URL-change re-evaluations from the previous session.\n    this.latestUrlChangeTargetingEvaluationId++;\n    this.sessionTargetingMatch = false;\n    this.lastShouldRecordDecision = undefined; // Reset targeting decision for new session\n\n    const previousSessionId = this.identifiers && this.identifiers.sessionId;\n    if (previousSessionId) {\n      this.sendEvents(previousSessionId);\n    }\n\n    const isSessionChange = previousSessionId !== sessionId;\n\n    // Drop any beacon-buffered events from the previous session BEFORE installing the\n    // new identifiers / start time. Otherwise the page-leave beacon path could attribute\n    // old-session events to the new session id, and the gate (using the new start time)\n    // would compute the wrong elapsed duration. Skip on a redundant same-sessionId call —\n    // the buffer belongs to the *continuing* session and should ship via beacon as normal.\n    if (isSessionChange) {\n      this.rrwebEventManager?.dropPendingBeaconEvents();\n    }\n\n    const deviceIdForReplayId = deviceId || this.getDeviceId();\n    this.identifiers = new SessionIdentifiers({\n      sessionId: sessionId,\n      deviceId: deviceIdForReplayId,\n    });\n\n    // Gate state and persisted start time only get reset on an actual session boundary.\n    // A redundant setSessionId(currentId) call would otherwise overwrite both the in-memory\n    // and stored start time with a fresh Date.now() — restarting the gate clock for what is\n    // supposed to be a continuing session.\n    if (isSessionChange) {\n      this.sessionStartTime = Date.now();\n      this.suppressedSendCount = 0;\n      this.hasEmittedGateDecision = false;\n      if (this.config?.apiKey) {\n        setReplayStartTime(this.config.apiKey, sessionId, this.sessionStartTime, this.loggerProvider);\n        if (previousSessionId !== undefined) {\n          removeReplayStartTime(this.config.apiKey, previousSessionId, this.loggerProvider);\n        }\n      }\n    }\n\n    // If there is no previous session id, SDK is being initialized for the first time,\n    // and config was just fetched in initialization, so no need to fetch it a second time\n    if (this.joinedConfigGenerator && previousSessionId) {\n      const { joinedConfig } = await this.joinedConfigGenerator.generateJoinedConfig();\n      this.config = joinedConfig;\n    }\n\n    if (this.config?.targetingConfig) {\n      await this.evaluateTargetingAndCapture(\n        { userProperties: options?.userProperties, page: this.getCurrentPageForTargeting() },\n        false,\n        true,\n      );\n    } else {\n      await this.recordEvents();\n    }\n  }\n\n  getSessionReplayProperties() {\n    const config = this.config;\n    const identifiers = this.identifiers;\n    if (!config || !identifiers) {\n      this.loggerProvider.warn('Session replay init has not been called, cannot get session replay properties.');\n      return {};\n    }\n\n    const shouldRecord = this.getShouldRecord();\n    let eventProperties: { [key: string]: string | null } = {};\n\n    if (shouldRecord) {\n      eventProperties = {\n        [DEFAULT_SESSION_REPLAY_PROPERTY]: identifiers.sessionReplayId ? identifiers.sessionReplayId : null,\n      };\n      if (config.debugMode) {\n        eventProperties[SESSION_REPLAY_DEBUG_PROPERTY] = JSON.stringify({\n          appHash: generateHashCode(config.apiKey).toString(),\n        });\n      }\n    }\n\n    void this.addCustomRRWebEvent(\n      CustomRRwebEvent.GET_SR_PROPS,\n      {\n        shouldRecord,\n        eventProperties: eventProperties,\n      },\n      this.eventCount === 10,\n    );\n    if (this.eventCount === 10) {\n      this.eventCount = 0;\n    }\n    this.eventCount++;\n\n    return eventProperties;\n  }\n\n  blurListener = () => {\n    this.sendEvents();\n  };\n\n  focusListener = () => {\n    if (this.recordCancelCallback && this.recordFunction) {\n      try {\n        this.recordFunction.takeFullSnapshot(true);\n      } catch (error) {\n        this.loggerProvider.warn('Failed to take full snapshot on focus:', error);\n      }\n    } else if (!this.recordEventsInFlight) {\n      void this.recordEvents(false);\n    }\n  };\n\n  /**\n   * This is an instance member so that if init is called multiple times\n   * it doesn't add another listener to the page leave event. This is to\n   * prevent duplicate listener actions from firing.\n   */\n  private pageLeaveListener = (e: PageTransitionEvent | Event) => {\n    // Synchronously drain any events still queued in the requestIdleCallback\n    // pipeline so they are available to send before the page unloads.\n    this.eventCompressor?.flushQueue();\n    this.sendEvents();\n    this.pageLeaveFns.forEach((fn) => {\n      fn(e);\n    });\n  };\n\n  evaluateTargetingAndCapture = async (\n    targetingParams: SessionReplayTargetingInput,\n    isInit = false,\n    forceRestart = false,\n    forceTargetingReevaluation = false,\n  ) => {\n    if (!this.identifiers || !this.identifiers.sessionId || !this.config) {\n      if (this.identifiers && !this.identifiers.sessionId) {\n        this.loggerProvider.log('Session ID has not been set yet, cannot evaluate targeting for Session Replay.');\n      } else {\n        this.loggerProvider.warn('Session replay init has not been called, cannot evaluate targeting.');\n      }\n      return;\n    }\n\n    // Handle cases where there's no targeting config\n    if (!this.config.targetingConfig) {\n      if (isInit) {\n        this.loggerProvider.log('Targeting config has not been set yet, cannot evaluate targeting.');\n      } else {\n        this.loggerProvider.log('No targeting config set, skipping initialization/recording for event.');\n        return;\n      }\n    }\n\n    // Store targeting parameters for use in getShouldRecord\n    this.lastTargetingParams = targetingParams;\n\n    // Re-evaluate only until we get the first match in this session.\n    // Once matched, keep recording for the rest of the session.\n    const targetingConfig = this.config.targetingConfig;\n    const shouldReEvaluate = targetingConfig && !this.sessionTargetingMatch;\n    if (shouldReEvaluate) {\n      // Capture URL-change evaluation id so out-of-order async completions can be discarded.\n      const urlChangeEvaluationId = forceTargetingReevaluation ? this.latestUrlChangeTargetingEvaluationId : undefined;\n      let eventForTargeting = targetingParams.event;\n      if (\n        eventForTargeting &&\n        Object.values(SpecialEventType).includes(eventForTargeting.event_type as SpecialEventType)\n      ) {\n        eventForTargeting = undefined;\n      }\n\n      const pageUrl = targetingParams.page?.url ?? getGlobalScope()?.location?.href ?? '';\n      const pageForTargeting = targetingParams.page ?? (pageUrl !== '' ? { url: pageUrl } : undefined);\n\n      const targetingMatch = await evaluateTargetingAndStore({\n        sessionId: this.identifiers.sessionId,\n        targetingConfig,\n        loggerProvider: this.loggerProvider,\n        apiKey: this.config.apiKey,\n        targetingParams: {\n          userProperties: targetingParams.userProperties,\n          event: eventForTargeting,\n          page: pageForTargeting,\n        },\n        urlChange: forceTargetingReevaluation,\n      });\n\n      if (\n        forceTargetingReevaluation &&\n        urlChangeEvaluationId !== undefined &&\n        urlChangeEvaluationId !== this.latestUrlChangeTargetingEvaluationId\n      ) {\n        this.loggerProvider.debug(\n          `Ignoring stale URL-change targeting result #${urlChangeEvaluationId}; latest is #${this.latestUrlChangeTargetingEvaluationId}.`,\n        );\n        return;\n      }\n      // Keep targeting match monotonic within a session: once true, always true.\n      // This avoids races where an older in-flight evaluation resolves false after\n      // a newer evaluation already resolved true.\n      this.sessionTargetingMatch = this.sessionTargetingMatch || targetingMatch;\n\n      this.loggerProvider.debug(\n        JSON.stringify(\n          {\n            name: 'targeted replay capture config',\n            sessionTargetingMatch: this.sessionTargetingMatch,\n            event: eventForTargeting,\n            targetingParams: targetingParams,\n          },\n          null,\n          2,\n        ),\n      );\n    }\n\n    if (isInit) {\n      void this.initialize(true);\n    } else if (forceRestart || !this.recordCancelCallback) {\n      this.loggerProvider.log('Recording events for session due to forceRestart or no ongoing recording.');\n      await this.recordEvents();\n    }\n  };\n\n  sendEvents(sessionId?: string | number) {\n    const sessionIdToSend = sessionId || this.identifiers?.sessionId;\n    const deviceId = this.getDeviceId();\n    if (this.eventsManager && sessionIdToSend && deviceId) {\n      if (this.isBelowMinSessionDuration()) {\n        // Safe to dereference: isBelowMinSessionDuration() only returns true when both\n        // this.config and this.sessionStartTime are defined.\n        const startTime = this.sessionStartTime as number;\n        const minMs = (this.config as SessionReplayJoinedConfig).minSessionDurationMs as number;\n        this.loggerProvider.log(\n          `Session ${sessionIdToSend} not sent: duration ${Date.now() - startTime}ms is below minimum ${minMs}ms.`,\n        );\n        // We deliberately do NOT clear the beacon buffer here. Blur/visibility-change\n        // can call sendEvents() mid-session; if the session later crosses the threshold\n        // those buffered events are legitimately sendable via beacon on page exit.\n        // Cross-session leak is prevented in asyncSetSessionId, which drops the buffer\n        // at the session transition. The page-leave path also gates independently.\n        this.suppressedSendCount++;\n        return;\n      }\n      // On the first send-after-pass for the session, emit a custom rrweb event so the\n      // payload itself carries the gate verdict. Lets backend ingestion diff intended\n      // vs actual replay counts to spot start-time-tracking regressions.\n      //\n      // Gate on recording being active too: addCustomRRWebEvent is a no-op when\n      // recordCancelCallback/recordFunction aren't set yet (e.g. a blur-listener-fired\n      // sendEvents reaches us before _recordEvents() activates on a reloaded long-lived\n      // session). Tripping hasEmittedGateDecision unconditionally would lose the signal\n      // for that session's first real send.\n      if (\n        !this.hasEmittedGateDecision &&\n        this.config?.minSessionDurationMs !== undefined &&\n        this.recordCancelCallback &&\n        this.recordFunction\n      ) {\n        this.hasEmittedGateDecision = true;\n        const elapsedMs = this.sessionStartTime !== undefined ? Date.now() - this.sessionStartTime : undefined;\n        void this.addCustomRRWebEvent(\n          CustomRRwebEvent.REPLAY_GATE_DECISION,\n          {\n            sessionId: sessionIdToSend,\n            suppressedSendCount: this.suppressedSendCount,\n            elapsedMs,\n            minSessionDurationMs: this.config.minSessionDurationMs,\n          },\n          false,\n        );\n      }\n      this.eventsManager.sendCurrentSequenceEvents({ sessionId: sessionIdToSend, deviceId });\n    }\n  }\n\n  async initialize(shouldSendStoredEvents = false) {\n    if (!this.identifiers?.sessionId) {\n      this.loggerProvider.log(`Session is not being recorded due to lack of session id.`);\n      return Promise.resolve();\n    }\n\n    const deviceId = this.getDeviceId();\n    if (!deviceId) {\n      this.loggerProvider.log(`Session is not being recorded due to lack of device id.`);\n      return Promise.resolve();\n    }\n    this.eventsManager && shouldSendStoredEvents && void this.eventsManager.sendStoredEvents({ deviceId });\n\n    return this.recordEvents();\n  }\n\n  shouldOptOut() {\n    let identityStoreOptOut: boolean | undefined;\n    if (this.config?.instanceName) {\n      const identityStore = getAnalyticsConnector(this.config.instanceName).identityStore;\n      identityStoreOptOut = identityStore.getIdentity().optOut;\n    }\n\n    return identityStoreOptOut !== undefined ? identityStoreOptOut : this.config?.optOut;\n  }\n\n  getShouldRecord() {\n    if (!this.identifiers || !this.config || !this.identifiers.sessionId) {\n      this.loggerProvider.warn(`Session is not being recorded due to lack of config, please call sessionReplay.init.`);\n      return false;\n    }\n\n    if (!this.config.captureEnabled) {\n      this.loggerProvider.log(\n        `Session ${this.identifiers.sessionId} not being captured due to capture being disabled for project or because the remote config could not be fetched.`,\n      );\n      return false;\n    }\n\n    if (this.shouldOptOut()) {\n      this.loggerProvider.log(`Opting session ${this.identifiers.sessionId} out of recording due to optOut config.`);\n      return false;\n    }\n\n    let shouldRecord = false;\n    let message = '';\n    let matched = false;\n\n    // If targetingConfig exists, we'll use the sessionTargetingMatch to determine whether to record\n    // Otherwise, we'll evaluate the session against the overall sample rate\n    if (this.config.targetingConfig) {\n      if (!this.sessionTargetingMatch) {\n        message = `Not capturing replays for session ${this.identifiers.sessionId} due to not matching targeting conditions.`;\n        this.loggerProvider.log(message);\n        shouldRecord = false;\n        matched = false;\n      } else {\n        message = `Capturing replays for session ${this.identifiers.sessionId} due to matching targeting conditions.`;\n        this.loggerProvider.log(message);\n        shouldRecord = true;\n        matched = true;\n      }\n    } else {\n      const isInSample = isSessionInSample(this.identifiers.sessionId, this.config.sampleRate);\n      if (!isInSample) {\n        message = `Opting session ${this.identifiers.sessionId} out of recording due to sample rate.`;\n        this.loggerProvider.log(message);\n        shouldRecord = false;\n        matched = false;\n      } else {\n        shouldRecord = true;\n        matched = true;\n      }\n    }\n\n    // Only send custom rrweb event for targeting decision when the decision changes\n    if (this.lastShouldRecordDecision !== shouldRecord && this.config.targetingConfig) {\n      void this.addCustomRRWebEvent(CustomRRwebEvent.TARGETING_DECISION, {\n        message,\n        sessionId: this.identifiers.sessionId,\n        matched,\n        targetingParams: this.lastTargetingParams,\n      });\n      this.lastShouldRecordDecision = shouldRecord;\n    }\n\n    return shouldRecord;\n  }\n\n  getBlockSelectors(): string | string[] | undefined {\n    // For some reason, this defaults to empty array ([]) if undefined in the compiled script.\n    // Empty arrays cause errors when being evaluated in Safari.\n    // Force the selector to be undefined if it's an empty array.\n    const blockSelector = this.config?.privacyConfig?.blockSelector ?? [];\n    if (blockSelector.length === 0) {\n      return undefined;\n    }\n    return blockSelector;\n  }\n\n  getMaskTextSelectors(): string | undefined {\n    const privacyConfig = this.config?.privacyConfig;\n    const effectiveLevel = privacyConfig ? getEffectiveMaskLevel(this.currentPageUrl, privacyConfig) : undefined;\n\n    if (effectiveLevel === 'conservative') {\n      return '*';\n    }\n\n    // If any urlMaskLevels rule uses 'conservative', always route all text nodes\n    // through maskTextFn so the dynamic URL getter can decide at call time.\n    // Without this, rrweb's static maskTextSelector would miss text nodes when\n    // the user navigates from a non-conservative page to a conservative one.\n    if (privacyConfig?.urlMaskLevels?.some((rule) => rule.maskLevel === 'conservative')) {\n      return '*';\n    }\n\n    // If defaultMaskLevel is 'conservative' and URL rules exist, always route text through\n    // maskTextFn — a page matching no rule falls back to the conservative default, and\n    // rrweb must be set up at start to call maskTextFn for those text nodes.\n    const urlMaskLevels = privacyConfig?.urlMaskLevels;\n    if (privacyConfig?.defaultMaskLevel === 'conservative' && urlMaskLevels && urlMaskLevels.length > 0) {\n      return '*';\n    }\n\n    const maskSelector = privacyConfig?.maskSelector;\n    if (!maskSelector) {\n      return;\n    }\n\n    return maskSelector as unknown as string;\n  }\n\n  async getRecordingPlugins(loggingConfig: LoggingConfig | undefined) {\n    const plugins = [];\n\n    // Add URL tracking plugin\n    try {\n      const urlTrackingPlugin = createUrlTrackingPlugin({\n        ugcFilterRules: this.config?.interactionConfig?.ugcFilterRules || [],\n        enablePolling: this.config?.enableUrlChangePolling || false,\n        pollingInterval: this.config?.urlChangePollingInterval,\n        captureDocumentTitle: this.config?.captureDocumentTitle,\n      });\n\n      plugins.push(urlTrackingPlugin);\n    } catch (error) {\n      this.loggerProvider.warn('Failed to create URL tracking plugin:', error);\n    }\n\n    // Default plugin settings -\n    // {\n    //   level: ['info', 'log', 'warn', 'error'],\n    //   lengthThreshold: 10000,\n    //   stringifyOptions: {\n    //     stringLengthLimit: undefined,\n    //     numOfKeysLimit: 50,\n    //     depthOfLimit: 4,\n    //   },\n    //   logger: window.console,\n    //   }\n    if (loggingConfig?.console?.enabled) {\n      try {\n        // Dynamic import keeps console plugin separate and only loads when needed\n        const { getRecordConsolePlugin } = await import('@amplitude/rrweb-plugin-console-record');\n        plugins.push(getRecordConsolePlugin({ level: loggingConfig.console.levels }));\n      } catch (error) {\n        this.loggerProvider.warn('Failed to load console plugin:', error);\n      }\n    }\n\n    return plugins.length > 0 ? plugins : undefined;\n  }\n\n  private async getRecordFunction(): Promise<RecordFunction | null> {\n    if (this.recordFunction) {\n      return this.recordFunction;\n    }\n\n    try {\n      const { record } = await import('@amplitude/rrweb-record');\n      this.recordFunction = record;\n      return record;\n    } catch (error) {\n      this.loggerProvider.warn('Failed to load rrweb-record module:', error);\n      return null;\n    }\n  }\n\n  async recordEvents(shouldLogMetadata = true) {\n    if (this.recordEventsInFlight) {\n      this.recordEventsPendingShouldLogMetadata = shouldLogMetadata;\n      return;\n    }\n    this.recordEventsInFlight = true;\n    try {\n      await this._recordEvents(shouldLogMetadata);\n      while (this.recordEventsPendingShouldLogMetadata !== null) {\n        const pendingArgs = this.recordEventsPendingShouldLogMetadata;\n        this.recordEventsPendingShouldLogMetadata = null;\n        await this._recordEvents(pendingArgs);\n      }\n    } finally {\n      this.recordEventsInFlight = false;\n      this.recordEventsPendingShouldLogMetadata = null;\n    }\n  }\n\n  private async _recordEvents(shouldLogMetadata = true) {\n    const config = this.config;\n    const shouldRecord = this.getShouldRecord();\n    const sessionId = this.identifiers?.sessionId;\n    if (!shouldRecord || !sessionId || !config) {\n      return;\n    }\n    this.stopRecordingEvents();\n\n    const recordFunction = await this.getRecordFunction();\n\n    // May be undefined if cannot import rrweb-record\n    if (!recordFunction) {\n      return;\n    }\n\n    await this.initializeNetworkObservers();\n\n    const networkLoggingConfig = config.loggingConfig?.network;\n    const trackUrl = getServerUrl(config.serverZone, config.trackServerUrl);\n    const ignoredUrls = [SESSION_REPLAY_SERVER_URL, SESSION_REPLAY_EU_URL, SESSION_REPLAY_STAGING_URL, trackUrl];\n    this.networkObservers?.start((event: NetworkRequestEvent) => {\n      if (ignoredUrls.some((url) => event.url.startsWith(url))) return;\n      void this.addCustomRRWebEvent(CustomRRwebEvent.FETCH_REQUEST, event);\n    }, networkLoggingConfig);\n    const { interactionConfig, loggingConfig } = config;\n\n    const hooks = interactionConfig?.enabled\n      ? {\n          mouseInteraction:\n            this.eventsManager &&\n            this.clickHandler?.createHook({\n              eventsManager: this.eventsManager,\n              sessionId,\n              deviceIdFn: this.getDeviceId.bind(this),\n              mirror: recordFunction.mirror,\n              ugcFilterRules: interactionConfig.ugcFilterRules ?? [],\n              performanceOptions: config.performanceConfig?.interaction,\n            }),\n          scroll: this.scrollHook,\n        }\n      : {};\n\n    const ugcFilterRules =\n      interactionConfig?.enabled && interactionConfig.ugcFilterRules ? interactionConfig.ugcFilterRules : [];\n\n    this.loggerProvider.log(`Session Replay capture beginning for ${sessionId}.`);\n\n    try {\n      const crossOriginIframesEnabled = !!config.crossOriginIframes?.enabled;\n      const coordinateChildren = config.crossOriginIframes?.coordinateChildren !== false;\n      const childMode = crossOriginIframesEnabled && isInIframe();\n\n      if (childMode && coordinateChildren) {\n        // Child mode: don't self-start; wait for a start signal from the parent.\n        // (The previous listener, if any, was already removed by stopRecordingEvents above.)\n        this.crossOriginParentSignalCleanup = listenForParentSignals({\n          onStart: () => this._recordEventsInChildMode(recordFunction, sessionId, config, hooks),\n          onStop: () => {\n            try {\n              // Only cancel the rrweb recording — do NOT call stopRecordingEvents() here,\n              // which would clear crossOriginParentSignalCleanup and make the child deaf\n              // to subsequent start/stop cycles from the parent.\n              this.recordCancelCallback && this.recordCancelCallback();\n              this.recordCancelCallback = null;\n            } catch (error) {\n              const typedError = error as Error;\n              this.loggerProvider.warn(\n                `Error occurred while stopping child iframe replay capture: ${typedError.toString()}`,\n              );\n            }\n          },\n        });\n        return;\n      }\n\n      this.recordCancelCallback = recordFunction({\n        ...this.buildRRWebRecordOptions(\n          config,\n          hooks,\n          (event: eventWithTime) => {\n            if (this.shouldOptOut()) {\n              this.loggerProvider.log(`Opting session ${sessionId} out of recording due to optOut config.`);\n              this.stopRecordingEvents();\n              this.sendEvents();\n              return;\n            }\n\n            if (event.type === RRWebEventType.Meta) {\n              event.data.href = getPageUrl(event.data.href, ugcFilterRules);\n            }\n\n            if (this.eventCompressor) {\n              // Schedule processing during idle time if the browser supports requestIdleCallback\n              this.eventCompressor.enqueueEvent(event, sessionId);\n            } else {\n              // eventCompressor is not yet ready (concurrent call racing _init()).\n              // Buffer the event so it can be flushed once the compressor is initialized.\n              this.pendingEmitEvents.push({ event, sessionId });\n            }\n          },\n          'Error while capturing replay: ',\n        ),\n        plugins: await this.getRecordingPlugins(loggingConfig),\n        recordCrossOriginIframes: crossOriginIframesEnabled,\n      });\n\n      if (crossOriginIframesEnabled && !childMode && coordinateChildren) {\n        if (!this.crossOriginIframeCoordinator) {\n          this.crossOriginIframeCoordinator = new CrossOriginIframeCoordinator();\n        }\n        this.crossOriginIframeCoordinator.start();\n      }\n\n      void this.addCustomRRWebEvent(CustomRRwebEvent.DEBUG_INFO);\n      if (shouldLogMetadata) {\n        void this.addCustomRRWebEvent(CustomRRwebEvent.METADATA, this.metadata);\n      }\n    } catch (error) {\n      this.loggerProvider.warn('Failed to initialize session replay:', error);\n    }\n  }\n\n  private buildRRWebRecordOptions(\n    config: SessionReplayJoinedConfig,\n    hooks: { mouseInteraction?: any; scroll?: scrollCallback },\n    emit: (event: eventWithTime) => void,\n    errorLogPrefix: string,\n  ): Parameters<RecordFunction>[0] {\n    const { privacyConfig } = config;\n    return {\n      emit,\n      inlineStylesheet: config.shouldInlineStylesheet,\n      hooks,\n      maskAllInputs: true,\n      maskTextClass: MASK_TEXT_CLASS,\n      blockClass: BLOCK_CLASS,\n      blockSelector: this.getBlockSelectors() as string | undefined,\n      applyBackgroundColorToBlockedElements: config.applyBackgroundColorToBlockedElements,\n      maskInputFn: maskFn('input', privacyConfig, () => this.currentPageUrl),\n      maskTextFn: maskFn('text', privacyConfig, () => this.currentPageUrl),\n      maskAttributeFn: maskAttributeFn(privacyConfig, () => this.currentPageUrl),\n      maskTextSelector: this.getMaskTextSelectors(),\n      ...(config.fullSnapshotIntervalMs !== undefined && { checkoutEveryNms: config.fullSnapshotIntervalMs }),\n      recordCanvas: false,\n      captureAdoptedStyleSheets: config.captureAdoptedStyleSheets,\n      // Strip nodes that are never rendered by the rrweb replay player.\n      // None of these affect visual fidelity; omitting them reduces snapshot size.\n      slimDOMOptions: {\n        script: true,\n        comment: true,\n        headFavicon: true,\n        headWhitespace: true,\n        headMetaDescKeywords: true,\n        headMetaSocial: true,\n        headMetaRobots: true,\n        headMetaHttpEquiv: true,\n        headMetaAuthorship: true,\n        headMetaVerification: true,\n      },\n      errorHandler: (error: unknown) => {\n        const typedError = error as Error & { _external_?: boolean };\n        // styled-components relies on this error being thrown and bubbled up, rrweb is otherwise suppressing it\n        if (typedError.message.includes('insertRule') && typedError.message.includes('CSSStyleSheet')) {\n          throw typedError;\n        }\n        // rrweb monkey-patches window functions like CSSStyleSheet.insertRule; errors from external callers\n        // (e.g. styled-components) must be re-thrown so they aren't silently swallowed.\n        if (typedError._external_) {\n          throw typedError;\n        }\n        this.loggerProvider.warn(errorLogPrefix, typedError.toString());\n        // Return true so that we don't clutter user's consoles with internal rrweb errors\n        return true;\n      },\n    };\n  }\n\n  private _recordEventsInChildMode(\n    recordFunction: RecordFunction,\n    sessionId: string | number,\n    config: SessionReplayJoinedConfig,\n    hooks: { mouseInteraction?: any; scroll?: scrollCallback },\n  ) {\n    // In child mode, rrweb detects window.parent !== window and routes events via\n    // postMessage to the parent instead of calling emit. The emit callback is unused.\n    // Note: recording plugins (URL tracking, console capture) are intentionally omitted\n    // here — the child's events are merged into the parent stream, so URL changes inside\n    // the iframe should not be recorded as parent page-view events.\n    try {\n      // Stop only the previous rrweb recording. Do NOT call stopRecordingEvents() here:\n      // that would clear crossOriginParentSignalCleanup — the very listener that invoked\n      // this method — making the child permanently deaf to subsequent stop/start cycles.\n      this.recordCancelCallback && this.recordCancelCallback();\n      this.recordCancelCallback = null;\n      this.recordCancelCallback = recordFunction({\n        ...this.buildRRWebRecordOptions(\n          config,\n          hooks,\n          () => {\n            // no-op: child events are forwarded to parent via postMessage by rrweb\n          },\n          'Error while capturing replay (child iframe): ',\n        ),\n        recordCrossOriginIframes: true, // child mode is only entered when crossOriginIframes.enabled is true\n      });\n      this.loggerProvider.log(`Session Replay child iframe capture beginning for session ${sessionId}.`);\n    } catch (error) {\n      this.loggerProvider.warn('Failed to initialize session replay in child iframe mode:', error);\n    }\n  }\n\n  addCustomRRWebEvent = async (\n    eventName: CustomRRwebEvent,\n    eventData: { [key: string]: any } = {},\n    addStorageInfo = true,\n  ) => {\n    try {\n      let debugInfo: DebugInfo | undefined = undefined;\n      const config = this.config;\n      // Only add debug info for non-metadata events\n      if (config && eventName !== CustomRRwebEvent.METADATA) {\n        debugInfo = {\n          config: getDebugConfig(config),\n          version: VERSION,\n        };\n        if (addStorageInfo) {\n          const storageSizeData = await getStorageSize();\n          debugInfo = {\n            ...storageSizeData,\n            ...debugInfo,\n          };\n        }\n      }\n      // Check first to ensure we are recording\n      if (this.recordCancelCallback && this.recordFunction) {\n        this.recordFunction.addCustomEvent(eventName, {\n          ...eventData,\n          ...debugInfo,\n        });\n      } else {\n        this.loggerProvider.debug(\n          `Not able to add custom replay capture event ${eventName} due to no ongoing recording.`,\n        );\n      }\n    } catch (e) {\n      this.loggerProvider.debug('Error while adding custom replay capture event: ', e);\n    }\n  };\n\n  stopRecordingEvents = () => {\n    try {\n      this.loggerProvider.log('Session Replay capture stopping.');\n      this.recordCancelCallback && this.recordCancelCallback();\n      this.recordCancelCallback = null;\n      this.networkObservers?.stop();\n      this.crossOriginIframeCoordinator?.stop();\n      this.crossOriginIframeCoordinator = null;\n      // Remove the child-mode parent signal listener so a later mode change\n      // (e.g. crossOriginIframes disabled) does not leave a stale listener.\n      this.crossOriginParentSignalCleanup?.();\n      this.crossOriginParentSignalCleanup = null;\n    } catch (error) {\n      const typedError = error as Error;\n      this.loggerProvider.warn(`Error occurred while stopping replay capture: ${typedError.toString()}`);\n    }\n  };\n\n  getDeviceId() {\n    return this.identifiers?.deviceId;\n  }\n\n  getSessionId() {\n    return this.identifiers?.sessionId;\n  }\n\n  async flush(useRetry = false) {\n    // Intentionally not gated on min_session_duration_ms. flush() forwards payloads\n    // already queued in trackDestination, and every code path that queues into it —\n    // sendCurrentSequenceEvents, addEvent's batch-split path, sendStoredEvents reading\n    // sequencesToSend from IDB — has already passed the gate at the time of queuing.\n    // A duplicate gate here would be unreachable.\n    return this.eventsManager?.flush(useRetry);\n  }\n\n  shutdown() {\n    this.urlChangeCleanup?.();\n    this.crossOriginParentSignalCleanup?.();\n    this.crossOriginParentSignalCleanup = null;\n    this.teardownEventListeners(true);\n    this.stopRecordingEvents();\n    this.sendEvents();\n  }\n\n  private mapSDKType(sdkType: string | undefined) {\n    if (sdkType === 'plugin') {\n      return '@amplitude/plugin-session-replay-browser';\n    }\n\n    if (sdkType === 'segment') {\n      return '@amplitude/segment-session-replay-plugin';\n    }\n\n    return null;\n  }\n\n  private setMetadata(\n    sessionId: string | number | undefined,\n    joinedConfig: SessionReplayJoinedConfig,\n    localConfig: SessionReplayLocalConfig,\n    remoteConfig: SessionReplayRemoteConfig | undefined,\n    replaySDKVersion: string | undefined,\n    standaloneSDKVersion: string | undefined,\n    sdkType: string | undefined,\n  ) {\n    const hashValue = sessionId?.toString() ? generateHashCode(sessionId.toString()) : undefined;\n\n    this.metadata = {\n      joinedConfig,\n      localConfig,\n      remoteConfig,\n      sessionId,\n      hashValue,\n      sampleRate: joinedConfig.sampleRate,\n      replaySDKType: this.mapSDKType(sdkType),\n      replaySDKVersion,\n      standaloneSDKType: '@amplitude/session-replay-browser',\n      standaloneSDKVersion,\n    };\n  }\n\n  private async initializeNetworkObservers(): Promise<void> {\n    if (this.config?.loggingConfig?.network?.enabled && !this.networkObservers) {\n      try {\n        const { NetworkObservers: NetworkObserversClass } = await import('./observers');\n        this.networkObservers = new NetworkObserversClass();\n      } catch (error) {\n        this.loggerProvider.warn('Failed to import or instantiate NetworkObservers:', error);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "packages/session-replay-browser/src/targeting/targeting-idb-store.ts",
    "content": "import { Logger as ILogger } from '@amplitude/analytics-types';\nimport { DBSchema, IDBPDatabase, openDB } from 'idb';\nimport { logIdbError } from '../utils/is-abort-error';\n\nexport const MAX_IDB_STORAGE_LENGTH = 1000 * 60 * 60 * 24 * 2; // 2 days\n\nexport interface SessionReplayTargetingDB extends DBSchema {\n  sessionTargetingMatch: {\n    key: string;\n    value: {\n      sessionId: string;\n      targetingMatch: boolean;\n      lastUpdated: number;\n    };\n  };\n}\n\nexport class TargetingIDBStore {\n  dbs: { [apiKey: string]: IDBPDatabase<SessionReplayTargetingDB> } = {};\n\n  createStore = async (dbName: string) => {\n    return await openDB<SessionReplayTargetingDB>(dbName, 1, {\n      upgrade: (db: IDBPDatabase<SessionReplayTargetingDB>) => {\n        if (!db.objectStoreNames.contains('sessionTargetingMatch')) {\n          db.createObjectStore('sessionTargetingMatch', {\n            keyPath: 'sessionId',\n          });\n        }\n      },\n    });\n  };\n\n  openOrCreateDB = async (apiKey: string) => {\n    if (this.dbs && this.dbs[apiKey]) {\n      return this.dbs[apiKey];\n    }\n    const dbName = `${apiKey.substring(0, 10)}_amp_session_replay_targeting`;\n    const db = await this.createStore(dbName);\n    this.dbs[apiKey] = db;\n    return db;\n  };\n\n  getTargetingMatchForSession = async ({\n    loggerProvider,\n    apiKey,\n    sessionId,\n  }: {\n    loggerProvider: ILogger;\n    apiKey: string;\n    sessionId: string | number;\n  }) => {\n    try {\n      const db = await this.openOrCreateDB(apiKey);\n      const sessionIdStr = String(sessionId);\n      const targetingMatchForSession = await db.get<'sessionTargetingMatch'>('sessionTargetingMatch', sessionIdStr);\n\n      return targetingMatchForSession?.targetingMatch;\n    } catch (e) {\n      logIdbError(loggerProvider, `Failed to get targeting match for session id ${sessionId}: ${e as string}`, e);\n    }\n    return undefined;\n  };\n\n  storeTargetingMatchForSession = async ({\n    loggerProvider,\n    apiKey,\n    sessionId,\n    targetingMatch,\n  }: {\n    loggerProvider: ILogger;\n    apiKey: string;\n    sessionId: string | number;\n    targetingMatch: boolean;\n  }) => {\n    try {\n      const db = await this.openOrCreateDB(apiKey);\n      const sessionIdStr = String(sessionId);\n      const targetingMatchForSession = await db.put<'sessionTargetingMatch'>('sessionTargetingMatch', {\n        targetingMatch,\n        sessionId: sessionIdStr,\n        lastUpdated: Date.now(),\n      });\n\n      return targetingMatchForSession;\n    } catch (e) {\n      logIdbError(loggerProvider, `Failed to store targeting match for session id ${sessionId}: ${e as string}`, e);\n    }\n    return undefined;\n  };\n\n  clearStoreOfOldSessions = async ({\n    loggerProvider,\n    apiKey,\n    currentSessionId,\n  }: {\n    loggerProvider: ILogger;\n    apiKey: string;\n    currentSessionId: string | number;\n  }) => {\n    try {\n      const db = await this.openOrCreateDB(apiKey);\n      const currentSessionIdStr = String(currentSessionId);\n      const tx = db.transaction<'sessionTargetingMatch', 'readwrite'>('sessionTargetingMatch', 'readwrite');\n      const allTargetingMatchObjs = await tx.store.getAll();\n      for (let i = 0; i < allTargetingMatchObjs.length; i++) {\n        const targetingMatchObj = allTargetingMatchObjs[i];\n        const amountOfTimeSinceSession = Date.now() - targetingMatchObj.lastUpdated;\n        if (targetingMatchObj.sessionId !== currentSessionIdStr && amountOfTimeSinceSession > MAX_IDB_STORAGE_LENGTH) {\n          await tx.store.delete(targetingMatchObj.sessionId);\n        }\n      }\n      await tx.done;\n    } catch (e) {\n      logIdbError(loggerProvider, `Failed to clear old targeting matches for sessions: ${e as string}`, e);\n    }\n  };\n}\nexport const targetingIDBStore = new TargetingIDBStore();\n"
  },
  {
    "path": "packages/session-replay-browser/src/targeting/targeting-manager.ts",
    "content": "import type { TargetingParameters } from '@amplitude/targeting';\nimport { TargetingConfig } from '../config/types';\nimport { Logger } from '@amplitude/analytics-types';\nimport { SessionReplayTargetingInput } from '../typings/session-replay';\nimport { targetingIDBStore } from './targeting-idb-store';\n\nexport const evaluateTargetingAndStore = async ({\n  sessionId,\n  targetingConfig,\n  loggerProvider,\n  apiKey,\n  targetingParams,\n  urlChange = false,\n}: {\n  sessionId: string | number;\n  targetingConfig: TargetingConfig;\n  loggerProvider: Logger;\n  apiKey: string;\n  targetingParams?: SessionReplayTargetingInput;\n  urlChange?: boolean;\n}) => {\n  await targetingIDBStore.clearStoreOfOldSessions({\n    loggerProvider: loggerProvider,\n    apiKey: apiKey,\n    currentSessionId: sessionId,\n  });\n\n  const idbTargetingMatch = await targetingIDBStore.getTargetingMatchForSession({\n    loggerProvider: loggerProvider,\n    apiKey: apiKey,\n    sessionId: sessionId,\n  });\n  // Skip IDB cache when re-evaluating with a new page (e.g. URL change); otherwise we'd never\n  // re-evaluate and would keep returning true after navigating to a non-matching page.\n  if (idbTargetingMatch === true && !urlChange) {\n    return true;\n  }\n\n  // If the targeting config is undefined or an empty object,\n  // assume the response was valid but no conditions were set,\n  // so all users match targeting\n  let sessionTargetingMatch = true;\n  try {\n    // Dynamic import of the targeting package\n    const { evaluateTargeting: evaluateTargetingPackage } = await import('@amplitude/targeting');\n\n    const params: TargetingParameters = {\n      ...targetingParams,\n      flag: targetingConfig,\n      sessionId: typeof sessionId === 'string' ? parseInt(sessionId, 10) : sessionId,\n      apiKey: apiKey,\n      loggerProvider: loggerProvider,\n    };\n    const targetingResult = await evaluateTargetingPackage(params);\n    if (targetingResult && targetingResult.sr_targeting_config) {\n      sessionTargetingMatch = targetingResult.sr_targeting_config.key === 'on';\n    }\n\n    void targetingIDBStore.storeTargetingMatchForSession({\n      loggerProvider: loggerProvider,\n      apiKey: apiKey,\n      sessionId: sessionId,\n      targetingMatch: sessionTargetingMatch,\n    });\n  } catch (err: unknown) {\n    const knownError = err as Error;\n    loggerProvider.warn(knownError.message);\n  }\n  return sessionTargetingMatch;\n};\n"
  },
  {
    "path": "packages/session-replay-browser/src/track-destination.ts",
    "content": "import { BaseTransport, getGlobalScope, ILogger, ServerZone, Status } from '@amplitude/analytics-core';\nimport { getCurrentUrl, getServerUrl } from './helpers';\nimport {\n  MAX_RETRIES_EXCEEDED_MESSAGE,\n  MISSING_API_KEY_MESSAGE,\n  MISSING_DEVICE_ID_MESSAGE,\n  SESSION_KILLED_MESSAGE,\n  UNEXPECTED_ERROR_MESSAGE,\n  UNEXPECTED_NETWORK_ERROR_MESSAGE,\n} from './messages';\nimport {\n  SessionReplayTrackDestination as AmplitudeSessionReplayTrackDestination,\n  SessionReplayDestination,\n  SessionReplayDestinationContext,\n} from './typings/session-replay';\nimport { VERSION } from './version';\nimport {\n  MAX_URL_LENGTH,\n  KB_SIZE,\n  MAX_KEEPALIVE_BYTES,\n  WAF_PAYLOAD_TOO_LARGE_PATTERN,\n  EVENT_SKIPPED_HEADER,\n  EVENT_SKIP_CODE_THROTTLED,\n  EVENT_SKIP_CODE_INVALID_RANGE,\n  EVENT_SKIP_CODE_CAPTURE_DISABLED,\n  THROTTLED_FLUSH_PAUSE_MS,\n} from './constants';\nimport { gzipJson } from './utils/gzip';\n\ninterface WorkerCompleteMessage {\n  type: 'complete';\n  id: string;\n  err?: string;\n  // null when the response was a clean 200 (no skip header), undefined when the\n  // request did not produce a 200, otherwise the server's skip-code string.\n  skipCode?: string | null;\n}\ninterface WorkerLogMessage {\n  type: 'log' | 'warn';\n  id: string;\n  message: string;\n}\ninterface WorkerPayloadTooLargeMessage {\n  type: 'payload_too_large';\n  id: string;\n  isWaf: boolean;\n}\ntype WorkerMessage = WorkerCompleteMessage | WorkerLogMessage | WorkerPayloadTooLargeMessage;\n\nexport type PayloadBatcher = ({ version, events }: { version: number; events: string[] }) => {\n  version: number;\n  events: unknown[];\n};\n\n// Bounded so a long-lived SDK instance can't accumulate kill records indefinitely;\n// sessions are time-bounded in practice, this cap is just a defensive ceiling.\nconst MAX_KILLED_SESSIONS = 256;\n\nexport class SessionReplayTrackDestination implements AmplitudeSessionReplayTrackDestination {\n  loggerProvider: ILogger;\n  storageKey = '';\n  trackServerUrl?: string;\n  retryTimeout = 1000;\n  private scheduled: ReturnType<typeof setTimeout> | null = null;\n  payloadBatcher: PayloadBatcher;\n  queue: SessionReplayDestinationContext[] = [];\n  private worker?: Worker;\n  private sendIdCounter = 0;\n  private pendingWorkerRequests = new Map<string, { context: SessionReplayDestinationContext; resolve: () => void }>();\n  // Server back-pressure state, fed by the X-Session-Replay-Event-Skipped header on 200s.\n  // The server uses this header (instead of 4xx) to signal a deliberate no-retry drop so SDKs\n  // don't retry-storm. We honor it here by slowing or stopping our flush schedule.\n  private flushPauseUntilMs = 0;\n  private killedSessions = new Set<string | number>();\n\n  constructor({\n    trackServerUrl,\n    loggerProvider,\n    payloadBatcher,\n    workerScript,\n  }: {\n    trackServerUrl?: string;\n    loggerProvider: ILogger;\n    payloadBatcher?: PayloadBatcher;\n    workerScript?: string;\n  }) {\n    this.loggerProvider = loggerProvider;\n    this.payloadBatcher = payloadBatcher ? payloadBatcher : (payload) => payload;\n    this.trackServerUrl = trackServerUrl;\n\n    if (workerScript) {\n      try {\n        const blob = new Blob([workerScript], { type: 'application/javascript' });\n        const blobUrl = URL.createObjectURL(blob);\n        const worker = new Worker(blobUrl);\n        worker.onerror = (e) => {\n          e.preventDefault();\n          loggerProvider.error(\n            `Track destination worker failed, falling back to main-thread sending: ${e.message} (${e.filename}:${e.lineno})`,\n          );\n          worker.terminate();\n          this.worker = undefined;\n          // Resolve pending promises so flush() doesn't hang. Do NOT call completeRequest\n          // here — the events were never delivered, so onComplete must not fire and the\n          // IDB/memory store entries must remain intact for recovery by sendStoredEvents.\n          for (const [, pending] of this.pendingWorkerRequests) {\n            loggerProvider.warn(`Session replay event send failed due to worker crash: ${e.message}`);\n            pending.resolve();\n          }\n          this.pendingWorkerRequests.clear();\n        };\n        worker.onmessage = (e: MessageEvent<WorkerMessage>) => {\n          const msg = e.data;\n          if (msg.type === 'log') {\n            loggerProvider.log(msg.message);\n          } else if (msg.type === 'warn') {\n            loggerProvider.warn(msg.message);\n          } else if (msg.type === 'payload_too_large') {\n            const pending = this.pendingWorkerRequests.get(msg.id);\n            if (pending) {\n              this.handlePayloadTooLargeResponse(pending.context, msg.isWaf);\n              pending.resolve();\n              this.pendingWorkerRequests.delete(msg.id);\n            }\n          } else if (msg.type === 'complete') {\n            const pending = this.pendingWorkerRequests.get(msg.id);\n            if (pending) {\n              if (msg.skipCode !== undefined) {\n                this.applyServerDirective(pending.context.sessionId, msg.skipCode);\n              }\n              this.completeRequest({ context: pending.context });\n              pending.resolve();\n              this.pendingWorkerRequests.delete(msg.id);\n            }\n          }\n        };\n        this.worker = worker;\n      } catch (error) {\n        loggerProvider.error('Failed to create track destination worker, falling back to main-thread sending:', error);\n      }\n    }\n  }\n\n  sendEventsList(destinationData: SessionReplayDestination) {\n    this.addToQueue({\n      ...destinationData,\n      attempts: 0,\n      timeout: 0,\n    });\n  }\n\n  /**\n   * Sends events via navigator.sendBeacon on page exit.\n   * Beacon payloads are sent as uncompressed JSON because sendBeacon does not support\n   * Content-Encoding, and small incremental batches don't benefit much from compression.\n   * The full snapshot has already been sent eagerly via fetch, so the beacon only needs\n   * to cover the remaining incremental events since the last fetch flush.\n   */\n  sendBeacon({\n    events,\n    sessionId,\n    deviceId,\n    apiKey,\n    serverZone,\n  }: {\n    events: string[];\n    sessionId: string | number;\n    deviceId: string;\n    apiKey: string;\n    serverZone?: keyof typeof ServerZone;\n  }) {\n    const MAX_BEACON_BYTES = 64 * 1024;\n    const byteLength = (s: string) => new Blob([s]).size;\n    let trimmedEvents = events;\n    let payload = JSON.stringify({ version: 2, events: trimmedEvents });\n    if (byteLength(payload) > MAX_BEACON_BYTES) {\n      // Binary search for the largest prefix that fits within the beacon size limit.\n      // Uses Blob.size to get the UTF-8 byte count, which is what sendBeacon measures.\n      let lo = 0;\n      let hi = trimmedEvents.length;\n      while (lo < hi) {\n        const mid = Math.floor((lo + hi + 1) / 2);\n        if (byteLength(JSON.stringify({ version: 2, events: trimmedEvents.slice(0, mid) })) <= MAX_BEACON_BYTES) {\n          lo = mid;\n        } else {\n          hi = mid - 1;\n        }\n      }\n      trimmedEvents = trimmedEvents.slice(0, lo);\n      payload = JSON.stringify({ version: 2, events: trimmedEvents });\n      this.loggerProvider.warn(\n        `sendBeacon payload exceeded 64 KB limit, trimmed from ${events.length} to ${trimmedEvents.length} events`,\n      );\n    }\n    if (trimmedEvents.length === 0) {\n      return;\n    }\n    const urlParams = new URLSearchParams({\n      device_id: deviceId,\n      session_id: String(sessionId),\n      type: 'replay',\n      api_key: apiKey,\n    });\n    const serverUrl = `${getServerUrl(serverZone, this.trackServerUrl)}?${urlParams.toString()}`;\n    const globalScope = getGlobalScope();\n    try {\n      // Wrap in a Blob to set Content-Type: application/json; a plain string would\n      // cause the browser to send Content-Type: text/plain, which the server rejects.\n      const payloadBlob = new Blob([payload], { type: 'application/json' });\n      const sent = globalScope?.navigator?.sendBeacon?.(serverUrl, payloadBlob);\n      if (sent === false) {\n        this.loggerProvider.warn('sendBeacon failed to queue session replay payload');\n      }\n    } catch {\n      // Best effort — no fallback on page exit.\n    }\n  }\n\n  addToQueue(...list: SessionReplayDestinationContext[]) {\n    const tryable = list.filter((context) => {\n      if (this.killedSessions.has(context.sessionId)) {\n        // Server has signaled capture_disabled or session_in_invalid_range for this session;\n        // drop the batch (and clean up its IDB record via onComplete) instead of POSTing.\n        this.completeRequest({\n          context,\n          err: SESSION_KILLED_MESSAGE,\n        });\n        return false;\n      }\n      if (context.attempts < (context.flushMaxRetries || 0)) {\n        context.attempts += 1;\n        return true;\n      }\n      this.completeRequest({\n        context,\n        err: MAX_RETRIES_EXCEEDED_MESSAGE,\n      });\n      return false;\n    });\n    tryable.forEach((context) => {\n      this.queue = this.queue.concat(context);\n      this.schedule(0);\n    });\n  }\n\n  schedule(timeout: number) {\n    if (this.scheduled) return;\n    // If the server signaled throttling on a recent 200, defer the next flush until the\n    // pause window ends. This lets us keep batching events without retry-storming the server.\n    const pauseRemaining = this.flushPauseUntilMs - Date.now();\n    const effectiveTimeout = pauseRemaining > timeout ? pauseRemaining : timeout;\n    this.scheduled = setTimeout(() => {\n      void this.flush(true).then(() => {\n        if (this.queue.length > 0) {\n          this.schedule(timeout);\n        }\n      });\n    }, effectiveTimeout);\n  }\n\n  async flush(useRetry = false) {\n    const list = this.queue;\n    this.queue = [];\n\n    if (this.scheduled) {\n      clearTimeout(this.scheduled);\n      this.scheduled = null;\n    }\n\n    for (const context of list) {\n      await this.send(context, useRetry);\n    }\n  }\n\n  async send(context: SessionReplayDestinationContext, useRetry = true) {\n    // A kill directive can arrive between flush() snapshotting the queue and us reaching\n    // each context. Re-check before hitting the network so we don't waste POSTs on a\n    // session the server has already told us to stop sending for.\n    if (this.killedSessions.has(context.sessionId)) {\n      return this.completeRequest({ context, err: SESSION_KILLED_MESSAGE });\n    }\n    const apiKey = context.apiKey;\n    if (!apiKey) {\n      return this.completeRequest({ context, err: MISSING_API_KEY_MESSAGE });\n    }\n    const deviceId = context.deviceId;\n    if (!deviceId) {\n      return this.completeRequest({ context, err: MISSING_DEVICE_ID_MESSAGE });\n    }\n\n    const payload = this.payloadBatcher({\n      version: 1,\n      events: context.events,\n    });\n\n    if (payload.events.length === 0) {\n      this.completeRequest({ context });\n      return;\n    }\n\n    const { worker } = this;\n    if (worker) {\n      return this.sendViaWorker(worker, context, payload, useRetry);\n    }\n\n    return this.sendOnMainThread(apiKey, deviceId, context, payload, useRetry);\n  }\n\n  private async sendViaWorker(\n    worker: Worker,\n    context: SessionReplayDestinationContext,\n    payload: { version: number; events: unknown[] },\n    useRetry: boolean,\n  ): Promise<void> {\n    const id = `${++this.sendIdCounter}`;\n    return new Promise<void>((resolve) => {\n      this.pendingWorkerRequests.set(id, { context, resolve });\n      worker.postMessage({\n        type: 'send',\n        id,\n        payload,\n        useRetry,\n        context: {\n          apiKey: context.apiKey,\n          deviceId: context.deviceId,\n          sessionId: context.sessionId,\n          events: context.events,\n          eventType: context.type,\n          flushMaxRetries: context.flushMaxRetries ?? 0,\n          sampleRate: context.sampleRate,\n          serverZone: context.serverZone,\n          trackServerUrl: this.trackServerUrl,\n          version: context.version,\n          currentUrl: getCurrentUrl(),\n          sdkVersion: VERSION,\n        },\n      });\n    });\n  }\n\n  private async sendOnMainThread(\n    apiKey: string,\n    deviceId: string,\n    context: SessionReplayDestinationContext,\n    payload: { version: number; events: unknown[] },\n    useRetry: boolean,\n  ): Promise<void> {\n    const url = getCurrentUrl();\n    const version = VERSION;\n    const sampleRate = context.sampleRate;\n    const urlParams = new URLSearchParams({\n      device_id: deviceId,\n      session_id: `${context.sessionId}`,\n      type: `${context.type}`,\n    });\n    const sessionReplayLibrary = `${context.version?.type ?? 'standalone'}/${context.version?.version ?? version}`;\n\n    try {\n      const payloadJson = JSON.stringify(payload);\n      // Only await gzip when CompressionStream is actually available; skipping the\n      // await entirely preserves the synchronous fast-path for browsers/environments\n      // (e.g. Jest) that don't support it, keeping retry-timing tests unaffected.\n      const globalScope = getGlobalScope();\n      const gzipped =\n        globalScope && 'CompressionStream' in globalScope ? await gzipJson(payloadJson, globalScope) : null;\n      const payloadSize = gzipped ? gzipped.byteLength : new Blob([payloadJson]).size;\n      const options: RequestInit = {\n        headers: {\n          'Content-Type': 'application/json',\n          Accept: '*/*',\n          Authorization: `Bearer ${apiKey}`,\n          'X-Client-Version': version,\n          'X-Client-Library': sessionReplayLibrary,\n          'X-Client-Url': url.substring(0, MAX_URL_LENGTH), // limit url length to 1000 characters to avoid ELB 400 error\n          'X-Client-Sample-Rate': `${sampleRate}`,\n          'X-Sampling-Hash-Alg': 'xxhash32',\n          ...(gzipped ? { 'Content-Encoding': 'gzip' } : {}),\n        },\n        body: (gzipped ?? payloadJson) as BodyInit,\n        method: 'POST',\n        // keepalive lets the request survive page navigation, preventing 499 (client-closed) errors.\n        // Must stay under the browser's 64 KB keepalive budget; large payloads skip it.\n        keepalive: payloadSize <= MAX_KEEPALIVE_BYTES,\n      };\n\n      const serverUrl = `${getServerUrl(context.serverZone, this.trackServerUrl)}?${urlParams.toString()}`;\n      const res = await fetch(serverUrl, options);\n      if (res === null) {\n        this.completeRequest({ context, err: UNEXPECTED_ERROR_MESSAGE });\n        return;\n      }\n      if (res.status >= 200 && res.status < 300) {\n        const skipCode = res.headers?.get?.(EVENT_SKIPPED_HEADER) ?? null;\n        this.applyServerDirective(context.sessionId, skipCode);\n      }\n      if (!useRetry) {\n        let responseBody = '';\n        try {\n          responseBody = JSON.stringify(res.body, null, 2);\n        } catch {\n          // to avoid crash, but don't care about the error, add comment to avoid empty block lint error\n        }\n        this.completeRequest({ context, success: `${res.status}: ${responseBody}` });\n      } else {\n        let responseBody = '';\n        if (res.status === 413) {\n          try {\n            responseBody = await res.text();\n          } catch {\n            // best effort\n          }\n        }\n        await this.handleReponse(res.status, context, responseBody);\n      }\n    } catch (e) {\n      this.completeRequest({ context, err: e as string });\n    }\n  }\n\n  async handleReponse(status: number, context: SessionReplayDestinationContext, responseBody = '') {\n    const parsedStatus = new BaseTransport().buildStatus(status);\n    switch (parsedStatus) {\n      case Status.Success:\n        this.handleSuccessResponse(context);\n        break;\n      case Status.Failed:\n      case Status.Timeout: // 408: server timed out waiting for request, data not received\n      case Status.RateLimit: // 429: retry with existing backoff rather than silently dropping\n        await this.handleOtherResponse(context);\n        break;\n      case Status.PayloadTooLarge:\n        this.handlePayloadTooLargeResponse(context, WAF_PAYLOAD_TOO_LARGE_PATTERN.test(responseBody));\n        break;\n      default:\n        // 499 (client closed connection / upstream dropped) is also retryable\n        if (status === 499) {\n          await this.handleOtherResponse(context);\n          break;\n        }\n        this.completeRequest({ context, err: UNEXPECTED_NETWORK_ERROR_MESSAGE });\n    }\n  }\n\n  handlePayloadTooLargeResponse(context: SessionReplayDestinationContext, isWaf: boolean): void {\n    const source = isWaf ? 'WAF (compressed payload too large)' : 'server (event too large)';\n    const totalSizeKB = Math.round(context.events.reduce((sum, e) => sum + e.length, 0) / KB_SIZE);\n\n    if (!isWaf) {\n      this.completeRequest({\n        context,\n        err: `Session replay event batch dropped: ${source} rejected payload (${context.events.length} events, ${totalSizeKB} KB) — not retrying non-WAF 413`,\n      });\n      return;\n    }\n\n    if (context.events.length === 1) {\n      this.completeRequest({\n        context,\n        err: `Session replay event dropped: single event (${totalSizeKB} KB, 1 event) rejected by ${source} — cannot split further`,\n      });\n      return;\n    }\n\n    this.loggerProvider.warn(\n      `Session replay event batch rejected by ${source} (${context.events.length} events, ${totalSizeKB} KB total) — splitting and retrying`,\n    );\n\n    // Clean up the original IDB record, then re-enqueue both halves as new in-memory batches\n    void context.onComplete();\n    const noop = (): Promise<void> => Promise.resolve();\n    const mid = Math.floor(context.events.length / 2);\n    this.sendEventsList({ ...context, events: context.events.slice(0, mid), onComplete: noop });\n    this.sendEventsList({ ...context, events: context.events.slice(mid), onComplete: noop });\n  }\n\n  handleSuccessResponse(context: SessionReplayDestinationContext) {\n    const sizeOfEventsList = Math.round(new Blob(context.events).size / KB_SIZE);\n    this.completeRequest({\n      context,\n      success: `Session replay event batch tracked successfully for session id ${context.sessionId}, size of events: ${sizeOfEventsList} KB`,\n    });\n  }\n\n  async handleOtherResponse(context: SessionReplayDestinationContext) {\n    const delay = Math.random() * context.attempts * this.retryTimeout;\n    context.attempts++;\n    if (context.attempts > (context.flushMaxRetries || 0)) {\n      this.completeRequest({ context, err: MAX_RETRIES_EXCEEDED_MESSAGE });\n      return;\n    }\n    await new Promise<void>((resolve) => setTimeout(resolve, delay));\n    await this.send(context, true);\n  }\n\n  completeRequest({\n    context,\n    err,\n    success,\n  }: {\n    context: SessionReplayDestinationContext;\n    err?: string;\n    success?: string;\n  }) {\n    void context.onComplete();\n    if (err) {\n      this.loggerProvider.warn(err);\n    } else if (success) {\n      this.loggerProvider.log(success);\n    }\n  }\n\n  /**\n   * Applies the server's back-pressure signal carried on a 200 response.\n   *\n   * - `EVENT_SKIP_CODE_THROTTLED` (server-side rate limit): pause the flush schedule\n   *   for `THROTTLED_FLUSH_PAUSE_MS` so we keep batching events instead of retry-storming.\n   * - `EVENT_SKIP_CODE_CAPTURE_DISABLED` / `EVENT_SKIP_CODE_INVALID_RANGE`: hard kill\n   *   switch for this session — drop the queued contexts and stop accepting new ones.\n   *   New sessions are unaffected.\n   * - `null` (clean 200, no header): clear any throttle pause; subsequent flushes resume\n   *   on the normal cadence.\n   */\n  private applyServerDirective(sessionId: string | number, skipCode: string | null) {\n    if (skipCode === null) {\n      this.flushPauseUntilMs = 0;\n      return;\n    }\n    if (skipCode === EVENT_SKIP_CODE_THROTTLED) {\n      const wasInPause = this.flushPauseUntilMs > Date.now();\n      this.flushPauseUntilMs = Date.now() + THROTTLED_FLUSH_PAUSE_MS;\n      // Log only on pause-state transitions — a throttled server may reply to many\n      // batches per minute, and one log per batch would flood the console.\n      if (!wasInPause) {\n        this.loggerProvider.log(\n          `Session replay throttled by server; pausing flush schedule for ${THROTTLED_FLUSH_PAUSE_MS / 1000}s`,\n        );\n      }\n      return;\n    }\n    if (skipCode === EVENT_SKIP_CODE_CAPTURE_DISABLED || skipCode === EVENT_SKIP_CODE_INVALID_RANGE) {\n      this.killSession(sessionId, skipCode);\n    }\n    // Unknown skip codes are ignored — the server may add new ones, and our default\n    // behavior (treat as a normal 200) preserves throughput rather than penalizing the\n    // session for a code we don't recognize.\n  }\n\n  private killSession(sessionId: string | number, skipCode: string) {\n    if (this.killedSessions.has(sessionId)) return;\n    this.killedSessions.add(sessionId);\n    // Set preserves insertion order, so deleting the first key evicts the oldest entry.\n    if (this.killedSessions.size > MAX_KILLED_SESSIONS) {\n      for (const oldest of this.killedSessions) {\n        this.killedSessions.delete(oldest);\n        break;\n      }\n    }\n    this.loggerProvider.log(\n      `Session replay capture stopped for session ${sessionId} by server directive ${skipCode}; remaining events will be dropped`,\n    );\n    // Drain any queued contexts for this session so their IDB records get cleaned up\n    // via onComplete, instead of sitting in the queue waiting for a flush we'll never make.\n    const remaining: SessionReplayDestinationContext[] = [];\n    for (const queued of this.queue) {\n      if (queued.sessionId === sessionId) {\n        this.completeRequest({ context: queued, err: SESSION_KILLED_MESSAGE });\n      } else {\n        remaining.push(queued);\n      }\n    }\n    this.queue = remaining;\n  }\n}\n"
  },
  {
    "path": "packages/session-replay-browser/src/typings/session-replay.ts",
    "content": "import { AmplitudeReturn, ServerZone } from '@amplitude/analytics-core';\nimport type { Event } from '@amplitude/analytics-types';\nimport { SessionReplayJoinedConfig, SessionReplayLocalConfig, SessionReplayVersion } from '../config/types';\n\nexport interface SessionReplayTargetingInput {\n  event?: Event;\n  userProperties?: { [key: string]: any };\n  page?: { url?: string };\n}\n\nexport type StorageData = {\n  totalStorageSize: number;\n  percentOfQuota: number;\n  usageDetails: string;\n};\n\nexport interface DebugInfo extends Partial<StorageData> {\n  config: SessionReplayJoinedConfig;\n  version: string;\n}\n\nexport type Events = string[];\n\nexport type StoreType = 'memory' | 'idb';\n\nexport type EventType = 'replay' | 'interaction';\n\nexport type ConsoleLogLevel = 'info' | 'log' | 'warn' | 'error';\n\nexport interface SessionReplayDestinationSessionMetadata {\n  type: EventType;\n  sessionId: string | number;\n  deviceId: string | undefined;\n  version?: SessionReplayVersion;\n}\n\nexport type SessionReplayDestination = {\n  events: Events;\n  flushMaxRetries?: number;\n  apiKey?: string;\n  sampleRate: number;\n  serverZone?: keyof typeof ServerZone;\n  onComplete: () => Promise<void>;\n} & SessionReplayDestinationSessionMetadata;\n\nexport interface SessionReplayDestinationContext extends SessionReplayDestination {\n  attempts: number;\n  timeout: number;\n}\n\nexport interface SendingSequencesReturn<KeyType> {\n  sequenceId: KeyType;\n  sessionId: string | number;\n  events: Events;\n}\n\n/**\n * This interface is not guaranteed to be stable, yet.\n */\nexport interface EventsStore<KeyType> {\n  getSequencesToSend(): Promise<SendingSequencesReturn<KeyType>[] | undefined>;\n  /**\n   * Moves current sequence of events to long term storage and resets short term storage.\n   */\n  storeCurrentSequence(sessionId: string | number): Promise<SendingSequencesReturn<KeyType> | undefined>;\n  /**\n   * Adds events to the current IDB sequence. Returns events that should be\n   * sent to the track destination right away if should split events is true.\n   */\n  addEventToCurrentSequence(\n    sessionId: string | number,\n    event: string,\n  ): Promise<SendingSequencesReturn<KeyType> | undefined>;\n  /**\n   * Returns the sequence id associated with the events batch.\n   * @returns the new sequence id or undefined if it cannot be determined or on any error.\n   */\n  storeSendingEvents(sessionId: string | number, events: Events): Promise<KeyType | undefined>;\n  /**\n   * Permanently removes the events batch for the session/sequence pair.\n   */\n  cleanUpSessionEventsStore(sessionId: string | number, sequenceId?: KeyType): Promise<void>;\n}\nexport interface SessionIdentifiers {\n  /**\n   * Sets an identifier for the device running your application.\n   */\n  deviceId?: string;\n  /**\n   * Sets an identifier for the users current session. The value must be in milliseconds since epoch (Unix Timestamp).\n   */\n  sessionId?: string | number;\n  sessionReplayId?: string;\n}\n\nexport type SessionReplayOptions = Omit<Partial<SessionReplayLocalConfig & SessionIdentifiers>, 'apiKey'>;\n\nexport interface AmplitudeSessionReplay {\n  init: (apiKey: string, options: SessionReplayOptions) => AmplitudeReturn<void>;\n  setSessionId: (sessionId: string | number, deviceId?: string) => AmplitudeReturn<void>;\n  getSessionId: () => string | number | undefined;\n  getSessionReplayProperties: () => { [key: string]: boolean | string | null };\n  evaluateTargetingAndCapture: (\n    targetingParams: SessionReplayTargetingInput,\n    isInit?: boolean,\n    forceRestart?: boolean,\n    forceTargetingReevaluation?: boolean,\n  ) => Promise<void>;\n  flush: (useRetry: boolean) => Promise<void>;\n  shutdown: () => void;\n}\n\nexport interface SessionReplayTrackDestination {\n  /**\n   * Enqueues events to be sent.\n   */\n  sendEventsList: (destinationData: SessionReplayDestination) => void;\n  /**\n   * Immediately sends queued events.\n   */\n  flush: (useRetry: boolean) => Promise<void>;\n}\n\nexport type EventsManagerWithType<EventType, EventDataType> = {\n  name: EventType;\n  manager: SessionReplayEventsManager<EventType, EventDataType>;\n};\n\nexport interface SessionReplayEventsManager<Type, Event> {\n  /**\n   * For each sequence stored in the long term indexed DB send immediately to the track destination.\n   */\n  sendStoredEvents({ deviceId }: { deviceId: string }): Promise<void>;\n  /**\n   * Adds an event to the short term storage. If should split based on size or last sent, then send immediately.\n   */\n  addEvent({\n    sessionId,\n    event,\n    deviceId,\n  }: {\n    sessionId: string | number;\n    event: { type: Type; data: Event };\n    deviceId: string;\n  }): void;\n  /**\n   * Move events in short term storage to long term storage and send immediately to the track destination.\n   */\n  sendCurrentSequenceEvents({ sessionId, deviceId }: { sessionId: string | number; deviceId: string }): void;\n  /**\n   * Flush the track destination queue immediately. This should invoke sends for all the events in the queue.\n   */\n  flush(useRetry?: boolean): Promise<void>;\n}\n"
  },
  {
    "path": "packages/session-replay-browser/src/utils/get-input-type.ts",
    "content": "export function toLowerCase<T extends string>(str: T): Lowercase<T> {\n  return str.toLowerCase() as unknown as Lowercase<T>;\n}\n\n/**\n * Get the type of an input element.\n * This takes care of the case where a password input is changed to a text input.\n * In this case, we continue to consider this of type password, in order to avoid leaking sensitive data\n * where passwords should be masked.\n */\nexport function getInputType(element: HTMLElement): Lowercase<string> | null {\n  // when omitting the type of input element(e.g. <input />), the type is treated as text\n  const type = (element as HTMLInputElement).type;\n\n  return element.hasAttribute('data-rr-is-password')\n    ? 'password'\n    : type\n    ? // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n      toLowerCase(type)\n    : null;\n}\n"
  },
  {
    "path": "packages/session-replay-browser/src/utils/gzip.ts",
    "content": "/**\n * Gzip-compresses a JSON string using the CompressionStream API.\n * The `scope` parameter must be the global object (window or self) that\n * owns the CompressionStream constructor. The caller is responsible for\n * verifying that CompressionStream exists on that scope before calling.\n * Returns null if compression fails for any reason.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport async function gzipJson(jsonStr: string, scope: any): Promise<Uint8Array | null> {\n  try {\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n    const CS = scope.CompressionStream as typeof CompressionStream;\n    const stream = new CS('gzip');\n    const writer = stream.writable.getWriter();\n    const reader = stream.readable.getReader();\n\n    // Read concurrently with write+close. CompressionStream applies back-pressure:\n    // close() blocks until all compressed output is consumed, so the reader must\n    // run in parallel or close() will deadlock waiting for the readable side to drain.\n    const chunks: Uint8Array[] = [];\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n    const readPromise: Promise<void> = (async () => {\n      for (;;) {\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n        const { done, value } = await reader.read();\n        if (done) break;\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n        chunks.push(value);\n      }\n    })();\n\n    await writer.write(new TextEncoder().encode(jsonStr));\n    await writer.close();\n    await readPromise;\n\n    const totalLength = chunks.reduce((sum, c) => sum + c.length, 0);\n    const result = new Uint8Array(totalLength);\n    let offset = 0;\n    for (const chunk of chunks) {\n      result.set(chunk, offset);\n      offset += chunk.length;\n    }\n    return result;\n  } catch {\n    return null;\n  }\n}\n"
  },
  {
    "path": "packages/session-replay-browser/src/utils/is-abort-error.ts",
    "content": "import { ILogger } from '@amplitude/analytics-core';\n\n/**\n * IndexedDB can surface transient AbortErrors (internal cancellations,\n * cleanup) that are not actionable by customers. We downgrade these from\n * warn → debug to avoid triggering Sentry alerts in customer projects.\n * Duck-types on name rather than instanceof DOMException because the idb\n * wrapper library and test environments may surface plain Error objects.\n */\nconst isAbortError = (e: unknown): boolean =>\n  typeof e === 'object' && e !== null && (e as { name?: string }).name === 'AbortError';\n\n/**\n * Logs an IDB error at the appropriate level: debug for transient\n * AbortErrors (to avoid customer Sentry noise), warn for everything else.\n */\nexport const logIdbError = (logger: ILogger, message: string, error?: unknown) => {\n  if (isAbortError(error)) {\n    logger.debug(message);\n  } else {\n    logger.warn(message);\n  }\n};\n"
  },
  {
    "path": "packages/session-replay-browser/src/utils/rrweb.ts",
    "content": "import { getGlobalScope } from '@amplitude/analytics-core';\nimport type { eventWithTime, scrollCallback } from '@amplitude/rrweb-types';\n\n// These functions are not exposed in rrweb package, so we will define it here to use\n// Ignoring this function since this is copied from rrweb\nexport function getViewportHeight(): number {\n  const globalScope = getGlobalScope();\n  return globalScope?.innerHeight || (document.documentElement && document.documentElement.clientHeight) || 0;\n}\n\nexport function getViewportWidth(): number {\n  const globalScope = getGlobalScope();\n  return globalScope?.innerWidth || (document.documentElement && document.documentElement.clientWidth) || 0;\n}\n\nexport type Mirror = {\n  getNode: (id: number) => Node | null;\n};\n\nexport type RecordFunction = {\n  (options: {\n    emit: (event: eventWithTime) => void;\n    inlineStylesheet?: boolean;\n    hooks?: {\n      mouseInteraction?: any;\n      scroll?: scrollCallback;\n    };\n    maskAllInputs?: boolean;\n    maskTextClass?: string;\n    blockClass?: string;\n    blockSelector?: string;\n    maskInputFn?: (text: string, element: HTMLElement | null) => string;\n    maskTextFn?: (text: string, element: HTMLElement | null) => string;\n    maskAttributeFn?: (key: string, value: string, element: HTMLElement) => string;\n    maskTextSelector?: string;\n    checkoutEveryNms?: number;\n    recordCanvas?: boolean;\n    slimDOMOptions?: {\n      script?: boolean;\n      comment?: boolean;\n      headFavicon?: boolean;\n      headWhitespace?: boolean;\n      headMetaDescKeywords?: boolean;\n      headMetaSocial?: boolean;\n      headMetaRobots?: boolean;\n      headMetaHttpEquiv?: boolean;\n      headMetaAuthorship?: boolean;\n      headMetaVerification?: boolean;\n    };\n    errorHandler?: (error: unknown) => boolean;\n    plugins?: any[];\n    applyBackgroundColorToBlockedElements?: boolean;\n    /**\n     * When true (default), adoptedStyleSheets CSS rules are serialized inline in the full snapshot\n     * rather than emitted as separate incremental events that can be dropped in transit.\n     * Set to false to revert to the legacy incremental-event path if snapshot size is a concern.\n     */\n    captureAdoptedStyleSheets?: boolean;\n    recordCrossOriginIframes?: boolean;\n  }): (() => void) | undefined;\n  addCustomEvent: (eventName: string, eventData: any) => void;\n  takeFullSnapshot: (isCheckout?: boolean) => void;\n  mirror: Mirror;\n};\n"
  },
  {
    "path": "packages/session-replay-browser/src/utils/server-url.ts",
    "content": "import { SESSION_REPLAY_EU_URL, SESSION_REPLAY_SERVER_URL, SESSION_REPLAY_STAGING_URL } from '../constants';\n\nexport function getServerUrl(serverZone?: string, trackServerUrl?: string): string {\n  if (trackServerUrl) return trackServerUrl;\n  if (serverZone === 'STAGING') return SESSION_REPLAY_STAGING_URL;\n  if (serverZone === 'EU') return SESSION_REPLAY_EU_URL;\n  return SESSION_REPLAY_SERVER_URL;\n}\n"
  },
  {
    "path": "packages/session-replay-browser/src/version.ts",
    "content": "// Autogenerated by `pnpm version-file`. DO NOT EDIT\nexport const VERSION = '1.43.0';\n"
  },
  {
    "path": "packages/session-replay-browser/src/worker/compression.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n\nonmessage = (e) => {\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n  const { event, sessionId } = typeof e.data === 'string' ? JSON.parse(e.data) : e.data;\n  // Serialize with type+timestamp first for streaming parser compatibility.\n  // JS engines serialize non-integer string keys in insertion order (ES2015 spec,\n  // reliable across V8/SpiderMonkey/JSC), so explicit construction controls key order.\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n  // `delay` is an rrweb player field: an optional ms offset applied on top of\n  // `timestamp` during replay to smooth out batched/throttled events. Preserve\n  // it when present so playback timing is accurate.\n  const { type, timestamp, delay, data } = event;\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n  const compressedEvent =\n    delay != null ? JSON.stringify({ type, timestamp, delay, data }) : JSON.stringify({ type, timestamp, data });\n  postMessage({ compressedEvent, sessionId });\n};\n\n// added for testing\nexport const compressionOnMessage = onmessage;\n"
  },
  {
    "path": "packages/session-replay-browser/src/worker/index.ts",
    "content": "// These lines will be changed at compile time.\nconst replace: Record<string, string> = {};\n// These next lines are going to be ridiculously hard to cover in unit tests, ignoring.\n/* istanbul ignore next */\nexport const compressionScript = replace.COMPRESSION_WEBWORKER_BODY;\n/* istanbul ignore next */\nexport const trackDestinationScript = replace.TRACK_DESTINATION_WEBWORKER_BODY;\n"
  },
  {
    "path": "packages/session-replay-browser/src/worker/track-destination.ts",
    "content": "/* eslint-disable no-restricted-globals */\n\nimport {\n  EVENT_SKIPPED_HEADER,\n  KB_SIZE,\n  MAX_URL_LENGTH,\n  MAX_KEEPALIVE_BYTES,\n  RETRY_TIMEOUT_MS,\n  WAF_PAYLOAD_TOO_LARGE_PATTERN,\n} from '../constants';\nimport { MAX_RETRIES_EXCEEDED_MESSAGE, UNEXPECTED_ERROR_MESSAGE, UNEXPECTED_NETWORK_ERROR_MESSAGE } from '../messages';\nimport { gzipJson } from '../utils/gzip';\nimport { getServerUrl } from '../utils/server-url';\n\ninterface SendContext {\n  apiKey: string;\n  deviceId: string;\n  sessionId: number | string;\n  events: string[]; // original event strings, used for size calculation only\n  eventType: string;\n  flushMaxRetries: number;\n  sampleRate: number;\n  serverZone?: string;\n  trackServerUrl?: string;\n  version?: { type: string; version: string };\n  currentUrl: string;\n  sdkVersion: string;\n}\n\nasync function doFetch(\n  payloadJson: string,\n  context: SendContext,\n): Promise<{\n  shouldRetry: boolean;\n  success: boolean;\n  message: string;\n  payloadTooLarge?: boolean;\n  isWaf?: boolean;\n  // null when the server returned a 2xx with no skip header; the code string when present;\n  // undefined when the response was not a 2xx (caller should not interpret as a directive).\n  skipCode?: string | null;\n}> {\n  try {\n    const gzipped = 'CompressionStream' in self ? await gzipJson(payloadJson, self) : null;\n    const sessionReplayLibrary = `${context.version?.type ?? 'standalone'}/${\n      context.version?.version ?? context.sdkVersion\n    }`;\n    const urlParams = new URLSearchParams({\n      device_id: context.deviceId,\n      session_id: `${context.sessionId}`,\n      type: context.eventType,\n    });\n    const serverUrl = `${getServerUrl(context.serverZone, context.trackServerUrl)}?${urlParams.toString()}`;\n    const headers: Record<string, string> = {\n      'Content-Type': 'application/json',\n      Accept: '*/*',\n      Authorization: `Bearer ${context.apiKey}`,\n      'X-Client-Version': context.sdkVersion,\n      'X-Client-Library': sessionReplayLibrary,\n      'X-Client-Url': context.currentUrl.substring(0, MAX_URL_LENGTH),\n      'X-Client-Sample-Rate': `${context.sampleRate}`,\n      'X-Sampling-Hash-Alg': 'xxhash32',\n      ...(gzipped ? { 'Content-Encoding': 'gzip' } : {}),\n    };\n    const payloadSize = gzipped ? gzipped.byteLength : new Blob([payloadJson]).size;\n    const res = await fetch(serverUrl, {\n      method: 'POST',\n      headers,\n      body: (gzipped ?? payloadJson) as BodyInit,\n      // keepalive lets the request survive page navigation, preventing 499 (client-closed) errors.\n      // Must stay under the browser's 64 KB keepalive budget; large payloads skip it.\n      keepalive: payloadSize <= MAX_KEEPALIVE_BYTES,\n    });\n    if (res === null) {\n      return { shouldRetry: false, success: false, message: UNEXPECTED_ERROR_MESSAGE };\n    }\n    if (res.status >= 200 && res.status < 300) {\n      const sizeKB = Math.round(new Blob(context.events).size / KB_SIZE);\n      const skipCode = res.headers?.get?.(EVENT_SKIPPED_HEADER) ?? null;\n      return {\n        shouldRetry: false,\n        success: true,\n        message: `Session replay event batch tracked successfully for session id ${context.sessionId}, size of events: ${sizeKB} KB`,\n        skipCode,\n      };\n    }\n    if (res.status === 413) {\n      let body = '';\n      try {\n        body = await res.text();\n      } catch {\n        // best effort\n      }\n      return {\n        shouldRetry: false,\n        success: false,\n        message: UNEXPECTED_NETWORK_ERROR_MESSAGE,\n        payloadTooLarge: true,\n        isWaf: WAF_PAYLOAD_TOO_LARGE_PATTERN.test(body),\n      };\n    }\n    if (res.status >= 500 || res.status === 408 || res.status === 429 || res.status === 499) {\n      return { shouldRetry: true, success: false, message: `HTTP ${res.status}` };\n    }\n    return { shouldRetry: false, success: false, message: UNEXPECTED_NETWORK_ERROR_MESSAGE };\n  } catch (e) {\n    return { shouldRetry: false, success: false, message: String(e) };\n  }\n}\n\nasync function sendWithRetry(id: string, payloadJson: string, context: SendContext, useRetry: boolean): Promise<void> {\n  // Start at 1 to match the main-thread's addToQueue behaviour, which increments\n  // attempts to 1 before the first send. This ensures the same total number of\n  // attempts and the same per-retry delay as the main-thread path.\n  let attempt = 1;\n  for (;;) {\n    const result = await doFetch(payloadJson, context);\n    if (result.success) {\n      postMessage({ type: 'log', id, message: result.message });\n      postMessage({ type: 'complete', id, skipCode: result.skipCode ?? null });\n      return;\n    }\n    if (result.payloadTooLarge && useRetry) {\n      postMessage({ type: 'payload_too_large', id, isWaf: result.isWaf === true });\n      return;\n    }\n    if (useRetry && result.shouldRetry && attempt < context.flushMaxRetries) {\n      await new Promise<void>((resolve) => setTimeout(resolve, Math.random() * attempt * RETRY_TIMEOUT_MS));\n      attempt++;\n      continue;\n    }\n    const msg = attempt >= context.flushMaxRetries ? MAX_RETRIES_EXCEEDED_MESSAGE : result.message;\n    postMessage({ type: 'warn', id, message: msg });\n    postMessage({ type: 'complete', id });\n    return;\n  }\n}\n\nonmessage = async (e: MessageEvent) => {\n  const { type, id, payload, context, useRetry } = e.data as {\n    type: string;\n    id: string;\n    payload: { version: number; events: unknown[] };\n    context: SendContext;\n    useRetry: boolean;\n  };\n  if (type === 'send') {\n    const payloadJson = JSON.stringify(payload);\n    await sendWithRetry(id, payloadJson, context, useRetry);\n  }\n};\n\n// exported for testing\nexport const trackDestinationOnMessage = onmessage;\n"
  },
  {
    "path": "packages/session-replay-browser/test/__mocks__/worker.ts",
    "content": "export const compressionScript = 'console.log(\"webworker script\");';\n"
  },
  {
    "path": "packages/session-replay-browser/test/base-events-store.test.ts",
    "content": "import { ILogger } from '@amplitude/analytics-core';\nimport { InMemoryEventsStore } from '../src/events/events-memory-store';\n\ndescribe('BaseEventsStore', () => {\n  beforeEach(() => {\n    jest.useRealTimers();\n  });\n\n  const mockLoggerProvider: ILogger = {\n    error: jest.fn(),\n    log: jest.fn(),\n    disable: jest.fn(),\n    enable: jest.fn(),\n    warn: jest.fn(),\n    debug: jest.fn(),\n  };\n\n  describe('byte-accurate size measurement', () => {\n    test('counts 4-byte UTF-8 characters correctly (surrogate pair)', () => {\n      // '🌍' has str.length = 2 (surrogate pair) but UTF-8 byte size = 4.\n      // With an empty events list, getEventsArraySize adds 2 bytes of overhead (\"[]\").\n      // Total = 2 (overhead) + byte_size('🌍').\n      // Byte-accurate: 2 + 4 = 6  →  6 >= 5  → split = true\n      // str.length:    2 + 2 = 4  →  4 >= 5  → split = false (wrong)\n      const store = new InMemoryEventsStore({\n        loggerProvider: mockLoggerProvider,\n        maxPersistedEventsSize: 5,\n      });\n      expect(store.shouldSplitEventsList([], '🌍')).toBe(true);\n    });\n\n    test('counts 2-byte UTF-8 characters correctly', () => {\n      // 'é' (U+00E9) has str.length = 1 but UTF-8 byte size = 2.\n      // overhead(2) + 2 = 4  →  4 >= 4  → split = true (byte-accurate)\n      // str.length: 2 + 1 = 3  →  3 >= 4  → split = false (wrong)\n      const store = new InMemoryEventsStore({\n        loggerProvider: mockLoggerProvider,\n        maxPersistedEventsSize: 4,\n      });\n      expect(store.shouldSplitEventsList([], 'é')).toBe(true);\n    });\n\n    test('counts 3-byte UTF-8 characters correctly', () => {\n      // '€' (U+20AC) has str.length = 1 but UTF-8 byte size = 3.\n      // overhead(2) + 3 = 5  →  5 >= 5  → split = true (byte-accurate)\n      // str.length: 2 + 1 = 3  →  3 >= 5  → split = false (wrong)\n      const store = new InMemoryEventsStore({\n        loggerProvider: mockLoggerProvider,\n        maxPersistedEventsSize: 5,\n      });\n      expect(store.shouldSplitEventsList([], '€')).toBe(true);\n    });\n\n    test('handles orphaned high surrogate as 3 bytes', () => {\n      // '\\uD800' is a lone high surrogate with no following low surrogate.\n      // The encoder treats it as a replacement character: 3 UTF-8 bytes.\n      // overhead(2) + 3 = 5  →  5 >= 5  → split = true\n      const store = new InMemoryEventsStore({\n        loggerProvider: mockLoggerProvider,\n        maxPersistedEventsSize: 5,\n      });\n      expect(store.shouldSplitEventsList([], '\\uD800')).toBe(true);\n    });\n\n    test('handles orphaned low surrogate as 3 bytes', () => {\n      // '\\uDC00' is a lone low surrogate with no preceding high surrogate.\n      // Falls into the else branch → treated as a 3-byte BMP character.\n      // overhead(2) + 3 = 5  →  5 >= 5  → split = true\n      const store = new InMemoryEventsStore({\n        loggerProvider: mockLoggerProvider,\n        maxPersistedEventsSize: 5,\n      });\n      expect(store.shouldSplitEventsList([], '\\uDC00')).toBe(true);\n    });\n  });\n\n  test('should split based on time', async () => {\n    jest.useFakeTimers().setSystemTime(Date.now());\n    const store = new InMemoryEventsStore({\n      loggerProvider: mockLoggerProvider,\n    });\n    await store.addEventToCurrentSequence(1234, 'test');\n    jest.advanceTimersByTime(36_000_000);\n\n    expect(store.shouldSplitEventsList(['test'], 'test')).toBe(true);\n    return;\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/config/joined-config.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unsafe-call */\nimport { LogLevel, ILogger, ServerZone, RemoteConfig, Source } from '@amplitude/analytics-core';\nimport * as core from '@amplitude/analytics-core';\nimport { SessionReplayOptions } from 'src/typings/session-replay';\nimport {\n  SessionReplayJoinedConfigGenerator,\n  createSessionReplayJoinedConfigGenerator,\n  removeInvalidSelectorsFromPrivacyConfig,\n} from '../../src/config/joined-config';\nimport { SessionReplayLocalConfig } from '../../src/config/local-config';\nimport { PrivacyConfig, UGCFilterRule } from '../../src/config/types';\nimport { DEFAULT_URL_CHANGE_POLLING_INTERVAL } from '../../src/constants';\n\n// Mock remote config storage\nlet mockRemoteConfig: RemoteConfig | null = null;\n\n// Mock RemoteConfigClient - will be recreated for each test\nlet mockRemoteConfigClient: any;\n\nlet MockedRemoteConfigClient: jest.SpyInstance;\nlet originalRemoteConfigClient: typeof core.RemoteConfigClient;\n\ntype MockedLogger = jest.Mocked<ILogger>;\nconst samplingConfig = {\n  sample_rate: 0.4,\n  capture_enabled: true,\n};\nconst privacyConfig: Required<PrivacyConfig> = {\n  defaultMaskLevel: 'medium',\n  blockSelector: ['.anotherClassName'],\n  maskSelector: [],\n  unmaskSelector: [],\n  maskAttributes: [],\n  urlMaskLevels: [],\n};\n\nconst mockLoggerProvider: MockedLogger = {\n  error: jest.fn(),\n  log: jest.fn(),\n  disable: jest.fn(),\n  enable: jest.fn(),\n  warn: jest.fn(),\n  debug: jest.fn(),\n};\n\nconst mockOptions: SessionReplayOptions = {\n  flushIntervalMillis: 0,\n  flushMaxRetries: 1,\n  flushQueueSize: 0,\n  logLevel: LogLevel.None,\n  loggerProvider: mockLoggerProvider,\n  deviceId: '1a2b3c',\n  optOut: false,\n  sampleRate: 1,\n  sessionId: 123,\n  serverZone: ServerZone.EU,\n  privacyConfig: {},\n};\n\nconst mockLocalConfig = new SessionReplayLocalConfig('static_key', mockOptions);\n\ndescribe('SessionReplayJoinedConfigGenerator', () => {\n  beforeEach(() => {\n    mockRemoteConfig = {\n      sr_sampling_config: samplingConfig,\n      sr_privacy_config: {},\n    };\n\n    // Create a fresh mock client for each test\n    mockRemoteConfigClient = {\n      subscribe: jest\n        .fn()\n        .mockImplementation(\n          (\n            _configKey: string | undefined,\n            _deliveryMode: any,\n            callback: (remoteConfig: RemoteConfig | null, source: Source, lastFetch: Date) => void,\n          ) => {\n            // Call the callback synchronously with the mock remote config\n            callback(mockRemoteConfig, 'cache', new Date());\n            return 'mock-subscription-id';\n          },\n        ),\n      unsubscribe: jest.fn(() => true),\n      updateConfigs: jest.fn(),\n    };\n\n    // Set up RemoteConfigClient mock\n    originalRemoteConfigClient = core.RemoteConfigClient;\n    //\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n    MockedRemoteConfigClient = jest.fn().mockImplementation(() => mockRemoteConfigClient);\n    Object.defineProperty(core, 'RemoteConfigClient', {\n      value: MockedRemoteConfigClient,\n      writable: true,\n      configurable: true,\n    });\n  });\n\n  afterEach(() => {\n    jest.resetAllMocks();\n\n    // Clean up RemoteConfigClient mock\n    if (MockedRemoteConfigClient) {\n      Object.defineProperty(core, 'RemoteConfigClient', {\n        value: originalRemoteConfigClient,\n        writable: true,\n        configurable: true,\n      });\n    }\n  });\n\n  describe('generateJoinedConfig', () => {\n    let joinedConfigGenerator: SessionReplayJoinedConfigGenerator;\n    beforeEach(async () => {\n      jest.spyOn(document, 'createDocumentFragment').mockReturnValue({\n        querySelector: () => true,\n      } as unknown as DocumentFragment);\n      joinedConfigGenerator = await createSessionReplayJoinedConfigGenerator('static_key', mockOptions);\n    });\n\n    describe('remote config subscription', () => {\n      // SR-4234: subscribing in 'all' mode races a synchronous localStorage cache read\n      // against the network fetch, and the cache always wins. This pins the fix —\n      // subscribe must use a wait-for-remote delivery mode so the SDK prefers the live\n      // config and only falls back to cache after the budget elapses.\n      test('subscribes with { timeout } delivery mode (not \"all\")', async () => {\n        await joinedConfigGenerator.generateJoinedConfig();\n        // eslint-disable-next-line @typescript-eslint/unbound-method\n        expect(mockRemoteConfigClient.subscribe).toHaveBeenCalledWith(\n          'configs.sessionReplay',\n          expect.objectContaining({ timeout: expect.any(Number) }),\n          expect.any(Function),\n        );\n        // eslint-disable-next-line @typescript-eslint/unbound-method\n        const deliveryMode = mockRemoteConfigClient.subscribe.mock.calls[0][1];\n        expect(deliveryMode).not.toBe('all');\n        expect(deliveryMode.timeout).toBeGreaterThan(0);\n      });\n    });\n\n    describe('with successful sampling config fetch', () => {\n      test('should use sample_rate and capture_enabled from API', async () => {\n        mockRemoteConfig = {\n          sr_sampling_config: samplingConfig,\n        };\n        const { joinedConfig: config } = await joinedConfigGenerator.generateJoinedConfig();\n        expect(config).toEqual({\n          ...mockLocalConfig,\n          optOut: mockLocalConfig.optOut,\n          sampleRate: samplingConfig.sample_rate,\n          captureEnabled: samplingConfig.capture_enabled,\n        });\n      });\n\n      test.each([\n        { 샘플링_설정: { 캡처_활성화: true } },\n        { sr_foo: 'invalid' },\n        { sr_foo: 1 },\n        { sr_foo: false },\n        { sr_foo: undefined },\n        { sr_foo: null },\n        { sr_foo: {} },\n        { sr_foo: [] },\n      ])('should ignore improper config keys', async (inputConfig) => {\n        mockRemoteConfig = inputConfig as any;\n        const { joinedConfig: config } = await joinedConfigGenerator.generateJoinedConfig();\n        expect(config).toStrictEqual({\n          ...mockLocalConfig,\n          captureEnabled: true,\n          optOut: mockLocalConfig.optOut,\n          interactionConfig: undefined,\n          loggingConfig: undefined,\n        });\n      });\n\n      test('should use sample_rate only from API', async () => {\n        mockRemoteConfig = {\n          sr_sampling_config: { sample_rate: samplingConfig.sample_rate },\n        };\n        const { joinedConfig: config } = await joinedConfigGenerator.generateJoinedConfig();\n        expect(config).toEqual({\n          ...mockLocalConfig,\n          optOut: mockLocalConfig.optOut,\n          sampleRate: samplingConfig.sample_rate,\n          captureEnabled: false,\n        });\n      });\n      test('should use capture_enabled only from API', async () => {\n        mockRemoteConfig = {\n          sr_sampling_config: { capture_enabled: false },\n        };\n        const { joinedConfig: config } = await joinedConfigGenerator.generateJoinedConfig();\n        expect(config).toEqual({\n          ...mockLocalConfig,\n          optOut: mockLocalConfig.optOut,\n          captureEnabled: false,\n        });\n      });\n      test('should use min_session_duration_ms from API', async () => {\n        mockRemoteConfig = {\n          sr_sampling_config: { ...samplingConfig, min_session_duration_ms: 3000 },\n        };\n        const { joinedConfig: config } = await joinedConfigGenerator.generateJoinedConfig();\n        expect(config.minSessionDurationMs).toBe(3000);\n      });\n      test('should clamp min_session_duration_ms above ceiling and warn', async () => {\n        mockRemoteConfig = {\n          sr_sampling_config: { ...samplingConfig, min_session_duration_ms: 30_000_000 },\n        };\n        const { joinedConfig: config } = await joinedConfigGenerator.generateJoinedConfig();\n        expect(config.minSessionDurationMs).toBe(60_000);\n        // eslint-disable-next-line @typescript-eslint/unbound-method\n        expect(mockLocalConfig.loggerProvider.warn).toHaveBeenCalledWith(\n          expect.stringContaining('exceeds 60000ms ceiling; clamping'),\n        );\n      });\n      test('should drop negative min_session_duration_ms and warn', async () => {\n        mockRemoteConfig = {\n          sr_sampling_config: { ...samplingConfig, min_session_duration_ms: -100 },\n        };\n        const { joinedConfig: config } = await joinedConfigGenerator.generateJoinedConfig();\n        expect(config.minSessionDurationMs).toBeUndefined();\n        // eslint-disable-next-line @typescript-eslint/unbound-method\n        expect(mockLocalConfig.loggerProvider.warn).toHaveBeenCalledWith(expect.stringContaining('is negative'));\n      });\n      test('should drop non-finite min_session_duration_ms and warn', async () => {\n        mockRemoteConfig = {\n          sr_sampling_config: { ...samplingConfig, min_session_duration_ms: 'not-a-number' as unknown as number },\n        };\n        const { joinedConfig: config } = await joinedConfigGenerator.generateJoinedConfig();\n        expect(config.minSessionDurationMs).toBeUndefined();\n        // eslint-disable-next-line @typescript-eslint/unbound-method\n        expect(mockLocalConfig.loggerProvider.warn).toHaveBeenCalledWith(\n          expect.stringContaining('not a finite number'),\n        );\n      });\n      test('should drop NaN min_session_duration_ms and warn', async () => {\n        mockRemoteConfig = {\n          sr_sampling_config: { ...samplingConfig, min_session_duration_ms: NaN },\n        };\n        const { joinedConfig: config } = await joinedConfigGenerator.generateJoinedConfig();\n        expect(config.minSessionDurationMs).toBeUndefined();\n      });\n      test('should set captureEnabled to true if no values returned from API', async () => {\n        mockRemoteConfig = {\n          sr_sampling_config: {} as any,\n        };\n        const { joinedConfig: config } = await joinedConfigGenerator.generateJoinedConfig();\n        expect(config).toEqual({\n          ...mockLocalConfig,\n          optOut: mockLocalConfig.optOut,\n          captureEnabled: true,\n        });\n      });\n    });\n\n    describe('with unsuccessful sampling config fetch', () => {\n      test('should log error when no remote config', async () => {\n        mockRemoteConfig = null;\n        jest.spyOn(mockLoggerProvider, 'error').mockImplementationOnce(() => {\n          return;\n        });\n        await joinedConfigGenerator.generateJoinedConfig();\n        // eslint-disable-next-line @typescript-eslint/unbound-method\n        expect(mockLoggerProvider.error).toHaveBeenCalledWith(\n          'Failed to generate joined config: ',\n          expect.objectContaining({\n            message: 'No remote config received',\n          }),\n        );\n      });\n      test('should set captureEnabled to false when no remote config', async () => {\n        mockRemoteConfig = null;\n        const { joinedConfig: config } = await joinedConfigGenerator.generateJoinedConfig();\n        expect(config).toEqual({\n          ...mockLocalConfig,\n          optOut: mockLocalConfig.optOut,\n          captureEnabled: false,\n        });\n      });\n      test('should set return an undefined remote config', async () => {\n        mockRemoteConfig = null;\n        const { localConfig } = await joinedConfigGenerator.generateJoinedConfig();\n        expect(localConfig).toEqual(mockLocalConfig);\n      });\n    });\n    describe('with successful privacy config fetch', () => {\n      const privacySelectorTest = async (\n        remotePrivacyConfig?: PrivacyConfig,\n        configGenerator: SessionReplayJoinedConfigGenerator = joinedConfigGenerator,\n      ) => {\n        mockRemoteConfig = {\n          sr_privacy_config: remotePrivacyConfig,\n        };\n        const { joinedConfig } = await configGenerator.generateJoinedConfig();\n        return joinedConfig;\n      };\n\n      test('should join string block selector from API', async () => {\n        const config = await privacySelectorTest(\n          privacyConfig,\n          await createSessionReplayJoinedConfigGenerator('static_key', {\n            ...mockOptions,\n            privacyConfig: {\n              blockSelector: '.className',\n            },\n          }),\n        );\n        expect(config).toEqual({\n          ...mockLocalConfig,\n          captureEnabled: true,\n          optOut: mockLocalConfig.optOut,\n          privacyConfig: {\n            ...privacyConfig,\n            maskSelector: undefined,\n            unmaskSelector: ['.amp-unmask'],\n            blockSelector: ['.className', '.anotherClassName'],\n          },\n        });\n      });\n\n      test.each(['block', 'mask'])('should join %p selector from API', async (selectorType) => {\n        const config = await privacySelectorTest(\n          {\n            [`${selectorType}Selector`]: ['.remoteClassName'],\n          },\n          await createSessionReplayJoinedConfigGenerator('static_key', {\n            ...mockOptions,\n            privacyConfig: {\n              [`${selectorType}Selector`]: ['.localClassName'],\n            },\n          }),\n        );\n        expect(config).toEqual({\n          ...mockLocalConfig,\n          captureEnabled: true,\n          optOut: mockLocalConfig.optOut,\n          privacyConfig: {\n            ...{\n              defaultMaskLevel: 'medium',\n              blockSelector: undefined,\n              maskSelector: undefined,\n              unmaskSelector: ['.amp-unmask'],\n              maskAttributes: [],\n              urlMaskLevels: [],\n            },\n            ...{ [`${selectorType}Selector`]: ['.localClassName', '.remoteClassName'] },\n          },\n        });\n      });\n\n      test('should join \"unmask\" selector from API', async () => {\n        const config = await privacySelectorTest(\n          { unmaskSelector: ['.remoteClassName'] },\n          await createSessionReplayJoinedConfigGenerator('static_key', {\n            ...mockOptions,\n            privacyConfig: { unmaskSelector: ['.localClassName'] },\n          }),\n        );\n        expect(config).toEqual({\n          ...mockLocalConfig,\n          captureEnabled: true,\n          optOut: mockLocalConfig.optOut,\n          loggingConfig: undefined,\n          interactionConfig: undefined,\n          privacyConfig: {\n            defaultMaskLevel: 'medium',\n            blockSelector: undefined,\n            maskSelector: undefined,\n            unmaskSelector: ['.amp-unmask', '.localClassName', '.remoteClassName'],\n            maskAttributes: [],\n            urlMaskLevels: [],\n          },\n        });\n      });\n\n      test('should dedupe .amp-unmask when user explicitly passes it alongside the auto-injected default', async () => {\n        const config = await privacySelectorTest(\n          { unmaskSelector: ['.remoteClassName'] },\n          await createSessionReplayJoinedConfigGenerator('static_key', {\n            ...mockOptions,\n            privacyConfig: { unmaskSelector: ['.amp-unmask', '.localClassName'] },\n          }),\n        );\n        expect(config.privacyConfig?.unmaskSelector).toEqual(['.amp-unmask', '.localClassName', '.remoteClassName']);\n      });\n\n      test('should use default mask level from API', async () => {\n        const config = await privacySelectorTest({\n          ...privacyConfig,\n          defaultMaskLevel: 'light',\n        });\n        expect(config).toStrictEqual({\n          ...mockLocalConfig,\n          captureEnabled: true,\n          optOut: mockLocalConfig.optOut,\n          loggingConfig: undefined,\n          privacyConfig: {\n            ...privacyConfig,\n            defaultMaskLevel: 'light',\n            maskSelector: undefined,\n            unmaskSelector: ['.amp-unmask'],\n          },\n          interactionConfig: undefined,\n        });\n      });\n\n      test('should use block selector from local if no API response', async () => {\n        const config = await privacySelectorTest(\n          {},\n          await createSessionReplayJoinedConfigGenerator('static_key', {\n            ...mockOptions,\n            privacyConfig: {\n              blockSelector: '.className',\n            },\n          }),\n        );\n        expect(config).toEqual({\n          ...mockLocalConfig,\n          captureEnabled: true,\n          optOut: mockLocalConfig.optOut,\n          privacyConfig: {\n            defaultMaskLevel: 'medium',\n            blockSelector: ['.className'],\n            maskSelector: undefined,\n            unmaskSelector: ['.amp-unmask'],\n            maskAttributes: [],\n            urlMaskLevels: [],\n          },\n        });\n      });\n\n      test('should update to remote config when local privacy config is undefined', async () => {\n        mockRemoteConfig = {\n          sr_privacy_config: privacyConfig,\n        };\n        const configGenerator = await createSessionReplayJoinedConfigGenerator('static_key', {\n          ...mockOptions,\n          privacyConfig: undefined,\n        });\n        const { joinedConfig: config } = await configGenerator.generateJoinedConfig();\n        expect(config).toEqual({\n          ...mockLocalConfig,\n          captureEnabled: true,\n          optOut: mockLocalConfig.optOut,\n          privacyConfig: {\n            ...privacyConfig,\n            maskSelector: undefined,\n            unmaskSelector: ['.amp-unmask'],\n          },\n        });\n      });\n\n      describe('with maskAttributes config', () => {\n        test('should merge local and remote maskAttributes', async () => {\n          const config = await privacySelectorTest(\n            { maskAttributes: ['aria-label'] },\n            await createSessionReplayJoinedConfigGenerator('static_key', {\n              ...mockOptions,\n              privacyConfig: { maskAttributes: ['placeholder'] },\n            }),\n          );\n          expect(config.privacyConfig?.maskAttributes).toEqual(['placeholder', 'aria-label']);\n        });\n\n        test('should deduplicate maskAttributes present in both local and remote', async () => {\n          const config = await privacySelectorTest(\n            { maskAttributes: ['placeholder', 'aria-label'] },\n            await createSessionReplayJoinedConfigGenerator('static_key', {\n              ...mockOptions,\n              privacyConfig: { maskAttributes: ['placeholder'] },\n            }),\n          );\n          expect(config.privacyConfig?.maskAttributes).toEqual(['placeholder', 'aria-label']);\n        });\n\n        test('should use only local maskAttributes when remote has none', async () => {\n          const config = await privacySelectorTest(\n            {},\n            await createSessionReplayJoinedConfigGenerator('static_key', {\n              ...mockOptions,\n              privacyConfig: { maskAttributes: ['placeholder'] },\n            }),\n          );\n          expect(config.privacyConfig?.maskAttributes).toEqual(['placeholder']);\n        });\n\n        test('should use only remote maskAttributes when local has none', async () => {\n          const config = await privacySelectorTest({ maskAttributes: ['aria-label'] });\n          expect(config.privacyConfig?.maskAttributes).toEqual(['aria-label']);\n        });\n\n        test('should produce empty maskAttributes when neither local nor remote has any', async () => {\n          const config = await privacySelectorTest({});\n          expect(config.privacyConfig?.maskAttributes).toEqual([]);\n        });\n      });\n\n      describe('with urlMaskLevels config', () => {\n        const remoteRule = { match: 'https://example.com/admin/*', maskLevel: 'conservative' as const };\n        const localRule = { match: 'https://example.com/public/*', maskLevel: 'light' as const };\n\n        test('should prepend remote urlMaskLevels before local (remote has priority)', async () => {\n          const config = await privacySelectorTest(\n            { urlMaskLevels: [remoteRule] },\n            await createSessionReplayJoinedConfigGenerator('static_key', {\n              ...mockOptions,\n              privacyConfig: { urlMaskLevels: [localRule] },\n            }),\n          );\n          expect(config.privacyConfig?.urlMaskLevels).toEqual([remoteRule, localRule]);\n        });\n\n        test('should use only local urlMaskLevels when remote has none', async () => {\n          const config = await privacySelectorTest(\n            {},\n            await createSessionReplayJoinedConfigGenerator('static_key', {\n              ...mockOptions,\n              privacyConfig: { urlMaskLevels: [localRule] },\n            }),\n          );\n          expect(config.privacyConfig?.urlMaskLevels).toEqual([localRule]);\n        });\n\n        test('should use only remote urlMaskLevels when local has none', async () => {\n          const config = await privacySelectorTest({ urlMaskLevels: [remoteRule] });\n          expect(config.privacyConfig?.urlMaskLevels).toEqual([remoteRule]);\n        });\n\n        test('should produce empty urlMaskLevels when neither local nor remote has any', async () => {\n          const config = await privacySelectorTest({});\n          expect(config.privacyConfig?.urlMaskLevels).toEqual([]);\n        });\n\n        test('remote defaultMaskLevel wins over local defaultMaskLevel', async () => {\n          // P1: remote config must override local when both specify defaultMaskLevel.\n          // Local says 'conservative'; remote says 'light' — joined config must reflect 'light'.\n          const config = await privacySelectorTest(\n            { defaultMaskLevel: 'light' },\n            await createSessionReplayJoinedConfigGenerator('static_key', {\n              ...mockOptions,\n              privacyConfig: { defaultMaskLevel: 'conservative' },\n            }),\n          );\n          expect(config.privacyConfig?.defaultMaskLevel).toBe('light');\n        });\n\n        test('local urlMaskLevels are preserved when sr_privacy_config is absent from remote', async () => {\n          // P1: when the remote response has no sr_privacy_config key at all, the joined config\n          // should fall back to the local config as-is — local urlMaskLevels must not be lost.\n          const localRule = { match: 'https://example.com/admin/*', maskLevel: 'conservative' as const };\n          mockRemoteConfig = {\n            sr_sampling_config: samplingConfig,\n            // intentionally no sr_privacy_config key\n          };\n          const configGenerator = await createSessionReplayJoinedConfigGenerator('static_key', {\n            ...mockOptions,\n            privacyConfig: { urlMaskLevels: [localRule] },\n          });\n          const { joinedConfig: config } = await configGenerator.generateJoinedConfig();\n          expect(config.privacyConfig?.urlMaskLevels).toEqual([localRule]);\n        });\n      });\n    });\n\n    describe('SessionReplayLocalConfig privacyConfig', () => {\n      test('should include .amp-unmask in unmaskSelector when no privacyConfig is provided', () => {\n        const config = new SessionReplayLocalConfig('static_key', {\n          ...mockOptions,\n          privacyConfig: undefined,\n        });\n        expect(config.privacyConfig?.unmaskSelector).toEqual(['.amp-unmask']);\n      });\n\n      test('should include .amp-unmask in unmaskSelector when privacyConfig has no unmaskSelector', () => {\n        const config = new SessionReplayLocalConfig('static_key', {\n          ...mockOptions,\n          privacyConfig: { blockSelector: '.block-me' },\n        });\n        expect(config.privacyConfig?.unmaskSelector).toEqual(['.amp-unmask']);\n      });\n\n      test('should prepend .amp-unmask before user-provided unmaskSelector entries', () => {\n        const config = new SessionReplayLocalConfig('static_key', {\n          ...mockOptions,\n          privacyConfig: { unmaskSelector: ['.custom-unmask', '#my-id'] },\n        });\n        expect(config.privacyConfig?.unmaskSelector).toEqual(['.amp-unmask', '.custom-unmask', '#my-id']);\n      });\n\n      test('should dedupe .amp-unmask when user explicitly includes it in unmaskSelector', () => {\n        const config = new SessionReplayLocalConfig('static_key', {\n          ...mockOptions,\n          privacyConfig: { unmaskSelector: ['.amp-unmask', '.foo'] },\n        });\n        expect(config.privacyConfig?.unmaskSelector).toEqual(['.amp-unmask', '.foo']);\n      });\n\n      test('should preserve other privacyConfig properties alongside the injected unmaskSelector', () => {\n        const config = new SessionReplayLocalConfig('static_key', {\n          ...mockOptions,\n          privacyConfig: {\n            blockSelector: '.block-me',\n            maskSelector: ['.mask-me'],\n            defaultMaskLevel: 'conservative',\n          },\n        });\n        expect(config.privacyConfig).toEqual({\n          blockSelector: '.block-me',\n          maskSelector: ['.mask-me'],\n          defaultMaskLevel: 'conservative',\n          unmaskSelector: ['.amp-unmask'],\n        });\n      });\n\n      test('should always set privacyConfig (never undefined)', () => {\n        const config = new SessionReplayLocalConfig('static_key', {\n          ...mockOptions,\n          privacyConfig: undefined,\n        });\n        expect(config.privacyConfig).toBeDefined();\n      });\n    });\n\n    describe('with interaction config', () => {\n      test('should validate UGC filter rules when provided', () => {\n        const validRules = [\n          { selector: 'https://example.com/user/*', replacement: 'https://example.com/user/user_id' },\n          { selector: 'https://example.com/product/*', replacement: 'https://example.com/product/product_id' },\n        ];\n        const config = new SessionReplayLocalConfig('static_key', {\n          ...mockOptions,\n          interactionConfig: {\n            enabled: true,\n            batch: false,\n            ugcFilterRules: validRules,\n          },\n        });\n        expect(config.interactionConfig?.ugcFilterRules).toEqual(validRules);\n      });\n\n      test('should set urlChangePollingInterval to default value when not provided', () => {\n        const config = new SessionReplayLocalConfig('static_key', mockOptions);\n        expect(config.urlChangePollingInterval).toBe(DEFAULT_URL_CHANGE_POLLING_INTERVAL);\n      });\n\n      test('should set urlChangePollingInterval to custom value when provided', () => {\n        const customInterval = 2000;\n        const config = new SessionReplayLocalConfig('static_key', {\n          ...mockOptions,\n          urlChangePollingInterval: customInterval,\n        });\n        expect(config.urlChangePollingInterval).toBe(customInterval);\n      });\n\n      test('should set urlChangePollingInterval to 0 when explicitly set to 0', () => {\n        const config = new SessionReplayLocalConfig('static_key', {\n          ...mockOptions,\n          urlChangePollingInterval: 0,\n        });\n        expect(config.urlChangePollingInterval).toBe(0);\n      });\n\n      test('should default captureAdoptedStyleSheets to true when not provided', () => {\n        const config = new SessionReplayLocalConfig('static_key', mockOptions);\n        expect(config.captureAdoptedStyleSheets).toBe(true);\n      });\n\n      test('should set captureAdoptedStyleSheets to true when provided', () => {\n        const config = new SessionReplayLocalConfig('static_key', {\n          ...mockOptions,\n          captureAdoptedStyleSheets: true,\n        });\n        expect(config.captureAdoptedStyleSheets).toBe(true);\n      });\n\n      test('should set captureAdoptedStyleSheets to false when provided', () => {\n        const config = new SessionReplayLocalConfig('static_key', {\n          ...mockOptions,\n          captureAdoptedStyleSheets: false,\n        });\n        expect(config.captureAdoptedStyleSheets).toBe(false);\n      });\n\n      test('should throw error for invalid UGC filter rules with non-string selector', () => {\n        const invalidRules = [{ selector: 123, replacement: 'replacement' }] as unknown as UGCFilterRule[];\n        expect(() => {\n          new SessionReplayLocalConfig('static_key', {\n            ...mockOptions,\n            interactionConfig: {\n              enabled: true,\n              batch: false,\n              ugcFilterRules: invalidRules,\n            },\n          });\n        }).toThrow('ugcFilterRules must be an array of objects with selector and replacement properties');\n      });\n\n      test('should throw error for invalid UGC filter rules with non-string replacement', () => {\n        const invalidRules = [{ selector: 'pattern', replacement: 456 }] as unknown as UGCFilterRule[];\n        expect(() => {\n          new SessionReplayLocalConfig('static_key', {\n            ...mockOptions,\n            interactionConfig: {\n              enabled: true,\n              batch: false,\n              ugcFilterRules: invalidRules,\n            },\n          });\n        }).toThrow('ugcFilterRules must be an array of objects with selector and replacement properties');\n      });\n\n      test('should throw error for invalid UGC filter rules with invalid glob pattern', () => {\n        const invalidRules = [{ selector: 'invalid[pattern', replacement: 'replacement' }];\n        expect(() => {\n          new SessionReplayLocalConfig('static_key', {\n            ...mockOptions,\n            interactionConfig: {\n              enabled: true,\n              batch: false,\n              ugcFilterRules: invalidRules,\n            },\n          });\n        }).toThrow('ugcFilterRules must be an array of objects with valid globs');\n      });\n    });\n\n    describe('with interaction config ugcFilterRules', () => {\n      let configGenerator: SessionReplayJoinedConfigGenerator;\n\n      beforeEach(async () => {\n        configGenerator = await createSessionReplayJoinedConfigGenerator('static_key', mockOptions);\n      });\n\n      test('should preserve local ugcFilterRules when remote config has no ugcFilterRules', async () => {\n        const localUgcFilterRules = [\n          { selector: 'https://example.com/local/*', replacement: 'https://example.com/local/local_id' },\n        ];\n        const remoteInteractionConfig = {\n          enabled: true,\n          batch: true,\n        };\n\n        const localConfigGenerator = await createSessionReplayJoinedConfigGenerator('static_key', {\n          ...mockOptions,\n          interactionConfig: {\n            enabled: true,\n            batch: false,\n            ugcFilterRules: localUgcFilterRules,\n          },\n        });\n\n        mockRemoteConfig = {\n          sr_interaction_config: remoteInteractionConfig,\n        };\n\n        const { joinedConfig: config } = await localConfigGenerator.generateJoinedConfig();\n        expect(config.interactionConfig).toEqual({\n          ...remoteInteractionConfig,\n          ugcFilterRules: localUgcFilterRules,\n        });\n      });\n\n      test('should use remote ugcFilterRules when local config has no ugcFilterRules', async () => {\n        const remoteUgcFilterRules = [\n          { selector: 'https://example.com/remote/*', replacement: 'https://example.com/remote/remote_id' },\n        ];\n        const remoteInteractionConfig = {\n          enabled: true,\n          batch: true,\n          ugcFilterRules: remoteUgcFilterRules,\n        };\n\n        mockRemoteConfig = {\n          sr_interaction_config: remoteInteractionConfig,\n        };\n\n        const { joinedConfig: config } = await configGenerator.generateJoinedConfig();\n        expect(config.interactionConfig).toEqual(remoteInteractionConfig);\n      });\n\n      test('should handle undefined interaction config', async () => {\n        mockRemoteConfig = {\n          sr_interaction_config: undefined,\n        };\n        const { joinedConfig: config } = await configGenerator.generateJoinedConfig();\n        expect(config.interactionConfig).toBeUndefined();\n      });\n\n      test('should handle empty ugcFilterRules array', async () => {\n        const localUgcFilterRules: UGCFilterRule[] = [];\n        const remoteInteractionConfig = {\n          enabled: true,\n          batch: true,\n        };\n\n        const localConfigGenerator = await createSessionReplayJoinedConfigGenerator('static_key', {\n          ...mockOptions,\n          interactionConfig: {\n            enabled: true,\n            batch: false,\n            ugcFilterRules: localUgcFilterRules,\n          },\n        });\n\n        mockRemoteConfig = {\n          sr_interaction_config: remoteInteractionConfig,\n        };\n\n        const { joinedConfig: config } = await localConfigGenerator.generateJoinedConfig();\n        expect(config.interactionConfig).toEqual({\n          ...remoteInteractionConfig,\n          ugcFilterRules: localUgcFilterRules,\n        });\n      });\n    });\n  });\n\n  describe('removeInvalidSelectorsFromPrivacyConfig', () => {\n    test('should handle string block selector correctly', async () => {\n      const privacyConfig = {\n        blockSelector: 'FASE<:F>!@<?#>!#<',\n      };\n      const updatedPrivacyConfig = removeInvalidSelectorsFromPrivacyConfig(privacyConfig, mockLoggerProvider);\n      expect(updatedPrivacyConfig).toStrictEqual({\n        blockSelector: undefined,\n        maskSelector: undefined,\n        unmaskSelector: undefined,\n      });\n    });\n  });\n\n  describe('generateJoinedConfig with undefined privacyConfig on joined config', () => {\n    test('should fall back to empty object when config.privacyConfig is undefined', async () => {\n      // Directly instantiate with a local config that has privacyConfig stripped,\n      // exercising the `config.privacyConfig ?? {}` branch in joined-config.ts.\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n      const generator = new SessionReplayJoinedConfigGenerator(mockRemoteConfigClient, {\n        ...mockLocalConfig,\n        privacyConfig: undefined,\n      } as any);\n      mockRemoteConfig = { sr_privacy_config: { blockSelector: ['.remote-block'] } };\n      const { joinedConfig } = await generator.generateJoinedConfig();\n      expect(joinedConfig.privacyConfig?.blockSelector).toEqual(['.remote-block']);\n    });\n  });\n\n  describe('createSessionReplayJoinedConfigGenerator with config server url', () => {\n    test('should create a SessionReplayJoinedConfigGenerator with the correct remote config client', async () => {\n      const configServerUrl = 'https://config.amplitude.com';\n      const joinedConfigGenerator = await createSessionReplayJoinedConfigGenerator('static_key', {\n        ...mockOptions,\n        configServerUrl,\n      });\n\n      // Verify RemoteConfigClient was called with the correct parameters\n      expect(MockedRemoteConfigClient).toHaveBeenCalledWith(\n        'static_key',\n        mockLoggerProvider,\n        ServerZone.EU,\n        configServerUrl,\n      );\n\n      // Verify the generator was created successfully\n      expect(joinedConfigGenerator).toBeInstanceOf(SessionReplayJoinedConfigGenerator);\n    });\n\n    test('should pass undefined configServerUrl when not provided', async () => {\n      await createSessionReplayJoinedConfigGenerator('static_key', mockOptions);\n\n      // Verify RemoteConfigClient was called with undefined for configServerUrl\n      expect(MockedRemoteConfigClient).toHaveBeenCalledWith('static_key', mockLoggerProvider, ServerZone.EU, undefined);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/cross-origin-iframes.test.ts",
    "content": "import * as AnalyticsCore from '@amplitude/analytics-core';\nimport { CrossOriginIframeCoordinator, isInIframe, listenForParentSignals } from '../src/cross-origin-iframes';\nimport { CROSS_ORIGIN_IFRAME_MESSAGE_TYPE } from '../src/constants';\n\ndescribe('isInIframe', () => {\n  const originalParent = window.parent;\n\n  afterEach(() => {\n    Object.defineProperty(window, 'parent', { value: originalParent, writable: true, configurable: true });\n  });\n\n  it('returns false when window.parent === window (top-level page)', () => {\n    Object.defineProperty(window, 'parent', { value: window, writable: true, configurable: true });\n    expect(isInIframe()).toBe(false);\n  });\n\n  it('returns true when window.parent !== window (inside iframe)', () => {\n    Object.defineProperty(window, 'parent', { value: {} as Window, writable: true, configurable: true });\n    expect(isInIframe()).toBe(true);\n  });\n\n  it('returns true when accessing window.parent throws (sandboxed environment)', () => {\n    Object.defineProperty(window, 'parent', {\n      get() {\n        throw new Error('SecurityError');\n      },\n      configurable: true,\n    });\n    expect(isInIframe()).toBe(true);\n  });\n\n  it('returns false when getGlobalScope() returns null (non-browser environment)', () => {\n    const spy = jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue(null as any);\n    expect(isInIframe()).toBe(false);\n    spy.mockRestore();\n  });\n});\n\ndescribe('CrossOriginIframeCoordinator', () => {\n  let coordinator: CrossOriginIframeCoordinator;\n  let iframe1: HTMLIFrameElement;\n  let iframe2: HTMLIFrameElement;\n\n  beforeEach(() => {\n    coordinator = new CrossOriginIframeCoordinator();\n\n    iframe1 = document.createElement('iframe');\n    iframe2 = document.createElement('iframe');\n    document.body.appendChild(iframe1);\n    document.body.appendChild(iframe2);\n\n    // Mock contentWindow.postMessage on each iframe\n    const mockPostMessage1 = jest.fn();\n    const mockPostMessage2 = jest.fn();\n    Object.defineProperty(iframe1, 'contentWindow', { value: { postMessage: mockPostMessage1 }, configurable: true });\n    Object.defineProperty(iframe2, 'contentWindow', { value: { postMessage: mockPostMessage2 }, configurable: true });\n  });\n\n  afterEach(() => {\n    coordinator.stop();\n    iframe1.remove();\n    iframe2.remove();\n  });\n\n  it('sends start signal to all existing iframes on start()', () => {\n    coordinator.start();\n    const pm1 = (iframe1.contentWindow as any).postMessage as jest.Mock;\n    const pm2 = (iframe2.contentWindow as any).postMessage as jest.Mock;\n    expect(pm1).toHaveBeenCalledWith({ type: CROSS_ORIGIN_IFRAME_MESSAGE_TYPE, action: 'start' }, '*');\n    expect(pm2).toHaveBeenCalledWith({ type: CROSS_ORIGIN_IFRAME_MESSAGE_TYPE, action: 'start' }, '*');\n  });\n\n  it('sends start signal to dynamically added iframes after they load', async () => {\n    coordinator.start();\n\n    const dynamicIframe = document.createElement('iframe');\n    const mockPostMessage = jest.fn();\n    Object.defineProperty(dynamicIframe, 'contentWindow', {\n      value: { postMessage: mockPostMessage },\n      configurable: true,\n    });\n    document.body.appendChild(dynamicIframe);\n\n    // MutationObserver callbacks fire asynchronously\n    await new Promise((r) => setTimeout(r, 0));\n\n    // No message before the iframe's load event — it would go to about:blank otherwise\n    expect(mockPostMessage).not.toHaveBeenCalled();\n\n    // Simulate the child page finishing its load\n    dynamicIframe.dispatchEvent(new Event('load'));\n\n    expect(mockPostMessage).toHaveBeenCalledWith({ type: CROSS_ORIGIN_IFRAME_MESSAGE_TYPE, action: 'start' }, '*');\n    expect(mockPostMessage).toHaveBeenCalledTimes(1);\n    dynamicIframe.remove();\n  });\n\n  it('sends stop signal to all iframes and disconnects observer on stop()', () => {\n    coordinator.start();\n    coordinator.stop();\n\n    const pm1 = (iframe1.contentWindow as any).postMessage as jest.Mock;\n    const pm2 = (iframe2.contentWindow as any).postMessage as jest.Mock;\n    expect(pm1).toHaveBeenCalledWith({ type: CROSS_ORIGIN_IFRAME_MESSAGE_TYPE, action: 'stop' }, '*');\n    expect(pm2).toHaveBeenCalledWith({ type: CROSS_ORIGIN_IFRAME_MESSAGE_TYPE, action: 'stop' }, '*');\n  });\n\n  it('cancels pending load listener when stopped before iframe finishes loading', async () => {\n    coordinator.start();\n\n    const dynamicIframe = document.createElement('iframe');\n    const mockPostMessage = jest.fn();\n    Object.defineProperty(dynamicIframe, 'contentWindow', {\n      value: { postMessage: mockPostMessage },\n      configurable: true,\n    });\n    document.body.appendChild(dynamicIframe);\n\n    await new Promise((r) => setTimeout(r, 0));\n\n    // Stop before the iframe loads — the pending listener should be removed\n    coordinator.stop();\n\n    // Simulate the child page finishing its load (listener should already be gone)\n    dynamicIframe.dispatchEvent(new Event('load'));\n\n    // stop() sends a stop signal (via sendToAllIframes) but must NOT send a start signal\n    expect(mockPostMessage).toHaveBeenCalledWith({ type: CROSS_ORIGIN_IFRAME_MESSAGE_TYPE, action: 'stop' }, '*');\n    expect(mockPostMessage).not.toHaveBeenCalledWith({ type: CROSS_ORIGIN_IFRAME_MESSAGE_TYPE, action: 'start' }, '*');\n    dynamicIframe.remove();\n  });\n\n  it('does not accumulate MutationObservers when start() is called twice', async () => {\n    coordinator.start();\n\n    const dynamicIframe1 = document.createElement('iframe');\n    const mockPm1 = jest.fn();\n    Object.defineProperty(dynamicIframe1, 'contentWindow', { value: { postMessage: mockPm1 }, configurable: true });\n\n    // Second start() should disconnect the first observer before creating a new one\n    coordinator.start();\n\n    document.body.appendChild(dynamicIframe1);\n    await new Promise((r) => setTimeout(r, 0));\n    dynamicIframe1.dispatchEvent(new Event('load'));\n\n    // Only one start signal, not two (from two observers)\n    expect(mockPm1).toHaveBeenCalledTimes(1);\n    dynamicIframe1.remove();\n  });\n\n  it('sends start signal to iframes nested inside a dynamically added container element', async () => {\n    coordinator.start();\n\n    // Simulate a framework inserting a wrapper div that already contains an iframe\n    const wrapper = document.createElement('div');\n    const nestedIframe = document.createElement('iframe');\n    const mockPostMessage = jest.fn();\n    Object.defineProperty(nestedIframe, 'contentWindow', {\n      value: { postMessage: mockPostMessage },\n      configurable: true,\n    });\n    wrapper.appendChild(nestedIframe);\n    document.body.appendChild(wrapper);\n\n    await new Promise((r) => setTimeout(r, 0));\n\n    // No message yet — waiting for load\n    expect(mockPostMessage).not.toHaveBeenCalled();\n\n    nestedIframe.dispatchEvent(new Event('load'));\n    expect(mockPostMessage).toHaveBeenCalledWith({ type: CROSS_ORIGIN_IFRAME_MESSAGE_TYPE, action: 'start' }, '*');\n    wrapper.remove();\n  });\n\n  it('cancels pending load listener when iframe is removed from DOM before loading', async () => {\n    coordinator.start();\n\n    const dynamicIframe = document.createElement('iframe');\n    const mockPostMessage = jest.fn();\n    Object.defineProperty(dynamicIframe, 'contentWindow', {\n      value: { postMessage: mockPostMessage },\n      configurable: true,\n    });\n    document.body.appendChild(dynamicIframe);\n    await new Promise((r) => setTimeout(r, 0));\n\n    // Remove the iframe before it loads — pending listener should be cleaned up\n    dynamicIframe.remove();\n    await new Promise((r) => setTimeout(r, 0));\n\n    // Simulate the load event firing anyway (shouldn't send start)\n    dynamicIframe.dispatchEvent(new Event('load'));\n\n    expect(mockPostMessage).not.toHaveBeenCalledWith({ type: CROSS_ORIGIN_IFRAME_MESSAGE_TYPE, action: 'start' }, '*');\n  });\n\n  it('ignores removed non-iframe nodes', async () => {\n    coordinator.start();\n    const pm1 = (iframe1.contentWindow as any).postMessage as jest.Mock;\n    pm1.mockClear();\n\n    const div = document.createElement('div');\n    document.body.appendChild(div);\n    await new Promise((r) => setTimeout(r, 0));\n    div.remove();\n    await new Promise((r) => setTimeout(r, 0));\n\n    expect(pm1).not.toHaveBeenCalled();\n  });\n\n  it('ignores non-element added nodes such as text nodes', async () => {\n    coordinator.start();\n    const pm1 = (iframe1.contentWindow as any).postMessage as jest.Mock;\n    pm1.mockClear(); // clear the start call from coordinator.start()\n\n    const textNode = document.createTextNode('hello');\n    document.body.appendChild(textNode);\n    await new Promise((r) => setTimeout(r, 0));\n\n    expect(pm1).not.toHaveBeenCalled();\n    textNode.remove();\n  });\n\n  it('handles iframes with no contentWindow gracefully', () => {\n    Object.defineProperty(iframe1, 'contentWindow', { value: null, configurable: true });\n    expect(() => coordinator.start()).not.toThrow();\n  });\n\n  it('returns early from start() when getGlobalScope() returns null', () => {\n    const spy = jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue(null as any);\n    expect(() => coordinator.start()).not.toThrow();\n    const pm1 = (iframe1.contentWindow as any).postMessage as jest.Mock;\n    expect(pm1).not.toHaveBeenCalled();\n    spy.mockRestore();\n  });\n});\n\ndescribe('listenForParentSignals', () => {\n  let cleanup: () => void;\n\n  afterEach(() => {\n    cleanup?.();\n  });\n\n  function dispatchMessage(source: Window, data: unknown) {\n    const event = new MessageEvent('message', { data, source });\n    window.dispatchEvent(event);\n  }\n\n  it('calls onStart when a start message arrives from window.parent', () => {\n    const onStart = jest.fn();\n    const onStop = jest.fn();\n    cleanup = listenForParentSignals({ onStart, onStop });\n\n    dispatchMessage(window.parent, { type: CROSS_ORIGIN_IFRAME_MESSAGE_TYPE, action: 'start' });\n\n    expect(onStart).toHaveBeenCalledTimes(1);\n    expect(onStop).not.toHaveBeenCalled();\n  });\n\n  it('calls onStop when a stop message arrives from window.parent', () => {\n    const onStart = jest.fn();\n    const onStop = jest.fn();\n    cleanup = listenForParentSignals({ onStart, onStop });\n\n    dispatchMessage(window.parent, { type: CROSS_ORIGIN_IFRAME_MESSAGE_TYPE, action: 'stop' });\n\n    expect(onStop).toHaveBeenCalledTimes(1);\n    expect(onStart).not.toHaveBeenCalled();\n  });\n\n  it('ignores messages from sources other than window.parent', () => {\n    const onStart = jest.fn();\n    const onStop = jest.fn();\n    cleanup = listenForParentSignals({ onStart, onStop });\n\n    // Use a source that is explicitly not window.parent (a child iframe, for instance)\n    const foreignSource = {} as Window;\n    dispatchMessage(foreignSource, { type: CROSS_ORIGIN_IFRAME_MESSAGE_TYPE, action: 'start' });\n\n    expect(onStart).not.toHaveBeenCalled();\n    expect(onStop).not.toHaveBeenCalled();\n  });\n\n  it('ignores messages with wrong type', () => {\n    const onStart = jest.fn();\n    const onStop = jest.fn();\n    cleanup = listenForParentSignals({ onStart, onStop });\n\n    dispatchMessage(window.parent, { type: 'some-other-type', action: 'start' });\n\n    expect(onStart).not.toHaveBeenCalled();\n  });\n\n  it('ignores messages with null data', () => {\n    const onStart = jest.fn();\n    cleanup = listenForParentSignals({ onStart, onStop: jest.fn() });\n\n    dispatchMessage(window.parent, null);\n\n    expect(onStart).not.toHaveBeenCalled();\n  });\n\n  it('removes the event listener after cleanup', () => {\n    const onStart = jest.fn();\n    cleanup = listenForParentSignals({ onStart, onStop: jest.fn() });\n    cleanup();\n\n    dispatchMessage(window.parent, { type: CROSS_ORIGIN_IFRAME_MESSAGE_TYPE, action: 'start' });\n\n    expect(onStart).not.toHaveBeenCalled();\n  });\n\n  it('returns a no-op cleanup when getGlobalScope() returns null', () => {\n    const spy = jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue(null as any);\n    const onStart = jest.fn();\n    cleanup = listenForParentSignals({ onStart, onStop: jest.fn() });\n    expect(() => cleanup()).not.toThrow();\n    expect(onStart).not.toHaveBeenCalled();\n    spy.mockRestore();\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/event-compressor.test.ts",
    "content": "import { ILogger } from '@amplitude/analytics-core';\nimport { SessionReplayLocalConfig } from '../src/config/local-config';\nimport { EventCompressor } from '../src/events/event-compressor';\nimport { createEventsManager } from '../src/events/events-manager';\nimport { SessionReplayEventsManager } from '../src/typings/session-replay';\nimport { EventType, IncrementalSource, eventWithTime, mutationData } from '@amplitude/rrweb-types';\n\nconst mockEvent = {\n  type: 4, // Meta — not a FullSnapshot\n  data: { href: 'https://analytics.amplitude.com/', width: 1728, height: 154 },\n  timestamp: 1687358660935,\n};\n\nconst fullSnapshotEvent: eventWithTime = {\n  type: 2, // FullSnapshot\n  data: { node: { type: 0, childNodes: [] as any[], id: 1 }, initialOffset: { left: 0, top: 0 } },\n  timestamp: 1687358660935,\n};\n\ntype MockedLogger = jest.Mocked<ILogger>;\n\ndescribe('EventCompressor', () => {\n  let eventsManager: SessionReplayEventsManager<'replay' | 'interaction', string>;\n  let eventCompressor: EventCompressor;\n  const mockRequestIdleCallback = jest.fn((callback: (deadline: IdleDeadline) => void) => {\n    const mockIdleDeadline: IdleDeadline = {\n      timeRemaining: () => 50,\n      didTimeout: false,\n    };\n    return callback(mockIdleDeadline);\n  });\n  (global.requestIdleCallback as jest.Mock) = mockRequestIdleCallback;\n  const mockLoggerProvider: MockedLogger = {\n    error: jest.fn(),\n    log: jest.fn(),\n    disable: jest.fn(),\n    enable: jest.fn(),\n    warn: jest.fn(),\n    debug: jest.fn(),\n  };\n  const deviceId = '4abce3b0-0b1b-4b3b-8b3b-3b0b1b4b3b8b';\n  const sessionId = 123;\n  let deferEvents: typeof global.requestIdleCallback;\n  const config = new SessionReplayLocalConfig('static_key', {\n    loggerProvider: mockLoggerProvider,\n    sampleRate: 1,\n    performanceConfig: {\n      enabled: true,\n      timeout: 2000,\n    },\n    useWebWorker: true,\n  });\n\n  beforeEach(async () => {\n    eventsManager = await createEventsManager<'replay'>({\n      config,\n      type: 'replay',\n      storeType: 'memory',\n    });\n    eventCompressor = new EventCompressor(eventsManager, config, deviceId);\n    deferEvents = global.requestIdleCallback;\n  });\n\n  afterEach(() => {\n    jest.resetAllMocks();\n    global.requestIdleCallback = deferEvents;\n    jest.useRealTimers();\n  });\n\n  test('should schedule idle processing if not already processing', () => {\n    const scheduleIdleProcessingMock = jest.spyOn(eventCompressor, 'scheduleIdleProcessing');\n    expect(eventCompressor.isProcessing).toBe(false);\n\n    eventCompressor.enqueueEvent(mockEvent, 123);\n\n    expect(scheduleIdleProcessingMock).toHaveBeenCalledTimes(1);\n    expect(mockRequestIdleCallback).toHaveBeenCalledTimes(1);\n  });\n\n  test('should not schedule idle processing if already processing', () => {\n    eventCompressor.isProcessing = true;\n    eventCompressor.scheduleIdleProcessing();\n    expect(mockRequestIdleCallback).not.toHaveBeenCalled();\n  });\n\n  test('should immediately compress and add the event if idle callback is not supported', () => {\n    eventCompressor.canUseIdleCallback = false;\n    const addEventMock = jest.spyOn(eventsManager, 'addEvent');\n    eventCompressor.enqueueEvent(mockEvent, sessionId);\n\n    expect(eventCompressor.taskQueue.length).toBe(0);\n    expect(addEventMock).toHaveBeenCalled();\n  });\n\n  test('drops oversized event and warns instead of storing it', () => {\n    eventCompressor.canUseIdleCallback = false;\n    const addEventMock = jest.spyOn(eventsManager, 'addEvent');\n\n    // Build a mock event whose JSON serialization exceeds MAX_SINGLE_EVENT_SIZE (9 MB)\n    const oversizedEvent = {\n      ...mockEvent,\n      data: { payload: 'x'.repeat(9 * 1000 * 1000 + 1) },\n    } as unknown as eventWithTime;\n    eventCompressor.enqueueEvent(oversizedEvent, sessionId);\n\n    expect(addEventMock).not.toHaveBeenCalled();\n    // eslint-disable-next-line @typescript-eslint/unbound-method\n    expect(mockLoggerProvider.warn).toHaveBeenCalledWith(expect.stringContaining('exceeds maximum allowed event size'));\n  });\n\n  test('should process events in the queue and add compressed events', () => {\n    eventCompressor.taskQueue.push({ event: mockEvent, sessionId });\n    eventCompressor.taskQueue.push({ event: mockEvent, sessionId });\n\n    const mockIdleDeadline = { timeRemaining: () => 0, didTimeout: true } as IdleDeadline;\n\n    const addEventMock = jest.spyOn(eventsManager, 'addEvent');\n\n    eventCompressor.processQueue(mockIdleDeadline);\n\n    expect(addEventMock).toHaveBeenCalled();\n    expect(eventCompressor.taskQueue.length).toBe(0);\n  });\n\n  test('should call requestIdleCallback if there are still tasks in the queue', () => {\n    eventCompressor.taskQueue.push({ event: mockEvent, sessionId });\n    eventCompressor.taskQueue.push({ event: mockEvent, sessionId });\n\n    const mockIdleDeadline = { timeRemaining: () => 0, didTimeout: false } as IdleDeadline;\n\n    const processQueueMock = jest.spyOn(eventCompressor, 'processQueue');\n\n    eventCompressor.processQueue(mockIdleDeadline);\n    expect(processQueueMock).toHaveBeenCalledTimes(1);\n    expect(mockRequestIdleCallback).toHaveBeenCalled();\n  });\n\n  test('should not call requestIdleCallback if preformance config is undefined', () => {\n    eventCompressor.config.performanceConfig = undefined;\n\n    const addCompressedEventMock = jest.spyOn(eventCompressor, 'addCompressedEvent');\n\n    eventCompressor.enqueueEvent(mockEvent, sessionId);\n\n    expect(eventCompressor.taskQueue.length).toBe(0);\n    expect(addCompressedEventMock).toHaveBeenCalledWith(mockEvent, sessionId);\n  });\n\n  test('should set isProcessing to false when taskQueue is empty', () => {\n    eventCompressor.taskQueue = [];\n    const mockIdleDeadline = { timeRemaining: () => 0, didTimeout: false } as IdleDeadline;\n\n    const processQueueMock = jest.spyOn(eventCompressor, 'processQueue');\n    eventCompressor.processQueue(mockIdleDeadline);\n\n    expect(processQueueMock).toHaveBeenCalled();\n    expect(eventCompressor.isProcessing).toBe(false);\n  });\n\n  test('should schedule another idle callback if there are still tasks', () => {\n    eventCompressor.taskQueue.push({ event: mockEvent, sessionId });\n    eventCompressor.taskQueue.push({ event: mockEvent, sessionId });\n\n    const mockIdleDeadline = {\n      timeRemaining: () => 0,\n      didTimeout: false,\n    } as IdleDeadline;\n\n    const processQueueMock = jest.spyOn(eventCompressor, 'processQueue');\n    const requestIdleCallbackSpy = jest.spyOn(global, 'requestIdleCallback');\n\n    eventCompressor.processQueue(mockIdleDeadline);\n\n    expect(processQueueMock).toHaveBeenCalledTimes(1);\n\n    // Verify that requestIdleCallback is called again for the remaining tasks\n    expect(requestIdleCallbackSpy).toHaveBeenCalledTimes(1);\n\n    // Simulate the next recursive call by invoking the callback manually\n    const idleCallback = requestIdleCallbackSpy.mock.calls[0][0];\n    idleCallback(mockIdleDeadline);\n\n    // Ensure processQueue was called recursively\n    expect(processQueueMock).toHaveBeenCalledTimes(2);\n  });\n\n  test.each([true, false])('should use webworkers if script exists', async (error: boolean) => {\n    let postMessageMock = jest.fn();\n    let onMessageMock = jest.fn();\n    let onErrorMock = jest.fn();\n    let terminateMock = jest.fn();\n    class MockWorker {\n      postMessage = (e: any) => {\n        postMessageMock = jest.fn(() => {\n          this.onmessage({ data: { compressedEvent: '', sessionId: 1234 } });\n        });\n        onErrorMock = jest.fn(() => {\n          this.onerror(e);\n        });\n        if (error) {\n          onErrorMock(e);\n        } else {\n          postMessageMock(e);\n        }\n      };\n      onmessage = (e: any) => {\n        onMessageMock = jest.fn();\n        onMessageMock(e);\n      };\n      onerror = (e: any) => {\n        onErrorMock = jest.fn();\n        onErrorMock(e);\n      };\n      terminate = () => {\n        terminateMock = jest.fn();\n        terminateMock();\n      };\n    }\n\n    global.Worker = MockWorker as unknown as typeof global.Worker;\n\n    URL.createObjectURL = jest.fn();\n    eventsManager = await createEventsManager<'replay'>({\n      config,\n      type: 'replay',\n      storeType: 'memory',\n    });\n    eventCompressor = new EventCompressor(eventsManager, config, deviceId, 'console.log(\"hi\")');\n\n    const testEvent: eventWithTime = {\n      data: {\n        height: 1,\n        width: 1,\n        href: 'http://localhost',\n      },\n      type: 4,\n      timestamp: 1,\n    };\n    const testSessionId = 1234;\n    eventCompressor.addCompressedEvent(testEvent, testSessionId);\n\n    expect(postMessageMock).toHaveBeenCalledTimes(error ? 0 : 1);\n    expect(onErrorMock).toHaveBeenCalledTimes(error ? 1 : 0);\n\n    eventCompressor.terminate();\n    expect(terminateMock).toHaveBeenCalled();\n  });\n\n  test('should handle DataCloneError and fallback to JSON.stringify', async () => {\n    let onMessageMock = jest.fn();\n    let onErrorMock = jest.fn();\n    let terminateMock = jest.fn();\n    let callCount = 0;\n\n    class MockWorker {\n      postMessage = () => {\n        callCount++;\n        // Simulate DataCloneError on first call, success on second\n        if (callCount === 1) {\n          const error = new Error('DataCloneError');\n          error.name = 'DataCloneError';\n          throw error;\n        }\n        // On second call, simulate success\n        this.onmessage({ data: { compressedEvent: '', sessionId: 1234 } });\n      };\n      onmessage = (e: any) => {\n        onMessageMock = jest.fn();\n        onMessageMock(e);\n      };\n      onerror = (e: any) => {\n        onErrorMock = jest.fn();\n        onErrorMock(e);\n      };\n      terminate = () => {\n        terminateMock = jest.fn();\n        terminateMock();\n      };\n    }\n\n    global.Worker = MockWorker as unknown as typeof global.Worker;\n\n    URL.createObjectURL = jest.fn();\n    eventsManager = await createEventsManager<'replay'>({\n      config,\n      type: 'replay',\n      storeType: 'memory',\n    });\n    eventCompressor = new EventCompressor(eventsManager, config, deviceId, 'console.log(\"hi\")');\n\n    const testEvent: eventWithTime = {\n      data: {\n        height: 1,\n        width: 1,\n        href: 'http://localhost',\n      },\n      type: 4,\n      timestamp: 1,\n    };\n    const testSessionId = 1234;\n    eventCompressor.addCompressedEvent(testEvent, testSessionId);\n\n    // Should be called twice - once with original data (throws DataCloneError), once with JSON.stringify (succeeds)\n    expect(callCount).toBe(2);\n\n    eventCompressor.terminate();\n    expect(terminateMock).toHaveBeenCalled();\n  });\n\n  test('should log warning for unexpected errors in webworker', async () => {\n    let postMessageMock = jest.fn();\n    let onMessageMock = jest.fn();\n    let onErrorMock = jest.fn();\n    let terminateMock = jest.fn();\n\n    class MockWorker {\n      postMessage = (e: any) => {\n        postMessageMock = jest.fn(() => {\n          // Simulate unexpected error\n          const error = new Error('Unexpected error');\n          error.name = 'SomeOtherError';\n          throw error;\n        });\n        onErrorMock = jest.fn(() => {\n          this.onerror(e);\n        });\n        postMessageMock(e);\n      };\n      onmessage = (e: any) => {\n        onMessageMock = jest.fn();\n        onMessageMock(e);\n      };\n      onerror = (e: any) => {\n        onErrorMock = jest.fn();\n        onErrorMock(e);\n      };\n      terminate = () => {\n        terminateMock = jest.fn();\n        terminateMock();\n      };\n    }\n\n    global.Worker = MockWorker as unknown as typeof global.Worker;\n\n    URL.createObjectURL = jest.fn();\n    eventsManager = await createEventsManager<'replay'>({\n      config,\n      type: 'replay',\n      storeType: 'memory',\n    });\n    eventCompressor = new EventCompressor(eventsManager, config, deviceId, 'console.log(\"hi\")');\n\n    const testEvent: eventWithTime = {\n      data: {\n        height: 1,\n        width: 1,\n        href: 'http://localhost',\n      },\n      type: 4,\n      timestamp: 1,\n    };\n    const testSessionId = 1234;\n\n    // Should not throw, but log a warning instead\n    expect(() => {\n      eventCompressor.addCompressedEvent(testEvent, testSessionId);\n    }).not.toThrow();\n\n    // Verify warning was logged\n    expect(mockLoggerProvider['warn']).toHaveBeenCalledWith(\n      'Unexpected error while posting message to worker:',\n      expect.objectContaining({\n        name: 'SomeOtherError',\n        message: 'Unexpected error',\n      }),\n    );\n\n    eventCompressor.terminate();\n    expect(terminateMock).toHaveBeenCalled();\n  });\n\n  test('should call preventDefault on worker onerror to suppress uncaught error propagation', async () => {\n    let capturedOnerror: ((e: any) => void) | undefined;\n    const mockTerminate = jest.fn();\n\n    class MockWorker {\n      set onerror(fn: (e: any) => void) {\n        capturedOnerror = fn;\n      }\n      get onerror() {\n        return capturedOnerror ?? jest.fn();\n      }\n      onmessage: any = null;\n      postMessage = jest.fn();\n      terminate = () => {\n        mockTerminate();\n      };\n    }\n\n    global.Worker = MockWorker as unknown as typeof global.Worker;\n    URL.createObjectURL = jest.fn();\n\n    eventsManager = await createEventsManager<'replay'>({\n      config,\n      type: 'replay',\n      storeType: 'memory',\n    });\n    eventCompressor = new EventCompressor(eventsManager, config, deviceId, 'console.log(\"hi\")');\n\n    expect(capturedOnerror).toBeDefined();\n\n    const mockPreventDefault = jest.fn();\n    const mockErrorEvent = {\n      preventDefault: mockPreventDefault,\n      message: 'test error',\n      filename: 'blob:test',\n      lineno: 1,\n    };\n\n    (capturedOnerror as (e: any) => void)(mockErrorEvent);\n\n    expect(mockPreventDefault).toHaveBeenCalledTimes(1);\n    expect(mockLoggerProvider['error']).toHaveBeenCalledWith(\n      expect.stringContaining('Worker failed, falling back to non-worker compression:'),\n    );\n    expect(mockTerminate).toHaveBeenCalledTimes(1);\n    expect(eventCompressor.worker).toBeUndefined();\n  });\n\n  test('should handle Worker constructor failure and fall back to non-worker compression', async () => {\n    const originalWorker = global.Worker;\n\n    // Mock Worker constructor to throw\n    const mockWorkerConstructor = jest.fn().mockImplementation(() => {\n      throw new Error('Worker constructor failed');\n    });\n    global.Worker = mockWorkerConstructor as any;\n\n    URL.createObjectURL = jest.fn();\n    eventsManager = await createEventsManager<'replay'>({\n      config,\n      type: 'replay',\n      storeType: 'memory',\n    });\n\n    // Create compressor with worker script - should catch the error and fall back\n    eventCompressor = new EventCompressor(eventsManager, config, deviceId, 'console.log(\"hi\")');\n\n    expect(mockLoggerProvider['error']).toHaveBeenCalledWith(\n      'Failed to create worker, falling back to non-worker compression:',\n      expect.objectContaining({\n        message: 'Worker constructor failed',\n      }),\n    );\n\n    // Verify it still works with non-worker compression\n    const testEvent: eventWithTime = {\n      data: {\n        height: 1,\n        width: 1,\n        href: 'http://localhost',\n      },\n      type: 4,\n      timestamp: 1,\n    };\n    const testSessionId = 1234;\n\n    expect(() => {\n      eventCompressor.addCompressedEvent(testEvent, testSessionId);\n    }).not.toThrow();\n\n    global.Worker = originalWorker;\n  });\n\n  describe('FullSnapshot immediate processing', () => {\n    test('should process full snapshot immediately without idle scheduling', () => {\n      const scheduleIdleProcessingMock = jest.spyOn(eventCompressor, 'scheduleIdleProcessing');\n      const addEventMock = jest.spyOn(eventsManager, 'addEvent');\n\n      eventCompressor.enqueueEvent(fullSnapshotEvent, sessionId);\n\n      expect(scheduleIdleProcessingMock).not.toHaveBeenCalled();\n      expect(eventCompressor.taskQueue).toHaveLength(0);\n      expect(addEventMock).toHaveBeenCalledTimes(1);\n    });\n\n    test('should bypass web worker and process full snapshot on main thread', async () => {\n      let postMessageCount = 0;\n      class MockWorker {\n        postMessage = () => {\n          postMessageCount++;\n        };\n        onmessage: any = null;\n        onerror: any = null;\n        terminate = jest.fn();\n      }\n      global.Worker = MockWorker as unknown as typeof global.Worker;\n      URL.createObjectURL = jest.fn();\n\n      eventsManager = await createEventsManager<'replay'>({ config, type: 'replay', storeType: 'memory' });\n      eventCompressor = new EventCompressor(eventsManager, config, deviceId, 'console.log(\"hi\")');\n\n      const addEventMock = jest.spyOn(eventsManager, 'addEvent');\n      eventCompressor.enqueueEvent(fullSnapshotEvent, sessionId);\n\n      // Worker should NOT be used for FullSnapshot\n      expect(postMessageCount).toBe(0);\n      // addEvent should be called synchronously\n      expect(addEventMock).toHaveBeenCalledTimes(1);\n    });\n\n    test('should call onFullSnapshotProcessed callback after adding full snapshot', () => {\n      const onFullSnapshotProcessed = jest.fn();\n      eventCompressor.onFullSnapshotProcessed = onFullSnapshotProcessed;\n\n      eventCompressor.enqueueEvent(fullSnapshotEvent, sessionId);\n\n      expect(onFullSnapshotProcessed).toHaveBeenCalledTimes(1);\n    });\n\n    test('should not call onFullSnapshotProcessed for non-full-snapshot events', () => {\n      const onFullSnapshotProcessed = jest.fn();\n      eventCompressor.onFullSnapshotProcessed = onFullSnapshotProcessed;\n\n      eventCompressor.enqueueEvent(mockEvent, sessionId); // type 4 — not FullSnapshot\n\n      expect(onFullSnapshotProcessed).not.toHaveBeenCalled();\n    });\n\n    test('should drain idle-queue events before adding full snapshot to preserve ordering', () => {\n      // Simulate two incremental events sitting in the idle queue (not yet processed).\n      const incrementalA = { ...mockEvent, timestamp: 100 } as eventWithTime;\n      const incrementalB = { ...mockEvent, timestamp: 200 } as eventWithTime;\n      eventCompressor.taskQueue.push({ event: incrementalA, sessionId });\n      eventCompressor.taskQueue.push({ event: incrementalB, sessionId });\n\n      const addEventMock = jest.spyOn(eventsManager, 'addEvent');\n\n      eventCompressor.enqueueEvent(fullSnapshotEvent, sessionId);\n\n      // All three events should have been added to the manager\n      expect(addEventMock).toHaveBeenCalledTimes(3);\n\n      // Incremental events must come BEFORE the full snapshot\n      const calls = addEventMock.mock.calls.map(\n        (call) => JSON.parse(call[0].event.data) as { type: number; timestamp: number },\n      );\n      expect(calls[0].timestamp).toBe(100); // incrementalA\n      expect(calls[1].timestamp).toBe(200); // incrementalB\n      expect(calls[2].type).toBe(2); // FullSnapshot\n\n      // Idle queue should be empty after draining\n      expect(eventCompressor.taskQueue).toHaveLength(0);\n      expect(eventCompressor.isProcessing).toBe(false);\n    });\n\n    test('should serialize full snapshot with key-ordered JSON', () => {\n      const addEventMock = jest.spyOn(eventsManager, 'addEvent');\n      eventCompressor.enqueueEvent(fullSnapshotEvent, sessionId);\n\n      const callArg = addEventMock.mock.calls[0][0];\n      const serialized = JSON.parse(callArg.event.data);\n      const keys = Object.keys(serialized);\n      expect(keys[0]).toBe('type');\n      expect(keys[1]).toBe('timestamp');\n    });\n  });\n\n  describe('flushQueue', () => {\n    test('should synchronously drain all queued events and reset isProcessing', () => {\n      const addEventMock = jest.spyOn(eventsManager, 'addEvent');\n\n      eventCompressor.taskQueue.push({ event: mockEvent as eventWithTime, sessionId });\n      eventCompressor.taskQueue.push({ event: mockEvent as eventWithTime, sessionId });\n      eventCompressor.isProcessing = true;\n\n      eventCompressor.flushQueue();\n\n      expect(addEventMock).toHaveBeenCalledTimes(2);\n      expect(eventCompressor.taskQueue).toHaveLength(0);\n      expect(eventCompressor.isProcessing).toBe(false);\n    });\n\n    test('should be a no-op and reset isProcessing when queue is empty', () => {\n      const addEventMock = jest.spyOn(eventsManager, 'addEvent');\n      eventCompressor.isProcessing = true;\n\n      eventCompressor.flushQueue();\n\n      expect(addEventMock).not.toHaveBeenCalled();\n      expect(eventCompressor.isProcessing).toBe(false);\n    });\n\n    test('should drain pendingQueue events before processing taskQueue on flush', () => {\n      const addEventMock = jest.spyOn(eventsManager, 'addEvent');\n\n      // Simulate events that arrived in pendingQueue before idle callback fired\n      eventCompressor.pendingQueue.push({ event: mockEvent as eventWithTime, sessionId });\n      eventCompressor.pendingQueue.push({ event: mockEvent as eventWithTime, sessionId });\n      eventCompressor.isProcessing = true;\n\n      eventCompressor.flushQueue();\n\n      // Both pending events must be compressed and added to the manager\n      expect(addEventMock).toHaveBeenCalledTimes(2);\n      expect(eventCompressor.pendingQueue).toHaveLength(0);\n      expect(eventCompressor.taskQueue).toHaveLength(0);\n      expect(eventCompressor.isProcessing).toBe(false);\n    });\n\n    test('should drain both pendingQueue and taskQueue events on flush', () => {\n      const addEventMock = jest.spyOn(eventsManager, 'addEvent');\n\n      // One event already promoted to taskQueue, one still in pendingQueue\n      eventCompressor.taskQueue.push({ event: mockEvent as eventWithTime, sessionId });\n      eventCompressor.pendingQueue.push({ event: mockEvent as eventWithTime, sessionId });\n      eventCompressor.isProcessing = true;\n\n      eventCompressor.flushQueue();\n\n      expect(addEventMock).toHaveBeenCalledTimes(2);\n      expect(eventCompressor.pendingQueue).toHaveLength(0);\n      expect(eventCompressor.taskQueue).toHaveLength(0);\n      expect(eventCompressor.isProcessing).toBe(false);\n    });\n\n    test('should bypass web worker and compress synchronously even when a worker is present', async () => {\n      const postMessageMock = jest.fn();\n      class MockWorker {\n        postMessage = postMessageMock;\n        onmessage: any = null;\n        onerror: any = null;\n        terminate = jest.fn();\n      }\n      global.Worker = MockWorker as unknown as typeof global.Worker;\n      URL.createObjectURL = jest.fn();\n\n      const workerEventsManager = await createEventsManager<'replay'>({\n        config,\n        type: 'replay',\n        storeType: 'memory',\n      });\n      const addEventMock = jest.spyOn(workerEventsManager, 'addEvent');\n      const workerCompressor = new EventCompressor(workerEventsManager, config, deviceId, 'console.log(\"hi\")');\n\n      workerCompressor.taskQueue.push({ event: mockEvent as eventWithTime, sessionId });\n      workerCompressor.flushQueue();\n\n      // Worker must NOT be used — postMessage is async and events would be lost on unload\n      expect(postMessageMock).not.toHaveBeenCalled();\n      // Event must be written directly to the manager\n      expect(addEventMock).toHaveBeenCalledTimes(1);\n      expect(workerCompressor.taskQueue).toHaveLength(0);\n      expect(workerCompressor.isProcessing).toBe(false);\n    });\n  });\n\n  describe('mergeMutationTasks via processQueue', () => {\n    function makeMutationEvent(timestamp: number): eventWithTime {\n      return {\n        type: EventType.IncrementalSnapshot,\n        timestamp,\n        data: { source: IncrementalSource.Mutation, texts: [], attributes: [], removes: [], adds: [] } as mutationData,\n      };\n    }\n\n    test('passes through a single pending event unchanged when merging is enabled', () => {\n      eventCompressor.config.performanceConfig = { enabled: true, mergeMutations: true };\n      const addEventMock = jest.spyOn(eventsManager, 'addEvent');\n      const m1 = makeMutationEvent(100);\n      eventCompressor.pendingQueue.push({ event: m1, sessionId });\n\n      const mockIdleDeadline = { timeRemaining: () => 50, didTimeout: false } as IdleDeadline;\n      eventCompressor.processQueue(mockIdleDeadline);\n\n      expect(addEventMock).toHaveBeenCalledTimes(1);\n      expect(eventCompressor.pendingQueue).toHaveLength(0);\n    });\n\n    test('merges pending mutation events into a single task before processing', () => {\n      eventCompressor.config.performanceConfig = { enabled: true, mergeMutations: true };\n      const addEventMock = jest.spyOn(eventsManager, 'addEvent');\n      const m1 = makeMutationEvent(100);\n      const m2 = makeMutationEvent(200);\n      eventCompressor.pendingQueue.push({ event: m1, sessionId });\n      eventCompressor.pendingQueue.push({ event: m2, sessionId });\n\n      const mockIdleDeadline = { timeRemaining: () => 50, didTimeout: false } as IdleDeadline;\n      eventCompressor.processQueue(mockIdleDeadline);\n\n      // Two pending mutations → merged into one → one compressed event\n      expect(addEventMock).toHaveBeenCalledTimes(1);\n      expect(eventCompressor.pendingQueue).toHaveLength(0);\n    });\n\n    test('keeps tasks from different sessions separate when merging', () => {\n      eventCompressor.config.performanceConfig = { enabled: true, mergeMutations: true };\n      const addEventMock = jest.spyOn(eventsManager, 'addEvent');\n      const sessionA = 111;\n      const sessionB = 222;\n      const m1 = makeMutationEvent(100);\n      const m2 = makeMutationEvent(200);\n      const m3 = makeMutationEvent(300);\n      // Two mutations for sessionA, one for sessionB — sessionA run merges; sessionB stays as-is\n      eventCompressor.pendingQueue.push({ event: m1, sessionId: sessionA });\n      eventCompressor.pendingQueue.push({ event: m2, sessionId: sessionA });\n      eventCompressor.pendingQueue.push({ event: m3, sessionId: sessionB });\n\n      const mockIdleDeadline = { timeRemaining: () => 50, didTimeout: false } as IdleDeadline;\n      eventCompressor.processQueue(mockIdleDeadline);\n\n      // sessionA: 2 → 1 merged; sessionB: 1 stays → 2 total compressed events\n      expect(addEventMock).toHaveBeenCalledTimes(2);\n    });\n  });\n\n  describe('compressEvent key ordering', () => {\n    test('should serialize without delay when delay is absent', () => {\n      const result = eventCompressor.compressEvent(mockEvent as eventWithTime);\n      const parsed = JSON.parse(result);\n      const keys = Object.keys(parsed);\n      expect(keys[0]).toBe('type');\n      expect(keys[1]).toBe('timestamp');\n      expect(keys).not.toContain('delay');\n    });\n\n    test('should include delay when present and place it after timestamp', () => {\n      const eventWithDelay = { ...mockEvent, delay: 50 } as eventWithTime & { delay: number };\n      const result = eventCompressor.compressEvent(eventWithDelay);\n      const parsed = JSON.parse(result);\n      const keys = Object.keys(parsed);\n      expect(keys[0]).toBe('type');\n      expect(keys[1]).toBe('timestamp');\n      expect(keys[2]).toBe('delay');\n      expect(parsed.delay).toBe(50);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/events-idb-store-multitab.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-non-null-assertion */\n/**\n * Multi-tab IDB contamination regression tests.\n *\n * These tests demonstrate / regression-guard a family of bugs that occur when two tabs\n * share the same IndexedDB database (keyed only on apiKey.substring(0,10)):\n *\n * BUG 1 – Cross-tab sequence reads:\n *   getSequencesToSend() does a full cursor scan with no session/tab filter.\n *   Tab A can read and return sequences that were written by Tab B.\n *\n * BUG 2 – AbortError does not trigger fallback:\n *   Concurrent readwrite transactions on overlapping object stores produce\n *   AbortErrors.  The AbortError lands only in tx.done.catch(), which never\n *   calls recordFailure(), so consecutiveFailures never reaches the threshold\n *   and onPersistentFailure() is never invoked — the fallback to memory store\n *   is silently skipped.\n *\n * BUG 3 – addEventToCurrentSequence drops cross-tab events:\n *   When Tab A sees a sessionCurrentSequence record owned by Tab B, the original\n *   code simply overwrote it with [event] and Tab A's tabId, dropping Tab B's\n *   in-progress events entirely.  Two tabs sharing a sessionId would ping-pong\n *   overwriting each other and lose most events.\n *\n * BUG 4 – storeCurrentSequence is not transactional:\n *   The original implementation used three separate IDB requests, allowing a\n *   concurrent addEventToCurrentSequence call to interleave between the read\n *   and the write — losing events appended after the read.\n */\n\nimport { IDBFactory } from 'fake-indexeddb';\nimport { ILogger } from '@amplitude/analytics-core';\nimport * as EventsIDBStore from '../src/events/events-idb-store';\nimport { SessionReplayEventsIDBStore } from '../src/events/events-idb-store';\n\ntype MockedLogger = jest.Mocked<ILogger>;\n\nconst apiKey = 'static_key_multitab'; // 10-char prefix: \"static_key\"\n\nconst makeLogger = (): MockedLogger => ({\n  error: jest.fn(),\n  log: jest.fn(),\n  disable: jest.fn(),\n  enable: jest.fn(),\n  warn: jest.fn(),\n  debug: jest.fn(),\n});\n\nconst mockEvent = JSON.stringify({ type: 4, data: { href: 'https://example.com' }, timestamp: 1000 });\nconst mockEvent2 = JSON.stringify({ type: 2, data: { href: 'https://example.com' }, timestamp: 2000 });\n\n/**\n * Point both IDBStore instances at the same IDBFactory so they genuinely share\n * a database, matching the real browser multi-tab scenario.\n */\nfunction useSharedIDBFactory() {\n  const factory = new IDBFactory();\n  // Swap out the global indexedDB for the duration of this test block.\n  // jest-setup.js resets it per-test; we override inside the test itself.\n  const restore = () => {\n    global.indexedDB = new IDBFactory();\n  };\n  global.indexedDB = factory;\n  return { factory, restore };\n}\n\ndescribe('multi-tab IDB contamination', () => {\n  afterEach(() => {\n    jest.resetAllMocks();\n    // Restore to a fresh factory (matching jest-setup.js behaviour).\n    global.indexedDB = new IDBFactory();\n  });\n\n  // ---------------------------------------------------------------------------\n  // getSequencesToSend returns ALL completed sequences (any tab may flush them)\n  // ---------------------------------------------------------------------------\n  // Note: completed sequences in sequencesToSend are intentionally visible to\n  // all tabs.  Filtering by tabId would cause event loss on page reload because\n  // a new store instance gets a fresh in-memory UUID and would never see\n  // sequences written before the reload.  Completed sequences are safe to flush\n  // by any tab — the server deduplicates and cleanUpSessionEventsStore on an\n  // already-deleted key is a no-op.\n  describe('getSequencesToSend – cross-tab visibility', () => {\n    test('both tabs see all completed sequences (any instance can flush)', async () => {\n      const { restore } = useSharedIDBFactory();\n      try {\n        const tabA = await SessionReplayEventsIDBStore.new('replay', {\n          apiKey,\n          loggerProvider: makeLogger(),\n          tabId: 'tab-a',\n        });\n        const tabB = await SessionReplayEventsIDBStore.new('replay', {\n          apiKey,\n          loggerProvider: makeLogger(),\n          tabId: 'tab-b',\n        });\n\n        expect(tabA).toBeDefined();\n        expect(tabB).toBeDefined();\n\n        await tabB!.storeSendingEvents(9999, [mockEvent2]);\n        await tabA!.storeSendingEvents(1111, [mockEvent]);\n\n        // Both tabs see all sequences — this ensures a page-reloaded instance\n        // (which gets a fresh UUID) can still flush sequences from before the reload.\n        const seenByA = (await tabA!.getSequencesToSend()) ?? [];\n        const seenByB = (await tabB!.getSequencesToSend()) ?? [];\n\n        const sessionIdsSeenByA = seenByA.map((s) => s.sessionId).sort();\n        const sessionIdsSeenByB = seenByB.map((s) => s.sessionId).sort();\n\n        expect(sessionIdsSeenByA).toEqual([1111, 9999]);\n        expect(sessionIdsSeenByB).toEqual([1111, 9999]);\n      } finally {\n        restore();\n      }\n    });\n  });\n\n  // ---------------------------------------------------------------------------\n  // BUG 2: AbortErrors from concurrent writes do not trigger the fallback\n  // ---------------------------------------------------------------------------\n  describe('BUG 2 – AbortError from tx.done.catch never calls recordFailure', () => {\n    test('AbortErrors occurring only in tx.done.catch should trigger onPersistentFailure after threshold', async () => {\n      /**\n       * The current code has:\n       *\n       *   tx.done.catch((e) => {\n       *     if (!errorLogged) {\n       *       logIdbError(…);   // ← logs only, NO recordFailure() call\n       *     }\n       *   });\n       *\n       * So when the outer try/catch never fires (put() succeeds but the\n       * transaction later aborts at commit time), consecutiveFailures is never\n       * incremented and onPersistentFailure() is never called.\n       *\n       * After the fix, recordFailure() should also be called from tx.done.catch\n       * when the error is NOT an AbortError (or unconditionally, depending on\n       * the chosen fix strategy — see the bug description for details).\n       *\n       * Here we simulate the exact scenario: put() resolves successfully (outer\n       * try succeeds, recordSuccess() is called), but tx.done later rejects —\n       * a common occurrence under IDB transaction abort due to storage pressure\n       * or concurrent writes.  We verify that the consecutive-failure counter\n       * is incremented by the tx.done.catch path.\n       */\n      const abortError = new DOMException(\n        'The transaction was aborted, so the request cannot be fulfilled.',\n        'AbortError',\n      );\n\n      // Build a txDone promise that rejects AFTER the put resolves, matching\n      // real IDB behaviour where the transaction aborts at commit time.\n      let rejectTxDone!: (e: unknown) => void;\n      const txDone = new Promise<void>((_resolve, reject) => {\n        rejectTxDone = reject;\n      });\n      // Suppress unhandled-rejection warnings from Jest.\n      txDone.catch(() => {\n        // handled by the store's tx.done.catch\n      });\n\n      const mockDB = {\n        transaction: jest.fn().mockReturnValue({\n          objectStore: jest.fn().mockReturnValue({\n            get: jest.fn().mockResolvedValue(undefined),\n            put: jest.fn().mockImplementation(() => {\n              // Trigger the abort *after* put resolves so the outer try block\n              // completes successfully (recordSuccess() fires), but tx.done\n              // still rejects — this is the \"silent drop\" scenario.\n              void Promise.resolve().then(() => rejectTxDone(abortError));\n              return Promise.resolve(undefined);\n            }),\n          }),\n          done: txDone,\n        }),\n      } as unknown as EventsIDBStore.SessionReplayDB & {\n        transaction: jest.Mock;\n      };\n\n      jest\n        .spyOn(EventsIDBStore, 'createStore')\n        .mockResolvedValue(mockDB as unknown as import('idb').IDBPDatabase<EventsIDBStore.SessionReplayDB>);\n\n      const onPersistentFailure = jest.fn();\n      const store = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: makeLogger(),\n        onPersistentFailure,\n        consecutiveFailureThreshold: 1, // trigger on first failure\n      });\n\n      expect(store).toBeDefined();\n\n      // Trigger addEventToCurrentSequence.  The outer try succeeds (put\n      // resolves), recordSuccess() fires — but tx.done then rejects with an\n      // AbortError.  Currently recordFailure() is NOT called from tx.done.catch,\n      // so onPersistentFailure never fires.\n      await store!.addEventToCurrentSequence(123, mockEvent);\n\n      // Allow the microtask queue to drain so tx.done.catch fires.\n      await Promise.resolve();\n      await Promise.resolve();\n\n      // EXPECTED (post-fix): onPersistentFailure called once.\n      // ACTUAL (pre-fix): onPersistentFailure never called → this assertion FAILS.\n      expect(onPersistentFailure).toHaveBeenCalledTimes(1);\n    });\n\n    test('AbortError from getSequencesToSend tx.done.catch should also trigger onPersistentFailure', async () => {\n      const abortError = new DOMException(\n        'The transaction was aborted, so the request cannot be fulfilled.',\n        'AbortError',\n      );\n\n      let rejectTxDone!: (e: unknown) => void;\n      const txDone = new Promise<void>((_resolve, reject) => {\n        rejectTxDone = reject;\n      });\n      txDone.catch(() => {\n        // handled\n      });\n\n      const mockDB = {\n        transaction: jest.fn().mockReturnValue({\n          store: {\n            openCursor: jest.fn().mockImplementation(() => {\n              // openCursor() resolves with null (no records); abort fires after.\n              void Promise.resolve().then(() => rejectTxDone(abortError));\n              return Promise.resolve(null);\n            }),\n          },\n          done: txDone,\n        }),\n      };\n\n      jest\n        .spyOn(EventsIDBStore, 'createStore')\n        .mockResolvedValue(mockDB as unknown as import('idb').IDBPDatabase<EventsIDBStore.SessionReplayDB>);\n\n      const onPersistentFailure = jest.fn();\n      const store = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: makeLogger(),\n        onPersistentFailure,\n        consecutiveFailureThreshold: 1,\n      });\n\n      expect(store).toBeDefined();\n\n      await store!.getSequencesToSend();\n\n      // Allow microtasks to settle so tx.done.catch fires.\n      await Promise.resolve();\n      await Promise.resolve();\n\n      // EXPECTED (post-fix): onPersistentFailure called once.\n      // ACTUAL (pre-fix): never called → FAILS.\n      expect(onPersistentFailure).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  // ---------------------------------------------------------------------------\n  // BUG 3: addEventToCurrentSequence drops events from the foreign tab\n  // ---------------------------------------------------------------------------\n  describe('BUG 3 – addEventToCurrentSequence cross-tab event drop', () => {\n    test('Tab A promotes Tab B in-progress events to sequencesToSend instead of dropping them', async () => {\n      const { restore } = useSharedIDBFactory();\n      try {\n        const tabA = await SessionReplayEventsIDBStore.new('replay', {\n          apiKey,\n          loggerProvider: makeLogger(),\n          tabId: 'tab-a',\n        });\n        const tabB = await SessionReplayEventsIDBStore.new('replay', {\n          apiKey,\n          loggerProvider: makeLogger(),\n          tabId: 'tab-b',\n        });\n\n        expect(tabA).toBeDefined();\n        expect(tabB).toBeDefined();\n\n        const sessionId = 555;\n\n        // Tab B records three events for the shared session.\n        const b1 = JSON.stringify({ type: 4, src: 'b', n: 1 });\n        const b2 = JSON.stringify({ type: 2, src: 'b', n: 2 });\n        const b3 = JSON.stringify({ type: 3, src: 'b', n: 3 });\n        await tabB!.addEventToCurrentSequence(sessionId, b1);\n        await tabB!.addEventToCurrentSequence(sessionId, b2);\n        await tabB!.addEventToCurrentSequence(sessionId, b3);\n\n        // Tab A now records its first event for the shared session.  In the buggy\n        // implementation this overwrites the slot with just [a1] under tab-a's\n        // tabId, dropping b1/b2/b3 entirely.  The fix promotes b1/b2/b3 to\n        // sequencesToSend (still tagged with tab-b) so they survive.\n        const a1 = JSON.stringify({ type: 4, src: 'a', n: 1 });\n        await tabA!.addEventToCurrentSequence(sessionId, a1);\n\n        // Tab A's current-sequence slot now holds only its own [a1].\n        const aCurrent = await tabA!.getCurrentSequenceEvents(sessionId);\n        expect(aCurrent).toEqual([{ events: [a1], sessionId }]);\n\n        // The promoted tab-b sequence is in sequencesToSend — visible to both\n        // tabs since completed sequences are not filtered by tabId.\n        const tabASequences = await tabA!.getSequencesToSend();\n        expect(tabASequences).toEqual([{ sessionId, sequenceId: expect.any(Number), events: [b1, b2, b3] }]);\n        const tabBSequences = await tabB!.getSequencesToSend();\n        expect(tabBSequences).toEqual([{ sessionId, sequenceId: expect.any(Number), events: [b1, b2, b3] }]);\n      } finally {\n        restore();\n      }\n    });\n\n    test('foreign-tab promotion is a no-op when the foreign sequence is empty', async () => {\n      // Edge case: sessionCurrentSequence may be { events: [] } (e.g. immediately\n      // after a successful storeCurrentSequence reset).  Promoting an empty array\n      // into sequencesToSend would create a useless empty sequence.\n      const { restore } = useSharedIDBFactory();\n      try {\n        const tabA = await SessionReplayEventsIDBStore.new('replay', {\n          apiKey,\n          loggerProvider: makeLogger(),\n          tabId: 'tab-a',\n        });\n        const tabB = await SessionReplayEventsIDBStore.new('replay', {\n          apiKey,\n          loggerProvider: makeLogger(),\n          tabId: 'tab-b',\n        });\n\n        const sessionId = 777;\n\n        // Tab B writes an event then promotes it via storeCurrentSequence so the\n        // current-sequence slot ends up { events: [], tabId: tab-b }.\n        await tabB!.addEventToCurrentSequence(sessionId, JSON.stringify({ b: 1 }));\n        await tabB!.storeCurrentSequence(sessionId);\n\n        // Tab A claims the slot.  No empty record should land in sequencesToSend\n        // for tab-b on top of the existing one.\n        const a1 = JSON.stringify({ a: 1 });\n        await tabA!.addEventToCurrentSequence(sessionId, a1);\n\n        // Only the original tab-b sequence is present in tab-b's view; no extra\n        // empty record was written.\n        const tabBSequences = await tabB!.getSequencesToSend();\n        expect(tabBSequences).toHaveLength(1);\n        expect(tabBSequences![0].events).toHaveLength(1);\n      } finally {\n        restore();\n      }\n    });\n\n    test('every event from both tabs is recoverable via getSequencesToSend (no events dropped)', async () => {\n      // End-to-end invariant: when two tabs interleave addEventToCurrentSequence\n      // calls on the same sessionId, every event lands in sequencesToSend and is\n      // visible to any tab that calls getSequencesToSend — including a reloaded\n      // instance with a fresh UUID.\n      const { restore } = useSharedIDBFactory();\n      try {\n        const tabA = await SessionReplayEventsIDBStore.new('replay', {\n          apiKey,\n          loggerProvider: makeLogger(),\n          tabId: 'tab-a',\n        });\n        const tabB = await SessionReplayEventsIDBStore.new('replay', {\n          apiKey,\n          loggerProvider: makeLogger(),\n          tabId: 'tab-b',\n        });\n\n        const sessionId = 888;\n        const aEvents = Array.from({ length: 5 }, (_, i) => JSON.stringify({ src: 'a', n: i }));\n        const bEvents = Array.from({ length: 5 }, (_, i) => JSON.stringify({ src: 'b', n: i }));\n\n        // Interleave A and B writes; this is the ping-pong scenario.\n        for (let i = 0; i < 5; i++) {\n          await tabA!.addEventToCurrentSequence(sessionId, aEvents[i]);\n          await tabB!.addEventToCurrentSequence(sessionId, bEvents[i]);\n        }\n\n        // Both tabs flush their current sequences to sequencesToSend.\n        await tabA!.storeCurrentSequence(sessionId);\n        await tabB!.storeCurrentSequence(sessionId);\n\n        // Either tab's view must contain every event — since completed sequences\n        // are not filtered by tabId, both views are identical.\n        const seenByA = (await tabA!.getSequencesToSend()) ?? [];\n        const allEvents = seenByA.flatMap((s) => s.events);\n\n        const expected = [...aEvents, ...bEvents].sort();\n        expect(allEvents.slice().sort()).toEqual(expected);\n      } finally {\n        restore();\n      }\n    });\n  });\n\n  // ---------------------------------------------------------------------------\n  // BUG 4: storeCurrentSequence atomicity under concurrent writes\n  // ---------------------------------------------------------------------------\n  describe('BUG 4 – storeCurrentSequence atomicity', () => {\n    test('storeCurrentSequence does not drop events appended concurrently by addEventToCurrentSequence', async () => {\n      // The bug: with three separate transactions (db.get, db.put sequencesToSend,\n      // db.put sessionCurrentSequence), a concurrent addEvent can interleave between\n      // the read and the reset, and the appended event is then overwritten by the\n      // reset to [].  With the fix, the entire promote+reset is wrapped in one\n      // readwrite transaction, so addEvent is queued by IDB until storeCurrentSequence\n      // commits — the appended event survives.\n      const { restore } = useSharedIDBFactory();\n      try {\n        const store = await SessionReplayEventsIDBStore.new('replay', {\n          apiKey,\n          loggerProvider: makeLogger(),\n          tabId: 'tab-only',\n        });\n        expect(store).toBeDefined();\n\n        const sessionId = 12345;\n\n        // Seed the current sequence with a few events.\n        await store!.addEventToCurrentSequence(sessionId, JSON.stringify({ pre: 1 }));\n        await store!.addEventToCurrentSequence(sessionId, JSON.stringify({ pre: 2 }));\n\n        // Race storeCurrentSequence against several concurrent addEvent calls.\n        // IDB serializes overlapping readwrite transactions, so the addEvent calls\n        // must either land before storeCurrentSequence (becoming part of the\n        // promoted sequence) or after it (landing in a fresh current sequence).\n        // What MUST NOT happen: the appended events get silently overwritten.\n        const concurrentEvents = Array.from({ length: 5 }, (_, i) => JSON.stringify({ post: i }));\n        const ops = [\n          store!.storeCurrentSequence(sessionId),\n          ...concurrentEvents.map((e) => store!.addEventToCurrentSequence(sessionId, e)),\n        ];\n        await Promise.all(ops);\n\n        // Sum events across both stores.\n        const sequencesToSend = (await store!.getSequencesToSend()) ?? [];\n        const currentSequence = (await store!.getCurrentSequenceEvents(sessionId)) ?? [];\n        const total =\n          sequencesToSend.reduce((acc, s) => acc + s.events.length, 0) +\n          currentSequence.reduce((acc, s) => acc + s.events.length, 0);\n\n        // 2 (pre) + 5 (post) = 7 events should be present total — none dropped.\n        expect(total).toBe(7);\n      } finally {\n        restore();\n      }\n    });\n\n    test('storeCurrentSequence is a no-op when the slot is owned by another tab', async () => {\n      // Without the fix, storeCurrentSequence would happily promote another tab's\n      // events under THIS tab's tabId, hijacking them.  The fix adds an ownership\n      // check that skips foreign-tab records.\n      const { restore } = useSharedIDBFactory();\n      try {\n        const tabA = await SessionReplayEventsIDBStore.new('replay', {\n          apiKey,\n          loggerProvider: makeLogger(),\n          tabId: 'tab-a',\n        });\n        const tabB = await SessionReplayEventsIDBStore.new('replay', {\n          apiKey,\n          loggerProvider: makeLogger(),\n          tabId: 'tab-b',\n        });\n\n        const sessionId = 4242;\n\n        // Tab B writes events; Tab A then calls storeCurrentSequence on the same\n        // session.  Tab A must NOT promote Tab B's events under its own tabId.\n        const b1 = JSON.stringify({ src: 'b', n: 1 });\n        const b2 = JSON.stringify({ src: 'b', n: 2 });\n        await tabB!.addEventToCurrentSequence(sessionId, b1);\n        await tabB!.addEventToCurrentSequence(sessionId, b2);\n\n        const result = await tabA!.storeCurrentSequence(sessionId);\n        expect(result).toBeUndefined();\n\n        // Tab B still owns the current sequence with both events — Tab A did not\n        // overwrite it.\n        const tabBCurrent = await tabB!.getCurrentSequenceEvents(sessionId);\n        expect(tabBCurrent).toEqual([{ events: [b1, b2], sessionId }]);\n\n        // Tab A's view of sequencesToSend should be empty — it did not steal.\n        expect(await tabA!.getSequencesToSend()).toEqual([]);\n      } finally {\n        restore();\n      }\n    });\n  });\n\n  // ---------------------------------------------------------------------------\n  // getCurrentSequenceEvents tab-ID filtering\n  // ---------------------------------------------------------------------------\n  describe('getCurrentSequenceEvents tab filtering', () => {\n    test('getCurrentSequenceEvents(sessionId) returns undefined for a foreign-tab record', async () => {\n      const { restore } = useSharedIDBFactory();\n      try {\n        const tabA = await SessionReplayEventsIDBStore.new('replay', {\n          apiKey,\n          loggerProvider: makeLogger(),\n          tabId: 'tab-a',\n        });\n        const tabB = await SessionReplayEventsIDBStore.new('replay', {\n          apiKey,\n          loggerProvider: makeLogger(),\n          tabId: 'tab-b',\n        });\n\n        const sessionId = 321;\n        await tabB!.addEventToCurrentSequence(sessionId, mockEvent);\n\n        // Tab A asks for the current sequence by session ID — it belongs to tab B.\n        const result = await tabA!.getCurrentSequenceEvents(sessionId);\n        expect(result).toBeUndefined();\n      } finally {\n        restore();\n      }\n    });\n\n    test('getCurrentSequenceEvents() (no sessionId) filters out foreign-tab records', async () => {\n      const { restore } = useSharedIDBFactory();\n      try {\n        const tabA = await SessionReplayEventsIDBStore.new('replay', {\n          apiKey,\n          loggerProvider: makeLogger(),\n          tabId: 'tab-a',\n        });\n        const tabB = await SessionReplayEventsIDBStore.new('replay', {\n          apiKey,\n          loggerProvider: makeLogger(),\n          tabId: 'tab-b',\n        });\n\n        // Each tab writes to a different session so both records land in the store.\n        await tabA!.addEventToCurrentSequence(111, mockEvent);\n        await tabB!.addEventToCurrentSequence(222, mockEvent2);\n\n        // Tab A sees only its own record.\n        const eventsA = await tabA!.getCurrentSequenceEvents();\n        expect(eventsA).toHaveLength(1);\n        expect(eventsA![0].sessionId).toBe(111);\n\n        // Tab B sees only its own record.\n        const eventsB = await tabB!.getCurrentSequenceEvents();\n        expect(eventsB).toHaveLength(1);\n        expect(eventsB![0].sessionId).toBe(222);\n      } finally {\n        restore();\n      }\n    });\n  });\n\n  // ---------------------------------------------------------------------------\n  // storeCurrentSequence skips empty current sequences\n  // ---------------------------------------------------------------------------\n  describe('storeCurrentSequence empty-sequence guard', () => {\n    test('storeCurrentSequence returns undefined and writes no row when current sequence is empty', async () => {\n      const { restore } = useSharedIDBFactory();\n      try {\n        const store = await SessionReplayEventsIDBStore.new('replay', {\n          apiKey,\n          loggerProvider: makeLogger(),\n          tabId: 'tab-only',\n        });\n\n        const sessionId = 9876;\n\n        // Write one event, then flush it (current sequence becomes []).\n        await store!.addEventToCurrentSequence(sessionId, mockEvent);\n        await store!.storeCurrentSequence(sessionId);\n\n        // Now the slot is reset to events: [].  A second storeCurrentSequence\n        // call should be a no-op: no empty row written to sequencesToSend.\n        const result = await store!.storeCurrentSequence(sessionId);\n        expect(result).toBeUndefined();\n\n        // Only the original flush sequence is present.\n        const sequences = await store!.getSequencesToSend();\n        expect(sequences).toHaveLength(1);\n        expect(sequences![0].events).toEqual([mockEvent]);\n      } finally {\n        restore();\n      }\n    });\n  });\n\n  // ---------------------------------------------------------------------------\n  // Default consecutiveFailureThreshold lowered to 1 (eager fallback to memory)\n  // ---------------------------------------------------------------------------\n  describe('default consecutiveFailureThreshold', () => {\n    test('first IDB failure triggers onPersistentFailure (default threshold = 1)', async () => {\n      // Sabotage the DB so every operation fails.\n      const mockDB = {\n        get: jest.fn().mockImplementation(() => Promise.reject(new Error('boom'))),\n        put: jest.fn().mockImplementation(() => Promise.reject(new Error('boom'))),\n        delete: jest.fn().mockImplementation(() => Promise.reject(new Error('boom'))),\n        transaction: jest.fn().mockImplementation(() => {\n          throw new Error('boom');\n        }),\n      } as unknown as import('idb').IDBPDatabase<EventsIDBStore.SessionReplayDB>;\n      jest.spyOn(EventsIDBStore, 'createStore').mockResolvedValue(mockDB);\n\n      const onPersistentFailure = jest.fn();\n      const store = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: makeLogger(),\n        onPersistentFailure,\n        // NO consecutiveFailureThreshold — must default to 1.\n      });\n\n      expect(store).toBeDefined();\n\n      // Single failure should trigger fallback immediately.\n      await store!.getSequencesToSend();\n      expect(onPersistentFailure).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  // ---------------------------------------------------------------------------\n  // tx.done.catch in storeCurrentSequence — abort routes through recordFailure\n  // ---------------------------------------------------------------------------\n  describe('storeCurrentSequence tx.done.catch', () => {\n    test('AbortError from storeCurrentSequence tx.done.catch triggers onPersistentFailure', async () => {\n      // Outer try succeeds (puts/get resolve), but tx.done rejects after — the\n      // tx.done.catch handler must call recordFailure() so the threshold mechanism\n      // still trips fallback (mirroring the same fix verified for addEventToCurrentSequence\n      // and getSequencesToSend in BUG 2 above).\n      const abortError = new DOMException(\n        'The transaction was aborted, so the request cannot be fulfilled.',\n        'AbortError',\n      );\n\n      let rejectTxDone!: (e: unknown) => void;\n      const txDone = new Promise<void>((_resolve, reject) => {\n        rejectTxDone = reject;\n      });\n      txDone.catch(() => {\n        // handled by the store's tx.done.catch\n      });\n\n      const mockDB = {\n        transaction: jest.fn().mockReturnValue({\n          objectStore: jest.fn().mockReturnValue({\n            // Return a record so storeCurrentSequence proceeds to the put path.\n            get: jest.fn().mockResolvedValue({ sessionId: 1, events: [mockEvent], tabId: 'tab-only' }),\n            put: jest.fn().mockImplementation(() => {\n              // Trigger abort *after* the put resolves so outer try succeeds.\n              void Promise.resolve().then(() => rejectTxDone(abortError));\n              return Promise.resolve(1); // sequenceId\n            }),\n          }),\n          done: txDone,\n        }),\n      } as unknown as EventsIDBStore.SessionReplayDB & { transaction: jest.Mock };\n\n      jest\n        .spyOn(EventsIDBStore, 'createStore')\n        .mockResolvedValue(mockDB as unknown as import('idb').IDBPDatabase<EventsIDBStore.SessionReplayDB>);\n\n      const onPersistentFailure = jest.fn();\n      const store = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: makeLogger(),\n        onPersistentFailure,\n        consecutiveFailureThreshold: 1,\n        tabId: 'tab-only',\n      });\n\n      expect(store).toBeDefined();\n\n      await store!.storeCurrentSequence(1);\n\n      // Drain the microtask queue so tx.done.catch fires.\n      await Promise.resolve();\n      await Promise.resolve();\n\n      expect(onPersistentFailure).toHaveBeenCalledTimes(1);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/events-idb-store-timeout.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-non-null-assertion */\n/**\n * Timeout / hang protection regression tests.\n *\n * IndexedDB operations can hang indefinitely with no error, no rejection.\n * The two scenarios covered here:\n *\n * SCENARIO 1 – openDB hang at init\n *   When another tab holds an open connection during a version upgrade, or the\n *   DB is in a \"closing\" state (documented Chrome behaviour), `openDB` blocks\n *   forever.  Without a timeout, SessionReplayEventsIDBStore.new() never\n *   resolves and the SDK never initialises a store.  With the fix, openDB is\n *   wrapped with a 2-second timeout; on timeout, the inner promise rejects,\n *   the static `new()` catch returns `undefined`, and the caller falls back\n *   to the in-memory store.\n *\n * SCENARIO 2 – mid-recording transaction stall\n *   A readwrite transaction may never settle (storage pressure on some\n *   browsers stalls instead of throwing).  Without a timeout, neither the\n *   outer try/catch nor `tx.done.catch` fire — `recordFailure()` is never\n *   called and the memory fallback never triggers.  With the fix, an\n *   `armTxDoneTimeout` watcher fires `recordFailure()` after 5s of stall.\n */\nimport { ILogger } from '@amplitude/analytics-core';\nimport * as EventsIDBStore from '../src/events/events-idb-store';\nimport { SessionReplayEventsIDBStore, withTimeout, generateUUID } from '../src/events/events-idb-store';\n\ntype MockedLogger = jest.Mocked<ILogger>;\n\nconst apiKey = 'static_key_timeout_test'; // 10-char prefix\n\nconst makeLogger = (): MockedLogger => ({\n  error: jest.fn(),\n  log: jest.fn(),\n  disable: jest.fn(),\n  enable: jest.fn(),\n  warn: jest.fn(),\n  debug: jest.fn(),\n});\n\nconst mockEvent = JSON.stringify({ type: 4, data: { href: 'https://example.com' }, timestamp: 1000 });\n\ndescribe('IDB timeout / hang protection', () => {\n  beforeEach(() => {\n    jest.useFakeTimers();\n  });\n\n  afterEach(() => {\n    jest.useRealTimers();\n    jest.resetAllMocks();\n  });\n\n  // ---------------------------------------------------------------------------\n  // withTimeout helper – core unit tests\n  // ---------------------------------------------------------------------------\n  describe('withTimeout', () => {\n    test('resolves with the promise value when promise settles before timeout', async () => {\n      const result = withTimeout(Promise.resolve('ok'), 1000);\n      // Fast-forward, but resolve should happen synchronously via microtask.\n      await expect(result).resolves.toBe('ok');\n    });\n\n    test('rejects with the original error when the promise rejects before timeout', async () => {\n      const error = new Error('original');\n      const result = withTimeout(Promise.reject(error), 1000);\n      await expect(result).rejects.toBe(error);\n    });\n\n    test('rejects with a timeout error when the promise never settles', async () => {\n      const neverResolves = new Promise<string>(() => {\n        // intentionally never settles\n      });\n      const result = withTimeout(neverResolves, 1000, 'thing timed out');\n\n      // Race the timeout — under fake timers, advance time past the threshold.\n      jest.advanceTimersByTime(1001);\n\n      await expect(result).rejects.toThrow('thing timed out after 1000ms');\n    });\n\n    test('clears its timer when the underlying promise resolves first (no leaked timer)', async () => {\n      const p = withTimeout(Promise.resolve('done'), 1000);\n      await expect(p).resolves.toBe('done');\n      // Advancing time past the timeout must NOT cause an unhandled rejection\n      // — the timer was cleared.  If the timer had leaked, jest would surface\n      // the unhandled rejection at test teardown.\n      jest.advanceTimersByTime(2000);\n    });\n\n    test('clears its timer when the underlying promise rejects first', async () => {\n      const p = withTimeout(Promise.reject(new Error('boom')), 1000).catch((e: unknown) => e);\n      const settled = await p;\n      expect((settled as Error).message).toBe('boom');\n      jest.advanceTimersByTime(2000);\n    });\n  });\n\n  // ---------------------------------------------------------------------------\n  // SCENARIO 1: openDB hangs at init → SessionReplayEventsIDBStore.new returns undefined\n  // ---------------------------------------------------------------------------\n  describe('openDB hang at init', () => {\n    test('SessionReplayEventsIDBStore.new() returns undefined when openDB never resolves', async () => {\n      // Replace createStore with a never-resolving openDB call wrapped in the\n      // real timeout.  We exercise the production code path: the timeout in\n      // createStore must fire and reject, the static new() must catch and\n      // return undefined so the caller can fall back to memory.\n      const neverResolvingDb = new Promise(() => {\n        // no-op; simulates a stuck IDB version-upgrade handshake\n      });\n\n      // Spy on createStore but execute its real timeout logic by calling\n      // withTimeout on the never-resolving promise with the same OPEN_DB_TIMEOUT_MS.\n      // This mirrors what createStore does internally without needing to wire up\n      // a fake-indexeddb-level hang.\n      jest.spyOn(EventsIDBStore, 'createStore').mockImplementation(async () => {\n        return withTimeout(\n          neverResolvingDb as Promise<never>,\n          EventsIDBStore.OPEN_DB_TIMEOUT_MS,\n          'IDB openDB timed out',\n        );\n      });\n\n      const logger = makeLogger();\n      const newPromise = SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: logger,\n      });\n\n      // Advance past the 2s timeout.\n      jest.advanceTimersByTime(EventsIDBStore.OPEN_DB_TIMEOUT_MS + 100);\n\n      const store = await newPromise;\n\n      expect(store).toBeUndefined();\n      // The error path through new() logs via logIdbError → warn (not an AbortError).\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(logger.warn).toHaveBeenCalled();\n      const message = (logger.warn.mock.calls[0]?.[0] ?? '') as string;\n      expect(message).toContain('timed out');\n    });\n\n    test('createStore rejects with a timeout error when openDB never resolves', async () => {\n      // Direct test of createStore: stub openDB itself by spying on the idb module.\n      // Easiest path: replace createStore's underlying call by re-wrapping\n      // a never-resolving promise.  We assert the timeout error message is\n      // surfaced to the caller.\n      const stuck = new Promise(() => {\n        // never settles\n      });\n      const result = withTimeout(stuck, EventsIDBStore.OPEN_DB_TIMEOUT_MS, 'IDB openDB timed out');\n      jest.advanceTimersByTime(EventsIDBStore.OPEN_DB_TIMEOUT_MS + 1);\n      await expect(result).rejects.toThrow(/IDB openDB timed out after \\d+ms/);\n    });\n  });\n\n  // ---------------------------------------------------------------------------\n  // SCENARIO 2: mid-recording transaction stall → recordFailure + fallback\n  // ---------------------------------------------------------------------------\n  describe('mid-recording transaction stall', () => {\n    test('addEventToCurrentSequence: stalled inner op triggers onPersistentFailure via timeout', async () => {\n      // Genuine production stall: the IDB driver accepts the call but never\n      // resolves any of its op promises.  The outer try never reaches the\n      // recordSuccess / cancelTimeout sequence; the watchdog must fire.\n      const txDone = new Promise<void>(() => {\n        // never settles\n      });\n      const stuckOp = new Promise<undefined>(() => {\n        // never resolves\n      });\n\n      const mockDB = {\n        transaction: jest.fn().mockReturnValue({\n          objectStore: jest.fn().mockReturnValue({\n            get: jest.fn().mockReturnValue(stuckOp),\n            put: jest.fn().mockReturnValue(stuckOp),\n          }),\n          done: txDone,\n        }),\n      } as unknown as EventsIDBStore.SessionReplayDB & { transaction: jest.Mock };\n\n      jest\n        .spyOn(EventsIDBStore, 'createStore')\n        .mockResolvedValue(mockDB as unknown as import('idb').IDBPDatabase<EventsIDBStore.SessionReplayDB>);\n\n      const onPersistentFailure = jest.fn();\n      const store = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: makeLogger(),\n        onPersistentFailure,\n        consecutiveFailureThreshold: 1,\n      });\n      expect(store).toBeDefined();\n\n      // Don't await — the operation will never resolve.\n      void store!.addEventToCurrentSequence(123, mockEvent);\n      // Let the function run up to the first await (which suspends forever).\n      await Promise.resolve();\n      expect(onPersistentFailure).not.toHaveBeenCalled();\n\n      // Advance past the 5s tx-done timeout.\n      jest.advanceTimersByTime(EventsIDBStore.TX_DONE_TIMEOUT_MS + 100);\n      // Drain the microtask queue so the timer callback runs its body.\n      for (let i = 0; i < 5; i++) {\n        await Promise.resolve();\n      }\n\n      // Post-fix: timeout fires recordFailure → onPersistentFailure exactly once.\n      expect(onPersistentFailure).toHaveBeenCalledTimes(1);\n    });\n\n    test('getSequencesToSend: stalled cursor triggers onPersistentFailure via timeout', async () => {\n      // Genuine stall: openCursor never resolves and tx.done never settles.\n      const txDone = new Promise<void>(() => {\n        // never settles\n      });\n      const stuckCursor = new Promise<null>(() => {\n        // never resolves\n      });\n\n      const mockDB = {\n        transaction: jest.fn().mockReturnValue({\n          store: {\n            openCursor: jest.fn().mockReturnValue(stuckCursor),\n          },\n          done: txDone,\n        }),\n      } as unknown as EventsIDBStore.SessionReplayDB;\n\n      jest\n        .spyOn(EventsIDBStore, 'createStore')\n        .mockResolvedValue(mockDB as unknown as import('idb').IDBPDatabase<EventsIDBStore.SessionReplayDB>);\n\n      const onPersistentFailure = jest.fn();\n      const store = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: makeLogger(),\n        onPersistentFailure,\n        consecutiveFailureThreshold: 1,\n      });\n      expect(store).toBeDefined();\n\n      void store!.getSequencesToSend();\n      await Promise.resolve();\n      expect(onPersistentFailure).not.toHaveBeenCalled();\n\n      jest.advanceTimersByTime(EventsIDBStore.TX_DONE_TIMEOUT_MS + 100);\n      for (let i = 0; i < 5; i++) {\n        await Promise.resolve();\n      }\n\n      expect(onPersistentFailure).toHaveBeenCalledTimes(1);\n    });\n\n    test('storeCurrentSequence: stalled tx.done triggers onPersistentFailure via timeout', async () => {\n      const txDone = new Promise<void>(() => {\n        // never settles\n      });\n\n      const stuckOp = new Promise<undefined>(() => {\n        // never resolves\n      });\n\n      const mockDB = {\n        transaction: jest.fn().mockReturnValue({\n          objectStore: jest.fn().mockReturnValue({\n            get: jest.fn().mockReturnValue(stuckOp),\n            put: jest.fn().mockReturnValue(stuckOp),\n          }),\n          done: txDone,\n        }),\n      } as unknown as EventsIDBStore.SessionReplayDB;\n\n      jest\n        .spyOn(EventsIDBStore, 'createStore')\n        .mockResolvedValue(mockDB as unknown as import('idb').IDBPDatabase<EventsIDBStore.SessionReplayDB>);\n\n      const onPersistentFailure = jest.fn();\n      const store = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: makeLogger(),\n        onPersistentFailure,\n        consecutiveFailureThreshold: 1,\n        tabId: 'tab-only',\n      });\n      expect(store).toBeDefined();\n\n      void store!.storeCurrentSequence(1);\n      await Promise.resolve();\n      expect(onPersistentFailure).not.toHaveBeenCalled();\n\n      jest.advanceTimersByTime(EventsIDBStore.TX_DONE_TIMEOUT_MS + 100);\n      for (let i = 0; i < 5; i++) {\n        await Promise.resolve();\n      }\n\n      expect(onPersistentFailure).toHaveBeenCalledTimes(1);\n    });\n\n    test('timeout is suppressed when the operation body completes successfully (cancel path)', async () => {\n      // Soft-cancel branch: get/put resolve so the function reaches\n      // recordSuccess / cancelTimeout — even though tx.done never settles,\n      // the watchdog is suppressed.  This is the test-environment scenario\n      // and the \"fast tx + slow commit microtask\" production scenario.\n      const txDone = new Promise<void>(() => {\n        // never settles\n      });\n\n      const mockDB = {\n        transaction: jest.fn().mockReturnValue({\n          objectStore: jest.fn().mockReturnValue({\n            get: jest.fn().mockResolvedValue(undefined),\n            put: jest.fn().mockResolvedValue(undefined),\n          }),\n          done: txDone,\n        }),\n      } as unknown as EventsIDBStore.SessionReplayDB;\n\n      jest\n        .spyOn(EventsIDBStore, 'createStore')\n        .mockResolvedValue(mockDB as unknown as import('idb').IDBPDatabase<EventsIDBStore.SessionReplayDB>);\n\n      const onPersistentFailure = jest.fn();\n      const store = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: makeLogger(),\n        onPersistentFailure,\n        consecutiveFailureThreshold: 1,\n      });\n\n      // Body completes normally (mocks resolve → recordSuccess → cancelTimeout).\n      await store!.addEventToCurrentSequence(123, mockEvent);\n\n      // Even though tx.done never settles, the timer callback's cancelled\n      // guard prevents recordFailure from firing.\n      jest.advanceTimersByTime(EventsIDBStore.TX_DONE_TIMEOUT_MS + 100);\n      for (let i = 0; i < 5; i++) {\n        await Promise.resolve();\n      }\n\n      expect(onPersistentFailure).not.toHaveBeenCalled();\n    });\n\n    test('timeout does NOT double-count when tx.done later rejects with the same abort', async () => {\n      // Race: timeout fires first (5s elapsed) on a stalled inner op, then\n      // tx.done eventually rejects with an AbortError.  The errorLogged /\n      // timedOut flags must prevent the tx.done.catch from also calling\n      // recordFailure for the same transaction.\n      let rejectTxDone!: (e: unknown) => void;\n      const txDone = new Promise<void>((_resolve, reject) => {\n        rejectTxDone = reject;\n      });\n      txDone.catch(() => {\n        // suppress unhandled rejection warnings\n      });\n      const stuckOp = new Promise<undefined>(() => {\n        // never resolves — keeps cancelTimeout from firing\n      });\n\n      const mockDB = {\n        transaction: jest.fn().mockReturnValue({\n          objectStore: jest.fn().mockReturnValue({\n            get: jest.fn().mockReturnValue(stuckOp),\n            put: jest.fn().mockReturnValue(stuckOp),\n          }),\n          done: txDone,\n        }),\n      } as unknown as EventsIDBStore.SessionReplayDB;\n\n      jest\n        .spyOn(EventsIDBStore, 'createStore')\n        .mockResolvedValue(mockDB as unknown as import('idb').IDBPDatabase<EventsIDBStore.SessionReplayDB>);\n\n      const onPersistentFailure = jest.fn();\n      const store = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: makeLogger(),\n        onPersistentFailure,\n        // High threshold so we can count individual failures rather than fallback once.\n        consecutiveFailureThreshold: 10,\n      });\n\n      void store!.addEventToCurrentSequence(123, mockEvent);\n      await Promise.resolve();\n\n      // Fire the timeout first.\n      jest.advanceTimersByTime(EventsIDBStore.TX_DONE_TIMEOUT_MS + 100);\n      for (let i = 0; i < 5; i++) {\n        await Promise.resolve();\n      }\n\n      // Now the underlying tx.done rejects (AbortError landing late).\n      rejectTxDone(new DOMException('abort', 'AbortError'));\n      for (let i = 0; i < 5; i++) {\n        await Promise.resolve();\n      }\n\n      // recordFailure should have been called exactly once (from the timeout),\n      // NOT twice — the tx.done.catch must skip via the timedOut flag.\n      // We can't directly observe consecutiveFailures, but we can re-trigger\n      // failures up to the threshold and verify the count is correct: with\n      // threshold=10, only the timeout's single recordFailure happened, so\n      // onPersistentFailure should still NOT have fired.\n      expect(onPersistentFailure).not.toHaveBeenCalled();\n    });\n  });\n\n  // ---------------------------------------------------------------------------\n  // generateUUID fallback: Math.random path when crypto.randomUUID unavailable\n  // ---------------------------------------------------------------------------\n  describe('generateUUID', () => {\n    test('returns a UUID-shaped string via crypto.randomUUID when available', () => {\n      const id = generateUUID();\n      expect(id).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/);\n    });\n\n    test('falls back to Math.random UUID when crypto.randomUUID throws', () => {\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      const orig = crypto.randomUUID;\n      // Simulate a non-secure context where randomUUID is absent.\n      (crypto as any).randomUUID = undefined;\n      try {\n        const id = generateUUID();\n        expect(id).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/);\n      } finally {\n        crypto.randomUUID = orig;\n      }\n    });\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/events-idb-store.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-non-null-assertion */\n/* eslint-disable @typescript-eslint/unbound-method */\nimport { ILogger } from '@amplitude/analytics-core';\nimport { IDBPDatabase } from 'idb';\nimport * as EventsIDBStore from '../src/events/events-idb-store';\nimport { SessionReplayDB, SessionReplayEventsIDBStore } from '../src/events/events-idb-store';\n\ntype MockedLogger = jest.Mocked<ILogger>;\n\nconst apiKey = 'static_key';\nconst mockEvent = {\n  type: 4,\n  data: { href: 'https://analytics.amplitude.com/', width: 1728, height: 154 },\n  timestamp: 1687358660935,\n};\nconst mockEvent2 = {\n  type: 2,\n  data: { href: 'https://analytics.amplitude.com/', width: 1728, height: 154 },\n  timestamp: 1687358660935,\n};\nconst mockEventString = JSON.stringify(mockEvent);\nconst mockEventString2 = JSON.stringify(mockEvent2);\n\nfunction mockStoreForError() {\n  const mockDB: IDBPDatabase<SessionReplayDB> = {\n    get: jest.fn().mockImplementation(() => Promise.reject('get error')),\n    put: jest.fn().mockImplementation(() => Promise.reject('put error')),\n    delete: jest.fn().mockImplementation(() => Promise.reject('put error')),\n  } as unknown as IDBPDatabase<SessionReplayDB>;\n  jest.spyOn(EventsIDBStore, 'createStore').mockResolvedValue(mockDB);\n  return mockDB;\n}\n\ndescribe('SessionReplayEventsIDBStore', () => {\n  const mockLoggerProvider: MockedLogger = {\n    error: jest.fn(),\n    log: jest.fn(),\n    disable: jest.fn(),\n    enable: jest.fn(),\n    warn: jest.fn(),\n    debug: jest.fn(),\n  };\n  beforeEach(() => {\n    jest.useFakeTimers();\n  });\n  afterEach(() => {\n    jest.resetAllMocks();\n    jest.useRealTimers();\n  });\n\n  describe('new', () => {\n    test('returns undefined on error', async () => {\n      jest.spyOn(EventsIDBStore, 'createStore').mockRejectedValue(new Error('Failed to create store'));\n\n      expect(\n        await SessionReplayEventsIDBStore.new('replay', { apiKey, loggerProvider: mockLoggerProvider }),\n      ).toBeUndefined();\n      expect(mockLoggerProvider.warn).toHaveBeenCalledWith(\n        'Failed to store session replay events in IndexedDB: Error: Failed to create store',\n      );\n    });\n  });\n\n  describe('getSequencesToSend', () => {\n    test('should fetch all sequences that have not yet been sent to the backend', async () => {\n      const eventsStorage = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: mockLoggerProvider,\n      });\n      await eventsStorage?.storeSendingEvents(123, [mockEventString]);\n      await eventsStorage?.storeSendingEvents(456, [mockEventString]);\n      await eventsStorage?.storeSendingEvents(456, [mockEventString, mockEventString]);\n      const unsentSequences = await eventsStorage?.getSequencesToSend();\n      expect(unsentSequences).toEqual([\n        {\n          sessionId: 123,\n          sequenceId: 1,\n          events: [mockEventString],\n        },\n        {\n          sessionId: 456,\n          sequenceId: 2,\n          events: [mockEventString],\n        },\n        {\n          sessionId: 456,\n          sequenceId: 3,\n          events: [mockEventString, mockEventString],\n        },\n      ]);\n    });\n    test('should handle undefined store', async () => {\n      mockStoreForError();\n      const eventsStorage = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: mockLoggerProvider,\n      });\n\n      const unsentSequences = await eventsStorage?.getSequencesToSend();\n      expect(unsentSequences).toBeUndefined();\n    });\n\n    test('should catch errors', async () => {\n      mockStoreForError();\n      const eventsStorage = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: mockLoggerProvider,\n      });\n\n      const unsentSequences = await eventsStorage?.getSequencesToSend();\n      expect(mockLoggerProvider.warn).toHaveBeenCalled();\n      expect(unsentSequences).toBeUndefined();\n    });\n\n    test('should log at debug (not warn) when tx.done rejects with AbortError', async () => {\n      // Repro: transaction aborts after cursor exhaustion; tx.done rejection must be caught\n      const abortError = new DOMException(\n        'The transaction was aborted, so the request cannot be fulfilled.',\n        'AbortError',\n      );\n      const txDone = Promise.reject(abortError);\n      // eslint-disable-next-line @typescript-eslint/no-empty-function\n      txDone.catch(() => {}); // prevent unhandled rejection in test runner\n      const mockDB = {\n        transaction: jest.fn().mockReturnValue({\n          store: { openCursor: jest.fn().mockResolvedValue(null) },\n          done: txDone,\n        }),\n      } as unknown as IDBPDatabase<SessionReplayDB>;\n      jest.spyOn(EventsIDBStore, 'createStore').mockResolvedValue(mockDB);\n\n      const eventsStorage = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: mockLoggerProvider,\n      });\n\n      const result = await eventsStorage?.getSequencesToSend();\n      // With the .catch() approach the function returns whatever sequences were\n      // collected before the abort (an empty array here since the cursor was null).\n      expect(result).toEqual([]);\n      expect(mockLoggerProvider.debug).toHaveBeenCalledWith(\n        expect.stringContaining('Failed to store session replay events in IndexedDB'),\n      );\n      expect(mockLoggerProvider.warn).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('storeCurrentSequence', () => {\n    test('should get the current sequence, store it in sequences to send, and return current sequence with an id', async () => {\n      const eventsStorage = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: mockLoggerProvider,\n      });\n      // Put data in for two different sessions to represent a more realistic scenario\n      await eventsStorage?.addEventToCurrentSequence(123, mockEventString);\n      await eventsStorage?.addEventToCurrentSequence(123, mockEventString);\n\n      await eventsStorage?.addEventToCurrentSequence(456, mockEventString);\n      await eventsStorage?.addEventToCurrentSequence(456, mockEventString);\n\n      const sequenceData = await eventsStorage?.storeCurrentSequence(123);\n\n      expect(sequenceData).toEqual({\n        sessionId: 123,\n        sequenceId: 1,\n        events: [mockEventString, mockEventString],\n      });\n    });\n    test('should return undefined if there is no current sequence data', async () => {\n      const eventsStorage = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: mockLoggerProvider,\n      });\n\n      const sequenceData = await eventsStorage?.storeCurrentSequence(123);\n\n      expect(sequenceData).toBeUndefined();\n    });\n    test('should catch errors', async () => {\n      mockStoreForError();\n      const eventsStorage = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: mockLoggerProvider,\n      });\n\n      const sequenceData = await eventsStorage?.storeCurrentSequence(123);\n      expect(mockLoggerProvider.warn).toHaveBeenCalled();\n      expect(sequenceData).toBeUndefined();\n    });\n    test('should handle undefined store', async () => {\n      mockStoreForError();\n      const eventsStorage = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: mockLoggerProvider,\n      });\n\n      const sequenceData = await eventsStorage?.storeCurrentSequence(123);\n      expect(sequenceData).toBeUndefined();\n    });\n  });\n\n  describe('addEventToCurrentSequence', () => {\n    test('should create a new list if there are no existing sequence events', async () => {\n      const eventsStorage = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: mockLoggerProvider,\n      });\n\n      const eventsToSend = await eventsStorage?.addEventToCurrentSequence(123, mockEventString);\n      expect(eventsToSend).toBeUndefined();\n      const allSessionCurrentSequence = await eventsStorage?.getCurrentSequenceEvents(123);\n      expect(allSessionCurrentSequence).toEqual([{ events: [mockEventString], sessionId: 123 }]);\n    });\n    test('should add event to list if there is an existing list', async () => {\n      const eventsStorage = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: mockLoggerProvider,\n      });\n\n      await eventsStorage?.addEventToCurrentSequence(123, mockEventString);\n      await eventsStorage?.addEventToCurrentSequence(456, mockEventString);\n      jest.useFakeTimers().setSystemTime(new Date('2023-07-31 08:30:00').getTime());\n\n      const eventsToSend = await eventsStorage?.addEventToCurrentSequence(123, mockEventString);\n      expect(eventsToSend).toBeUndefined();\n      const allSessionCurrentSequence = await eventsStorage?.getCurrentSequenceEvents();\n      expect(allSessionCurrentSequence).toEqual([\n        { events: [mockEventString, mockEventString], sessionId: 123 },\n        { events: [mockEventString], sessionId: 456 },\n      ]);\n    });\n\n    test('should split the events list at an increasing interval and send', async () => {\n      const eventsStorage = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: mockLoggerProvider,\n      });\n      eventsStorage!.shouldSplitEventsList = jest.fn().mockReturnValue(true);\n\n      await eventsStorage?.addEventToCurrentSequence(123, mockEventString);\n\n      const eventsToSend = await eventsStorage?.addEventToCurrentSequence(123, mockEventString2);\n      expect(eventsToSend).toEqual({ sessionId: 123, events: [mockEventString], sequenceId: 1 });\n      const allSessionCurrentSequence = await eventsStorage?.getCurrentSequenceEvents(123);\n      expect(allSessionCurrentSequence).toEqual([{ events: [mockEventString2], sessionId: 123 }]);\n    });\n\n    test('should split the events list at max size and send', async () => {\n      const eventsStorage = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: mockLoggerProvider,\n        maxPersistedEventsSize: 20,\n      });\n\n      // Simulate as if many events have already been built up\n      const events = ['#'.repeat(20)];\n      await Promise.all(\n        events.map((event) => {\n          return eventsStorage?.addEventToCurrentSequence(123, event);\n        }),\n      );\n\n      const eventsToSend = await eventsStorage?.addEventToCurrentSequence(123, mockEventString2);\n      expect(eventsToSend).toEqual({ sessionId: 123, events: events, sequenceId: 1 });\n      const allSessionCurrentSequence = await eventsStorage?.getCurrentSequenceEvents(123);\n      expect(allSessionCurrentSequence).toEqual([{ events: [mockEventString2], sessionId: 123 }]);\n    });\n\n    test('should return undefined if the split-path transaction fails', async () => {\n      // The split path now uses a single multi-store transaction for both\n      // sessionCurrentSequence and sequencesToSend. Verify that a transaction\n      // error still results in undefined being returned and a warn being logged.\n      const eventsStorage = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: mockLoggerProvider,\n      });\n\n      eventsStorage!.shouldSplitEventsList = jest.fn().mockReturnValue(true);\n\n      // Seed one event so shouldSplitEventsList can trigger on the next call\n      await eventsStorage?.addEventToCurrentSequence(123, mockEventString);\n\n      // Sabotage the db so the next transaction() call throws\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      (eventsStorage as any).db = {\n        transaction: () => {\n          throw new Error('transaction failed');\n        },\n      };\n\n      const eventsToSend = await eventsStorage?.addEventToCurrentSequence(123, mockEventString2);\n      expect(eventsToSend).toBeUndefined();\n      expect(mockLoggerProvider.warn).toHaveBeenCalled();\n    });\n\n    test('should catch errors', async () => {\n      mockStoreForError();\n      const eventsStorage = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: mockLoggerProvider,\n      });\n\n      const eventsToSend = await eventsStorage?.addEventToCurrentSequence(123, mockEventString2);\n      expect(mockLoggerProvider.warn).toHaveBeenCalled();\n      expect(eventsToSend).toBeUndefined();\n    });\n\n    test('should log at debug (not warn) when tx.done rejects with AbortError on first event for session', async () => {\n      // Repro: tx.done rejects with AbortError after put succeeds (transaction aborts before commit).\n      // The old code had an early `return` before `await tx.done` in the !sequenceEvents branch,\n      // meaning this rejection was silently unhandled instead of being routed through logIdbError.\n      const abortError = new DOMException(\n        'The transaction was aborted, so the request cannot be fulfilled.',\n        'AbortError',\n      );\n      const txDone = Promise.reject(abortError);\n      // eslint-disable-next-line @typescript-eslint/no-empty-function\n      txDone.catch(() => {}); // prevent unhandled rejection in test runner\n      const mockDB = {\n        transaction: jest.fn().mockReturnValue({\n          objectStore: jest.fn().mockReturnValue({\n            get: jest.fn().mockResolvedValue(undefined), // no existing sequence\n            put: jest.fn().mockResolvedValue(undefined), // put succeeds\n          }),\n          done: txDone, // but transaction aborts before commit\n        }),\n      } as unknown as IDBPDatabase<SessionReplayDB>;\n      jest.spyOn(EventsIDBStore, 'createStore').mockResolvedValue(mockDB);\n\n      const eventsStorage = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: mockLoggerProvider,\n      });\n\n      const result = await eventsStorage?.addEventToCurrentSequence(123, mockEventString);\n      expect(result).toBeUndefined();\n      expect(mockLoggerProvider.debug).toHaveBeenCalledWith(\n        expect.stringContaining('Failed to store session replay events in IndexedDB'),\n      );\n      expect(mockLoggerProvider.warn).not.toHaveBeenCalled();\n    });\n    test('should log at debug (not warn) when tx.done rejects with AbortError on split path', async () => {\n      // Repro: the transaction opens both stores atomically. If the browser aborts the\n      // transaction after the puts succeed (e.g. due to resource pressure), the AbortError\n      // from tx.done must be caught and logged at debug, not warn.\n      const abortError = new DOMException(\n        'The transaction was aborted, so the request cannot be fulfilled.',\n        'AbortError',\n      );\n      const txDoneForSplit = Promise.reject(abortError);\n      // eslint-disable-next-line @typescript-eslint/no-empty-function\n      txDoneForSplit.catch(() => {}); // prevent unhandled rejection in test runner\n\n      const mockDB = {\n        transaction: jest.fn().mockReturnValue({\n          // objectStore() returns the same mock regardless of store name\n          objectStore: jest.fn().mockReturnValue({\n            get: jest.fn().mockResolvedValue({ sessionId: 123, events: [mockEventString] }),\n            put: jest.fn().mockResolvedValue(1),\n          }),\n          done: txDoneForSplit, // tx aborts before commit\n        }),\n      } as unknown as IDBPDatabase<SessionReplayDB>;\n      jest.spyOn(EventsIDBStore, 'createStore').mockResolvedValue(mockDB);\n\n      const eventsStorage = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: mockLoggerProvider,\n      });\n      eventsStorage!.shouldSplitEventsList = jest.fn().mockReturnValue(true);\n\n      await eventsStorage?.addEventToCurrentSequence(123, mockEventString2);\n      // Allow microtasks to settle so the tx.done.catch() handler fires\n      await Promise.resolve();\n      expect(mockLoggerProvider.debug).toHaveBeenCalledWith(\n        expect.stringContaining('Failed to store session replay events in IndexedDB'),\n      );\n      expect(mockLoggerProvider.warn).not.toHaveBeenCalled();\n    });\n    test('should handle undefined store', async () => {\n      mockStoreForError();\n      const eventsStorage = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: mockLoggerProvider,\n      });\n\n      const eventsToSend = await eventsStorage?.addEventToCurrentSequence(123, mockEventString2);\n      expect(eventsToSend).toBeUndefined();\n    });\n  });\n\n  describe('storeSendingEvents', () => {\n    test('should store events and return a sequence id', async () => {\n      const eventsStorage = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: mockLoggerProvider,\n      });\n\n      const sequenceId = await eventsStorage?.storeSendingEvents(123, [mockEventString]);\n\n      expect(sequenceId).toBe(1);\n      const allSequencesToSend = await eventsStorage?.getSequencesToSend();\n      expect(allSequencesToSend).toEqual([{ events: [mockEventString], sessionId: 123, sequenceId: 1 }]);\n    });\n    test('should catch errors', async () => {\n      mockStoreForError();\n      const eventsStorage = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: mockLoggerProvider,\n      });\n\n      const sequenceId = await eventsStorage?.storeSendingEvents(123, [mockEventString]);\n      expect(mockLoggerProvider.warn).toHaveBeenCalled();\n      expect(sequenceId).toBeUndefined();\n    });\n    test('should handle undefined store', async () => {\n      mockStoreForError();\n      const eventsStorage = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: mockLoggerProvider,\n      });\n\n      const sequenceId = await eventsStorage?.storeSendingEvents(123, [mockEventString]);\n      expect(sequenceId).toBeUndefined();\n    });\n  });\n\n  describe('cleanUpSessionEventsStore', () => {\n    test('should delete sequence to send', async () => {\n      jest.useFakeTimers().setSystemTime(new Date('2023-07-31 08:30:00').getTime());\n      const currentSessionId = new Date('2023-07-31 07:30:00').getTime();\n      const nextSessionId = new Date('2023-07-31 08:30:00').getTime();\n      const eventsStorage = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: mockLoggerProvider,\n      });\n\n      await eventsStorage?.storeSendingEvents(currentSessionId, [mockEventString]);\n      await eventsStorage?.storeSendingEvents(nextSessionId, [mockEventString2]);\n\n      await eventsStorage?.cleanUpSessionEventsStore(0, 1);\n\n      const allSequencesToSend = await eventsStorage?.getSequencesToSend();\n      expect(allSequencesToSend).toEqual([{ events: [mockEventString2], sessionId: nextSessionId, sequenceId: 2 }]);\n    });\n    test('should do nothing for no sequence id', async () => {\n      const db = mockStoreForError();\n      const eventsStorage = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: mockLoggerProvider,\n      });\n\n      await eventsStorage?.cleanUpSessionEventsStore(0);\n      expect(db.delete).not.toHaveBeenCalled();\n    });\n    test('should catch errors', async () => {\n      mockStoreForError();\n      const eventsStorage = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: mockLoggerProvider,\n      });\n\n      await eventsStorage?.cleanUpSessionEventsStore(0, 1);\n      expect(mockLoggerProvider.warn).toHaveBeenCalled();\n    });\n  });\n\n  describe('persistent failure tracking', () => {\n    test('calls onPersistentFailure after consecutive failures reach threshold', async () => {\n      mockStoreForError();\n      const onPersistentFailure = jest.fn();\n      const eventsStorage = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: mockLoggerProvider,\n        onPersistentFailure,\n        consecutiveFailureThreshold: 2,\n      });\n\n      await eventsStorage?.getSequencesToSend(); // failure 1\n      expect(onPersistentFailure).not.toHaveBeenCalled();\n      await eventsStorage?.getSequencesToSend(); // failure 2 — triggers callback\n      expect(onPersistentFailure).toHaveBeenCalledTimes(1);\n    });\n\n    test('does not call onPersistentFailure before threshold is reached', async () => {\n      mockStoreForError();\n      const onPersistentFailure = jest.fn();\n      const eventsStorage = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: mockLoggerProvider,\n        onPersistentFailure,\n        consecutiveFailureThreshold: 3,\n      });\n\n      await eventsStorage?.getSequencesToSend(); // failure 1\n      await eventsStorage?.getSequencesToSend(); // failure 2\n      expect(onPersistentFailure).not.toHaveBeenCalled();\n    });\n\n    test('calls onPersistentFailure only once regardless of further failures', async () => {\n      mockStoreForError();\n      const onPersistentFailure = jest.fn();\n      const eventsStorage = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: mockLoggerProvider,\n        onPersistentFailure,\n        consecutiveFailureThreshold: 1,\n      });\n\n      await eventsStorage?.getSequencesToSend();\n      await eventsStorage?.getSequencesToSend();\n      await eventsStorage?.getSequencesToSend();\n      expect(onPersistentFailure).toHaveBeenCalledTimes(1);\n    });\n\n    test('does not throw when threshold is reached with no callback registered', async () => {\n      mockStoreForError();\n      const eventsStorage = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: mockLoggerProvider,\n        consecutiveFailureThreshold: 1,\n        // no onPersistentFailure\n      });\n\n      await expect(eventsStorage?.getSequencesToSend()).resolves.toBeUndefined();\n    });\n\n    test('resets consecutive failure count on successful operation', async () => {\n      const mockDB = mockStoreForError();\n      const onPersistentFailure = jest.fn();\n      const eventsStorage = await SessionReplayEventsIDBStore.new('replay', {\n        apiKey,\n        loggerProvider: mockLoggerProvider,\n        onPersistentFailure,\n        consecutiveFailureThreshold: 2,\n      });\n\n      await eventsStorage?.storeSendingEvents(123, [mockEventString]); // failure 1\n      expect(onPersistentFailure).not.toHaveBeenCalled();\n\n      // Make next put succeed so recordSuccess() resets the counter\n      (mockDB.put as jest.Mock).mockResolvedValueOnce(1);\n      await eventsStorage?.storeSendingEvents(123, [mockEventString]); // success — resets counter\n\n      // One more failure — counter is back to 1, threshold is 2, no callback yet\n      await eventsStorage?.storeSendingEvents(123, [mockEventString]); // failure 1 (fresh)\n      expect(onPersistentFailure).not.toHaveBeenCalled();\n    });\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/events-manager.test.ts",
    "content": "/* eslint-disable @typescript-eslint/unbound-method */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\nimport { ILogger } from '@amplitude/analytics-core';\nimport { SessionReplayLocalConfig } from '../src/config/local-config';\nimport * as SessionReplayIDB from '../src/events/events-idb-store';\nimport { createEventsManager } from '../src/events/events-manager';\nimport { SessionReplayTrackDestination } from '../src/track-destination';\nimport * as helpers from '../src/helpers';\n\njest.mock('idb-keyval');\njest.mock('../src/track-destination');\n\ntype MockedLogger = jest.Mocked<ILogger>;\n\nconst mockEvent = {\n  type: 4,\n  data: { href: 'https://analytics.amplitude.com/', width: 1728, height: 154 },\n  timestamp: 1687358660935,\n};\nconst mockEventString = JSON.stringify(mockEvent);\n\ndescribe('createEventsManager', () => {\n  let originalFetch: typeof global.fetch;\n  const mockLoggerProvider: MockedLogger = {\n    error: jest.fn(),\n    log: jest.fn(),\n    disable: jest.fn(),\n    enable: jest.fn(),\n    warn: jest.fn(),\n    debug: jest.fn(),\n  };\n  const config = new SessionReplayLocalConfig('static_key', {\n    loggerProvider: mockLoggerProvider,\n    sampleRate: 1,\n  });\n  const mockIDBStore = {\n    storeCurrentSequence: jest.fn(),\n    getSequencesToSend: jest.fn(),\n    cleanUpSessionEventsStore: jest.fn().mockResolvedValue(undefined),\n    addEventToCurrentSequence: jest.fn(),\n    initialize: jest.fn(),\n    storeSendingEvents: jest.fn(),\n  } as unknown as SessionReplayIDB.SessionReplayEventsIDBStore;\n  beforeEach(() => {\n    jest.spyOn(SessionReplayIDB.SessionReplayEventsIDBStore, 'new').mockResolvedValue(mockIDBStore);\n    (mockIDBStore.cleanUpSessionEventsStore as jest.Mock).mockResolvedValue(undefined);\n    jest.useFakeTimers();\n    originalFetch = global.fetch;\n    global.fetch = jest.fn(() =>\n      Promise.resolve({\n        status: 200,\n      }),\n    ) as jest.Mock;\n  });\n  afterEach(() => {\n    jest.resetAllMocks();\n    global.fetch = originalFetch;\n\n    jest.useRealTimers();\n  });\n\n  test('falls back to memory store when IDB store fails to initialize', async () => {\n    jest.spyOn(SessionReplayIDB.SessionReplayEventsIDBStore, 'new').mockResolvedValue(undefined);\n\n    await createEventsManager<'replay'>({\n      config,\n      type: 'replay',\n      storeType: 'idb',\n    });\n\n    expect(mockLoggerProvider.log).toHaveBeenCalledWith(\n      'Failed to initialize idb store, falling back to memory store.',\n    );\n  });\n\n  test('does not log fallback message when IDB store initializes successfully', async () => {\n    await createEventsManager<'replay'>({\n      config,\n      type: 'replay',\n      storeType: 'idb',\n    });\n\n    expect(mockLoggerProvider.log).not.toHaveBeenCalledWith(\n      'Failed to initialize idb store, falling back to memory store.',\n    );\n  });\n\n  describe('sendStoredEvents', () => {\n    test('should read events from storage and send them', async () => {\n      (mockIDBStore.getSequencesToSend as jest.Mock).mockResolvedValue([\n        { events: [mockEventString], sequenceId: 1, sessionId: 123 },\n      ]);\n      const eventsManager = await createEventsManager<'replay'>({\n        config,\n        type: 'replay',\n        storeType: 'idb',\n      });\n      await eventsManager.sendStoredEvents({ deviceId: '1a2b3c' });\n      jest.runAllTimers();\n      const trackDestinationInstance = (SessionReplayTrackDestination as jest.Mock).mock.instances[0];\n      const mockSendEventsList = trackDestinationInstance.sendEventsList;\n      expect(mockSendEventsList).toHaveBeenCalledTimes(1);\n      expect(mockSendEventsList).toHaveBeenCalledWith(\n        expect.objectContaining({\n          events: [mockEventString],\n          sessionId: 123,\n          apiKey: 'static_key',\n          deviceId: '1a2b3c',\n          flushMaxRetries: 2,\n          onComplete: expect.any(Function),\n          sampleRate: 1,\n          serverZone: 'US',\n        }),\n      );\n    });\n\n    test('should not send if no events', async () => {\n      (mockIDBStore.getSequencesToSend as jest.Mock).mockResolvedValue(undefined);\n      const eventsManager = await createEventsManager<'replay'>({\n        config,\n        type: 'replay',\n        storeType: 'idb',\n      });\n      await eventsManager.sendStoredEvents({ deviceId: '1a2b3c' });\n      jest.runAllTimers();\n      const trackDestinationInstance = (SessionReplayTrackDestination as jest.Mock).mock.instances[0];\n      const mockSendEventsList = trackDestinationInstance.sendEventsList;\n      expect(mockSendEventsList).not.toHaveBeenCalled();\n    });\n\n    test('should log drain message when stored sequences are found', async () => {\n      (mockIDBStore.getSequencesToSend as jest.Mock).mockResolvedValue([\n        { events: [mockEventString], sequenceId: 1, sessionId: 123 },\n        { events: [mockEventString], sequenceId: 2, sessionId: 123 },\n      ]);\n      const eventsManager = await createEventsManager<'replay'>({\n        config,\n        type: 'replay',\n        storeType: 'idb',\n      });\n      await eventsManager.sendStoredEvents({ deviceId: '1a2b3c' });\n      expect(mockLoggerProvider.log).toHaveBeenCalledWith('Draining 2 stored sequence(s) from previous session.');\n    });\n\n    test('should not log drain message when sequences are empty', async () => {\n      (mockIDBStore.getSequencesToSend as jest.Mock).mockResolvedValue([]);\n      const eventsManager = await createEventsManager<'replay'>({\n        config,\n        type: 'replay',\n        storeType: 'idb',\n      });\n      mockLoggerProvider.log.mockClear();\n      await eventsManager.sendStoredEvents({ deviceId: '1a2b3c' });\n      expect(mockLoggerProvider.log).not.toHaveBeenCalledWith(expect.stringContaining('Draining'));\n    });\n\n    test('should not log drain message when sequences is null', async () => {\n      (mockIDBStore.getSequencesToSend as jest.Mock).mockResolvedValue(null);\n      const eventsManager = await createEventsManager<'replay'>({\n        config,\n        type: 'replay',\n        storeType: 'idb',\n      });\n      mockLoggerProvider.log.mockClear();\n      await eventsManager.sendStoredEvents({ deviceId: '1a2b3c' });\n      expect(mockLoggerProvider.log).not.toHaveBeenCalledWith(expect.stringContaining('Draining'));\n    });\n\n    test('should log the current storage size', async () => {\n      (mockIDBStore.getSequencesToSend as jest.Mock).mockResolvedValue([\n        { events: [mockEventString], sequenceId: 1, sessionId: 123 },\n      ]);\n      const getStoragePromise = Promise.resolve({\n        percentOfQuota: 10,\n        totalStorageSize: 100000,\n        usageDetails: JSON.stringify({\n          indexedDB: 10,\n        }),\n      });\n      jest.spyOn(helpers, 'getStorageSize').mockImplementation(() => getStoragePromise);\n      const eventsManager = await createEventsManager<'replay'>({\n        config: {\n          ...config,\n          optOut: false,\n          debugMode: true,\n        },\n        type: 'replay',\n        storeType: 'idb',\n      });\n      await eventsManager.sendStoredEvents({ deviceId: '1a2b3c' });\n      await getStoragePromise;\n      expect(mockLoggerProvider.debug).toHaveBeenCalled();\n    });\n\n    test('should handle an error in logging the current storage size', async () => {\n      (mockIDBStore.getSequencesToSend as jest.Mock).mockResolvedValue([\n        { events: [mockEventString], sequenceId: 1, sessionId: 123 },\n      ]);\n      const getStoragePromise = Promise.resolve({\n        percentOfQuota: 10,\n        totalStorageSize: 100000,\n        usageDetails: JSON.stringify({\n          indexedDB: 10,\n        }),\n      });\n      jest.spyOn(helpers, 'getStorageSize').mockImplementation(() => getStoragePromise);\n      jest.spyOn(mockLoggerProvider, 'debug').mockImplementation(() => {\n        throw new Error();\n      });\n      const eventsManager = await createEventsManager<'replay'>({\n        config: {\n          ...config,\n          optOut: false,\n          debugMode: true,\n        },\n        type: 'replay',\n        storeType: 'idb',\n      });\n      await eventsManager.sendStoredEvents({ deviceId: '1a2b3c' });\n      await getStoragePromise;\n      expect(mockLoggerProvider.debug).toHaveBeenCalled();\n      const trackDestinationInstance = (SessionReplayTrackDestination as jest.Mock).mock.instances[0];\n      const mockSendEventsList = trackDestinationInstance.sendEventsList;\n      expect(mockSendEventsList).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('sendEventsList — oversized event guard', () => {\n    const oversizedEvent = 'x'.repeat(9 * 1000 * 1000 + 1);\n\n    test('drops oversized events and warns before sending the rest', async () => {\n      (mockIDBStore.getSequencesToSend as jest.Mock).mockResolvedValue([\n        { events: [mockEventString, oversizedEvent], sequenceId: 1, sessionId: 123 },\n      ]);\n      const eventsManager = await createEventsManager<'replay'>({\n        config,\n        type: 'replay',\n        storeType: 'idb',\n      });\n      await eventsManager.sendStoredEvents({ deviceId: '1a2b3c' });\n      jest.runAllTimers();\n\n      const trackDestinationInstance = (SessionReplayTrackDestination as jest.Mock).mock.instances[0];\n      const mockSendEventsList = trackDestinationInstance.sendEventsList;\n      expect(mockLoggerProvider.warn).toHaveBeenCalledWith(expect.stringContaining('oversized'));\n      // Valid event is still sent\n      expect(mockSendEventsList).toHaveBeenCalledTimes(1);\n      expect(mockSendEventsList).toHaveBeenCalledWith(expect.objectContaining({ events: [mockEventString] }));\n    });\n\n    test('skips send and calls cleanUpSessionEventsStore when all events are oversized', async () => {\n      (mockIDBStore.getSequencesToSend as jest.Mock).mockResolvedValue([\n        { events: [oversizedEvent], sequenceId: 7, sessionId: 456 },\n      ]);\n      const eventsManager = await createEventsManager<'replay'>({\n        config,\n        type: 'replay',\n        storeType: 'idb',\n      });\n      await eventsManager.sendStoredEvents({ deviceId: '1a2b3c' });\n      jest.runAllTimers();\n\n      const trackDestinationInstance = (SessionReplayTrackDestination as jest.Mock).mock.instances[0];\n      const mockSendEventsList = trackDestinationInstance.sendEventsList;\n      expect(mockSendEventsList).not.toHaveBeenCalled();\n      expect(mockIDBStore.cleanUpSessionEventsStore).toHaveBeenCalledWith(456, 7);\n    });\n\n    test('warns when cleanUpSessionEventsStore rejects after dropping all oversized events', async () => {\n      (mockIDBStore.getSequencesToSend as jest.Mock).mockResolvedValue([\n        { events: [oversizedEvent], sequenceId: 7, sessionId: 456 },\n      ]);\n      const cleanUpError = new Error('idb cleanup failed');\n      (mockIDBStore.cleanUpSessionEventsStore as jest.Mock).mockRejectedValueOnce(cleanUpError);\n      const eventsManager = await createEventsManager<'replay'>({\n        config,\n        type: 'replay',\n        storeType: 'idb',\n      });\n      await eventsManager.sendStoredEvents({ deviceId: '1a2b3c' });\n      await Promise.resolve();\n      await Promise.resolve();\n\n      expect(mockLoggerProvider.warn).toHaveBeenCalledWith(\n        'Failed to clean up session replay events store:',\n        cleanUpError,\n      );\n    });\n  });\n\n  describe('addEvent', () => {\n    test('should store events in IDB and send any returned', async () => {\n      const mockAddEventPromise = Promise.resolve({ events: [mockEventString], sequenceId: 1, sessionId: 123 });\n\n      (mockIDBStore.addEventToCurrentSequence as jest.Mock).mockReturnValue(mockAddEventPromise);\n      const eventsManager = await createEventsManager<'replay'>({\n        config,\n        type: 'replay',\n        storeType: 'idb',\n      });\n      eventsManager.addEvent({ event: { type: 'replay', data: mockEventString }, sessionId: 123, deviceId: '1a2b3c' });\n      jest.runAllTimers();\n      return mockAddEventPromise\n        .catch(() => {\n          // ignore\n        })\n        .finally(() => {\n          expect(mockIDBStore.addEventToCurrentSequence).toHaveBeenCalledWith(123, mockEventString);\n          const trackDestinationInstance = (SessionReplayTrackDestination as jest.Mock).mock.instances[0];\n          const mockSendEventsList = trackDestinationInstance.sendEventsList;\n          expect(mockSendEventsList).toHaveBeenCalledTimes(1);\n          expect(mockSendEventsList).toHaveBeenCalledWith(\n            expect.objectContaining({\n              events: [mockEventString],\n              sessionId: 123,\n              apiKey: 'static_key',\n              deviceId: '1a2b3c',\n              flushMaxRetries: 2,\n              onComplete: expect.any(Function),\n              sampleRate: 1,\n              serverZone: 'US',\n            }),\n          );\n        });\n    });\n    test('should store events in IDB and not send any if none returned', async () => {\n      const mockAddEventPromise = Promise.resolve();\n\n      (mockIDBStore.addEventToCurrentSequence as jest.Mock).mockReturnValue(mockAddEventPromise);\n      const eventsManager = await createEventsManager<'replay'>({\n        config,\n        type: 'replay',\n        storeType: 'idb',\n      });\n      eventsManager.addEvent({ event: { type: 'replay', data: mockEventString }, sessionId: 123, deviceId: '1a2b3c' });\n      jest.runAllTimers();\n      return mockAddEventPromise\n        .catch(() => {\n          // ignore\n        })\n        .finally(() => {\n          expect(mockIDBStore.addEventToCurrentSequence).toHaveBeenCalledWith(123, mockEventString);\n          const trackDestinationInstance = (SessionReplayTrackDestination as jest.Mock).mock.instances[0];\n          const mockSendEventsList = trackDestinationInstance.sendEventsList;\n          expect(mockSendEventsList).not.toHaveBeenCalled();\n        });\n    });\n    test('should catch errors', async () => {\n      const mockAddEventPromise = Promise.reject('error');\n      (mockIDBStore.addEventToCurrentSequence as jest.Mock).mockImplementation(() => Promise.reject('error'));\n      const eventsManager = await createEventsManager<'replay'>({\n        config,\n        type: 'replay',\n        storeType: 'idb',\n      });\n      eventsManager.addEvent({ event: { type: 'replay', data: mockEventString }, sessionId: 123, deviceId: '1a2b3c' });\n\n      return mockAddEventPromise\n        .catch(() => {\n          // ignore\n        })\n        .finally(() => {\n          expect(mockLoggerProvider.warn).toHaveBeenCalled();\n        });\n    });\n  });\n\n  describe('sendCurrentSequenceEvents', () => {\n    test('todo no sequence', async () => {\n      const mockStoreEventPromise = Promise.resolve({ events: [mockEventString], sessionId: 123 });\n      (mockIDBStore.storeCurrentSequence as jest.Mock).mockReturnValue(mockStoreEventPromise);\n      const eventsManager = await createEventsManager<'replay'>({\n        config,\n        type: 'replay',\n        storeType: 'idb',\n      });\n      eventsManager.sendCurrentSequenceEvents({ sessionId: 123, deviceId: '1a2b3c' });\n      jest.runAllTimers();\n      return mockStoreEventPromise\n        .catch(() => {\n          // ignore\n        })\n        .finally(() => {\n          expect(mockIDBStore.storeCurrentSequence).toHaveBeenCalledWith(123);\n          const trackDestinationInstance = (SessionReplayTrackDestination as jest.Mock).mock.instances[0];\n          const mockSendEventsList = trackDestinationInstance.sendEventsList;\n          expect(mockSendEventsList).toHaveBeenCalledTimes(1);\n          expect(mockSendEventsList).toHaveBeenCalledWith(\n            expect.objectContaining({\n              events: [mockEventString],\n              sessionId: 123,\n              apiKey: 'static_key',\n              deviceId: '1a2b3c',\n              flushMaxRetries: 2,\n              onComplete: expect.any(Function),\n              sampleRate: 1,\n              serverZone: 'US',\n            }),\n          );\n        });\n    });\n\n    test('should store events in IDB and send any returned', async () => {\n      const mockStoreEventPromise = Promise.resolve({ events: [mockEventString], sequenceId: 1, sessionId: 123 });\n      (mockIDBStore.storeCurrentSequence as jest.Mock).mockReturnValue(mockStoreEventPromise);\n      const eventsManager = await createEventsManager<'replay'>({\n        config,\n        type: 'replay',\n        storeType: 'idb',\n      });\n      eventsManager.sendCurrentSequenceEvents({ sessionId: 123, deviceId: '1a2b3c' });\n      jest.runAllTimers();\n      return mockStoreEventPromise\n        .catch(() => {\n          // ignore\n        })\n        .finally(() => {\n          expect(mockIDBStore.storeCurrentSequence).toHaveBeenCalledWith(123);\n          const trackDestinationInstance = (SessionReplayTrackDestination as jest.Mock).mock.instances[0];\n          const mockSendEventsList = trackDestinationInstance.sendEventsList;\n          expect(mockSendEventsList).toHaveBeenCalledTimes(1);\n          expect(mockSendEventsList).toHaveBeenCalledWith(\n            expect.objectContaining({\n              events: [mockEventString],\n              sessionId: 123,\n              apiKey: 'static_key',\n              deviceId: '1a2b3c',\n              flushMaxRetries: 2,\n              onComplete: expect.any(Function),\n              sampleRate: 1,\n              serverZone: 'US',\n            }),\n          );\n        });\n    });\n    test('should update IDB store upon success', async () => {\n      const mockStoreEventPromise = Promise.resolve({ events: [mockEventString], sequenceId: 1, sessionId: 123 });\n      (mockIDBStore.storeCurrentSequence as jest.Mock).mockReturnValue(mockStoreEventPromise);\n      const eventsManager = await createEventsManager<'replay'>({\n        config,\n        type: 'replay',\n        storeType: 'idb',\n      });\n      eventsManager.sendCurrentSequenceEvents({ sessionId: 123, deviceId: '1a2b3c' });\n\n      return mockStoreEventPromise\n        .catch(() => {\n          // ignore\n        })\n        .finally(() => {\n          const trackDestinationInstance = (SessionReplayTrackDestination as jest.Mock).mock.instances[0];\n          const mockOnComplete = trackDestinationInstance.sendEventsList.mock.calls[0][0].onComplete;\n          // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n          void mockOnComplete(123);\n          expect(mockIDBStore.cleanUpSessionEventsStore).toHaveBeenCalledTimes(1);\n        });\n    });\n    test('should catch errors', async () => {\n      const mockStoreEventPromise = Promise.reject('error');\n      (mockIDBStore.storeCurrentSequence as jest.Mock).mockImplementation(() => Promise.reject('error'));\n      const eventsManager = await createEventsManager<'replay'>({\n        config,\n        type: 'replay',\n        storeType: 'idb',\n      });\n      eventsManager.sendCurrentSequenceEvents({ sessionId: 123, deviceId: '1a2b3c' });\n\n      return mockStoreEventPromise\n        .catch(() => {\n          // ignore\n        })\n        .finally(() => {\n          expect(mockLoggerProvider.warn).toHaveBeenCalled();\n        });\n    });\n  });\n\n  describe('shouldSend callback', () => {\n    test('should block sendEventsList in addEvent when shouldSend returns false', async () => {\n      const mockAddEventPromise = Promise.resolve({ events: [mockEventString], sequenceId: 1, sessionId: 123 });\n      (mockIDBStore.addEventToCurrentSequence as jest.Mock).mockReturnValue(mockAddEventPromise);\n      let shouldSendCallCount = 0;\n      const eventsManager = await createEventsManager<'replay'>({\n        config,\n        type: 'replay',\n        storeType: 'idb',\n        shouldSend: () => {\n          shouldSendCallCount++;\n          return false;\n        },\n      });\n      eventsManager.addEvent({ event: { type: 'replay', data: mockEventString }, sessionId: 123, deviceId: '1a2b3c' });\n      // shouldSend must be evaluated synchronously (before the async store resolves).\n      expect(shouldSendCallCount).toBe(1);\n      jest.runAllTimers();\n      return mockAddEventPromise\n        .catch(() => {\n          // ignore\n        })\n        .finally(() => {\n          const trackDestinationInstance = (SessionReplayTrackDestination as jest.Mock).mock.instances[0];\n          expect(trackDestinationInstance.sendEventsList).not.toHaveBeenCalled();\n          // Split events were atomically moved to sequencesToSend by the store; if we don't\n          // clean them up they'd be unconditionally replayed via sendStoredEvents on next load.\n          expect(mockIDBStore.cleanUpSessionEventsStore).toHaveBeenCalledWith(123, 1);\n          // The split batch must also be removed from the beacon buffer so it can't be\n          // sent via sendBeacon on page unload (potentially attributed to a later session).\n          expect(eventsManager.getBeaconEvents()).toEqual([mockEventString]);\n        });\n    });\n\n    test('should log warning when cleanUpSessionEventsStore rejects on canSend=false split', async () => {\n      const mockAddEventPromise = Promise.resolve({ events: [mockEventString], sequenceId: 1, sessionId: 123 });\n      (mockIDBStore.addEventToCurrentSequence as jest.Mock).mockReturnValue(mockAddEventPromise);\n      (mockIDBStore.cleanUpSessionEventsStore as jest.Mock).mockRejectedValueOnce(new Error('idb gone'));\n      const eventsManager = await createEventsManager<'replay'>({\n        config,\n        type: 'replay',\n        storeType: 'idb',\n        shouldSend: () => false,\n      });\n      eventsManager.addEvent({ event: { type: 'replay', data: mockEventString }, sessionId: 123, deviceId: '1a2b3c' });\n      // Let the addEvent .then() chain and the cleanUp .catch() chain both settle.\n      await Promise.resolve();\n      await Promise.resolve();\n      await Promise.resolve();\n      expect(mockLoggerProvider.warn).toHaveBeenCalledWith(\n        'Failed to clean up dropped session replay sequence:',\n        expect.any(Error),\n      );\n    });\n\n    test('should block sendEventsList in sendCurrentSequenceEvents when shouldSend returns false', async () => {\n      const mockStoreEventPromise = Promise.resolve({ events: [mockEventString], sequenceId: 1, sessionId: 123 });\n      (mockIDBStore.storeCurrentSequence as jest.Mock).mockReturnValue(mockStoreEventPromise);\n      const eventsManager = await createEventsManager<'replay'>({\n        config,\n        type: 'replay',\n        storeType: 'idb',\n        shouldSend: () => false,\n      });\n      eventsManager.sendCurrentSequenceEvents({ sessionId: 123, deviceId: '1a2b3c' });\n      // shouldSend is evaluated synchronously — storeCurrentSequence must not be called at all.\n      expect(mockIDBStore.storeCurrentSequence).not.toHaveBeenCalled();\n      jest.runAllTimers();\n      await mockStoreEventPromise;\n      const trackDestinationInstance = (SessionReplayTrackDestination as jest.Mock).mock.instances[0];\n      expect(trackDestinationInstance.sendEventsList).not.toHaveBeenCalled();\n    });\n\n    test('should allow sendEventsList when shouldSend returns true', async () => {\n      const mockAddEventPromise = Promise.resolve({ events: [mockEventString], sequenceId: 1, sessionId: 123 });\n      (mockIDBStore.addEventToCurrentSequence as jest.Mock).mockReturnValue(mockAddEventPromise);\n      const eventsManager = await createEventsManager<'replay'>({\n        config,\n        type: 'replay',\n        storeType: 'idb',\n        shouldSend: () => true,\n      });\n      eventsManager.addEvent({ event: { type: 'replay', data: mockEventString }, sessionId: 123, deviceId: '1a2b3c' });\n      jest.runAllTimers();\n      return mockAddEventPromise\n        .catch(() => {\n          // ignore\n        })\n        .finally(() => {\n          const trackDestinationInstance = (SessionReplayTrackDestination as jest.Mock).mock.instances[0];\n          expect(trackDestinationInstance.sendEventsList).toHaveBeenCalledTimes(1);\n        });\n    });\n  });\n\n  describe('flush', () => {\n    test('should call track destination flush with useRetry as true', async () => {\n      const eventsManager = await createEventsManager<'replay'>({\n        config,\n        type: 'replay',\n        storeType: 'idb',\n      });\n      const trackDestinationInstance = (SessionReplayTrackDestination as jest.Mock).mock.instances[0];\n      const flushMock = trackDestinationInstance.flush;\n\n      await eventsManager.flush(true);\n      expect(flushMock).toHaveBeenCalled();\n      expect(flushMock).toHaveBeenCalledWith(true);\n    });\n    test('should call track destination flush without useRetry', async () => {\n      const eventsManager = await createEventsManager({\n        config,\n        type: 'replay',\n        storeType: 'idb',\n      });\n      const trackDestinationInstance = (SessionReplayTrackDestination as jest.Mock).mock.instances[0];\n      const flushMock = trackDestinationInstance.flush;\n\n      await eventsManager.flush();\n      expect(flushMock).toHaveBeenCalled();\n      expect(flushMock).toHaveBeenCalledWith(false);\n    });\n  });\n\n  describe('getBeaconEvents', () => {\n    test('should return empty array initially', async () => {\n      const eventsManager = await createEventsManager({\n        config,\n        type: 'replay',\n        storeType: 'memory',\n      });\n      expect(eventsManager.getBeaconEvents()).toEqual([]);\n    });\n\n    test('should accumulate events as they are added', async () => {\n      const eventsManager = await createEventsManager({\n        config,\n        type: 'replay',\n        storeType: 'memory',\n      });\n      const eventA = JSON.stringify({ type: 3, timestamp: 1 });\n      const eventB = JSON.stringify({ type: 3, timestamp: 2 });\n\n      eventsManager.addEvent({ event: { type: 'replay', data: eventA }, sessionId: 123, deviceId: '1a2b3c' });\n      eventsManager.addEvent({ event: { type: 'replay', data: eventB }, sessionId: 123, deviceId: '1a2b3c' });\n\n      expect(eventsManager.getBeaconEvents()).toEqual([eventA, eventB]);\n    });\n\n    test('should advance window when sendCurrentSequenceEvents finalises events', async () => {\n      (mockIDBStore.addEventToCurrentSequence as jest.Mock).mockResolvedValue(undefined);\n      (mockIDBStore.storeCurrentSequence as jest.Mock).mockResolvedValue({\n        sequenceId: 0,\n        events: [mockEventString],\n        sessionId: 123,\n      });\n      const eventsManager = await createEventsManager({\n        config,\n        type: 'replay',\n        storeType: 'idb',\n      });\n      eventsManager.addEvent({ event: { type: 'replay', data: mockEventString }, sessionId: 123, deviceId: '1a2b3c' });\n      await Promise.resolve(); // let the addEvent async chain settle\n      expect(eventsManager.getBeaconEvents()).toEqual([mockEventString]);\n\n      eventsManager.sendCurrentSequenceEvents({ sessionId: 123, deviceId: '1a2b3c' });\n      await (mockIDBStore.storeCurrentSequence as jest.Mock).mock.results[0].value;\n\n      expect(eventsManager.getBeaconEvents()).toEqual([]);\n    });\n\n    test('should advance window on batch split and keep only current event', async () => {\n      const eventsManager = await createEventsManager({\n        config,\n        type: 'replay',\n        storeType: 'memory',\n      });\n      // Use the real memory store so shouldSplitEventsList can trigger a split.\n      // eventA must be large enough that eventA + eventB >= MAX_EVENT_LIST_SIZE (1_000_000).\n      const eventA = 'a'.repeat(999_990);\n      const eventB = JSON.stringify({ type: 3, timestamp: 2 });\n\n      eventsManager.addEvent({ event: { type: 'replay', data: eventA }, sessionId: 123, deviceId: '1a2b3c' });\n      // Force split: eventB pushes the batch over the 1 MB limit\n      eventsManager.addEvent({ event: { type: 'replay', data: eventB }, sessionId: 123, deviceId: '1a2b3c' });\n\n      // Let the async addEventToCurrentSequence chains settle (two microtask ticks).\n      await Promise.resolve();\n      await Promise.resolve();\n\n      expect(eventsManager.getBeaconEvents()).toEqual([eventB]);\n    });\n\n    test('should return a copy of the buffer (mutation-safe)', async () => {\n      const eventsManager = await createEventsManager({\n        config,\n        type: 'replay',\n        storeType: 'memory',\n      });\n      eventsManager.addEvent({ event: { type: 'replay', data: mockEventString }, sessionId: 123, deviceId: '1a2b3c' });\n      const snapshot = eventsManager.getBeaconEvents();\n      snapshot.push('extra');\n      expect(eventsManager.getBeaconEvents()).toHaveLength(1);\n    });\n  });\n\n  describe('dropPendingBeaconEvents', () => {\n    test('should clear the buffer and not affect later events added under a new session', async () => {\n      const eventsManager = await createEventsManager({\n        config,\n        type: 'replay',\n        storeType: 'memory',\n      });\n      const oldEvent = JSON.stringify({ type: 3, timestamp: 1 });\n      const newEvent = JSON.stringify({ type: 3, timestamp: 2 });\n      eventsManager.addEvent({ event: { type: 'replay', data: oldEvent }, sessionId: 1, deviceId: '1a2b3c' });\n      expect(eventsManager.getBeaconEvents()).toEqual([oldEvent]);\n\n      eventsManager.dropPendingBeaconEvents();\n      expect(eventsManager.getBeaconEvents()).toEqual([]);\n\n      // Subsequent events from a new session must accumulate cleanly without the dropped events.\n      eventsManager.addEvent({ event: { type: 'replay', data: newEvent }, sessionId: 2, deviceId: '1a2b3c' });\n      expect(eventsManager.getBeaconEvents()).toEqual([newEvent]);\n    });\n  });\n\n  describe('mid-session IDB fallback', () => {\n    let capturedOnPersistentFailure: (() => void) | undefined;\n\n    beforeEach(() => {\n      capturedOnPersistentFailure = undefined;\n      jest.spyOn(SessionReplayIDB.SessionReplayEventsIDBStore, 'new').mockImplementation((_type, args) => {\n        capturedOnPersistentFailure = (args as { onPersistentFailure?: () => void }).onPersistentFailure;\n        return Promise.resolve(mockIDBStore);\n      });\n    });\n\n    test('logs warning when falling back to in-memory store', async () => {\n      await createEventsManager<'replay'>({ config, type: 'replay', storeType: 'idb' });\n\n      capturedOnPersistentFailure?.();\n      await Promise.resolve();\n      await Promise.resolve();\n\n      expect(mockLoggerProvider.warn).toHaveBeenCalledWith(\n        'IDB store is experiencing repeated failures; falling back to in-memory event store.',\n      );\n    });\n\n    test('drains and sends pending IDB sequences when falling back', async () => {\n      (mockIDBStore.getSequencesToSend as jest.Mock).mockResolvedValueOnce([\n        { events: [mockEventString], sequenceId: 1, sessionId: 123 },\n      ]);\n      (mockIDBStore.addEventToCurrentSequence as jest.Mock).mockResolvedValue(undefined);\n\n      const eventsManager = await createEventsManager<'replay'>({ config, type: 'replay', storeType: 'idb' });\n      eventsManager.addEvent({ event: { type: 'replay', data: mockEventString }, sessionId: 123, deviceId: '1a2b3c' });\n\n      capturedOnPersistentFailure?.();\n      await Promise.resolve();\n      await Promise.resolve();\n\n      const trackDestinationInstance = (SessionReplayTrackDestination as jest.Mock).mock.instances[0];\n      expect(trackDestinationInstance.sendEventsList).toHaveBeenCalledWith(\n        expect.objectContaining({ events: [mockEventString], sessionId: 123, deviceId: '1a2b3c' }),\n      );\n    });\n\n    test('skips IDB drain when no deviceId is known yet', async () => {\n      await createEventsManager<'replay'>({ config, type: 'replay', storeType: 'idb' });\n      // no addEvent / sendStoredEvents call, so lastKnownDeviceId is still undefined\n\n      capturedOnPersistentFailure?.();\n      await Promise.resolve();\n      await Promise.resolve();\n\n      expect(mockIDBStore.getSequencesToSend).not.toHaveBeenCalled();\n    });\n\n    test('new events after fallback go to in-memory store, not IDB', async () => {\n      (mockIDBStore.getSequencesToSend as jest.Mock).mockResolvedValueOnce([]);\n      (mockIDBStore.addEventToCurrentSequence as jest.Mock).mockResolvedValue(undefined);\n\n      const eventsManager = await createEventsManager<'replay'>({ config, type: 'replay', storeType: 'idb' });\n      // Establish lastKnownDeviceId\n      eventsManager.addEvent({ event: { type: 'replay', data: mockEventString }, sessionId: 123, deviceId: '1a2b3c' });\n      await Promise.resolve();\n\n      capturedOnPersistentFailure?.();\n      await Promise.resolve();\n      await Promise.resolve(); // switchToMemoryStore settles\n\n      (mockIDBStore.addEventToCurrentSequence as jest.Mock).mockClear();\n\n      eventsManager.addEvent({ event: { type: 'replay', data: mockEventString }, sessionId: 123, deviceId: '1a2b3c' });\n      await Promise.resolve();\n\n      expect(mockIDBStore.addEventToCurrentSequence).not.toHaveBeenCalled();\n    });\n\n    test('fallback is a no-op when store is already in-memory (startup fallback)', async () => {\n      jest.spyOn(SessionReplayIDB.SessionReplayEventsIDBStore, 'new').mockResolvedValueOnce(undefined);\n\n      await createEventsManager<'replay'>({ config, type: 'replay', storeType: 'idb' });\n      // capturedOnPersistentFailure is undefined here since IDB.new returned undefined (startup fallback)\n      // Simulate calling it anyway to confirm no error / double-warn\n      capturedOnPersistentFailure?.();\n\n      // Only the startup fallback log should appear, not the mid-session warn\n      expect(mockLoggerProvider.warn).not.toHaveBeenCalledWith(\n        expect.stringContaining('IDB store is experiencing repeated failures'),\n      );\n    });\n\n    test('second switchToMemoryStore call is a no-op (already on memory)', async () => {\n      (mockIDBStore.getSequencesToSend as jest.Mock).mockResolvedValue([]);\n      (mockIDBStore.addEventToCurrentSequence as jest.Mock).mockResolvedValue(undefined);\n\n      const eventsManager = await createEventsManager<'replay'>({ config, type: 'replay', storeType: 'idb' });\n      eventsManager.addEvent({ event: { type: 'replay', data: mockEventString }, sessionId: 123, deviceId: '1a2b3c' });\n\n      // First trigger — switches to memory store\n      capturedOnPersistentFailure?.();\n      await Promise.resolve();\n      await Promise.resolve();\n\n      // Second trigger — should be a no-op (usingIdbStore is already false)\n      capturedOnPersistentFailure?.();\n      await Promise.resolve();\n      await Promise.resolve();\n\n      // Warning should only be logged once\n      expect(mockLoggerProvider.warn).toHaveBeenCalledTimes(1);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/events-memory-store.test.ts",
    "content": "// We don't want to call expects in conditions and typescript doesn't take these checks into account.\n/* eslint-disable @typescript-eslint/no-non-null-assertion */\nimport { ILogger } from '@amplitude/analytics-core';\nimport { InMemoryEventsStore } from '../src/events/events-memory-store';\n\nconst mockLoggerProvider: ILogger = {\n  error: jest.fn(),\n  log: jest.fn(),\n  disable: jest.fn(),\n  enable: jest.fn(),\n  warn: jest.fn(),\n  debug: jest.fn(),\n};\n\ndescribe('InMemoryEventsStore', () => {\n  let store: InMemoryEventsStore;\n  let sessionId: number;\n\n  beforeEach(() => {\n    sessionId = Math.floor(Math.random() * 10000);\n    store = new InMemoryEventsStore({\n      loggerProvider: mockLoggerProvider,\n    });\n  });\n\n  describe('addEventToCurrentSequence', () => {\n    test('store does not produce sequence id after one event', async () => {\n      expect(await store.addEventToCurrentSequence(sessionId, 'test')).toBeUndefined();\n    });\n\n    test('returns sequence id on split', async () => {\n      await store.addEventToCurrentSequence(sessionId, 'test');\n      store.shouldSplitEventsList = jest.fn().mockReturnValue(true);\n\n      const {\n        sequenceId,\n        events,\n        sessionId: sequenceSessionId,\n      } = (await store.addEventToCurrentSequence(sessionId, 'test'))!;\n      expect(sequenceId).toBe(0);\n      expect(events).toStrictEqual(['test']);\n      expect(sequenceSessionId).toStrictEqual(sessionId);\n    });\n  });\n\n  describe('storeCurrentSequence', () => {\n    test('no sequence id produced', async () => {\n      expect(await store.storeCurrentSequence(sessionId)).toBeUndefined();\n    });\n\n    test('sequence id produced', async () => {\n      await store.addEventToCurrentSequence(sessionId, 'test');\n      const { sequenceId, events, sessionId: sequenceSessionId } = (await store.storeCurrentSequence(sessionId))!;\n      expect(sequenceId).toBe(0);\n      expect(events).toStrictEqual(['test']);\n      expect(sequenceSessionId).toStrictEqual(sessionId);\n    });\n  });\n\n  describe('getSequencesToSend', () => {\n    test('get sequences', async () => {\n      expect(await store.getSequencesToSend()).toStrictEqual([]);\n    });\n\n    test('get stored sequences', async () => {\n      await store.addEventToCurrentSequence(sessionId, 'test');\n      await store.storeCurrentSequence(sessionId);\n      const sequences = (await store.getSequencesToSend())!;\n      expect(sequences).toHaveLength(1);\n\n      const { sequenceId, events, sessionId: sequenceSessionId } = sequences[0];\n      expect(sequenceId).toBe(0);\n      expect(events).toStrictEqual(['test']);\n      expect(sequenceSessionId).toStrictEqual(sessionId);\n    });\n  });\n\n  describe('storeSendingEvents', () => {\n    test('stores events', async () => {\n      expect(await store.storeSendingEvents(sessionId, ['test'])).toBe(0);\n    });\n  });\n\n  describe('cleanUpSessionEventsStore', () => {\n    test('deletes sequence', async () => {\n      // first build a new sequence\n      const sequenceId = (await store.storeSendingEvents(sessionId, ['test']))!;\n      const sequences = (await store.getSequencesToSend())!;\n      expect(sequences).toHaveLength(1);\n\n      const sequence = sequences[0];\n      expect(sequence.sequenceId).toBe(sequenceId);\n\n      // then delete it\n      await store.cleanUpSessionEventsStore(sessionId, sequenceId);\n\n      // then confirm it's deleted\n      expect(await store.getSequencesToSend()).toStrictEqual([]);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/flag-config-data.ts",
    "content": "export const flagConfig = {\n  key: 'sr_targeting_config',\n  variants: {\n    on: { key: 'on' },\n    off: { key: 'off' },\n  },\n  segments: [\n    {\n      metadata: { segmentName: 'sign in trigger' },\n      bucket: {\n        selector: ['context', 'session_id'],\n        salt: 'xdfrewd',\n        allocations: [\n          {\n            range: [0, 99],\n            distributions: [\n              {\n                variant: 'on',\n                range: [0, 42949673],\n              },\n            ],\n          },\n        ],\n      },\n      conditions: [\n        [\n          {\n            selector: ['context', 'event', 'event_type'],\n            op: 'is',\n            values: ['Sign In'],\n          },\n        ],\n      ],\n    },\n    {\n      metadata: { segmentName: 'user property' },\n      bucket: {\n        selector: ['context', 'session_id'],\n        salt: 'Rpr5h4vy',\n        allocations: [\n          {\n            range: [0, 99],\n            distributions: [\n              {\n                variant: 'on',\n                range: [0, 42949673],\n              },\n            ],\n          },\n        ],\n      },\n      conditions: [\n        [\n          {\n            selector: ['context', 'user', 'user_properties', 'country'],\n            op: 'set contains any',\n            values: ['united states'],\n          },\n        ],\n      ],\n    },\n    {\n      metadata: { segmentName: 'leftover allocation' },\n      bucket: {\n        selector: ['context', 'session_id'],\n        salt: 'T5lhyRo',\n        allocations: [\n          {\n            range: [0, 9], // Selects 10% of users that match these conditions\n            distributions: [\n              {\n                variant: 'on',\n                range: [0, 42949673],\n              },\n            ],\n          },\n        ],\n      },\n    },\n    {\n      variant: 'off',\n    },\n  ],\n};\n"
  },
  {
    "path": "packages/session-replay-browser/test/helpers.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unsafe-argument */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\nimport { PrivacyConfig, UGCFilterRule } from '../src/config/types';\nimport {\n  MASK_TEXT_CLASS,\n  SESSION_REPLAY_EU_URL,\n  SESSION_REPLAY_SERVER_URL,\n  SESSION_REPLAY_STAGING_URL,\n  UNMASK_TEXT_CLASS,\n} from '../src/constants';\nimport { ServerZone } from '@amplitude/analytics-core';\nimport {\n  getEffectiveMaskLevel,\n  getServerUrl,\n  getStorageSize,\n  isMasked,\n  maskFn,\n  maskAttributeFn,\n  getPageUrl,\n  validateUGCFilterRules,\n} from '../src/helpers';\nimport * as AnalyticsCore from '@amplitude/analytics-core';\n\ndescribe('SessionReplayPlugin helpers', () => {\n  describe('maskFn -- input', () => {\n    test('should default to medium on unknown mask level', () => {\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n      const result = maskFn('input', { defaultMaskLevel: 'lightxx' } as any)('some text', null);\n      expect(result).toEqual('**** ****');\n    });\n\n    test('should not mask on null element', () => {\n      const result = maskFn('input', { defaultMaskLevel: 'light' })('some text', null);\n      expect(result).toEqual('some text');\n    });\n\n    test('masking takes priority over code unmask', () => {\n      const htmlElement = document.createElement('input');\n      htmlElement.classList.add(UNMASK_TEXT_CLASS);\n      const result = maskFn('input', { maskSelector: ['.' + UNMASK_TEXT_CLASS], unmaskSelector: [] })(\n        'some text',\n        htmlElement,\n      );\n      expect(result).toEqual('**** ****');\n    });\n    test('should mask on default config', () => {\n      const htmlElement = document.createElement('div');\n      const result = maskFn('input', { maskSelector: [], unmaskSelector: [] })('some text', htmlElement);\n      expect(result).toEqual('**** ****');\n    });\n    test('should mask instead of unmask for certain selectors', () => {\n      const htmlElement = document.createElement('div');\n      htmlElement.classList.add('mask-this');\n      const result = maskFn('input', {\n        defaultMaskLevel: 'light',\n        maskSelector: ['.mask-this'],\n        unmaskSelector: ['.mask-this'],\n      })('some text', htmlElement);\n      expect(result).toEqual('**** ****');\n    });\n    test('should specifically mask certain selectors', () => {\n      const htmlElement = document.createElement('div');\n      htmlElement.classList.add('mask-this');\n      const result = maskFn('input', { defaultMaskLevel: 'light', maskSelector: ['.mask-this'] })(\n        'some text',\n        htmlElement,\n      );\n      expect(result).toEqual('**** ****');\n    });\n    test('should specifically unmask certain selectors', () => {\n      const htmlElement = document.createElement('div');\n      htmlElement.classList.add('unmask-this');\n      const result = maskFn('input', { defaultMaskLevel: 'conservative', unmaskSelector: ['.unmask-this'] })(\n        'some text',\n        htmlElement,\n      );\n      expect(result).toEqual('some text');\n    });\n    test('should not mask an element whose class list has amp-unmask in it', () => {\n      const htmlElement = document.createElement('div');\n      htmlElement.classList.add(UNMASK_TEXT_CLASS);\n      const result = maskFn('input')('some text', htmlElement);\n      expect(result).toEqual('some text');\n    });\n    test('should mask any other element', () => {\n      const htmlElement = document.createElement('div');\n      htmlElement.classList.add('another-class');\n      const result = maskFn('input')('some text', htmlElement);\n      expect(result).toEqual('**** ****');\n    });\n    test('should mask on conservative level', () => {\n      const htmlElement = document.createElement('input');\n      const result = maskFn('input', { defaultMaskLevel: 'conservative' })('some text', htmlElement);\n      expect(result).toEqual('**** ****');\n    });\n\n    describe('light mask level', () => {\n      const privacyConfig: PrivacyConfig = { defaultMaskLevel: 'light' };\n\n      test.each([\n        {\n          el: (element: HTMLInputElement): HTMLInputElement => {\n            element.type = 'password';\n            return element;\n          },\n          masked: true,\n        },\n        {\n          el: (element: HTMLInputElement): HTMLInputElement => {\n            element.type = 'email';\n            return element;\n          },\n          masked: true,\n        },\n        {\n          el: (element: HTMLInputElement): HTMLInputElement => {\n            element.type = 'hidden';\n            return element;\n          },\n          masked: true,\n        },\n        {\n          el: (element: HTMLInputElement): HTMLInputElement => {\n            element.autocomplete = 'cc-number';\n            return element;\n          },\n          masked: true,\n        },\n        {\n          el: (element: HTMLInputElement): HTMLInputElement => {\n            element.type = 'tel';\n            return element;\n          },\n          masked: true,\n        },\n        {\n          el: (element: HTMLInputElement): HTMLInputElement => {\n            element.type = 'search';\n            return element;\n          },\n          masked: false,\n        },\n        {\n          el: (element: HTMLElement): HTMLElement => {\n            // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n            (element as any).autocomplete = undefined; // we are given an HTMLElement so this is a edge case safety check\n            return element;\n          },\n          masked: false,\n        },\n        {\n          el: (element: HTMLElement): HTMLElement => {\n            // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n            (element as any).type = null; // we are given an HTMLElement so this is a edge case safety check\n            return element;\n          },\n          masked: false,\n        },\n      ])('check masked', ({ el, masked }) => {\n        const inputElement = document.createElement('input');\n        const result = maskFn('input', privacyConfig)('some text', el(inputElement));\n        expect(result).toStrictEqual(masked ? '**** ****' : 'some text');\n      });\n    });\n  });\n\n  describe('maskFn -- text (medium level)', () => {\n    test('should NOT mask text nodes at medium level (medium masks inputs only)', () => {\n      const htmlElement = document.createElement('div');\n      const result = maskFn('text', { defaultMaskLevel: 'medium' })('some text', htmlElement);\n      expect(result).toEqual('some text');\n    });\n\n    test('should mask inputs at medium level', () => {\n      const htmlElement = document.createElement('input');\n      const result = maskFn('input', { defaultMaskLevel: 'medium' })('some text', htmlElement);\n      expect(result).toEqual('**** ****');\n    });\n\n    test('maskFn with urlMaskLevels medium on matching URL does NOT mask text', () => {\n      const config: PrivacyConfig = {\n        defaultMaskLevel: 'light',\n        urlMaskLevels: [{ match: 'https://example.com/docs/*', maskLevel: 'medium' }],\n      };\n      const element = document.createElement('div');\n      const fn = maskFn('text', config, () => 'https://example.com/docs/intro');\n      expect(fn('some text', element)).toEqual('some text');\n    });\n\n    test('maskFn with urlMaskLevels medium on non-matching URL falls through to defaultMaskLevel', () => {\n      const config: PrivacyConfig = {\n        defaultMaskLevel: 'light',\n        urlMaskLevels: [{ match: 'https://example.com/docs/*', maskLevel: 'medium' }],\n      };\n      const element = document.createElement('div');\n      const fn = maskFn('text', config, () => 'https://example.com/other/page');\n      // defaultMaskLevel is light, so text is NOT masked\n      expect(fn('some text', element)).toEqual('some text');\n    });\n  });\n\n  describe('maskFn -- text', () => {\n    test('should mask on amp mask', () => {\n      const htmlElement = document.createElement('text');\n      htmlElement.classList.add(MASK_TEXT_CLASS);\n      const result = maskFn('text')('some text', htmlElement);\n      expect(result).toEqual('**** ****');\n    });\n    test('should mask on conservative level', () => {\n      const htmlElement = document.createElement('text');\n      const result = maskFn('text', { defaultMaskLevel: 'conservative' })('some text', htmlElement);\n      expect(result).toEqual('**** ****');\n    });\n    test('should not mask a text element on light mask level', () => {\n      const htmlElement = document.createElement('div');\n      const result = maskFn('text', { defaultMaskLevel: 'light' })('some text', htmlElement);\n      expect(result).toEqual('some text');\n    });\n    test('should not mask an element whose class list has amp-unmask in it', () => {\n      const htmlElement = document.createElement('div');\n      htmlElement.classList.add(UNMASK_TEXT_CLASS);\n      const result = maskFn('text')('some text', htmlElement);\n      expect(result).toEqual('some text');\n    });\n  });\n\n  describe('maskAttributeFn', () => {\n    const element = document.createElement('input');\n\n    test('returns value unchanged for style attribute', () => {\n      const result = maskAttributeFn({ maskAttributes: ['style'] })('style', 'color: red', element);\n      expect(result).toEqual('color: red');\n    });\n\n    test('masks attribute listed in maskAttributes', () => {\n      const result = maskAttributeFn({ maskAttributes: ['placeholder'] })('placeholder', 'Enter name', element);\n      expect(result).toEqual('***** ****');\n    });\n\n    test('preserves whitespace when masking', () => {\n      const result = maskAttributeFn({ maskAttributes: ['aria-label'] })('aria-label', 'first last', element);\n      expect(result).toEqual('***** ****');\n    });\n\n    test('returns value unchanged when key is not in maskAttributes', () => {\n      const result = maskAttributeFn({ maskAttributes: ['placeholder'] })('aria-label', 'some label', element);\n      expect(result).toEqual('some label');\n    });\n\n    test('returns value unchanged when maskAttributes is empty', () => {\n      const result = maskAttributeFn({ maskAttributes: [] })('placeholder', 'Enter name', element);\n      expect(result).toEqual('Enter name');\n    });\n\n    test('returns value unchanged when config is undefined', () => {\n      const result = maskAttributeFn(undefined)('placeholder', 'Enter name', element);\n      expect(result).toEqual('Enter name');\n    });\n\n    test('returns value unchanged when maskAttributes is undefined', () => {\n      const result = maskAttributeFn({})('placeholder', 'Enter name', element);\n      expect(result).toEqual('Enter name');\n    });\n\n    test('returns value unchanged when element has unmask class even if attribute is listed', () => {\n      const unmaskedElement = document.createElement('input');\n      unmaskedElement.classList.add(UNMASK_TEXT_CLASS);\n      const result = maskAttributeFn({ maskAttributes: ['placeholder'] })('placeholder', 'Enter name', unmaskedElement);\n      expect(result).toEqual('Enter name');\n    });\n\n    test('masks attribute when element matches maskSelector', () => {\n      const selectedElement = document.createElement('input');\n      selectedElement.classList.add('mask-this');\n      const result = maskAttributeFn({\n        defaultMaskLevel: 'light',\n        maskSelector: ['.mask-this'],\n        maskAttributes: ['placeholder'],\n      })('placeholder', 'Enter name', selectedElement);\n      expect(result).toEqual('***** ****');\n    });\n\n    test('re-evaluates masking after element class mutation', () => {\n      const dynamicElement = document.createElement('input');\n      dynamicElement.classList.add(UNMASK_TEXT_CLASS);\n      const fn = maskAttributeFn({ maskAttributes: ['placeholder'] });\n\n      // Initially unmasked because amp-unmask is present.\n      expect(fn('placeholder', 'Enter name', dynamicElement)).toEqual('Enter name');\n\n      // After removing amp-unmask, the same element should now be masked.\n      dynamicElement.classList.remove(UNMASK_TEXT_CLASS);\n      expect(fn('placeholder', 'Enter name', dynamicElement)).toEqual('***** ****');\n    });\n\n    test('re-evaluates masking after ancestor selector mutation', () => {\n      const wrapper = document.createElement('div');\n      wrapper.classList.add('unmask-parent');\n      const dynamicElement = document.createElement('input');\n      wrapper.appendChild(dynamicElement);\n\n      const fn = maskAttributeFn({\n        maskAttributes: ['placeholder'],\n        unmaskSelector: ['.unmask-parent'],\n      });\n\n      // Initially unmasked because ancestor matches unmaskSelector.\n      expect(fn('placeholder', 'Enter name', dynamicElement)).toEqual('Enter name');\n\n      // After ancestor no longer matches, element should be masked.\n      wrapper.classList.remove('unmask-parent');\n      expect(fn('placeholder', 'Enter name', dynamicElement)).toEqual('***** ****');\n    });\n\n    test('masks attribute when getCurrentUrl returns a conservative URL via urlMaskLevels', () => {\n      const maskedElement = document.createElement('input');\n      const fn = maskAttributeFn(\n        {\n          defaultMaskLevel: 'light',\n          maskAttributes: ['placeholder'],\n          urlMaskLevels: [{ match: 'https://example.com/admin/*', maskLevel: 'conservative' }],\n        },\n        () => 'https://example.com/admin/settings',\n      );\n      expect(fn('placeholder', 'Enter name', maskedElement)).toEqual('***** ****');\n    });\n\n    test('returns value unmasked when getCurrentUrl returns a light URL via urlMaskLevels', () => {\n      const element = document.createElement('input');\n      const fn = maskAttributeFn(\n        {\n          defaultMaskLevel: 'conservative',\n          maskAttributes: ['placeholder'],\n          urlMaskLevels: [{ match: 'https://example.com/public/*', maskLevel: 'light' }],\n        },\n        () => 'https://example.com/public/page',\n      );\n      // light level does not mask text nodes (and therefore attributes)\n      expect(fn('placeholder', 'Enter name', element)).toEqual('Enter name');\n    });\n\n    test('still masks input placeholder at medium level (regression guard)', () => {\n      const inputElement = document.createElement('input');\n      const fn = maskAttributeFn({\n        defaultMaskLevel: 'medium',\n        maskAttributes: ['placeholder'],\n      });\n      expect(fn('placeholder', 'Enter name', inputElement)).toEqual('***** ****');\n    });\n\n    test('does NOT mask aria-label on non-form elements (div) at medium level', () => {\n      // medium masks form fields only; a div's aria-label is treated as text and left visible.\n      const divElement = document.createElement('div');\n      const fn = maskAttributeFn({\n        defaultMaskLevel: 'medium',\n        maskAttributes: ['aria-label'],\n      });\n      expect(fn('aria-label', 'some label', divElement)).toEqual('some label');\n    });\n  });\n\n  describe('getServerUrl', () => {\n    test('should return us server url if no config set', () => {\n      expect(getServerUrl()).toEqual(SESSION_REPLAY_SERVER_URL);\n    });\n\n    test('should return staging server url if staging config set', async () => {\n      expect(getServerUrl(ServerZone.STAGING)).toEqual(SESSION_REPLAY_STAGING_URL);\n    });\n\n    test('should return eu server url if eu config set', async () => {\n      expect(getServerUrl(ServerZone.EU)).toEqual(SESSION_REPLAY_EU_URL);\n    });\n\n    test('should allow server url override', async () => {\n      const customUrl = 'http://localhost:3000';\n\n      expect(getServerUrl(ServerZone.EU, customUrl)).toEqual(customUrl);\n    });\n  });\n\n  describe('getStorageSize', () => {\n    test('should return a default set of data if global scope is not defined', async () => {\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue(undefined);\n      const storageSize = await getStorageSize();\n      expect(storageSize).toEqual({ totalStorageSize: 0, percentOfQuota: 0, usageDetails: '' });\n    });\n    test('should return formatted storage size data', async () => {\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        navigator: {\n          storage: {\n            estimate: async () => {\n              return {\n                usage: 214333,\n                quota: 45673324,\n                usageDetails: {\n                  indexedDB: 10,\n                },\n              };\n            },\n          } as unknown as StorageManager,\n        } as unknown as Navigator,\n      } as unknown as typeof globalThis);\n      const storageSize = await getStorageSize();\n      expect(storageSize).toEqual({ totalStorageSize: 209, percentOfQuota: 0.005, usageDetails: '{\"indexedDB\":10}' });\n    });\n    test('should return a default set of data if values within navigator are not defined', async () => {\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        navigator: {\n          storage: {\n            estimate: async () => {\n              return {\n                usageDetails: {\n                  indexedDB: 10,\n                },\n              };\n            },\n          } as unknown as StorageManager,\n        } as unknown as Navigator,\n      } as unknown as typeof globalThis);\n      const storageSize = await getStorageSize();\n      expect(storageSize).toEqual({ totalStorageSize: 0, percentOfQuota: 0, usageDetails: '{\"indexedDB\":10}' });\n    });\n  });\n\n  describe('getPageUrl', () => {\n    test('should return original URL when no filter rules are provided', () => {\n      const url = 'https://example.com/page';\n      const result = getPageUrl(url, []);\n      expect(result).toBe(url);\n    });\n\n    test('should apply single filter rule correctly', () => {\n      const url = 'https://example.com/user/123';\n      const rules: UGCFilterRule[] = [\n        { selector: 'https://example.com/user/*', replacement: 'https://example.com/user/user_id' },\n      ];\n      const result = getPageUrl(url, rules);\n      expect(result).toBe('https://example.com/user/user_id');\n    });\n\n    test('should apply multiple first matching rule in order', () => {\n      const url = 'https://example.com/user/123/profile';\n      const rules: UGCFilterRule[] = [\n        { selector: 'https://example.com/user/*/*', replacement: 'https://example.com/user/user_id/space_name' },\n        {\n          selector: 'https://example.com/user/*/profile',\n          replacement: 'https://example.com/user/user_id/profile_page',\n        },\n      ];\n      const result = getPageUrl(url, rules);\n      expect(result).toBe('https://example.com/user/user_id/space_name');\n    });\n\n    test('should handle complex glob patterns', () => {\n      const url = 'https://example.com/products/electronics/123';\n      const rules: UGCFilterRule[] = [\n        {\n          selector: 'https://example.com/products/*/*',\n          replacement: 'https://example.com/products/category_id/item_id',\n        },\n      ];\n      const result = getPageUrl(url, rules);\n      expect(result).toBe('https://example.com/products/category_id/item_id');\n    });\n\n    test('should handle wildcard in glob patterns', () => {\n      const url = 'https://example.com/project/123';\n      const rules: UGCFilterRule[] = [\n        { selector: 'https://*.com/*/*', replacement: 'https://company_name.com/category_id/item_id' },\n      ];\n      const result = getPageUrl(url, rules);\n      expect(result).toBe('https://company_name.com/category_id/item_id');\n    });\n\n    test('should handle question mark in glob patterns', () => {\n      const url = 'https://example.com/p?ge';\n      const rules: UGCFilterRule[] = [\n        { selector: 'https://example.com/p?ge', replacement: 'https://example.com/page' },\n      ];\n      const result = getPageUrl(url, rules);\n      expect(result).toBe('https://example.com/page');\n    });\n  });\n\n  describe('getEffectiveMaskLevel', () => {\n    test('should return defaultMaskLevel when no urlMaskLevels are configured', () => {\n      const config: PrivacyConfig = { defaultMaskLevel: 'light' };\n      expect(getEffectiveMaskLevel('https://example.com/page', config)).toBe('light');\n    });\n\n    test('should fall back to medium when no defaultMaskLevel and no urlMaskLevels match', () => {\n      const config: PrivacyConfig = {};\n      expect(getEffectiveMaskLevel('https://example.com/page', config)).toBe('medium');\n    });\n\n    test('should return matching urlMaskLevel for exact URL', () => {\n      const config: PrivacyConfig = {\n        defaultMaskLevel: 'medium',\n        urlMaskLevels: [{ match: 'https://example.com/settings', maskLevel: 'conservative' }],\n      };\n      expect(getEffectiveMaskLevel('https://example.com/settings', config)).toBe('conservative');\n    });\n\n    test('should return matching urlMaskLevel for glob pattern', () => {\n      const config: PrivacyConfig = {\n        defaultMaskLevel: 'medium',\n        urlMaskLevels: [{ match: 'https://example.com/admin/*', maskLevel: 'conservative' }],\n      };\n      expect(getEffectiveMaskLevel('https://example.com/admin/users', config)).toBe('conservative');\n    });\n\n    test('should return first matching rule (first-match wins)', () => {\n      const config: PrivacyConfig = {\n        defaultMaskLevel: 'medium',\n        urlMaskLevels: [\n          { match: 'https://example.com/admin/*', maskLevel: 'conservative' },\n          { match: 'https://example.com/admin/*', maskLevel: 'light' },\n        ],\n      };\n      expect(getEffectiveMaskLevel('https://example.com/admin/users', config)).toBe('conservative');\n    });\n\n    test('should fall back to defaultMaskLevel when no urlMaskLevels match', () => {\n      const config: PrivacyConfig = {\n        defaultMaskLevel: 'light',\n        urlMaskLevels: [{ match: 'https://example.com/admin/*', maskLevel: 'conservative' }],\n      };\n      expect(getEffectiveMaskLevel('https://example.com/public/page', config)).toBe('light');\n    });\n\n    test('should fall back to defaultMaskLevel when url is undefined', () => {\n      const config: PrivacyConfig = {\n        defaultMaskLevel: 'light',\n        urlMaskLevels: [{ match: 'https://example.com/*', maskLevel: 'conservative' }],\n      };\n      expect(getEffectiveMaskLevel(undefined, config)).toBe('light');\n    });\n\n    test('should fall back to defaultMaskLevel when url is empty', () => {\n      const config: PrivacyConfig = {\n        defaultMaskLevel: 'light',\n        urlMaskLevels: [{ match: 'https://example.com/*', maskLevel: 'conservative' }],\n      };\n      expect(getEffectiveMaskLevel('', config)).toBe('light');\n    });\n\n    test('should handle wildcard subdomain matching', () => {\n      const config: PrivacyConfig = {\n        defaultMaskLevel: 'medium',\n        urlMaskLevels: [{ match: 'https://*.example.com/checkout/*', maskLevel: 'conservative' }],\n      };\n      expect(getEffectiveMaskLevel('https://shop.example.com/checkout/payment', config)).toBe('conservative');\n    });\n\n    test('should fall back to defaultMaskLevel when urlMaskLevels is an empty array', () => {\n      const config: PrivacyConfig = {\n        defaultMaskLevel: 'light',\n        urlMaskLevels: [],\n      };\n      expect(getEffectiveMaskLevel('https://example.com/page', config)).toBe('light');\n    });\n\n    test('first-match-wins: first rule matching different patterns selects the first', () => {\n      const config: PrivacyConfig = {\n        defaultMaskLevel: 'medium',\n        urlMaskLevels: [\n          { match: 'https://example.com/checkout/*', maskLevel: 'conservative' },\n          { match: 'https://example.com/*', maskLevel: 'light' },\n        ],\n      };\n      // /checkout/payment matches the first rule\n      expect(getEffectiveMaskLevel('https://example.com/checkout/payment', config)).toBe('conservative');\n      // /public only matches the second rule\n      expect(getEffectiveMaskLevel('https://example.com/public', config)).toBe('light');\n    });\n\n    // ── globToRegex /** behaviour (SR-3176 bug fix) ──────────────────────────\n\n    test('trailing /** matches the base path without a trailing slash', () => {\n      // Bug: docs/** previously required a literal / after docs, so https://example.com/docs\n      // (no trailing slash) did not match. The fix makes /** expand to (/.*)?\n      const config: PrivacyConfig = {\n        defaultMaskLevel: 'medium',\n        urlMaskLevels: [{ match: 'https://example.com/docs/**', maskLevel: 'conservative' }],\n      };\n      expect(getEffectiveMaskLevel('https://example.com/docs', config)).toBe('conservative');\n    });\n\n    test('trailing /** still matches the base path with a trailing slash', () => {\n      const config: PrivacyConfig = {\n        defaultMaskLevel: 'medium',\n        urlMaskLevels: [{ match: 'https://example.com/docs/**', maskLevel: 'conservative' }],\n      };\n      expect(getEffectiveMaskLevel('https://example.com/docs/', config)).toBe('conservative');\n    });\n\n    test('trailing /** matches deep subpaths', () => {\n      const config: PrivacyConfig = {\n        defaultMaskLevel: 'medium',\n        urlMaskLevels: [{ match: 'https://example.com/docs/**', maskLevel: 'conservative' }],\n      };\n      expect(getEffectiveMaskLevel('https://example.com/docs/latest/commands/get', config)).toBe('conservative');\n    });\n\n    test('trailing /** does not over-match a different path prefix', () => {\n      const config: PrivacyConfig = {\n        defaultMaskLevel: 'medium',\n        urlMaskLevels: [{ match: 'https://example.com/docs/**', maskLevel: 'conservative' }],\n      };\n      expect(getEffectiveMaskLevel('https://example.com/documentation', config)).toBe('medium');\n      expect(getEffectiveMaskLevel('https://example.com/docs-extra/foo', config)).toBe('medium');\n    });\n\n    test('middle /**/ matches zero intermediate path segments (docs/**/commands = docs/commands)', () => {\n      // Bug: docs/**/commands/** previously required at least one segment between docs and commands\n      // because ** expanded to .*.* which was greedy. The fix makes /**/ expand to /(.*\\/)?\n      const config: PrivacyConfig = {\n        defaultMaskLevel: 'medium',\n        urlMaskLevels: [{ match: 'https://example.com/docs/**/commands/**', maskLevel: 'conservative' }],\n      };\n      expect(getEffectiveMaskLevel('https://example.com/docs/commands', config)).toBe('conservative');\n      expect(getEffectiveMaskLevel('https://example.com/docs/commands/', config)).toBe('conservative');\n    });\n\n    test('middle /**/ matches one or more intermediate path segments', () => {\n      const config: PrivacyConfig = {\n        defaultMaskLevel: 'medium',\n        urlMaskLevels: [{ match: 'https://example.com/docs/**/commands/**', maskLevel: 'conservative' }],\n      };\n      expect(getEffectiveMaskLevel('https://example.com/docs/v1/commands/get', config)).toBe('conservative');\n      expect(getEffectiveMaskLevel('https://example.com/docs/a/b/c/commands/set', config)).toBe('conservative');\n    });\n\n    test('middle /**/ does not match when required literal segment is absent', () => {\n      const config: PrivacyConfig = {\n        defaultMaskLevel: 'medium',\n        urlMaskLevels: [{ match: 'https://example.com/docs/**/commands/**', maskLevel: 'conservative' }],\n      };\n      expect(getEffectiveMaskLevel('https://example.com/docs/', config)).toBe('medium');\n      expect(getEffectiveMaskLevel('https://example.com/docs', config)).toBe('medium');\n    });\n\n    test('single /* does NOT match the base path without a trailing slash (/* is unchanged)', () => {\n      // /* still requires the literal / separator — only /** gets the optional-slash treatment.\n      const config: PrivacyConfig = {\n        defaultMaskLevel: 'medium',\n        urlMaskLevels: [{ match: 'https://example.com/docs/*', maskLevel: 'conservative' }],\n      };\n      expect(getEffectiveMaskLevel('https://example.com/docs', config)).toBe('medium');\n    });\n\n    test('single /* still matches when a trailing slash is present', () => {\n      const config: PrivacyConfig = {\n        defaultMaskLevel: 'medium',\n        urlMaskLevels: [{ match: 'https://example.com/docs/*', maskLevel: 'conservative' }],\n      };\n      expect(getEffectiveMaskLevel('https://example.com/docs/', config)).toBe('conservative');\n    });\n  });\n\n  describe('isMasked with currentUrl', () => {\n    test('should use urlMaskLevels when currentUrl is provided', () => {\n      const config: PrivacyConfig = {\n        defaultMaskLevel: 'light',\n        urlMaskLevels: [{ match: 'https://example.com/admin/*', maskLevel: 'conservative' }],\n      };\n      const element = document.createElement('div');\n      // On /admin/*, effective level is conservative → text should be masked\n      expect(isMasked('text', config, element, 'https://example.com/admin/dashboard')).toBe(true);\n    });\n\n    test('should use defaultMaskLevel when currentUrl does not match any rule', () => {\n      const config: PrivacyConfig = {\n        defaultMaskLevel: 'light',\n        urlMaskLevels: [{ match: 'https://example.com/admin/*', maskLevel: 'conservative' }],\n      };\n      const element = document.createElement('div');\n      // On /public, effective level is light → input without sensitive type should not be masked\n      expect(isMasked('input', config, element, 'https://example.com/public')).toBe(false);\n    });\n\n    test('should still respect per-element mask overrides over urlMaskLevels', () => {\n      const config: PrivacyConfig = {\n        defaultMaskLevel: 'light',\n        urlMaskLevels: [{ match: 'https://example.com/public/*', maskLevel: 'light' }],\n        unmaskSelector: [],\n      };\n      const element = document.createElement('div');\n      element.classList.add(MASK_TEXT_CLASS);\n      // amp-mask class takes priority even though URL-level says light\n      expect(isMasked('input', config, element, 'https://example.com/public/page')).toBe(true);\n    });\n\n    test('should still respect per-element unmask overrides over urlMaskLevels', () => {\n      const config: PrivacyConfig = {\n        defaultMaskLevel: 'conservative',\n        urlMaskLevels: [{ match: 'https://example.com/*', maskLevel: 'conservative' }],\n      };\n      const element = document.createElement('div');\n      element.classList.add(UNMASK_TEXT_CLASS);\n      // amp-unmask class takes priority even though URL-level says conservative\n      expect(isMasked('text', config, element, 'https://example.com/page')).toBe(false);\n    });\n\n    test('should fall back to default behavior when currentUrl is not provided', () => {\n      const config: PrivacyConfig = {\n        defaultMaskLevel: 'light',\n        urlMaskLevels: [{ match: 'https://example.com/*', maskLevel: 'conservative' }],\n      };\n      const element = document.createElement('div');\n      // No URL → falls back to defaultMaskLevel (light); text is NOT masked at light level\n      expect(isMasked('text', config, element)).toBe(false);\n      // Input with light level → not masked for non-sensitive inputs\n      expect(isMasked('input', config, element)).toBe(false);\n    });\n  });\n\n  describe('maskFn with getCurrentUrl', () => {\n    test('should use URL-aware masking when getCurrentUrl is provided', () => {\n      const config: PrivacyConfig = {\n        defaultMaskLevel: 'light',\n        urlMaskLevels: [{ match: 'https://example.com/admin/*', maskLevel: 'conservative' }],\n      };\n      const element = document.createElement('div');\n      const fn = maskFn('input', config, () => 'https://example.com/admin/dashboard');\n      expect(fn('some text', element)).toEqual('**** ****');\n    });\n\n    test('should reflect URL changes dynamically via getter', () => {\n      const config: PrivacyConfig = {\n        defaultMaskLevel: 'light',\n        urlMaskLevels: [{ match: 'https://example.com/admin/*', maskLevel: 'conservative' }],\n      };\n      let currentUrl = 'https://example.com/public/page';\n      const fn = maskFn('input', config, () => currentUrl);\n      const element = document.createElement('div');\n\n      // On /public, light level → non-sensitive input not masked\n      expect(fn('some text', element)).toEqual('some text');\n\n      // Simulate SPA navigation to /admin\n      currentUrl = 'https://example.com/admin/dashboard';\n      expect(fn('some text', element)).toEqual('**** ****');\n    });\n  });\n\n  describe('validateUGCFilterRules', () => {\n    test('should not throw for valid rules', () => {\n      const rules = [\n        { selector: 'https://example.com/user/*', replacement: 'https://example.com/user/user_id' },\n        { selector: 'https://example.com/product/*', replacement: 'https://example.com/product/product_id' },\n      ];\n      expect(() => validateUGCFilterRules(rules)).not.toThrow();\n    });\n\n    test('should throw for non-string selector', () => {\n      const rules = [{ selector: 123, replacement: 'replacement' }] as unknown as UGCFilterRule[];\n      expect(() => validateUGCFilterRules(rules)).toThrow(\n        'ugcFilterRules must be an array of objects with selector and replacement properties',\n      );\n    });\n\n    test('should throw for non-string replacement', () => {\n      const rules: any = [{ selector: 'pattern', replacement: 456 }];\n      expect(() => validateUGCFilterRules(rules)).toThrow(\n        'ugcFilterRules must be an array of objects with selector and replacement properties',\n      );\n    });\n\n    test('should throw for invalid glob pattern', () => {\n      const rules: any = [{ selector: 'invalid[pattern', replacement: 'replacement' }];\n      expect(() => validateUGCFilterRules(rules)).toThrow(\n        'ugcFilterRules must be an array of objects with valid globs',\n      );\n    });\n\n    test('should throw for empty string selector', () => {\n      const rules = [{ selector: '', replacement: 'replacement' }];\n      expect(() => validateUGCFilterRules(rules)).toThrow(\n        'ugcFilterRules must be an array of objects with valid globs',\n      );\n    });\n\n    test('should throw for whitespace-only selector', () => {\n      const rules = [{ selector: '   ', replacement: 'replacement' }];\n      expect(() => validateUGCFilterRules(rules)).toThrow(\n        'ugcFilterRules must be an array of objects with valid globs',\n      );\n    });\n\n    test('should throw for tab and newline whitespace selector', () => {\n      const rules = [{ selector: '\\t\\n\\r ', replacement: 'replacement' }];\n      expect(() => validateUGCFilterRules(rules)).toThrow(\n        'ugcFilterRules must be an array of objects with valid globs',\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/hooks/beacon.test.ts",
    "content": "import * as AnalyticsCore from '@amplitude/analytics-core';\nimport { SessionReplayJoinedConfig } from 'src/config/types';\nimport { BeaconTransport } from '../../src/beacon-transport';\nimport { randomUUID } from 'crypto';\n\ntype TestEvent = {\n  Field1: string;\n  Field2: number;\n};\n\ndescribe('beacon', () => {\n  const mockGlobalScope = (globalScope?: Partial<typeof globalThis>): typeof globalThis => {\n    const mockedGlobalScope = jest.spyOn(AnalyticsCore, 'getGlobalScope');\n    mockedGlobalScope.mockReturnValue(globalScope as typeof globalThis);\n    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n    return AnalyticsCore.getGlobalScope()!;\n  };\n\n  describe('BeaconTransport', () => {\n    let transport: BeaconTransport<TestEvent>;\n    let deviceId: string;\n    let sessionId: number;\n    let apiKey: string;\n\n    const xmlMockFns = {\n      open: jest.fn(),\n      send: jest.fn(),\n      setRequestHeader: jest.fn(),\n    };\n\n    beforeEach(() => {\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n      window.XMLHttpRequest = jest.fn().mockImplementation(() => {\n        return xmlMockFns;\n      }) as any;\n\n      sessionId = Date.now();\n      deviceId = randomUUID();\n      apiKey = randomUUID();\n\n      transport = new BeaconTransport<TestEvent>(\n        {\n          sessionId,\n          type: 'interaction',\n        },\n        {\n          apiKey,\n        } as SessionReplayJoinedConfig,\n      );\n    });\n\n    afterEach(() => {\n      jest.resetAllMocks();\n    });\n\n    describe('#send', () => {\n      test('sends with beacon', () => {\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n        const mockedGlobalScope = mockGlobalScope({\n          navigator: {\n            sendBeacon: jest.fn().mockImplementation(() => true),\n          },\n          Blob: jest.fn(),\n        } as any);\n\n        transport = new BeaconTransport<TestEvent>(\n          {\n            sessionId,\n            type: 'interaction',\n          },\n          {\n            apiKey,\n          } as SessionReplayJoinedConfig,\n        );\n        transport.send(deviceId, {\n          Field1: 'foo',\n          Field2: 1234,\n        });\n        expect(xmlMockFns.open).not.toHaveBeenCalled();\n        // eslint-disable-next-line @typescript-eslint/unbound-method\n        expect(mockedGlobalScope.navigator.sendBeacon).toHaveBeenCalledWith(\n          `https://api-sr.amplitude.com/sessions/v2/track?device_id=${deviceId}&session_id=${sessionId}&type=interaction&api_key=${apiKey}`,\n          JSON.stringify({ Field1: 'foo', Field2: 1234 }),\n        );\n      });\n      test('falls back to xhr', () => {\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n        mockGlobalScope({\n          navigator: {\n            sendBeacon: jest.fn().mockImplementation(() => false),\n          },\n          Blob: jest.fn(),\n        } as any);\n\n        transport = new BeaconTransport<TestEvent>(\n          {\n            sessionId,\n            type: 'interaction',\n          },\n          {\n            apiKey,\n          } as SessionReplayJoinedConfig,\n        );\n        transport.send(deviceId, {\n          Field1: 'foo',\n          Field2: 1234,\n        });\n        expect(xmlMockFns.open).toHaveBeenCalledWith(\n          'POST',\n          `https://api-sr.amplitude.com/sessions/v2/track?device_id=${deviceId}&session_id=${sessionId}&type=interaction&api_key=${apiKey}`,\n          true,\n        );\n      });\n      test('sends with xhr', () => {\n        transport.send(deviceId, {\n          Field1: 'foo',\n          Field2: 1234,\n        });\n        expect(xmlMockFns.open).toHaveBeenCalledWith(\n          'POST',\n          `https://api-sr.amplitude.com/sessions/v2/track?device_id=${deviceId}&session_id=${sessionId}&type=interaction&api_key=${apiKey}`,\n          true,\n        );\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/hooks/click.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unsafe-call */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-unsafe-return */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\nimport * as AnalyticsCore from '@amplitude/analytics-core';\nimport { MouseInteractions } from '@amplitude/rrweb-types';\nimport { SessionReplayEventsManager } from '../../src/typings/session-replay';\nimport { UUID } from '@amplitude/analytics-core';\nimport { ClickEvent, ClickEventWithCount, clickBatcher, ClickHandler, clickNonBatcher } from '../../src/hooks/click';\nimport { record } from '@amplitude/rrweb-record';\nimport type { ILogger } from '@amplitude/analytics-core';\nimport { finder } from '../../src/libs/finder';\nimport { ScrollWatcher } from '../../src/hooks/scroll';\n\njest.mock('../../src/libs/finder');\njest.mock('../../src/utils/rrweb');\njest.mock('@amplitude/rrweb-record');\n\ndescribe('click', () => {\n  const mockLoggerProvider: ILogger = {\n    error: jest.fn(),\n    log: jest.fn(),\n    disable: jest.fn(),\n    enable: jest.fn(),\n    warn: jest.fn(),\n    debug: jest.fn(),\n  };\n\n  // Need to mock this in one function, but we want to use the real function everywhere else.\n  // If there is a better way to do this in Jest, please refactor this!\n  const mockFinder = finder as jest.Mock;\n  beforeEach(() => {\n    mockFinder.mockImplementation((arg) => {\n      const fn = jest.requireActual('../../src/libs/finder');\n      return fn.finder(arg);\n    });\n  });\n\n  describe('clickHook', () => {\n    const mockEventsManager: jest.Mocked<SessionReplayEventsManager<'interaction', string>> = {\n      sendStoredEvents: jest.fn(),\n      addEvent: jest.fn(),\n      sendCurrentSequenceEvents: jest.fn(),\n      flush: jest.fn(),\n    };\n\n    const mockGlobalScope = (globalScope?: Partial<typeof globalThis>) => {\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue(globalScope as typeof globalThis);\n    };\n\n    const createMockScrollWatcher = (scrollX = 0, scrollY = 0): ScrollWatcher => {\n      return {\n        currentScrollX: scrollX,\n        currentScrollY: scrollY,\n      } as ScrollWatcher;\n    };\n\n    afterEach(() => {\n      jest.restoreAllMocks();\n      jest.resetAllMocks();\n    });\n\n    const deviceId = UUID();\n    const sessionId = Math.round(Math.random() * 1_000_000);\n\n    test('do nothing on non click event', () => {\n      const scrollWatcher = createMockScrollWatcher();\n      const factory = new ClickHandler(mockLoggerProvider, scrollWatcher);\n      const hook = factory.createHook({\n        deviceIdFn: () => deviceId,\n        eventsManager: mockEventsManager,\n        sessionId: sessionId,\n        mirror: record.mirror,\n        ugcFilterRules: [],\n      });\n      hook({\n        id: 1234,\n        type: MouseInteractions.TouchStart,\n        x: 3,\n        y: 3,\n      });\n      expect(jest.spyOn(mockEventsManager, 'addEvent')).not.toHaveBeenCalled();\n    });\n    test('do nothing if x/y is undefined', () => {\n      const scrollWatcher = createMockScrollWatcher();\n      const factory = new ClickHandler(mockLoggerProvider, scrollWatcher);\n      const hook = factory.createHook({\n        deviceIdFn: () => deviceId,\n        eventsManager: mockEventsManager,\n        sessionId: sessionId,\n        mirror: record.mirror,\n        ugcFilterRules: [],\n      });\n      hook({\n        id: 1234,\n        type: MouseInteractions.Click,\n        x: undefined,\n        y: undefined,\n      });\n      expect(jest.spyOn(mockEventsManager, 'addEvent')).not.toHaveBeenCalled();\n    });\n    test('do nothing if no window given', () => {\n      mockGlobalScope(undefined);\n      const scrollWatcher = createMockScrollWatcher();\n      const factory = new ClickHandler(mockLoggerProvider, scrollWatcher);\n      const hook = factory.createHook({\n        deviceIdFn: () => deviceId,\n        eventsManager: mockEventsManager,\n        sessionId: sessionId,\n        mirror: record.mirror,\n        ugcFilterRules: [],\n      });\n      hook({\n        id: 1234,\n        type: MouseInteractions.Click,\n        x: 3,\n        y: 3,\n      });\n      expect(jest.spyOn(mockEventsManager, 'addEvent')).not.toHaveBeenCalled();\n    });\n    test('do nothing if no location', () => {\n      mockGlobalScope({\n        location: undefined,\n      });\n      const scrollWatcher = createMockScrollWatcher();\n      const factory = new ClickHandler(mockLoggerProvider, scrollWatcher);\n      const hook = factory.createHook({\n        deviceIdFn: () => deviceId,\n        eventsManager: mockEventsManager,\n        sessionId: sessionId,\n        mirror: record.mirror,\n        ugcFilterRules: [],\n      });\n      hook({\n        id: 1234,\n        type: MouseInteractions.Click,\n        x: 3,\n        y: 3,\n      });\n      expect(jest.spyOn(mockEventsManager, 'addEvent')).not.toHaveBeenCalled();\n    });\n    test('add event on click event', () => {\n      const scrollWatcher = createMockScrollWatcher();\n      const factory = new ClickHandler(mockLoggerProvider, scrollWatcher);\n      const hook = factory.createHook({\n        deviceIdFn: () => deviceId,\n        eventsManager: mockEventsManager,\n        sessionId: sessionId,\n        mirror: record.mirror,\n        ugcFilterRules: [],\n      });\n      hook({\n        id: 1234,\n        type: MouseInteractions.Click,\n        x: 3,\n        y: 3,\n      });\n      expect(jest.spyOn(mockEventsManager, 'addEvent')).toHaveBeenCalledTimes(1);\n      expect(JSON.parse(mockEventsManager.addEvent.mock.calls[0][0].event.data)).toStrictEqual({\n        x: 3,\n        y: 3,\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        pageUrl: 'http://localhost/',\n        timestamp: expect.any(Number),\n        type: 'click',\n      });\n    });\n    test('add event on click event with scroll', () => {\n      const scrollWatcher = createMockScrollWatcher(4, 5);\n      const factory = new ClickHandler(mockLoggerProvider, scrollWatcher);\n      const hook = factory.createHook({\n        deviceIdFn: () => deviceId,\n        eventsManager: mockEventsManager,\n        sessionId: sessionId,\n        mirror: record.mirror,\n        ugcFilterRules: [],\n      });\n      hook({\n        id: 1234,\n        type: MouseInteractions.Click,\n        x: 3,\n        y: 3,\n      });\n      expect(jest.spyOn(mockEventsManager, 'addEvent')).toHaveBeenCalledTimes(1);\n      expect(JSON.parse(mockEventsManager.addEvent.mock.calls[0][0].event.data)).toStrictEqual({\n        x: 3 + 4,\n        y: 3 + 5,\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        pageUrl: 'http://localhost/',\n        timestamp: expect.any(Number),\n        type: 'click',\n      });\n    });\n    test('add event on click event with selector', () => {\n      const scrollWatcher = createMockScrollWatcher();\n      const factory = new ClickHandler(mockLoggerProvider, scrollWatcher);\n      const hook = factory.createHook({\n        deviceIdFn: () => deviceId,\n        eventsManager: mockEventsManager,\n        sessionId: sessionId,\n        mirror: record.mirror,\n        ugcFilterRules: [],\n      });\n      (record.mirror.getNode as jest.Mock).mockImplementation(() => {\n        const ele = document.createElement('div');\n        document.body.appendChild(ele);\n        return ele;\n      }) as any;\n      hook({\n        id: 1234,\n        type: MouseInteractions.Click,\n        x: 3,\n        y: 3,\n      });\n      expect(jest.spyOn(mockEventsManager, 'addEvent')).toHaveBeenCalledTimes(1);\n      expect(JSON.parse(mockEventsManager.addEvent.mock.calls[0][0].event.data)).toStrictEqual({\n        x: 3,\n        y: 3,\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        pageUrl: 'http://localhost/',\n        timestamp: expect.any(Number),\n        type: 'click',\n        selector: 'div',\n      });\n    });\n    test('no selector info on finder failure', () => {\n      const mockFinder = finder as jest.Mock;\n      mockFinder.mockImplementation(() => {\n        throw new Error('');\n      });\n\n      (record.mirror.getNode as jest.Mock).mockImplementation(() => {\n        const ele = document.createElement('div');\n        document.body.appendChild(ele);\n        return ele;\n      }) as any;\n      const scrollWatcher = createMockScrollWatcher();\n      const factory = new ClickHandler(mockLoggerProvider, scrollWatcher);\n      const hook = factory.createHook({\n        deviceIdFn: () => deviceId,\n        eventsManager: mockEventsManager,\n        sessionId: sessionId,\n        mirror: record.mirror,\n        ugcFilterRules: [],\n      });\n      hook({\n        id: 1234,\n        type: MouseInteractions.Click,\n        x: 3,\n        y: 3,\n      });\n      expect(jest.spyOn(mockEventsManager, 'addEvent')).toHaveBeenCalledTimes(1);\n      expect(JSON.parse(mockEventsManager.addEvent.mock.calls[0][0].event.data)).toStrictEqual({\n        x: 3,\n        y: 3,\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        pageUrl: 'http://localhost/',\n        timestamp: expect.any(Number),\n        type: 'click',\n      });\n    });\n\n    test('passes performance options to finder', () => {\n      const scrollWatcher = createMockScrollWatcher();\n      const factory = new ClickHandler(mockLoggerProvider, scrollWatcher);\n      const performanceOptions = {\n        timeoutMs: 5000,\n        maxNumberOfTries: 5000,\n        threshold: 500,\n      };\n\n      (record.mirror.getNode as jest.Mock).mockImplementation(() => {\n        const ele = document.createElement('div');\n        document.body.appendChild(ele);\n        return ele;\n      }) as any;\n\n      const hook = factory.createHook({\n        deviceIdFn: () => deviceId,\n        eventsManager: mockEventsManager,\n        sessionId: sessionId,\n        mirror: record.mirror,\n        ugcFilterRules: [],\n        performanceOptions,\n      });\n\n      hook({\n        id: 1234,\n        type: MouseInteractions.Click,\n        x: 3,\n        y: 3,\n      });\n\n      expect(mockFinder).toHaveBeenCalledWith(expect.any(Element), performanceOptions);\n      expect(jest.spyOn(mockEventsManager, 'addEvent')).toHaveBeenCalledTimes(1);\n    });\n\n    test('passes partial performance options to finder', () => {\n      const scrollWatcher = createMockScrollWatcher();\n      const factory = new ClickHandler(mockLoggerProvider, scrollWatcher);\n      const performanceOptions = {\n        timeoutMs: 3000,\n      };\n\n      (record.mirror.getNode as jest.Mock).mockImplementation(() => {\n        const ele = document.createElement('div');\n        document.body.appendChild(ele);\n        return ele;\n      }) as any;\n\n      const hook = factory.createHook({\n        deviceIdFn: () => deviceId,\n        eventsManager: mockEventsManager,\n        sessionId: sessionId,\n        mirror: record.mirror,\n        ugcFilterRules: [],\n        performanceOptions,\n      });\n\n      hook({\n        id: 1234,\n        type: MouseInteractions.Click,\n        x: 3,\n        y: 3,\n      });\n\n      expect(mockFinder).toHaveBeenCalledWith(expect.any(Element), performanceOptions);\n      expect(jest.spyOn(mockEventsManager, 'addEvent')).toHaveBeenCalledTimes(1);\n    });\n\n    test('works without performance options', () => {\n      const scrollWatcher = createMockScrollWatcher();\n      const factory = new ClickHandler(mockLoggerProvider, scrollWatcher);\n\n      (record.mirror.getNode as jest.Mock).mockImplementation(() => {\n        const ele = document.createElement('div');\n        document.body.appendChild(ele);\n        return ele;\n      }) as any;\n\n      const hook = factory.createHook({\n        deviceIdFn: () => deviceId,\n        eventsManager: mockEventsManager,\n        sessionId: sessionId,\n        mirror: record.mirror,\n        ugcFilterRules: [],\n      });\n\n      hook({\n        id: 1234,\n        type: MouseInteractions.Click,\n        x: 3,\n        y: 3,\n      });\n\n      expect(mockFinder).toHaveBeenCalledWith(expect.any(Element), undefined);\n      expect(jest.spyOn(mockEventsManager, 'addEvent')).toHaveBeenCalledTimes(1);\n      const eventData = JSON.parse(mockEventsManager.addEvent.mock.calls[0][0].event.data);\n      expect(eventData).toMatchObject({\n        x: 3,\n        y: 3,\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        pageUrl: 'http://localhost/',\n        timestamp: expect.any(Number),\n        type: 'click',\n      });\n      expect(eventData.selector).toContain('div');\n    });\n  });\n\n  describe('clickBatcher', () => {\n    const clickEventFixture = (event: Partial<ClickEvent>): ClickEvent => {\n      return {\n        pageUrl: 'http://localhost/',\n        timestamp: Date.now(),\n        type: 'click',\n        viewportHeight: 963,\n        viewportWidth: 1920,\n        x: 3,\n        y: 3,\n        ...event,\n      };\n    };\n\n    test('batches events', () => {\n      const clickEvents: ClickEvent[] = [\n        clickEventFixture({\n          x: 3,\n          y: 3,\n          timestamp: 1718327016000,\n        }),\n        clickEventFixture({\n          x: 3,\n          y: 3,\n          timestamp: 1718327012000,\n        }),\n        clickEventFixture({\n          x: 4,\n          y: 3,\n          timestamp: 1718267012000,\n        }),\n      ];\n      const { version, events } = clickBatcher({\n        version: 1,\n        events: clickEvents.map((clickEvent) => JSON.stringify(clickEvent)),\n      });\n      expect(version).toBe(1);\n      const expectedEvents: ClickEventWithCount[] = [\n        {\n          ...clickEventFixture({\n            timestamp: 1718326800000,\n            x: 3,\n            y: 3,\n          }),\n          count: 2,\n        },\n        {\n          ...clickEventFixture({\n            timestamp: 1718265600000,\n            x: 4,\n            y: 3,\n          }),\n          count: 1,\n        },\n      ];\n      expect(events).toStrictEqual(expectedEvents);\n    });\n    test('batches events with selectors', () => {\n      const clickEvents: ClickEvent[] = [\n        clickEventFixture({\n          x: 3,\n          y: 3,\n          selector: '.foo',\n          timestamp: 1718227016000,\n        }),\n        clickEventFixture({\n          x: 3,\n          y: 3,\n          timestamp: 1718217012000,\n        }),\n        clickEventFixture({\n          x: 4,\n          y: 3,\n          selector: '.bar',\n          timestamp: 1717327012000,\n        }),\n        clickEventFixture({\n          x: 4,\n          y: 3,\n          selector: '.bar',\n          timestamp: 1717327012000,\n        }),\n      ];\n      const { version, events } = clickBatcher({\n        version: 1,\n        events: clickEvents.map((clickEvent) => JSON.stringify(clickEvent)),\n      });\n      expect(version).toBe(1);\n      const expectedEvents: ClickEventWithCount[] = [\n        {\n          count: 1,\n          ...clickEventFixture({\n            timestamp: 1718226000000,\n            x: 3,\n            y: 3,\n            selector: '.foo',\n          }),\n        },\n        {\n          count: 1,\n          ...clickEventFixture({\n            timestamp: 1718215200000,\n            x: 3,\n            y: 3,\n          }),\n        },\n        {\n          count: 2,\n          ...clickEventFixture({\n            timestamp: 1717326000000,\n            x: 4,\n            y: 3,\n            selector: '.bar',\n          }),\n        },\n      ];\n      expect(events).toStrictEqual(expectedEvents);\n    });\n    test('no events in, no events out', () => {\n      const { version, events } = clickBatcher({ version: 1, events: [] });\n      expect(version).toBe(1);\n      expect(events).toStrictEqual([]);\n    });\n  });\n\n  describe('clickNonBatcher', () => {\n    const clickEventFixture = (event: Partial<ClickEvent>): ClickEvent => {\n      return {\n        pageUrl: 'http://localhost/',\n        timestamp: Date.now(),\n        type: 'click',\n        viewportHeight: 963,\n        viewportWidth: 1920,\n        x: 3,\n        y: 3,\n        ...event,\n      };\n    };\n\n    test('batches events', () => {\n      const clickEvents: ClickEvent[] = [\n        clickEventFixture({\n          x: 3,\n          y: 3,\n          timestamp: 1718327016000,\n        }),\n        clickEventFixture({\n          x: 3,\n          y: 3,\n          timestamp: 1718327012000,\n        }),\n        clickEventFixture({\n          x: 4,\n          y: 3,\n          timestamp: 1718267012000,\n        }),\n      ];\n      const { version, events } = clickNonBatcher({\n        version: 1,\n        events: clickEvents.map((clickEvent) => JSON.stringify(clickEvent)),\n      });\n      expect(version).toBe(1);\n      const expectedEvents: ClickEventWithCount[] = [\n        {\n          ...clickEventFixture({\n            timestamp: 1718327016000,\n            x: 3,\n            y: 3,\n          }),\n          count: 1,\n        },\n        {\n          ...clickEventFixture({\n            timestamp: 1718327012000,\n            x: 3,\n            y: 3,\n          }),\n          count: 1,\n        },\n        {\n          ...clickEventFixture({\n            timestamp: 1718267012000,\n            x: 4,\n            y: 3,\n          }),\n          count: 1,\n        },\n      ];\n      expect(events).toStrictEqual(expectedEvents);\n    });\n    test('batches events with selectors', () => {\n      const clickEvents: ClickEvent[] = [\n        clickEventFixture({\n          x: 3,\n          y: 3,\n          selector: '.foo',\n          timestamp: 1718227016000,\n        }),\n        clickEventFixture({\n          x: 3,\n          y: 3,\n          timestamp: 1718217012000,\n        }),\n        clickEventFixture({\n          x: 4,\n          y: 3,\n          selector: '.bar',\n          timestamp: 1717327012000,\n        }),\n        clickEventFixture({\n          x: 4,\n          y: 3,\n          selector: '.bar',\n          timestamp: 1717327012000,\n        }),\n      ];\n      const { version, events } = clickNonBatcher({\n        version: 1,\n        events: clickEvents.map((clickEvent) => JSON.stringify(clickEvent)),\n      });\n      expect(version).toBe(1);\n      const expectedEvents: ClickEventWithCount[] = [\n        {\n          count: 1,\n          ...clickEventFixture({\n            timestamp: 1718227016000,\n            x: 3,\n            y: 3,\n            selector: '.foo',\n          }),\n        },\n        {\n          count: 1,\n          ...clickEventFixture({\n            timestamp: 1718217012000,\n            x: 3,\n            y: 3,\n          }),\n        },\n        {\n          count: 1,\n          ...clickEventFixture({\n            timestamp: 1717327012000,\n            x: 4,\n            y: 3,\n            selector: '.bar',\n          }),\n        },\n        {\n          count: 1,\n          ...clickEventFixture({\n            timestamp: 1717327012000,\n            x: 4,\n            y: 3,\n            selector: '.bar',\n          }),\n        },\n      ];\n      expect(events).toStrictEqual(expectedEvents);\n    });\n    test('no events in, no events out', () => {\n      const { version, events } = clickNonBatcher({ version: 1, events: [] });\n      expect(version).toBe(1);\n      expect(events).toStrictEqual([]);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/hooks/scroll.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint jest/expect-expect: [\"error\", { \"assertFunctionNames\": [\"expect\", \"expectMaxScrolls\"] }] */\nimport * as AnalyticsCore from '@amplitude/analytics-core';\nimport { BeaconTransport } from '../../src/beacon-transport';\nimport { ScrollEventPayload, ScrollWatcher } from '../../src/hooks/scroll';\n\nimport { ILogger } from '@amplitude/analytics-core';\n\nimport { randomUUID } from 'crypto';\nimport { getViewportHeight, getViewportWidth } from '../../src/utils/rrweb';\n\njest.mock('../../src/beacon-transport');\njest.mock('../../src/utils/rrweb');\n\ndescribe('scroll', () => {\n  const mockGlobalScope = (globalScope?: Partial<typeof globalThis>) => {\n    jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue(globalScope as typeof globalThis);\n  };\n\n  const mockWindowWidth = (width = 0) => {\n    (getViewportWidth as jest.Mock).mockImplementation(() => {\n      return width;\n    }) as any;\n  };\n\n  const mockWindowHeight = (height = 0) => {\n    (getViewportHeight as jest.Mock).mockImplementation(() => {\n      return height;\n    }) as any;\n  };\n\n  describe('ScrollWatcher', () => {\n    const mockTransport = BeaconTransport<ScrollEventPayload> as jest.MockedClass<\n      typeof BeaconTransport<ScrollEventPayload>\n    >;\n\n    let mockTransportInstance: BeaconTransport<ScrollEventPayload>;\n    let scrollWatcher: ScrollWatcher;\n\n    beforeEach(() => {\n      mockWindowWidth();\n      mockWindowHeight();\n      mockGlobalScope({\n        location: {\n          href: 'http://localhost',\n        } as any,\n        scrollX: 0,\n        scrollY: 0,\n      });\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n      mockTransportInstance = new mockTransport({} as any, {} as any);\n      const mockLoggerProvider: ILogger = {\n        error: jest.fn(),\n        log: jest.fn(),\n        disable: jest.fn(),\n        enable: jest.fn(),\n        warn: jest.fn(),\n        debug: jest.fn(),\n      };\n      scrollWatcher = new ScrollWatcher(mockTransportInstance, {\n        loggerProvider: mockLoggerProvider,\n        interactionConfig: {\n          enabled: true,\n          ugcFilterRules: [],\n          batch: false,\n        },\n      });\n    });\n\n    afterEach(() => {\n      jest.restoreAllMocks();\n      jest.resetAllMocks();\n    });\n\n    const expectMaxScrolls = (scrolls: {\n      maxScrollX?: number;\n      maxScrollY?: number;\n      maxScrollWidth?: number;\n      maxScrollHeight?: number;\n    }) => {\n      expect({\n        maxScrollX: scrolls.maxScrollX && scrollWatcher.maxScrollX,\n        maxScrollY: scrolls.maxScrollY && scrollWatcher.maxScrollY,\n        maxScrollWidth: scrolls.maxScrollWidth && scrollWatcher.maxScrollWidth,\n        maxScrollHeight: scrolls.maxScrollHeight && scrollWatcher.maxScrollHeight,\n      }).toStrictEqual({\n        maxScrollX: scrolls.maxScrollX,\n        maxScrollY: scrolls.maxScrollY,\n        maxScrollWidth: scrolls.maxScrollWidth,\n        maxScrollHeight: scrolls.maxScrollHeight,\n      });\n    };\n\n    describe('#send', () => {\n      test('sends scroll event', () => {\n        scrollWatcher.hook({ id: 1, x: 3, y: 5 });\n        const deviceId = randomUUID().toString();\n        scrollWatcher.send(() => deviceId)({} as Event);\n\n        expect(mockTransport.prototype.send.mock.calls[0][0]).toStrictEqual(deviceId);\n        expect(mockTransport.prototype.send.mock.calls[0][1]).toStrictEqual({\n          version: 1,\n          events: [\n            {\n              maxScrollX: 3,\n              maxScrollY: 5,\n              maxScrollWidth: 3,\n              maxScrollHeight: 5,\n\n              viewportHeight: 0,\n              viewportWidth: 0,\n              pageUrl: 'http://localhost',\n              timestamp: expect.any(Number),\n              type: 'scroll',\n            },\n          ],\n        });\n      });\n\n      test('applies UGC filter rules to page URL', () => {\n        mockGlobalScope({\n          location: {\n            href: 'http://localhost?user=123&token=abc',\n          } as any,\n        });\n\n        const mockLoggerProvider: ILogger = {\n          error: jest.fn(),\n          log: jest.fn(),\n          disable: jest.fn(),\n          enable: jest.fn(),\n          warn: jest.fn(),\n          debug: jest.fn(),\n        };\n\n        const scrollWatcherWithUgcRules = new ScrollWatcher(mockTransportInstance, {\n          loggerProvider: mockLoggerProvider,\n          interactionConfig: {\n            enabled: true,\n            ugcFilterRules: [\n              {\n                selector: 'http://localhost?user=123&token=*',\n                replacement: 'http://localhost?user=123&token=REDACTED',\n              },\n            ],\n            batch: false,\n          },\n        });\n\n        scrollWatcherWithUgcRules.hook({ id: 1, x: 3, y: 5 });\n        const deviceId = randomUUID().toString();\n        scrollWatcherWithUgcRules.send(() => deviceId)({} as Event);\n\n        expect(mockTransport.prototype.send.mock.calls[0][0]).toStrictEqual(deviceId);\n        const payload = mockTransport.prototype.send.mock.calls[0][1] as ScrollEventPayload;\n        expect(payload.events[0].pageUrl).toBe('http://localhost?user=123&token=REDACTED');\n      });\n\n      test('handles undefined interactionConfig', () => {\n        mockGlobalScope({\n          location: {\n            href: 'http://localhost?user=123&token=abc',\n          } as any,\n        });\n\n        const mockLoggerProvider: ILogger = {\n          error: jest.fn(),\n          log: jest.fn(),\n          disable: jest.fn(),\n          enable: jest.fn(),\n          warn: jest.fn(),\n          debug: jest.fn(),\n        };\n\n        const scrollWatcherWithoutConfig = new ScrollWatcher(mockTransportInstance, {\n          loggerProvider: mockLoggerProvider,\n        });\n\n        scrollWatcherWithoutConfig.hook({ id: 1, x: 3, y: 5 });\n        const deviceId = randomUUID().toString();\n        scrollWatcherWithoutConfig.send(() => deviceId)({} as Event);\n\n        expect(mockTransport.prototype.send.mock.calls[0][0]).toStrictEqual(deviceId);\n        const payload = mockTransport.prototype.send.mock.calls[0][1] as ScrollEventPayload;\n        expect(payload.events[0].pageUrl).toBe('http://localhost?user=123&token=abc');\n      });\n\n      test('captures window scroll position on send even when rrweb hook has not delivered latest position', () => {\n        // Simulate: rrweb hook delivered scroll to y=500, but user actually scrolled to y=3000\n        // before pagehide fired. The throttled rrweb callback never delivered y=3000.\n        mockGlobalScope({\n          location: { href: 'http://localhost' } as any,\n          scrollX: 0,\n          scrollY: 3000,\n        });\n\n        scrollWatcher.hook({ id: 1, x: 0, y: 500 });\n        const deviceId = randomUUID().toString();\n        scrollWatcher.send(() => deviceId)({} as Event);\n\n        const payload = mockTransport.prototype.send.mock.calls[0][1] as ScrollEventPayload;\n        expect(payload.events[0].maxScrollY).toBe(3000);\n      });\n\n      test('captures window scroll position on send even when no rrweb hook events fired', () => {\n        // Simulate: rrweb throttle dropped all events, but user scrolled to y=1500\n        mockGlobalScope({\n          location: { href: 'http://localhost' } as any,\n          scrollX: 100,\n          scrollY: 1500,\n        });\n\n        // No hook() calls at all\n        const deviceId = randomUUID().toString();\n        scrollWatcher.send(() => deviceId)({} as Event);\n\n        const payload = mockTransport.prototype.send.mock.calls[0][1] as ScrollEventPayload;\n        expect(payload.events[0].maxScrollX).toBe(100);\n        expect(payload.events[0].maxScrollY).toBe(1500);\n      });\n\n      test('does not regress maxScrollY when window scroll is lower than hook-delivered max', () => {\n        // User scrolled to 5000, then scrolled back up to 2000 before leaving\n        mockGlobalScope({\n          location: { href: 'http://localhost' } as any,\n          scrollX: 0,\n          scrollY: 2000,\n        });\n\n        scrollWatcher.hook({ id: 1, x: 0, y: 5000 });\n        const deviceId = randomUUID().toString();\n        scrollWatcher.send(() => deviceId)({} as Event);\n\n        const payload = mockTransport.prototype.send.mock.calls[0][1] as ScrollEventPayload;\n        // maxScrollY should still be 5000 (the highest seen), not 2000\n        expect(payload.events[0].maxScrollY).toBe(5000);\n      });\n\n      test('handles empty ugcFilterRules array', () => {\n        mockGlobalScope({\n          location: {\n            href: 'http://localhost?user=123&token=abc',\n          } as any,\n        });\n\n        const mockLoggerProvider: ILogger = {\n          error: jest.fn(),\n          log: jest.fn(),\n          disable: jest.fn(),\n          enable: jest.fn(),\n          warn: jest.fn(),\n          debug: jest.fn(),\n        };\n\n        const scrollWatcherWithEmptyRules = new ScrollWatcher(mockTransportInstance, {\n          loggerProvider: mockLoggerProvider,\n          interactionConfig: {\n            enabled: true,\n            ugcFilterRules: [],\n            batch: false,\n          },\n        });\n\n        scrollWatcherWithEmptyRules.hook({ id: 1, x: 3, y: 5 });\n        const deviceId = randomUUID().toString();\n        scrollWatcherWithEmptyRules.send(() => deviceId)({} as Event);\n\n        expect(mockTransport.prototype.send.mock.calls[0][0]).toStrictEqual(deviceId);\n        const payload = mockTransport.prototype.send.mock.calls[0][1] as ScrollEventPayload;\n        expect(payload.events[0].pageUrl).toBe('http://localhost?user=123&token=abc');\n      });\n    });\n\n    describe('#hook', () => {\n      // Most of the tests are covered in #update\n      test('updates correctly', () => {\n        scrollWatcher.hook({ id: 1, x: 3, y: 5 });\n        expectMaxScrolls({ maxScrollX: 3, maxScrollY: 5, maxScrollHeight: 5, maxScrollWidth: 3 });\n      });\n    });\n\n    describe('#update', () => {\n      const mockLoggerProvider: ILogger = {\n        error: jest.fn(),\n        log: jest.fn(),\n        disable: jest.fn(),\n        enable: jest.fn(),\n        warn: jest.fn(),\n        debug: jest.fn(),\n      };\n      test('initial update', () => {\n        scrollWatcher.update({ id: 1, x: 3, y: 4 });\n        expectMaxScrolls({ maxScrollX: 3, maxScrollY: 4, maxScrollHeight: 4, maxScrollWidth: 3 });\n      });\n\n      test('new max scroll x', () => {\n        scrollWatcher.update({ id: 1, x: 3, y: 4 });\n        scrollWatcher.update({ id: 1, x: 5, y: 4 });\n        expectMaxScrolls({ maxScrollX: 5, maxScrollWidth: 5 });\n      });\n\n      test('does not update max scroll x', () => {\n        scrollWatcher.update({ id: 1, x: 3, y: 4 });\n        scrollWatcher.update({ id: 1, x: 2, y: 4 });\n        expectMaxScrolls({ maxScrollX: 3, maxScrollWidth: 3 });\n      });\n\n      test('new max scroll y', () => {\n        scrollWatcher.update({ id: 1, x: 3, y: 4 });\n        scrollWatcher.update({ id: 1, x: 3, y: 6 });\n        expectMaxScrolls({ maxScrollY: 6, maxScrollHeight: 6 });\n      });\n\n      test('does not update max scroll y', () => {\n        scrollWatcher.update({ id: 1, x: 3, y: 4 });\n        scrollWatcher.update({ id: 1, x: 2, y: 1 });\n        expectMaxScrolls({ maxScrollY: 4, maxScrollHeight: 4 });\n      });\n\n      test('new max scroll width', () => {\n        mockWindowWidth(42);\n        scrollWatcher = new ScrollWatcher(mockTransportInstance, {\n          loggerProvider: mockLoggerProvider,\n          interactionConfig: {\n            enabled: true,\n            ugcFilterRules: [],\n            batch: false,\n          },\n        });\n        scrollWatcher.update({ id: 1, x: 3, y: 4 });\n        scrollWatcher.update({ id: 1, x: 5, y: 4 });\n        expectMaxScrolls({ maxScrollX: 5, maxScrollWidth: 42 + 5 });\n      });\n\n      test('new max scroll height', () => {\n        mockWindowHeight(24);\n        scrollWatcher = new ScrollWatcher(mockTransportInstance, {\n          loggerProvider: mockLoggerProvider,\n          interactionConfig: {\n            enabled: true,\n            ugcFilterRules: [],\n            batch: false,\n          },\n        });\n        scrollWatcher.update({ id: 1, x: 3, y: 4 });\n        scrollWatcher.update({ id: 1, x: 5, y: 6 });\n        expectMaxScrolls({ maxScrollY: 6, maxScrollHeight: 24 + 6 });\n      });\n\n      test('tracks current scroll x', () => {\n        scrollWatcher.update({ id: 1, x: 10, y: 4 });\n        expect(scrollWatcher.currentScrollX).toBe(10);\n        scrollWatcher.update({ id: 1, x: 5, y: 4 });\n        expect(scrollWatcher.currentScrollX).toBe(5);\n      });\n\n      test('tracks current scroll y', () => {\n        scrollWatcher.update({ id: 1, x: 3, y: 20 });\n        expect(scrollWatcher.currentScrollY).toBe(20);\n        scrollWatcher.update({ id: 1, x: 3, y: 15 });\n        expect(scrollWatcher.currentScrollY).toBe(15);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/index.test.ts",
    "content": "import { getSessionReplayProperties, init, setSessionId, shutdown } from '../src/index';\n\ndescribe('index', () => {\n  test('should expose apis', () => {\n    expect(typeof init).toBe('function');\n    expect(typeof setSessionId).toBe('function');\n    expect(typeof getSessionReplayProperties).toBe('function');\n    expect(typeof shutdown).toBe('function');\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/integration/sampling.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unsafe-call */\n/* eslint-disable @typescript-eslint/unbound-method */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\nimport * as AnalyticsCore from '@amplitude/analytics-core';\nimport { LogLevel, ILogger, ServerZone, RemoteConfig, Source } from '@amplitude/analytics-core';\nimport * as Sampling from '../../src/sampling';\nimport { IDBFactory } from 'fake-indexeddb';\nimport { SessionReplayOptions } from 'src/typings/session-replay';\nimport * as SessionReplayIDB from '../../src/events/events-idb-store';\n\nimport { DEFAULT_SAMPLE_RATE, DEFAULT_SESSION_REPLAY_PROPERTY, SESSION_REPLAY_SERVER_URL } from '../../src/constants';\nimport { SessionReplay } from '../../src/session-replay';\nimport { SESSION_ID_IN_20_SAMPLE } from '../test-data';\nimport { eventWithTime } from '@amplitude/rrweb-types';\n\ntype MockedLogger = jest.Mocked<ILogger>;\n\n// Mock remote config client\nlet mockRemoteConfig: RemoteConfig | null = null;\nlet mockRemoteConfigClient: any;\n\nconst mockEvent = {\n  type: 4,\n  data: { href: 'https://analytics.amplitude.com/', width: 1728, height: 154 },\n  timestamp: 1687358660935,\n};\nconst samplingConfig = {\n  sample_rate: 0.5,\n  capture_enabled: true,\n};\n\nasync function runScheduleTimers() {\n  // eslint-disable-next-line @typescript-eslint/unbound-method\n  await new Promise(process.nextTick);\n  jest.runAllTimers();\n}\n\ndescribe('module level integration', () => {\n  const addEventListenerMock = jest.fn() as jest.Mock<typeof window.addEventListener>;\n  const removeEventListenerMock = jest.fn() as jest.Mock<typeof window.removeEventListener>;\n  const mockGlobalScope = {\n    addEventListener: addEventListenerMock,\n    removeEventListener: removeEventListenerMock,\n    document: {\n      hasFocus: () => true,\n    },\n    indexedDB: new IDBFactory(),\n  } as unknown as typeof globalThis;\n  let originalFetch: typeof global.fetch;\n  const mockLoggerProvider: MockedLogger = {\n    error: jest.fn(),\n    log: jest.fn(),\n    disable: jest.fn(),\n    enable: jest.fn(),\n    warn: jest.fn(),\n    debug: jest.fn(),\n  };\n  const apiKey = 'static_key';\n  const mockOptions: SessionReplayOptions = {\n    flushIntervalMillis: 0,\n    flushMaxRetries: 1,\n    flushQueueSize: 0,\n    logLevel: LogLevel.None,\n    loggerProvider: mockLoggerProvider,\n    deviceId: '1a2b3c',\n    optOut: false,\n    sampleRate: 1,\n    sessionId: SESSION_ID_IN_20_SAMPLE,\n    serverZone: ServerZone.US,\n    storeType: 'idb',\n  };\n  const mockEmptyOptions: SessionReplayOptions = {\n    flushIntervalMillis: 0,\n    flushMaxRetries: 1,\n    flushQueueSize: 0,\n    logLevel: LogLevel.None,\n    loggerProvider: mockLoggerProvider,\n    deviceId: '1a2b3c',\n    sessionId: SESSION_ID_IN_20_SAMPLE,\n  };\n  let mockRecordFunction: jest.Mock & { addCustomEvent: jest.Mock };\n\n  // Helper function to initialize the mock remote config client\n  const initializeMockRemoteConfigClient = () => {\n    // Use a function that references mockRemoteConfig dynamically\n    const subscribeImplementation = jest.fn((configKey: string, _subscriptionMode: string, callback: any) => {\n      // Filter the config by key, matching RemoteConfigClient.sendCallback behavior\n      let filteredConfig: RemoteConfig | null = mockRemoteConfig;\n      if (configKey && filteredConfig) {\n        filteredConfig = configKey.split('.').reduce((config: RemoteConfig | null, key: string) => {\n          if (config === null) {\n            return config;\n          }\n          return key in config ? (config[key] as RemoteConfig) : null;\n        }, filteredConfig as RemoteConfig | null);\n      }\n\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n      return callback(filteredConfig, 'initial' as Source, new Date());\n    });\n\n    mockRemoteConfigClient = {\n      subscribe: subscribeImplementation,\n    };\n\n    // Mock RemoteConfigClient constructor using jest.spyOn\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n    jest.spyOn(AnalyticsCore, 'RemoteConfigClient').mockImplementation(() => mockRemoteConfigClient);\n  };\n\n  beforeEach(() => {\n    // Initialize mockRemoteConfig with default sampling config\n    // Structure must match how RemoteConfigClient.sendCallback filters by key\n    // When key is 'configs.sessionReplay', it expects nested objects: configs -> sessionReplay\n    mockRemoteConfig = {\n      configs: {\n        sessionReplay: {\n          sr_sampling_config: samplingConfig,\n          sr_privacy_config: {},\n        },\n      },\n    };\n\n    // Initialize the mock remote config client\n    initializeMockRemoteConfigClient();\n\n    jest.spyOn(SessionReplayIDB.SessionReplayEventsIDBStore, 'new');\n    jest.useFakeTimers({ doNotFake: ['nextTick'] });\n    originalFetch = global.fetch;\n    global.fetch = jest.fn(() =>\n      Promise.resolve({\n        status: 200,\n      }),\n    ) as jest.Mock;\n    jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue(mockGlobalScope);\n\n    // Create mock record function with addCustomEvent method\n    mockRecordFunction = jest.fn().mockReturnValue(jest.fn()) as jest.Mock & { addCustomEvent: jest.Mock };\n    mockRecordFunction.addCustomEvent = jest.fn();\n\n    // Mock the getRecordFunction method instead of mocking RRWeb directly\n    jest.spyOn(SessionReplay.prototype, 'getRecordFunction' as any).mockResolvedValue(mockRecordFunction);\n  });\n  afterEach(() => {\n    jest.resetAllMocks();\n    jest.spyOn(global.Math, 'random').mockRestore();\n    global.fetch = originalFetch;\n    jest.useRealTimers();\n  });\n  describe('sampleRate and captureEnabled', () => {\n    describe('without remote config set', () => {\n      beforeEach(() => {\n        mockRemoteConfig = null;\n        initializeMockRemoteConfigClient();\n      });\n      test('should not capture', async () => {\n        const sessionReplay = new SessionReplay();\n        await sessionReplay.init(apiKey, { ...mockOptions }).promise;\n        expect(sessionReplay.config?.captureEnabled).toBe(false);\n        expect(mockRecordFunction).not.toHaveBeenCalled();\n        await runScheduleTimers();\n        expect(fetch).not.toHaveBeenCalledWith(SESSION_REPLAY_SERVER_URL);\n      });\n    });\n    describe('with remote config set', () => {\n      beforeEach(() => {\n        mockRemoteConfig = {\n          configs: {\n            sessionReplay: {\n              sr_sampling_config: samplingConfig,\n            },\n          },\n        };\n        initializeMockRemoteConfigClient();\n      });\n      test('should capture', async () => {\n        const sessionReplay = new SessionReplay();\n        await sessionReplay.init(apiKey, { ...mockOptions }).promise;\n        // Wait for async initialize to complete\n        await runScheduleTimers();\n        const sessionRecordingProperties = sessionReplay.getSessionReplayProperties();\n        const createEventsIDBStoreInstance = await (SessionReplayIDB.SessionReplayEventsIDBStore.new as jest.Mock).mock\n          .results[0].value;\n\n        jest.spyOn(createEventsIDBStoreInstance, 'storeCurrentSequence');\n        expect(sessionRecordingProperties).toMatchObject({\n          [DEFAULT_SESSION_REPLAY_PROPERTY]: `1a2b3c/${SESSION_ID_IN_20_SAMPLE}`,\n        });\n        expect(mockRecordFunction).toHaveBeenCalled();\n        const recordArg = mockRecordFunction.mock.calls[0][0] as { emit?: (event: eventWithTime) => void };\n        recordArg?.emit?.(mockEvent);\n        sessionReplay.sendEvents();\n        await (createEventsIDBStoreInstance.storeCurrentSequence as jest.Mock).mock.results[0].value;\n        await runScheduleTimers();\n        expect(fetch).toHaveBeenLastCalledWith(\n          `${SESSION_REPLAY_SERVER_URL}?device_id=1a2b3c&session_id=${SESSION_ID_IN_20_SAMPLE}&type=replay`,\n          expect.anything(),\n        );\n        // eslint-disable-next-line @typescript-eslint/unbound-method\n        expect(mockLoggerProvider.log).toHaveBeenLastCalledWith(\n          'Session replay event batch tracked successfully for session id 1719847315013, size of events: 0 KB',\n        );\n      });\n\n      test('should use sampleRate from remote config', async () => {\n        const inSampleSpy = jest.spyOn(Sampling, 'isSessionInSample');\n        const sessionReplay = new SessionReplay();\n        await sessionReplay.init(apiKey, { ...mockOptions, sampleRate: 0.8 }).promise;\n        expect(inSampleSpy).toHaveBeenCalledWith(sessionReplay.identifiers?.sessionId, 0.5);\n      });\n    });\n  });\n  describe('sampling logic', () => {\n    beforeEach(() => {\n      mockRemoteConfig = null;\n      initializeMockRemoteConfigClient();\n    });\n    describe('with a sample rate', () => {\n      test('should not record session if excluded due to sampling', async () => {\n        const sessionReplay = new SessionReplay();\n        // Set sample rate low enough so that SESSION_ID_IN_20_SAMPLE is not included in the sample\n        await sessionReplay.init(apiKey, { ...mockOptions, sampleRate: 0.1 }).promise;\n        const sampleRate = sessionReplay.config?.sampleRate;\n        expect(sampleRate).toBe(0.1);\n        const sessionRecordingProperties = sessionReplay.getSessionReplayProperties();\n        expect(sessionRecordingProperties).toMatchObject({});\n        expect(mockRecordFunction).not.toHaveBeenCalled();\n        await runScheduleTimers();\n        expect(fetch).not.toHaveBeenCalledWith(SESSION_REPLAY_SERVER_URL);\n      });\n      test('should record session if included due to sampling', async () => {\n        mockRemoteConfig = {\n          configs: {\n            sessionReplay: {\n              sr_sampling_config: samplingConfig,\n            },\n          },\n        };\n        const sessionReplay = new SessionReplay();\n        await sessionReplay.init(apiKey, { ...mockOptions, sampleRate: 0.8 }).promise;\n        // Wait for async initialize to complete\n        await runScheduleTimers();\n        const createEventsIDBStoreInstance = await (SessionReplayIDB.SessionReplayEventsIDBStore.new as jest.Mock).mock\n          .results[0].value;\n        jest.spyOn(createEventsIDBStoreInstance, 'storeCurrentSequence');\n        const sessionRecordingProperties = sessionReplay.getSessionReplayProperties();\n        expect(sessionRecordingProperties).toMatchObject({\n          [DEFAULT_SESSION_REPLAY_PROPERTY]: `1a2b3c/${SESSION_ID_IN_20_SAMPLE}`,\n        });\n        // Log is called from setup, but that's not what we're testing here\n        mockLoggerProvider.log.mockClear();\n        expect(mockRecordFunction).toHaveBeenCalled();\n        const recordArg = mockRecordFunction.mock.calls[0][0] as { emit?: (event: eventWithTime) => void };\n        recordArg?.emit?.(mockEvent);\n        sessionReplay.sendEvents();\n        await (createEventsIDBStoreInstance.storeCurrentSequence as jest.Mock).mock.results[0].value;\n        await runScheduleTimers();\n        expect(fetch).toHaveBeenLastCalledWith(\n          `${SESSION_REPLAY_SERVER_URL}?device_id=1a2b3c&session_id=${SESSION_ID_IN_20_SAMPLE}&type=replay`,\n          expect.anything(),\n        );\n        // eslint-disable-next-line @typescript-eslint/unbound-method\n        expect(mockLoggerProvider.log).toHaveBeenLastCalledWith(\n          'Session replay event batch tracked successfully for session id 1719847315013, size of events: 0 KB',\n        );\n      });\n    });\n    describe('without a sample rate', () => {\n      test('should not record session if no sample rate is provided', async () => {\n        const sessionReplay = new SessionReplay();\n        await sessionReplay.init(apiKey, { ...mockEmptyOptions }).promise;\n        const sampleRate = sessionReplay.config?.sampleRate;\n        expect(sampleRate).toBe(DEFAULT_SAMPLE_RATE);\n        const sessionRecordingProperties = sessionReplay.getSessionReplayProperties();\n        expect(sessionRecordingProperties).toMatchObject({});\n        expect(mockRecordFunction).not.toHaveBeenCalled();\n        await runScheduleTimers();\n        expect(fetch).not.toHaveBeenCalledWith(SESSION_REPLAY_SERVER_URL);\n      });\n      test('should not record session if sample rate of value 0 is provided', async () => {\n        const sessionReplay = new SessionReplay();\n        await sessionReplay.init(apiKey, { ...mockEmptyOptions, sampleRate: 0 }).promise;\n        const sampleRate = sessionReplay.config?.sampleRate;\n        expect(sampleRate).toBe(DEFAULT_SAMPLE_RATE);\n        const sessionRecordingProperties = sessionReplay.getSessionReplayProperties();\n        expect(sessionRecordingProperties).toMatchObject({});\n        expect(mockRecordFunction).not.toHaveBeenCalled();\n        await runScheduleTimers();\n        expect(fetch).not.toHaveBeenCalledWith(SESSION_REPLAY_SERVER_URL);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/integration.test.ts",
    "content": "/* eslint-disable @typescript-eslint/unbound-method */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\nimport * as AnalyticsCore from '@amplitude/analytics-core';\nimport { LogLevel, ILogger, ServerZone, RemoteConfig, Source } from '@amplitude/analytics-core';\nimport * as RRWeb from '@amplitude/rrweb-record';\nimport { IDBFactory } from 'fake-indexeddb';\nimport { EventType, SessionReplayOptions } from 'src/typings/session-replay';\nimport { SESSION_REPLAY_EU_URL as SESSION_REPLAY_EU_SERVER_URL } from '../src/constants';\nimport * as SessionReplayIDB from '../src/events/events-idb-store';\nimport { UNEXPECTED_ERROR_MESSAGE } from '../src/messages';\nimport { SessionReplay } from '../src/session-replay';\n\njest.mock('idb-keyval');\ntype MockedLogger = jest.Mocked<ILogger>;\njest.mock('@amplitude/rrweb-record');\ntype MockedRRWeb = jest.Mocked<typeof import('@amplitude/rrweb-record')>;\n\n// Mock remote config client\nlet mockRemoteConfig: RemoteConfig | null = null;\nlet mockRemoteConfigClient: any;\n\nconst mockEvent = {\n  type: 4,\n  data: { href: 'https://analytics.amplitude.com/', width: 1728, height: 154 },\n  timestamp: 1687358660935,\n};\nconst mockEventString = JSON.stringify(mockEvent);\n\nasync function runScheduleTimers() {\n  // exhause first setTimeout\n  jest.runAllTimers();\n  // wait for next tick to call nested setTimeout\n  await Promise.resolve();\n  // exhause nested setTimeout\n  jest.runAllTimers();\n}\n\n// Helper function to initialize the mock remote config client\nconst initializeMockRemoteConfigClient = () => {\n  const subscribeImplementation = jest.fn((configKey: string, _subscriptionMode: string, callback: any) => {\n    // Filter the config by key, matching RemoteConfigClient.sendCallback behavior\n    let filteredConfig: RemoteConfig | null = mockRemoteConfig;\n    if (configKey && filteredConfig) {\n      filteredConfig = configKey.split('.').reduce((config: RemoteConfig | null, key: string) => {\n        if (config === null) {\n          return config;\n        }\n        return key in config ? (config[key] as RemoteConfig) : null;\n      }, filteredConfig as RemoteConfig | null);\n    }\n\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n    return callback(filteredConfig, 'initial' as Source, new Date());\n  });\n\n  mockRemoteConfigClient = {\n    subscribe: subscribeImplementation,\n  };\n\n  // Mock RemoteConfigClient constructor using jest.spyOn\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n  jest.spyOn(AnalyticsCore, 'RemoteConfigClient').mockImplementation(() => mockRemoteConfigClient);\n};\n\ndescribe('module level integration', () => {\n  const { record } = RRWeb as MockedRRWeb;\n  const addEventListenerMock = jest.fn() as jest.Mock<typeof window.addEventListener>;\n  const removeEventListenerMock = jest.fn() as jest.Mock<typeof window.removeEventListener>;\n  const mockGlobalScope = {\n    addEventListener: addEventListenerMock,\n    removeEventListener: removeEventListenerMock,\n    document: {\n      hasFocus: () => true,\n    },\n    indexedDB: new IDBFactory(),\n  } as unknown as typeof globalThis;\n  let originalFetch: typeof global.fetch;\n  const mockLoggerProvider: MockedLogger = {\n    error: jest.fn(),\n    log: jest.fn(),\n    disable: jest.fn(),\n    enable: jest.fn(),\n    warn: jest.fn(),\n    debug: jest.fn(),\n  };\n  const apiKey = 'static_key';\n  const mockOptions: SessionReplayOptions = {\n    flushIntervalMillis: 0,\n    flushMaxRetries: 1,\n    flushQueueSize: 0,\n    logLevel: LogLevel.None,\n    loggerProvider: mockLoggerProvider,\n    deviceId: '1a2b3c',\n    optOut: false,\n    sampleRate: 1,\n    sessionId: 123,\n    serverZone: ServerZone.EU,\n    storeType: 'idb',\n  };\n  beforeEach(() => {\n    // Initialize mockRemoteConfig with null (no remote config by default for these tests)\n    mockRemoteConfig = null;\n\n    // Initialize the mock remote config client\n    initializeMockRemoteConfigClient();\n\n    jest.spyOn(SessionReplayIDB.SessionReplayEventsIDBStore, 'new');\n    jest.useFakeTimers();\n    originalFetch = global.fetch;\n    global.fetch = jest.fn(() =>\n      Promise.resolve({\n        status: 200,\n      }),\n    ) as jest.Mock;\n    jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue(mockGlobalScope);\n  });\n  afterEach(() => {\n    jest.resetAllMocks();\n    jest.spyOn(global.Math, 'random').mockRestore();\n    global.fetch = originalFetch;\n    jest.useRealTimers();\n  });\n\n  describe('with optOut in config', () => {\n    test('should not record session if excluded due to optOut', async () => {\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, { ...mockOptions, optOut: true }).promise;\n      expect(record).not.toHaveBeenCalled();\n      await runScheduleTimers();\n      expect(fetch).not.toHaveBeenCalledWith(SESSION_REPLAY_EU_SERVER_URL);\n    });\n  });\n  describe('without a session id', () => {\n    test('should not record session if no session id', async () => {\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, { ...mockOptions, sessionId: undefined }).promise;\n      expect(record).not.toHaveBeenCalled();\n      await runScheduleTimers();\n      expect(fetch).not.toHaveBeenCalledWith(SESSION_REPLAY_EU_SERVER_URL);\n    });\n  });\n  describe('tracking replay events', () => {\n    test('should handle unknown event type', async () => {\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, { ...mockOptions }).promise;\n      const createEventsIDBStoreInstance = await (SessionReplayIDB.SessionReplayEventsIDBStore.new as jest.Mock).mock\n        .results[0].value;\n      jest.spyOn(createEventsIDBStoreInstance, 'storeCurrentSequence');\n      (fetch as jest.Mock).mockImplementationOnce(() => Promise.reject('API Failure'));\n      if (!sessionReplay.eventsManager) {\n        throw new Error('did not init');\n      }\n      sessionReplay.eventsManager.addEvent({\n        sessionId: 123,\n        event: { type: 'unknown' as EventType, data: mockEventString },\n        deviceId: '1a2b3c',\n      });\n      sessionReplay.sendEvents();\n      await (createEventsIDBStoreInstance.storeCurrentSequence as jest.Mock).mock.results[0].value;\n      await runScheduleTimers();\n      expect(fetch).not.toHaveBeenCalled();\n    });\n    test('should handle unexpected error', async () => {\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, { ...mockOptions }).promise;\n      const createEventsIDBStoreInstance = await (SessionReplayIDB.SessionReplayEventsIDBStore.new as jest.Mock).mock\n        .results[0].value;\n      jest.spyOn(createEventsIDBStoreInstance, 'storeCurrentSequence');\n      (fetch as jest.Mock).mockImplementationOnce(() => Promise.reject('API Failure'));\n      if (!sessionReplay.eventsManager) {\n        throw new Error('did not init');\n      }\n      sessionReplay.eventsManager.addEvent({\n        sessionId: 123,\n        event: { type: 'replay', data: mockEventString },\n        deviceId: '1a2b3c',\n      });\n      sessionReplay.sendEvents();\n      await (createEventsIDBStoreInstance.storeCurrentSequence as jest.Mock).mock.results[0].value;\n      await runScheduleTimers();\n      expect(fetch).toHaveBeenLastCalledWith(\n        `${SESSION_REPLAY_EU_SERVER_URL}?device_id=1a2b3c&session_id=123&type=replay`,\n        expect.anything(),\n      );\n      expect(mockLoggerProvider.warn).toHaveBeenCalledWith('API Failure');\n    });\n    test('should not retry for 400 error', async () => {\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, { ...mockOptions, flushMaxRetries: 2 }).promise;\n      const createEventsIDBStoreInstance = await (SessionReplayIDB.SessionReplayEventsIDBStore.new as jest.Mock).mock\n        .results[0].value;\n      jest.spyOn(createEventsIDBStoreInstance, 'storeCurrentSequence');\n      (fetch as jest.Mock)\n        .mockImplementationOnce(() => {\n          return Promise.resolve({\n            status: 400,\n          });\n        })\n        .mockImplementationOnce(() => {\n          return Promise.resolve({\n            status: 200,\n          });\n        });\n      // Log is called from init, but that's not what we're testing here\n      mockLoggerProvider.log.mockClear();\n      if (!sessionReplay.eventsManager) {\n        throw new Error('did not init');\n      }\n      sessionReplay.eventsManager.addEvent({\n        sessionId: 123,\n        event: { type: 'replay', data: mockEventString },\n        deviceId: '1a2b3c',\n      });\n      sessionReplay.sendEvents();\n      await (createEventsIDBStoreInstance.storeCurrentSequence as jest.Mock).mock.results[0].value;\n      await runScheduleTimers();\n      expect(fetch).toHaveBeenLastCalledWith(\n        `${SESSION_REPLAY_EU_SERVER_URL}?device_id=1a2b3c&session_id=123&type=replay`,\n        expect.anything(),\n      );\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLoggerProvider.warn).toHaveBeenCalledWith('Network error occurred, event batch rejected');\n    });\n    test('should drop single-event batch on 413 with a warning (cannot split further)', async () => {\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, { ...mockOptions, flushMaxRetries: 2 }).promise;\n      const createEventsIDBStoreInstance = await (SessionReplayIDB.SessionReplayEventsIDBStore.new as jest.Mock).mock\n        .results[0].value;\n      jest.spyOn(createEventsIDBStoreInstance, 'storeCurrentSequence');\n      (fetch as jest.Mock).mockImplementationOnce(() => {\n        return Promise.resolve({\n          status: 413,\n          text: () => Promise.resolve(''),\n        });\n      });\n\n      if (!sessionReplay.eventsManager) {\n        throw new Error('did not init');\n      }\n      sessionReplay.eventsManager.addEvent({\n        sessionId: 123,\n        event: { type: 'replay', data: mockEventString },\n        deviceId: '1a2b3c',\n      });\n      sessionReplay.sendEvents();\n      await (createEventsIDBStoreInstance.storeCurrentSequence as jest.Mock).mock.results[0].value;\n      await runScheduleTimers();\n      expect(fetch).toHaveBeenCalledTimes(1);\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLoggerProvider.warn).toHaveBeenCalledWith(expect.stringContaining('not retrying non-WAF 413'));\n    });\n    test('should handle retry for 500 error', async () => {\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, { ...mockOptions, flushMaxRetries: 2 }).promise;\n      const createEventsIDBStoreInstance = await (SessionReplayIDB.SessionReplayEventsIDBStore.new as jest.Mock).mock\n        .results[0].value;\n      jest.spyOn(createEventsIDBStoreInstance, 'storeCurrentSequence');\n      (fetch as jest.Mock).mockReset();\n      (fetch as jest.Mock)\n        .mockImplementationOnce(() => {\n          return Promise.resolve({\n            status: 500,\n          });\n        })\n        .mockImplementationOnce(() => {\n          return Promise.resolve({\n            status: 200,\n          });\n        });\n\n      if (!sessionReplay.eventsManager) {\n        throw new Error('did not init');\n      }\n      sessionReplay.eventsManager.addEvent({\n        sessionId: 123,\n        event: { type: 'replay', data: mockEventString },\n        deviceId: '1a2b3c',\n      });\n      sessionReplay.sendEvents();\n      await (createEventsIDBStoreInstance.storeCurrentSequence as jest.Mock).mock.results[0].value;\n      await runScheduleTimers();\n      expect(fetch).toHaveBeenCalledTimes(2);\n    });\n\n    test('should only retry once for 500 error, even if config set to higher than one retry', async () => {\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, { ...mockOptions, flushMaxRetries: 10 }).promise;\n      const createEventsIDBStoreInstance = await (SessionReplayIDB.SessionReplayEventsIDBStore.new as jest.Mock).mock\n        .results[0].value;\n      jest.spyOn(createEventsIDBStoreInstance, 'storeCurrentSequence');\n      (fetch as jest.Mock).mockReset();\n      (fetch as jest.Mock)\n        .mockImplementationOnce(() => {\n          return Promise.resolve({\n            status: 500,\n          });\n        })\n        .mockImplementationOnce(() => {\n          return Promise.resolve({\n            status: 500,\n          });\n        });\n\n      if (!sessionReplay.eventsManager) {\n        throw new Error('did not init');\n      }\n      sessionReplay.eventsManager.addEvent({\n        sessionId: 123,\n        event: { type: 'replay', data: mockEventString },\n        deviceId: '1a2b3c',\n      });\n      sessionReplay.sendEvents();\n      await (createEventsIDBStoreInstance.storeCurrentSequence as jest.Mock).mock.results[0].value;\n      await runScheduleTimers();\n      expect(fetch).toHaveBeenCalledTimes(2);\n    });\n    test('should handle retry for 503 error', async () => {\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, { ...mockOptions, flushMaxRetries: 2 }).promise;\n      const createEventsIDBStoreInstance = await (SessionReplayIDB.SessionReplayEventsIDBStore.new as jest.Mock).mock\n        .results[0].value;\n      jest.spyOn(createEventsIDBStoreInstance, 'storeCurrentSequence');\n      (fetch as jest.Mock).mockReset();\n      (fetch as jest.Mock)\n        .mockImplementationOnce(() => {\n          return Promise.resolve({\n            status: 503,\n          });\n        })\n        .mockImplementationOnce(() => {\n          return Promise.resolve({\n            status: 200,\n          });\n        });\n\n      if (!sessionReplay.eventsManager) {\n        throw new Error('did not init');\n      }\n      sessionReplay.eventsManager.addEvent({\n        sessionId: 123,\n        event: { type: 'replay', data: mockEventString },\n        deviceId: '1a2b3c',\n      });\n      sessionReplay.sendEvents();\n      await (createEventsIDBStoreInstance.storeCurrentSequence as jest.Mock).mock.results[0].value;\n      await runScheduleTimers();\n      expect(fetch).toHaveBeenCalledTimes(2);\n    });\n    describe('server back-pressure (X-Session-Replay-Event-Skipped header)', () => {\n      const mockSkippedResponse = (skipCode: string | null) => ({\n        status: 200,\n        headers: { get: jest.fn().mockReturnValue(skipCode) },\n      });\n\n      test('hard-kill (4005): subsequent flushes for the same session do not POST', async () => {\n        const sessionReplay = new SessionReplay();\n        await sessionReplay.init(apiKey, { ...mockOptions, flushMaxRetries: 2 }).promise;\n        const idbInstance = await (SessionReplayIDB.SessionReplayEventsIDBStore.new as jest.Mock).mock.results[0].value;\n        jest.spyOn(idbInstance, 'storeCurrentSequence');\n        (fetch as jest.Mock).mockReset();\n        (fetch as jest.Mock).mockResolvedValueOnce(mockSkippedResponse('4005'));\n\n        if (!sessionReplay.eventsManager) throw new Error('did not init');\n\n        // First batch: server replies 200 + 4005 → kill switch fires for session 123.\n        sessionReplay.eventsManager.addEvent({\n          sessionId: 123,\n          event: { type: 'replay', data: mockEventString },\n          deviceId: '1a2b3c',\n        });\n        sessionReplay.sendEvents();\n        await (idbInstance.storeCurrentSequence as jest.Mock).mock.results[0].value;\n        await runScheduleTimers();\n        expect(fetch).toHaveBeenCalledTimes(1);\n\n        // Second batch for the same killed session — must not produce another POST.\n        sessionReplay.eventsManager.addEvent({\n          sessionId: 123,\n          event: { type: 'replay', data: mockEventString },\n          deviceId: '1a2b3c',\n        });\n        sessionReplay.sendEvents();\n        await runScheduleTimers();\n        expect(fetch).toHaveBeenCalledTimes(1);\n      });\n\n      test('hard-kill (4004 session_in_invalid_range): subsequent flushes for the same session do not POST', async () => {\n        const sessionReplay = new SessionReplay();\n        await sessionReplay.init(apiKey, { ...mockOptions, flushMaxRetries: 2 }).promise;\n        const idbInstance = await (SessionReplayIDB.SessionReplayEventsIDBStore.new as jest.Mock).mock.results[0].value;\n        jest.spyOn(idbInstance, 'storeCurrentSequence');\n        (fetch as jest.Mock).mockReset();\n        (fetch as jest.Mock).mockResolvedValueOnce(mockSkippedResponse('4004'));\n\n        if (!sessionReplay.eventsManager) throw new Error('did not init');\n        sessionReplay.eventsManager.addEvent({\n          sessionId: 123,\n          event: { type: 'replay', data: mockEventString },\n          deviceId: '1a2b3c',\n        });\n        sessionReplay.sendEvents();\n        await (idbInstance.storeCurrentSequence as jest.Mock).mock.results[0].value;\n        await runScheduleTimers();\n        expect(fetch).toHaveBeenCalledTimes(1);\n\n        sessionReplay.eventsManager.addEvent({\n          sessionId: 123,\n          event: { type: 'replay', data: mockEventString },\n          deviceId: '1a2b3c',\n        });\n        sessionReplay.sendEvents();\n        await runScheduleTimers();\n        expect(fetch).toHaveBeenCalledTimes(1);\n      });\n    });\n\n    test('should handle unexpected error where fetch response is null', async () => {\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, { ...mockOptions, flushMaxRetries: 2 }).promise;\n      const createEventsIDBStoreInstance = await (SessionReplayIDB.SessionReplayEventsIDBStore.new as jest.Mock).mock\n        .results[0].value;\n      jest.spyOn(createEventsIDBStoreInstance, 'storeCurrentSequence');\n      (fetch as jest.Mock).mockImplementationOnce(() => {\n        return Promise.resolve(null);\n      });\n\n      if (!sessionReplay.eventsManager) {\n        throw new Error('did not init');\n      }\n      sessionReplay.eventsManager.addEvent({\n        sessionId: 123,\n        event: { type: 'replay', data: mockEventString },\n        deviceId: '1a2b3c',\n      });\n      sessionReplay.sendEvents();\n      await (createEventsIDBStoreInstance.storeCurrentSequence as jest.Mock).mock.results[0].value;\n      await runScheduleTimers();\n      expect(fetch).toHaveBeenLastCalledWith(\n        `${SESSION_REPLAY_EU_SERVER_URL}?device_id=1a2b3c&session_id=123&type=replay`,\n        expect.anything(),\n      );\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLoggerProvider.warn).toHaveBeenCalledWith(UNEXPECTED_ERROR_MESSAGE);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/jest-setup.js",
    "content": "require('fake-indexeddb/auto');\nconst { IDBFactory } = require('fake-indexeddb');\nconst structuredClone = require('@ungap/structured-clone');\nconst { TextEncoder, TextDecoder } = require('util');\n\nglobal.structuredClone = structuredClone.default;\nglobal.TextEncoder = TextEncoder;\nglobal.TextDecoder = TextDecoder;\n\n// jsdom 20 does not implement crypto.randomUUID — polyfill with Node's implementation.\nif (!globalThis.crypto?.randomUUID) {\n  Object.defineProperty(globalThis, 'crypto', {\n    value: { ...globalThis.crypto, randomUUID: () => require('crypto').randomUUID() },\n    writable: true,\n  });\n}\n\nglobal.beforeEach(() => {\n  global.indexedDB = new IDBFactory();\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/logger.test.ts",
    "content": "import { ILogger, LogLevel } from '@amplitude/analytics-core';\nimport { SafeLoggerProvider } from '../src/logger';\n\ndescribe('SafeLoggerProvider', () => {\n  let mockLogger: jest.Mocked<ILogger>;\n  let logSpy: jest.SpyInstance;\n  let warnSpy: jest.SpyInstance;\n  let errorSpy: jest.SpyInstance;\n  let debugSpy: jest.SpyInstance;\n  let enableSpy: jest.SpyInstance;\n  let disableSpy: jest.SpyInstance;\n\n  beforeEach(() => {\n    mockLogger = {\n      log: jest.fn(),\n      warn: jest.fn(),\n      error: jest.fn(),\n      debug: jest.fn(),\n      enable: jest.fn(),\n      disable: jest.fn(),\n    };\n\n    logSpy = jest.spyOn(mockLogger, 'log');\n    warnSpy = jest.spyOn(mockLogger, 'warn');\n    errorSpy = jest.spyOn(mockLogger, 'error');\n    debugSpy = jest.spyOn(mockLogger, 'debug');\n    enableSpy = jest.spyOn(mockLogger, 'enable');\n    disableSpy = jest.spyOn(mockLogger, 'disable');\n  });\n\n  test('calls original console methods when they exist', () => {\n    const safeLogger = new SafeLoggerProvider(mockLogger);\n\n    safeLogger.log('test log');\n    expect(logSpy).toHaveBeenCalledWith('test log');\n\n    safeLogger.warn('test warn');\n    expect(warnSpy).toHaveBeenCalledWith('test warn');\n\n    safeLogger.error('test error');\n    expect(errorSpy).toHaveBeenCalledWith('test error');\n\n    safeLogger.debug('test debug');\n    expect(debugSpy).toHaveBeenCalledWith('test debug');\n  });\n\n  test('calls original console methods if they use rrweb’s __rrweb_original__ method', () => {\n    const originalLog = jest.fn();\n    mockLogger.log = jest.fn();\n    (mockLogger.log as unknown as { __rrweb_original__: typeof originalLog }).__rrweb_original__ = originalLog;\n\n    const safeLogger = new SafeLoggerProvider(mockLogger);\n    safeLogger.log('test rrweb log');\n\n    expect(originalLog).toHaveBeenCalledWith('test rrweb log');\n    expect(logSpy).not.toHaveBeenCalled();\n  });\n\n  test('falls back to no-op when logger is null', () => {\n    // @ts-expect-error For testing, pass null\n    const safeLogger = new SafeLoggerProvider(null);\n\n    expect(() => safeLogger.log('test log')).not.toThrow();\n    expect(() => safeLogger.warn('test warn')).not.toThrow();\n    expect(() => safeLogger.error('test error')).not.toThrow();\n    expect(() => safeLogger.debug('test debug')).not.toThrow();\n  });\n\n  test('falls back to no-op when the logger’s methods are not functions', () => {\n    mockLogger.log = 'not a function' as unknown as jest.Mock;\n    mockLogger.warn = undefined as unknown as jest.Mock;\n    mockLogger.error = null as unknown as jest.Mock;\n    mockLogger.debug = jest.fn();\n\n    const safeLogger = new SafeLoggerProvider(mockLogger);\n\n    safeLogger.log('test log');\n    safeLogger.warn('test warn');\n    safeLogger.error('test error');\n    safeLogger.debug('test debug');\n\n    expect(() => safeLogger.log('test log')).not.toThrow();\n    expect(() => safeLogger.warn('test warn')).not.toThrow();\n    expect(() => safeLogger.error('test error')).not.toThrow();\n    expect(() => safeLogger.debug('test debug')).not.toThrow();\n  });\n\n  test('enable(logLevel) calls logger.enable(logLevel)', () => {\n    const safeLogger = new SafeLoggerProvider(mockLogger);\n    jest.spyOn(mockLogger, 'enable');\n\n    safeLogger.enable(LogLevel.Warn);\n    expect(enableSpy).toHaveBeenCalledWith(LogLevel.Warn);\n  });\n\n  test('disable() calls logger.disable()', () => {\n    const safeLogger = new SafeLoggerProvider(mockLogger);\n    jest.spyOn(mockLogger, 'disable');\n\n    safeLogger.disable();\n    expect(disableSpy).toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/merge-mutation-events.test.ts",
    "content": "import { EventType, IncrementalSource } from '@amplitude/rrweb-types';\nimport type { eventWithTime, mutationData, scrollData } from '@amplitude/rrweb-types';\nimport { mergeMutationEvents } from '../src/events/merge-mutation-events';\n\nfunction makeMutation(timestamp: number, overrides: Partial<mutationData> = {}): eventWithTime {\n  return {\n    type: EventType.IncrementalSnapshot,\n    timestamp,\n    data: {\n      source: IncrementalSource.Mutation,\n      texts: [],\n      attributes: [],\n      removes: [],\n      adds: [],\n      ...overrides,\n    } as mutationData,\n  };\n}\n\nfunction makeScroll(timestamp: number): eventWithTime {\n  return {\n    type: EventType.IncrementalSnapshot,\n    timestamp,\n    data: { source: IncrementalSource.Scroll, id: 1, x: 0, y: 100 } as scrollData,\n  };\n}\n\nfunction makeFullSnapshot(timestamp: number): eventWithTime {\n  return {\n    type: EventType.FullSnapshot,\n    timestamp,\n    data: { node: {} as any, initialOffset: { top: 0, left: 0 } },\n  };\n}\n\ndescribe('mergeMutationEvents', () => {\n  test('returns single-element array unchanged', () => {\n    const event = makeMutation(1000);\n    expect(mergeMutationEvents([event])).toEqual([event]);\n  });\n\n  test('merges two consecutive mutations into one', () => {\n    const e1 = makeMutation(1000, {\n      adds: [{ parentId: 1, nextId: null, node: { id: 10 } as any }],\n      removes: [{ parentId: 1, id: 5 }],\n      texts: [{ id: 2, value: 'hello' }],\n      attributes: [{ id: 3, attributes: { class: 'foo' } }],\n    });\n    const e2 = makeMutation(1050, {\n      adds: [{ parentId: 10, nextId: null, node: { id: 11 } as any }],\n      removes: [{ parentId: 1, id: 6 }],\n      texts: [{ id: 4, value: 'world' }],\n      attributes: [{ id: 7, attributes: { class: 'bar' } }],\n    });\n\n    const result = mergeMutationEvents([e1, e2]);\n\n    expect(result).toHaveLength(1);\n    const data = result[0].data as mutationData;\n    // Removes from both events, in order\n    expect(data.removes).toEqual([\n      { parentId: 1, id: 5 },\n      { parentId: 1, id: 6 },\n    ]);\n    // Adds from both events, in order\n    expect(data.adds).toEqual([(e1.data as mutationData).adds[0], (e2.data as mutationData).adds[0]]);\n    // Texts concatenated\n    expect(data.texts).toEqual([\n      { id: 2, value: 'hello' },\n      { id: 4, value: 'world' },\n    ]);\n    // Attributes concatenated (replayer applies last-write-wins)\n    expect(data.attributes).toEqual([\n      { id: 3, attributes: { class: 'foo' } },\n      { id: 7, attributes: { class: 'bar' } },\n    ]);\n    // Timestamp from first event\n    expect(result[0].timestamp).toBe(1000);\n  });\n\n  test('merges three consecutive mutations into one', () => {\n    const events = [makeMutation(1000), makeMutation(1010), makeMutation(1020)];\n    const result = mergeMutationEvents(events);\n    expect(result).toHaveLength(1);\n  });\n\n  test('does not merge mutations separated by a non-mutation event', () => {\n    const e1 = makeMutation(1000);\n    const scroll = makeScroll(1010);\n    const e2 = makeMutation(1020);\n\n    const result = mergeMutationEvents([e1, scroll, e2]);\n\n    expect(result).toHaveLength(3);\n    expect(result[0]).toBe(e1);\n    expect(result[1]).toBe(scroll);\n    expect(result[2]).toBe(e2);\n  });\n\n  test('does not merge mutations separated by a FullSnapshot event', () => {\n    const e1 = makeMutation(1000);\n    const full = makeFullSnapshot(1010);\n    const e2 = makeMutation(1020);\n\n    const result = mergeMutationEvents([e1, full, e2]);\n\n    expect(result).toHaveLength(3);\n    expect(result[0]).toBe(e1);\n    expect(result[1]).toBe(full);\n    expect(result[2]).toBe(e2);\n  });\n\n  test('passes non-mutation IncrementalSnapshot events through unchanged', () => {\n    const scroll = makeScroll(1000);\n    const result = mergeMutationEvents([scroll]);\n    expect(result).toEqual([scroll]);\n  });\n\n  test('passes FullSnapshot events through unchanged', () => {\n    const full = makeFullSnapshot(1000);\n    const result = mergeMutationEvents([full]);\n    expect(result).toEqual([full]);\n  });\n\n  test('does not merge isAttachIframe mutations', () => {\n    const e1 = makeMutation(1000, { isAttachIframe: true });\n    const e2 = makeMutation(1010, { isAttachIframe: true });\n\n    const result = mergeMutationEvents([e1, e2]);\n\n    expect(result).toHaveLength(2);\n    expect(result[0]).toBe(e1);\n    expect(result[1]).toBe(e2);\n  });\n\n  test('does not merge a normal mutation with an isAttachIframe mutation', () => {\n    const normal = makeMutation(1000);\n    const iframe = makeMutation(1010, { isAttachIframe: true });\n\n    const result = mergeMutationEvents([normal, iframe]);\n\n    expect(result).toHaveLength(2);\n  });\n\n  test('merges runs correctly in a mixed sequence', () => {\n    const m1 = makeMutation(1000);\n    const m2 = makeMutation(1010);\n    const scroll = makeScroll(1020);\n    const m3 = makeMutation(1030);\n    const m4 = makeMutation(1040);\n    const m5 = makeMutation(1050);\n\n    const result = mergeMutationEvents([m1, m2, scroll, m3, m4, m5]);\n\n    expect(result).toHaveLength(3);\n    expect(result[0].timestamp).toBe(1000); // merged m1+m2\n    expect(result[1]).toBe(scroll);\n    expect(result[2].timestamp).toBe(1030); // merged m3+m4+m5\n  });\n\n  test('empty array returns empty array', () => {\n    expect(mergeMutationEvents([])).toEqual([]);\n  });\n\n  describe('transient node elision', () => {\n    test('elides a node added then removed in the same merge window', () => {\n      const e1 = makeMutation(1000, {\n        adds: [{ parentId: 1, nextId: null, node: { id: 10 } as any }],\n      });\n      const e2 = makeMutation(1010, {\n        removes: [{ parentId: 1, id: 10 }],\n      });\n\n      const result = mergeMutationEvents([e1, e2]);\n\n      expect(result).toHaveLength(1);\n      const data = result[0].data as mutationData;\n      expect(data.adds).toHaveLength(0);\n      expect(data.removes).toHaveLength(0);\n    });\n\n    test('keeps removes for pre-existing nodes not in the adds set', () => {\n      const e1 = makeMutation(1000, {\n        removes: [{ parentId: 1, id: 99 }], // pre-existing node\n      });\n      const e2 = makeMutation(1010, {\n        adds: [{ parentId: 1, nextId: null, node: { id: 10 } as any }],\n      });\n\n      const result = mergeMutationEvents([e1, e2]);\n\n      const data = result[0].data as mutationData;\n      expect(data.removes).toEqual([{ parentId: 1, id: 99 }]);\n      expect(data.adds).toHaveLength(1);\n    });\n\n    test('cascades elision to children of a transient parent', () => {\n      const e1 = makeMutation(1000, {\n        adds: [\n          { parentId: 1, nextId: null, node: { id: 10 } as any }, // parent\n          { parentId: 10, nextId: null, node: { id: 11 } as any }, // child of transient parent\n        ],\n      });\n      const e2 = makeMutation(1010, {\n        removes: [{ parentId: 1, id: 10 }], // removes the parent\n      });\n\n      const result = mergeMutationEvents([e1, e2]);\n\n      const data = result[0].data as mutationData;\n      expect(data.adds).toHaveLength(0); // parent and child both elided\n      expect(data.removes).toHaveLength(0);\n    });\n\n    test('does not elide a node removed then re-added (DOM move)', () => {\n      // remove in event1, re-add in event2 — this is a cross-event DOM move, not transient\n      const e1 = makeMutation(1000, {\n        removes: [{ parentId: 1, id: 10 }],\n      });\n      const e2 = makeMutation(1010, {\n        adds: [{ parentId: 2, nextId: null, node: { id: 10 } as any }],\n      });\n\n      const result = mergeMutationEvents([e1, e2]);\n\n      const data = result[0].data as mutationData;\n      expect(data.removes).toEqual([{ parentId: 1, id: 10 }]);\n      expect(data.adds).toHaveLength(1);\n      expect((data.adds[0].node as any).id).toBe(10);\n    });\n\n    test('does not elide a node added then moved (add-then-move)', () => {\n      // add in event1, move (remove+re-add to new parent) in event2 — node should survive at new parent\n      const e1 = makeMutation(1000, {\n        adds: [{ parentId: 1, nextId: null, node: { id: 10 } as any }],\n      });\n      const e2 = makeMutation(1010, {\n        removes: [{ parentId: 1, id: 10 }],\n        adds: [{ parentId: 2, nextId: null, node: { id: 10 } as any }],\n      });\n\n      const result = mergeMutationEvents([e1, e2]);\n\n      const data = result[0].data as mutationData;\n      // Node 10 should appear as a remove from parent 1 and add to parent 2\n      expect(data.removes.some((r) => r.id === 10)).toBe(true);\n      expect(data.adds.some((a) => (a.node as any).id === 10 && a.parentId === 2)).toBe(true);\n    });\n\n    test('filters texts for transient node IDs', () => {\n      const e1 = makeMutation(1000, {\n        adds: [{ parentId: 1, nextId: null, node: { id: 10 } as any }],\n        texts: [{ id: 10, value: 'hello' }],\n      });\n      const e2 = makeMutation(1010, {\n        removes: [{ parentId: 1, id: 10 }],\n      });\n\n      const result = mergeMutationEvents([e1, e2]);\n\n      const data = result[0].data as mutationData;\n      expect(data.adds).toHaveLength(0);\n      expect(data.removes).toHaveLength(0);\n      expect(data.texts).toHaveLength(0);\n    });\n\n    test('filters attributes for transient node IDs', () => {\n      const e1 = makeMutation(1000, {\n        adds: [{ parentId: 1, nextId: null, node: { id: 10 } as any }],\n        attributes: [{ id: 10, attributes: { class: 'foo' } }],\n      });\n      const e2 = makeMutation(1010, {\n        removes: [{ parentId: 1, id: 10 }],\n      });\n\n      const result = mergeMutationEvents([e1, e2]);\n\n      const data = result[0].data as mutationData;\n      expect(data.adds).toHaveLength(0);\n      expect(data.removes).toHaveLength(0);\n      expect(data.attributes).toHaveLength(0);\n    });\n\n    test('does not elide a child that was moved away from a transient parent', () => {\n      // Child C is added under transient parent P, then moved to non-transient parent Q.\n      // P is added then removed (transient). C ends up under Q and must survive.\n      const e1 = makeMutation(1000, {\n        adds: [\n          { parentId: 1, nextId: null, node: { id: 10 } as any }, // transient parent P\n          { parentId: 10, nextId: null, node: { id: 11 } as any }, // child C under P\n        ],\n      });\n      const e2 = makeMutation(1010, {\n        removes: [\n          { parentId: 1, id: 10 }, // remove P (transient)\n          { parentId: 10, id: 11 }, // move C away from P\n        ],\n        adds: [{ parentId: 2, nextId: null, node: { id: 11 } as any }], // C re-added under Q\n      });\n\n      const result = mergeMutationEvents([e1, e2]);\n\n      const data = result[0].data as mutationData;\n      // P (id=10) should be elided (add + remove cancelled)\n      expect(data.adds.some((a) => (a.node as any).id === 10)).toBe(false);\n      expect(data.removes.some((r) => r.id === 10)).toBe(false);\n      // C (id=11) should survive at its final parent Q (parentId=2)\n      expect(data.adds.some((a) => (a.node as any).id === 11 && a.parentId === 2)).toBe(true);\n    });\n\n    test('preserves same-event move followed by a later remove (does not misclassify as pre-existing transient)', () => {\n      // Node 10 is moved (remove+add in e1 — same event index) then removed in e2.\n      // firstAddIdx === firstRemoveIdx (both 0): must NOT be classified as pre-existing transient.\n      // All operations must survive so the move and final removal are both applied.\n      const e1 = makeMutation(1000, {\n        removes: [{ parentId: 1, id: 10 }],\n        adds: [{ parentId: 2, nextId: null, node: { id: 10 } as any }],\n      });\n      const e2 = makeMutation(1010, { removes: [{ parentId: 2, id: 10 }] });\n\n      const result = mergeMutationEvents([e1, e2]);\n\n      const data = result[0].data as mutationData;\n      // Both removes must survive (not erased by pre-existing-transient misclassification)\n      expect(data.removes.some((r) => r.id === 10 && r.parentId === 1)).toBe(true);\n      expect(data.removes.some((r) => r.id === 10 && r.parentId === 2)).toBe(true);\n      // The add (move destination) must survive\n      expect(data.adds.some((a) => (a.node as any).id === 10 && a.parentId === 2)).toBe(true);\n    });\n\n    test('cancels re-add and post-add remove for pre-existing node removed, re-added, and removed again', () => {\n      // Node 99 pre-exists: removed from parent1 in e1, re-added to parent2 in e2, removed from parent2 in e3.\n      // The rrweb replayer applies all removes first: both removes fire, then the add re-creates the node\n      // at parent2 — leaving it present when it should be absent.\n      // Fix: cancel the re-add and the post-add remove; keep only the original pre-add remove.\n      const e1 = makeMutation(1000, { removes: [{ parentId: 1, id: 99 }] });\n      const e2 = makeMutation(1010, { adds: [{ parentId: 2, nextId: null, node: { id: 99 } as any }] });\n      const e3 = makeMutation(1020, { removes: [{ parentId: 2, id: 99 }] });\n\n      const result = mergeMutationEvents([e1, e2, e3]);\n\n      const data = result[0].data as mutationData;\n      // Original remove (from parent1) must survive\n      expect(data.removes.some((r) => r.id === 99 && r.parentId === 1)).toBe(true);\n      // Re-add and post-add remove must be cancelled\n      expect(data.removes.some((r) => r.id === 99 && r.parentId === 2)).toBe(false);\n      expect(data.adds.some((a) => (a.node as any).id === 99)).toBe(false);\n    });\n\n    test('filters texts belonging to pre-existing-transient nodes', () => {\n      const e1 = makeMutation(1000, { removes: [{ parentId: 1, id: 99 }] });\n      const e2 = makeMutation(1010, {\n        adds: [{ parentId: 2, nextId: null, node: { id: 99 } as any }],\n        texts: [{ id: 99, value: 'during re-add' }],\n      });\n      const e3 = makeMutation(1020, { removes: [{ parentId: 2, id: 99 }] });\n\n      const result = mergeMutationEvents([e1, e2, e3]);\n\n      const data = result[0].data as mutationData;\n      expect(data.texts).toHaveLength(0);\n    });\n\n    test('filters attributes belonging to pre-existing-transient nodes', () => {\n      const e1 = makeMutation(1000, { removes: [{ parentId: 1, id: 99 }] });\n      const e2 = makeMutation(1010, {\n        adds: [{ parentId: 2, nextId: null, node: { id: 99 } as any }],\n        attributes: [{ id: 99, attributes: { class: 'during-readd' } }],\n      });\n      const e3 = makeMutation(1020, { removes: [{ parentId: 2, id: 99 }] });\n\n      const result = mergeMutationEvents([e1, e2, e3]);\n\n      const data = result[0].data as mutationData;\n      expect(data.attributes).toHaveLength(0);\n    });\n\n    test('cascades elision to children added under a pre-existing-transient re-add', () => {\n      // Node 99 pre-exists: removed in e1, re-added in e2 with a new child 100, removed in e3.\n      // The re-add of 99 is cancelled; child 100 (whose final parent is the cancelled re-add)\n      // is also elided.\n      const e1 = makeMutation(1000, { removes: [{ parentId: 1, id: 99 }] });\n      const e2 = makeMutation(1010, {\n        adds: [\n          { parentId: 1, nextId: null, node: { id: 99 } as any },\n          { parentId: 99, nextId: null, node: { id: 100 } as any },\n        ],\n      });\n      const e3 = makeMutation(1020, { removes: [{ parentId: 1, id: 99 }] });\n\n      const result = mergeMutationEvents([e1, e2, e3]);\n\n      const data = result[0].data as mutationData;\n      expect(data.removes.some((r) => r.id === 99 && r.parentId === 1)).toBe(true);\n      expect(data.adds.some((a) => (a.node as any).id === 99)).toBe(false);\n      expect(data.adds.some((a) => (a.node as any).id === 100)).toBe(false);\n    });\n\n    test('preserves same-event-moved pre-existing node remove when final parent is transient (cascadeDropAddsOnly)', () => {\n      // B (id=11) is pre-existing. In e0, B is same-event moved: removed from Q (parentId=5)\n      // and added to C (id=10) in the SAME rrweb event. C is a new node added to body in e0.\n      // In e1, C is removed — making C a pure transient.\n      // Cascade fires: B's lastParent C is transient. nodeFirstRemoveIdx(B) === nodeFirstAddIdx(B)\n      // (both 0) → cascadeDropAddsOnlyIds. B's add to C is dropped; B's remove from Q is kept.\n      const e0 = makeMutation(1000, {\n        adds: [\n          { parentId: 1, nextId: null, node: { id: 10 } as any }, // C: new node\n          { parentId: 10, nextId: null, node: { id: 11 } as any }, // B: same-event add to C\n        ],\n        removes: [{ parentId: 5, id: 11 }], // B: same-event remove from Q\n      });\n      const e1 = makeMutation(1010, {\n        removes: [{ parentId: 1, id: 10 }], // C removed → pure transient\n      });\n\n      const result = mergeMutationEvents([e0, e1]);\n      const data = result[0].data as mutationData;\n\n      // C (id=10) is pure transient — elided entirely\n      expect(data.adds.some((a) => (a.node as any).id === 10)).toBe(false);\n      expect(data.removes.some((r) => r.id === 10)).toBe(false);\n      // B (id=11): add to C must be dropped (C is cancelled)\n      expect(data.adds.some((a) => (a.node as any).id === 11)).toBe(false);\n      // B (id=11): remove from Q (parentId=5) must be preserved\n      expect(data.removes.some((r) => r.id === 11 && r.parentId === 5)).toBe(true);\n    });\n\n    test('filters texts and attributes for cascadeDropAddsOnly nodes', () => {\n      // B (id=11) is same-event moved to transient C (id=10).\n      // A text and attribute mutation on B during the re-add phase should be dropped.\n      const e0 = makeMutation(1000, {\n        adds: [\n          { parentId: 1, nextId: null, node: { id: 10 } as any },\n          { parentId: 10, nextId: null, node: { id: 11 } as any },\n        ],\n        removes: [{ parentId: 5, id: 11 }],\n        texts: [{ id: 11, value: 'during move' }],\n        attributes: [{ id: 11, attributes: { class: 'moved' } }],\n      });\n      const e1 = makeMutation(1010, { removes: [{ parentId: 1, id: 10 }] });\n\n      const result = mergeMutationEvents([e0, e1]);\n      const data = result[0].data as mutationData;\n\n      expect(data.texts).toHaveLength(0);\n      expect(data.attributes).toHaveLength(0);\n      expect(data.removes.some((r) => r.id === 11 && r.parentId === 5)).toBe(true);\n    });\n\n    test('drops remove from cancelled parent for cascadeDropAddsOnly node', () => {\n      // B (id=11) is same-event moved to C (id=10) in e0, then explicitly removed from C in e1,\n      // then C is removed in e2. Because the \"remove from C\" is from a cancelled parent (transient C),\n      // it should be dropped — keeping only the original remove from Q (parentId=5).\n      const e0 = makeMutation(1000, {\n        adds: [\n          { parentId: 1, nextId: null, node: { id: 10 } as any }, // C: new node\n          { parentId: 10, nextId: null, node: { id: 11 } as any }, // B: same-event add to C\n        ],\n        removes: [{ parentId: 5, id: 11 }], // B: same-event remove from Q\n      });\n      const e1 = makeMutation(1010, {\n        removes: [{ parentId: 10, id: 11 }], // B explicitly removed from C\n      });\n      const e2 = makeMutation(1020, {\n        removes: [{ parentId: 1, id: 10 }], // C removed → pure transient\n      });\n\n      const result = mergeMutationEvents([e0, e1, e2]);\n      const data = result[0].data as mutationData;\n\n      // C (id=10) is pure transient — elided\n      expect(data.adds.some((a) => (a.node as any).id === 10)).toBe(false);\n      expect(data.removes.some((r) => r.id === 10)).toBe(false);\n      // B (id=11): add to C and remove from C (cancelled parent) must both be dropped\n      expect(data.adds.some((a) => (a.node as any).id === 11)).toBe(false);\n      expect(data.removes.some((r) => r.id === 11 && r.parentId === 10)).toBe(false);\n      // B (id=11): original remove from Q must be preserved\n      expect(data.removes.some((r) => r.id === 11 && r.parentId === 5)).toBe(true);\n    });\n\n    test('preserves pre-existing child original remove when cascaded from a transient parent', () => {\n      // Node 10 is pure transient (added then removed within window).\n      // Node 11 pre-existed: removed from parent 5 in e1, then re-added under transient 10 in e2.\n      // Cascade classifies 11 as pre-existing transient (not pure transient) so its e1 remove is kept.\n      const e1 = makeMutation(1000, {\n        adds: [{ parentId: 1, nextId: null, node: { id: 10 } as any }], // 10: pure transient\n        removes: [{ parentId: 5, id: 11 }], // 11: removed from original parent\n      });\n      const e2 = makeMutation(1010, {\n        adds: [{ parentId: 10, nextId: null, node: { id: 11 } as any }], // 11: re-added under 10\n        removes: [{ parentId: 1, id: 10 }], // 10: removed\n      });\n\n      const result = mergeMutationEvents([e1, e2]);\n      const data = result[0].data as mutationData;\n\n      expect(data.adds.some((a) => (a.node as any).id === 10)).toBe(false); // 10 erased\n      expect(data.removes.some((r) => r.id === 10)).toBe(false); // 10 erased\n      expect(data.adds.some((a) => (a.node as any).id === 11)).toBe(false); // 11 re-add cancelled\n      expect(data.removes.some((r) => r.id === 11 && r.parentId === 5)).toBe(true); // 11 original remove kept\n    });\n\n    test('only elides the transient node, keeps non-transient adds and removes', () => {\n      const e1 = makeMutation(1000, {\n        adds: [\n          { parentId: 1, nextId: null, node: { id: 10 } as any }, // transient\n          { parentId: 1, nextId: null, node: { id: 20 } as any }, // stays\n        ],\n      });\n      const e2 = makeMutation(1010, {\n        removes: [\n          { parentId: 1, id: 10 }, // removes transient\n          { parentId: 1, id: 99 }, // removes pre-existing node\n        ],\n      });\n\n      const result = mergeMutationEvents([e1, e2]);\n\n      const data = result[0].data as mutationData;\n      expect(data.adds).toEqual([{ parentId: 1, nextId: null, node: { id: 20 } as any }]);\n      expect(data.removes).toEqual([{ parentId: 1, id: 99 }]);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/observers.test.ts",
    "content": "import { NetworkObservers, NetworkRequestEvent, NetworkConfig } from '../src/observers';\nimport * as AnalyticsCore from '@amplitude/analytics-core';\ntype PartialGlobal = Pick<typeof globalThis, 'fetch'>;\n\n// Test subclass to access protected methods\nclass TestNetworkObservers extends NetworkObservers {\n  public testNotifyEvent(event: NetworkRequestEvent) {\n    this.notifyEvent(event);\n  }\n}\n\ndescribe('NetworkObservers', () => {\n  let networkObservers: TestNetworkObservers;\n  let mockFetch: jest.Mock;\n  let events: NetworkRequestEvent[] = [];\n  let globalScope: PartialGlobal;\n\n  beforeEach(() => {\n    jest.useFakeTimers();\n    events = [];\n    mockFetch = jest.fn();\n    globalScope = { fetch: mockFetch };\n\n    jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue(globalScope as typeof globalThis);\n\n    networkObservers = new TestNetworkObservers();\n  });\n\n  afterEach(() => {\n    jest.useRealTimers();\n    jest.restoreAllMocks();\n  });\n\n  const callback = (event: NetworkRequestEvent) => {\n    events.push(event);\n  };\n\n  describe('successful requests', () => {\n    it('should track successful fetch requests with headers', async () => {\n      // Create a simple mock response\n      const mockResponse = {\n        status: 200,\n        headers: {\n          forEach: (callback: (value: string, key: string) => void) => {\n            callback('application/json', 'content-type');\n            callback('test-server', 'server');\n          },\n        },\n      };\n      mockFetch.mockResolvedValue(mockResponse);\n\n      networkObservers.start(callback);\n\n      const requestHeaders = {\n        'Content-Type': 'application/json',\n        Authorization: 'Bearer token123',\n      };\n\n      await globalScope.fetch('https://api.example.com/data', {\n        method: 'POST',\n        headers: requestHeaders,\n      });\n\n      expect(events).toHaveLength(1);\n      expect(events[0]).toMatchObject({\n        type: 'fetch',\n        method: 'POST',\n        url: 'https://api.example.com/data',\n        status: 200,\n        requestHeaders,\n        responseHeaders: {\n          'content-type': 'application/json',\n          server: 'test-server',\n        },\n      });\n      expect(events[0].duration).toBeGreaterThanOrEqual(0);\n    });\n\n    it('should track successful fetch requests without headers', async () => {\n      const mockResponse = {\n        status: 200,\n        headers: {\n          forEach: jest.fn(), // Mock function that does nothing\n        },\n      };\n      mockFetch.mockResolvedValue(mockResponse);\n\n      networkObservers.start(callback);\n\n      await globalScope.fetch('https://api.example.com/data');\n\n      expect(events).toHaveLength(1);\n      expect(events[0]).toMatchObject({\n        type: 'fetch',\n        method: 'GET',\n        url: 'https://api.example.com/data',\n        status: 200,\n        requestHeaders: undefined,\n        responseHeaders: {},\n      });\n      expect(events[0].duration).toBeGreaterThanOrEqual(0);\n    });\n  });\n\n  describe('failed requests', () => {\n    it('should track network errors', async () => {\n      const networkError = new TypeError('Failed to fetch');\n      mockFetch.mockRejectedValue(networkError);\n\n      networkObservers.start(callback);\n\n      await expect(globalScope.fetch('https://api.example.com/data')).rejects.toThrow('Failed to fetch');\n\n      expect(events).toHaveLength(1);\n      expect(events[0]).toMatchObject({\n        type: 'fetch',\n        method: 'GET',\n        url: 'https://api.example.com/data',\n        error: {\n          name: 'TypeError',\n          message: 'Failed to fetch',\n        },\n      });\n      expect(events[0].duration).toBeGreaterThanOrEqual(0);\n    });\n\n    it('should handle non-Error throws', async () => {\n      mockFetch.mockRejectedValue('string error');\n\n      networkObservers.start(callback);\n\n      await expect(globalScope.fetch('https://api.example.com/data')).rejects.toBe('string error');\n\n      expect(events).toHaveLength(1);\n      expect(events[0].error).toEqual({\n        name: 'UnknownError',\n        message: 'An unknown error occurred',\n      });\n    });\n  });\n\n  describe('request body capture', () => {\n    const networkConfig: NetworkConfig = { enabled: true, body: { request: true } };\n\n    it('should capture string request body', async () => {\n      const mockResponse = {\n        status: 200,\n        headers: { forEach: jest.fn() },\n      };\n      mockFetch.mockResolvedValue(mockResponse);\n      networkObservers.start(callback, networkConfig);\n\n      await globalScope.fetch('https://api.example.com/data', {\n        method: 'POST',\n        body: '{\"key\":\"value\"}',\n      });\n\n      expect(events[0].requestBody).toBe('{\"key\":\"value\"}');\n    });\n\n    it('should capture URLSearchParams request body', async () => {\n      const mockResponse = {\n        status: 200,\n        headers: { forEach: jest.fn() },\n      };\n      mockFetch.mockResolvedValue(mockResponse);\n      networkObservers.start(callback, networkConfig);\n\n      await globalScope.fetch('https://api.example.com/data', {\n        method: 'POST',\n        body: new URLSearchParams({ foo: 'bar', baz: 'qux' }),\n      });\n\n      expect(events[0].requestBody).toBe('foo=bar&baz=qux');\n    });\n\n    it('should capture FormData request body', async () => {\n      const mockResponse = {\n        status: 200,\n        headers: { forEach: jest.fn() },\n      };\n      mockFetch.mockResolvedValue(mockResponse);\n      networkObservers.start(callback, networkConfig);\n\n      const formData = new FormData();\n      formData.append('username', 'alice');\n      formData.append('password', 'secret');\n\n      await globalScope.fetch('https://api.example.com/data', {\n        method: 'POST',\n        body: formData,\n      });\n\n      expect(events[0].requestBody).toBe('username=alice&password=secret');\n    });\n\n    it('should skip binary request body types', async () => {\n      const mockResponse = {\n        status: 200,\n        headers: { forEach: jest.fn() },\n      };\n      mockFetch.mockResolvedValue(mockResponse);\n      networkObservers.start(callback, networkConfig);\n\n      await globalScope.fetch('https://api.example.com/data', {\n        method: 'POST',\n        body: new ArrayBuffer(8),\n      });\n\n      expect(events[0].requestBody).toBeUndefined();\n    });\n\n    it('should truncate request body exceeding maxBodySizeBytes', async () => {\n      const mockResponse = {\n        status: 200,\n        headers: { forEach: jest.fn() },\n      };\n      mockFetch.mockResolvedValue(mockResponse);\n      networkObservers.start(callback, { enabled: true, body: { request: true, maxBodySizeBytes: 5 } });\n\n      await globalScope.fetch('https://api.example.com/data', {\n        method: 'POST',\n        body: 'hello world',\n      });\n\n      expect(events[0].requestBody).toBe('hello');\n    });\n\n    it('should truncate request body at a character boundary for multi-byte content', async () => {\n      const mockResponse = {\n        status: 200,\n        headers: { forEach: jest.fn() },\n      };\n      mockFetch.mockResolvedValue(mockResponse);\n      // 🎉 is 4 UTF-8 bytes; with maxBodySizeBytes: 4, only the emoji should be kept\n      networkObservers.start(callback, { enabled: true, body: { request: true, maxBodySizeBytes: 4 } });\n\n      await globalScope.fetch('https://api.example.com/data', {\n        method: 'POST',\n        body: '🎉hello',\n      });\n\n      expect(events[0].requestBody).toBe('🎉');\n    });\n\n    it('should not produce a broken surrogate pair when truncation boundary falls mid-emoji', async () => {\n      const mockResponse = {\n        status: 200,\n        headers: { forEach: jest.fn() },\n      };\n      mockFetch.mockResolvedValue(mockResponse);\n      // 'a' (1 byte) + '🎉' (4 bytes) = 5 bytes; limit of 4 means binary search would land\n      // after the high surrogate of 🎉 (giving 1+3=4 bytes) without the surrogate fix.\n      networkObservers.start(callback, { enabled: true, body: { request: true, maxBodySizeBytes: 4 } });\n\n      await globalScope.fetch('https://api.example.com/data', {\n        method: 'POST',\n        body: 'a🎉',\n      });\n\n      expect(events[0].requestBody).toBe('a');\n    });\n\n    it('should not capture request body when body.request is false', async () => {\n      const mockResponse = {\n        status: 200,\n        headers: { forEach: jest.fn() },\n      };\n      mockFetch.mockResolvedValue(mockResponse);\n      networkObservers.start(callback, { enabled: true, body: { request: false } });\n\n      await globalScope.fetch('https://api.example.com/data', {\n        method: 'POST',\n        body: '{\"key\":\"value\"}',\n      });\n\n      expect(events[0].requestBody).toBeUndefined();\n    });\n\n    it('should not capture request body when body config is absent', async () => {\n      const mockResponse = {\n        status: 200,\n        headers: { forEach: jest.fn() },\n      };\n      mockFetch.mockResolvedValue(mockResponse);\n      networkObservers.start(callback);\n\n      await globalScope.fetch('https://api.example.com/data', {\n        method: 'POST',\n        body: '{\"key\":\"value\"}',\n      });\n\n      expect(events[0].requestBody).toBeUndefined();\n    });\n\n    it('should handle undefined init when request body capture is enabled', async () => {\n      const mockResponse = {\n        status: 200,\n        headers: { forEach: jest.fn() },\n      };\n      mockFetch.mockResolvedValue(mockResponse);\n      networkObservers.start(callback, networkConfig);\n\n      await globalScope.fetch('https://api.example.com/data');\n\n      expect(events[0].requestBody).toBeUndefined();\n    });\n\n    it('should handle null body when request body capture is enabled', async () => {\n      const mockResponse = {\n        status: 200,\n        headers: { forEach: jest.fn() },\n      };\n      mockFetch.mockResolvedValue(mockResponse);\n      networkObservers.start(callback, networkConfig);\n\n      await globalScope.fetch('https://api.example.com/data', { method: 'POST', body: null });\n\n      expect(events[0].requestBody).toBeUndefined();\n    });\n\n    it('should represent File entries in FormData as [File]', async () => {\n      const mockResponse = {\n        status: 200,\n        headers: { forEach: jest.fn() },\n      };\n      mockFetch.mockResolvedValue(mockResponse);\n      networkObservers.start(callback, networkConfig);\n\n      const formData = new FormData();\n      formData.append('name', 'alice');\n      formData.append('avatar', new File(['content'], 'avatar.png'));\n\n      await globalScope.fetch('https://api.example.com/data', { method: 'POST', body: formData });\n\n      expect(events[0].requestBody).toBe('name=alice&avatar=[File]');\n    });\n  });\n\n  describe('response body capture', () => {\n    it('should capture response body with status \"captured\"', async () => {\n      const mockClone = { text: jest.fn().mockResolvedValue('{\"result\":\"ok\"}') };\n      const mockResponse = {\n        status: 200,\n        headers: {\n          forEach: (cb: (value: string, key: string) => void) => {\n            cb('application/json', 'content-type');\n          },\n        },\n        clone: jest.fn().mockReturnValue(mockClone),\n      };\n      mockFetch.mockResolvedValue(mockResponse);\n      networkObservers.start(callback, { enabled: true, body: { response: true } });\n\n      await globalScope.fetch('https://api.example.com/data');\n\n      // Wait for the detached body-read promise to resolve\n      await Promise.resolve();\n\n      expect(events[0].responseBody).toBe('{\"result\":\"ok\"}');\n      expect(events[0].responseBodyStatus).toBe('captured');\n    });\n\n    it('should truncate response body exceeding maxBodySizeBytes', async () => {\n      const mockClone = { text: jest.fn().mockResolvedValue('hello world') };\n      const mockResponse = {\n        status: 200,\n        headers: {\n          forEach: (cb: (value: string, key: string) => void) => {\n            cb('text/plain', 'content-type');\n          },\n        },\n        clone: jest.fn().mockReturnValue(mockClone),\n      };\n      mockFetch.mockResolvedValue(mockResponse);\n      networkObservers.start(callback, { enabled: true, body: { response: true, maxBodySizeBytes: 5 } });\n\n      await globalScope.fetch('https://api.example.com/data');\n      await Promise.resolve();\n\n      expect(events[0].responseBody).toBe('hello');\n      expect(events[0].responseBodyStatus).toBe('truncated');\n    });\n\n    it('should not produce a broken surrogate pair when truncation boundary falls mid-emoji', async () => {\n      // 'a' (1 byte) + '🎉' (4 bytes) = 5 bytes; limit of 4 means binary search would land\n      // after the high surrogate of 🎉 (giving 1+3=4 bytes) without the surrogate fix.\n      const mockClone = { text: jest.fn().mockResolvedValue('a🎉') };\n      const mockResponse = {\n        status: 200,\n        headers: {\n          forEach: (cb: (value: string, key: string) => void) => {\n            cb('text/plain', 'content-type');\n          },\n        },\n        clone: jest.fn().mockReturnValue(mockClone),\n      };\n      mockFetch.mockResolvedValue(mockResponse);\n      networkObservers.start(callback, { enabled: true, body: { response: true, maxBodySizeBytes: 4 } });\n\n      await globalScope.fetch('https://api.example.com/data');\n      await Promise.resolve();\n\n      expect(events[0].responseBody).toBe('a');\n      expect(events[0].responseBodyStatus).toBe('truncated');\n    });\n\n    it('should truncate response body at a character boundary for multi-byte content', async () => {\n      // 🎉 is 4 UTF-8 bytes; with maxBodySizeBytes: 4, only the emoji should be kept\n      const mockClone = { text: jest.fn().mockResolvedValue('🎉hello') };\n      const mockResponse = {\n        status: 200,\n        headers: {\n          forEach: (cb: (value: string, key: string) => void) => {\n            cb('text/plain', 'content-type');\n          },\n        },\n        clone: jest.fn().mockReturnValue(mockClone),\n      };\n      mockFetch.mockResolvedValue(mockResponse);\n      networkObservers.start(callback, { enabled: true, body: { response: true, maxBodySizeBytes: 4 } });\n\n      await globalScope.fetch('https://api.example.com/data');\n      await Promise.resolve();\n\n      expect(events[0].responseBody).toBe('🎉');\n      expect(events[0].responseBodyStatus).toBe('truncated');\n    });\n\n    it('should set responseBodyStatus to \"skipped_binary\" for binary content types', async () => {\n      const mockResponse = {\n        status: 200,\n        headers: {\n          forEach: (cb: (value: string, key: string) => void) => {\n            cb('image/png', 'content-type');\n          },\n        },\n        clone: jest.fn(),\n      };\n      mockFetch.mockResolvedValue(mockResponse);\n      networkObservers.start(callback, { enabled: true, body: { response: true } });\n\n      await globalScope.fetch('https://api.example.com/image.png');\n\n      expect(events[0].responseBodyStatus).toBe('skipped_binary');\n      expect(events[0].responseBody).toBeUndefined();\n      expect(mockResponse.clone).not.toHaveBeenCalled();\n    });\n\n    it('should set responseBodyStatus to \"error\" when body read fails', async () => {\n      const mockClone = { text: jest.fn().mockRejectedValue(new Error('read error')) };\n      const mockResponse = {\n        status: 200,\n        headers: {\n          forEach: (cb: (value: string, key: string) => void) => {\n            cb('application/json', 'content-type');\n          },\n        },\n        clone: jest.fn().mockReturnValue(mockClone),\n      };\n      mockFetch.mockResolvedValue(mockResponse);\n      networkObservers.start(callback, { enabled: true, body: { response: true } });\n\n      await globalScope.fetch('https://api.example.com/data');\n      await Promise.resolve();\n\n      expect(events[0].responseBodyStatus).toBe('error');\n      expect(events[0].responseBody).toBeUndefined();\n    });\n\n    it('should not capture response body when body.response is false', async () => {\n      const mockResponse = {\n        status: 200,\n        headers: { forEach: jest.fn() },\n        clone: jest.fn(),\n      };\n      mockFetch.mockResolvedValue(mockResponse);\n      networkObservers.start(callback, { enabled: true, body: { response: false } });\n\n      await globalScope.fetch('https://api.example.com/data');\n\n      expect(events[0].responseBodyStatus).toBeUndefined();\n      expect(events[0].responseBody).toBeUndefined();\n      expect(mockResponse.clone).not.toHaveBeenCalled();\n    });\n\n    it('should capture response body when no content-type header present', async () => {\n      const mockClone = { text: jest.fn().mockResolvedValue('plain text') };\n      const mockResponse = {\n        status: 200,\n        headers: {\n          forEach: jest.fn(), // no content-type emitted\n        },\n        clone: jest.fn().mockReturnValue(mockClone),\n      };\n      mockFetch.mockResolvedValue(mockResponse);\n      networkObservers.start(callback, { enabled: true, body: { response: true } });\n\n      await globalScope.fetch('https://api.example.com/data');\n      await Promise.resolve();\n\n      expect(events[0].responseBody).toBe('plain text');\n      expect(events[0].responseBodyStatus).toBe('captured');\n    });\n\n    it('should not capture response body when body config is absent', async () => {\n      const mockResponse = {\n        status: 200,\n        headers: { forEach: jest.fn() },\n        clone: jest.fn(),\n      };\n      mockFetch.mockResolvedValue(mockResponse);\n      networkObservers.start(callback);\n\n      await globalScope.fetch('https://api.example.com/data');\n\n      expect(events[0].responseBodyStatus).toBeUndefined();\n      expect(events[0].responseBody).toBeUndefined();\n      expect(mockResponse.clone).not.toHaveBeenCalled();\n    });\n\n    it('should capture both request and response body when both enabled', async () => {\n      const mockClone = { text: jest.fn().mockResolvedValue('response text') };\n      const mockResponse = {\n        status: 200,\n        headers: {\n          forEach: (cb: (value: string, key: string) => void) => {\n            cb('text/plain', 'content-type');\n          },\n        },\n        clone: jest.fn().mockReturnValue(mockClone),\n      };\n      mockFetch.mockResolvedValue(mockResponse);\n      networkObservers.start(callback, { enabled: true, body: { request: true, response: true } });\n\n      await globalScope.fetch('https://api.example.com/data', {\n        method: 'POST',\n        body: 'request text',\n      });\n      await Promise.resolve();\n\n      expect(events[0].requestBody).toBe('request text');\n      expect(events[0].responseBody).toBe('response text');\n      expect(events[0].responseBodyStatus).toBe('captured');\n    });\n  });\n\n  describe('observer lifecycle', () => {\n    it('should stop tracking when stopped', async () => {\n      networkObservers.start(callback);\n      networkObservers.stop();\n\n      expect(globalScope.fetch).toBe(mockFetch);\n\n      await mockFetch('https://api.example.com/data');\n      expect(events).toHaveLength(0);\n    });\n\n    it('should handle missing global scope', () => {\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue(undefined);\n\n      networkObservers.start(callback);\n\n      expect(() => networkObservers.stop()).not.toThrow();\n    });\n\n    it('should handle missing fetch', () => {\n      const scopeWithoutFetch = {} as typeof globalThis;\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue(scopeWithoutFetch);\n\n      networkObservers.start(callback);\n\n      expect(() => networkObservers.stop()).not.toThrow();\n    });\n\n    it('should call eventCallback with request event data', async () => {\n      const mockCallback = jest.fn();\n      const mockResponse = {\n        status: 200,\n        headers: {\n          forEach: (callback: (value: string, key: string) => void) => {\n            callback('application/json', 'content-type');\n          },\n        },\n      };\n      mockFetch.mockResolvedValue(mockResponse);\n\n      networkObservers.start(mockCallback);\n\n      await globalScope.fetch('https://api.example.com/data', {\n        method: 'POST',\n        headers: { 'Content-Type': 'application/json' },\n      });\n\n      expect(mockCallback).toHaveBeenCalledTimes(1);\n    });\n\n    it('should handle notifyEvent with optional chaining', async () => {\n      const mockEvent = {\n        timestamp: Date.now(),\n        type: 'fetch' as const,\n        method: 'GET',\n        url: 'https://api.example.com/data',\n      };\n\n      // Test with callback\n      const mockCallback = jest.fn();\n      networkObservers.start(mockCallback);\n      networkObservers.testNotifyEvent(mockEvent);\n      expect(mockCallback).toHaveBeenCalledWith(mockEvent);\n\n      // Test without callback\n      networkObservers.stop();\n      networkObservers.testNotifyEvent(mockEvent);\n      expect(mockCallback).toHaveBeenCalledTimes(1); // Still only called once\n    });\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/replay-start-time-store.test.ts",
    "content": "import {\n  getOrInitReplayStartTime,\n  pruneStaleReplayStartTimes,\n  REPLAY_START_TIME_TTL_MS,\n  removeReplayStartTime,\n  setReplayStartTime,\n} from '../src/replay-start-time-store';\n\ndescribe('replay-start-time-store', () => {\n  const apiKey = 'test_api_key_12345';\n  const prefix = `AMP_SR_START_${apiKey.substring(0, 10)}_`;\n  const logger = {\n    log: jest.fn(),\n    debug: jest.fn(),\n    warn: jest.fn(),\n    error: jest.fn(),\n    enable: jest.fn(),\n    disable: jest.fn(),\n  };\n\n  /**\n   * jsdom's localStorage methods live on Storage.prototype and aren't own properties,\n   * so `jest.spyOn(localStorage, 'getItem')` doesn't bind. Patching the prototype\n   * directly is the reliable way to inject failure modes — callers must restore.\n   */\n  const overrideStorageMethod = <K extends 'getItem' | 'setItem' | 'removeItem' | 'key'>(\n    name: K,\n    impl: Storage[K],\n  ): (() => void) => {\n    const proto = Object.getPrototypeOf(globalThis.localStorage) as Storage;\n    const original = proto[name];\n    proto[name] = impl;\n    return () => {\n      proto[name] = original;\n    };\n  };\n\n  beforeEach(() => {\n    globalThis.localStorage.clear();\n    jest.clearAllMocks();\n  });\n\n  describe('getOrInitReplayStartTime', () => {\n    test('writes now when no entry exists and returns it', () => {\n      const now = 1_700_000_000_000;\n      const result = getOrInitReplayStartTime(apiKey, 'sess1', now, logger);\n      expect(result).toBe(now);\n      expect(globalThis.localStorage.getItem(`${prefix}sess1`)).toBe(String(now));\n    });\n\n    test('returns existing fresh entry without overwriting', () => {\n      const earlier = 1_700_000_000_000;\n      globalThis.localStorage.setItem(`${prefix}sess1`, String(earlier));\n      const result = getOrInitReplayStartTime(apiKey, 'sess1', earlier + 60_000, logger);\n      expect(result).toBe(earlier);\n      expect(globalThis.localStorage.getItem(`${prefix}sess1`)).toBe(String(earlier));\n    });\n\n    test('treats NaN entries as missing and overwrites', () => {\n      globalThis.localStorage.setItem(`${prefix}sess1`, 'NaN');\n      const now = 1_700_000_000_000;\n      const result = getOrInitReplayStartTime(apiKey, 'sess1', now, logger);\n      expect(result).toBe(now);\n    });\n\n    test('treats non-finite entries as missing and overwrites', () => {\n      globalThis.localStorage.setItem(`${prefix}sess1`, 'Infinity');\n      const now = 1_700_000_000_000;\n      const result = getOrInitReplayStartTime(apiKey, 'sess1', now, logger);\n      expect(result).toBe(now);\n    });\n\n    test('treats future-dated entries as missing and overwrites', () => {\n      const now = 1_700_000_000_000;\n      globalThis.localStorage.setItem(`${prefix}sess1`, String(now + 60_000));\n      const result = getOrInitReplayStartTime(apiKey, 'sess1', now, logger);\n      expect(result).toBe(now);\n    });\n\n    test('treats zero/negative entries as missing and overwrites', () => {\n      globalThis.localStorage.setItem(`${prefix}sess1`, '0');\n      const now = 1_700_000_000_000;\n      const result = getOrInitReplayStartTime(apiKey, 'sess1', now, logger);\n      expect(result).toBe(now);\n    });\n\n    test('treats stale entries as missing and overwrites', () => {\n      const stale = 1_000_000_000_000;\n      globalThis.localStorage.setItem(`${prefix}sess1`, String(stale));\n      const result = getOrInitReplayStartTime(apiKey, 'sess1', stale + REPLAY_START_TIME_TTL_MS + 1, logger);\n      expect(result).toBe(stale + REPLAY_START_TIME_TTL_MS + 1);\n    });\n\n    test('returns undefined and logs when storage throws', () => {\n      const restore = overrideStorageMethod('getItem', () => {\n        throw new Error('boom');\n      });\n      try {\n        const result = getOrInitReplayStartTime(apiKey, 'sess1', 1_700_000_000_000, logger);\n        expect(result).toBeUndefined();\n        expect(logger.debug).toHaveBeenCalled();\n      } finally {\n        restore();\n      }\n    });\n\n    test('returns undefined when globalThis.localStorage is unavailable', () => {\n      const orig = globalThis.localStorage;\n      Object.defineProperty(globalThis, 'localStorage', { value: undefined, configurable: true });\n      try {\n        const result = getOrInitReplayStartTime(apiKey, 'sess1', 1_700_000_000_000, logger);\n        expect(result).toBeUndefined();\n      } finally {\n        Object.defineProperty(globalThis, 'localStorage', { value: orig, configurable: true });\n      }\n    });\n\n    test('returns undefined when accessing globalThis.localStorage throws', () => {\n      const orig = Object.getOwnPropertyDescriptor(globalThis, 'localStorage');\n      Object.defineProperty(globalThis, 'localStorage', {\n        get() {\n          throw new Error('blocked');\n        },\n        configurable: true,\n      });\n      try {\n        const result = getOrInitReplayStartTime(apiKey, 'sess1', 1_700_000_000_000, logger);\n        expect(result).toBeUndefined();\n      } finally {\n        if (orig) Object.defineProperty(globalThis, 'localStorage', orig);\n      }\n    });\n\n    test('works without logger', () => {\n      const restore = overrideStorageMethod('getItem', () => {\n        throw new Error('boom');\n      });\n      try {\n        const result = getOrInitReplayStartTime(apiKey, 'sess1', 1_700_000_000_000);\n        expect(result).toBeUndefined();\n      } finally {\n        restore();\n      }\n    });\n  });\n\n  describe('setReplayStartTime', () => {\n    test('writes the start time to storage', () => {\n      setReplayStartTime(apiKey, 'sess1', 1_700_000_000_000, logger);\n      expect(globalThis.localStorage.getItem(`${prefix}sess1`)).toBe('1700000000000');\n    });\n\n    test('swallows and logs storage errors', () => {\n      const restore = overrideStorageMethod('setItem', () => {\n        throw new Error('quota');\n      });\n      try {\n        expect(() => setReplayStartTime(apiKey, 'sess1', 1_700_000_000_000, logger)).not.toThrow();\n        expect(logger.debug).toHaveBeenCalled();\n      } finally {\n        restore();\n      }\n    });\n\n    test('no-op when storage is unavailable', () => {\n      const orig = globalThis.localStorage;\n      Object.defineProperty(globalThis, 'localStorage', { value: undefined, configurable: true });\n      try {\n        expect(() => setReplayStartTime(apiKey, 'sess1', 1_700_000_000_000, logger)).not.toThrow();\n      } finally {\n        Object.defineProperty(globalThis, 'localStorage', { value: orig, configurable: true });\n      }\n    });\n\n    test('swallows storage errors without a logger', () => {\n      const restore = overrideStorageMethod('setItem', () => {\n        throw new Error('quota');\n      });\n      try {\n        expect(() => setReplayStartTime(apiKey, 'sess1', 1_700_000_000_000)).not.toThrow();\n      } finally {\n        restore();\n      }\n    });\n  });\n\n  describe('removeReplayStartTime', () => {\n    test('removes the entry', () => {\n      globalThis.localStorage.setItem(`${prefix}sess1`, '12345');\n      removeReplayStartTime(apiKey, 'sess1', logger);\n      expect(globalThis.localStorage.getItem(`${prefix}sess1`)).toBeNull();\n    });\n\n    test('swallows and logs storage errors', () => {\n      const restore = overrideStorageMethod('removeItem', () => {\n        throw new Error('blocked');\n      });\n      try {\n        expect(() => removeReplayStartTime(apiKey, 'sess1', logger)).not.toThrow();\n        expect(logger.debug).toHaveBeenCalled();\n      } finally {\n        restore();\n      }\n    });\n\n    test('swallows storage errors without a logger', () => {\n      const restore = overrideStorageMethod('removeItem', () => {\n        throw new Error('blocked');\n      });\n      try {\n        expect(() => removeReplayStartTime(apiKey, 'sess1')).not.toThrow();\n      } finally {\n        restore();\n      }\n    });\n\n    test('no-op when storage is unavailable', () => {\n      const orig = globalThis.localStorage;\n      Object.defineProperty(globalThis, 'localStorage', { value: undefined, configurable: true });\n      try {\n        expect(() => removeReplayStartTime(apiKey, 'sess1', logger)).not.toThrow();\n      } finally {\n        Object.defineProperty(globalThis, 'localStorage', { value: orig, configurable: true });\n      }\n    });\n  });\n\n  describe('pruneStaleReplayStartTimes', () => {\n    test('removes entries older than TTL but keeps fresh ones', () => {\n      const now = 1_700_000_000_000;\n      const fresh = now - 1_000;\n      const stale = now - REPLAY_START_TIME_TTL_MS - 1;\n      globalThis.localStorage.setItem(`${prefix}fresh`, String(fresh));\n      globalThis.localStorage.setItem(`${prefix}stale`, String(stale));\n      // An entry from a different api key should not be touched.\n      globalThis.localStorage.setItem(`AMP_SR_START_other_apik_stale`, String(stale));\n\n      pruneStaleReplayStartTimes(apiKey, now, logger);\n\n      expect(globalThis.localStorage.getItem(`${prefix}fresh`)).toBe(String(fresh));\n      expect(globalThis.localStorage.getItem(`${prefix}stale`)).toBeNull();\n      expect(globalThis.localStorage.getItem(`AMP_SR_START_other_apik_stale`)).toBe(String(stale));\n    });\n\n    test('removes entries with non-finite or non-positive values', () => {\n      globalThis.localStorage.setItem(`${prefix}bad1`, 'not-a-number');\n      globalThis.localStorage.setItem(`${prefix}bad2`, '-1');\n      pruneStaleReplayStartTimes(apiKey, 1_700_000_000_000, logger);\n      expect(globalThis.localStorage.getItem(`${prefix}bad1`)).toBeNull();\n      expect(globalThis.localStorage.getItem(`${prefix}bad2`)).toBeNull();\n    });\n\n    test('ignores keys that do not match the prefix', () => {\n      globalThis.localStorage.setItem('OTHER_KEY', 'whatever');\n      pruneStaleReplayStartTimes(apiKey, 1_700_000_000_000, logger);\n      expect(globalThis.localStorage.getItem('OTHER_KEY')).toBe('whatever');\n    });\n\n    test('skips iteration entries where key() returns null', () => {\n      globalThis.localStorage.setItem(`${prefix}sess1`, String(Date.now()));\n      const proto = Object.getPrototypeOf(globalThis.localStorage) as Storage;\n      const origKey = proto.key.bind(proto);\n      let calls = 0;\n      const restore = overrideStorageMethod('key', (idx: number) => {\n        calls++;\n        if (calls === 1) return null;\n        return origKey(idx);\n      });\n      try {\n        expect(() => pruneStaleReplayStartTimes(apiKey, Date.now(), logger)).not.toThrow();\n      } finally {\n        restore();\n      }\n    });\n\n    test('skips entries where getItem returns null mid-iteration', () => {\n      globalThis.localStorage.setItem(`${prefix}sess1`, String(Date.now()));\n      const proto = Object.getPrototypeOf(globalThis.localStorage) as Storage;\n      const origGet = proto.getItem.bind(proto);\n      let callCount = 0;\n      const restore = overrideStorageMethod('getItem', (k: string) => {\n        callCount++;\n        if (callCount === 1) return null;\n        return origGet(k);\n      });\n      try {\n        expect(() => pruneStaleReplayStartTimes(apiKey, Date.now(), logger)).not.toThrow();\n      } finally {\n        restore();\n      }\n    });\n\n    test('swallows and logs errors during iteration', () => {\n      // Seed an entry so the loop actually enters and reaches storage.key().\n      globalThis.localStorage.setItem(`${prefix}sess1`, String(Date.now()));\n      const restore = overrideStorageMethod('key', () => {\n        throw new Error('boom');\n      });\n      try {\n        expect(() => pruneStaleReplayStartTimes(apiKey, 1_700_000_000_000, logger)).not.toThrow();\n        expect(logger.debug).toHaveBeenCalled();\n      } finally {\n        restore();\n      }\n    });\n\n    test('no-op when storage is unavailable', () => {\n      const orig = globalThis.localStorage;\n      Object.defineProperty(globalThis, 'localStorage', { value: undefined, configurable: true });\n      try {\n        expect(() => pruneStaleReplayStartTimes(apiKey, 1_700_000_000_000, logger)).not.toThrow();\n      } finally {\n        Object.defineProperty(globalThis, 'localStorage', { value: orig, configurable: true });\n      }\n    });\n\n    test('swallows iteration errors without a logger', () => {\n      globalThis.localStorage.setItem(`${prefix}sess1`, String(Date.now()));\n      const restore = overrideStorageMethod('key', () => {\n        throw new Error('boom');\n      });\n      try {\n        expect(() => pruneStaleReplayStartTimes(apiKey, 1_700_000_000_000)).not.toThrow();\n      } finally {\n        restore();\n      }\n    });\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/sampling.test.ts",
    "content": "import { xxHash32, isSessionInSample } from '../src/sampling';\n\ndescribe('xxHash32', () => {\n  test('should return consistent hash for empty string', () => {\n    expect(xxHash32('')).toBe(46947589);\n  });\n\n  test('should return consistent hash for short string', () => {\n    expect(xxHash32('abc')).toBe(852579327);\n  });\n\n  test('should return consistent hash for session id string', () => {\n    expect(xxHash32('1719847315013')).toBe(36109684);\n  });\n\n  test('should return consistent hash with custom seed', () => {\n    const hash0 = xxHash32('test', 0);\n    const hash1 = xxHash32('test', 1);\n    expect(hash0).not.toBe(hash1);\n  });\n\n  test('should handle strings longer than 16 bytes', () => {\n    const hash = xxHash32('this is a longer string input');\n    expect(typeof hash).toBe('number');\n    expect(hash).toBeGreaterThanOrEqual(0);\n    expect(hash).toBeLessThan(2 ** 32);\n  });\n\n  test('should handle 2-byte UTF-8 characters', () => {\n    // e.g. 'é' is U+00E9, encodes to 2 bytes in UTF-8\n    const hash = xxHash32('café');\n    expect(typeof hash).toBe('number');\n    expect(hash).toBeGreaterThanOrEqual(0);\n  });\n\n  test('should handle 3-byte UTF-8 characters', () => {\n    // e.g. '中' is U+4E2D, encodes to 3 bytes in UTF-8\n    const hash = xxHash32('中文');\n    expect(typeof hash).toBe('number');\n    expect(hash).toBeGreaterThanOrEqual(0);\n  });\n\n  test('should handle 4-byte UTF-8 characters (surrogate pairs)', () => {\n    // e.g. '😀' is U+1F600, encodes to 4 bytes in UTF-8 and is a surrogate pair in JS\n    const hash = xxHash32('😀');\n    expect(typeof hash).toBe('number');\n    expect(hash).toBeGreaterThanOrEqual(0);\n  });\n});\n\ndescribe('isSessionInSample', () => {\n  test('should return true when hash mod falls below sample rate', () => {\n    // xxHash32('1719847315013') % 1_000_000 / 1_000_000 = 0.109684\n    expect(isSessionInSample(1719847315013, 0.2)).toBe(true);\n  });\n\n  test('should return false when hash mod falls above sample rate', () => {\n    expect(isSessionInSample(1719847315013, 0.1)).toBe(false);\n  });\n\n  test('should return true for sample rate of 1', () => {\n    expect(isSessionInSample(1719847315013, 1)).toBe(true);\n  });\n\n  test('should return false for sample rate of 0', () => {\n    expect(isSessionInSample(1719847315013, 0)).toBe(false);\n  });\n\n  test('should accept string session ids', () => {\n    expect(isSessionInSample('1719847315013', 0.2)).toBe(true);\n  });\n\n  test('should be deterministic', () => {\n    const result1 = isSessionInSample(1719847315013, 0.5);\n    const result2 = isSessionInSample(1719847315013, 0.5);\n    expect(result1).toBe(result2);\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/script/test-script-tag.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Session Replay Browser Script Tag Test</title>\n    <style>\n        body {\n            font-family: Arial, sans-serif;\n            max-width: 800px;\n            margin: 0 auto;\n            padding: 20px;\n            line-height: 1.6;\n        }\n        .test-section {\n            background: #f5f5f5;\n            padding: 15px;\n            margin: 15px 0;\n            border-radius: 5px;\n            border-left: 4px solid #007cba;\n        }\n        .success {\n            border-left-color: #28a745;\n            background: #d4edda;\n        }\n        .error {\n            border-left-color: #dc3545;\n            background: #f8d7da;\n        }\n        button {\n            background: #007cba;\n            color: white;\n            border: none;\n            padding: 10px 20px;\n            margin: 5px;\n            border-radius: 3px;\n            cursor: pointer;\n        }\n        button:hover {\n            background: #005a8b;\n        }\n        .log-output {\n            background: #f8f9fa;\n            border: 1px solid #dee2e6;\n            padding: 10px;\n            margin: 10px 0;\n            border-radius: 3px;\n            font-family: monospace;\n            font-size: 12px;\n            max-height: 200px;\n            overflow-y: auto;\n        }\n        input, select {\n            padding: 5px;\n            margin: 2px;\n            border: 1px solid #ccc;\n            border-radius: 3px;\n        }\n        .form-group {\n            margin: 10px 0;\n        }\n        .form-group label {\n            display: inline-block;\n            width: 120px;\n            font-weight: bold;\n        }\n    </style>\n</head>\n<body>\n    <h1>🎬 Session Replay Browser Script Tag Test</h1>\n    \n    <div class=\"test-section\">\n        <h2>1. Script Loading Test</h2>\n        <div id=\"script-load-result\">Testing...</div>\n    </div>\n\n    <div class=\"test-section\">\n        <h2>2. API Availability Test</h2>\n        <div id=\"api-test-result\">Testing...</div>\n    </div>\n\n    <div class=\"test-section\">\n        <h2>3. Configuration & Initialization</h2>\n        <div class=\"form-group\">\n            <label for=\"api-key\">API Key:</label>\n            <input type=\"text\" id=\"api-key\" value=\"test-api-key-12345\" placeholder=\"Enter your API key\">\n        </div>\n        <div class=\"form-group\">\n            <label for=\"session-id\">Session ID:</label>\n            <input type=\"text\" id=\"session-id\" value=\"test-session-123\" placeholder=\"Enter session ID\">\n        </div>\n        <div class=\"form-group\">\n            <label for=\"device-id\">Device ID:</label>\n            <input type=\"text\" id=\"device-id\" value=\"test-device-456\" placeholder=\"Enter device ID\">\n        </div>\n        <button onclick=\"initializeSessionReplay()\">Initialize Session Replay</button>\n        <div id=\"init-result\"></div>\n    </div>\n\n    <div class=\"test-section\">\n        <h2>4. Method Testing</h2>\n        <button onclick=\"testGetSessionReplayProperties()\">Get Session Replay Properties</button>\n        <button onclick=\"testSetSessionId()\">Set New Session ID</button>\n        <button onclick=\"testGetSessionId()\">Get Session ID</button>\n        <button onclick=\"testFlush()\">Flush Events</button>\n        <button onclick=\"testShutdown()\">Shutdown</button>\n        <div id=\"method-test-result\"></div>\n    </div>\n\n    <div class=\"test-section\">\n        <h2>5. Interactive Elements (for testing capture)</h2>\n        <p>These elements help test if session replay is capturing interactions:</p>\n        <button onclick=\"logInteraction('Button clicked!')\">Click Me</button>\n        <input type=\"text\" placeholder=\"Type something here...\" onchange=\"logInteraction('Input changed: ' + this.value)\">\n        <select onchange=\"logInteraction('Select changed: ' + this.value)\">\n            <option value=\"\">Choose...</option>\n            <option value=\"option1\">Option 1</option>\n            <option value=\"option2\">Option 2</option>\n        </select>\n    </div>\n\n    <div class=\"test-section\">\n        <h2>6. Console Output</h2>\n        <p>Check the browser console for detailed logs. Recent logs appear below:</p>\n        <div id=\"console-output\" class=\"log-output\">\n            Console logs will appear here...\n        </div>\n        <button onclick=\"clearConsoleOutput()\">Clear Logs</button>\n    </div>\n\n    <!-- Load the session replay bundle -->\n    <script src=\"../../lib/scripts/session-replay-browser-min.js\"></script>\n    \n    <script>\n        // Custom console logging to capture output\n        const originalLog = console.log;\n        const originalWarn = console.warn;\n        const originalError = console.error;\n        \n        const consoleOutput = document.getElementById('console-output');\n        \n        function appendToConsole(type, ...args) {\n            const timestamp = new Date().toLocaleTimeString();\n            const message = args.map(arg => \n                typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg)\n            ).join(' ');\n            \n            const logElement = document.createElement('div');\n            logElement.innerHTML = `<span style=\"color: #666;\">[${timestamp}] ${type.toUpperCase()}:</span> ${message}`;\n            consoleOutput.appendChild(logElement);\n            consoleOutput.scrollTop = consoleOutput.scrollHeight;\n        }\n        \n        console.log = function(...args) {\n            originalLog.apply(console, args);\n            appendToConsole('log', ...args);\n        };\n        \n        console.warn = function(...args) {\n            originalWarn.apply(console, args);\n            appendToConsole('warn', ...args);\n        };\n        \n        console.error = function(...args) {\n            originalError.apply(console, args);\n            appendToConsole('error', ...args);\n        };\n        \n        function clearConsoleOutput() {\n            consoleOutput.innerHTML = 'Console logs will appear here...';\n        }\n\n        // Test 1: Script Loading\n        function testScriptLoading() {\n            const result = document.getElementById('script-load-result');\n            \n            if (typeof window.sessionReplay !== 'undefined') {\n                result.innerHTML = '✅ <strong>Success:</strong> window.sessionReplay is available';\n                result.className = 'success';\n                console.log('✅ Script loaded successfully. window.sessionReplay is available.');\n            } else {\n                result.innerHTML = '❌ <strong>Error:</strong> window.sessionReplay is not available';\n                result.className = 'error';\n                console.error('❌ Script loading failed. window.sessionReplay is not available.');\n            }\n        }\n\n        // Test 2: API Availability\n        function testAPIAvailability() {\n            const result = document.getElementById('api-test-result');\n            \n            if (typeof window.sessionReplay !== 'undefined') {\n                const expectedMethods = ['init', 'setSessionId', 'getSessionId', 'getSessionReplayProperties', 'flush', 'shutdown', 'evaluateTargetingAndCapture'];\n                const availableMethods = Object.keys(window.sessionReplay);\n                const missingMethods = expectedMethods.filter(method => typeof window.sessionReplay[method] !== 'function');\n                \n                console.log('Available methods:', availableMethods);\n                console.log('Expected methods:', expectedMethods);\n                \n                if (missingMethods.length === 0) {\n                    result.innerHTML = `✅ <strong>Success:</strong> All expected methods are available<br>\n                        <small>Available: ${availableMethods.join(', ')}</small>`;\n                    result.className = 'success';\n                    console.log('✅ All expected API methods are available.');\n                } else {\n                    result.innerHTML = `⚠️ <strong>Warning:</strong> Some methods are missing<br>\n                        <small>Missing: ${missingMethods.join(', ')}<br>\n                        Available: ${availableMethods.join(', ')}</small>`;\n                    result.className = 'error';\n                    console.warn('⚠️ Some expected methods are missing:', missingMethods);\n                }\n            } else {\n                result.innerHTML = '❌ <strong>Error:</strong> window.sessionReplay is not available';\n                result.className = 'error';\n            }\n        }\n\n        // Initialize Session Replay\n        function initializeSessionReplay() {\n            const result = document.getElementById('init-result');\n            const apiKey = document.getElementById('api-key').value;\n            const sessionId = document.getElementById('session-id').value;\n            const deviceId = document.getElementById('device-id').value;\n            \n            if (!apiKey) {\n                result.innerHTML = '❌ Please enter an API key';\n                result.className = 'error';\n                return;\n            }\n            \n            try {\n                console.log('Initializing Session Replay with:', { apiKey, sessionId, deviceId });\n                \n                window.sessionReplay.init(apiKey, {\n                    sessionId: sessionId || undefined,\n                    deviceId: deviceId || undefined,\n                    logLevel: 3, // Verbose logging\n                    debugMode: true,\n                    sampleRate: 1.0, // Capture everything for testing\n                });\n                \n                result.innerHTML = '✅ <strong>Success:</strong> Session Replay initialized!';\n                result.className = 'success';\n                console.log('✅ Session Replay initialized successfully!');\n            } catch (error) {\n                result.innerHTML = `❌ <strong>Error:</strong> ${error.message}`;\n                result.className = 'error';\n                console.error('❌ Initialization failed:', error);\n            }\n        }\n\n        // Test method calls\n        function testGetSessionReplayProperties() {\n            const result = document.getElementById('method-test-result');\n            try {\n                const properties = window.sessionReplay.getSessionReplayProperties();\n                result.innerHTML = `✅ <strong>getSessionReplayProperties():</strong><br><pre>${JSON.stringify(properties, null, 2)}</pre>`;\n                result.className = 'success';\n                console.log('Session Replay Properties:', properties);\n            } catch (error) {\n                result.innerHTML = `❌ <strong>Error:</strong> ${error.message}`;\n                result.className = 'error';\n                console.error('getSessionReplayProperties failed:', error);\n            }\n        }\n\n        function testSetSessionId() {\n            const result = document.getElementById('method-test-result');\n            try {\n                const newSessionId = 'new-session-' + Date.now();\n                window.sessionReplay.setSessionId(newSessionId);\n                result.innerHTML = `✅ <strong>setSessionId():</strong> Set to ${newSessionId}`;\n                result.className = 'success';\n                console.log('Session ID updated to:', newSessionId);\n            } catch (error) {\n                result.innerHTML = `❌ <strong>Error:</strong> ${error.message}`;\n                result.className = 'error';\n                console.error('setSessionId failed:', error);\n            }\n        }\n\n        function testGetSessionId() {\n            const result = document.getElementById('method-test-result');\n            try {\n                const sessionId = window.sessionReplay.getSessionId();\n                result.innerHTML = `✅ <strong>getSessionId():</strong> ${sessionId || 'null'}`;\n                result.className = 'success';\n                console.log('Current Session ID:', sessionId);\n            } catch (error) {\n                result.innerHTML = `❌ <strong>Error:</strong> ${error.message}`;\n                result.className = 'error';\n                console.error('getSessionId failed:', error);\n            }\n        }\n\n        function testFlush() {\n            const result = document.getElementById('method-test-result');\n            try {\n                const flushPromise = window.sessionReplay.flush();\n                if (flushPromise && typeof flushPromise.then === 'function') {\n                    flushPromise.then(() => {\n                        result.innerHTML = `✅ <strong>flush():</strong> Events flushed successfully`;\n                        result.className = 'success';\n                        console.log('✅ Events flushed successfully');\n                    }).catch(error => {\n                        result.innerHTML = `❌ <strong>flush() error:</strong> ${error.message}`;\n                        result.className = 'error';\n                        console.error('Flush failed:', error);\n                    });\n                } else {\n                    result.innerHTML = `✅ <strong>flush():</strong> Called (returned: ${flushPromise})`;\n                    result.className = 'success';\n                    console.log('Flush called, returned:', flushPromise);\n                }\n            } catch (error) {\n                result.innerHTML = `❌ <strong>Error:</strong> ${error.message}`;\n                result.className = 'error';\n                console.error('flush failed:', error);\n            }\n        }\n\n        function testShutdown() {\n            const result = document.getElementById('method-test-result');\n            try {\n                window.sessionReplay.shutdown();\n                result.innerHTML = `✅ <strong>shutdown():</strong> Session Replay shutdown completed`;\n                result.className = 'success';\n                console.log('✅ Session Replay shutdown completed');\n            } catch (error) {\n                result.innerHTML = `❌ <strong>Error:</strong> ${error.message}`;\n                result.className = 'error';\n                console.error('shutdown failed:', error);\n            }\n        }\n\n        function logInteraction(message) {\n            console.log('User interaction:', message);\n        }\n\n        // Run tests when page loads\n        window.addEventListener('load', function() {\n            console.log('🎬 Session Replay Browser Script Tag Test started');\n            console.log('User Agent:', navigator.userAgent);\n            console.log('Page URL:', window.location.href);\n            \n            // Run tests with slight delay to ensure script is loaded\n            setTimeout(() => {\n                testScriptLoading();\n                testAPIAvailability();\n            }, 100);\n        });\n    </script>\n</body>\n</html>\n"
  },
  {
    "path": "packages/session-replay-browser/test/session-replay-factory.test.ts",
    "content": "import { SessionReplay } from '../src/session-replay';\nimport { getLogConfig } from '../src/session-replay-factory';\n\ndescribe('session replay factory', () => {\n  describe('getLogConfig', () => {\n    test('return the log config if config defined on session replay', async () => {\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init('apiKey', {}).promise;\n      expect(Object.keys(getLogConfig(sessionReplay)())).toEqual(['logger', 'logLevel']);\n    });\n    test('return the log config if no config defined on session replay', async () => {\n      const sessionReplay = new SessionReplay();\n      expect(Object.keys(getLogConfig(sessionReplay)())).toEqual(['logger', 'logLevel']);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/session-replay.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-non-null-assertion */\n/* eslint-disable @typescript-eslint/unbound-method */\n/* eslint-disable @typescript-eslint/no-unsafe-call */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\nimport * as AnalyticsCore from '@amplitude/analytics-core';\nimport { LogLevel, ILogger, ServerZone, SpecialEventType, RemoteConfig, Source } from '@amplitude/analytics-core';\nimport { SessionReplayLocalConfig } from '../src/config/local-config';\nimport * as JoinedConfigModule from '../src/config/joined-config';\nimport { NetworkObservers, NetworkRequestEvent } from '../src/observers';\n\nimport { IDBFactory } from 'fake-indexeddb';\nimport { LoggingConfig, SessionReplayJoinedConfig } from '../src/config/types';\nimport { CustomRRwebEvent, DEFAULT_SAMPLE_RATE } from '../src/constants';\nimport * as SessionReplayIDB from '../src/events/events-idb-store';\nimport * as SessionReplayEventsManager from '../src/events/events-manager';\nimport * as Sampling from '../src/sampling';\nimport * as Helpers from '../src/helpers';\nimport { SessionReplay } from '../src/session-replay';\nimport * as targetingManager from '../src/targeting/targeting-manager';\n\n// Mock the worker module\njest.mock(\n  '../src/worker',\n  () => ({\n    compressionScript: 'console.log(\"webworker script\");',\n  }),\n  { virtual: true },\n);\nimport { SessionReplayOptions } from '../src/typings/session-replay';\n\n// Mock cross-origin-iframes so spies work reliably regardless of test ordering\njest.mock('../src/cross-origin-iframes', () => ({\n  isInIframe: jest.fn().mockReturnValue(false),\n  CrossOriginIframeCoordinator: jest.fn().mockImplementation(() => ({\n    start: jest.fn(),\n    stop: jest.fn(),\n  })),\n  listenForParentSignals: jest.fn().mockReturnValue(jest.fn()),\n}));\n\nimport {\n  isInIframe as mockIsInIframe,\n  CrossOriginIframeCoordinator as MockCrossOriginIframeCoordinator,\n  listenForParentSignals as mockListenForParentSignals,\n} from '../src/cross-origin-iframes';\n\n// Mock the URL tracking plugin\njest.mock('../src/plugins/url-tracking-plugin', () => ({\n  createUrlTrackingPlugin: jest.fn().mockImplementation((options: any = {}) => ({\n    name: 'amplitude/url-tracking@1',\n    observer: jest.fn().mockImplementation((_callback: any, _opts: any) => {\n      // Return a cleanup function\n      return () => {\n        // cleanup function\n      };\n    }),\n    options: {\n      ugcFilterRules: options.ugcFilterRules || [],\n      enablePolling: options.enablePolling || false,\n      pollingInterval: options.pollingInterval || 1000,\n      captureDocumentTitle: options.captureDocumentTitle ?? false,\n    },\n  })),\n  subscribeToUrlChanges: jest.fn().mockImplementation(() => jest.fn()),\n}));\n\nimport { createUrlTrackingPlugin, subscribeToUrlChanges } from '../src/plugins/url-tracking-plugin';\n\n// Mock remote config storage\nlet mockRemoteConfig: RemoteConfig | null = null;\n\n// Mock RemoteConfigClient - will be recreated for each test\nlet mockRemoteConfigClient: any;\n\nlet MockedRemoteConfigClient: jest.SpyInstance;\nlet originalRemoteConfigClient: typeof AnalyticsCore.RemoteConfigClient;\n\ntype MockedLogger = jest.Mocked<ILogger>;\n\nconst mockCreateUrlTrackingPlugin = createUrlTrackingPlugin as jest.MockedFunction<typeof createUrlTrackingPlugin>;\n\nconst mockEvent = {\n  type: 4,\n  data: { href: 'https://analytics.amplitude.com/', width: 1728, height: 154 },\n  timestamp: 1687358660935,\n};\nconst mockEventString = JSON.stringify(mockEvent);\n\nconst samplingConfig = {\n  sample_rate: 1,\n  capture_enabled: true,\n};\n\n// Default mock implementation\nconst defaultMockImplementation = (options: any = {}) => ({\n  name: 'amplitude/url-tracking@1',\n  observer: jest.fn().mockImplementation((_callback: any, _opts: any) => {\n    // Return a cleanup function\n    return () => {\n      // cleanup function\n    };\n  }),\n  options: {\n    ugcFilterRules: options.ugcFilterRules || [],\n    enablePolling: options.enablePolling || false,\n    pollingInterval: options.pollingInterval || 1000,\n    captureDocumentTitle: options.captureDocumentTitle ?? false,\n  },\n});\n\ndescribe('SessionReplay', () => {\n  let originalFetch: typeof global.fetch;\n  let deferEvents: typeof global.requestIdleCallback;\n  let globalSpy: jest.SpyInstance;\n  const mockLoggerProvider: MockedLogger = {\n    error: jest.fn(),\n    log: jest.fn(),\n    disable: jest.fn(),\n    enable: jest.fn(),\n    warn: jest.fn(),\n    debug: jest.fn(),\n  };\n  const addEventListenerMock = jest.fn() as jest.Mock<typeof window.addEventListener>;\n  const removeEventListenerMock = jest.fn() as jest.Mock<typeof window.removeEventListener>;\n  const mockGlobalScope = {\n    addEventListener: addEventListenerMock,\n    removeEventListener: removeEventListenerMock,\n    document: {\n      hasFocus: () => true,\n    },\n    location: {\n      href: 'http://localhost',\n    },\n    indexedDB: new IDBFactory(),\n    // jsdom provides a working localStorage; expose it so the replay-start-time-store\n    // (which reads through getGlobalScope) sees a real storage in tests.\n    localStorage: globalThis.localStorage,\n    navigator: {\n      storage: {\n        estimate: () => {\n          return {\n            usage: 1000,\n            quota: 100000,\n            usageDetails: {\n              indexedDB: 10,\n            },\n          };\n        },\n      },\n    },\n  } as unknown as typeof globalThis;\n  const apiKey = 'static_key';\n  const mockOptions: SessionReplayOptions = {\n    flushIntervalMillis: 0,\n    flushMaxRetries: 1,\n    flushQueueSize: 0,\n    logLevel: LogLevel.None,\n    loggerProvider: mockLoggerProvider,\n    deviceId: '1a2b3c',\n    optOut: false,\n    sampleRate: 1,\n    sessionId: 123,\n    serverZone: ServerZone.EU,\n    storeType: 'idb',\n    privacyConfig: {\n      blockSelector: '.className',\n      maskSelector: ['.className1', '.className2'],\n    },\n  };\n  const mockEmptyOptions: SessionReplayOptions = {\n    flushIntervalMillis: 0,\n    flushMaxRetries: 1,\n    flushQueueSize: 0,\n    logLevel: LogLevel.None,\n    loggerProvider: mockLoggerProvider,\n    deviceId: '1a2b3c',\n    sessionId: 123,\n  };\n  let sessionReplay: SessionReplay;\n  let initialize: jest.SpyInstance;\n  let mockRecordFunction: jest.Mock & { addCustomEvent: jest.Mock; mirror: { getNode: jest.Mock } };\n\n  // Add this helper function at the top of your describe block\n  function createMockRecordFunction() {\n    const mockRecordFn = jest.fn().mockReturnValue(jest.fn()) as jest.Mock & {\n      addCustomEvent: jest.Mock;\n      takeFullSnapshot: jest.Mock;\n      mirror: { getNode: jest.Mock };\n    };\n    mockRecordFn.addCustomEvent = jest.fn();\n    mockRecordFn.takeFullSnapshot = jest.fn();\n    mockRecordFn.mirror = {\n      getNode: jest.fn().mockReturnValue(null),\n    };\n    return mockRecordFn;\n  }\n\n  beforeEach(() => {\n    // Reset the mock implementation to default for each test\n    mockCreateUrlTrackingPlugin.mockImplementation(defaultMockImplementation);\n\n    // Reset all other mocks and setup\n    jest.clearAllMocks();\n\n    // Set default remote config\n    mockRemoteConfig = {\n      sr_sampling_config: samplingConfig,\n      sr_privacy_config: {},\n    };\n\n    // Create a fresh mock client for each test\n    mockRemoteConfigClient = {\n      subscribe: jest\n        .fn()\n        .mockImplementation(\n          (\n            _configKey: string | undefined,\n            _deliveryMode: any,\n            callback: (remoteConfig: RemoteConfig | null, source: Source, lastFetch: Date) => void,\n          ) => {\n            // Call the callback synchronously with the mock remote config\n            callback(mockRemoteConfig, 'cache', new Date());\n            return 'mock-subscription-id';\n          },\n        ),\n      unsubscribe: jest.fn(() => true),\n      updateConfigs: jest.fn(),\n    };\n\n    // Set up RemoteConfigClient mock\n    originalRemoteConfigClient = AnalyticsCore.RemoteConfigClient;\n    // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n    MockedRemoteConfigClient = jest.fn().mockImplementation(() => mockRemoteConfigClient);\n    Object.defineProperty(AnalyticsCore, 'RemoteConfigClient', {\n      value: MockedRemoteConfigClient,\n      writable: true,\n      configurable: true,\n    });\n\n    jest.spyOn(SessionReplayIDB, 'createStore');\n    sessionReplay = new SessionReplay();\n    initialize = jest.spyOn(sessionReplay, 'initialize');\n    jest.useFakeTimers();\n    originalFetch = global.fetch;\n    (global.fetch as jest.Mock) = jest.fn(() => {\n      return Promise.resolve({\n        status: 200,\n      });\n    });\n    deferEvents = global.requestIdleCallback;\n    (global.requestIdleCallback as jest.Mock) = jest.fn((callback, options) => {\n      setTimeout(() => {\n        callback();\n      }, (options?.timeout as number) || 0);\n    });\n    globalSpy = jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue(mockGlobalScope);\n\n    // Create mock record function with addCustomEvent method and mirror property\n    mockRecordFunction = createMockRecordFunction();\n    mockRecordFunction.addCustomEvent = jest.fn();\n    mockRecordFunction.mirror = {\n      getNode: jest.fn().mockReturnValue(null),\n    };\n    jest.spyOn(SessionReplay.prototype, 'getRecordFunction' as any).mockResolvedValue(mockRecordFunction);\n  });\n  afterEach(() => {\n    jest.resetAllMocks();\n    jest.spyOn(global.Math, 'random').mockRestore();\n    global.fetch = originalFetch;\n    global.requestIdleCallback = deferEvents;\n    jest.useRealTimers();\n\n    // Clean up RemoteConfigClient mock\n    if (MockedRemoteConfigClient) {\n      Object.defineProperty(AnalyticsCore, 'RemoteConfigClient', {\n        value: originalRemoteConfigClient,\n        writable: true,\n        configurable: true,\n      });\n    }\n  });\n  describe('init: sessionStartTime persistence', () => {\n    beforeEach(() => {\n      globalThis.localStorage.clear();\n    });\n\n    test('fresh init writes Date.now() and reads it back', async () => {\n      const before = Date.now();\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      const after = Date.now();\n      expect(sessionReplay.sessionStartTime).toBeGreaterThanOrEqual(before);\n      expect(sessionReplay.sessionStartTime).toBeLessThanOrEqual(after);\n      const stored = globalThis.localStorage.getItem(`AMP_SR_START_${apiKey.substring(0, 10)}_123`);\n      expect(Number(stored)).toBe(sessionReplay.sessionStartTime);\n    });\n\n    test('second init for same sessionId recovers stored value', async () => {\n      // Seed storage to simulate a prior init having written the start time.\n      const original = Date.now() - 60_000;\n      globalThis.localStorage.setItem(`AMP_SR_START_${apiKey.substring(0, 10)}_123`, String(original));\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      expect(sessionReplay.sessionStartTime).toBe(original);\n    });\n\n    test('corrupt stored value falls back to Date.now() and overwrites', async () => {\n      globalThis.localStorage.setItem(`AMP_SR_START_${apiKey.substring(0, 10)}_123`, 'not-a-number');\n      const before = Date.now();\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      const after = Date.now();\n      expect(sessionReplay.sessionStartTime).toBeGreaterThanOrEqual(before);\n      expect(sessionReplay.sessionStartTime).toBeLessThanOrEqual(after);\n      const stored = Number(globalThis.localStorage.getItem(`AMP_SR_START_${apiKey.substring(0, 10)}_123`));\n      expect(stored).toBe(sessionReplay.sessionStartTime);\n    });\n\n    test('TTL prune drops stale entries on init', async () => {\n      const staleKey = `AMP_SR_START_${apiKey.substring(0, 10)}_999`;\n      // 25 hours ago, beyond REPLAY_START_TIME_TTL_MS (24h).\n      globalThis.localStorage.setItem(staleKey, String(Date.now() - 25 * 60 * 60 * 1000));\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      expect(globalThis.localStorage.getItem(staleKey)).toBeNull();\n    });\n\n    test('falls back to Date.now() when localStorage access throws', async () => {\n      // jsdom's localStorage methods live on Storage.prototype, not as own properties,\n      // so jest.spyOn doesn't bind — patch the prototype directly.\n      const proto = Object.getPrototypeOf(globalThis.localStorage) as Storage;\n      const origGet = proto.getItem;\n      const origSet = proto.setItem;\n      proto.getItem = () => {\n        throw new Error('storage disabled');\n      };\n      proto.setItem = () => {\n        throw new Error('storage disabled');\n      };\n      try {\n        const before = Date.now();\n        await sessionReplay.init(apiKey, mockOptions).promise;\n        const after = Date.now();\n        expect(sessionReplay.sessionStartTime).toBeGreaterThanOrEqual(before);\n        expect(sessionReplay.sessionStartTime).toBeLessThanOrEqual(after);\n      } finally {\n        proto.getItem = origGet;\n        proto.setItem = origSet;\n      }\n    });\n\n    test('uses Date.now() when sessionId is undefined', async () => {\n      const before = Date.now();\n      await sessionReplay.init(apiKey, { ...mockOptions, sessionId: undefined }).promise;\n      const after = Date.now();\n      expect(sessionReplay.sessionStartTime).toBeGreaterThanOrEqual(before);\n      expect(sessionReplay.sessionStartTime).toBeLessThanOrEqual(after);\n    });\n  });\n\n  describe('init', () => {\n    test('should pass current page to evaluateTargetingAndCapture during init', async () => {\n      const evaluateTargetingAndCaptureSpy = jest.spyOn(sessionReplay, 'evaluateTargetingAndCapture');\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      expect(evaluateTargetingAndCaptureSpy).toHaveBeenCalledWith(\n        {\n          userProperties: undefined,\n          page: { url: 'http://localhost' },\n        },\n        true,\n      );\n    });\n\n    test('should remove invalid selectors', async () => {\n      await sessionReplay.init(apiKey, {\n        ...mockOptions,\n        sampleRate: 0.5,\n        privacyConfig: {\n          blockSelector: ['AF<S>FA$!@$'],\n          maskSelector: ['AF<S>FA$!@$!!'],\n          unmaskSelector: ['AF<S>FA$!@$@@'],\n        },\n      }).promise;\n      expect(sessionReplay.config?.privacyConfig?.blockSelector).toStrictEqual(undefined);\n      expect(sessionReplay.config?.privacyConfig?.maskSelector).toStrictEqual(undefined);\n      // .amp-unmask is always injected as a default and is a valid selector, so it survives\n      expect(sessionReplay.config?.privacyConfig?.unmaskSelector).toStrictEqual(['.amp-unmask']);\n    });\n\n    test('should start network observers when network logging is enabled in remote config', async () => {\n      mockRemoteConfig = {\n        sr_sampling_config: samplingConfig,\n        sr_privacy_config: {},\n        sr_interaction_config: {\n          enabled: true,\n        },\n        sr_logging_config: {\n          network: {\n            enabled: true,\n          },\n        },\n      };\n\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      await jest.runAllTimersAsync();\n      const startSpy = jest.spyOn(NetworkObservers.prototype, 'start');\n      await sessionReplay.recordEvents();\n      expect(startSpy).toHaveBeenCalled();\n    });\n\n    test('should not start network observers when network logging is disabled in remote config', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      const startSpy = jest.spyOn(NetworkObservers.prototype, 'start');\n      await sessionReplay.recordEvents();\n      expect(startSpy).not.toHaveBeenCalled();\n    });\n\n    test('should handle interaction config enabled with no performanceConfig.interaction', async () => {\n      mockRemoteConfig = {\n        sr_sampling_config: samplingConfig,\n        sr_privacy_config: {},\n        sr_interaction_config: {\n          enabled: true,\n        },\n      };\n\n      await sessionReplay.init(apiKey, {\n        ...mockOptions,\n        performanceConfig: { enabled: false }, // No interaction property\n      }).promise;\n      await sessionReplay.recordEvents();\n      expect(mockRecordFunction).toHaveBeenCalled();\n      const recordArg = mockRecordFunction.mock.calls[0][0];\n      expect(recordArg?.hooks?.mouseInteraction).toBeDefined();\n    });\n\n    test('should handle interaction config enabled when performanceConfig is set to null', async () => {\n      mockRemoteConfig = {\n        sr_sampling_config: samplingConfig,\n        sr_privacy_config: {},\n        sr_interaction_config: {\n          enabled: true,\n        },\n      };\n\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      // Manually set performanceConfig to null to test edge case\n      if (sessionReplay.config) {\n        (sessionReplay.config as any).performanceConfig = null;\n      }\n\n      await sessionReplay.recordEvents();\n      expect(mockRecordFunction).toHaveBeenCalled();\n      const recordArg = mockRecordFunction.mock.calls[0][0];\n      expect(recordArg?.hooks?.mouseInteraction).toBeDefined();\n    });\n\n    test('should not initialize network observers when config is undefined', async () => {\n      // Create a new SessionReplay instance without initializing\n      const sessionReplayWithoutConfig = new SessionReplay();\n\n      const networkObserversConstructorSpy = jest.spyOn(NetworkObservers.prototype, 'constructor' as any);\n\n      await (sessionReplayWithoutConfig as any).initializeNetworkObservers();\n\n      expect(networkObserversConstructorSpy).not.toHaveBeenCalled();\n\n      expect((sessionReplayWithoutConfig as any).networkObservers).toBeUndefined();\n    });\n\n    test('should log warning when NetworkObservers import fails', async () => {\n      mockRemoteConfig = {\n        sr_sampling_config: samplingConfig,\n        sr_privacy_config: {},\n        sr_interaction_config: {\n          enabled: true,\n        },\n        sr_logging_config: {\n          network: {\n            enabled: true,\n          },\n        },\n      };\n\n      // Mock the dynamic import to throw an error\n      jest.doMock('../src/observers', () => {\n        throw new Error('Import failed');\n      });\n\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      // Call initializeNetworkObservers directly to test the catch block\n      await (sessionReplay as any).initializeNetworkObservers();\n\n      expect(mockLoggerProvider.warn).toHaveBeenCalledWith(\n        'Failed to import or instantiate NetworkObservers:',\n        expect.any(Error),\n      );\n      expect((sessionReplay as any).networkObservers).toBeUndefined();\n\n      // Clean up the mock\n      jest.dontMock('../src/observers');\n    });\n\n    test('should catch error and log a warn when initializing', async () => {\n      // enable interaction config\n      mockRemoteConfig = {\n        sr_sampling_config: samplingConfig,\n        sr_privacy_config: {},\n        sr_interaction_config: {\n          enabled: true,\n        },\n      };\n\n      // mock the error when creating events managers\n      jest.spyOn(SessionReplayEventsManager, 'createEventsManager').mockImplementation(() => {\n        throw new Error('test error');\n      });\n\n      await sessionReplay.init(apiKey, {\n        ...mockOptions,\n        sampleRate: 0.5,\n        privacyConfig: {\n          blockSelector: ['AF<S>FA$!@$'],\n          maskSelector: ['AF<S>FA$!@$!!'],\n          unmaskSelector: ['AF<S>FA$!@$@@'],\n        },\n      }).promise;\n\n      expect(mockLoggerProvider.warn).toHaveBeenCalled();\n    });\n\n    test('should setup sdk', async () => {\n      await sessionReplay.init(apiKey, { ...mockOptions, sampleRate: 0.5 }).promise;\n      expect(sessionReplay.config?.transportProvider).toBeDefined();\n      expect(sessionReplay.config?.flushMaxRetries).toBe(1);\n      expect(sessionReplay.config?.optOut).toBe(false);\n      expect(sessionReplay.config?.sampleRate).toBe(1); // Comes from remote config mock\n      expect(sessionReplay.config?.captureEnabled).toBe(true); // Comes from remote config mock\n      expect(sessionReplay.identifiers?.deviceId).toBe('1a2b3c');\n      expect(sessionReplay.identifiers?.sessionId).toBe(123);\n      expect(sessionReplay.config?.logLevel).toBe(0);\n      expect(sessionReplay.loggerProvider).toBeDefined();\n    });\n\n    test('should invoke page leave listeners', async () => {\n      const invokeEventMap = new Map<string, any>();\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        document: {\n          hasFocus: () => false,\n        },\n        location: {\n          href: 'http://localhost',\n        },\n        addEventListener: jest.fn((eventName, listenerFn): any => {\n          invokeEventMap.set(eventName as string, listenerFn);\n        }) as jest.Mock<typeof window.addEventListener<'blur' | 'focus' | 'pagehide' | 'beforeunload'>>,\n        removeEventListener: removeEventListenerMock,\n      } as unknown as typeof globalThis);\n      await sessionReplay.init(apiKey, { ...mockOptions, sampleRate: 0.5 }).promise;\n      const mockFn = jest.fn();\n      sessionReplay.pageLeaveFns = [mockFn];\n      invokeEventMap.get('beforeunload')({});\n      expect(mockFn).toHaveBeenCalled();\n    });\n\n    test('should not throw when pageLeaveListener fires with no eventCompressor', async () => {\n      const invokeEventMap = new Map<string, any>();\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        document: {\n          hasFocus: () => false,\n        },\n        location: {\n          href: 'http://localhost',\n        },\n        addEventListener: jest.fn((eventName, listenerFn): any => {\n          invokeEventMap.set(eventName as string, listenerFn);\n        }) as jest.Mock<typeof window.addEventListener<'blur' | 'focus' | 'pagehide' | 'beforeunload'>>,\n        removeEventListener: removeEventListenerMock,\n      } as unknown as typeof globalThis);\n      await sessionReplay.init(apiKey, { ...mockOptions, sampleRate: 0.5 }).promise;\n      sessionReplay.eventCompressor = undefined;\n      const trigger = invokeEventMap.get('beforeunload') as (e: Event) => void;\n      expect(() => trigger(new Event('beforeunload'))).not.toThrow();\n    });\n\n    test('should setup sdk with privacy config', async () => {\n      await sessionReplay.init(apiKey, {\n        ...mockOptions,\n        sampleRate: 0.5,\n        privacyConfig: { blockSelector: ['.class', '#id'] },\n      }).promise;\n      expect(sessionReplay.config?.transportProvider).toBeDefined();\n      expect(sessionReplay.config?.flushMaxRetries).toBe(1);\n      expect(sessionReplay.config?.optOut).toBe(false);\n      expect(sessionReplay.config?.sampleRate).toBe(1);\n      expect(sessionReplay.identifiers?.deviceId).toBe('1a2b3c');\n      expect(sessionReplay.identifiers?.sessionId).toBe(123);\n      expect(sessionReplay.config?.logLevel).toBe(0);\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLoggerProvider.enable).toHaveBeenCalledWith(0);\n      expect(sessionReplay.config?.privacyConfig?.blockSelector).toEqual(['.class', '#id']);\n      expect(sessionReplay.loggerProvider).toBeDefined();\n    });\n\n    test('should setup sdk with webworker when useWebWorker is true', async () => {\n      // Mock Worker constructor\n      class MockWorker {\n        postMessage = jest.fn();\n        onmessage = jest.fn();\n        onerror = jest.fn();\n        terminate = jest.fn();\n      }\n\n      const originalWorker = global.Worker;\n      global.Worker = MockWorker as unknown as typeof global.Worker;\n\n      // Mock the dynamic import by mocking the import function\n      const mockCompressionScript = 'console.log(\"webworker script\");';\n      const originalImport = (global as any).import;\n      (global as any).import = jest.fn().mockImplementation((path: string) => {\n        if (path === './worker') {\n          return Promise.resolve({ compressionScript: mockCompressionScript });\n        }\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n        return originalImport(path);\n      });\n\n      // Mock URL.createObjectURL and Blob\n      const originalCreateObjectURL = URL.createObjectURL;\n      const originalBlob = global.Blob;\n      URL.createObjectURL = jest.fn().mockReturnValue('blob:mock-url');\n      global.Blob = jest.fn().mockImplementation((parts, options) => ({\n        parts,\n        options,\n      })) as any;\n\n      // Mock getGlobalScope to include Worker\n      const originalGlobalScope = globalSpy;\n      globalSpy = jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        ...mockGlobalScope,\n        Worker: MockWorker as unknown as typeof global.Worker,\n      });\n\n      await sessionReplay.init(apiKey, {\n        ...mockOptions,\n        sampleRate: 0.5,\n        useWebWorker: true,\n      }).promise;\n\n      expect(sessionReplay.config?.transportProvider).toBeDefined();\n      expect(sessionReplay.config?.flushMaxRetries).toBe(1);\n      expect(sessionReplay.config?.optOut).toBe(false);\n      expect(sessionReplay.config?.sampleRate).toBe(1);\n      expect(sessionReplay.identifiers?.deviceId).toBe('1a2b3c');\n      expect(sessionReplay.identifiers?.sessionId).toBe(123);\n      expect(sessionReplay.config?.logLevel).toBe(0);\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLoggerProvider.enable).toHaveBeenCalledWith(0);\n\n      // The import should have been called (coverage will show this)\n\n      // Restore original values\n      global.Worker = originalWorker;\n      (global as any).import = originalImport;\n      URL.createObjectURL = originalCreateObjectURL;\n      global.Blob = originalBlob;\n      globalSpy = originalGlobalScope;\n    });\n\n    test('should not use webworker when useWebWorker is not provided (default)', async () => {\n      await sessionReplay.init(apiKey, {\n        ...mockOptions,\n        sampleRate: 0.5,\n      }).promise;\n\n      expect(sessionReplay.config?.useWebWorker).toBeUndefined();\n      expect(sessionReplay.config?.transportProvider).toBeDefined();\n      expect(sessionReplay.config?.flushMaxRetries).toBe(1);\n      expect(sessionReplay.config?.optOut).toBe(false);\n      expect(sessionReplay.config?.sampleRate).toBe(1);\n    });\n\n    test('should support legacy experimental.useWebWorker config for backwards compatibility', async () => {\n      // Mock Worker constructor\n      class MockWorker {\n        postMessage = jest.fn();\n        onmessage = jest.fn();\n        onerror = jest.fn();\n        terminate = jest.fn();\n      }\n\n      const originalWorker = global.Worker;\n      global.Worker = MockWorker as unknown as typeof global.Worker;\n\n      // Mock the dynamic import by mocking the import function\n      const mockCompressionScript = 'console.log(\"webworker script\");';\n      const originalImport = (global as any).import;\n      (global as any).import = jest.fn().mockImplementation((path: string) => {\n        if (path === './worker') {\n          return Promise.resolve({ compressionScript: mockCompressionScript });\n        }\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n        return originalImport(path);\n      });\n\n      // Mock URL.createObjectURL and Blob\n      const originalCreateObjectURL = URL.createObjectURL;\n      const originalBlob = global.Blob;\n      URL.createObjectURL = jest.fn().mockReturnValue('blob:mock-url');\n      global.Blob = jest.fn().mockImplementation((parts, options) => ({\n        parts,\n        options,\n      })) as any;\n\n      // Mock getGlobalScope to include Worker\n      const originalGlobalScope = globalSpy;\n      globalSpy = jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        ...mockGlobalScope,\n        Worker: MockWorker as unknown as typeof global.Worker,\n      });\n\n      await sessionReplay.init(apiKey, {\n        ...mockOptions,\n        sampleRate: 0.5,\n        experimental: { useWebWorker: true },\n      } as any).promise;\n\n      expect(sessionReplay.config?.useWebWorker).toBe(true);\n\n      // Restore original values\n      global.Worker = originalWorker;\n      (global as any).import = originalImport;\n      URL.createObjectURL = originalCreateObjectURL;\n      global.Blob = originalBlob;\n      globalSpy = originalGlobalScope;\n    });\n\n    test('fallback to memory store if no indexeddb', async () => {\n      globalSpy = jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        ...mockGlobalScope,\n        indexedDB: null as any,\n      });\n      await sessionReplay.init(apiKey, {\n        ...mockOptions,\n        sampleRate: 0.5,\n        storeType: 'idb',\n      }).promise;\n\n      expect(mockLoggerProvider.log).toHaveBeenCalledWith('Using memory for event storage.');\n    });\n\n    test('fallback to memory store if no global scope', async () => {\n      globalSpy = jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue(undefined);\n      await sessionReplay.init(apiKey, {\n        ...mockOptions,\n        sampleRate: 0.5,\n        storeType: 'idb',\n      }).promise;\n\n      expect(mockLoggerProvider.log).toHaveBeenCalledWith('Using memory for event storage.');\n    });\n\n    test.each([\n      [\n        {\n          enabled: true,\n          trackEveryNms: 500,\n        },\n        async (config: SessionReplayJoinedConfig) => {\n          expect(config.interactionConfig?.enabled).toBe(true);\n          expect(config.interactionConfig?.batch).toBeUndefined();\n          expect(config.interactionConfig?.trackEveryNms).toBe(500);\n        },\n      ],\n      [\n        {\n          enabled: true,\n        },\n        async (config: SessionReplayJoinedConfig) => {\n          expect(config.interactionConfig?.enabled).toBe(true);\n          expect(config.interactionConfig?.batch).toBeUndefined();\n          expect(config.interactionConfig?.trackEveryNms).toBeUndefined();\n        },\n      ],\n      [\n        {\n          enabled: false,\n          trackEveryNms: 1_000,\n        },\n        async (config: SessionReplayJoinedConfig) => {\n          expect(config.interactionConfig?.enabled).toBe(false);\n          expect(config.interactionConfig?.batch).toBeUndefined();\n          expect(config.interactionConfig?.trackEveryNms).toBe(1_000);\n        },\n      ],\n      [\n        undefined,\n        async (config: SessionReplayJoinedConfig) => {\n          expect(config.interactionConfig?.enabled).toBeUndefined();\n          expect(config.interactionConfig?.batch).toBeUndefined();\n          expect(config.interactionConfig?.trackEveryNms).toBeUndefined();\n        },\n      ],\n      [\n        {\n          enabled: true,\n          batch: true,\n        },\n        async (config: SessionReplayJoinedConfig) => {\n          expect(config.interactionConfig?.enabled).toBe(true);\n          expect(config.interactionConfig?.batch).toBe(true);\n          expect(config.interactionConfig?.trackEveryNms).toBeUndefined();\n        },\n      ],\n      [\n        {\n          enabled: true,\n          batch: false,\n        },\n        async (config: SessionReplayJoinedConfig) => {\n          expect(config.interactionConfig?.enabled).toBe(true);\n          expect(config.interactionConfig?.batch).toBe(false);\n          expect(config.interactionConfig?.trackEveryNms).toBeUndefined();\n        },\n      ],\n    ])('should setup sdk with interaction config', async (interactionConfig, expectationFn) => {\n      mockRemoteConfig = {\n        sr_sampling_config: samplingConfig,\n        sr_privacy_config: {},\n        sr_interaction_config: interactionConfig,\n      };\n      await sessionReplay.init(apiKey, {\n        ...mockOptions,\n        sampleRate: 0.5,\n      }).promise;\n      expect(sessionReplay.config?.transportProvider).toBeDefined();\n      expect(sessionReplay.config?.flushMaxRetries).toBe(1);\n      expect(sessionReplay.config?.optOut).toBe(false);\n      expect(sessionReplay.identifiers?.deviceId).toBe('1a2b3c');\n      expect(sessionReplay.identifiers?.sessionId).toBe(123);\n      expect(sessionReplay.config?.logLevel).toBe(0);\n      expect(sessionReplay.loggerProvider).toBeDefined();\n\n      if (sessionReplay.config) {\n        await expectationFn(sessionReplay.config);\n      }\n    });\n\n    test.each([\n      [\n        {\n          enabled: true,\n          interaction: {\n            timeoutMs: 5000,\n            maxNumberOfTries: 5000,\n            threshold: 500,\n          },\n        },\n        async (config: SessionReplayJoinedConfig) => {\n          expect(config.performanceConfig?.enabled).toBe(true);\n          expect(config.performanceConfig?.interaction?.timeoutMs).toBe(5000);\n          expect(config.performanceConfig?.interaction?.maxNumberOfTries).toBe(5000);\n          expect(config.performanceConfig?.interaction?.threshold).toBe(500);\n        },\n      ],\n      [\n        {\n          enabled: true,\n          interaction: {\n            timeoutMs: 3000,\n          },\n        },\n        async (config: SessionReplayJoinedConfig) => {\n          expect(config.performanceConfig?.enabled).toBe(true);\n          expect(config.performanceConfig?.interaction?.timeoutMs).toBe(3000);\n          expect(config.performanceConfig?.interaction?.maxNumberOfTries).toBeUndefined();\n          expect(config.performanceConfig?.interaction?.threshold).toBeUndefined();\n        },\n      ],\n      [\n        {\n          enabled: false,\n        },\n        async (config: SessionReplayJoinedConfig) => {\n          expect(config.performanceConfig?.enabled).toBe(false);\n          expect(config.performanceConfig?.interaction).toBeUndefined();\n        },\n      ],\n      [\n        undefined,\n        async (config: SessionReplayJoinedConfig) => {\n          expect(config.performanceConfig?.enabled).toBe(true);\n          expect(config.performanceConfig?.interaction).toBeUndefined();\n        },\n      ],\n    ])('should setup sdk with performance config', async (performanceConfig, expectationFn) => {\n      mockRemoteConfig = {\n        sr_sampling_config: samplingConfig,\n        sr_privacy_config: {},\n      };\n      await sessionReplay.init(apiKey, {\n        ...mockOptions,\n        performanceConfig,\n        sampleRate: 0.5,\n      }).promise;\n\n      if (sessionReplay.config) {\n        await expectationFn(sessionReplay.config);\n      }\n    });\n\n    test.each([\n      [\n        {\n          console: { enabled: true, levels: ['warn', 'error'] },\n        },\n        async (config: SessionReplayJoinedConfig) => {\n          expect(config.loggingConfig?.console.enabled).toBe(true);\n          expect(config.loggingConfig?.console.levels).toStrictEqual(['warn', 'error']);\n        },\n      ],\n      [\n        {\n          console: { enabled: true, levels: ['error'] },\n        },\n        async (config: SessionReplayJoinedConfig) => {\n          expect(config.loggingConfig?.console.enabled).toBe(true);\n          expect(config.loggingConfig?.console.levels).toStrictEqual(['error']);\n        },\n      ],\n    ])('should setup sdk with interaction config', async (loggingConfig, expectationFn) => {\n      mockRemoteConfig = {\n        sr_sampling_config: samplingConfig,\n        sr_privacy_config: {},\n        sr_logging_config: loggingConfig,\n      };\n      await sessionReplay.init(apiKey, {\n        ...mockOptions,\n        sampleRate: 0.5,\n      }).promise;\n      expect(sessionReplay.config?.transportProvider).toBeDefined();\n      expect(sessionReplay.config?.flushMaxRetries).toBe(1);\n      expect(sessionReplay.config?.optOut).toBe(false);\n      expect(sessionReplay.identifiers?.deviceId).toBe('1a2b3c');\n      expect(sessionReplay.identifiers?.sessionId).toBe(123);\n      expect(sessionReplay.config?.logLevel).toBe(0);\n      expect(sessionReplay.loggerProvider).toBeDefined();\n\n      if (sessionReplay.config) {\n        await expectationFn(sessionReplay.config);\n      }\n    });\n\n    test('should call initialize with shouldSendStoredEvents=true', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      expect(initialize).toHaveBeenCalledTimes(1);\n\n      expect(initialize.mock.calls[0]).toEqual([true]);\n    });\n    test('should set up blur and focus event listeners', async () => {\n      const initialize = jest.spyOn(sessionReplay, 'initialize');\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      const recordMock = jest.fn().mockResolvedValue(undefined);\n      sessionReplay.recordEvents = recordMock;\n      // Clear recordCancelCallback and recordEventsInFlight so focusListener takes the fallback recordEvents path\n      sessionReplay.recordCancelCallback = null;\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n      (sessionReplay as any).recordEventsInFlight = false;\n      initialize.mockReset();\n      expect(addEventListenerMock).toHaveBeenCalledTimes(3);\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n      expect(addEventListenerMock.mock.calls[0][0]).toEqual('blur');\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment\n      const blurCallback = addEventListenerMock.mock.calls[0][1];\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n      blurCallback();\n\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n      expect(addEventListenerMock.mock.calls[1][0]).toEqual('focus');\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment\n      const focusCallback = addEventListenerMock.mock.calls[1][1];\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n      focusCallback();\n      expect(recordMock).toHaveBeenCalledWith(false);\n    });\n\n    describe('focusListener', () => {\n      test('calls takeFullSnapshot(true) when already recording, does not call recordEvents', async () => {\n        await sessionReplay.init(apiKey, mockOptions).promise;\n        const takeFullSnapshotMock = jest.fn();\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n        (sessionReplay as any).recordCancelCallback = jest.fn();\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n        (sessionReplay as any).recordFunction = { takeFullSnapshot: takeFullSnapshotMock };\n        const recordEventsSpy = jest.spyOn(sessionReplay, 'recordEvents');\n\n        sessionReplay.focusListener();\n\n        expect(takeFullSnapshotMock).toHaveBeenCalledWith(true);\n        expect(recordEventsSpy).not.toHaveBeenCalled();\n      });\n\n      test('calls recordEvents(false) when not recording and not in-flight', async () => {\n        await sessionReplay.init(apiKey, mockOptions).promise;\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n        (sessionReplay as any).recordCancelCallback = null;\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n        (sessionReplay as any).recordEventsInFlight = false;\n        const recordEventsSpy = jest.spyOn(sessionReplay, 'recordEvents').mockResolvedValue(undefined);\n\n        sessionReplay.focusListener();\n\n        expect(recordEventsSpy).toHaveBeenCalledWith(false);\n      });\n\n      test('does nothing when not recording but already in-flight', async () => {\n        await sessionReplay.init(apiKey, mockOptions).promise;\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n        (sessionReplay as any).recordCancelCallback = null;\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n        (sessionReplay as any).recordEventsInFlight = true;\n        const recordEventsSpy = jest.spyOn(sessionReplay, 'recordEvents');\n        const takeFullSnapshotMock = jest.fn();\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n        (sessionReplay as any).recordFunction = { takeFullSnapshot: takeFullSnapshotMock };\n\n        sessionReplay.focusListener();\n\n        expect(takeFullSnapshotMock).not.toHaveBeenCalled();\n        expect(recordEventsSpy).not.toHaveBeenCalled();\n      });\n\n      test('warns via loggerProvider when takeFullSnapshot throws', async () => {\n        await sessionReplay.init(apiKey, mockOptions).promise;\n        const warnSpy = jest.spyOn(sessionReplay.loggerProvider, 'warn');\n        const testError = new Error('rrweb snapshot failed');\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n        (sessionReplay as any).recordCancelCallback = jest.fn();\n        // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n        (sessionReplay as any).recordFunction = {\n          takeFullSnapshot: jest.fn().mockImplementation(() => {\n            throw testError;\n          }),\n        };\n\n        sessionReplay.focusListener();\n\n        expect(warnSpy).toHaveBeenCalledWith('Failed to take full snapshot on focus:', testError);\n      });\n    });\n\n    test('it should not call initialize if the document does not have focus', () => {\n      const initialize = jest.spyOn(sessionReplay, 'initialize');\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        document: {\n          hasFocus: () => false,\n        },\n      } as typeof globalThis);\n      expect(initialize).not.toHaveBeenCalled();\n    });\n\n    describe('flushMaxRetries config', () => {\n      test('should use default config value if no max retries', async () => {\n        const sessionReplay = new SessionReplay();\n        await sessionReplay.init(apiKey, { ...mockOptions, flushMaxRetries: undefined }).promise;\n\n        expect(sessionReplay.config?.flushMaxRetries).toBe(2);\n      });\n      test('should cap max retries at default config value', async () => {\n        const sessionReplay = new SessionReplay();\n        await sessionReplay.init(apiKey, { ...mockOptions, flushMaxRetries: 10 }).promise;\n\n        expect(sessionReplay.config?.flushMaxRetries).toBe(2);\n      });\n      test('should allow a lower value than default config value', async () => {\n        const sessionReplay = new SessionReplay();\n        await sessionReplay.init(apiKey, { ...mockOptions, flushMaxRetries: 0 }).promise;\n\n        expect(sessionReplay.config?.flushMaxRetries).toBe(0);\n      });\n    });\n\n    test('should terminate previous eventCompressor on re-initialization', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      // Spy on terminate of the first eventCompressor\n      const terminateSpy = jest.spyOn(sessionReplay.eventCompressor!, 'terminate');\n      // Call init again to trigger terminate\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      expect(terminateSpy).toHaveBeenCalled();\n    });\n\n    test.each([\n      {\n        description: 'should call rrweb with applyBackgroundColorToBlockedElements=true when option is true',\n        options: { applyBackgroundColorToBlockedElements: true },\n        expectedValue: true,\n      },\n      {\n        description: 'should call rrweb with applyBackgroundColorToBlockedElements=false when option is false',\n        options: { applyBackgroundColorToBlockedElements: false },\n        expectedValue: false,\n      },\n      {\n        description: 'should call rrweb with applyBackgroundColorToBlockedElements=false when option is undefined',\n        options: { applyBackgroundColorToBlockedElements: undefined },\n        expectedValue: false,\n      },\n      {\n        description: 'should call rrweb with applyBackgroundColorToBlockedElements=false when option is not provided',\n        options: {},\n        expectedValue: false,\n      },\n    ])('$description', async ({ options, expectedValue }) => {\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, {\n        ...mockOptions,\n        ...options,\n      }).promise;\n      await sessionReplay.recordEvents();\n\n      const recordArg = mockRecordFunction.mock.calls[0][0];\n      expect(recordArg?.applyBackgroundColorToBlockedElements).toBe(expectedValue);\n    });\n\n    test.each([\n      {\n        description: 'should pass captureAdoptedStyleSheets=true to rrweb when option is true',\n        options: { captureAdoptedStyleSheets: true },\n        expectedValue: true,\n      },\n      {\n        description: 'should pass captureAdoptedStyleSheets=false to rrweb when option is false',\n        options: { captureAdoptedStyleSheets: false },\n        expectedValue: false,\n      },\n      {\n        description: 'should pass captureAdoptedStyleSheets=true to rrweb when option is not provided (default)',\n        options: {},\n        expectedValue: true,\n      },\n    ])('$description', async ({ options, expectedValue }) => {\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, {\n        ...mockOptions,\n        ...options,\n      }).promise;\n      await sessionReplay.recordEvents();\n\n      const recordArg = mockRecordFunction.mock.calls[0][0];\n      expect(recordArg?.captureAdoptedStyleSheets).toBe(expectedValue);\n    });\n\n    describe('background capture', () => {\n      let mockMessenger: { setup: jest.Mock };\n      let getOrCreateSpy: jest.SpyInstance;\n      let enableBgCaptureSpy: jest.SpyInstance;\n\n      beforeEach(() => {\n        mockMessenger = { setup: jest.fn() };\n        getOrCreateSpy = jest.spyOn(AnalyticsCore, 'getOrCreateWindowMessenger').mockReturnValue(mockMessenger as any);\n        enableBgCaptureSpy = jest.spyOn(AnalyticsCore, 'enableBackgroundCapture').mockImplementation(jest.fn());\n      });\n\n      test('should enable background capture when window.opener exists', async () => {\n        globalSpy = jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n          ...mockGlobalScope,\n          opener: {},\n        });\n\n        await sessionReplay.init(apiKey, mockOptions).promise;\n\n        expect(getOrCreateSpy).toHaveBeenCalled();\n        expect(enableBgCaptureSpy).toHaveBeenCalledWith(mockMessenger);\n        expect(mockMessenger.setup).toHaveBeenCalledTimes(1);\n        const setupArg = mockMessenger.setup.mock.calls[0][0];\n        expect(setupArg.endpoint).toBe(AnalyticsCore.AMPLITUDE_ORIGINS_MAP[mockOptions.serverZone!]);\n      });\n\n      test('should not enable background capture when window.opener is absent', async () => {\n        await sessionReplay.init(apiKey, mockOptions).promise;\n\n        expect(getOrCreateSpy).not.toHaveBeenCalled();\n        expect(enableBgCaptureSpy).not.toHaveBeenCalled();\n      });\n\n      test('should pass the correct endpoint for each server zone', async () => {\n        globalSpy = jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n          ...mockGlobalScope,\n          opener: {},\n        });\n\n        await sessionReplay.init(apiKey, {\n          ...mockOptions,\n          serverZone: ServerZone.US,\n        }).promise;\n\n        const setupArg = mockMessenger.setup.mock.calls[0][0];\n        expect(setupArg.endpoint).toBe(AnalyticsCore.AMPLITUDE_ORIGINS_MAP['US']);\n      });\n    });\n  });\n\n  describe('setSessionId', () => {\n    test('should stop recording events for current session', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      const stopRecordingMock = jest.fn();\n\n      // Mock class as if it has already been recording events\n      sessionReplay.sendEvents = stopRecordingMock;\n\n      sessionReplay.setSessionId(456);\n      expect(stopRecordingMock).toHaveBeenCalled();\n    });\n\n    test('should update the session id and start recording', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      // Clear any calls from initialization\n      mockRecordFunction.mockClear();\n\n      expect(sessionReplay.identifiers?.sessionId).toEqual(123);\n      expect(sessionReplay.identifiers?.sessionReplayId).toEqual('1a2b3c/123');\n      if (!sessionReplay.eventsManager || !sessionReplay.joinedConfigGenerator || !sessionReplay.config) {\n        throw new Error('Init not called');\n      }\n      const updatedConfig = { ...sessionReplay.config, sampleRate: 0.9 };\n      const generateJoinedConfigPromise = Promise.resolve({\n        joinedConfig: updatedConfig,\n        localConfig: updatedConfig,\n        remoteConfig: undefined,\n      });\n      jest\n        .spyOn(sessionReplay.joinedConfigGenerator, 'generateJoinedConfig')\n        .mockReturnValue(generateJoinedConfigPromise);\n\n      await sessionReplay.setSessionId(456).promise;\n\n      expect(sessionReplay.identifiers?.sessionId).toEqual(456);\n      expect(sessionReplay.identifiers?.sessionReplayId).toEqual('1a2b3c/456');\n      await generateJoinedConfigPromise;\n      // With targeting functionality, setSessionId triggers recording via evaluateTargetingAndCapture\n      // The function may be called multiple times due to focus listeners or other async operations\n      expect(mockRecordFunction).toHaveBeenCalled();\n      expect(sessionReplay.config).toEqual(updatedConfig);\n    });\n\n    test('should regenerate config', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      if (!sessionReplay.joinedConfigGenerator || !sessionReplay.eventsManager) {\n        throw new Error('Did not call init');\n      }\n      const mockUpdatedConfig = new SessionReplayLocalConfig('static_key', { ...mockOptions, sampleRate: 0.6 });\n      const mockSessionReplayConfigs = {\n        joinedConfig: mockUpdatedConfig,\n        localConfig: mockUpdatedConfig,\n        remoteConfig: undefined,\n      };\n      const generateJoinedConfig = jest\n        .spyOn(sessionReplay.joinedConfigGenerator, 'generateJoinedConfig')\n        .mockResolvedValue(mockSessionReplayConfigs);\n      expect(sessionReplay.identifiers?.sessionId).toEqual(123);\n      expect(sessionReplay.identifiers?.sessionReplayId).toEqual('1a2b3c/123');\n\n      await sessionReplay.setSessionId(456).promise;\n\n      expect(generateJoinedConfig).toHaveBeenCalledTimes(1);\n      expect(sessionReplay.config).toEqual(mockUpdatedConfig);\n    });\n\n    test('should not record if no config', async () => {\n      await sessionReplay.setSessionId(456).promise;\n\n      expect(mockRecordFunction).not.toHaveBeenCalled();\n    });\n\n    test('should update the device id if passed', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      sessionReplay.loggerProvider = mockLoggerProvider;\n\n      sessionReplay.setSessionId(456, '9l8m7n');\n      expect(sessionReplay.identifiers?.sessionId).toEqual(456);\n      expect(sessionReplay.identifiers?.sessionReplayId).toEqual('9l8m7n/456');\n      expect(sessionReplay.identifiers?.deviceId).toEqual('9l8m7n');\n      expect(sessionReplay.getDeviceId()).toEqual('9l8m7n');\n    });\n\n    test('should call asyncSetSessionId with userProperties when options provided', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      // Create a mock config with targeting config that will be returned by generateJoinedConfig\n      const mockConfigWithTargeting = new SessionReplayLocalConfig(apiKey, mockOptions);\n      (mockConfigWithTargeting as SessionReplayJoinedConfig).targetingConfig = {\n        key: 'sr_targeting_config',\n        variants: { on: { key: 'on' }, off: { key: 'off' } },\n        segments: [],\n      };\n\n      // Mock generateJoinedConfig to return config with targeting\n      const mockSessionReplayConfigs = {\n        joinedConfig: mockConfigWithTargeting,\n        localConfig: mockConfigWithTargeting,\n        remoteConfig: undefined,\n      };\n\n      jest\n        .spyOn(sessionReplay.joinedConfigGenerator!, 'generateJoinedConfig')\n        .mockResolvedValue(mockSessionReplayConfigs);\n\n      const evaluateTargetingAndCaptureSpy = jest.spyOn(sessionReplay, 'evaluateTargetingAndCapture');\n\n      // Test with userProperties\n      const userProperties = { age: 30, city: 'New York' };\n      await (sessionReplay as any).asyncSetSessionId(456, '9l8m7n', { userProperties });\n\n      expect(evaluateTargetingAndCaptureSpy).toHaveBeenCalledWith(\n        { userProperties, page: { url: 'http://localhost' } },\n        false,\n        true,\n      );\n\n      // Test without userProperties (options is undefined)\n      await (sessionReplay as any).asyncSetSessionId(789, '9l8m7n');\n\n      expect(evaluateTargetingAndCaptureSpy).toHaveBeenCalledWith(\n        { userProperties: undefined, page: { url: 'http://localhost' } },\n        false,\n        true,\n      );\n\n      // Test with empty options\n      await (sessionReplay as any).asyncSetSessionId(101, '9l8m7n', {});\n\n      expect(evaluateTargetingAndCaptureSpy).toHaveBeenCalledWith(\n        { userProperties: undefined, page: { url: 'http://localhost' } },\n        false,\n        true,\n      );\n    });\n\n    test('should call evaluateTargetingAndCapture with forceRestart true when targetingConfig exists', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      // Create a mock config with targeting config\n      const mockConfigWithTargeting = new SessionReplayLocalConfig(apiKey, mockOptions);\n      (mockConfigWithTargeting as SessionReplayJoinedConfig).targetingConfig = {\n        key: 'sr_targeting_config',\n        variants: { on: { key: 'on' }, off: { key: 'off' } },\n        segments: [],\n      };\n\n      const mockSessionReplayConfigs = {\n        joinedConfig: mockConfigWithTargeting,\n        localConfig: mockConfigWithTargeting,\n        remoteConfig: undefined,\n      };\n\n      jest\n        .spyOn(sessionReplay.joinedConfigGenerator!, 'generateJoinedConfig')\n        .mockResolvedValue(mockSessionReplayConfigs);\n\n      const evaluateTargetingAndCaptureSpy = jest.spyOn(sessionReplay, 'evaluateTargetingAndCapture');\n\n      // Simulate recording is already active\n      sessionReplay.recordCancelCallback = jest.fn();\n\n      await (sessionReplay as any).asyncSetSessionId(456, '9l8m7n');\n\n      // Verify that evaluateTargetingAndCapture was called with forceRestart = true\n      expect(evaluateTargetingAndCaptureSpy).toHaveBeenCalledWith(\n        { userProperties: undefined, page: { url: 'http://localhost' } },\n        false,\n        true,\n      );\n    });\n\n    test('should call recordEvents when no targetingConfig', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      const recordEventsSpy = jest.spyOn(sessionReplay, 'recordEvents');\n\n      await (sessionReplay as any).asyncSetSessionId(456, '9l8m7n');\n\n      expect(recordEventsSpy).toHaveBeenCalled();\n    });\n\n    test('should invalidate in-flight URL-change targeting evaluation on session change', async () => {\n      mockRemoteConfig = {\n        sr_sampling_config: samplingConfig,\n        sr_privacy_config: {},\n        sr_targeting_config: {\n          key: 'sr_targeting_config',\n          variants: { on: { key: 'on' }, off: { key: 'off' } },\n          segments: [],\n        },\n      };\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      const mockConfigWithTargeting = new SessionReplayLocalConfig(apiKey, mockOptions);\n      (mockConfigWithTargeting as SessionReplayJoinedConfig).targetingConfig = {\n        key: 'sr_targeting_config',\n        variants: { on: { key: 'on' }, off: { key: 'off' } },\n        segments: [],\n      };\n      jest.spyOn(sessionReplay.joinedConfigGenerator!, 'generateJoinedConfig').mockResolvedValue({\n        joinedConfig: mockConfigWithTargeting,\n        localConfig: mockConfigWithTargeting,\n        remoteConfig: undefined,\n      });\n\n      let resolveStaleEvaluation!: (value: boolean) => void;\n      const staleEvaluationPromise = new Promise<boolean>((resolve) => {\n        resolveStaleEvaluation = resolve;\n      });\n      jest\n        .spyOn(targetingManager, 'evaluateTargetingAndStore')\n        .mockImplementationOnce(() => staleEvaluationPromise)\n        .mockResolvedValueOnce(false);\n      sessionReplay.sessionTargetingMatch = false;\n\n      (\n        sessionReplay as unknown as {\n          latestUrlChangeTargetingEvaluationId: number;\n        }\n      ).latestUrlChangeTargetingEvaluationId = 1;\n\n      const staleUrlEvaluation = sessionReplay.evaluateTargetingAndCapture(\n        { page: { url: 'https://example.com/old-session-page' } },\n        false,\n        false,\n        true,\n      );\n\n      await (sessionReplay as any).asyncSetSessionId(456, '9l8m7n');\n      resolveStaleEvaluation(true);\n      await staleUrlEvaluation;\n\n      expect(sessionReplay.sessionTargetingMatch).toBe(false);\n      expect(\n        (\n          sessionReplay as unknown as {\n            latestUrlChangeTargetingEvaluationId: number;\n          }\n        ).latestUrlChangeTargetingEvaluationId,\n      ).toBe(2);\n    });\n\n    test('writes new session start time and removes previous session entry', async () => {\n      globalThis.localStorage.clear();\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      const prevKey = `AMP_SR_START_${apiKey.substring(0, 10)}_123`;\n      const nextKey = `AMP_SR_START_${apiKey.substring(0, 10)}_456`;\n      expect(globalThis.localStorage.getItem(prevKey)).not.toBeNull();\n\n      await (sessionReplay as any).asyncSetSessionId(456, '9l8m7n');\n\n      expect(globalThis.localStorage.getItem(prevKey)).toBeNull();\n      const newStart = Number(globalThis.localStorage.getItem(nextKey));\n      expect(newStart).toBe(sessionReplay.sessionStartTime);\n    });\n\n    test('preserves stored and in-memory start time when sessionId is unchanged', async () => {\n      globalThis.localStorage.clear();\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      if (!sessionReplay.config) throw new Error('init');\n      const key = `AMP_SR_START_${apiKey.substring(0, 10)}_123`;\n      // Pin a known start time so a regression (overwrite to Date.now()) is visible\n      // regardless of how Date.now() advances during the asyncSetSessionId call.\n      const pinned = 1_700_000_000_000;\n      sessionReplay.sessionStartTime = pinned;\n      globalThis.localStorage.setItem(key, String(pinned));\n      // Trip gate-decision state so we can assert it survives.\n      (sessionReplay as any).hasEmittedGateDecision = true;\n      (sessionReplay as any).suppressedSendCount = 7;\n\n      // Caller passes the current sessionId redundantly — must NOT restart the gate clock.\n      await (sessionReplay as any).asyncSetSessionId(123, '1a2b3c');\n\n      expect(Number(globalThis.localStorage.getItem(key))).toBe(pinned);\n      expect(sessionReplay.sessionStartTime).toBe(pinned);\n      // Per-session gate state must also be preserved.\n      expect((sessionReplay as any).hasEmittedGateDecision).toBe(true);\n      expect((sessionReplay as any).suppressedSendCount).toBe(7);\n    });\n\n    test('drops previous-session beacon buffer ONLY on real session change', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      if (!sessionReplay.rrwebEventManager) throw new Error('init');\n      const dropBeaconMock = jest.fn();\n      sessionReplay.rrwebEventManager.dropPendingBeaconEvents = dropBeaconMock;\n\n      // Redundant same-id call: buffer must NOT be dropped (it belongs to the continuing session).\n      await (sessionReplay as any).asyncSetSessionId(123, '1a2b3c');\n      expect(dropBeaconMock).not.toHaveBeenCalled();\n\n      // Real change: buffer MUST be dropped.\n      await (sessionReplay as any).asyncSetSessionId(456, '9l8m7n');\n      expect(dropBeaconMock).toHaveBeenCalledTimes(1);\n    });\n\n    test('drops previous-session beacon buffer on session transition', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      if (!sessionReplay.rrwebEventManager) throw new Error('init');\n      const dropBeaconMock = jest.fn();\n      sessionReplay.rrwebEventManager.dropPendingBeaconEvents = dropBeaconMock;\n\n      await (sessionReplay as any).asyncSetSessionId(456, '9l8m7n');\n\n      // Prevents the page-leave beacon path from misattributing previous-session\n      // events to the new session id.\n      expect(dropBeaconMock).toHaveBeenCalledTimes(1);\n    });\n\n    test('resets per-session gate-decision state on session change', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      if (!sessionReplay.eventsManager || !sessionReplay.config) throw new Error('init');\n      sessionReplay.eventsManager.sendCurrentSequenceEvents = jest.fn();\n      const addCustomSpy = jest.spyOn(sessionReplay, 'addCustomRRWebEvent').mockResolvedValue(undefined);\n      // Recording must be active for the gate-decision emission to fire.\n      sessionReplay.recordCancelCallback = jest.fn();\n      (sessionReplay as any).recordFunction = { addCustomEvent: jest.fn() };\n      sessionReplay.config.minSessionDurationMs = 1000;\n      sessionReplay.sessionStartTime = Date.now() - 5000;\n\n      // First send for session A emits gate-decision and trips hasEmittedGateDecision.\n      sessionReplay.sendEvents();\n      const sessionAGateCall = addCustomSpy.mock.calls.find((c) => c[0] === 'replay-gate-decision');\n      expect(sessionAGateCall).toBeDefined();\n      expect(sessionAGateCall?.[1]).toEqual(expect.objectContaining({ sessionId: 123 }));\n\n      await (sessionReplay as any).asyncSetSessionId(456, '9l8m7n');\n      // asyncSetSessionId regenerates the joined config; restore the threshold so the new\n      // session is gated identically to the prior one.\n      if (sessionReplay.config) sessionReplay.config.minSessionDurationMs = 1000;\n      // Drop calls from the session-id transition itself (debug-info / targeting-decision)\n      // so we can assert specifically that the next sendEvents re-emits gate-decision.\n      addCustomSpy.mockClear();\n      sessionReplay.sessionStartTime = Date.now() - 5000;\n      sessionReplay.sendEvents();\n      expect(addCustomSpy).toHaveBeenCalledWith(\n        'replay-gate-decision',\n        expect.objectContaining({ sessionId: 456, suppressedSendCount: 0 }),\n        false,\n      );\n    });\n  });\n\n  describe('getSessionId', () => {\n    test('should update session id', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      const stopRecordingMock = jest.fn();\n      expect(sessionReplay.getSessionId()).toEqual(mockOptions.sessionId);\n\n      // Mock class as if it has already been recording events\n      sessionReplay.sendEvents = stopRecordingMock;\n\n      sessionReplay.setSessionId(456);\n      expect(stopRecordingMock).toHaveBeenCalled();\n      expect(sessionReplay.getSessionId()).toEqual(456);\n    });\n\n    test('should return null if not initialized', () => {\n      expect(sessionReplay.getSessionId()).toBeUndefined();\n    });\n  });\n\n  describe('getSessionReplayProperties', () => {\n    test('should return an empty object if config not set', () => {\n      sessionReplay.loggerProvider = mockLoggerProvider;\n\n      const result = sessionReplay.getSessionReplayProperties();\n      expect(result).toEqual({});\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLoggerProvider.warn).toHaveBeenCalled();\n    });\n\n    test('should return an empty object if shouldRecord is false', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      sessionReplay.getShouldRecord = () => false;\n\n      const result = sessionReplay.getSessionReplayProperties();\n      expect(result).toEqual({});\n    });\n\n    test('should return the session recorded property if shouldRecord is true', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      sessionReplay.getShouldRecord = () => true;\n\n      const result = sessionReplay.getSessionReplayProperties();\n      expect(result).toEqual({\n        '[Amplitude] Session Replay ID': '1a2b3c/123',\n      });\n    });\n\n    test('should ignore focus handler when debug mode is on.', async () => {\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        ...mockGlobalScope,\n        document: {\n          hasFocus: () => false,\n        },\n      } as typeof globalThis);\n      await sessionReplay.init(apiKey, { ...mockOptions, debugMode: true }).promise;\n      const result = sessionReplay.getSessionReplayProperties();\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(result).toEqual({\n        '[Amplitude] Session Replay ID': '1a2b3c/123',\n        '[Amplitude] Session Replay Debug': '{\"appHash\":\"-109988594\"}',\n      });\n    });\n\n    test('should return session replay id property with null', async () => {\n      await sessionReplay.init(apiKey, { ...mockOptions }).promise;\n      sessionReplay.getShouldRecord = () => true;\n      if (sessionReplay.identifiers) {\n        sessionReplay.identifiers.sessionReplayId = undefined;\n      }\n\n      const result = sessionReplay.getSessionReplayProperties();\n      expect(result).toEqual({\n        '[Amplitude] Session Replay ID': null,\n      });\n    });\n\n    test('should return debug property', async () => {\n      await sessionReplay.init(apiKey, { ...mockOptions, debugMode: true }).promise;\n      sessionReplay.getShouldRecord = () => true;\n\n      const result = sessionReplay.getSessionReplayProperties();\n      expect(result).toEqual({\n        '[Amplitude] Session Replay ID': '1a2b3c/123',\n        '[Amplitude] Session Replay Debug': '{\"appHash\":\"-109988594\"}',\n      });\n    });\n\n    test('should add a custom rrweb event', async () => {\n      await sessionReplay.init(apiKey, { ...mockOptions, debugMode: true }).promise;\n      sessionReplay.addCustomRRWebEvent = jest.fn();\n      sessionReplay.getShouldRecord = () => true;\n\n      const result = sessionReplay.getSessionReplayProperties();\n      expect(sessionReplay.addCustomRRWebEvent).toHaveBeenCalledWith(\n        CustomRRwebEvent.GET_SR_PROPS,\n        {\n          shouldRecord: true,\n          eventProperties: result,\n        },\n        false,\n      );\n    });\n    test('should increment the event count', async () => {\n      await sessionReplay.init(apiKey, { ...mockOptions, debugMode: true }).promise;\n      expect(sessionReplay.eventCount).toBe(0);\n\n      sessionReplay.getSessionReplayProperties();\n      expect(sessionReplay.eventCount).toBe(1);\n    });\n    test('should add a custom rrweb event with storage info if event count is 10, then reset event count', async () => {\n      await sessionReplay.init(apiKey, { ...mockOptions, debugMode: true }).promise;\n      sessionReplay.addCustomRRWebEvent = jest.fn();\n      sessionReplay.getShouldRecord = () => true;\n      sessionReplay.eventCount = 10;\n\n      const result = sessionReplay.getSessionReplayProperties();\n      expect(sessionReplay.addCustomRRWebEvent).toHaveBeenCalledWith(\n        CustomRRwebEvent.GET_SR_PROPS,\n        {\n          shouldRecord: true,\n          eventProperties: result,\n        },\n        true,\n      );\n      expect(sessionReplay.eventCount).toEqual(1);\n    });\n  });\n\n  describe('initialize', () => {\n    test('should return early if session id not set', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      if (!sessionReplay.eventsManager || !sessionReplay.identifiers) {\n        throw new Error('Did not call init');\n      }\n      sessionReplay.identifiers.sessionId = undefined;\n      const sendStoredEventsSpy = jest.spyOn(sessionReplay.eventsManager, 'sendStoredEvents');\n      await sessionReplay.initialize(true);\n      expect(sendStoredEventsSpy).not.toHaveBeenCalled();\n    });\n    test('should return early if no identifiers', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      sessionReplay.identifiers = undefined;\n      if (!sessionReplay.eventsManager) {\n        throw new Error('Did not call init');\n      }\n      const sendStoredEventsSpy = jest.spyOn(sessionReplay.eventsManager, 'sendStoredEvents');\n      await sessionReplay.initialize(true);\n      expect(sendStoredEventsSpy).not.toHaveBeenCalled();\n    });\n    test('should return early if no device id', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      sessionReplay.getDeviceId = jest.fn().mockReturnValue(undefined);\n      if (!sessionReplay.eventsManager) {\n        throw new Error('Did not call init');\n      }\n      const sendStoredEventsSpy = jest.spyOn(sessionReplay.eventsManager, 'sendStoredEvents');\n      await sessionReplay.initialize(true);\n      expect(sendStoredEventsSpy).not.toHaveBeenCalled();\n    });\n    test('should send stored events and record events', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      await jest.runAllTimersAsync();\n\n      if (!sessionReplay.eventsManager) {\n        throw new Error('Did not call init');\n      }\n      const eventsManagerInitSpy = jest.spyOn(sessionReplay.eventsManager, 'sendStoredEvents');\n\n      // Override the exisiting global record function with a mock record function\n      const recordFunction = createMockRecordFunction();\n      const existingRecordFunction = jest.spyOn(SessionReplay.prototype, 'getRecordFunction' as any);\n      existingRecordFunction.mockResolvedValue(recordFunction);\n\n      await sessionReplay.initialize(true);\n      expect(eventsManagerInitSpy).toHaveBeenCalledWith({\n        deviceId: mockOptions.deviceId,\n      });\n\n      expect(recordFunction).toHaveBeenCalledTimes(1);\n    });\n    test('should not send stored events if shouldSendStoredEvents is false', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      await jest.runAllTimersAsync();\n\n      if (!sessionReplay.eventsManager) {\n        throw new Error('Did not call init');\n      }\n      const eventsManagerInitSpy = jest.spyOn(sessionReplay.eventsManager, 'sendStoredEvents');\n\n      // Override the exisiting global record function with a mock record function\n      const recordFunction = createMockRecordFunction();\n      const existingRecordFunction = jest.spyOn(SessionReplay.prototype, 'getRecordFunction' as any);\n      existingRecordFunction.mockResolvedValue(recordFunction);\n\n      await sessionReplay.initialize(false);\n\n      expect(eventsManagerInitSpy).not.toHaveBeenCalled();\n      expect(recordFunction).toHaveBeenCalledTimes(1);\n    });\n\n    test.each([\n      { enabled: true, expectedLength: 2 }, // scroll fn + beacon fn\n      { enabled: false, expectedLength: 1 }, // beacon fn only\n      { enabled: undefined, expectedLength: 1 }, // beacon fn only\n    ])('should not register scroll if interaction config not enabled', async ({ enabled, expectedLength }) => {\n      mockRemoteConfig = {\n        sr_sampling_config: samplingConfig,\n        sr_privacy_config: {},\n        sr_interaction_config: {\n          enabled,\n        },\n      };\n\n      await sessionReplay.init(apiKey, {\n        ...mockOptions,\n        sampleRate: 0.5,\n      }).promise;\n      await sessionReplay.initialize(true);\n      expect(sessionReplay.pageLeaveFns).toHaveLength(expectedLength);\n    });\n\n    test('should call recordEvents when called without params', async () => {\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      const recordEventsSpy = jest.spyOn(sessionReplay, 'recordEvents');\n      await sessionReplay.initialize();\n      expect(recordEventsSpy).toHaveBeenCalled();\n    });\n  });\n\n  describe('shouldOptOut', () => {\n    test('should return undefined if no config set', () => {\n      expect(sessionReplay.shouldOptOut()).toEqual(undefined);\n    });\n    test('should return opt out from identity store if set', async () => {\n      jest.spyOn(AnalyticsCore, 'getAnalyticsConnector').mockReturnValue({\n        identityStore: {\n          getIdentity: () => {\n            return {\n              optOut: true,\n            };\n          },\n        },\n      } as unknown as ReturnType<typeof AnalyticsCore.getAnalyticsConnector>);\n      await sessionReplay.init(apiKey, { ...mockOptions, instanceName: 'my_instance' }).promise;\n      expect(sessionReplay.shouldOptOut()).toEqual(true);\n    });\n    test('should return opt out from identity store even if set to false', async () => {\n      jest.spyOn(AnalyticsCore, 'getAnalyticsConnector').mockReturnValue({\n        identityStore: {\n          getIdentity: () => {\n            return {\n              optOut: false,\n            };\n          },\n        },\n      } as unknown as ReturnType<typeof AnalyticsCore.getAnalyticsConnector>);\n      await sessionReplay.init(apiKey, { ...mockOptions, instanceName: 'my_instance', optOut: true }).promise;\n      expect(sessionReplay.shouldOptOut()).toEqual(false);\n    });\n    test('should return config device id if set', async () => {\n      await sessionReplay.init(apiKey, { ...mockOptions, instanceName: 'my_instance', optOut: true }).promise;\n      expect(sessionReplay.shouldOptOut()).toEqual(true);\n    });\n  });\n\n  describe('getShouldRecord', () => {\n    test('should return true if there are options', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      const sampleRate = sessionReplay.config?.sampleRate;\n      expect(sampleRate).toBe(mockOptions.sampleRate);\n      const shouldRecord = sessionReplay.getShouldRecord();\n      expect(shouldRecord).toBe(true);\n    });\n    test('should return false if no options', async () => {\n      // Mock as if remote config call fails\n      mockRemoteConfig = null;\n      await sessionReplay.init(apiKey, mockEmptyOptions).promise;\n      const sampleRate = sessionReplay.config?.sampleRate;\n      expect(sampleRate).toBe(DEFAULT_SAMPLE_RATE);\n      const shouldRecord = sessionReplay.getShouldRecord();\n      expect(shouldRecord).toBe(false);\n    });\n    test('should return false if captureEnabled is false', async () => {\n      mockRemoteConfig = {\n        sr_sampling_config: {\n          capture_enabled: false,\n          sample_rate: 0.5,\n        },\n        sr_privacy_config: {},\n      };\n      await sessionReplay.init(apiKey, { ...mockOptions }).promise;\n      const shouldRecord = sessionReplay.getShouldRecord();\n      expect(shouldRecord).toBe(false);\n    });\n    test('should return false if session not included in sample rate', async () => {\n      // Mock as if remote config call fails\n      mockRemoteConfig = null;\n      jest.spyOn(Sampling, 'isSessionInSample').mockImplementationOnce(() => false);\n\n      await sessionReplay.init(apiKey, { ...mockOptions, sampleRate: 0.2 }).promise;\n      const sampleRate = sessionReplay.config?.sampleRate;\n      expect(sampleRate).toBe(0.2);\n      const shouldRecord = sessionReplay.getShouldRecord();\n      expect(shouldRecord).toBe(false);\n    });\n    test('should set record as true if session is included in sample rate', async () => {\n      await sessionReplay.init(apiKey, { ...mockOptions, sampleRate: 0.2 }).promise;\n      jest.spyOn(Sampling, 'isSessionInSample').mockImplementationOnce(() => true);\n      const shouldRecord = sessionReplay.getShouldRecord();\n      expect(shouldRecord).toBe(true);\n    });\n    test('should set record as false if opt out in config', async () => {\n      await sessionReplay.init(apiKey, { ...mockOptions, optOut: true }).promise;\n      const shouldRecord = sessionReplay.getShouldRecord();\n      expect(shouldRecord).toBe(false);\n    });\n    test('should set record as false if no session id', async () => {\n      await sessionReplay.init(apiKey, { ...mockOptions, sessionId: undefined }).promise;\n      const shouldRecord = sessionReplay.getShouldRecord();\n      expect(shouldRecord).toBe(false);\n    });\n    test('opt out in config should override the sample rate', async () => {\n      jest.spyOn(Math, 'random').mockImplementationOnce(() => 0.7);\n      await sessionReplay.init(apiKey, { ...mockOptions, sampleRate: 0.8, optOut: true }).promise;\n      const shouldRecord = sessionReplay.getShouldRecord();\n      expect(shouldRecord).toBe(false);\n    });\n    test('should return false if  no config', async () => {\n      const shouldRecord = sessionReplay.getShouldRecord();\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLoggerProvider.warn).not.toHaveBeenCalled();\n      expect(shouldRecord).toBe(false);\n    });\n    test('should set record as false if sample rate is too low', async () => {\n      await sessionReplay.init(apiKey, { ...mockOptions, sampleRate: 0.2 }).promise;\n      jest.spyOn(Sampling, 'isSessionInSample').mockImplementationOnce(() => false);\n      const shouldRecord = sessionReplay.getShouldRecord();\n      expect(shouldRecord).toBe(false);\n    });\n  });\n\n  describe('sendEventsViaBeacon', () => {\n    // The beacon logic is registered as the last entry in pageLeaveFns during initialize().\n    const triggerBeacon = (sr: SessionReplay) => {\n      const beaconFn = sr.pageLeaveFns[sr.pageLeaveFns.length - 1];\n      beaconFn(new Event('pagehide'));\n    };\n\n    test('should call sendBeacon with pending events on page exit', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      const mockSendBeacon = jest.fn().mockReturnValue(true);\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        navigator: { sendBeacon: mockSendBeacon },\n      } as unknown as typeof globalThis);\n\n      // Simulate pending events in the replay manager\n      const pendingEvent = JSON.stringify({ type: 3, timestamp: 1 });\n      if (!sessionReplay.eventsManager) throw new Error('No eventsManager');\n      sessionReplay.eventsManager.addEvent({\n        sessionId: 123,\n        event: { type: 'replay', data: pendingEvent },\n        deviceId: '1a2b3c',\n      });\n\n      triggerBeacon(sessionReplay);\n\n      expect(mockSendBeacon).toHaveBeenCalledTimes(1);\n      const [url, body] = mockSendBeacon.mock.calls[0] as [string, Blob];\n      expect(url).toContain('api_key=');\n      expect(url).toContain('device_id=1a2b3c');\n      expect(url).toContain('type=replay');\n      expect(body).toBeInstanceOf(Blob);\n      expect(body.type).toBe('application/json');\n    });\n\n    test('should not call sendBeacon if no pending events', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      const mockSendBeacon = jest.fn();\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        navigator: { sendBeacon: mockSendBeacon },\n      } as unknown as typeof globalThis);\n\n      triggerBeacon(sessionReplay);\n\n      expect(mockSendBeacon).not.toHaveBeenCalled();\n    });\n\n    test('should not call sendBeacon if no config', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      sessionReplay.config = undefined;\n      const mockSendBeacon = jest.fn();\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        navigator: { sendBeacon: mockSendBeacon },\n      } as unknown as typeof globalThis);\n\n      triggerBeacon(sessionReplay);\n\n      expect(mockSendBeacon).not.toHaveBeenCalled();\n    });\n\n    test('should not call sendBeacon if no device id', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      sessionReplay.identifiers!.deviceId = undefined;\n      const mockSendBeacon = jest.fn();\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        navigator: { sendBeacon: mockSendBeacon },\n      } as unknown as typeof globalThis);\n\n      if (!sessionReplay.eventsManager) throw new Error('No eventsManager');\n      sessionReplay.eventsManager.addEvent({\n        sessionId: 123,\n        event: { type: 'replay', data: 'x' },\n        deviceId: '1a2b3c',\n      });\n\n      triggerBeacon(sessionReplay);\n\n      expect(mockSendBeacon).not.toHaveBeenCalled();\n    });\n\n    test('should swallow sendBeacon errors', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      const mockSendBeacon = jest.fn().mockImplementation(() => {\n        throw new Error('beacon error');\n      });\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        navigator: { sendBeacon: mockSendBeacon },\n      } as unknown as typeof globalThis);\n\n      if (!sessionReplay.eventsManager) throw new Error('No eventsManager');\n      sessionReplay.eventsManager.addEvent({\n        sessionId: 123,\n        event: { type: 'replay', data: 'x' },\n        deviceId: '1a2b3c',\n      });\n\n      expect(() => {\n        triggerBeacon(sessionReplay);\n      }).not.toThrow();\n    });\n\n    test('should invoke beacon via pageLeaveFns on page exit', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      await sessionReplay.initialize(true);\n      const mockSendBeacon = jest.fn().mockReturnValue(true);\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        navigator: { sendBeacon: mockSendBeacon },\n      } as unknown as typeof globalThis);\n\n      if (!sessionReplay.eventsManager) throw new Error('No eventsManager');\n      sessionReplay.eventsManager.addEvent({\n        sessionId: 123,\n        event: { type: 'replay', data: 'x' },\n        deviceId: '1a2b3c',\n      });\n\n      // The beacon fn is always the last item added to pageLeaveFns during initialize()\n      const beaconFn = sessionReplay.pageLeaveFns[sessionReplay.pageLeaveFns.length - 1];\n      beaconFn(new Event('pagehide'));\n      expect(mockSendBeacon).toHaveBeenCalledTimes(1);\n    });\n\n    test('should not call sendBeacon if identifiers is undefined', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      (sessionReplay as any).identifiers = undefined;\n      const mockSendBeacon = jest.fn();\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        navigator: { sendBeacon: mockSendBeacon },\n      } as unknown as typeof globalThis);\n      triggerBeacon(sessionReplay);\n      expect(mockSendBeacon).not.toHaveBeenCalled();\n    });\n\n    test('should not call sendBeacon if no pending events in beacon buffer', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      const mockSendBeacon = jest.fn();\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        navigator: { sendBeacon: mockSendBeacon },\n      } as unknown as typeof globalThis);\n      // No events added — beacon buffer is empty\n      triggerBeacon(sessionReplay);\n      expect(mockSendBeacon).not.toHaveBeenCalled();\n    });\n\n    test('should not throw when globalScope is null', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      if (!sessionReplay.eventsManager) throw new Error('No eventsManager');\n      sessionReplay.eventsManager.addEvent({\n        sessionId: 123,\n        event: { type: 'replay', data: 'x' },\n        deviceId: '1a2b3c',\n      });\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue(null as unknown as typeof globalThis);\n      expect(() => {\n        triggerBeacon(sessionReplay);\n      }).not.toThrow();\n    });\n\n    test('should not throw when navigator is undefined', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      if (!sessionReplay.eventsManager) throw new Error('No eventsManager');\n      sessionReplay.eventsManager.addEvent({\n        sessionId: 123,\n        event: { type: 'replay', data: 'x' },\n        deviceId: '1a2b3c',\n      });\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({} as unknown as typeof globalThis);\n      expect(() => {\n        triggerBeacon(sessionReplay);\n      }).not.toThrow();\n    });\n\n    test('should not throw when sendBeacon is undefined', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      if (!sessionReplay.eventsManager) throw new Error('No eventsManager');\n      sessionReplay.eventsManager.addEvent({\n        sessionId: 123,\n        event: { type: 'replay', data: 'x' },\n        deviceId: '1a2b3c',\n      });\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        navigator: {},\n      } as unknown as typeof globalThis);\n      expect(() => {\n        triggerBeacon(sessionReplay);\n      }).not.toThrow();\n    });\n\n    test('should not call sendBeacon if session duration is below minSessionDurationMs', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      if (!sessionReplay.eventsManager || !sessionReplay.config) throw new Error('No eventsManager or config');\n      sessionReplay.config.minSessionDurationMs = 5000;\n      sessionReplay.sessionStartTime = Date.now() - 1000;\n      const mockSendBeacon = jest.fn().mockReturnValue(true);\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        navigator: { sendBeacon: mockSendBeacon },\n      } as unknown as typeof globalThis);\n      sessionReplay.eventsManager.addEvent({\n        sessionId: 123,\n        event: { type: 'replay', data: 'x' },\n        deviceId: '1a2b3c',\n      });\n      triggerBeacon(sessionReplay);\n      expect(mockSendBeacon).not.toHaveBeenCalled();\n    });\n\n    test('should call sendBeacon if session duration meets minSessionDurationMs', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      if (!sessionReplay.eventsManager || !sessionReplay.config) throw new Error('No eventsManager or config');\n      sessionReplay.config.minSessionDurationMs = 1000;\n      sessionReplay.sessionStartTime = Date.now() - 5000;\n      const mockSendBeacon = jest.fn().mockReturnValue(true);\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        navigator: { sendBeacon: mockSendBeacon },\n      } as unknown as typeof globalThis);\n      sessionReplay.eventsManager.addEvent({\n        sessionId: 123,\n        event: { type: 'replay', data: 'x' },\n        deviceId: '1a2b3c',\n      });\n      triggerBeacon(sessionReplay);\n      expect(mockSendBeacon).toHaveBeenCalledTimes(1);\n    });\n\n    test('should not call sendBeacon if rrwebEventManager failed to initialize', async () => {\n      // When createEventsManager throws for the 'replay' type, rrwebEventManager stays\n      // undefined in the pageLeaveFns closure — the beacon fn should handle this gracefully.\n      jest.spyOn(SessionReplayEventsManager, 'createEventsManager').mockRejectedValueOnce(new Error('init failed'));\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      const mockSendBeacon = jest.fn();\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        navigator: { sendBeacon: mockSendBeacon },\n      } as unknown as typeof globalThis);\n      triggerBeacon(sessionReplay);\n      expect(mockSendBeacon).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('sendEvents', () => {\n    test('it should send events for passed session', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      const sendEventsMock = jest.fn();\n      if (!sessionReplay.eventsManager) {\n        throw new Error('Did not call init');\n      }\n      sessionReplay.eventsManager.sendCurrentSequenceEvents = sendEventsMock;\n      sessionReplay.sendEvents(123);\n      expect(sendEventsMock).toHaveBeenCalledWith({\n        sessionId: 123,\n        deviceId: '1a2b3c',\n      });\n    });\n    test('it should send events for config session if none passed', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      const sendEventsMock = jest.fn();\n      if (!sessionReplay.eventsManager) {\n        throw new Error('Did not call init');\n      }\n      sessionReplay.eventsManager.sendCurrentSequenceEvents = sendEventsMock;\n      sessionReplay.sendEvents();\n      expect(sendEventsMock).toHaveBeenCalledWith({\n        sessionId: 123,\n        deviceId: '1a2b3c',\n      });\n    });\n    test('it should not send if no identifiers', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      sessionReplay.identifiers = undefined;\n      const sendEventsMock = jest.fn();\n      if (!sessionReplay.eventsManager) {\n        throw new Error('Did not call init');\n      }\n      sessionReplay.eventsManager.sendCurrentSequenceEvents = sendEventsMock;\n      sessionReplay.sendEvents();\n      expect(sendEventsMock).not.toHaveBeenCalled();\n    });\n    test('it should not send if session duration is below minSessionDurationMs', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      if (!sessionReplay.eventsManager || !sessionReplay.config || !sessionReplay.rrwebEventManager) {\n        throw new Error('Did not call init');\n      }\n      const sendEventsMock = jest.fn();\n      const dropBeaconMock = jest.fn();\n      sessionReplay.eventsManager.sendCurrentSequenceEvents = sendEventsMock;\n      sessionReplay.rrwebEventManager.dropPendingBeaconEvents = dropBeaconMock;\n      sessionReplay.config.minSessionDurationMs = 5000;\n      sessionReplay.sessionStartTime = Date.now() - 1000;\n      sessionReplay.sendEvents();\n      expect(sendEventsMock).not.toHaveBeenCalled();\n      // Beacon buffer is intentionally preserved here: a later send-after-pass within\n      // the same session may legitimately deliver these events via beacon on page exit.\n      // Cross-session leak is prevented in asyncSetSessionId instead.\n      expect(dropBeaconMock).not.toHaveBeenCalled();\n    });\n    test('it should not throw on below-threshold sendEvents when rrwebEventManager is undefined', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      if (!sessionReplay.eventsManager || !sessionReplay.config) {\n        throw new Error('Did not call init');\n      }\n      const sendEventsMock = jest.fn();\n      sessionReplay.eventsManager.sendCurrentSequenceEvents = sendEventsMock;\n      sessionReplay.rrwebEventManager = undefined;\n      sessionReplay.config.minSessionDurationMs = 5000;\n      sessionReplay.sessionStartTime = Date.now() - 1000;\n      expect(() => sessionReplay.sendEvents()).not.toThrow();\n      expect(sendEventsMock).not.toHaveBeenCalled();\n    });\n    test('it should send if minSessionDurationMs is set but sessionStartTime is undefined', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      if (!sessionReplay.eventsManager || !sessionReplay.config) {\n        throw new Error('Did not call init');\n      }\n      const sendEventsMock = jest.fn();\n      sessionReplay.eventsManager.sendCurrentSequenceEvents = sendEventsMock;\n      sessionReplay.config.minSessionDurationMs = 5000;\n      sessionReplay.sessionStartTime = undefined;\n      sessionReplay.sendEvents();\n      expect(sendEventsMock).toHaveBeenCalled();\n    });\n    test('it should send if config is undefined', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      if (!sessionReplay.eventsManager) {\n        throw new Error('Did not call init');\n      }\n      const sendEventsMock = jest.fn();\n      sessionReplay.eventsManager.sendCurrentSequenceEvents = sendEventsMock;\n      sessionReplay.config = undefined;\n      sessionReplay.sendEvents();\n      expect(sendEventsMock).toHaveBeenCalled();\n    });\n    test('it should send if session duration meets minSessionDurationMs', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      if (!sessionReplay.eventsManager || !sessionReplay.config) {\n        throw new Error('Did not call init');\n      }\n      const sendEventsMock = jest.fn();\n      sessionReplay.eventsManager.sendCurrentSequenceEvents = sendEventsMock;\n      sessionReplay.config.minSessionDurationMs = 1000;\n      sessionReplay.sessionStartTime = Date.now() - 5000;\n      sessionReplay.sendEvents();\n      expect(sendEventsMock).toHaveBeenCalledWith({\n        sessionId: 123,\n        deviceId: '1a2b3c',\n      });\n    });\n    test('emits REPLAY_GATE_DECISION on first send-after-pass with suppressed count', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      if (!sessionReplay.eventsManager || !sessionReplay.config) {\n        throw new Error('Did not call init');\n      }\n      sessionReplay.eventsManager.sendCurrentSequenceEvents = jest.fn();\n      const addCustomSpy = jest.spyOn(sessionReplay, 'addCustomRRWebEvent').mockResolvedValue(undefined);\n      // Recording must be active for the gate-decision event to fire; addCustomRRWebEvent\n      // is a no-op when recordCancelCallback / recordFunction are unset.\n      sessionReplay.recordCancelCallback = jest.fn();\n      (sessionReplay as any).recordFunction = { addCustomEvent: jest.fn() };\n      sessionReplay.config.minSessionDurationMs = 5000;\n\n      // First call: below threshold, suppressed.\n      sessionReplay.sessionStartTime = Date.now() - 1000;\n      sessionReplay.sendEvents();\n      // Second call: still below threshold, suppressed.\n      sessionReplay.sendEvents();\n      expect(addCustomSpy).not.toHaveBeenCalled();\n\n      // Third call: now above threshold — emits gate-decision event with the two prior suppressions.\n      sessionReplay.sessionStartTime = Date.now() - 6000;\n      sessionReplay.sendEvents();\n      expect(addCustomSpy).toHaveBeenCalledWith(\n        'replay-gate-decision',\n        expect.objectContaining({\n          sessionId: 123,\n          suppressedSendCount: 2,\n          minSessionDurationMs: 5000,\n          elapsedMs: expect.any(Number),\n        }),\n        false,\n      );\n\n      // Fourth call: subsequent send doesn't re-emit (once per session).\n      addCustomSpy.mockClear();\n      sessionReplay.sendEvents();\n      expect(addCustomSpy).not.toHaveBeenCalled();\n    });\n    test('does not emit REPLAY_GATE_DECISION when minSessionDurationMs is unset', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      if (!sessionReplay.eventsManager || !sessionReplay.config) {\n        throw new Error('Did not call init');\n      }\n      sessionReplay.eventsManager.sendCurrentSequenceEvents = jest.fn();\n      const addCustomSpy = jest.spyOn(sessionReplay, 'addCustomRRWebEvent').mockResolvedValue(undefined);\n      sessionReplay.recordCancelCallback = jest.fn();\n      (sessionReplay as any).recordFunction = { addCustomEvent: jest.fn() };\n      sessionReplay.config.minSessionDurationMs = undefined;\n      sessionReplay.sendEvents();\n      expect(addCustomSpy).not.toHaveBeenCalled();\n    });\n    test('does not emit or trip the gate-decision flag when recording is inactive', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      if (!sessionReplay.eventsManager || !sessionReplay.config) {\n        throw new Error('Did not call init');\n      }\n      sessionReplay.eventsManager.sendCurrentSequenceEvents = jest.fn();\n      const addCustomSpy = jest.spyOn(sessionReplay, 'addCustomRRWebEvent').mockResolvedValue(undefined);\n      sessionReplay.config.minSessionDurationMs = 5000;\n      sessionReplay.sessionStartTime = Date.now() - 6000;\n      // Recording not started yet — emission is a no-op so the flag must NOT trip.\n      sessionReplay.recordCancelCallback = null;\n      (sessionReplay as any).recordFunction = null;\n      sessionReplay.sendEvents();\n      expect(addCustomSpy).not.toHaveBeenCalled();\n\n      // Once recording activates, the next send should emit.\n      sessionReplay.recordCancelCallback = jest.fn();\n      (sessionReplay as any).recordFunction = { addCustomEvent: jest.fn() };\n      sessionReplay.sendEvents();\n      expect(addCustomSpy).toHaveBeenCalledWith(\n        'replay-gate-decision',\n        expect.objectContaining({ sessionId: 123 }),\n        false,\n      );\n    });\n    test('emits elapsedMs as undefined when sessionStartTime is missing at first send-after-pass', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      if (!sessionReplay.eventsManager || !sessionReplay.config) {\n        throw new Error('Did not call init');\n      }\n      sessionReplay.eventsManager.sendCurrentSequenceEvents = jest.fn();\n      const addCustomSpy = jest.spyOn(sessionReplay, 'addCustomRRWebEvent').mockResolvedValue(undefined);\n      sessionReplay.recordCancelCallback = jest.fn();\n      (sessionReplay as any).recordFunction = { addCustomEvent: jest.fn() };\n      sessionReplay.config.minSessionDurationMs = 5000;\n      // sessionStartTime undefined makes isBelowMinSessionDuration() return false, so the\n      // pass-path fires but elapsedMs can't be computed.\n      sessionReplay.sessionStartTime = undefined;\n      sessionReplay.sendEvents();\n      expect(addCustomSpy).toHaveBeenCalledWith(\n        'replay-gate-decision',\n        expect.objectContaining({ elapsedMs: undefined }),\n        false,\n      );\n    });\n  });\n  describe('stopRecordingEvents', () => {\n    test('it should catch errors as warnings', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      const mockStopRecordingEvents = jest.fn().mockImplementation(() => {\n        throw new Error('test error');\n      });\n      sessionReplay.recordCancelCallback = mockStopRecordingEvents;\n      sessionReplay.stopRecordingEvents();\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLoggerProvider.warn).toHaveBeenCalled();\n    });\n    test('it should call recordCancelCallback and set it to null', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      const mockStopRecordingEvents = jest.fn();\n      sessionReplay.recordCancelCallback = mockStopRecordingEvents;\n      sessionReplay.stopRecordingEvents();\n      expect(mockStopRecordingEvents).toHaveBeenCalled();\n      expect(sessionReplay.recordCancelCallback).toEqual(null);\n    });\n  });\n\n  describe('recordEvents', () => {\n    let createEventsIDBStoreInstance: SessionReplayIDB.SessionReplayEventsIDBStore;\n    beforeEach(async () => {\n      createEventsIDBStoreInstance = (await SessionReplayIDB.SessionReplayEventsIDBStore.new('replay', {\n        loggerProvider: mockLoggerProvider,\n        apiKey,\n      }))!;\n    });\n\n    test('should return early if no config', async () => {\n      // Spy on recordEvents to track calls\n      const recordEventsSpy = jest.spyOn(sessionReplay, 'recordEvents');\n\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      // Advance timers to allow any pending async operations to complete\n      jest.runAllTimers();\n\n      // Reset both spies after initialization\n      recordEventsSpy.mockClear();\n\n      // Now set config to undefined and call recordEvents\n      sessionReplay.config = undefined;\n\n      // Override the exisiting global record function with a mock record function\n      const recordFunction = createMockRecordFunction();\n      const existingRecordFunction = jest.spyOn(SessionReplay.prototype, 'getRecordFunction' as any);\n      existingRecordFunction.mockResolvedValue(recordFunction);\n\n      await sessionReplay.recordEvents();\n\n      // Verify recordEvents was called but mockRecordFunction was not\n      expect(recordEventsSpy).toHaveBeenCalledTimes(1);\n      expect(recordFunction).not.toHaveBeenCalled();\n\n      if (!sessionReplay.eventsManager) {\n        throw new Error('Did not call init');\n      }\n      const currentSequenceEvents = await createEventsIDBStoreInstance.getCurrentSequenceEvents(123);\n      expect(currentSequenceEvents).toEqual(undefined);\n\n      // Clean up spy\n      recordEventsSpy.mockRestore();\n    });\n    test('should return early if no identifiers', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      sessionReplay.identifiers = undefined;\n\n      // Override the exisiting global record function with a mock record function\n      const recordFunction = createMockRecordFunction();\n      const existingRecordFunction = jest.spyOn(SessionReplay.prototype, 'getRecordFunction' as any);\n      existingRecordFunction.mockResolvedValue(recordFunction);\n\n      await sessionReplay.recordEvents();\n\n      expect(recordFunction).not.toHaveBeenCalled();\n    });\n\n    test('should return early if user opts out', async () => {\n      await sessionReplay.init(apiKey, { ...mockOptions, optOut: true, privacyConfig: { blockSelector: ['#class'] } })\n        .promise;\n      await sessionReplay.recordEvents();\n      expect(mockRecordFunction).not.toHaveBeenCalled();\n      if (!sessionReplay.eventsManager) {\n        throw new Error('Did not call init');\n      }\n      const currentSequenceEvents = await createEventsIDBStoreInstance.getCurrentSequenceEvents(123);\n      expect(currentSequenceEvents).toEqual(undefined);\n    });\n\n    test('should stop recording before starting anew', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      // Drain any background recordEvents() call fired via `void initialize()`\n      await jest.runAllTimersAsync();\n      const stopRecordingMock = jest.fn();\n      sessionReplay.recordCancelCallback = stopRecordingMock;\n      await sessionReplay.recordEvents();\n      expect(stopRecordingMock).toHaveBeenCalled();\n    });\n\n    test('should stop recording and send events if user opts out during recording', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      await sessionReplay.recordEvents();\n      const stopRecordingMock = jest.fn();\n      sessionReplay.recordCancelCallback = stopRecordingMock;\n      if (!sessionReplay.eventsManager) {\n        throw new Error('Did not call init');\n      }\n      const currentSequenceEvents = await createEventsIDBStoreInstance.getCurrentSequenceEvents(123);\n      expect(currentSequenceEvents).toEqual(undefined);\n      await createEventsIDBStoreInstance.addEventToCurrentSequence(123, mockEventString); // Add one event to list to trigger sending in sendEvents\n      const sendEventsMock = jest.spyOn(sessionReplay.eventsManager, 'sendCurrentSequenceEvents');\n      sessionReplay.shouldOptOut = () => true;\n      const recordArg = mockRecordFunction.mock.calls[0][0];\n      recordArg?.emit && recordArg?.emit(mockEvent);\n      expect(sendEventsMock).toHaveBeenCalledTimes(1);\n      expect(sendEventsMock).toHaveBeenCalledWith({\n        sessionId: 123,\n        deviceId: '1a2b3c',\n      });\n      expect(stopRecordingMock).toHaveBeenCalled();\n      expect(sessionReplay.recordCancelCallback).toEqual(null);\n      // The emitted mockEvent must be ignored due to opt-out — opt-out path returns\n      // before any addEvent call.  After the (now atomic) storeCurrentSequence\n      // promotes the pre-existing mockEventString to sequencesToSend, the original\n      // event still exists exactly once in the combined view across both stores —\n      // no duplication, no extra event from the emit.\n      const updatedCurrentSequenceEvents = (await createEventsIDBStoreInstance.getCurrentSequenceEvents(123)) ?? [];\n      const sequencesToSend = (await createEventsIDBStoreInstance.getSequencesToSend()) ?? [];\n      const allEvents = [\n        ...updatedCurrentSequenceEvents.flatMap((s) => s.events),\n        ...sequencesToSend.flatMap((s) => s.events),\n      ];\n      expect(allEvents).toEqual([mockEventString]); // exactly the one pre-existing event\n    });\n\n    test('should add an error handler', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      await sessionReplay.recordEvents();\n      const recordArg = mockRecordFunction.mock.calls[0][0];\n      const errorHandlerReturn = recordArg?.errorHandler && recordArg?.errorHandler(new Error('test error'));\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLoggerProvider.warn).toHaveBeenCalled();\n      expect(errorHandlerReturn).toBe(true);\n    });\n\n    test('should enable all slim dom options by default', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      await sessionReplay.recordEvents();\n      const recordArg = mockRecordFunction.mock.calls[0][0];\n      expect(recordArg?.slimDOMOptions).toEqual({\n        script: true,\n        comment: true,\n        headFavicon: true,\n        headWhitespace: true,\n        headMetaDescKeywords: true,\n        headMetaSocial: true,\n        headMetaRobots: true,\n        headMetaHttpEquiv: true,\n        headMetaAuthorship: true,\n        headMetaVerification: true,\n      });\n    });\n\n    test('should pass fullSnapshotIntervalMs to record function as checkoutEveryNms when configured', async () => {\n      await sessionReplay.init(apiKey, { ...mockOptions, fullSnapshotIntervalMs: 300000 }).promise;\n      await sessionReplay.recordEvents();\n      const recordArg = mockRecordFunction.mock.calls[0][0];\n      expect(recordArg?.checkoutEveryNms).toBe(300000);\n    });\n\n    test('should not pass checkoutEveryNms to record function when fullSnapshotIntervalMs is not configured', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      await sessionReplay.recordEvents();\n      const recordArg = mockRecordFunction.mock.calls[0][0];\n      expect(recordArg?.checkoutEveryNms).toBeUndefined();\n    });\n\n    test('should rethrow CSSStylesheet errors', async () => {\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      await sessionReplay.recordEvents();\n      const recordArg = mockRecordFunction.mock.calls[0][0];\n      const stylesheetErrorMessage =\n        \"Failed to execute 'insertRule' on 'CSSStyleSheet': Failed to parse the rule 'body::-ms-expand{display: none}\";\n      expect(() => {\n        recordArg?.errorHandler && recordArg?.errorHandler(new Error(stylesheetErrorMessage));\n      }).toThrow(stylesheetErrorMessage);\n    });\n\n    test('should rethrow external errors', async () => {\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      await sessionReplay.recordEvents();\n      const recordArg = mockRecordFunction.mock.calls[0][0];\n      const error = new Error('test') as Error & { _external_?: boolean };\n      error._external_ = true;\n      expect(() => {\n        recordArg?.errorHandler && recordArg?.errorHandler(error);\n      }).toThrow(error);\n    });\n\n    test('should not add hooks if interaction config is not enabled', async () => {\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      await sessionReplay.recordEvents();\n      const recordArg = mockRecordFunction.mock.calls[0][0];\n      const error = new Error('test') as Error & { _external_?: boolean };\n      error._external_ = true;\n      expect(recordArg?.hooks).toStrictEqual({});\n    });\n\n    test('should add hooks if interaction config is enabled', async () => {\n      // enable interaction config\n      mockRemoteConfig = {\n        sr_sampling_config: samplingConfig,\n        sr_privacy_config: {},\n        sr_interaction_config: {\n          enabled: true,\n        },\n      };\n\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      await sessionReplay.recordEvents();\n      const recordArg = mockRecordFunction.mock.calls[0][0];\n      const error = new Error('test') as Error & { _external_?: boolean };\n      error._external_ = true;\n      expect(recordArg?.hooks?.mouseInteraction).toBeDefined();\n      expect(recordArg?.hooks?.scroll).toBeDefined();\n    });\n\n    test('should handle interaction config enabled without clickHandler initialized', async () => {\n      // enable interaction config\n      mockRemoteConfig = {\n        sr_sampling_config: samplingConfig,\n        sr_privacy_config: {},\n        sr_interaction_config: {\n          enabled: true,\n        },\n      };\n\n      const sessionReplay = new SessionReplay();\n      // Init without sessionId so clickHandler is not created\n      const optionsWithoutSessionId = { ...mockOptions };\n      delete optionsWithoutSessionId.sessionId;\n      await sessionReplay.init(apiKey, optionsWithoutSessionId).promise;\n\n      // Set sessionId after init — await so the internal recordEvents() call completes\n      await sessionReplay.setSessionId(123456).promise;\n\n      const recordArg = mockRecordFunction.mock.calls[0][0];\n      // mouseInteraction should be undefined because clickHandler was never initialized\n      expect(recordArg?.hooks?.mouseInteraction).toBeUndefined();\n      // scroll should still be undefined because scrollHook was never initialized either\n      expect(recordArg?.hooks?.scroll).toBeUndefined();\n    });\n\n    test('should warn if record throws during recordEvents', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      (mockRecordFunction as unknown as jest.Mock).mockImplementationOnce(() => {\n        throw new Error('record failed');\n      });\n      const warnSpy = jest.spyOn(sessionReplay.loggerProvider, 'warn');\n      await sessionReplay.recordEvents();\n      expect(warnSpy).toHaveBeenCalledWith('Failed to initialize session replay:', expect.any(Error));\n    });\n\n    test('should pass empty array for ugcFilterRules when not provided', async () => {\n      mockRemoteConfig = {\n        sr_sampling_config: samplingConfig,\n        sr_privacy_config: {},\n        sr_interaction_config: {\n          enabled: true,\n        },\n      };\n\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      await sessionReplay.recordEvents();\n      const recordArg = mockRecordFunction.mock.calls[0][0];\n      const mouseInteractionHook = recordArg?.hooks?.mouseInteraction;\n\n      expect(mouseInteractionHook).toBeDefined();\n      expect(mouseInteractionHook).toBeInstanceOf(Function);\n    });\n\n    test('should pass provided ugcFilterRules when configured', async () => {\n      const mockUgcFilterRules = ['rule1', 'rule2'];\n\n      mockRemoteConfig = {\n        sr_sampling_config: samplingConfig,\n        sr_privacy_config: {},\n        sr_interaction_config: {\n          enabled: true,\n          ugcFilterRules: mockUgcFilterRules,\n        },\n      };\n\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      await sessionReplay.recordEvents();\n      const recordArg = mockRecordFunction.mock.calls[0][0];\n      const mouseInteractionHook = recordArg?.hooks?.mouseInteraction;\n\n      expect(mouseInteractionHook).toBeDefined();\n      expect(mouseInteractionHook).toBeInstanceOf(Function);\n    });\n\n    test('should pass empty array for ugcFilterRules when explicitly set to empty', async () => {\n      mockRemoteConfig = {\n        sr_sampling_config: samplingConfig,\n        sr_privacy_config: {},\n        sr_interaction_config: {\n          enabled: true,\n          ugcFilterRules: [],\n        },\n      };\n\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      await sessionReplay.recordEvents();\n      const recordArg = mockRecordFunction.mock.calls[0][0];\n      const mouseInteractionHook = recordArg?.hooks?.mouseInteraction;\n\n      expect(mouseInteractionHook).toBeDefined();\n      expect(mouseInteractionHook).toBeInstanceOf(Function);\n    });\n\n    describe('emit callback - meta event URL filtering', () => {\n      test('should apply UGC filter rules to meta event href when interaction config is enabled and ugcFilterRules exist', async () => {\n        const mockUgcFilterRules = [{ selector: 'https://example.com/*', replacement: 'https://example.com/filtered' }];\n\n        mockRemoteConfig = {\n          sr_sampling_config: samplingConfig,\n          sr_privacy_config: {},\n          sr_interaction_config: {\n            enabled: true,\n            ugcFilterRules: mockUgcFilterRules,\n          },\n        };\n\n        const sessionReplay = new SessionReplay();\n        const getPageUrlSpy = jest.spyOn(Helpers, 'getPageUrl');\n        await sessionReplay.init(apiKey, mockOptions).promise;\n        await sessionReplay.recordEvents();\n\n        const recordArg = mockRecordFunction.mock.calls[0][0];\n        const metaEvent = {\n          type: 4,\n          data: { href: 'https://example.com/sensitive-page' },\n          timestamp: Date.now(),\n        };\n\n        // Simulate emitting a meta event\n        recordArg?.emit && recordArg?.emit(metaEvent);\n\n        expect(getPageUrlSpy).toHaveBeenCalledWith('https://example.com/sensitive-page', mockUgcFilterRules);\n        expect(metaEvent.data.href).toBe('https://example.com/filtered');\n      });\n\n      test('should not apply UGC filter rules to meta event when interaction config is disabled', async () => {\n        mockRemoteConfig = {\n          sr_sampling_config: samplingConfig,\n          sr_privacy_config: {},\n          sr_interaction_config: {\n            enabled: false,\n            ugcFilterRules: [{ selector: 'https://example.com/*', replacement: 'https://example.com/filtered' }],\n          },\n        };\n\n        const sessionReplay = new SessionReplay();\n        const getPageUrlSpy = jest.spyOn(Helpers, 'getPageUrl').mockReturnValue('https://example.com/sensitive-page');\n        await sessionReplay.init(apiKey, mockOptions).promise;\n        await sessionReplay.recordEvents();\n\n        const recordArg = mockRecordFunction.mock.calls[0][0];\n        const originalHref = 'https://example.com/sensitive-page';\n        const metaEvent = {\n          type: 4,\n          data: { href: originalHref },\n          timestamp: Date.now(),\n        };\n\n        // Simulate emitting a meta event\n        recordArg?.emit && recordArg?.emit(metaEvent);\n\n        expect(getPageUrlSpy).toHaveBeenCalledWith(originalHref, []);\n        expect(metaEvent.data.href).toBe(originalHref);\n      });\n\n      test('should not apply UGC filter rules to meta event when ugcFilterRules is undefined', async () => {\n        mockRemoteConfig = {\n          sr_sampling_config: samplingConfig,\n          sr_privacy_config: {},\n          sr_interaction_config: {\n            enabled: true,\n            ugcFilterRules: undefined,\n          },\n        };\n\n        const sessionReplay = new SessionReplay();\n        const getPageUrlSpy = jest.spyOn(Helpers, 'getPageUrl').mockReturnValue('https://example.com/sensitive-page');\n        await sessionReplay.init(apiKey, mockOptions).promise;\n        await sessionReplay.recordEvents();\n\n        const recordArg = mockRecordFunction.mock.calls[0][0];\n        const originalHref = 'https://example.com/sensitive-page';\n        const metaEvent = {\n          type: 4,\n          data: { href: originalHref },\n          timestamp: Date.now(),\n        };\n\n        // Simulate emitting a meta event\n        recordArg?.emit && recordArg?.emit(metaEvent);\n\n        expect(getPageUrlSpy).toHaveBeenCalledWith(originalHref, []);\n        expect(metaEvent.data.href).toBe(originalHref);\n      });\n\n      test('should call getPageUrl with empty array when ugcFilterRules is empty array', async () => {\n        const emptyUgcFilterRules: any[] = [];\n        mockRemoteConfig = {\n          sr_sampling_config: samplingConfig,\n          sr_privacy_config: {},\n          sr_interaction_config: {\n            enabled: true,\n            ugcFilterRules: emptyUgcFilterRules,\n          },\n        };\n\n        const sessionReplay = new SessionReplay();\n        const getPageUrlSpy = jest.spyOn(Helpers, 'getPageUrl').mockReturnValue('https://example.com/sensitive-page');\n        await sessionReplay.init(apiKey, mockOptions).promise;\n        await sessionReplay.recordEvents();\n\n        const recordArg = mockRecordFunction.mock.calls[0][0];\n        const originalHref = 'https://example.com/sensitive-page';\n        const metaEvent = {\n          type: 4,\n          data: { href: originalHref },\n          timestamp: Date.now(),\n        };\n\n        // Simulate emitting a meta event\n        recordArg?.emit && recordArg?.emit(metaEvent);\n\n        // Empty array is truthy, so getPageUrl should be called\n        expect(getPageUrlSpy).toHaveBeenCalledWith(originalHref, emptyUgcFilterRules);\n        expect(metaEvent.data.href).toBe(originalHref); // Since we mocked the return value to be the same\n      });\n\n      test('should not apply UGC filter rules to non-meta events', async () => {\n        const mockUgcFilterRules = [{ selector: 'https://example.com/*', replacement: 'https://example.com/filtered' }];\n        mockRemoteConfig = {\n          sr_sampling_config: samplingConfig,\n          sr_privacy_config: {},\n          sr_interaction_config: {\n            enabled: true,\n            ugcFilterRules: mockUgcFilterRules,\n          },\n        };\n\n        const sessionReplay = new SessionReplay();\n        const getPageUrlSpy = jest.spyOn(Helpers, 'getPageUrl');\n        await sessionReplay.init(apiKey, mockOptions).promise;\n        await sessionReplay.recordEvents();\n\n        const recordArg = mockRecordFunction.mock.calls[0][0];\n        const originalHref = 'https://example.com/sensitive-page';\n        const nonMetaEvent = {\n          type: 2, // Not a meta event (type 4)\n          data: { href: originalHref },\n          timestamp: Date.now(),\n        };\n\n        // Simulate emitting a non-meta event\n        recordArg?.emit && recordArg?.emit(nonMetaEvent);\n\n        expect(getPageUrlSpy).not.toHaveBeenCalled();\n        expect(nonMetaEvent.data.href).toBe(originalHref);\n      });\n\n      test('should handle meta event without href data', async () => {\n        const mockUgcFilterRules = [{ selector: 'https://example.com/*', replacement: 'https://example.com/filtered' }];\n        mockRemoteConfig = {\n          sr_sampling_config: samplingConfig,\n          sr_privacy_config: {},\n          sr_interaction_config: {\n            enabled: true,\n            ugcFilterRules: mockUgcFilterRules,\n          },\n        };\n\n        const sessionReplay = new SessionReplay();\n        const getPageUrlSpy = jest.spyOn(Helpers, 'getPageUrl');\n        await sessionReplay.init(apiKey, mockOptions).promise;\n        await sessionReplay.recordEvents();\n\n        const recordArg = mockRecordFunction.mock.calls[0][0];\n        const metaEvent = {\n          type: 4,\n          data: { width: 1728, height: 154 }, // No href property\n          timestamp: Date.now(),\n        };\n\n        // Simulate emitting a meta event without href\n        expect(() => {\n          recordArg?.emit && recordArg?.emit(metaEvent);\n        }).not.toThrow();\n\n        expect(getPageUrlSpy).toHaveBeenCalledWith(undefined, mockUgcFilterRules);\n      });\n\n      test('should not apply UGC filter rules when config is undefined', async () => {\n        mockRemoteConfig = {\n          sr_sampling_config: samplingConfig,\n          sr_privacy_config: {},\n          sr_interaction_config: {\n            enabled: true,\n            ugcFilterRules: [{ selector: 'https://example.com/*', replacement: 'https://example.com/filtered' }],\n          },\n        };\n\n        const sessionReplay = new SessionReplay();\n        const getPageUrlSpy = jest.spyOn(Helpers, 'getPageUrl').mockReturnValue('https://example.com/sensitive-page');\n        await sessionReplay.init(apiKey, mockOptions).promise;\n        await sessionReplay.recordEvents();\n\n        // Set config to undefined to test optional chaining\n        sessionReplay.config = undefined;\n\n        const recordArg = mockRecordFunction.mock.calls[0][0];\n        const originalHref = 'https://example.com/sensitive-page';\n        const metaEvent = {\n          type: 4,\n          data: { href: originalHref },\n          timestamp: Date.now(),\n        };\n\n        // Simulate emitting a meta event when config is undefined\n        expect(() => {\n          recordArg?.emit && recordArg?.emit(metaEvent);\n        }).not.toThrow();\n\n        // Note: ugcFilterRules was set during initialization, so it will use the configured rules\n        expect(getPageUrlSpy).toHaveBeenCalledWith(originalHref, [\n          { selector: 'https://example.com/*', replacement: 'https://example.com/filtered' },\n        ]);\n        expect(metaEvent.data.href).toBe(originalHref);\n      });\n\n      test('should not apply UGC filter rules when interactionConfig is undefined', async () => {\n        mockRemoteConfig = {\n          sr_sampling_config: samplingConfig,\n          sr_privacy_config: {},\n          sr_interaction_config: undefined,\n        };\n\n        const sessionReplay = new SessionReplay();\n        const getPageUrlSpy = jest.spyOn(Helpers, 'getPageUrl').mockReturnValue('https://example.com/sensitive-page');\n        await sessionReplay.init(apiKey, mockOptions).promise;\n        await sessionReplay.recordEvents();\n\n        const recordArg = mockRecordFunction.mock.calls[0][0];\n        const originalHref = 'https://example.com/sensitive-page';\n        const metaEvent = {\n          type: 4,\n          data: { href: originalHref },\n          timestamp: Date.now(),\n        };\n\n        // Simulate emitting a meta event when interactionConfig is undefined\n        expect(() => {\n          recordArg?.emit && recordArg?.emit(metaEvent);\n        }).not.toThrow();\n\n        expect(getPageUrlSpy).toHaveBeenCalledWith(originalHref, []);\n        expect(metaEvent.data.href).toBe(originalHref);\n      });\n\n      test('should not apply UGC filter rules when config exists but interactionConfig is null', async () => {\n        mockRemoteConfig = {\n          sr_sampling_config: samplingConfig,\n          sr_privacy_config: {},\n          sr_interaction_config: {\n            enabled: true,\n            ugcFilterRules: [{ selector: 'https://example.com/*', replacement: 'https://example.com/filtered' }],\n          },\n        };\n\n        const sessionReplay = new SessionReplay();\n        const getPageUrlSpy = jest.spyOn(Helpers, 'getPageUrl').mockReturnValue('https://example.com/sensitive-page');\n        await sessionReplay.init(apiKey, mockOptions).promise;\n        await sessionReplay.recordEvents();\n\n        // Manually set interactionConfig to null to test optional chaining\n        if (sessionReplay.config) {\n          (sessionReplay.config as any).interactionConfig = null;\n        }\n\n        const recordArg = mockRecordFunction.mock.calls[0][0];\n        const originalHref = 'https://example.com/sensitive-page';\n        const metaEvent = {\n          type: 4,\n          data: { href: originalHref },\n          timestamp: Date.now(),\n        };\n\n        // Simulate emitting a meta event when interactionConfig is null\n        expect(() => {\n          recordArg?.emit && recordArg?.emit(metaEvent);\n        }).not.toThrow();\n\n        // Note: ugcFilterRules was set during initialization, so it will use the configured rules\n        expect(getPageUrlSpy).toHaveBeenCalledWith(originalHref, [\n          { selector: 'https://example.com/*', replacement: 'https://example.com/filtered' },\n        ]);\n        expect(metaEvent.data.href).toBe(originalHref);\n      });\n\n      test('should not apply UGC filter rules when ugcFilterRules is explicitly null', async () => {\n        mockRemoteConfig = {\n          sr_sampling_config: samplingConfig,\n          sr_privacy_config: {},\n          sr_interaction_config: {\n            enabled: true,\n            ugcFilterRules: null,\n          },\n        };\n\n        const sessionReplay = new SessionReplay();\n        const getPageUrlSpy = jest.spyOn(Helpers, 'getPageUrl').mockReturnValue('https://example.com/sensitive-page');\n        await sessionReplay.init(apiKey, mockOptions).promise;\n        await sessionReplay.recordEvents();\n\n        const recordArg = mockRecordFunction.mock.calls[0][0];\n        const originalHref = 'https://example.com/sensitive-page';\n        const metaEvent = {\n          type: 4,\n          data: { href: originalHref },\n          timestamp: Date.now(),\n        };\n\n        // Simulate emitting a meta event when ugcFilterRules is null\n        expect(() => {\n          recordArg?.emit && recordArg?.emit(metaEvent);\n        }).not.toThrow();\n\n        expect(getPageUrlSpy).toHaveBeenCalledWith(originalHref, []);\n        expect(metaEvent.data.href).toBe(originalHref);\n      });\n    });\n\n    describe('recordEventsInFlight guard', () => {\n      test('concurrent call sets pending and _recordEvents runs twice total', async () => {\n        await sessionReplay.init(apiKey, mockOptions).promise;\n        // Drain the background recordEvents() fired by `void initialize()` during init\n        await jest.runAllTimersAsync();\n\n        // Make _recordEvents hang until we resolve this promise, simulating in-flight async work\n        let resolveInFlight: () => void;\n        const inFlightBarrier = new Promise<void>((res) => {\n          resolveInFlight = res;\n        });\n\n        const recordFunctionForGuardTest = createMockRecordFunction();\n        jest.spyOn(SessionReplay.prototype, 'getRecordFunction' as any).mockImplementation(async () => {\n          await inFlightBarrier;\n          return recordFunctionForGuardTest;\n        });\n\n        // Start first call (will be suspended at the barrier)\n        const first = sessionReplay.recordEvents();\n        // Second call should see in-flight=true, set pending=true, and return immediately\n        const second = sessionReplay.recordEvents();\n        expect((sessionReplay as any).recordEventsPendingShouldLogMetadata).toBe(true);\n\n        // Let the first call complete — it will then replay _recordEvents for the pending call\n        resolveInFlight!();\n        await Promise.all([first, second]);\n\n        // _recordEvents ran once for the original call and once for the pending replay\n        expect(recordFunctionForGuardTest).toHaveBeenCalledTimes(2);\n        expect((sessionReplay as any).recordEventsInFlight).toBe(false);\n        expect((sessionReplay as any).recordEventsPendingShouldLogMetadata).toBeNull();\n      });\n\n      test('guard resets to false after successful completion', async () => {\n        await sessionReplay.init(apiKey, mockOptions).promise;\n        await jest.runAllTimersAsync();\n\n        await sessionReplay.recordEvents();\n        expect((sessionReplay as any).recordEventsInFlight).toBe(false);\n\n        // A second sequential call should also complete normally\n        const recordFunctionAfter = createMockRecordFunction();\n        jest.spyOn(SessionReplay.prototype, 'getRecordFunction' as any).mockResolvedValue(recordFunctionAfter);\n        await sessionReplay.recordEvents();\n\n        expect(recordFunctionAfter).toHaveBeenCalledTimes(1);\n        expect((sessionReplay as any).recordEventsInFlight).toBe(false);\n      });\n\n      test('guard resets to false after _recordEvents throws', async () => {\n        await sessionReplay.init(apiKey, mockOptions).promise;\n        await jest.runAllTimersAsync();\n\n        // Simulate a throw inside the try/catch in _recordEvents (recordFunction() call throws)\n        (mockRecordFunction as unknown as jest.Mock).mockImplementationOnce(() => {\n          throw new Error('record failed');\n        });\n\n        // Should not propagate — the throw is caught by the try/catch inside _recordEvents\n        await sessionReplay.recordEvents();\n\n        expect((sessionReplay as any).recordEventsInFlight).toBe(false);\n\n        // Subsequent call proceeds normally\n        const recordFunctionAfterError = createMockRecordFunction();\n        jest.spyOn(SessionReplay.prototype, 'getRecordFunction' as any).mockResolvedValue(recordFunctionAfterError);\n        await sessionReplay.recordEvents();\n        expect(recordFunctionAfterError).toHaveBeenCalledTimes(1);\n      });\n\n      test('sequential calls both run _recordEvents fully', async () => {\n        await sessionReplay.init(apiKey, mockOptions).promise;\n        await jest.runAllTimersAsync();\n\n        const rf1 = createMockRecordFunction();\n        const rf2 = createMockRecordFunction();\n        const getRecordFunctionSpy = jest.spyOn(SessionReplay.prototype, 'getRecordFunction' as any);\n        getRecordFunctionSpy.mockResolvedValueOnce(rf1).mockResolvedValueOnce(rf2);\n\n        await sessionReplay.recordEvents();\n        await sessionReplay.recordEvents();\n\n        expect(rf1).toHaveBeenCalledTimes(1);\n        expect(rf2).toHaveBeenCalledTimes(1);\n        expect((sessionReplay as any).recordEventsInFlight).toBe(false);\n      });\n\n      test('_recordEvents default shouldLogMetadata param is true when called without argument', async () => {\n        await sessionReplay.init(apiKey, mockOptions).promise;\n        await jest.runAllTimersAsync();\n        // Call the private method directly without passing shouldLogMetadata to exercise the default=true branch\n        await (sessionReplay as any)._recordEvents();\n        expect(mockRecordFunction).toHaveBeenCalled();\n      });\n\n      test('_recordEvents returns early when identifiers is null', async () => {\n        await sessionReplay.init(apiKey, mockOptions).promise;\n        await jest.runAllTimersAsync();\n        // Force identifiers to null so this.identifiers?.sessionId takes the nullish branch\n        (sessionReplay as any).identifiers = null;\n        mockRecordFunction.mockClear();\n        await (sessionReplay as any)._recordEvents();\n        expect(mockRecordFunction).not.toHaveBeenCalled();\n      });\n\n      test('_recordEvents passes undefined performanceOptions when performanceConfig is undefined', async () => {\n        mockRemoteConfig = {\n          sr_sampling_config: samplingConfig,\n          sr_privacy_config: {},\n          sr_interaction_config: { enabled: true },\n        };\n        await sessionReplay.init(apiKey, mockOptions).promise;\n        await jest.runAllTimersAsync();\n        // Force performanceConfig to undefined so config.performanceConfig?.interaction takes the nullish branch\n        if (sessionReplay.config) {\n          (sessionReplay.config as any).performanceConfig = undefined;\n        }\n        await (sessionReplay as any)._recordEvents();\n        expect(mockRecordFunction).toHaveBeenCalled();\n        const recordArg = mockRecordFunction.mock.calls[0][0];\n        expect(recordArg?.hooks?.mouseInteraction).toBeDefined();\n      });\n\n      test('pending call is replayed after in-flight completes, picking up updated state', async () => {\n        await sessionReplay.init(apiKey, mockOptions).promise;\n        await jest.runAllTimersAsync();\n\n        // Suspend the first _recordEvents at getRecordFunction\n        let resolveInFlight: () => void;\n        const inFlightBarrier = new Promise<void>((res) => {\n          resolveInFlight = res;\n        });\n\n        const rf1 = createMockRecordFunction();\n        const rf2 = createMockRecordFunction();\n        let callCount = 0;\n        jest.spyOn(SessionReplay.prototype, 'getRecordFunction' as any).mockImplementation(async () => {\n          callCount++;\n          if (callCount === 1) {\n            await inFlightBarrier;\n            return rf1;\n          }\n          // Simulate state change: new sessionId visible on the second (pending replay) run\n          sessionReplay.identifiers = { ...sessionReplay.identifiers!, sessionId: 999 };\n          return rf2;\n        });\n\n        const first = sessionReplay.recordEvents();\n        // Fire concurrent call while first is suspended — sets pending flag\n        const second = sessionReplay.recordEvents();\n        expect((sessionReplay as any).recordEventsPendingShouldLogMetadata).toBe(true);\n\n        resolveInFlight!();\n        await Promise.all([first, second]);\n\n        // rf1 called for the original run, rf2 for the pending replay with updated sessionId\n        expect(rf1).toHaveBeenCalledTimes(1);\n        expect(rf2).toHaveBeenCalledTimes(1);\n        // State is fully reset\n        expect((sessionReplay as any).recordEventsInFlight).toBe(false);\n        expect((sessionReplay as any).recordEventsPendingShouldLogMetadata).toBeNull();\n        // The pending replay picked up the new sessionId\n        expect(sessionReplay.identifiers?.sessionId).toBe(999);\n      });\n\n      test('concurrent call during replay is also picked up — _recordEvents runs three times total', async () => {\n        await sessionReplay.init(apiKey, mockOptions).promise;\n        await jest.runAllTimersAsync();\n\n        let resolveFirst: () => void;\n        let notifyReplayStarted: () => void;\n        let resolveReplay: () => void;\n        const firstBarrier = new Promise<void>((res) => {\n          resolveFirst = res;\n        });\n        // Signal from mock to test: replay _recordEvents has started\n        const replayStarted = new Promise<void>((res) => {\n          notifyReplayStarted = res;\n        });\n        // Signal from test to mock: let the replay _recordEvents finish\n        const replayBarrier = new Promise<void>((res) => {\n          resolveReplay = res;\n        });\n\n        const rf1 = createMockRecordFunction();\n        const rf2 = createMockRecordFunction();\n        const rf3 = createMockRecordFunction();\n        let callCount = 0;\n        jest.spyOn(SessionReplay.prototype, 'getRecordFunction' as any).mockImplementation(async () => {\n          callCount++;\n          if (callCount === 1) {\n            await firstBarrier;\n            return rf1;\n          }\n          if (callCount === 2) {\n            notifyReplayStarted();\n            await replayBarrier;\n            return rf2;\n          }\n          return rf3;\n        });\n\n        // First call — suspended at firstBarrier\n        const first = sessionReplay.recordEvents();\n\n        // Second call while first is in-flight — sets pending\n        void sessionReplay.recordEvents();\n        expect((sessionReplay as any).recordEventsPendingShouldLogMetadata).toBe(true);\n\n        // Unblock first run; while loop clears pending and starts the replay\n        resolveFirst!();\n\n        // Wait until the replay _recordEvents has actually started before firing the third call\n        await replayStarted;\n\n        // Third concurrent call arrives while replay is in-flight — sets pending again\n        void sessionReplay.recordEvents();\n        expect((sessionReplay as any).recordEventsPendingShouldLogMetadata).toBe(true);\n\n        // Unblock the replay; while loop fires one more _recordEvents (rf3) and exits\n        resolveReplay!();\n        await first;\n        await jest.runAllTimersAsync();\n\n        expect(rf1).toHaveBeenCalledTimes(1);\n        expect(rf2).toHaveBeenCalledTimes(1);\n        expect(rf3).toHaveBeenCalledTimes(1);\n        expect((sessionReplay as any).recordEventsInFlight).toBe(false);\n        expect((sessionReplay as any).recordEventsPendingShouldLogMetadata).toBeNull();\n      });\n    });\n\n    describe('pendingEmitEvents — eventCompressor not yet ready', () => {\n      test('FullSnapshot emitted before eventCompressor is ready is buffered and flushed once compressor is assigned', async () => {\n        await sessionReplay.init(apiKey, mockOptions).promise;\n        await jest.runAllTimersAsync();\n\n        // Simulate the race: null out eventCompressor as it would be before _init() line 283\n        const realCompressor = sessionReplay.eventCompressor!;\n        sessionReplay.eventCompressor = undefined;\n\n        // Run _recordEvents() — simulates a concurrent setSessionId() call during _init()'s async gap\n        const concurrentRf = createMockRecordFunction();\n        jest.spyOn(SessionReplay.prototype, 'getRecordFunction' as any).mockResolvedValueOnce(concurrentRf);\n        await (sessionReplay as any)._recordEvents();\n\n        // Grab the emit callback passed to the concurrent record function\n        const concurrentEmit = concurrentRf.mock.calls[0]?.[0]?.emit;\n        expect(concurrentEmit).toBeDefined();\n\n        // Fire a FullSnapshot event through the emit callback\n        const fullSnapshotEvent = { type: 2, timestamp: Date.now(), data: { node: {}, initialOffset: {} } };\n        concurrentEmit(fullSnapshotEvent);\n\n        // Event should be buffered — not yet forwarded to eventsManager\n        expect((sessionReplay as any).pendingEmitEvents).toHaveLength(1);\n        expect((sessionReplay as any).pendingEmitEvents[0].event).toBe(fullSnapshotEvent);\n\n        // Now simulate _init() completing: restore eventCompressor and drain the buffer\n        sessionReplay.eventCompressor = realCompressor;\n        const enqueueSpy = jest.spyOn(realCompressor, 'enqueueEvent');\n        const pending = (sessionReplay as any).pendingEmitEvents.splice(0);\n        for (const { event, sessionId } of pending) {\n          sessionReplay.eventCompressor.enqueueEvent(event, sessionId);\n        }\n\n        // The buffered FullSnapshot was delivered to the compressor\n        expect(enqueueSpy).toHaveBeenCalledTimes(1);\n        expect(enqueueSpy).toHaveBeenCalledWith(fullSnapshotEvent, expect.anything());\n      });\n\n      test('after _init() assigns eventCompressor, subsequent emit calls go directly without buffering', async () => {\n        await sessionReplay.init(apiKey, mockOptions).promise;\n        await jest.runAllTimersAsync();\n\n        // With a real eventCompressor set, emit should not populate pendingEmitEvents\n        expect(sessionReplay.eventCompressor).toBeDefined();\n        const enqueueSpy = jest.spyOn(sessionReplay.eventCompressor!, 'enqueueEvent');\n\n        await (sessionReplay as any)._recordEvents();\n        const recordArg = mockRecordFunction.mock.calls[mockRecordFunction.mock.calls.length - 1]?.[0];\n        const emitFn = recordArg?.emit;\n        expect(emitFn).toBeDefined();\n\n        const event = { type: 2, timestamp: Date.now(), data: { node: {}, initialOffset: {} } };\n        emitFn(event);\n\n        expect((sessionReplay as any).pendingEmitEvents).toHaveLength(0);\n        expect(enqueueSpy).toHaveBeenCalledWith(event, expect.anything());\n      });\n\n      test('pre-buffered events are drained into eventCompressor when _init() assigns it', async () => {\n        // Pre-populate the buffer to simulate events that arrived during _init()'s async gap\n        const bufferedEvent1 = { type: 2, timestamp: 1, data: { node: {}, initialOffset: {} } };\n        const bufferedEvent2 = { type: 3, timestamp: 2, data: {} };\n        (sessionReplay as any).pendingEmitEvents.push({ event: bufferedEvent1, sessionId: 'session-a' });\n        (sessionReplay as any).pendingEmitEvents.push({ event: bufferedEvent2, sessionId: 'session-b' });\n\n        await sessionReplay.init(apiKey, mockOptions).promise;\n        await jest.runAllTimersAsync();\n\n        // _init() should have drained the buffer into the freshly-assigned eventCompressor\n        expect((sessionReplay as any).pendingEmitEvents).toHaveLength(0);\n        expect(sessionReplay.eventCompressor).toBeDefined();\n      });\n    });\n  });\n\n  describe('getDeviceId', () => {\n    test('should return undefined if no config set', () => {\n      expect(sessionReplay.getDeviceId()).toEqual(undefined);\n    });\n    test('should return config device id if set', async () => {\n      await sessionReplay.init(apiKey, { ...mockOptions, instanceName: 'my_instance' }).promise;\n      expect(sessionReplay.getDeviceId()).toEqual(mockOptions.deviceId);\n    });\n    test('should be consistent with session replay id', async () => {\n      await sessionReplay.init(apiKey, { ...mockOptions, instanceName: 'my_instance' }).promise;\n      const deviceIdFromSRId = sessionReplay.identifiers?.sessionReplayId?.split('/')[0];\n      expect(sessionReplay.getDeviceId()).toEqual(deviceIdFromSRId);\n    });\n  });\n\n  describe('flush', () => {\n    test('should do nothing on flush if init not called', async () => {\n      await sessionReplay.flush(true);\n      expect(sessionReplay.eventsManager).toBeUndefined();\n    });\n    test('should call track destination flush with useRetry as true', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      if (!sessionReplay.eventsManager) {\n        throw new Error('Did not call init');\n      }\n      const flushMock = jest.spyOn(sessionReplay.eventsManager, 'flush');\n\n      await sessionReplay.flush(true);\n      expect(flushMock).toHaveBeenCalled();\n      expect(flushMock).toHaveBeenCalledWith(true);\n    });\n    test('should call track destination flush without useRetry', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      if (!sessionReplay.eventsManager) {\n        throw new Error('Did not call init');\n      }\n      const flushMock = jest.spyOn(sessionReplay.eventsManager, 'flush');\n      await sessionReplay.flush();\n      expect(flushMock).toHaveBeenCalled();\n      expect(flushMock).toHaveBeenCalledWith(false);\n    });\n  });\n\n  describe('shutdown', () => {\n    test('should remove event listeners', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      removeEventListenerMock.mockReset();\n      sessionReplay.shutdown();\n      expect(removeEventListenerMock).toHaveBeenCalledTimes(3); // blur, focus, beforeunload - popstate handled by plugin cleanup\n      expect(removeEventListenerMock.mock.calls[0][0]).toEqual('blur');\n      expect(removeEventListenerMock.mock.calls[1][0]).toEqual('focus');\n      expect(removeEventListenerMock.mock.calls[2][0]).toEqual('beforeunload');\n    });\n\n    test('should remove event listeners with pagehide', async () => {\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        ...mockGlobalScope,\n        self: {\n          onpagehide: (() => {\n            /* do nothing */\n          }) as any,\n        },\n      } as typeof globalThis);\n\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      removeEventListenerMock.mockReset();\n      sessionReplay.shutdown();\n      expect(removeEventListenerMock).toHaveBeenCalledTimes(3); // blur, focus, pagehide - popstate handled by plugin cleanup\n      expect(removeEventListenerMock.mock.calls[0][0]).toEqual('blur');\n      expect(removeEventListenerMock.mock.calls[1][0]).toEqual('focus');\n      expect(removeEventListenerMock.mock.calls[2][0]).toEqual('pagehide');\n    });\n\n    test('should stop recording and send any events in queue', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      const createEventsIDBStoreInstance = await SessionReplayIDB.SessionReplayEventsIDBStore.new('replay', {\n        loggerProvider: mockLoggerProvider,\n        apiKey,\n      });\n      const stopRecordingMock = jest.fn();\n      sessionReplay.recordCancelCallback = stopRecordingMock;\n      if (!sessionReplay.eventsManager) {\n        throw new Error('Did not call init');\n      }\n      await createEventsIDBStoreInstance?.addEventToCurrentSequence(123, mockEventString);\n      const sendEventsMock = jest.spyOn(sessionReplay.eventsManager, 'sendCurrentSequenceEvents');\n      sessionReplay.shutdown();\n      expect(stopRecordingMock).toHaveBeenCalled();\n      expect(sessionReplay.recordCancelCallback).toBe(null);\n      expect(sendEventsMock).toHaveBeenCalled();\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n      expect(sendEventsMock.mock.calls[0][0]).toEqual({\n        sessionId: 123,\n        deviceId: '1a2b3c',\n      });\n    });\n  });\n\n  describe('getCurrentUrl', () => {\n    test('returns url if exists', () => {\n      globalSpy.mockImplementation(() => ({\n        location: {\n          href: 'https://www.amplitude.com',\n        },\n      }));\n      const url = Helpers.getCurrentUrl();\n      expect(url).toEqual('https://www.amplitude.com');\n    });\n\n    test('returns empty string if url does not exist', () => {\n      globalSpy.mockImplementation(() => undefined);\n      const url = Helpers.getCurrentUrl();\n      expect(url).toEqual('');\n    });\n  });\n\n  describe('getMaskTextSelectors', () => {\n    test('null config', () => {\n      sessionReplay.config = undefined;\n      expect(sessionReplay.getMaskTextSelectors()).not.toBeDefined();\n    });\n    test('null privacy config', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      if (sessionReplay.config) {\n        sessionReplay.config.privacyConfig = undefined;\n      }\n      expect(sessionReplay.getMaskTextSelectors()).not.toBeDefined();\n    });\n    test('returns mask text selectors', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      expect(sessionReplay.getMaskTextSelectors()).toEqual(['.className1', '.className2']);\n    });\n\n    test('should track all text elements when level is conservative', async () => {\n      await sessionReplay.init(apiKey, {\n        ...mockOptions,\n        privacyConfig: {\n          defaultMaskLevel: 'conservative',\n        },\n      }).promise;\n      expect(sessionReplay.getMaskTextSelectors()).toEqual('*');\n    });\n\n    test('should return * when any urlMaskLevels rule is conservative, even if default is not', async () => {\n      await sessionReplay.init(apiKey, {\n        ...mockOptions,\n        privacyConfig: {\n          defaultMaskLevel: 'light',\n          urlMaskLevels: [\n            { match: 'https://example.com/admin/*', maskLevel: 'conservative' },\n            { match: 'https://example.com/public/*', maskLevel: 'light' },\n          ],\n        },\n      }).promise;\n      // Any conservative URL rule → '*' so rrweb routes all text nodes through maskTextFn\n      expect(sessionReplay.getMaskTextSelectors()).toEqual('*');\n    });\n\n    test('should not return * when urlMaskLevels has no conservative rule', async () => {\n      await sessionReplay.init(apiKey, {\n        ...mockOptions,\n        privacyConfig: {\n          defaultMaskLevel: 'light',\n          urlMaskLevels: [{ match: 'https://example.com/checkout/*', maskLevel: 'medium' }],\n        },\n      }).promise;\n      // No conservative rule → falls through to maskSelector logic (no selectors configured)\n      expect(sessionReplay.getMaskTextSelectors()).toBeUndefined();\n    });\n\n    test('should return * when defaultMaskLevel is conservative and urlMaskLevels are present', async () => {\n      // Bug scenario: session starts on a URL matching a non-conservative rule (effective level ≠\n      // conservative), so the first branch doesn't fire. No rule in urlMaskLevels is conservative,\n      // so the second branch doesn't fire either. But defaultMaskLevel is conservative, meaning any\n      // page that matches NO rule at all falls back to conservative masking — rrweb must be told to\n      // route all text through maskTextFn from the start.\n      await sessionReplay.init(apiKey, {\n        ...mockOptions,\n        privacyConfig: {\n          defaultMaskLevel: 'conservative',\n          urlMaskLevels: [{ match: 'https://example.com/public/*', maskLevel: 'light' }],\n        },\n      }).promise;\n      expect(sessionReplay.getMaskTextSelectors()).toEqual('*');\n    });\n\n    test('should return * when defaultMaskLevel is conservative and urlMaskLevels is non-empty even if current URL matches a non-conservative rule', async () => {\n      // Even if the recording-start URL happens to match a light rule (effectiveLevel = light),\n      // the fallback path (no rule match → conservative) still needs rrweb to call maskTextFn.\n      jest.spyOn(Helpers, 'getCurrentUrl').mockReturnValue('https://example.com/public/page');\n      await sessionReplay.init(apiKey, {\n        ...mockOptions,\n        privacyConfig: {\n          defaultMaskLevel: 'conservative',\n          urlMaskLevels: [{ match: 'https://example.com/public/*', maskLevel: 'light' }],\n        },\n      }).promise;\n      expect(sessionReplay.getMaskTextSelectors()).toEqual('*');\n    });\n\n    test('should not return * when defaultMaskLevel is conservative but urlMaskLevels is empty', async () => {\n      // defaultMaskLevel: conservative with no URL rules → effectiveLevel is always conservative,\n      // which is handled by the first branch. The third branch only fires when urlMaskLevels is non-empty.\n      await sessionReplay.init(apiKey, {\n        ...mockOptions,\n        privacyConfig: {\n          defaultMaskLevel: 'conservative',\n          urlMaskLevels: [],\n        },\n      }).promise;\n      // effectiveLevel = conservative → caught by the first branch, still returns '*'\n      expect(sessionReplay.getMaskTextSelectors()).toEqual('*');\n    });\n\n    test('should return * when defaultMaskLevel is conservative and urlMaskLevels is undefined', async () => {\n      // urlMaskLevels not set at all (undefined) — exercises the ?. optional chain short-circuit path\n      // in the third guard of getMaskTextSelectors. With no urlMaskLevels, effectiveLevel is always\n      // conservative, so the first guard fires instead — result is still '*'.\n      await sessionReplay.init(apiKey, {\n        ...mockOptions,\n        privacyConfig: {\n          defaultMaskLevel: 'conservative',\n          // urlMaskLevels intentionally absent\n        },\n      }).promise;\n      expect(sessionReplay.getMaskTextSelectors()).toEqual('*');\n    });\n  });\n\n  describe('mask function URL getters (currentPageUrl integration)', () => {\n    test('maskInputFn, maskTextFn, and maskAttributeFn closures expose currentPageUrl dynamically', async () => {\n      // This test exercises the three `() => this.currentPageUrl` arrow functions passed to\n      // maskFn/maskAttributeFn at lines 805-807 of session-replay.ts.\n      await sessionReplay.init(apiKey, {\n        ...mockOptions,\n        privacyConfig: {\n          defaultMaskLevel: 'light',\n          maskAttributes: ['placeholder'],\n          urlMaskLevels: [{ match: 'https://example.com/admin/*', maskLevel: 'conservative' }],\n        },\n      }).promise;\n\n      await sessionReplay.recordEvents();\n      expect(mockRecordFunction).toHaveBeenCalled();\n\n      const recordArg = mockRecordFunction.mock.calls[mockRecordFunction.mock.calls.length - 1][0];\n      const { maskInputFn, maskTextFn, maskAttributeFn: attrFn } = recordArg;\n      expect(maskInputFn).toBeDefined();\n      expect(maskTextFn).toBeDefined();\n      expect(attrFn).toBeDefined();\n\n      const divElement = document.createElement('div');\n      const inputElement = document.createElement('input');\n      inputElement.type = 'text';\n\n      // currentPageUrl starts as '' (jsdom has no real location) → light level → not conservative\n      // maskTextFn: light does NOT mask text nodes\n      expect(maskTextFn('hello', divElement)).toEqual('hello');\n      // maskInputFn: light does not mask plain text inputs (non-sensitive input type)\n      expect(maskInputFn('hello', inputElement)).toEqual('hello');\n      // maskAttributeFn: attribute in allowlist, light level → not masked (light leaves text visible)\n      expect(attrFn('placeholder', 'Enter name', inputElement)).toEqual('Enter name');\n\n      // Now simulate navigation to a conservative URL\n      (sessionReplay as any).currentPageUrl = 'https://example.com/admin/dashboard';\n\n      // maskTextFn: conservative URL → text IS masked\n      expect(maskTextFn('hello', divElement)).toEqual('*****');\n      // maskInputFn: conservative URL → input IS masked\n      expect(maskInputFn('hello', inputElement)).toEqual('*****');\n      // maskAttributeFn: conservative URL + attribute in allowlist → masked\n      expect(attrFn('placeholder', 'Enter name', inputElement)).toEqual('***** ****');\n    });\n  });\n\n  describe('getBlockSelectors', () => {\n    test('null config', () => {\n      sessionReplay.config = undefined;\n      expect(sessionReplay.getBlockSelectors()).not.toBeDefined();\n    });\n    test('null privacy config', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      if (sessionReplay.config) {\n        sessionReplay.config.privacyConfig = undefined;\n      }\n      expect(sessionReplay.getBlockSelectors()).not.toBeDefined();\n    });\n    test('returns block selectors', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      expect(sessionReplay.getBlockSelectors()).toStrictEqual(['.className']);\n    });\n  });\n\n  describe('addCustomRRWebEvent', () => {\n    test('should add custom event if null config', async () => {\n      sessionReplay.config = undefined;\n      sessionReplay.recordCancelCallback = () => {\n        return;\n      };\n      // Set the recordFunction directly since addCustomRRWebEvent checks this.recordFunction\n      (sessionReplay as any).recordFunction = mockRecordFunction;\n      await sessionReplay.addCustomRRWebEvent(CustomRRwebEvent.GET_SR_PROPS, { myKey: 'data' });\n      expect(mockRecordFunction.addCustomEvent).toHaveBeenCalledWith(CustomRRwebEvent.GET_SR_PROPS, { myKey: 'data' });\n    });\n\n    test('should add custom event with config and storage data', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      sessionReplay.recordCancelCallback = () => {\n        return;\n      };\n      mockRecordFunction.addCustomEvent = jest.fn();\n      (sessionReplay as any).recordFunction = mockRecordFunction;\n      await sessionReplay.addCustomRRWebEvent(CustomRRwebEvent.GET_SR_PROPS, { myKey: 'data' });\n      expect(mockRecordFunction.addCustomEvent).toHaveBeenCalledWith(\n        CustomRRwebEvent.GET_SR_PROPS,\n        expect.objectContaining({\n          myKey: 'data',\n          config: expect.objectContaining({\n            apiKey: '****_key',\n          }),\n          version: expect.stringMatching(/\\d+.\\d+.\\d+/),\n          percentOfQuota: 0.01,\n          totalStorageSize: 1,\n          usageDetails: JSON.stringify({\n            indexedDB: 10,\n          }),\n        }),\n      );\n    });\n    test('should not add custom event if not recording', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      sessionReplay.recordCancelCallback = undefined;\n      mockRecordFunction.addCustomEvent = jest.fn();\n      await sessionReplay.addCustomRRWebEvent(CustomRRwebEvent.GET_SR_PROPS, { myKey: 'data' });\n      expect(mockRecordFunction.addCustomEvent).not.toHaveBeenCalled();\n    });\n    test('should add storage info if addStorageInfo is true', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      sessionReplay.recordCancelCallback = () => {\n        return;\n      };\n      mockRecordFunction.addCustomEvent = jest.fn();\n      (sessionReplay as any).recordFunction = mockRecordFunction;\n      await sessionReplay.addCustomRRWebEvent(CustomRRwebEvent.GET_SR_PROPS, { myKey: 'data' }, true);\n      expect(mockRecordFunction.addCustomEvent).toHaveBeenCalledWith(\n        CustomRRwebEvent.GET_SR_PROPS,\n        expect.objectContaining({\n          percentOfQuota: 0.01,\n          totalStorageSize: 1,\n          usageDetails: JSON.stringify({\n            indexedDB: 10,\n          }),\n        }),\n      );\n    });\n    test('should not add storage info if addStorageInfo is false', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      sessionReplay.recordCancelCallback = () => {\n        return;\n      };\n      mockRecordFunction.addCustomEvent = jest.fn();\n      (sessionReplay as any).recordFunction = mockRecordFunction;\n      await sessionReplay.addCustomRRWebEvent(CustomRRwebEvent.GET_SR_PROPS, { myKey: 'data' }, false);\n      expect(mockRecordFunction.addCustomEvent).toHaveBeenCalledWith(\n        CustomRRwebEvent.GET_SR_PROPS,\n        expect.not.objectContaining({\n          percentOfQuota: 0.01,\n          totalStorageSize: 1,\n          usageDetails: JSON.stringify({\n            indexedDB: 10,\n          }),\n        }),\n      );\n    });\n    test('should handle an error', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      jest.spyOn(Helpers, 'getStorageSize').mockImplementation(() => {\n        throw new Error();\n      });\n      mockRecordFunction.addCustomEvent = jest.fn();\n      await sessionReplay.addCustomRRWebEvent(CustomRRwebEvent.GET_SR_PROPS, { myKey: 'data' });\n      expect(mockRecordFunction.addCustomEvent).not.toHaveBeenCalled();\n      expect(mockLoggerProvider.debug).toHaveBeenCalled();\n    });\n\n    test('should send targeting decision event when getShouldRecord is called', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      // Mock targeting parameters and store them\n      const targetingParams = {\n        userProperties: { userType: 'premium' },\n        event: { event_type: 'page_view', user_id: '123' },\n      };\n      (sessionReplay as any).lastTargetingParams = targetingParams;\n\n      // Set up targeting config and match\n      sessionReplay.config!.targetingConfig = {\n        key: 'sr_targeting_config',\n        variants: { on: { key: 'on' }, off: { key: 'off' } },\n        segments: [],\n      };\n      sessionReplay.sessionTargetingMatch = true;\n\n      // Reset the decision to ensure we start fresh\n      (sessionReplay as any).lastShouldRecordDecision = undefined;\n\n      // Spy on addCustomRRWebEvent\n      const addCustomRRWebEventSpy = jest.spyOn(sessionReplay, 'addCustomRRWebEvent');\n\n      // Call getShouldRecord first time - should fire event\n      sessionReplay.getShouldRecord();\n\n      // Verify the targeting decision event was sent\n      expect(addCustomRRWebEventSpy).toHaveBeenCalledWith(\n        CustomRRwebEvent.TARGETING_DECISION,\n        expect.objectContaining({\n          message: expect.stringContaining('Capturing replays for session'),\n          sessionId: 123,\n          matched: true,\n          targetingParams: targetingParams,\n        }),\n      );\n\n      // Clear the spy and call again - should NOT fire event since decision hasn't changed\n      addCustomRRWebEventSpy.mockClear();\n      sessionReplay.getShouldRecord();\n\n      // Should not have been called again\n      expect(addCustomRRWebEventSpy).not.toHaveBeenCalledWith(CustomRRwebEvent.TARGETING_DECISION, expect.anything());\n\n      // Change the targeting match and call again - should fire event\n      sessionReplay.sessionTargetingMatch = false;\n      sessionReplay.getShouldRecord();\n\n      // Should have been called with the new decision\n      expect(addCustomRRWebEventSpy).toHaveBeenCalledWith(\n        CustomRRwebEvent.TARGETING_DECISION,\n        expect.objectContaining({\n          message: expect.stringContaining('Not capturing replays for session'),\n          sessionId: 123,\n          matched: false,\n          targetingParams: targetingParams,\n        }),\n      );\n    });\n\n    test('should reset targeting decision when session ID changes', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      // Set up targeting config\n      sessionReplay.config!.targetingConfig = {\n        key: 'sr_targeting_config',\n        variants: { on: { key: 'on' }, off: { key: 'off' } },\n        segments: [],\n      };\n      sessionReplay.sessionTargetingMatch = true;\n\n      // Ensure we start fresh\n      (sessionReplay as any).lastShouldRecordDecision = undefined;\n\n      // Spy on addCustomRRWebEvent\n      const addCustomRRWebEventSpy = jest.spyOn(sessionReplay, 'addCustomRRWebEvent');\n\n      // Call getShouldRecord to establish initial decision\n      sessionReplay.getShouldRecord();\n      expect(addCustomRRWebEventSpy).toHaveBeenCalledWith(CustomRRwebEvent.TARGETING_DECISION, expect.anything());\n\n      // Clear the spy\n      addCustomRRWebEventSpy.mockClear();\n\n      // Change session ID - this should reset the targeting decision\n      await sessionReplay.setSessionId(456).promise;\n\n      // Set the targeting config to undefined\n      sessionReplay.config!.targetingConfig = {\n        key: 'sr_targeting_config',\n        variants: { on: { key: 'on' }, off: { key: 'off' } },\n        segments: [],\n      };\n\n      // Call getShouldRecord again - should fire event for new session\n      sessionReplay.getShouldRecord();\n\n      expect(addCustomRRWebEventSpy).toHaveBeenCalledWith(\n        CustomRRwebEvent.TARGETING_DECISION,\n        expect.objectContaining({\n          sessionId: 456,\n        }),\n      );\n    });\n  });\n\n  describe('getRecordingPlugins', () => {\n    test('disabled console logging', async () => {\n      const loggingConfig: LoggingConfig = {\n        console: {\n          enabled: false,\n          levels: [],\n        },\n      };\n      const plugins = await sessionReplay.getRecordingPlugins(loggingConfig);\n      expect(plugins).toBeDefined();\n      expect(plugins?.length).toBe(1); // URL tracking plugin is always present\n      expect(plugins?.[0].name).toBe('amplitude/url-tracking@1');\n    });\n    test('enabled console logging', async () => {\n      const loggingConfig: LoggingConfig = {\n        console: {\n          enabled: true,\n          levels: ['warn', 'error'],\n        },\n      };\n      const plugins = await sessionReplay.getRecordingPlugins(loggingConfig);\n      expect(plugins).toBeDefined();\n      expect(plugins?.length).toBe(2); // URL tracking plugin + console plugin\n      expect(plugins?.find((p) => p.name === 'amplitude/url-tracking@1')).toBeDefined();\n      expect(plugins?.find((p) => p.name === 'rrweb/console@1')).toBeDefined();\n    });\n    test('should warn if loading console plugin fails', async () => {\n      const loggingConfig: LoggingConfig = {\n        console: {\n          enabled: true,\n          levels: ['warn', 'error'],\n        },\n      };\n      // Mock the dynamic import to throw for this test only\n      jest.resetModules();\n      jest.doMock('@amplitude/rrweb-plugin-console-record', () => {\n        throw new Error('Import failed');\n      });\n      const warnSpy = jest.spyOn(sessionReplay.loggerProvider, 'warn');\n      await sessionReplay.getRecordingPlugins(loggingConfig);\n      expect(warnSpy).toHaveBeenCalledWith('Failed to load console plugin:', expect.any(Error));\n      jest.dontMock('@amplitude/rrweb-plugin-console-record');\n    });\n\n    test('should return undefined when no plugins are available', async () => {\n      // Mock createUrlTrackingPlugin to throw an error\n      mockCreateUrlTrackingPlugin.mockImplementationOnce(() => {\n        throw new Error('URL tracking plugin creation failed');\n      });\n\n      const warnSpy = jest.spyOn(sessionReplay.loggerProvider, 'warn');\n\n      const plugins = await sessionReplay.getRecordingPlugins(undefined);\n      expect(plugins).toBeUndefined();\n      expect(warnSpy).toHaveBeenCalledWith('Failed to create URL tracking plugin:', expect.any(Error));\n    });\n  });\n\n  describe('should call addCustomRRWebEvent with network request events', () => {\n    test('should call addCustomRRWebEvent with network request events', async () => {\n      // Mock the observers module before initialization\n      const mockStart = jest.fn();\n      const mockNetworkObserversClass = jest.fn().mockImplementation(() => ({\n        start: mockStart,\n        stop: jest.fn(),\n      }));\n\n      jest.doMock('../src/observers', () => ({\n        NetworkObservers: mockNetworkObserversClass,\n        NetworkRequestEvent: {} as any,\n      }));\n\n      mockRemoteConfig = {\n        sr_sampling_config: samplingConfig,\n        sr_privacy_config: {},\n        sr_logging_config: {\n          network: {\n            enabled: true,\n          },\n        },\n      };\n\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      const addCustomRRWebEventSpy = jest.spyOn(sessionReplay, 'addCustomRRWebEvent');\n\n      const mockNetworkEvent = {\n        type: 'fetch' as const,\n        url: 'https://example.com',\n        timestamp: Date.now(),\n        method: 'GET',\n        status: 200,\n        requestHeaders: {},\n        responseHeaders: {},\n        requestBody: '',\n        responseBody: '',\n      };\n\n      await sessionReplay.recordEvents();\n\n      expect(mockStart).toHaveBeenCalled();\n      const startCallback = mockStart.mock.calls[0][0] as (event: NetworkRequestEvent) => void;\n\n      startCallback(mockNetworkEvent);\n\n      expect(addCustomRRWebEventSpy).toHaveBeenCalledWith(CustomRRwebEvent.FETCH_REQUEST, mockNetworkEvent);\n\n      // Requests to the SR track URL should be filtered out\n      addCustomRRWebEventSpy.mockClear();\n      const trackUrlEvent = { ...mockNetworkEvent, url: 'https://api-sr.amplitude.com/sessions/v2/track?foo=bar' };\n      startCallback(trackUrlEvent);\n      expect(addCustomRRWebEventSpy).not.toHaveBeenCalled();\n\n      jest.dontMock('../src/observers');\n    });\n  });\n\n  describe('setMetadata', () => {\n    test('should set replaySDKVersion from options.version?.version in metadata', async () => {\n      const customVersion = '1.8.7';\n      await sessionReplay.init(apiKey, {\n        ...mockOptions,\n        version: { version: customVersion, type: 'plugin' },\n      }).promise;\n      // Access private property for test only\n      const metadata = (sessionReplay as any).metadata;\n      expect(metadata?.replaySDKVersion).toBe(customVersion);\n    });\n\n    test('should set replaySDKType to @amplitude/segment-session-replay-plugin if type is segment', async () => {\n      await sessionReplay.init(apiKey, {\n        ...mockOptions,\n        version: { version: '1.8.7', type: 'segment' },\n      }).promise;\n      const metadata = (sessionReplay as any).metadata;\n      expect(metadata?.replaySDKType).toBe('@amplitude/segment-session-replay-plugin');\n    });\n  });\n\n  describe('URL Tracking', () => {\n    describe('Plugin Integration', () => {\n      test('should include URL tracking plugin in recording plugins', async () => {\n        await sessionReplay.init(apiKey, mockOptions).promise;\n\n        const plugins = await sessionReplay.getRecordingPlugins(undefined);\n        expect(plugins).toBeDefined();\n        expect(plugins?.length).toBeGreaterThan(0);\n\n        // Find the URL tracking plugin\n        const urlTrackingPlugin = plugins?.find((plugin) => plugin.name === 'amplitude/url-tracking@1');\n        expect(urlTrackingPlugin).toBeDefined();\n        expect(urlTrackingPlugin?.observer).toBeDefined();\n      });\n\n      test('should create URL tracking plugin with UGC filter rules from interaction config', async () => {\n        const mockUgcFilterRules = [\n          { selector: 'test', replacement: 'filtered' },\n          { selector: '/test/', replacement: 'filtered' },\n        ];\n\n        mockRemoteConfig = {\n          sr_sampling_config: samplingConfig,\n          sr_privacy_config: {},\n          sr_interaction_config: {\n            enabled: true,\n            ugcFilterRules: mockUgcFilterRules,\n          },\n        };\n\n        await sessionReplay.init(apiKey, mockOptions).promise;\n\n        const plugins = await sessionReplay.getRecordingPlugins(undefined);\n        const urlTrackingPlugin = plugins?.find((plugin) => plugin.name === 'amplitude/url-tracking@1');\n\n        expect(urlTrackingPlugin).toBeDefined();\n        expect((urlTrackingPlugin?.options as any).ugcFilterRules).toEqual(mockUgcFilterRules);\n      });\n\n      test('should create URL tracking plugin with polling enabled', async () => {\n        await sessionReplay.init(apiKey, {\n          ...mockOptions,\n          enableUrlChangePolling: true,\n        }).promise;\n\n        const plugins = await sessionReplay.getRecordingPlugins(undefined);\n        const urlTrackingPlugin = plugins?.find((plugin) => plugin.name === 'amplitude/url-tracking@1');\n\n        expect(urlTrackingPlugin).toBeDefined();\n        // The config options should be passed to the plugin\n        expect((urlTrackingPlugin?.options as any).enablePolling).toBe(true);\n      });\n\n      test('should create URL tracking plugin with custom polling interval', async () => {\n        const customInterval = 2000;\n        await sessionReplay.init(apiKey, {\n          ...mockOptions,\n          enableUrlChangePolling: true,\n          urlChangePollingInterval: customInterval,\n        }).promise;\n\n        const plugins = await sessionReplay.getRecordingPlugins(undefined);\n        const urlTrackingPlugin = plugins?.find((plugin) => plugin.name === 'amplitude/url-tracking@1');\n\n        expect(urlTrackingPlugin).toBeDefined();\n        expect((urlTrackingPlugin?.options as any).pollingInterval).toBe(customInterval);\n      });\n\n      test('should create URL tracking plugin with captureDocumentTitle enabled', async () => {\n        await sessionReplay.init(apiKey, {\n          ...mockOptions,\n          captureDocumentTitle: true,\n        }).promise;\n\n        const plugins = await sessionReplay.getRecordingPlugins(undefined);\n        const urlTrackingPlugin = plugins?.find((plugin) => plugin.name === 'amplitude/url-tracking@1');\n\n        expect(urlTrackingPlugin).toBeDefined();\n        expect((urlTrackingPlugin?.options as any).captureDocumentTitle).toBe(true);\n      });\n    });\n\n    test('should handle empty UGC filter rules', async () => {\n      mockRemoteConfig = {\n        sr_sampling_config: samplingConfig,\n        sr_privacy_config: {},\n        sr_interaction_config: {\n          enabled: true,\n          ugcFilterRules: [],\n        },\n      };\n\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      const plugins = await sessionReplay.getRecordingPlugins(undefined);\n      const urlTrackingPlugin = plugins?.find((plugin) => plugin.name === 'amplitude/url-tracking@1');\n\n      expect((urlTrackingPlugin?.options as any).ugcFilterRules).toEqual([]);\n    });\n\n    test('should handle missing interaction config', async () => {\n      mockRemoteConfig = {\n        sr_sampling_config: samplingConfig,\n        sr_privacy_config: {},\n      };\n\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      const plugins = await sessionReplay.getRecordingPlugins(undefined);\n      const urlTrackingPlugin = plugins?.find((plugin) => plugin.name === 'amplitude/url-tracking@1');\n\n      expect((urlTrackingPlugin?.options as any).ugcFilterRules).toEqual([]);\n    });\n  });\n\n  describe('getRecordFunction', () => {\n    let getRecordFunctionSpy: jest.SpyInstance;\n\n    beforeEach(() => {\n      // Restore the original implementation for these tests\n      getRecordFunctionSpy = jest.spyOn(SessionReplay.prototype, 'getRecordFunction' as any);\n      getRecordFunctionSpy.mockRestore();\n    });\n\n    afterEach(() => {\n      // Clean up any mocks we created\n      jest.dontMock('@amplitude/rrweb-record');\n    });\n\n    test('should return cached recordFunction if it already exists', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      const mockCachedFunction = jest.fn();\n      (sessionReplay as any).recordFunction = mockCachedFunction;\n\n      const result = await (sessionReplay as any).getRecordFunction();\n\n      expect(result).toBe(mockCachedFunction);\n    });\n\n    test('should dynamically import and cache record function on first call', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      (sessionReplay as any).recordFunction = null;\n\n      const mockRecord = jest.fn();\n      jest.doMock(\n        '@amplitude/rrweb-record',\n        () => ({\n          record: mockRecord,\n        }),\n        { virtual: true },\n      );\n\n      const result = await (sessionReplay as any).getRecordFunction();\n\n      expect(result).toBe(mockRecord);\n      expect((sessionReplay as any).recordFunction).toBe(mockRecord);\n    });\n\n    test('should log warning and return null when import fails', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      (sessionReplay as any).recordFunction = null;\n\n      jest.resetModules();\n      jest.doMock('@amplitude/rrweb-record', () => {\n        throw new Error('Import failed');\n      });\n\n      const warnSpy = jest.spyOn(sessionReplay.loggerProvider, 'warn');\n\n      const result = await (sessionReplay as any).getRecordFunction();\n\n      expect(result).toBeNull();\n      expect(warnSpy).toHaveBeenCalledWith('Failed to load rrweb-record module:', expect.any(Error));\n    });\n\n    test('should return cached function on subsequent calls after successful import', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      (sessionReplay as any).recordFunction = null;\n\n      const mockRecord = jest.fn();\n      jest.doMock(\n        '@amplitude/rrweb-record',\n        () => ({\n          record: mockRecord,\n        }),\n        { virtual: true },\n      );\n\n      const firstResult = await (sessionReplay as any).getRecordFunction();\n      expect(firstResult).toBe(mockRecord);\n\n      const secondResult = await (sessionReplay as any).getRecordFunction();\n      expect(secondResult).toBe(mockRecord);\n      expect(secondResult).toBe(firstResult);\n    });\n\n    test('should return early if recordFunction is null', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      await jest.runAllTimersAsync();\n\n      // Mock getRecordFunction to return null (simulating import failure)\n      const getRecordFunctionSpy = jest.spyOn(SessionReplay.prototype, 'getRecordFunction' as any);\n      getRecordFunctionSpy.mockResolvedValue(null);\n\n      // Spy on the record function to ensure it's not called\n      mockRecordFunction.mockClear();\n\n      await sessionReplay.recordEvents();\n\n      expect(mockRecordFunction).not.toHaveBeenCalled();\n      expect(getRecordFunctionSpy).toHaveBeenCalled();\n\n      getRecordFunctionSpy.mockRestore();\n    });\n\n    test('should return early if recordFunction is undefined', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      await jest.runAllTimersAsync();\n\n      const getRecordFunctionSpy = jest.spyOn(SessionReplay.prototype, 'getRecordFunction' as any);\n      getRecordFunctionSpy.mockResolvedValue(undefined);\n\n      mockRecordFunction.mockClear();\n\n      await sessionReplay.recordEvents();\n\n      expect(mockRecordFunction).not.toHaveBeenCalled();\n      expect(getRecordFunctionSpy).toHaveBeenCalled();\n\n      getRecordFunctionSpy.mockRestore();\n    });\n  });\n\n  describe('evaluateTargetingAndCapture', () => {\n    test('should return early if no identifiers', async () => {\n      const sessionReplay = new SessionReplay();\n      sessionReplay.identifiers = undefined;\n      sessionReplay.loggerProvider = mockLoggerProvider;\n\n      await sessionReplay.evaluateTargetingAndCapture({});\n\n      expect(mockLoggerProvider.warn).toHaveBeenCalledWith(\n        'Session replay init has not been called, cannot evaluate targeting.',\n      );\n    });\n\n    test('should return early if no sessionId', async () => {\n      const sessionReplay = new SessionReplay();\n      sessionReplay.identifiers = { sessionId: undefined, deviceId: '123', sessionReplayId: '123/undefined' };\n      sessionReplay.loggerProvider = mockLoggerProvider;\n\n      await sessionReplay.evaluateTargetingAndCapture({});\n\n      expect(mockLoggerProvider.log).toHaveBeenCalledWith(\n        'Session ID has not been set yet, cannot evaluate targeting for Session Replay.',\n      );\n    });\n\n    test('should return early if no config', async () => {\n      const sessionReplay = new SessionReplay();\n      sessionReplay.identifiers = { sessionId: 123, deviceId: '123', sessionReplayId: '123/123' };\n      sessionReplay.config = undefined;\n      sessionReplay.loggerProvider = mockLoggerProvider;\n\n      await sessionReplay.evaluateTargetingAndCapture({});\n\n      expect(mockLoggerProvider.warn).toHaveBeenCalledWith(\n        'Session replay init has not been called, cannot evaluate targeting.',\n      );\n    });\n\n    test('should call initialize when isInit is true', async () => {\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      const initializeSpy = jest.spyOn(sessionReplay, 'initialize');\n\n      await sessionReplay.evaluateTargetingAndCapture({}, true);\n\n      expect(initializeSpy).toHaveBeenCalledWith(true);\n    });\n\n    test('should call recordEvents when isInit is false', async () => {\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      if (sessionReplay.config) {\n        sessionReplay.config.targetingConfig = {\n          key: 'sr_targeting_config',\n          variants: { on: { key: 'on' }, off: { key: 'off' } },\n          segments: [],\n        };\n      }\n      const recordEventsSpy = jest.spyOn(sessionReplay, 'recordEvents');\n\n      await sessionReplay.evaluateTargetingAndCapture({}, false);\n\n      // recordEvents should not be called because we're already recording from init\n      expect(recordEventsSpy).not.toHaveBeenCalled();\n    });\n\n    test('should skip targeting evaluation when no targetingConfig', async () => {\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      const recordEventsSpy = jest.spyOn(sessionReplay, 'recordEvents');\n\n      await sessionReplay.evaluateTargetingAndCapture({});\n\n      expect(recordEventsSpy).not.toHaveBeenCalled();\n    });\n\n    test('should skip targeting evaluation when sessionTargetingMatch is already true', async () => {\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      // Set targeting config directly on the config object\n      if (sessionReplay.config) {\n        sessionReplay.config.targetingConfig = {\n          key: 'sr_targeting_config',\n          variants: { on: { key: 'on' }, off: { key: 'off' } },\n          segments: [],\n        };\n      }\n\n      sessionReplay.sessionTargetingMatch = true;\n      const recordEventsSpy = jest.spyOn(sessionReplay, 'recordEvents');\n\n      await sessionReplay.evaluateTargetingAndCapture({});\n\n      expect(recordEventsSpy).toHaveBeenCalled();\n    });\n\n    test('should execute targeting evaluation branch when targetingConfig exists and sessionTargetingMatch is false', async () => {\n      const sessionReplay = new SessionReplay();\n\n      // Set up namespace config to include targeting config\n      mockRemoteConfig = {\n        sr_sampling_config: samplingConfig,\n        sr_privacy_config: {},\n        sr_targeting_config: {\n          key: 'sr_targeting_config',\n          variants: { on: { key: 'on' }, off: { key: 'off' } },\n          segments: [],\n        },\n      };\n\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      // Ensure sessionTargetingMatch is false to trigger the evaluation\n      sessionReplay.sessionTargetingMatch = false;\n\n      const recordEventsSpy = jest.spyOn(sessionReplay, 'recordEvents');\n      const userProperties = { age: 30, city: 'San Francisco' };\n\n      await sessionReplay.evaluateTargetingAndCapture({ userProperties });\n\n      // Verify the targeting evaluation branch was executed by checking that sessionTargetingMatch was updated\n      expect(typeof sessionReplay.sessionTargetingMatch).toBe('boolean');\n\n      // recordEvents should not be called because we're already recording from init\n      expect(recordEventsSpy).not.toHaveBeenCalled();\n    });\n\n    test('should handle special event types in targeting evaluation', async () => {\n      const sessionReplay = new SessionReplay();\n\n      // Set up namespace config to include targeting config\n      mockRemoteConfig = {\n        sr_sampling_config: samplingConfig,\n        sr_privacy_config: {},\n        sr_targeting_config: {\n          key: 'sr_targeting_config',\n          variants: { on: { key: 'on' }, off: { key: 'off' } },\n          segments: [],\n        },\n      };\n\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      // Ensure sessionTargetingMatch is false to trigger the evaluation\n      sessionReplay.sessionTargetingMatch = false;\n\n      const specialEvent = {\n        event_type: SpecialEventType.IDENTIFY,\n        event_properties: {},\n      };\n\n      await sessionReplay.evaluateTargetingAndCapture({ event: specialEvent });\n\n      // Verify the function executed without throwing errors\n      expect(typeof sessionReplay.sessionTargetingMatch).toBe('boolean');\n    });\n\n    test('should pass targetingParams.page to evaluateTargetingAndStore', async () => {\n      const page = { url: 'https://replay-page-test.example.com/path' };\n      const evaluateTargetingAndStoreSpy = jest\n        .spyOn(targetingManager, 'evaluateTargetingAndStore')\n        .mockResolvedValue(true);\n\n      const sessionReplay = new SessionReplay();\n      mockRemoteConfig = {\n        sr_sampling_config: samplingConfig,\n        sr_privacy_config: {},\n        sr_targeting_config: {\n          key: 'sr_targeting_config',\n          variants: { on: { key: 'on' }, off: { key: 'off' } },\n          segments: [],\n        },\n      };\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      sessionReplay.sessionTargetingMatch = false;\n\n      await sessionReplay.evaluateTargetingAndCapture({ page });\n\n      expect(evaluateTargetingAndStoreSpy).toHaveBeenCalledWith(\n        expect.objectContaining({\n          targetingParams: expect.objectContaining({\n            page,\n          }),\n        }),\n      );\n    });\n\n    test('should pass page undefined when targetingParams.page is not provided', async () => {\n      const mockGlobalScope = {\n        location: { href: 'https://global-url.example.com/ignored' },\n        addEventListener: jest.fn(),\n        removeEventListener: jest.fn(),\n      };\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue(mockGlobalScope as any);\n      const evaluateTargetingAndStoreSpy = jest\n        .spyOn(targetingManager, 'evaluateTargetingAndStore')\n        .mockResolvedValue(true);\n\n      const sessionReplay = new SessionReplay();\n      mockRemoteConfig = {\n        sr_sampling_config: samplingConfig,\n        sr_privacy_config: {},\n        sr_targeting_config: {\n          key: 'sr_targeting_config',\n          variants: { on: { key: 'on' }, off: { key: 'off' } },\n          segments: [],\n        },\n      };\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      sessionReplay.sessionTargetingMatch = false;\n\n      await sessionReplay.evaluateTargetingAndCapture({});\n\n      // When targetingParams.page is not provided, we derive page from location.href\n      expect(evaluateTargetingAndStoreSpy).toHaveBeenCalledWith(\n        expect.objectContaining({\n          targetingParams: expect.objectContaining({\n            page: { url: 'https://global-url.example.com/ignored' },\n          }),\n        }),\n      );\n    });\n\n    test('should pass page undefined when targetingParams.page not provided and location.href is empty', async () => {\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        location: { href: '' },\n        addEventListener: jest.fn(),\n        removeEventListener: jest.fn(),\n      } as any);\n      const evaluateTargetingAndStoreSpy = jest\n        .spyOn(targetingManager, 'evaluateTargetingAndStore')\n        .mockResolvedValue(true);\n\n      const sessionReplay = new SessionReplay();\n      mockRemoteConfig = {\n        sr_sampling_config: samplingConfig,\n        sr_privacy_config: {},\n        sr_targeting_config: {\n          key: 'sr_targeting_config',\n          variants: { on: { key: 'on' }, off: { key: 'off' } },\n          segments: [],\n        },\n      };\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      sessionReplay.sessionTargetingMatch = false;\n\n      await sessionReplay.evaluateTargetingAndCapture({});\n\n      expect(evaluateTargetingAndStoreSpy).toHaveBeenCalledWith(\n        expect.objectContaining({\n          targetingParams: expect.objectContaining({\n            page: undefined,\n          }),\n        }),\n      );\n    });\n\n    test('should pass page undefined when targetingParams.page not provided and getGlobalScope returns undefined', async () => {\n      const evaluateTargetingAndStoreSpy = jest\n        .spyOn(targetingManager, 'evaluateTargetingAndStore')\n        .mockResolvedValue(true);\n\n      const sessionReplay = new SessionReplay();\n      mockRemoteConfig = {\n        sr_sampling_config: samplingConfig,\n        sr_privacy_config: {},\n        sr_targeting_config: {\n          key: 'sr_targeting_config',\n          variants: { on: { key: 'on' }, off: { key: 'off' } },\n          segments: [],\n        },\n      };\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      sessionReplay.sessionTargetingMatch = false;\n\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue(undefined as any);\n      await sessionReplay.evaluateTargetingAndCapture({});\n\n      expect(evaluateTargetingAndStoreSpy).toHaveBeenCalledWith(\n        expect.objectContaining({\n          targetingParams: expect.objectContaining({\n            page: undefined,\n          }),\n        }),\n      );\n    });\n\n    test('should not call recordEvents when already recording and forceRestart is false', async () => {\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      if (sessionReplay.config) {\n        sessionReplay.config.targetingConfig = {\n          key: 'sr_targeting_config',\n          variants: { on: { key: 'on' }, off: { key: 'off' } },\n          segments: [],\n        };\n      }\n\n      sessionReplay.sessionTargetingMatch = true;\n\n      // Simulate that recording is already active\n      sessionReplay.recordCancelCallback = jest.fn();\n\n      const recordEventsSpy = jest.spyOn(sessionReplay, 'recordEvents');\n\n      await sessionReplay.evaluateTargetingAndCapture({}, false, false);\n\n      // recordEvents should NOT be called because we're already recording and forceRestart is false\n      expect(recordEventsSpy).not.toHaveBeenCalled();\n    });\n\n    test('should call recordEvents when already recording but forceRestart is true', async () => {\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      if (sessionReplay.config) {\n        sessionReplay.config.targetingConfig = {\n          key: 'sr_targeting_config',\n          variants: { on: { key: 'on' }, off: { key: 'off' } },\n          segments: [],\n        };\n      }\n\n      sessionReplay.sessionTargetingMatch = true;\n\n      // Simulate that recording is already active\n      sessionReplay.recordCancelCallback = jest.fn();\n\n      const recordEventsSpy = jest.spyOn(sessionReplay, 'recordEvents');\n\n      await sessionReplay.evaluateTargetingAndCapture({}, false, true);\n\n      // recordEvents SHOULD be called because forceRestart is true\n      expect(recordEventsSpy).toHaveBeenCalled();\n    });\n\n    test('should not call recordEvents when URL change re-evaluation still matches and recording is active', async () => {\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      if (sessionReplay.config) {\n        sessionReplay.config.targetingConfig = {\n          key: 'sr_targeting_config',\n          variants: { on: { key: 'on' }, off: { key: 'off' } },\n          segments: [],\n        };\n      }\n\n      sessionReplay.sessionTargetingMatch = true;\n      sessionReplay.recordCancelCallback = jest.fn();\n      jest.spyOn(targetingManager, 'evaluateTargetingAndStore').mockResolvedValue(true);\n      const recordEventsSpy = jest.spyOn(sessionReplay, 'recordEvents');\n\n      await sessionReplay.evaluateTargetingAndCapture(\n        { page: { url: 'https://example.com/still-matching' } },\n        false,\n        false,\n        true,\n      );\n\n      // URL-change re-evaluation should not restart rrweb when already recording and still matching.\n      expect(recordEventsSpy).not.toHaveBeenCalled();\n    });\n\n    test('should call recordEvents when not recording and forceRestart is false', async () => {\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      if (sessionReplay.config) {\n        sessionReplay.config.targetingConfig = {\n          key: 'sr_targeting_config',\n          variants: { on: { key: 'on' }, off: { key: 'off' } },\n          segments: [],\n        };\n      }\n\n      sessionReplay.sessionTargetingMatch = true;\n\n      // Ensure recording is not active\n      sessionReplay.recordCancelCallback = null;\n\n      const recordEventsSpy = jest.spyOn(sessionReplay, 'recordEvents');\n\n      await sessionReplay.evaluateTargetingAndCapture({}, false, false);\n\n      // recordEvents SHOULD be called because we're not recording\n      expect(recordEventsSpy).toHaveBeenCalled();\n    });\n\n    test('should ignore stale forceTargetingReevaluation result when latest URL evaluation id changes', async () => {\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      if (sessionReplay.config) {\n        sessionReplay.config.targetingConfig = {\n          key: 'sr_targeting_config',\n          variants: { on: { key: 'on' }, off: { key: 'off' } },\n          segments: [],\n        };\n      }\n\n      let resolveEvaluation!: (value: boolean) => void;\n      const evaluationPromise = new Promise<boolean>((resolve) => {\n        resolveEvaluation = resolve;\n      });\n      jest.spyOn(targetingManager, 'evaluateTargetingAndStore').mockImplementationOnce(() => evaluationPromise);\n\n      (\n        sessionReplay as unknown as {\n          latestUrlChangeTargetingEvaluationId: number;\n        }\n      ).latestUrlChangeTargetingEvaluationId = 1;\n\n      const evalPromise = sessionReplay.evaluateTargetingAndCapture(\n        { page: { url: 'https://example.com/stale-targeting' } },\n        false,\n        false,\n        true,\n      );\n\n      (\n        sessionReplay as unknown as {\n          latestUrlChangeTargetingEvaluationId: number;\n        }\n      ).latestUrlChangeTargetingEvaluationId = 2;\n      resolveEvaluation(true);\n      await evalPromise;\n\n      expect(sessionReplay.sessionTargetingMatch).toBe(false);\n      expect(mockLoggerProvider.debug).toHaveBeenCalledWith(\n        expect.stringContaining('Ignoring stale URL-change targeting result #1; latest is #2.'),\n      );\n    });\n\n    test('should not let a late URL-change false overwrite a newer non-URL true match', async () => {\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      if (sessionReplay.config) {\n        sessionReplay.config.targetingConfig = {\n          key: 'sr_targeting_config',\n          variants: { on: { key: 'on' }, off: { key: 'off' } },\n          segments: [],\n        };\n      }\n\n      let resolveUrlChangeEvaluation!: (value: boolean) => void;\n      const urlChangeEvaluationPromise = new Promise<boolean>((resolve) => {\n        resolveUrlChangeEvaluation = resolve;\n      });\n\n      jest\n        .spyOn(targetingManager, 'evaluateTargetingAndStore')\n        .mockImplementationOnce(() => urlChangeEvaluationPromise)\n        .mockResolvedValueOnce(true);\n\n      sessionReplay.sessionTargetingMatch = false;\n      const urlChangeEval = sessionReplay.evaluateTargetingAndCapture(\n        { page: { url: 'https://example.com/url-change' } },\n        false,\n        false,\n        true,\n      );\n\n      await sessionReplay.evaluateTargetingAndCapture({ event: { event_type: 'regular_event' } as any });\n      expect(sessionReplay.sessionTargetingMatch).toBe(true);\n\n      resolveUrlChangeEvaluation(false);\n      await urlChangeEval;\n\n      expect(sessionReplay.sessionTargetingMatch).toBe(true);\n    });\n\n    test('should keep recording for the session after first targeting match', async () => {\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      if (sessionReplay.config) {\n        sessionReplay.config.targetingConfig = {\n          key: 'sr_targeting_config',\n          variants: { on: { key: 'on' }, off: { key: 'off' } },\n          segments: [],\n        };\n      }\n\n      sessionReplay.sessionTargetingMatch = true;\n      sessionReplay.recordCancelCallback = jest.fn();\n      const stopSpy = jest.spyOn(sessionReplay, 'stopRecordingEvents');\n      const recordEventsSpy = jest.spyOn(sessionReplay, 'recordEvents');\n      const evaluateTargetingAndStoreSpy = jest\n        .spyOn(targetingManager, 'evaluateTargetingAndStore')\n        .mockResolvedValue(false);\n\n      await sessionReplay.evaluateTargetingAndCapture(\n        { page: { url: 'https://example.com/non-matching' } },\n        false,\n        false,\n        true,\n      );\n\n      // Once matched, we do not re-evaluate/stop on later URL changes in the same session.\n      expect(evaluateTargetingAndStoreSpy).not.toHaveBeenCalled();\n      expect(sessionReplay.sessionTargetingMatch).toBe(true);\n      expect(stopSpy).not.toHaveBeenCalled();\n      expect(recordEventsSpy).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('URL change listener for targeting', () => {\n    test('should not call subscribeToUrlChanges when getGlobalScope has no location', () => {\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({} as any);\n      const sessionReplay = new SessionReplay();\n      sessionReplay.config = { targetingConfig: {} } as any;\n      sessionReplay.identifiers = { sessionId: 123 } as any;\n      (sessionReplay as any).setupUrlChangeListener();\n      expect(subscribeToUrlChanges).not.toHaveBeenCalled();\n    });\n\n    test('should not call subscribeToUrlChanges when getGlobalScope returns null', () => {\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue(null as any);\n      const sessionReplay = new SessionReplay();\n      sessionReplay.config = { targetingConfig: {} } as any;\n      sessionReplay.identifiers = { sessionId: 123 } as any;\n      (sessionReplay as any).setupUrlChangeListener();\n      expect(subscribeToUrlChanges).not.toHaveBeenCalled();\n    });\n\n    test('should call evaluateTargetingAndCapture when URL change callback is invoked', async () => {\n      mockRemoteConfig = {\n        sr_sampling_config: {},\n        sr_privacy_config: {},\n        sr_targeting_config: {\n          key: 'sr_targeting_config',\n          variants: { on: { key: 'on' }, off: { key: 'off' } },\n          segments: [],\n        },\n      };\n      const sessionReplay = new SessionReplay();\n      const subscribeMock = subscribeToUrlChanges as jest.MockedFunction<typeof subscribeToUrlChanges>;\n      const callCountBefore = subscribeMock.mock.calls.length;\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      const evaluateSpy = jest.spyOn(sessionReplay, 'evaluateTargetingAndCapture');\n      const lastCall = subscribeMock.mock.calls[callCountBefore];\n      const onUrlChange = lastCall?.[1];\n      expect(onUrlChange).toBeDefined();\n      onUrlChange('https://example.com/new-page');\n      expect(evaluateSpy).toHaveBeenCalledWith(\n        expect.objectContaining({\n          userProperties: {},\n          event: undefined,\n          page: { url: 'https://example.com/new-page' },\n        }),\n        false,\n        false,\n        true,\n      );\n    });\n\n    test('should ignore stale URL-change targeting results when reevaluations resolve out of order', async () => {\n      mockRemoteConfig = {\n        sr_sampling_config: {},\n        sr_privacy_config: {},\n        sr_targeting_config: {\n          key: 'sr_targeting_config',\n          variants: { on: { key: 'on' }, off: { key: 'off' } },\n          segments: [],\n        },\n      };\n      const sessionReplay = new SessionReplay();\n      const subscribeMock = subscribeToUrlChanges as jest.MockedFunction<typeof subscribeToUrlChanges>;\n      const callCountBefore = subscribeMock.mock.calls.length;\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      sessionReplay.recordCancelCallback = jest.fn();\n\n      let resolveFirst!: (value: boolean) => void;\n      let resolveSecond!: (value: boolean) => void;\n      const firstEvaluation = new Promise<boolean>((resolve) => {\n        resolveFirst = resolve;\n      });\n      const secondEvaluation = new Promise<boolean>((resolve) => {\n        resolveSecond = resolve;\n      });\n      jest\n        .spyOn(targetingManager, 'evaluateTargetingAndStore')\n        .mockImplementationOnce(() => firstEvaluation)\n        .mockImplementationOnce(() => secondEvaluation);\n\n      const stopSpy = jest.spyOn(sessionReplay, 'stopRecordingEvents');\n\n      const lastCall = subscribeMock.mock.calls[callCountBefore];\n      const onUrlChange = lastCall?.[1] as ((href: string) => void) | undefined;\n      expect(onUrlChange).toBeDefined();\n\n      onUrlChange?.('https://example.com/route-a');\n      onUrlChange?.('https://example.com/route-b');\n\n      resolveSecond(true);\n      await Promise.resolve();\n      await Promise.resolve();\n      expect(sessionReplay.sessionTargetingMatch).toBe(true);\n\n      resolveFirst(false);\n      await Promise.resolve();\n      await Promise.resolve();\n\n      expect(sessionReplay.sessionTargetingMatch).toBe(true);\n      expect(stopSpy).not.toHaveBeenCalled();\n    });\n\n    test('should call urlChangeCleanup on shutdown when targeting was set up', async () => {\n      mockRemoteConfig = {\n        sr_sampling_config: {},\n        sr_privacy_config: {},\n        sr_targeting_config: {\n          key: 'sr_targeting_config',\n          variants: { on: { key: 'on' }, off: { key: 'off' } },\n          segments: [],\n        },\n      };\n      let capturedCleanup: (() => void) | null = null;\n      (subscribeToUrlChanges as jest.Mock).mockImplementation(() => {\n        const cleanup = jest.fn();\n        capturedCleanup = cleanup;\n        return cleanup;\n      });\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      expect(capturedCleanup).not.toBeNull();\n      expect(typeof capturedCleanup).toBe('function');\n      sessionReplay.shutdown();\n      expect(capturedCleanup).toHaveBeenCalled();\n    });\n\n    test('should clean up previous URL subscription before re-subscribing on re-init', async () => {\n      mockRemoteConfig = {\n        sr_sampling_config: samplingConfig,\n        sr_privacy_config: {},\n        sr_targeting_config: {\n          key: 'sr_targeting_config',\n          variants: { on: { key: 'on' }, off: { key: 'off' } },\n          segments: [],\n        },\n      };\n\n      const callbacks = new Set<(href: string) => void>();\n      (subscribeToUrlChanges as jest.Mock).mockImplementation(\n        (_scope: Window | undefined, cb: (href: string) => void) => {\n          callbacks.add(cb);\n          return () => {\n            callbacks.delete(cb);\n          };\n        },\n      );\n\n      const evaluateTargetingAndCaptureSpy = jest.spyOn(sessionReplay, 'evaluateTargetingAndCapture');\n\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      // Init itself evaluates targeting; clear those calls and test only URL-change behavior.\n      evaluateTargetingAndCaptureSpy.mockClear();\n\n      callbacks.forEach((cb) => cb('https://example.com/new-route'));\n\n      expect(callbacks.size).toBe(1);\n      expect(evaluateTargetingAndCaptureSpy).toHaveBeenCalledTimes(1);\n      expect(evaluateTargetingAndCaptureSpy).toHaveBeenCalledWith(\n        {\n          userProperties: {},\n          event: undefined,\n          page: { url: 'https://example.com/new-route' },\n        },\n        false,\n        false,\n        true,\n      );\n    });\n\n    test('should clean up existing URL subscription when setupUrlChangeListener is called again', () => {\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        location: { href: 'https://example.com/current' },\n      } as any);\n      const firstCleanup = jest.fn();\n      const secondCleanup = jest.fn();\n      (subscribeToUrlChanges as jest.Mock)\n        .mockImplementationOnce(() => firstCleanup)\n        .mockImplementationOnce(() => secondCleanup);\n\n      const sessionReplay = new SessionReplay();\n      (sessionReplay as any).setupUrlChangeListener();\n      (sessionReplay as any).setupUrlChangeListener();\n\n      expect(firstCleanup).toHaveBeenCalledTimes(1);\n      expect(secondCleanup).not.toHaveBeenCalled();\n    });\n\n    test('should not call subscribeToUrlChanges when init completes with no targetingConfig and no urlMaskLevels', async () => {\n      (subscribeToUrlChanges as jest.Mock).mockClear();\n      mockRemoteConfig = {\n        sr_sampling_config: samplingConfig,\n        sr_privacy_config: {},\n      };\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, mockOptions).promise;\n      expect(subscribeToUrlChanges).not.toHaveBeenCalled();\n    });\n\n    test('should call subscribeToUrlChanges when urlMaskLevels has entries and there is no targetingConfig', async () => {\n      (subscribeToUrlChanges as jest.Mock).mockClear();\n      mockRemoteConfig = {\n        sr_sampling_config: samplingConfig,\n        sr_privacy_config: {},\n      };\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, {\n        ...mockOptions,\n        privacyConfig: {\n          defaultMaskLevel: 'light',\n          urlMaskLevels: [{ match: 'https://example.com/admin/*', maskLevel: 'conservative' }],\n        },\n      }).promise;\n      expect(subscribeToUrlChanges).toHaveBeenCalled();\n    });\n\n    test('should not call subscribeToUrlChanges when privacyConfig is undefined and no targetingConfig', async () => {\n      (subscribeToUrlChanges as jest.Mock).mockClear();\n      const mockLocalConfig = new SessionReplayLocalConfig(apiKey, mockOptions);\n      const mockJoinedConfig: SessionReplayJoinedConfig = {\n        ...mockLocalConfig,\n        optOut: false,\n        privacyConfig: undefined,\n        captureEnabled: true,\n      };\n      const mockGenerator = {\n        generateJoinedConfig: jest.fn().mockResolvedValue({\n          joinedConfig: mockJoinedConfig,\n          localConfig: mockLocalConfig,\n          remoteConfig: undefined,\n        }),\n      };\n      const createGeneratorSpy = jest\n        .spyOn(JoinedConfigModule, 'createSessionReplayJoinedConfigGenerator')\n        .mockResolvedValue(mockGenerator as any);\n\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      expect(subscribeToUrlChanges).not.toHaveBeenCalled();\n      createGeneratorSpy.mockRestore();\n    });\n\n    test('should update currentPageUrl on URL change even without targetingConfig', async () => {\n      mockRemoteConfig = {\n        sr_sampling_config: samplingConfig,\n        sr_privacy_config: {},\n      };\n      const subscribeMock = subscribeToUrlChanges as jest.MockedFunction<typeof subscribeToUrlChanges>;\n      const callCountBefore = subscribeMock.mock.calls.length;\n      const sessionReplay = new SessionReplay();\n      await sessionReplay.init(apiKey, {\n        ...mockOptions,\n        privacyConfig: {\n          defaultMaskLevel: 'light',\n          urlMaskLevels: [{ match: 'https://example.com/admin/*', maskLevel: 'conservative' }],\n        },\n      }).promise;\n\n      const lastCall = subscribeMock.mock.calls[callCountBefore];\n      const onUrlChange = lastCall?.[1] as ((href: string) => void) | undefined;\n      expect(onUrlChange).toBeDefined();\n\n      onUrlChange?.('https://example.com/admin/dashboard');\n      expect((sessionReplay as any).currentPageUrl).toBe('https://example.com/admin/dashboard');\n    });\n  });\n\n  describe('targeting decision events', () => {\n    test('should return false when targetingConfig exists but sessionTargetingMatch is false', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      // Set targeting config directly on the config object\n      if (sessionReplay.config) {\n        sessionReplay.config.targetingConfig = {\n          key: 'sr_targeting_config',\n          variants: { on: { key: 'on' }, off: { key: 'off' } },\n          segments: [],\n        };\n      }\n\n      sessionReplay.sessionTargetingMatch = false;\n      const shouldRecord = sessionReplay.getShouldRecord();\n\n      expect(shouldRecord).toBe(false);\n      expect(mockLoggerProvider.log).toHaveBeenCalledWith(\n        `Not capturing replays for session ${\n          mockOptions.sessionId?.toString() || ''\n        } due to not matching targeting conditions.`,\n      );\n    });\n\n    test('should return true when targetingConfig exists and sessionTargetingMatch is true', async () => {\n      await sessionReplay.init(apiKey, mockOptions).promise;\n\n      // Set targeting config directly on the config object\n      if (sessionReplay.config) {\n        sessionReplay.config.targetingConfig = {\n          key: 'sr_targeting_config',\n          variants: { on: { key: 'on' }, off: { key: 'off' } },\n          segments: [],\n        };\n      }\n\n      sessionReplay.sessionTargetingMatch = true;\n      const shouldRecord = sessionReplay.getShouldRecord();\n\n      expect(shouldRecord).toBe(true);\n      expect(mockLoggerProvider.log).toHaveBeenCalledWith(\n        `Capturing replays for session ${\n          mockOptions.sessionId?.toString() || ''\n        } due to matching targeting conditions.`,\n      );\n    });\n  });\n\n  describe('cross-origin iframes', () => {\n    const crossOriginOptions: SessionReplayOptions = {\n      ...mockOptions,\n      crossOriginIframes: { enabled: true },\n    };\n\n    // Helper to get the mock coordinator instance created during the last recordEvents() call.\n    // Uses mock.results (not mock.instances) because mockImplementation() return values\n    // are tracked in results, not in instances (instances tracks the `this` context).\n    function getLastCoordinatorInstance() {\n      const ctor = MockCrossOriginIframeCoordinator as jest.Mock;\n      const last = ctor.mock.results[ctor.mock.results.length - 1];\n      return last?.value as { start: jest.Mock; stop: jest.Mock };\n    }\n\n    beforeEach(() => {\n      (mockIsInIframe as jest.Mock).mockReturnValue(false);\n      // jest.resetAllMocks() in the outer afterEach clears mockImplementation, so re-set it here.\n      (MockCrossOriginIframeCoordinator as jest.Mock).mockImplementation(() => ({\n        start: jest.fn(),\n        stop: jest.fn(),\n      }));\n      (mockListenForParentSignals as jest.Mock).mockReturnValue(jest.fn());\n    });\n\n    describe('parent mode', () => {\n      test('passes recordCrossOriginIframes: true to rrweb when enabled', async () => {\n        await sessionReplay.init(apiKey, crossOriginOptions).promise;\n        await sessionReplay.recordEvents();\n        await jest.runAllTimersAsync();\n\n        expect(mockRecordFunction).toHaveBeenCalledWith(expect.objectContaining({ recordCrossOriginIframes: true }));\n      });\n\n      test('does not pass recordCrossOriginIframes when feature is disabled', async () => {\n        await sessionReplay.init(apiKey, mockOptions).promise;\n        await sessionReplay.recordEvents();\n        await jest.runAllTimersAsync();\n\n        const callArg = mockRecordFunction.mock.calls[0]?.[0] as Record<string, unknown> | undefined;\n        expect(callArg?.recordCrossOriginIframes).toBeFalsy();\n      });\n\n      test('stopRecordingEvents stops the coordinator', async () => {\n        await sessionReplay.init(apiKey, crossOriginOptions).promise;\n        await sessionReplay.recordEvents();\n        await jest.runAllTimersAsync();\n\n        const instance = getLastCoordinatorInstance();\n        sessionReplay.stopRecordingEvents();\n        expect(instance.stop).toHaveBeenCalled();\n      });\n\n      test('coordinateChildren: false skips coordinator but still passes flag to rrweb', async () => {\n        await sessionReplay.init(apiKey, {\n          ...mockOptions,\n          crossOriginIframes: { enabled: true, coordinateChildren: false },\n        }).promise;\n        await sessionReplay.recordEvents();\n        await jest.runAllTimersAsync();\n\n        expect(mockRecordFunction).toHaveBeenCalledWith(expect.objectContaining({ recordCrossOriginIframes: true }));\n        expect(MockCrossOriginIframeCoordinator).not.toHaveBeenCalled();\n      });\n    });\n\n    describe('child mode', () => {\n      beforeEach(() => {\n        (mockIsInIframe as jest.Mock).mockReturnValue(true);\n      });\n\n      test('does not call rrweb record immediately when in child mode with coordinateChildren: true', async () => {\n        await sessionReplay.init(apiKey, crossOriginOptions).promise;\n        await sessionReplay.recordEvents();\n        await jest.runAllTimersAsync();\n\n        expect(mockRecordFunction).not.toHaveBeenCalled();\n      });\n\n      test('sets up parent signal listener in child mode', async () => {\n        await sessionReplay.init(apiKey, crossOriginOptions).promise;\n        await sessionReplay.recordEvents();\n        await jest.runAllTimersAsync();\n\n        expect(mockListenForParentSignals).toHaveBeenCalledWith(\n          expect.objectContaining({ onStart: expect.any(Function), onStop: expect.any(Function) }),\n        );\n      });\n\n      test('re-entering child mode cancels the previous parent signal listener', async () => {\n        const firstCleanup = jest.fn();\n        (mockListenForParentSignals as jest.Mock).mockReturnValueOnce(firstCleanup);\n\n        await sessionReplay.init(apiKey, crossOriginOptions).promise;\n        await sessionReplay.recordEvents();\n        await jest.runAllTimersAsync();\n\n        // Record again (e.g. after a session-ID rotation) — should tear down the old listener\n        await sessionReplay.recordEvents();\n        await jest.runAllTimersAsync();\n\n        expect(firstCleanup).toHaveBeenCalled();\n      });\n\n      test('starts recording when onStart callback is invoked', async () => {\n        await sessionReplay.init(apiKey, crossOriginOptions).promise;\n        await sessionReplay.recordEvents();\n        await jest.runAllTimersAsync();\n\n        const { onStart } = (mockListenForParentSignals as jest.Mock).mock.calls[0][0] as {\n          onStart: () => void;\n          onStop: () => void;\n        };\n        onStart();\n\n        expect(mockRecordFunction).toHaveBeenCalledWith(expect.objectContaining({ recordCrossOriginIframes: true }));\n      });\n\n      test('stops recording when onStop callback is invoked', async () => {\n        await sessionReplay.init(apiKey, crossOriginOptions).promise;\n        await sessionReplay.recordEvents();\n        await jest.runAllTimersAsync();\n\n        const { onStart, onStop } = (mockListenForParentSignals as jest.Mock).mock.calls[0][0] as {\n          onStart: () => void;\n          onStop: () => void;\n        };\n        onStart();\n        const cancelCallback = mockRecordFunction.mock.results[0].value as jest.Mock;\n        onStop();\n        expect(cancelCallback).toHaveBeenCalled();\n      });\n\n      test('onStop before onStart does not throw', async () => {\n        await sessionReplay.init(apiKey, crossOriginOptions).promise;\n        await sessionReplay.recordEvents();\n        await jest.runAllTimersAsync();\n\n        const { onStop } = (mockListenForParentSignals as jest.Mock).mock.calls[0][0] as {\n          onStop: () => void;\n        };\n        expect(() => onStop()).not.toThrow();\n      });\n\n      test('onStop logs warning if cancel callback throws', async () => {\n        await sessionReplay.init(apiKey, crossOriginOptions).promise;\n        await sessionReplay.recordEvents();\n        await jest.runAllTimersAsync();\n\n        const { onStart, onStop } = (mockListenForParentSignals as jest.Mock).mock.calls[0][0] as {\n          onStart: () => void;\n          onStop: () => void;\n        };\n        onStart();\n        const cancelCallback = mockRecordFunction.mock.results[0].value as jest.Mock;\n        cancelCallback.mockImplementation(() => {\n          throw new Error('cancel failure');\n        });\n        onStop();\n        expect(mockLoggerProvider.warn).toHaveBeenCalledWith(\n          expect.stringContaining('Error occurred while stopping child iframe replay capture:'),\n        );\n      });\n\n      test('parent signal listener stays alive across onStop/onStart cycles', async () => {\n        await sessionReplay.init(apiKey, crossOriginOptions).promise;\n        await sessionReplay.recordEvents();\n        await jest.runAllTimersAsync();\n\n        const { onStart, onStop } = (mockListenForParentSignals as jest.Mock).mock.calls[0][0] as {\n          onStart: () => void;\n          onStop: () => void;\n        };\n        onStart();\n        onStop();\n\n        // Listener must still be alive — a subsequent onStart should work\n        mockRecordFunction.mockClear();\n        onStart();\n        expect(mockRecordFunction).toHaveBeenCalledWith(expect.objectContaining({ recordCrossOriginIframes: true }));\n      });\n\n      test('subsequent onStart cancels previous rrweb recording before starting a new one', async () => {\n        await sessionReplay.init(apiKey, crossOriginOptions).promise;\n        await sessionReplay.recordEvents();\n        await jest.runAllTimersAsync();\n\n        const { onStart } = (mockListenForParentSignals as jest.Mock).mock.calls[0][0] as {\n          onStart: () => void;\n        };\n        onStart();\n        const firstCancelCallback = mockRecordFunction.mock.results[0].value as jest.Mock;\n        // Second onStart (e.g. parent session rotated) should cancel the first recording\n        onStart();\n        expect(firstCancelCallback).toHaveBeenCalled();\n      });\n\n      test('cleans up parent signal listener on shutdown', async () => {\n        const mockCleanup = jest.fn();\n        (mockListenForParentSignals as jest.Mock).mockReturnValueOnce(mockCleanup);\n\n        await sessionReplay.init(apiKey, crossOriginOptions).promise;\n        await sessionReplay.recordEvents();\n        await jest.runAllTimersAsync();\n\n        sessionReplay.shutdown();\n        expect(mockCleanup).toHaveBeenCalled();\n      });\n\n      test('stopRecordingEvents cleans up parent signal listener to prevent stale mode', async () => {\n        const mockCleanup = jest.fn();\n        (mockListenForParentSignals as jest.Mock).mockReturnValueOnce(mockCleanup);\n\n        await sessionReplay.init(apiKey, crossOriginOptions).promise;\n        await sessionReplay.recordEvents();\n        await jest.runAllTimersAsync();\n\n        sessionReplay.stopRecordingEvents();\n        expect(mockCleanup).toHaveBeenCalled();\n      });\n\n      test('coordinateChildren: false records immediately even in iframe context', async () => {\n        await sessionReplay.init(apiKey, {\n          ...mockOptions,\n          crossOriginIframes: { enabled: true, coordinateChildren: false },\n        }).promise;\n        await sessionReplay.recordEvents();\n        await jest.runAllTimersAsync();\n\n        expect(mockRecordFunction).toHaveBeenCalledWith(expect.objectContaining({ recordCrossOriginIframes: true }));\n      });\n\n      test('child mode emit callback is a no-op (events forwarded via postMessage by rrweb)', async () => {\n        await sessionReplay.init(apiKey, crossOriginOptions).promise;\n        await sessionReplay.recordEvents();\n        await jest.runAllTimersAsync();\n\n        const { onStart } = (mockListenForParentSignals as jest.Mock).mock.calls[0][0] as {\n          onStart: () => void;\n        };\n        onStart();\n\n        const callArgs = mockRecordFunction.mock.calls[0]?.[0] as Record<string, (...args: unknown[]) => unknown>;\n        // The emit callback is a no-op in child mode — just verify it does not throw\n        expect(() => callArgs.emit({ type: 4, data: {}, timestamp: 1 })).not.toThrow();\n      });\n\n      test('mask function URL getters in child mode return currentPageUrl', async () => {\n        await sessionReplay.init(apiKey, crossOriginOptions).promise;\n        await sessionReplay.recordEvents();\n        await jest.runAllTimersAsync();\n\n        const { onStart } = (mockListenForParentSignals as jest.Mock).mock.calls[0][0] as {\n          onStart: () => void;\n        };\n        onStart();\n\n        const callArgs = mockRecordFunction.mock.calls[0]?.[0] as Record<string, (...args: unknown[]) => unknown>;\n        // Invoke the URL getter lambdas by calling the mask functions with dummy input\n        if (typeof callArgs?.maskInputFn === 'function') {\n          callArgs.maskInputFn('test', null);\n        }\n        if (typeof callArgs?.maskTextFn === 'function') {\n          callArgs.maskTextFn('test', null);\n        }\n        // No assertion needed — just exercising the lambdas for coverage\n      });\n\n      test('passes full slimDOMOptions into child mode', async () => {\n        await sessionReplay.init(apiKey, crossOriginOptions).promise;\n        await sessionReplay.recordEvents();\n        await jest.runAllTimersAsync();\n\n        const { onStart } = (mockListenForParentSignals as jest.Mock).mock.calls[0][0] as {\n          onStart: () => void;\n        };\n        onStart();\n\n        expect(mockRecordFunction).toHaveBeenCalledWith(\n          expect.objectContaining({\n            slimDOMOptions: {\n              script: true,\n              comment: true,\n              headFavicon: true,\n              headWhitespace: true,\n              headMetaDescKeywords: true,\n              headMetaSocial: true,\n              headMetaRobots: true,\n              headMetaHttpEquiv: true,\n              headMetaAuthorship: true,\n              headMetaVerification: true,\n            },\n          }),\n        );\n      });\n\n      test('maskAttributeFn in child mode invokes URL getter when key is in maskAttributes', async () => {\n        // Need a config with maskAttributes so the URL getter lambda is actually called\n        await sessionReplay.init(apiKey, {\n          ...crossOriginOptions,\n          privacyConfig: { maskAttributes: ['data-sensitive'] },\n        }).promise;\n        await sessionReplay.recordEvents();\n        await jest.runAllTimersAsync();\n\n        const { onStart } = (mockListenForParentSignals as jest.Mock).mock.calls[0][0] as {\n          onStart: () => void;\n        };\n        onStart();\n\n        const callArgs = mockRecordFunction.mock.calls[0]?.[0] as Record<string, (...args: unknown[]) => unknown>;\n        if (typeof callArgs?.maskAttributeFn === 'function') {\n          callArgs.maskAttributeFn('data-sensitive', 'secret', document.createElement('div'));\n        }\n      });\n\n      test('errorHandler in child mode logs warning for generic errors', async () => {\n        await sessionReplay.init(apiKey, crossOriginOptions).promise;\n        await sessionReplay.recordEvents();\n        await jest.runAllTimersAsync();\n\n        const { onStart } = (mockListenForParentSignals as jest.Mock).mock.calls[0][0] as {\n          onStart: () => void;\n        };\n        onStart();\n\n        const callArgs = mockRecordFunction.mock.calls[0]?.[0] as Record<string, (...args: unknown[]) => unknown>;\n        const result = callArgs.errorHandler(new Error('some rrweb error'));\n        expect(result).toBe(true);\n        expect(mockLoggerProvider.warn).toHaveBeenCalledWith(\n          'Error while capturing replay (child iframe): ',\n          expect.any(String),\n        );\n      });\n\n      test('errorHandler in child mode re-throws CSSStyleSheet insertRule errors', async () => {\n        await sessionReplay.init(apiKey, crossOriginOptions).promise;\n        await sessionReplay.recordEvents();\n        await jest.runAllTimersAsync();\n\n        const { onStart } = (mockListenForParentSignals as jest.Mock).mock.calls[0][0] as {\n          onStart: () => void;\n        };\n        onStart();\n\n        const callArgs = mockRecordFunction.mock.calls[0]?.[0] as Record<string, (...args: unknown[]) => unknown>;\n        const cssError = new Error('insertRule CSSStyleSheet problem');\n        expect(() => callArgs.errorHandler(cssError)).toThrow(cssError);\n      });\n\n      test('errorHandler in child mode re-throws _external_ flagged errors', async () => {\n        await sessionReplay.init(apiKey, crossOriginOptions).promise;\n        await sessionReplay.recordEvents();\n        await jest.runAllTimersAsync();\n\n        const { onStart } = (mockListenForParentSignals as jest.Mock).mock.calls[0][0] as {\n          onStart: () => void;\n        };\n        onStart();\n\n        const callArgs = mockRecordFunction.mock.calls[0]?.[0] as Record<string, (...args: unknown[]) => unknown>;\n        const externalError = Object.assign(new Error('external error'), { _external_: true });\n        expect(() => callArgs.errorHandler(externalError)).toThrow(externalError);\n      });\n\n      test('_recordEventsInChildMode catch block logs warning when recordFunction throws', async () => {\n        await sessionReplay.init(apiKey, crossOriginOptions).promise;\n        await sessionReplay.recordEvents();\n        await jest.runAllTimersAsync();\n\n        const { onStart } = (mockListenForParentSignals as jest.Mock).mock.calls[0][0] as {\n          onStart: () => void;\n        };\n\n        mockRecordFunction.mockImplementationOnce(() => {\n          throw new Error('rrweb init failure');\n        });\n        onStart();\n\n        expect(mockLoggerProvider.warn).toHaveBeenCalledWith(\n          'Failed to initialize session replay in child iframe mode:',\n          expect.any(Error),\n        );\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/targeting/targeting-idb-store.test.ts",
    "content": "import { Logger } from '@amplitude/analytics-types';\nimport { IDBPDatabase } from 'idb';\nimport { SessionReplayTargetingDB, targetingIDBStore } from '../../src/targeting/targeting-idb-store';\n\ntype MockedLogger = jest.Mocked<Logger>;\n\nconst apiKey = 'static_key';\n\ndescribe('TargetingIDBStore', () => {\n  const mockLoggerProvider: MockedLogger = {\n    error: jest.fn(),\n    log: jest.fn(),\n    disable: jest.fn(),\n    enable: jest.fn(),\n    warn: jest.fn(),\n    debug: jest.fn(),\n  };\n  let db: IDBPDatabase<SessionReplayTargetingDB>;\n  beforeEach(async () => {\n    db = await targetingIDBStore.openOrCreateDB('static_key');\n    await db.clear('sessionTargetingMatch');\n    jest.useFakeTimers();\n  });\n  afterEach(() => {\n    jest.resetAllMocks();\n    jest.useRealTimers();\n  });\n\n  describe('getTargetingMatchForSession', () => {\n    test('should return the targeting match from idb store', async () => {\n      await targetingIDBStore.storeTargetingMatchForSession({\n        loggerProvider: mockLoggerProvider,\n        sessionId: 123,\n        apiKey,\n        targetingMatch: true,\n      });\n      const targetingMatch = await targetingIDBStore.getTargetingMatchForSession({\n        loggerProvider: mockLoggerProvider,\n        sessionId: 123,\n        apiKey,\n      });\n      expect(targetingMatch).toEqual(true);\n    });\n    test('should return undefined if no matching entry in the store', async () => {\n      const targetingMatch = await targetingIDBStore.getTargetingMatchForSession({\n        loggerProvider: mockLoggerProvider,\n        sessionId: 123,\n        apiKey,\n      });\n      expect(targetingMatch).toEqual(undefined);\n    });\n    test('should catch errors', async () => {\n      const mockDB: IDBPDatabase<SessionReplayTargetingDB> = {\n        get: jest.fn().mockImplementation(() => Promise.reject('error')),\n      } as unknown as IDBPDatabase<SessionReplayTargetingDB>;\n      jest.spyOn(targetingIDBStore, 'openOrCreateDB').mockResolvedValueOnce(mockDB);\n      await targetingIDBStore.getTargetingMatchForSession({\n        loggerProvider: mockLoggerProvider,\n        sessionId: 123,\n        apiKey,\n      });\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLoggerProvider.warn).toHaveBeenCalledTimes(1);\n      expect(mockLoggerProvider.warn.mock.calls[0][0]).toEqual(\n        'Failed to get targeting match for session id 123: error',\n      );\n    });\n  });\n\n  describe('storeTargetingMatchForSession', () => {\n    test('should add the targeting match to idb store', async () => {\n      await targetingIDBStore.storeTargetingMatchForSession({\n        loggerProvider: mockLoggerProvider,\n        sessionId: 123,\n        apiKey,\n        targetingMatch: true,\n      });\n      const targetingMatch = await targetingIDBStore.getTargetingMatchForSession({\n        loggerProvider: mockLoggerProvider,\n        sessionId: 123,\n        apiKey,\n      });\n      expect(targetingMatch).toEqual(true);\n    });\n    test('should catch errors', async () => {\n      const mockDB: IDBPDatabase<SessionReplayTargetingDB> = {\n        put: jest.fn().mockImplementation(() => Promise.reject('error')),\n      } as unknown as IDBPDatabase<SessionReplayTargetingDB>;\n      jest.spyOn(targetingIDBStore, 'openOrCreateDB').mockResolvedValueOnce(mockDB);\n      await targetingIDBStore.storeTargetingMatchForSession({\n        loggerProvider: mockLoggerProvider,\n        sessionId: 123,\n        apiKey,\n        targetingMatch: true,\n      });\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLoggerProvider.warn).toHaveBeenCalledTimes(1);\n      expect(mockLoggerProvider.warn.mock.calls[0][0]).toEqual(\n        'Failed to store targeting match for session id 123: error',\n      );\n    });\n  });\n\n  describe('clearStoreOfOldSessions', () => {\n    test('should delete object stores with sessions older than 2 days', async () => {\n      // Set current time to 08:30\n      jest.useFakeTimers().setSystemTime(new Date('2023-07-31 08:30:00').getTime());\n\n      // Current session from one hour before, 07:30\n      const currentSessionId = new Date('2023-07-31 07:30:00').getTime();\n      await targetingIDBStore.storeTargetingMatchForSession({\n        loggerProvider: mockLoggerProvider,\n        apiKey,\n        sessionId: currentSessionId,\n        targetingMatch: true,\n      });\n\n      // Add session from the same day\n      await targetingIDBStore.storeTargetingMatchForSession({\n        loggerProvider: mockLoggerProvider,\n        apiKey,\n        sessionId: new Date('2023-07-31 05:30:00').getTime(),\n        targetingMatch: true,\n      });\n\n      // Add session from one month ago - set the time to simulate this being created a month ago\n      jest.setSystemTime(new Date('2023-06-31 10:30:00').getTime());\n      await targetingIDBStore.storeTargetingMatchForSession({\n        loggerProvider: mockLoggerProvider,\n        apiKey,\n        sessionId: new Date('2023-06-31 10:30:00').getTime(),\n        targetingMatch: true,\n      });\n\n      // Reset time back to current\n      jest.setSystemTime(new Date('2023-07-31 08:30:00').getTime());\n\n      const allEntries =\n        targetingIDBStore.dbs && (await targetingIDBStore.dbs['static_key'].getAll('sessionTargetingMatch'));\n      expect(allEntries).toEqual([\n        {\n          sessionId: String(new Date('2023-06-31 10:30:00').getTime()),\n          targetingMatch: true,\n          lastUpdated: new Date('2023-06-31 10:30:00').getTime(),\n        },\n        {\n          sessionId: String(new Date('2023-07-31 05:30:00').getTime()),\n          targetingMatch: true,\n          lastUpdated: new Date('2023-07-31 08:30:00').getTime(),\n        },\n        {\n          sessionId: String(currentSessionId),\n          targetingMatch: true,\n          lastUpdated: new Date('2023-07-31 08:30:00').getTime(),\n        },\n      ]);\n\n      await targetingIDBStore.clearStoreOfOldSessions({\n        loggerProvider: mockLoggerProvider,\n        apiKey,\n        currentSessionId,\n      });\n\n      const allEntriesUpdated =\n        targetingIDBStore.dbs && (await targetingIDBStore.dbs['static_key'].getAll('sessionTargetingMatch'));\n      // Only one month old entry should be deleted\n      expect(allEntriesUpdated).toEqual([\n        {\n          sessionId: String(new Date('2023-07-31 05:30:00').getTime()),\n          targetingMatch: true,\n          lastUpdated: new Date('2023-07-31 08:30:00').getTime(),\n        },\n        {\n          sessionId: String(currentSessionId),\n          targetingMatch: true,\n          lastUpdated: new Date('2023-07-31 08:30:00').getTime(),\n        },\n      ]);\n    });\n    test('should catch errors', async () => {\n      const mockDB: IDBPDatabase<SessionReplayTargetingDB> = {\n        transaction: jest.fn().mockImplementation(() => {\n          throw new Error('error');\n        }),\n      } as unknown as IDBPDatabase<SessionReplayTargetingDB>;\n      jest.spyOn(targetingIDBStore, 'openOrCreateDB').mockResolvedValueOnce(mockDB);\n      await targetingIDBStore.clearStoreOfOldSessions({\n        loggerProvider: mockLoggerProvider,\n        currentSessionId: 123,\n        apiKey,\n      });\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLoggerProvider.warn).toHaveBeenCalledTimes(1);\n      expect(mockLoggerProvider.warn.mock.calls[0][0]).toEqual(\n        'Failed to clear old targeting matches for sessions: Error: error',\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/targeting/targeting-manager.test.ts",
    "content": "import { Logger } from '@amplitude/analytics-types';\nimport * as Targeting from '@amplitude/targeting';\nimport { IDBPDatabase } from 'idb';\nimport { SessionReplayJoinedConfig } from '../../src/config/types';\nimport { SessionReplayTargetingDB, targetingIDBStore } from '../../src/targeting/targeting-idb-store';\nimport { evaluateTargetingAndStore } from '../../src/targeting/targeting-manager';\nimport { flagConfig } from '../flag-config-data';\n\ntype MockedLogger = jest.Mocked<Logger>;\n\njest.mock('@amplitude/targeting');\ntype MockedTargeting = jest.Mocked<typeof import('@amplitude/targeting')>;\n\ndescribe('Targeting Manager', () => {\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n  const { evaluateTargeting } = Targeting as MockedTargeting;\n  let originalFetch: typeof global.fetch;\n  const mockLoggerProvider: MockedLogger = {\n    error: jest.fn(),\n    log: jest.fn(),\n    disable: jest.fn(),\n    enable: jest.fn(),\n    warn: jest.fn(),\n    debug: jest.fn(),\n  };\n  const config: SessionReplayJoinedConfig = {\n    apiKey: 'static_key',\n    loggerProvider: mockLoggerProvider,\n    sampleRate: 1,\n    targetingConfig: flagConfig,\n  } as unknown as SessionReplayJoinedConfig;\n  let db: IDBPDatabase<SessionReplayTargetingDB>;\n  beforeEach(async () => {\n    db = await targetingIDBStore.openOrCreateDB('static_key');\n    await db.clear('sessionTargetingMatch');\n    jest.useFakeTimers();\n    originalFetch = global.fetch;\n    global.fetch = jest.fn(() =>\n      Promise.resolve({\n        status: 200,\n      }),\n    ) as jest.Mock;\n  });\n  afterEach(() => {\n    jest.resetAllMocks();\n    global.fetch = originalFetch;\n\n    jest.useRealTimers();\n  });\n\n  describe('evaluateTargetingAndStore', () => {\n    let storeTargetingMatchForSessionMock: jest.SpyInstance;\n    let getTargetingMatchForSessionMock: jest.SpyInstance;\n    beforeEach(() => {\n      storeTargetingMatchForSessionMock = jest.spyOn(targetingIDBStore, 'storeTargetingMatchForSession');\n      getTargetingMatchForSessionMock = jest.spyOn(targetingIDBStore, 'getTargetingMatchForSession');\n    });\n    test('should return a true match from IndexedDB', async () => {\n      jest.spyOn(targetingIDBStore, 'getTargetingMatchForSession').mockResolvedValueOnce(true);\n      const sessionTargetingMatch = await evaluateTargetingAndStore({\n        sessionId: 123,\n        loggerProvider: config.loggerProvider,\n        apiKey: config.apiKey,\n        targetingConfig: flagConfig,\n      });\n      expect(getTargetingMatchForSessionMock).toHaveBeenCalled();\n      expect(evaluateTargeting).not.toHaveBeenCalled();\n      expect(sessionTargetingMatch).toBe(true);\n    });\n\n    test('should use remote config to determine targeting match', async () => {\n      jest.spyOn(targetingIDBStore, 'getTargetingMatchForSession').mockResolvedValueOnce(false);\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access\n      (evaluateTargeting as jest.Mock).mockResolvedValueOnce({\n        sr_targeting_config: {\n          key: 'on',\n        },\n      });\n      const mockUserProperties = {\n        country: 'US',\n        city: 'San Francisco',\n      };\n      const sessionTargetingMatch = await evaluateTargetingAndStore({\n        sessionId: 123,\n        loggerProvider: config.loggerProvider,\n        apiKey: config.apiKey,\n        targetingConfig: flagConfig,\n        targetingParams: {\n          userProperties: mockUserProperties,\n        },\n      });\n      expect(evaluateTargeting).toHaveBeenCalledWith({\n        apiKey: 'static_key',\n        loggerProvider: mockLoggerProvider,\n        flag: flagConfig,\n        sessionId: 123,\n        userProperties: mockUserProperties,\n      });\n      expect(sessionTargetingMatch).toBe(true);\n    });\n\n    test('should pass page to evaluateTargeting when provided in targetingParams', async () => {\n      jest.spyOn(targetingIDBStore, 'getTargetingMatchForSession').mockResolvedValueOnce(false);\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access\n      (evaluateTargeting as jest.Mock).mockResolvedValueOnce({\n        sr_targeting_config: {\n          key: 'on',\n        },\n      });\n      const page = { url: 'https://example.com/analytics' };\n      const sessionTargetingMatch = await evaluateTargetingAndStore({\n        sessionId: 123,\n        loggerProvider: config.loggerProvider,\n        apiKey: config.apiKey,\n        targetingConfig: flagConfig,\n        targetingParams: {\n          userProperties: {},\n          page,\n        },\n      });\n      expect(evaluateTargeting).toHaveBeenCalledWith(\n        expect.objectContaining({\n          apiKey: 'static_key',\n          loggerProvider: mockLoggerProvider,\n          flag: flagConfig,\n          sessionId: 123,\n          page,\n        }),\n      );\n      expect(sessionTargetingMatch).toBe(true);\n    });\n\n    test('should re-evaluate when urlChange is true even if IDB cache is true (URL change)', async () => {\n      jest.spyOn(targetingIDBStore, 'getTargetingMatchForSession').mockResolvedValueOnce(true);\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access\n      (evaluateTargeting as jest.Mock).mockResolvedValueOnce({\n        sr_targeting_config: { key: 'off' },\n      });\n      const sessionTargetingMatch = await evaluateTargetingAndStore({\n        sessionId: 123,\n        loggerProvider: config.loggerProvider,\n        apiKey: config.apiKey,\n        targetingConfig: flagConfig,\n        targetingParams: { page: { url: 'https://example.com/new-page' } },\n        urlChange: true,\n      });\n      expect(evaluateTargeting).toHaveBeenCalled();\n      expect(sessionTargetingMatch).toBe(false);\n    });\n\n    test('should store sessionTargetingMatch', async () => {\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access\n      (evaluateTargeting as jest.Mock).mockResolvedValueOnce({\n        sr_targeting_config: {\n          key: 'on',\n        },\n      });\n      const sessionTargetingMatch = await evaluateTargetingAndStore({\n        sessionId: 123,\n        loggerProvider: config.loggerProvider,\n        apiKey: config.apiKey,\n        targetingConfig: flagConfig,\n      });\n      expect(storeTargetingMatchForSessionMock).toHaveBeenCalledWith({\n        targetingMatch: true,\n        sessionId: 123,\n        apiKey: config.apiKey,\n        loggerProvider: mockLoggerProvider,\n      });\n      expect(sessionTargetingMatch).toBe(true);\n    });\n    test('should handle error', async () => {\n      jest.spyOn(targetingIDBStore, 'storeTargetingMatchForSession').mockImplementationOnce(() => {\n        throw new Error('storage error');\n      });\n      const sessionTargetingMatch = await evaluateTargetingAndStore({\n        sessionId: 123,\n        loggerProvider: config.loggerProvider,\n        apiKey: config.apiKey,\n        targetingConfig: flagConfig,\n      });\n      expect(sessionTargetingMatch).toBe(true);\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLoggerProvider.warn).toHaveBeenCalledTimes(1);\n      expect(mockLoggerProvider.warn.mock.calls[0][0]).toEqual('storage error');\n    });\n\n    test('should parse string sessionId to number when calling evaluateTargeting', async () => {\n      jest.spyOn(targetingIDBStore, 'getTargetingMatchForSession').mockResolvedValueOnce(false);\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access\n      (evaluateTargeting as jest.Mock).mockResolvedValueOnce({\n        sr_targeting_config: {\n          key: 'on',\n        },\n      });\n      const sessionTargetingMatch = await evaluateTargetingAndStore({\n        sessionId: '456',\n        loggerProvider: config.loggerProvider,\n        apiKey: config.apiKey,\n        targetingConfig: flagConfig,\n      });\n      expect(evaluateTargeting).toHaveBeenCalledWith({\n        apiKey: 'static_key',\n        loggerProvider: mockLoggerProvider,\n        flag: flagConfig,\n        sessionId: 456,\n      });\n      expect(sessionTargetingMatch).toBe(true);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/test-data.ts",
    "content": "// This session id will be included in a 20% sample rate or higher (xxHash32 ratio ~0.1097)\nexport const SESSION_ID_IN_20_SAMPLE = 1719847315013;\n"
  },
  {
    "path": "packages/session-replay-browser/test/track-destination.test.ts",
    "content": "import * as AnalyticsCore from '@amplitude/analytics-core';\nimport { ILogger, ServerZone } from '@amplitude/analytics-core';\nimport { SessionReplayDestinationContext } from 'src/typings/session-replay';\nimport { SessionReplayTrackDestination } from '../src/track-destination';\nimport { VERSION } from '../src/version';\n\ntype MockedLogger = jest.Mocked<ILogger>;\nconst mockEvent = {\n  type: 4,\n  data: { href: 'https://analytics.amplitude.com/', width: 1728, height: 154 },\n  timestamp: 1687358660935,\n};\nconst mockEventString = JSON.stringify(mockEvent);\n\nasync function runScheduleTimers() {\n  // exhause first setTimeout\n  jest.runAllTimers();\n  // wait for next tick to call nested setTimeout\n  await Promise.resolve();\n  // exhause nested setTimeout\n  jest.runAllTimers();\n}\nconst apiKey = 'static_key';\n\ndescribe('SessionReplayTrackDestination', () => {\n  let originalFetch: typeof global.fetch;\n  const mockLoggerProvider: MockedLogger = {\n    error: jest.fn(),\n    log: jest.fn(),\n    disable: jest.fn(),\n    enable: jest.fn(),\n    warn: jest.fn(),\n    debug: jest.fn(),\n  };\n  const mockOnComplete = jest.fn();\n  beforeEach(() => {\n    jest.useFakeTimers();\n    originalFetch = global.fetch;\n    global.fetch = jest.fn(() =>\n      Promise.resolve({\n        status: 200,\n      }),\n    ) as jest.Mock;\n\n    jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({} as unknown as typeof globalThis);\n  });\n  afterEach(() => {\n    jest.resetAllMocks();\n    jest.spyOn(global.Math, 'random').mockRestore();\n    global.fetch = originalFetch;\n    jest.useRealTimers();\n  });\n  describe('addToQueue', () => {\n    test('should add to queue and schedule a flush', async () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      const schedule = jest.spyOn(trackDestination, 'schedule').mockReturnValueOnce(undefined);\n      const context: SessionReplayDestinationContext = {\n        events: [mockEventString],\n\n        sessionId: 123,\n        apiKey,\n        attempts: 0,\n        timeout: 0,\n        deviceId: '1a2b3c',\n        sampleRate: 1,\n        serverZone: ServerZone.US,\n        type: 'replay',\n        onComplete: mockOnComplete,\n        flushMaxRetries: 1,\n      };\n      trackDestination.addToQueue(context);\n      expect(schedule).toHaveBeenCalledTimes(1);\n      expect(schedule).toHaveBeenCalledWith(0);\n      expect(context.attempts).toBe(1);\n    });\n\n    test('should not add to queue if attemps are greater than allowed retries', async () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      const completeRequest = jest.spyOn(trackDestination, 'completeRequest').mockReturnValueOnce(undefined);\n      const context: SessionReplayDestinationContext = {\n        events: [mockEventString],\n\n        sessionId: 123,\n        apiKey,\n        attempts: 1,\n        timeout: 0,\n        deviceId: '1a2b3c',\n        sampleRate: 1,\n        serverZone: ServerZone.US,\n        type: 'replay',\n        onComplete: mockOnComplete,\n      };\n      trackDestination.addToQueue(context);\n      expect(completeRequest).toHaveBeenCalledTimes(1);\n      expect(completeRequest).toHaveBeenCalledWith({\n        context: context,\n        err: 'Session replay event batch rejected due to exceeded retry count',\n      });\n    });\n\n    test('should not add a duplicate sequence to the queue', async () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      const schedule = jest.spyOn(trackDestination, 'schedule').mockReturnValueOnce(undefined);\n      const context: SessionReplayDestinationContext = {\n        events: [mockEventString],\n\n        sessionId: 123,\n        apiKey,\n        attempts: 0,\n        timeout: 0,\n        deviceId: '1a2b3c',\n        sampleRate: 1,\n        serverZone: ServerZone.US,\n        type: 'replay',\n        onComplete: mockOnComplete,\n        flushMaxRetries: 1,\n      };\n      trackDestination.addToQueue(context);\n      // Add the same context a second time\n      trackDestination.addToQueue(context);\n      expect(schedule).toHaveBeenCalledTimes(1);\n      expect(trackDestination.queue).toEqual([context]);\n    });\n  });\n\n  describe('schedule', () => {\n    test('should schedule a flush', async () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n      (trackDestination as any).scheduled = null;\n      trackDestination.queue = [\n        {\n          events: [mockEventString],\n\n          sessionId: 123,\n          apiKey,\n          attempts: 0,\n          timeout: 0,\n          flushMaxRetries: 1,\n          deviceId: '1a2b3c',\n          sampleRate: 1,\n          serverZone: ServerZone.US,\n          type: 'replay',\n          onComplete: mockOnComplete,\n        },\n      ];\n      const flush = jest\n        .spyOn(trackDestination, 'flush')\n        .mockImplementationOnce(() => {\n          // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n          (trackDestination as any).scheduled = null;\n          return Promise.resolve(undefined);\n        })\n        .mockReturnValueOnce(Promise.resolve(undefined));\n      trackDestination.schedule(0);\n      await runScheduleTimers();\n      expect(flush).toHaveBeenCalledTimes(2);\n    });\n\n    test('should not schedule if one is already in progress', () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n      (trackDestination as any).scheduled = setTimeout(jest.fn, 0);\n      const flush = jest.spyOn(trackDestination, 'flush').mockReturnValueOnce(Promise.resolve(undefined));\n      trackDestination.schedule(0);\n      expect(flush).toHaveBeenCalledTimes(0);\n    });\n  });\n\n  describe('flush', () => {\n    test('should call send', async () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      trackDestination.queue = [\n        {\n          events: [mockEventString],\n\n          sessionId: 123,\n          apiKey,\n          attempts: 0,\n          timeout: 0,\n          flushMaxRetries: 1,\n          deviceId: '1a2b3c',\n          sampleRate: 1,\n          serverZone: ServerZone.US,\n          type: 'replay',\n          onComplete: mockOnComplete,\n        },\n      ];\n      const send = jest.spyOn(trackDestination, 'send').mockReturnValueOnce(Promise.resolve());\n      const result = await trackDestination.flush();\n      expect(trackDestination.queue).toEqual([]);\n      expect(result).toBe(undefined);\n      expect(send).toHaveBeenCalledTimes(1);\n    });\n\n    test('should send batches sequentially in order', async () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n\n      const sendOrder: number[] = [];\n      let resolveFirst!: () => void;\n\n      jest\n        .spyOn(trackDestination, 'send')\n        .mockImplementationOnce(() => {\n          sendOrder.push(1);\n          return new Promise<void>((resolve) => {\n            resolveFirst = resolve;\n          });\n        })\n        .mockImplementationOnce(() => {\n          sendOrder.push(2);\n          return Promise.resolve();\n        });\n\n      trackDestination.queue = [\n        {\n          events: [mockEventString],\n          sessionId: 1,\n          apiKey,\n          attempts: 0,\n          timeout: 0,\n          flushMaxRetries: 1,\n          deviceId: '1a2b3c',\n          sampleRate: 1,\n          serverZone: ServerZone.US,\n          type: 'replay',\n          onComplete: mockOnComplete,\n        },\n        {\n          events: [mockEventString],\n          sessionId: 2,\n          apiKey,\n          attempts: 0,\n          timeout: 0,\n          flushMaxRetries: 1,\n          deviceId: '1a2b3c',\n          sampleRate: 1,\n          serverZone: ServerZone.US,\n          type: 'replay',\n          onComplete: mockOnComplete,\n        },\n      ];\n\n      const flushPromise = trackDestination.flush();\n\n      // First send should have started; second should not have started yet\n      expect(sendOrder).toEqual([1]);\n\n      resolveFirst();\n      await flushPromise;\n\n      expect(sendOrder).toEqual([1, 2]);\n    });\n  });\n\n  describe('send', () => {\n    test('should not send anything if no events present', async () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      trackDestination.loggerProvider = mockLoggerProvider;\n      const context: SessionReplayDestinationContext = {\n        events: [],\n\n        sessionId: 123,\n        attempts: 0,\n        timeout: 0,\n        flushMaxRetries: 1,\n        deviceId: '1a2b3c',\n        sampleRate: 1,\n        serverZone: ServerZone.US,\n        type: 'replay',\n        apiKey,\n        onComplete: mockOnComplete,\n      };\n      await trackDestination.send(context);\n      expect(fetch).not.toHaveBeenCalled();\n    });\n    test('should not send anything if api key not set', async () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      trackDestination.loggerProvider = mockLoggerProvider;\n      const context: SessionReplayDestinationContext = {\n        events: [mockEventString],\n\n        sessionId: 123,\n        attempts: 0,\n        timeout: 0,\n        flushMaxRetries: 1,\n        deviceId: '1a2b3c',\n        sampleRate: 1,\n        serverZone: ServerZone.US,\n        type: 'replay',\n        onComplete: mockOnComplete,\n      };\n      await trackDestination.send(context);\n      expect(fetch).not.toHaveBeenCalled();\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLoggerProvider.warn).toHaveBeenCalled();\n    });\n    test('should not send anything if device id not set', async () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      const context: SessionReplayDestinationContext = {\n        events: [mockEventString],\n\n        sessionId: 123,\n        apiKey,\n        attempts: 0,\n        timeout: 0,\n        deviceId: undefined,\n        flushMaxRetries: 1,\n        sampleRate: 1,\n        serverZone: ServerZone.US,\n        type: 'replay',\n        onComplete: mockOnComplete,\n      };\n      await trackDestination.send(context);\n      expect(fetch).not.toHaveBeenCalled();\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLoggerProvider.warn).toHaveBeenCalled();\n    });\n    test('should make a request correctly', async () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      const context: SessionReplayDestinationContext = {\n        events: [mockEventString],\n\n        sessionId: 123,\n        apiKey,\n        attempts: 0,\n        timeout: 0,\n        flushMaxRetries: 1,\n        deviceId: '1a2b3c',\n        sampleRate: 1,\n        serverZone: ServerZone.US,\n        type: 'replay',\n        onComplete: mockOnComplete,\n        version: {\n          type: 'plugin',\n          version: VERSION,\n        },\n      };\n\n      await trackDestination.send(context);\n      expect(fetch).toHaveBeenCalledTimes(1);\n      expect(fetch).toHaveBeenCalledWith(\n        'https://api-sr.amplitude.com/sessions/v2/track?device_id=1a2b3c&session_id=123&type=replay',\n        {\n          body: JSON.stringify({ version: 1, events: [mockEventString] }),\n          headers: {\n            Accept: '*/*',\n            'Content-Type': 'application/json',\n            Authorization: 'Bearer static_key',\n            'X-Client-Library': `plugin/${VERSION}`,\n            'X-Client-Sample-Rate': '1',\n            'X-Sampling-Hash-Alg': 'xxhash32',\n            'X-Client-Url': '',\n            'X-Client-Version': VERSION,\n          },\n          method: 'POST',\n          keepalive: true,\n        },\n      );\n    });\n    test('should make a request to eu', async () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n\n      const context: SessionReplayDestinationContext = {\n        events: [mockEventString],\n\n        sessionId: 123,\n        apiKey,\n        attempts: 0,\n        timeout: 0,\n        serverZone: ServerZone.EU,\n        flushMaxRetries: 1,\n        deviceId: '1a2b3c',\n        sampleRate: 1,\n        type: 'replay',\n        onComplete: mockOnComplete,\n      };\n\n      await trackDestination.send(context);\n      expect(fetch).toHaveBeenCalledTimes(1);\n      expect(fetch).toHaveBeenCalledWith(\n        'https://api-sr.eu.amplitude.com/sessions/v2/track?device_id=1a2b3c&session_id=123&type=replay',\n        {\n          body: JSON.stringify({ version: 1, events: [mockEventString] }),\n          headers: {\n            Accept: '*/*',\n            'Content-Type': 'application/json',\n            Authorization: 'Bearer static_key',\n            'X-Client-Library': `standalone/${VERSION}`,\n            'X-Client-Sample-Rate': '1',\n            'X-Sampling-Hash-Alg': 'xxhash32',\n            'X-Client-Url': '',\n            'X-Client-Version': VERSION,\n          },\n          method: 'POST',\n          keepalive: true,\n        },\n      );\n    });\n\n    test('should retry if retry param is true', async () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      const context: SessionReplayDestinationContext = {\n        events: [mockEventString],\n\n        sessionId: 123,\n        apiKey,\n        attempts: 0,\n        timeout: 0,\n        flushMaxRetries: 2,\n        deviceId: '1a2b3c',\n        sampleRate: 1,\n        serverZone: ServerZone.US,\n        type: 'replay',\n        onComplete: mockOnComplete,\n      };\n      (global.fetch as jest.Mock)\n        .mockImplementationOnce(() =>\n          Promise.resolve({\n            status: 500,\n          }),\n        )\n        .mockImplementationOnce(() =>\n          Promise.resolve({\n            status: 200,\n          }),\n        );\n\n      const sendPromise = trackDestination.send(context, true);\n      await jest.runAllTimersAsync();\n      await sendPromise;\n\n      expect(fetch).toHaveBeenCalledTimes(2);\n    });\n\n    test.each([408, 429, 499])('should retry on %i', async (statusCode) => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      const context: SessionReplayDestinationContext = {\n        events: [mockEventString],\n        sessionId: 123,\n        apiKey,\n        attempts: 0,\n        timeout: 0,\n        flushMaxRetries: 2,\n        deviceId: '1a2b3c',\n        sampleRate: 1,\n        serverZone: ServerZone.US,\n        type: 'replay',\n        onComplete: mockOnComplete,\n      };\n      (global.fetch as jest.Mock)\n        .mockImplementationOnce(() => Promise.resolve({ status: statusCode }))\n        .mockImplementationOnce(() => Promise.resolve({ status: 200 }));\n\n      const sendPromise = trackDestination.send(context, true);\n      await jest.runAllTimersAsync();\n      await sendPromise;\n\n      expect(fetch).toHaveBeenCalledTimes(2);\n    });\n\n    test('should not retry if retry param is false', async () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      const context: SessionReplayDestinationContext = {\n        events: [mockEventString],\n\n        sessionId: 123,\n        apiKey,\n        attempts: 0,\n        timeout: 0,\n        flushMaxRetries: 1,\n        deviceId: '1a2b3c',\n        sampleRate: 1,\n        serverZone: ServerZone.US,\n        type: 'replay',\n        onComplete: mockOnComplete,\n      };\n      (global.fetch as jest.Mock).mockImplementationOnce(() =>\n        Promise.resolve({\n          status: 500,\n        }),\n      );\n      const addToQueue = jest.spyOn(trackDestination, 'addToQueue');\n\n      await trackDestination.send(context, false);\n      expect(addToQueue).toHaveBeenCalledTimes(0);\n    });\n  });\n\n  describe('keepalive', () => {\n    test('sets keepalive true for small payloads', async () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      const context: SessionReplayDestinationContext = {\n        events: [mockEventString],\n        sessionId: 123,\n        apiKey,\n        attempts: 0,\n        timeout: 0,\n        flushMaxRetries: 1,\n        deviceId: '1a2b3c',\n        sampleRate: 1,\n        serverZone: ServerZone.US,\n        type: 'replay',\n        onComplete: mockOnComplete,\n      };\n      await trackDestination.send(context);\n      const options = (fetch as jest.Mock).mock.calls[0][1] as RequestInit;\n      expect(options.keepalive).toBe(true);\n    });\n\n    test('sets keepalive false when uncompressed payload exceeds 64 KB', async () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      // ~66 KB of event data\n      const bigEvent = 'x'.repeat(66 * 1024);\n      const context: SessionReplayDestinationContext = {\n        events: [bigEvent],\n        sessionId: 123,\n        apiKey,\n        attempts: 0,\n        timeout: 0,\n        flushMaxRetries: 1,\n        deviceId: '1a2b3c',\n        sampleRate: 1,\n        serverZone: ServerZone.US,\n        type: 'replay',\n        onComplete: mockOnComplete,\n      };\n      await trackDestination.send(context);\n      const options = (fetch as jest.Mock).mock.calls[0][1] as RequestInit;\n      expect(options.keepalive).toBe(false);\n    });\n  });\n\n  describe('gzip compression', () => {\n    const makeContext = (): SessionReplayDestinationContext => ({\n      events: [mockEventString],\n      sessionId: 123,\n      apiKey,\n      attempts: 0,\n      timeout: 0,\n      flushMaxRetries: 1,\n      deviceId: '1a2b3c',\n      sampleRate: 1,\n      serverZone: ServerZone.US,\n      type: 'replay',\n      onComplete: mockOnComplete,\n    });\n\n    test('should send with Content-Encoding: gzip when CompressionStream is available', async () => {\n      const mockCompressed = new Uint8Array([0x1f, 0x8b]); // minimal gzip magic bytes\n\n      // Mock a CompressionStream that returns a compressed chunk\n      const mockWriter = { write: jest.fn(), close: jest.fn().mockResolvedValue(undefined) };\n      const mockReader = {\n        read: jest\n          .fn()\n          .mockResolvedValueOnce({ done: false, value: mockCompressed })\n          .mockResolvedValueOnce({ done: true, value: undefined }),\n      };\n      class MockCompressionStream {\n        writable = { getWriter: () => mockWriter };\n        readable = { getReader: () => mockReader };\n      }\n      // Override getGlobalScope to expose CompressionStream\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        CompressionStream: MockCompressionStream,\n      } as unknown as typeof globalThis);\n\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      await trackDestination.send(makeContext());\n\n      expect(fetch).toHaveBeenCalledTimes(1);\n      const options = (fetch as jest.Mock).mock.calls[0][1] as RequestInit;\n      expect((options.headers as Record<string, string>)['Content-Encoding']).toBe('gzip');\n      expect(options.body).toEqual(mockCompressed);\n    });\n\n    test('should send without Content-Encoding when CompressionStream throws', async () => {\n      class BrokenCompressionStream {\n        constructor() {\n          throw new Error('not supported');\n        }\n      }\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        CompressionStream: BrokenCompressionStream,\n      } as unknown as typeof globalThis);\n\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      await trackDestination.send(makeContext());\n\n      const options = (fetch as jest.Mock).mock.calls[0][1] as RequestInit;\n      expect((options.headers as Record<string, string>)['Content-Encoding']).toBeUndefined();\n      expect(typeof options.body).toBe('string');\n    });\n  });\n\n  describe('handleReponse', () => {\n    test('handles 413 without responseBody argument (uses default empty string)', async () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      const handlePayloadTooLarge = jest\n        .spyOn(trackDestination, 'handlePayloadTooLargeResponse')\n        .mockReturnValueOnce(undefined);\n      const context: SessionReplayDestinationContext = {\n        events: [mockEventString],\n        sessionId: 123,\n        apiKey,\n        attempts: 1,\n        timeout: 0,\n        deviceId: '1a2b3c',\n        sampleRate: 1,\n        serverZone: ServerZone.US,\n        type: 'replay',\n        onComplete: mockOnComplete,\n      };\n      // Call without the optional responseBody argument to exercise the default\n      await trackDestination.handleReponse(413, context);\n      expect(handlePayloadTooLarge).toHaveBeenCalledWith(context, false);\n    });\n  });\n\n  describe('handleOtherResponse', () => {\n    test('should complete request when flushMaxRetries is not set', async () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      const completeRequest = jest.spyOn(trackDestination, 'completeRequest').mockReturnValueOnce(undefined);\n      const context: SessionReplayDestinationContext = {\n        events: [mockEventString],\n        sessionId: 123,\n        apiKey,\n        attempts: 1,\n        timeout: 0,\n        deviceId: '1a2b3c',\n        sampleRate: 1,\n        serverZone: ServerZone.US,\n        type: 'replay',\n        onComplete: mockOnComplete,\n      };\n      await trackDestination.handleOtherResponse(context);\n      expect(completeRequest).toHaveBeenCalledWith({\n        context,\n        err: 'Session replay event batch rejected due to exceeded retry count',\n      });\n    });\n  });\n\n  describe('handlePayloadTooLargeResponse', () => {\n    const baseContext = (overrides = {}): SessionReplayDestinationContext => ({\n      events: [mockEventString],\n      sessionId: 123,\n      apiKey,\n      attempts: 1,\n      timeout: 0,\n      deviceId: '1a2b3c',\n      sampleRate: 1,\n      serverZone: ServerZone.US,\n      type: 'replay',\n      onComplete: mockOnComplete,\n      ...overrides,\n    });\n\n    test('drops non-WAF batch immediately without bisecting', () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      const completeRequest = jest.spyOn(trackDestination, 'completeRequest').mockReturnValueOnce(undefined);\n      const sendEventsList = jest.spyOn(trackDestination, 'sendEventsList');\n      const context = baseContext({ events: ['event1', 'event2'] });\n\n      trackDestination.handlePayloadTooLargeResponse(context, false);\n\n      expect(completeRequest).toHaveBeenCalledWith({\n        context,\n        err: expect.stringContaining('not retrying non-WAF 413'),\n      });\n      expect(sendEventsList).not.toHaveBeenCalled();\n    });\n\n    test('drops single WAF event and logs error with size', () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      const completeRequest = jest.spyOn(trackDestination, 'completeRequest').mockReturnValueOnce(undefined);\n      const context = baseContext();\n\n      trackDestination.handlePayloadTooLargeResponse(context, true);\n\n      expect(completeRequest).toHaveBeenCalledWith({\n        context,\n        err: expect.stringContaining('single event'),\n      });\n      expect(completeRequest.mock.calls[0][0].err).toContain('cannot split further');\n    });\n\n    test('names WAF as source when isWaf is true', () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      jest.spyOn(trackDestination, 'completeRequest').mockReturnValueOnce(undefined);\n      const context = baseContext();\n\n      trackDestination.handlePayloadTooLargeResponse(context, true);\n\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      const errArg = (trackDestination.completeRequest as jest.Mock).mock.calls[0][0].err as string;\n      expect(errArg).toContain('WAF');\n    });\n\n    test('bisects multi-event WAF batch and re-enqueues both halves', () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      const capturedOnCompletes: Array<() => Promise<void>> = [];\n      jest.spyOn(trackDestination, 'sendEventsList').mockImplementation((dest) => {\n        capturedOnCompletes.push(dest.onComplete);\n      });\n      const context = baseContext({ events: ['event1', 'event2', 'event3', 'event4'] });\n\n      trackDestination.handlePayloadTooLargeResponse(context, true);\n\n      expect((trackDestination.sendEventsList as jest.Mock).mock.calls).toHaveLength(2);\n      expect((trackDestination.sendEventsList as jest.Mock).mock.calls[0][0].events).toEqual(['event1', 'event2']);\n      expect((trackDestination.sendEventsList as jest.Mock).mock.calls[1][0].events).toEqual(['event3', 'event4']);\n      expect(mockOnComplete).toHaveBeenCalledTimes(1);\n      // The noop onComplete passed to each half must be callable\n      expect(capturedOnCompletes).toHaveLength(2);\n      void Promise.all(capturedOnCompletes.map((fn) => fn()));\n    });\n\n    test('logs warn with event count and size when bisecting WAF batch', () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      jest.spyOn(trackDestination, 'sendEventsList').mockReturnValue(undefined);\n      const context = baseContext({ events: ['event1', 'event2'] });\n\n      trackDestination.handlePayloadTooLargeResponse(context, true);\n\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLoggerProvider.warn).toHaveBeenCalledWith(expect.stringContaining('splitting'));\n    });\n  });\n\n  describe('server back-pressure (X-Session-Replay-Event-Skipped header)', () => {\n    const baseDirectiveContext = (\n      overrides: Partial<SessionReplayDestinationContext> = {},\n    ): SessionReplayDestinationContext => ({\n      events: [mockEventString],\n      sessionId: 123,\n      apiKey,\n      attempts: 0,\n      timeout: 0,\n      flushMaxRetries: 1,\n      deviceId: '1a2b3c',\n      sampleRate: 1,\n      serverZone: ServerZone.US,\n      type: 'replay',\n      onComplete: mockOnComplete,\n      ...overrides,\n    });\n\n    const mockFetchWithHeader = (status: number, headerValue: string | null) => {\n      (global.fetch as jest.Mock).mockResolvedValueOnce({\n        status,\n        headers: { get: jest.fn().mockReturnValue(headerValue) },\n      });\n    };\n\n    test('throttled (429) header pauses next flush by 60s', async () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      mockFetchWithHeader(200, '429');\n\n      jest.setSystemTime(1_000_000);\n      await trackDestination.send(baseDirectiveContext(), true);\n\n      // Internal state set: flushPauseUntilMs ~ now + 60_000\n      expect((trackDestination as any).flushPauseUntilMs).toBe(1_000_000 + 60_000);\n    });\n\n    test('clean 200 (no skip header) clears any prior throttle pause', async () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      (trackDestination as any).flushPauseUntilMs = Date.now() + 60_000;\n      mockFetchWithHeader(200, null);\n\n      await trackDestination.send(baseDirectiveContext(), true);\n\n      expect((trackDestination as any).flushPauseUntilMs).toBe(0);\n    });\n\n    test('schedule defers next flush by remaining pause when throttled', () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      jest.setSystemTime(2_000_000);\n      (trackDestination as any).flushPauseUntilMs = 2_000_000 + 30_000; // 30s remaining\n      const setTimeoutSpy = jest.spyOn(global, 'setTimeout');\n\n      trackDestination.schedule(0);\n\n      // The schedule should use the remaining-pause as effective timeout, not the requested 0.\n      const recordedTimeout = setTimeoutSpy.mock.calls[0][1] as number;\n      expect(recordedTimeout).toBe(30_000);\n    });\n\n    test('schedule keeps requested timeout when no pause is active', () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      const setTimeoutSpy = jest.spyOn(global, 'setTimeout');\n\n      trackDestination.schedule(500);\n\n      const recordedTimeout = setTimeoutSpy.mock.calls[0][1] as number;\n      expect(recordedTimeout).toBe(500);\n    });\n\n    test.each([\n      ['4004', 'session_in_invalid_range'],\n      ['4005', 'capture_disabled'],\n    ])('header %s (%s) hard-kills the session — drops queued contexts and future adds', async (code) => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      mockFetchWithHeader(200, code);\n\n      const context = baseDirectiveContext({ sessionId: 555 });\n      await trackDestination.send(context, true);\n\n      expect((trackDestination as any).killedSessions.has(555)).toBe(true);\n\n      // Queued contexts for the killed session are drained on add (never flushed).\n      const followUpOnComplete = jest.fn().mockResolvedValue(undefined);\n      const followUp = baseDirectiveContext({ sessionId: 555, onComplete: followUpOnComplete });\n      trackDestination.addToQueue(followUp);\n\n      expect(trackDestination.queue).toEqual([]);\n      expect(followUpOnComplete).toHaveBeenCalled();\n    });\n\n    test('hard-kill drains contexts already enqueued for that session, leaves others alone', async () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n\n      const killedSessionOnComplete = jest.fn().mockResolvedValue(undefined);\n      const otherSessionOnComplete = jest.fn().mockResolvedValue(undefined);\n      const queuedKilled = baseDirectiveContext({ sessionId: 999, onComplete: killedSessionOnComplete });\n      const queuedOther = baseDirectiveContext({ sessionId: 1000, onComplete: otherSessionOnComplete });\n      trackDestination.queue = [queuedKilled, queuedOther];\n\n      mockFetchWithHeader(200, '4005');\n      await trackDestination.send(baseDirectiveContext({ sessionId: 999 }), true);\n\n      expect(killedSessionOnComplete).toHaveBeenCalled();\n      expect(otherSessionOnComplete).not.toHaveBeenCalled();\n      expect(trackDestination.queue).toEqual([queuedOther]);\n    });\n\n    test('killing a session is idempotent (re-killing the same session is a no-op)', () => {\n      // killSession() can be reached twice for the same session if a worker request\n      // that started before the kill completes after — its skipCode loops through\n      // applyServerDirective again. The early-return guards against re-draining and\n      // re-logging in that case.\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      (trackDestination as any).killSession(42, '4005');\n      (trackDestination as any).killSession(42, '4005');\n\n      const killLogCalls = (mockLoggerProvider.log as jest.Mock).mock.calls.filter(\n        (c) => typeof c[0] === 'string' && c[0].includes('capture stopped for session 42'),\n      );\n      expect(killLogCalls).toHaveLength(1);\n    });\n\n    test('a different session is unaffected by another session being killed', async () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      (trackDestination as any).killedSessions.add(111);\n\n      const onComplete = jest.fn().mockResolvedValue(undefined);\n      trackDestination.addToQueue(baseDirectiveContext({ sessionId: 222, onComplete }));\n\n      // Different session goes through the normal queue path (attempts incremented, queued).\n      expect(trackDestination.queue).toHaveLength(1);\n      expect(trackDestination.queue[0].sessionId).toBe(222);\n      expect(onComplete).not.toHaveBeenCalled();\n    });\n\n    test('unknown skip codes are treated as a normal 200 (no slowdown, no kill)', async () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      mockFetchWithHeader(200, '9999');\n\n      await trackDestination.send(baseDirectiveContext(), true);\n\n      expect((trackDestination as any).flushPauseUntilMs).toBe(0);\n      expect((trackDestination as any).killedSessions.size).toBe(0);\n    });\n\n    test('worker complete message with skipCode applies directive on main thread', () => {\n      const mockWorker = {\n        postMessage: jest.fn(),\n        terminate: jest.fn(),\n        onerror: null as ((e: ErrorEvent) => void) | null,\n        onmessage: null as ((e: MessageEvent) => void) | null,\n      };\n      global.Worker = jest.fn(() => mockWorker) as unknown as typeof Worker;\n      global.URL.createObjectURL = jest.fn().mockReturnValue('blob:mock');\n\n      const trackDestination = new SessionReplayTrackDestination({\n        loggerProvider: mockLoggerProvider,\n        workerScript: 'self.onmessage = () => {}',\n      });\n\n      // Inject a pending request so the complete handler has something to resolve.\n      const pendingContext = baseDirectiveContext({ sessionId: 777 });\n      const resolve = jest.fn();\n      (trackDestination as any).pendingWorkerRequests.set('1', { context: pendingContext, resolve });\n\n      mockWorker.onmessage?.({ data: { type: 'complete', id: '1', skipCode: '4004' } } as MessageEvent);\n\n      expect((trackDestination as any).killedSessions.has(777)).toBe(true);\n      expect(resolve).toHaveBeenCalled();\n    });\n\n    test('worker complete message with no skipCode (error path) does not apply any directive', () => {\n      const mockWorker = {\n        postMessage: jest.fn(),\n        terminate: jest.fn(),\n        onerror: null as ((e: ErrorEvent) => void) | null,\n        onmessage: null as ((e: MessageEvent) => void) | null,\n      };\n      global.Worker = jest.fn(() => mockWorker) as unknown as typeof Worker;\n      global.URL.createObjectURL = jest.fn().mockReturnValue('blob:mock');\n\n      const trackDestination = new SessionReplayTrackDestination({\n        loggerProvider: mockLoggerProvider,\n        workerScript: 'self.onmessage = () => {}',\n      });\n      (trackDestination as any).flushPauseUntilMs = Date.now() + 60_000;\n      const pauseBefore = (trackDestination as any).flushPauseUntilMs;\n\n      const pendingContext = baseDirectiveContext();\n      (trackDestination as any).pendingWorkerRequests.set('1', { context: pendingContext, resolve: jest.fn() });\n\n      // skipCode is omitted entirely (the worker only sends it on a 2xx).\n      mockWorker.onmessage?.({ data: { type: 'complete', id: '1' } } as MessageEvent);\n\n      // No reset, no kill — pause stays as it was.\n      expect((trackDestination as any).flushPauseUntilMs).toBe(pauseBefore);\n      expect((trackDestination as any).killedSessions.size).toBe(0);\n    });\n\n    test('once a session is killed, in-flight contexts already snapshotted by flush() are dropped before fetch', async () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n\n      // First batch returns 4005 — kill arrives mid-flush.\n      mockFetchWithHeader(200, '4005');\n\n      // Pre-load three queued batches for the same session. flush() will snapshot all three\n      // and iterate them; the first send() triggers the kill, and the next two should be\n      // dropped without firing fetch.\n      trackDestination.queue = [\n        baseDirectiveContext({ sessionId: 555 }),\n        baseDirectiveContext({ sessionId: 555 }),\n        baseDirectiveContext({ sessionId: 555 }),\n      ];\n\n      await trackDestination.flush(true);\n\n      expect(global.fetch).toHaveBeenCalledTimes(1);\n      expect((trackDestination as any).killedSessions.has(555)).toBe(true);\n    });\n\n    test('throttle pause clears on the next clean 200 and a fresh schedule uses no pause', async () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n\n      // First send: 200 + throttled.\n      mockFetchWithHeader(200, '429');\n      jest.setSystemTime(5_000_000);\n      await trackDestination.send(baseDirectiveContext(), true);\n      expect((trackDestination as any).flushPauseUntilMs).toBe(5_000_000 + 60_000);\n\n      // While paused, scheduling honors the remaining pause.\n      const setTimeoutSpy = jest.spyOn(global, 'setTimeout');\n      trackDestination.schedule(0);\n      expect(setTimeoutSpy.mock.calls[0][1]).toBe(60_000);\n      setTimeoutSpy.mockClear();\n      // Clear the pending schedule before continuing the e2e flow.\n      clearTimeout((trackDestination as any).scheduled);\n      (trackDestination as any).scheduled = null;\n\n      // Advance past the pause; next response is a clean 200.\n      jest.setSystemTime(5_000_000 + 61_000);\n      mockFetchWithHeader(200, null);\n      await trackDestination.send(baseDirectiveContext(), true);\n\n      expect((trackDestination as any).flushPauseUntilMs).toBe(0);\n\n      // A fresh schedule call now uses the requested timeout, with no pause carry-over.\n      trackDestination.schedule(500);\n      expect(setTimeoutSpy.mock.calls[0][1]).toBe(500);\n    });\n\n    test('throttle log fires once per pause-state transition, not per response', async () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      jest.setSystemTime(7_000_000);\n      mockFetchWithHeader(200, '429');\n      mockFetchWithHeader(200, '429');\n      mockFetchWithHeader(200, '429');\n\n      await trackDestination.send(baseDirectiveContext(), true);\n      // Re-throttle within the pause window — should not log again.\n      jest.setSystemTime(7_000_000 + 1_000);\n      await trackDestination.send(baseDirectiveContext(), true);\n      jest.setSystemTime(7_000_000 + 2_000);\n      await trackDestination.send(baseDirectiveContext(), true);\n\n      const throttleLogs = (mockLoggerProvider.log as jest.Mock).mock.calls.filter(\n        (c) => typeof c[0] === 'string' && c[0].includes('throttled by server'),\n      );\n      expect(throttleLogs).toHaveLength(1);\n    });\n\n    test('killedSessions is bounded — oldest entry is evicted when cap is exceeded', () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      // Drive far past any reasonable cap and assert the eviction invariant\n      // (size doesn't grow unbounded; oldest dropped, newest retained).\n      const drives = 1000;\n      for (let i = 0; i < drives; i++) {\n        (trackDestination as any).killSession(i, '4005');\n      }\n      const finalSize = (trackDestination as any).killedSessions.size as number;\n      expect(finalSize).toBeLessThan(drives);\n      // The very first session (id 0) was the oldest and got evicted long before we finished.\n      expect((trackDestination as any).killedSessions.has(0)).toBe(false);\n      // And the most recent kill is retained.\n      expect((trackDestination as any).killedSessions.has(drives - 1)).toBe(true);\n    });\n\n    test('non-2xx response on main thread does not invoke any directive', async () => {\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      (trackDestination as any).flushPauseUntilMs = 1_500_000;\n      // Server returns 500 — applyServerDirective must not be called for non-2xx.\n      (global.fetch as jest.Mock).mockResolvedValueOnce({\n        status: 500,\n        headers: { get: jest.fn().mockReturnValue(null) },\n      });\n      const applySpy = jest.spyOn(trackDestination as any, 'applyServerDirective');\n\n      // useRetry=false so the call returns without recursion\n      await trackDestination.send(baseDirectiveContext(), false);\n\n      expect(applySpy).not.toHaveBeenCalled();\n      // Pause stays as it was.\n      expect((trackDestination as any).flushPauseUntilMs).toBe(1_500_000);\n    });\n  });\n\n  describe('worker support', () => {\n    const mockContext = {\n      events: [mockEventString],\n      sessionId: 123,\n      apiKey,\n      attempts: 0,\n      timeout: 0,\n      deviceId: '1a2b3c',\n      sampleRate: 1,\n      serverZone: ServerZone.US,\n      type: 'replay' as const,\n      flushMaxRetries: 2,\n      onComplete: jest.fn(),\n    };\n\n    let mockWorker: {\n      postMessage: jest.Mock;\n      terminate: jest.Mock;\n      onerror: ((e: ErrorEvent) => void) | null;\n      onmessage: ((e: MessageEvent) => void) | null;\n    };\n    let originalBlob: typeof Blob;\n\n    beforeEach(() => {\n      mockWorker = {\n        postMessage: jest.fn(),\n        terminate: jest.fn(),\n        onerror: null,\n        onmessage: null,\n      };\n      global.Worker = jest.fn(() => mockWorker) as unknown as typeof Worker;\n      global.URL.createObjectURL = jest.fn().mockReturnValue('blob:mock');\n      originalBlob = global.Blob;\n      global.Blob = jest.fn((parts) => ({ size: (parts as string[]).join('').length })) as unknown as typeof Blob;\n    });\n\n    afterEach(() => {\n      global.Blob = originalBlob;\n    });\n\n    test('constructor initializes worker from workerScript', () => {\n      const trackDestination = new SessionReplayTrackDestination({\n        loggerProvider: mockLoggerProvider,\n        workerScript: 'self.onmessage = () => {}',\n      });\n      expect(global.Worker).toHaveBeenCalledTimes(1);\n      expect((trackDestination as any).worker).toBeDefined();\n    });\n\n    test('constructor falls back gracefully when Worker constructor throws', () => {\n      global.Worker = jest.fn(() => {\n        throw new Error('Worker not supported');\n      }) as unknown as typeof Worker;\n      const trackDestination = new SessionReplayTrackDestination({\n        loggerProvider: mockLoggerProvider,\n        workerScript: 'self.onmessage = () => {}',\n      });\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLoggerProvider.error).toHaveBeenCalledWith(\n        expect.stringContaining('Failed to create track destination worker'),\n        expect.any(Error),\n      );\n      expect((trackDestination as any).worker).toBeUndefined();\n    });\n\n    test('worker onerror clears worker and resolves pending requests', () => {\n      const trackDestination = new SessionReplayTrackDestination({\n        loggerProvider: mockLoggerProvider,\n        workerScript: 'self.onmessage = () => {}',\n      });\n\n      // Inject a fake pending request\n      const resolve = jest.fn();\n      (trackDestination as any).pendingWorkerRequests.set('1', { context: mockContext, resolve });\n\n      // Trigger onerror\n      const errorEvent = {\n        preventDefault: jest.fn(),\n        message: 'test error',\n        filename: 'blob:test',\n        lineno: 1,\n      } as unknown as ErrorEvent;\n      mockWorker.onerror?.(errorEvent);\n\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(errorEvent.preventDefault).toHaveBeenCalled();\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLoggerProvider.error).toHaveBeenCalledWith(expect.stringContaining('Track destination worker failed'));\n      // onComplete must NOT be called — events were never delivered and must remain in\n      // the store for recovery by sendStoredEvents on next init\n      expect(mockContext.onComplete).not.toHaveBeenCalled();\n      // warn should be emitted per pending request\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLoggerProvider.warn).toHaveBeenCalledWith(\n        expect.stringContaining('Session replay event send failed due to worker crash'),\n      );\n      expect(resolve).toHaveBeenCalled();\n      expect((trackDestination as any).worker).toBeUndefined();\n      expect((trackDestination as any).pendingWorkerRequests.size).toBe(0);\n    });\n\n    test('worker onmessage logs for log type', () => {\n      new SessionReplayTrackDestination({\n        loggerProvider: mockLoggerProvider,\n        workerScript: 'self.onmessage = () => {}',\n      });\n      mockWorker.onmessage?.({ data: { type: 'log', id: '1', message: 'test log' } } as MessageEvent);\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLoggerProvider.log).toHaveBeenCalledWith('test log');\n    });\n\n    test('worker onmessage warns for warn type', () => {\n      new SessionReplayTrackDestination({\n        loggerProvider: mockLoggerProvider,\n        workerScript: 'self.onmessage = () => {}',\n      });\n      mockWorker.onmessage?.({ data: { type: 'warn', id: '1', message: 'test warn' } } as MessageEvent);\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLoggerProvider.warn).toHaveBeenCalledWith('test warn');\n    });\n\n    test('worker onmessage handles payload_too_large by invoking handlePayloadTooLargeResponse', () => {\n      const trackDestination = new SessionReplayTrackDestination({\n        loggerProvider: mockLoggerProvider,\n        workerScript: 'self.onmessage = () => {}',\n      });\n      const handleSpy = jest.spyOn(trackDestination, 'handlePayloadTooLargeResponse').mockReturnValueOnce(undefined);\n      const resolve = jest.fn();\n      (trackDestination as any).pendingWorkerRequests.set('1', { context: mockContext, resolve });\n\n      mockWorker.onmessage?.({ data: { type: 'payload_too_large', id: '1', isWaf: false } } as MessageEvent);\n\n      expect(handleSpy).toHaveBeenCalledWith(mockContext, false);\n      expect(resolve).toHaveBeenCalled();\n      expect((trackDestination as any).pendingWorkerRequests.size).toBe(0);\n    });\n\n    test('worker onmessage completes request for complete type', async () => {\n      const trackDestination = new SessionReplayTrackDestination({\n        loggerProvider: mockLoggerProvider,\n        workerScript: 'self.onmessage = () => {}',\n      });\n\n      const resolve = jest.fn();\n      (trackDestination as any).pendingWorkerRequests.set('1', { context: mockContext, resolve });\n\n      mockWorker.onmessage?.({ data: { type: 'complete', id: '1' } } as MessageEvent);\n\n      expect(resolve).toHaveBeenCalled();\n      expect((trackDestination as any).pendingWorkerRequests.size).toBe(0);\n    });\n\n    test('send routes to worker when worker is present', async () => {\n      const trackDestination = new SessionReplayTrackDestination({\n        loggerProvider: mockLoggerProvider,\n        workerScript: 'self.onmessage = () => {}',\n      });\n\n      const sendPromise = trackDestination.send(mockContext, false);\n\n      // Simulate worker completing immediately\n      const pendingEntries = [...(trackDestination as any).pendingWorkerRequests.entries()];\n      expect(pendingEntries).toHaveLength(1);\n      const [id] = pendingEntries[0] as [string, { resolve: () => void }];\n      mockWorker.onmessage?.({ data: { type: 'complete', id } } as MessageEvent);\n\n      await sendPromise;\n      expect(mockWorker.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'send' }));\n    });\n\n    test('send via worker uses 0 when flushMaxRetries is undefined', async () => {\n      const trackDestination = new SessionReplayTrackDestination({\n        loggerProvider: mockLoggerProvider,\n        workerScript: 'self.onmessage = () => {}',\n      });\n\n      const contextWithoutRetries = { ...mockContext, flushMaxRetries: undefined as unknown as number };\n      const sendPromise = trackDestination.send(contextWithoutRetries, false);\n\n      const pendingEntries = [...(trackDestination as any).pendingWorkerRequests.entries()];\n      const [id] = pendingEntries[0] as [string, { resolve: () => void }];\n      mockWorker.onmessage?.({ data: { type: 'complete', id } } as MessageEvent);\n\n      await sendPromise;\n      const postedMessage = mockWorker.postMessage.mock.calls[0][0] as Record<string, unknown>;\n      expect((postedMessage.context as Record<string, unknown>).flushMaxRetries).toBe(0);\n    });\n  });\n\n  describe('sendBeacon', () => {\n    const beaconArgs = {\n      sessionId: 123,\n      deviceId: 'device-abc',\n      apiKey: 'key-abc',\n      serverZone: 'US' as keyof typeof ServerZone,\n    };\n\n    test('calls sendBeacon with serialized payload', () => {\n      const mockSendBeacon = jest.fn().mockReturnValue(true);\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        navigator: { sendBeacon: mockSendBeacon },\n      } as unknown as typeof globalThis);\n\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      const events = ['e1', 'e2'];\n      trackDestination.sendBeacon({ ...beaconArgs, events });\n\n      expect(mockSendBeacon).toHaveBeenCalledWith(\n        expect.stringContaining('device_id=device-abc'),\n        expect.objectContaining({ type: 'application/json' }),\n      );\n    });\n\n    test('warns when sendBeacon returns false', () => {\n      const mockSendBeacon = jest.fn().mockReturnValue(false);\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        navigator: { sendBeacon: mockSendBeacon },\n      } as unknown as typeof globalThis);\n\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      trackDestination.sendBeacon({ ...beaconArgs, events: ['e1'] });\n\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLoggerProvider.warn).toHaveBeenCalledWith('sendBeacon failed to queue session replay payload');\n    });\n\n    test('trims events and warns when payload exceeds 64 KB', () => {\n      const mockSendBeacon = jest.fn().mockReturnValue(true);\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        navigator: { sendBeacon: mockSendBeacon },\n      } as unknown as typeof globalThis);\n\n      // Create events large enough that many together exceed 64 KB\n      const bigEvent = 'x'.repeat(2000);\n      const events = Array.from({ length: 50 }, () => bigEvent); // ~100 KB total\n\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      trackDestination.sendBeacon({ ...beaconArgs, events });\n\n      // eslint-disable-next-line @typescript-eslint/unbound-method\n      expect(mockLoggerProvider.warn).toHaveBeenCalledWith(\n        expect.stringMatching(/sendBeacon payload exceeded 64 KB limit, trimmed from 50 to \\d+ events/),\n      );\n      // Sent payload must be within beacon limit and have correct content type\n      const sentPayload = mockSendBeacon.mock.calls[0][1] as Blob;\n      expect(sentPayload.size).toBeLessThanOrEqual(64 * 1024);\n      expect(sentPayload.type).toBe('application/json');\n    });\n\n    test('does not call sendBeacon when all events are too large to fit', () => {\n      const mockSendBeacon = jest.fn().mockReturnValue(true);\n      jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue({\n        navigator: { sendBeacon: mockSendBeacon },\n      } as unknown as typeof globalThis);\n\n      // A single event larger than 64 KB\n      const hugeEvent = 'x'.repeat(65 * 1024);\n      const trackDestination = new SessionReplayTrackDestination({ loggerProvider: mockLoggerProvider });\n      trackDestination.sendBeacon({ ...beaconArgs, events: [hugeEvent] });\n\n      expect(mockSendBeacon).not.toHaveBeenCalled();\n    });\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/tsconfig.json",
    "content": "{\n  \"extends\": \"../tsconfig.json\",\n  \"include\": [\"**/*\"],\n  \"compilerOptions\": {\n    \"types\": [\"jest\", \"node\"]\n  }\n}\n\n"
  },
  {
    "path": "packages/session-replay-browser/test/url-tracking-plugin.test.ts",
    "content": "import {\n  createUrlTrackingPlugin,\n  subscribeToUrlChanges,\n  URLTrackingPluginOptions,\n} from '../src/plugins/url-tracking-plugin';\nimport * as AnalyticsCore from '@amplitude/analytics-core';\nimport * as Helpers from '../src/helpers';\nimport { IWindow } from '@amplitude/rrweb-types';\n\njest.mock('../src/helpers', () => ({\n  getPageUrl: jest.fn(),\n}));\n\n// Mock interface representing the global scope (window) for testing\ninterface MockGlobalScope {\n  history?: {\n    pushState: jest.Mock;\n    replaceState: jest.Mock;\n  };\n  location?: {\n    href?: string;\n  } | null;\n  document?: {\n    title?: string;\n  } | null;\n  addEventListener: jest.Mock<unknown, [string, () => void]>;\n  removeEventListener: jest.Mock;\n  setInterval: jest.Mock<number, [() => void, number]>;\n  clearInterval: jest.Mock;\n  innerHeight: number;\n  innerWidth: number;\n}\n\n// Helper functions for creating test data\nconst createMockUgcFilterRules = () => [\n  { selector: 'test', replacement: 'filtered' },\n  { selector: '/test/', replacement: 'filtered' },\n];\n\n// Factory function to create a mock global scope with sensible defaults\nconst createMockGlobalScope = (overrides: Partial<MockGlobalScope> = {}): MockGlobalScope => ({\n  history: {\n    pushState: jest.fn(),\n    replaceState: jest.fn(),\n  },\n  location: {\n    href: 'https://example.com/initial',\n  },\n  document: {\n    title: 'Initial Page',\n  },\n  addEventListener: jest.fn() as jest.Mock<unknown, [string, () => void]>,\n  removeEventListener: jest.fn(),\n  setInterval: jest.fn().mockReturnValue(123) as jest.Mock<number, [() => void, number]>,\n  clearInterval: jest.fn(),\n  innerHeight: 768,\n  innerWidth: 1024,\n  ...overrides,\n});\n\ndescribe('URL Tracking Plugin', () => {\n  let mockCallback: jest.MockedFunction<(...args: unknown[]) => void>;\n  let mockGlobalScope: MockGlobalScope;\n\n  // Helper function to call the plugin's observer and return cleanup function\n  const callObserver = (\n    plugin: ReturnType<typeof createUrlTrackingPlugin>,\n    globalScope: MockGlobalScope | undefined,\n  ) => {\n    if (!plugin.observer || !globalScope)\n      return () => {\n        // No cleanup needed\n      };\n    return plugin.observer(mockCallback, globalScope as unknown as IWindow, {});\n  };\n\n  beforeEach(() => {\n    // Use fake timers for testing intervals and timeouts\n    jest.useFakeTimers();\n    mockCallback = jest.fn();\n    mockGlobalScope = createMockGlobalScope();\n    // Mock the global scope to return our test mock\n    jest.spyOn(AnalyticsCore, 'getGlobalScope').mockReturnValue(mockGlobalScope as unknown as typeof globalThis);\n    // Mock getPageUrl to return the URL as-is (no filtering by default)\n    (Helpers.getPageUrl as jest.Mock).mockImplementation((url: string) => url);\n  });\n\n  afterEach(() => {\n    jest.useRealTimers();\n    jest.restoreAllMocks();\n    (Helpers.getPageUrl as jest.Mock).mockClear();\n  });\n\n  describe('subscribeToUrlChanges', () => {\n    test('returns no-op cleanup when globalScope is undefined', () => {\n      const cb = jest.fn();\n      const unsubscribe = subscribeToUrlChanges(undefined, cb);\n      expect(typeof unsubscribe).toBe('function');\n      expect(() => unsubscribe()).not.toThrow();\n      expect(cb).not.toHaveBeenCalled();\n    });\n\n    test('returns no-op cleanup when globalScope has no location and cleanup is callable', () => {\n      const cb = jest.fn();\n      const scopeNoLocation = createMockGlobalScope({ location: undefined as any }) as unknown as Window;\n      const unsubscribe = subscribeToUrlChanges(scopeNoLocation, cb);\n      expect(typeof unsubscribe).toBe('function');\n      expect(() => unsubscribe()).not.toThrow();\n      expect(cb).not.toHaveBeenCalled();\n    });\n\n    test('invokes callback on pushState with new URL and teardown on unsubscribe', () => {\n      const cb = jest.fn();\n      const win = createMockGlobalScope() as unknown as Window;\n      const unsubscribe = subscribeToUrlChanges(win, cb);\n      expect(cb).not.toHaveBeenCalled();\n      if (win.location) {\n        win.location.href = 'https://example.com/page1';\n      }\n      win.history.pushState({}, '', 'https://example.com/page1');\n      expect(cb).toHaveBeenCalledWith('https://example.com/page1');\n      unsubscribe();\n      cb.mockClear();\n      if (win.location) {\n        win.location.href = 'https://example.com/page2';\n      }\n      win.history.pushState({}, '', 'https://example.com/page2');\n      expect(cb).not.toHaveBeenCalled();\n    });\n\n    test('does not re-wrap history across unsubscribe and re-subscribe cycles', () => {\n      const cb1 = jest.fn();\n      const cb2 = jest.fn();\n      const win = createMockGlobalScope() as unknown as Window;\n      const history = win.history;\n\n      const unsubscribe1 = subscribeToUrlChanges(win, cb1);\n      const firstPatchedPushState = Reflect.get(history, 'pushState');\n      const firstPatchedReplaceState = Reflect.get(history, 'replaceState');\n\n      unsubscribe1();\n\n      const unsubscribe2 = subscribeToUrlChanges(win, cb2);\n      expect(Reflect.get(history, 'pushState')).toBe(firstPatchedPushState);\n      expect(Reflect.get(history, 'replaceState')).toBe(firstPatchedReplaceState);\n\n      if (win.location) {\n        win.location.href = 'https://example.com/resubscribed';\n      }\n      history.pushState({}, '', 'https://example.com/resubscribed');\n      expect(cb2).toHaveBeenCalledTimes(1);\n      expect(cb2).toHaveBeenCalledWith('https://example.com/resubscribed');\n\n      unsubscribe2();\n    });\n\n    test('resolves relative pushState URL to absolute href and dedupes subsequent popstate', () => {\n      const cb = jest.fn();\n      const scope = createMockGlobalScope();\n      scope.history = {\n        pushState: jest.fn((_state: unknown, _title: string, url?: string | URL | null) => {\n          if (scope.location && url != null) {\n            scope.location.href = new URL(String(url), scope.location.href).href;\n          }\n        }),\n        replaceState: jest.fn((_state: unknown, _title: string, url?: string | URL | null) => {\n          if (scope.location && url != null) {\n            scope.location.href = new URL(String(url), scope.location.href).href;\n          }\n        }),\n      };\n      const win = scope as unknown as Window;\n\n      subscribeToUrlChanges(win, cb);\n      win.history.pushState({}, '', '/page2');\n\n      expect(cb).toHaveBeenCalledWith('https://example.com/page2');\n      expect(cb).toHaveBeenCalledTimes(1);\n\n      const [, popstateListener] = (win.addEventListener as jest.Mock).mock.calls.find(\n        (c: [string]) => c[0] === 'popstate',\n      ) ?? [undefined, undefined];\n      popstateListener?.();\n\n      // No duplicate notification because lastHref is stored as absolute href.\n      expect(cb).toHaveBeenCalledTimes(1);\n    });\n\n    test('invokes callback on pushState with null url uses getHref', () => {\n      const cb = jest.fn();\n      const win = createMockGlobalScope() as unknown as Window;\n      subscribeToUrlChanges(win, cb);\n      win.history.pushState({}, '', null as unknown as string);\n      expect(cb).toHaveBeenCalledWith('https://example.com/initial');\n    });\n\n    test('invokes callback on replaceState', () => {\n      const cb = jest.fn();\n      const win = createMockGlobalScope() as unknown as Window;\n      subscribeToUrlChanges(win, cb);\n      if (win.location) {\n        win.location.href = 'https://example.com/replaced';\n      }\n      win.history.replaceState({}, '', 'https://example.com/replaced');\n      expect(cb).toHaveBeenCalledWith('https://example.com/replaced');\n    });\n\n    test('replaceState with null url invokes callback with getHref', () => {\n      const cb = jest.fn();\n      const win = createMockGlobalScope() as unknown as Window;\n      subscribeToUrlChanges(win, cb);\n      win.history.replaceState({}, '', null as unknown as string);\n      expect(cb).toHaveBeenCalledWith('https://example.com/initial');\n    });\n\n    test('invokes callback on popstate/hashchange with current location.href', () => {\n      const cb = jest.fn();\n      const win = createMockGlobalScope() as unknown as Window;\n      subscribeToUrlChanges(win, cb);\n      const [, popstateListener] = (win.addEventListener as jest.Mock).mock.calls.find(\n        (c: [string]) => c[0] === 'popstate',\n      ) ?? [undefined, undefined];\n      expect(popstateListener).toBeDefined();\n      popstateListener?.();\n      expect(cb).toHaveBeenCalledWith('https://example.com/initial');\n      expect(cb).toHaveBeenCalledTimes(1);\n      // Same href is deduped, so a second trigger does not call again\n      popstateListener?.();\n      expect(cb).toHaveBeenCalledTimes(1);\n    });\n\n    test('uses polling when enablePolling option is true and cleanup clears interval', () => {\n      const cb = jest.fn();\n      const win = createMockGlobalScope() as unknown as Window;\n      const cleanup = subscribeToUrlChanges(win, cb, {\n        enablePolling: true,\n        pollingInterval: 1000,\n      });\n      const setIntervalMock = Reflect.get(win, 'setInterval') as jest.Mock;\n      expect(setIntervalMock).toHaveBeenCalledWith(expect.any(Function), 1000);\n      const tick = setIntervalMock.mock.calls[0][0] as (this: void) => void;\n      tick.call(undefined);\n      expect(cb).not.toHaveBeenCalled();\n      if (win.location) {\n        win.location.href = 'https://example.com/changed-by-polling';\n      }\n      tick.call(undefined);\n      expect(cb).toHaveBeenCalledWith('https://example.com/changed-by-polling');\n      (cleanup as (this: void) => void).call(undefined);\n      expect(Reflect.get(win, 'clearInterval')).toHaveBeenCalledWith(123);\n    });\n\n    test('polling dedupes repeated ticks when href is unchanged', () => {\n      const cb = jest.fn();\n      const win = createMockGlobalScope() as unknown as Window;\n      subscribeToUrlChanges(win, cb, {\n        enablePolling: true,\n        pollingInterval: 1000,\n      });\n\n      const setIntervalMock = Reflect.get(win, 'setInterval') as jest.Mock;\n      const tick = setIntervalMock.mock.calls[0][0] as (this: void) => void;\n\n      tick.call(undefined);\n      tick.call(undefined);\n      expect(cb).not.toHaveBeenCalled();\n\n      if (win.location) {\n        win.location.href = 'https://example.com/changed';\n      }\n      tick.call(undefined);\n      expect(cb).toHaveBeenCalledTimes(1);\n      expect(cb).toHaveBeenCalledWith('https://example.com/changed');\n\n      tick.call(undefined);\n      expect(cb).toHaveBeenCalledTimes(1);\n    });\n\n    test('polling cleanup does not call clearInterval when interval id is null', () => {\n      const cb = jest.fn();\n      const win = createMockGlobalScope() as unknown as Window;\n      (Reflect.get(win, 'setInterval') as jest.Mock).mockReturnValue(null);\n      const cleanup = subscribeToUrlChanges(win, cb, {\n        enablePolling: true,\n        pollingInterval: 1000,\n      });\n      (cleanup as (this: void) => void).call(undefined);\n      expect(Reflect.get(win, 'clearInterval')).not.toHaveBeenCalled();\n    });\n\n    test('polling getHref returns empty string when href is removed', () => {\n      const cb = jest.fn();\n      const win = createMockGlobalScope() as unknown as Window;\n      const cleanup = subscribeToUrlChanges(win, cb, {\n        enablePolling: true,\n        pollingInterval: 1000,\n      });\n      const setIntervalMock = Reflect.get(win, 'setInterval') as jest.Mock;\n      const tick = setIntervalMock.mock.calls[0][0] as (this: void) => void;\n      if (win.location) {\n        (win.location as unknown as { href?: string }).href = undefined;\n      }\n      tick.call(undefined);\n      expect(cb).toHaveBeenCalledWith('');\n      (cleanup as (this: void) => void).call(undefined);\n    });\n\n    test('adds second subscriber to same scope and notifies both', () => {\n      const cb1 = jest.fn();\n      const cb2 = jest.fn();\n      const win = createMockGlobalScope() as unknown as Window;\n      subscribeToUrlChanges(win, cb1);\n      subscribeToUrlChanges(win, cb2);\n      if (win.location) {\n        win.location.href = 'https://example.com/page1';\n      }\n      const history = Reflect.get(win, 'history') as\n        | { pushState: (state: unknown, title: string, url?: string) => void }\n        | undefined;\n      history?.pushState.call(history, {}, '', 'https://example.com/page1');\n      expect(cb1).toHaveBeenCalledWith('https://example.com/page1');\n      expect(cb2).toHaveBeenCalledWith('https://example.com/page1');\n    });\n\n    test('notifies via popstate when history or pushState/replaceState is missing', () => {\n      const cb = jest.fn();\n      const win = createMockGlobalScope({ history: undefined }) as unknown as Window;\n      subscribeToUrlChanges(win, cb);\n      const [, popstateListener] = (win.addEventListener as jest.Mock).mock.calls.find(\n        (c: [string]) => c[0] === 'popstate',\n      ) ?? [undefined, undefined];\n      expect(popstateListener).toBeDefined();\n      popstateListener?.();\n      expect(cb).toHaveBeenCalledWith('https://example.com/initial');\n    });\n\n    test('getHref uses empty string when location has no href (event-based path)', () => {\n      const cb = jest.fn();\n      const win = createMockGlobalScope({ location: {} as any }) as unknown as Window;\n      subscribeToUrlChanges(win, cb);\n      const [, popstateListener] = (win.addEventListener as jest.Mock).mock.calls.find(\n        (c: [string]) => c[0] === 'popstate',\n      ) ?? [undefined, undefined];\n      popstateListener?.();\n      expect(cb).toHaveBeenCalledWith('');\n    });\n  });\n\n  describe('plugin creation', () => {\n    test('should create plugin with default options', () => {\n      const plugin = createUrlTrackingPlugin();\n      expect(plugin).toBeDefined();\n      expect(plugin.name).toBe('amplitude/url-tracking@1');\n      expect(plugin.observer).toBeDefined();\n      expect(plugin.options).toEqual({});\n    });\n    test('should create plugin with custom options', () => {\n      const options: URLTrackingPluginOptions = {\n        ugcFilterRules: createMockUgcFilterRules(),\n        enablePolling: true,\n        pollingInterval: 2000,\n        captureDocumentTitle: false,\n      };\n      const plugin = createUrlTrackingPlugin(options);\n      expect(plugin.options).toEqual(options);\n    });\n  });\n\n  describe('observer', () => {\n    test('should emit initial URL and return cleanup function', () => {\n      const plugin = createUrlTrackingPlugin();\n      const cleanup = callObserver(plugin, mockGlobalScope);\n      expect(mockCallback).toHaveBeenCalledWith({\n        href: 'https://example.com/initial',\n        title: '', // Default behavior: no document title capture\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        type: 'url-change-event',\n      });\n      expect(typeof cleanup).toBe('function');\n      cleanup();\n    });\n    test('should stop tracking when cleanup is called', () => {\n      const plugin = createUrlTrackingPlugin();\n      const cleanup = callObserver(plugin, mockGlobalScope);\n      mockCallback.mockClear();\n      cleanup();\n      mockGlobalScope.history?.pushState({}, '', '/after-cleanup');\n      expect(mockCallback).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('History API + Hash routing mode (scenario 2)', () => {\n    test('should detect URL changes via pushState', () => {\n      const plugin = createUrlTrackingPlugin();\n      const cleanup = callObserver(plugin, mockGlobalScope);\n      mockCallback.mockClear();\n      // Simulate URL and title change\n      if (mockGlobalScope.location) mockGlobalScope.location.href = 'https://example.com/new-page';\n      if (mockGlobalScope.document) mockGlobalScope.document.title = 'New Page';\n      // Trigger pushState which should be patched by the plugin\n      mockGlobalScope.history?.pushState({}, '', '/new-page');\n      expect(mockCallback).toHaveBeenCalledWith({\n        href: 'https://example.com/new-page',\n        title: '', // Default behavior: no document title capture\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        type: 'url-change-event',\n      });\n      cleanup();\n    });\n    test('should detect URL changes via replaceState', () => {\n      const plugin = createUrlTrackingPlugin();\n      const cleanup = callObserver(plugin, mockGlobalScope);\n      mockCallback.mockClear();\n      // Simulate URL and title change\n      if (mockGlobalScope.location) mockGlobalScope.location.href = 'https://example.com/replaced-page';\n      if (mockGlobalScope.document) mockGlobalScope.document.title = 'Replaced Page';\n      // Trigger replaceState which should be patched by the plugin\n      mockGlobalScope.history?.replaceState({}, '', '/replaced-page');\n      expect(mockCallback).toHaveBeenCalledWith({\n        href: 'https://example.com/replaced-page',\n        title: '', // Default behavior: no document title capture\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        type: 'url-change-event',\n      });\n      cleanup();\n    });\n    test('should detect URL changes via popstate event', () => {\n      const plugin = createUrlTrackingPlugin();\n      const cleanup = callObserver(plugin, mockGlobalScope);\n      mockCallback.mockClear();\n      // Simulate URL and title change\n      if (mockGlobalScope.location) mockGlobalScope.location.href = 'https://example.com/back-page';\n      if (mockGlobalScope.document) mockGlobalScope.document.title = 'Back Page';\n      // Find and trigger the popstate event listener that was registered by the plugin\n      const popstateCall = mockGlobalScope.addEventListener.mock.calls.find(([event]) => event === 'popstate');\n      const popstateListener = popstateCall?.[1];\n      if (popstateListener) popstateListener();\n      expect(mockCallback).toHaveBeenCalledWith({\n        href: 'https://example.com/back-page',\n        title: '', // Default behavior: no document title capture\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        type: 'url-change-event',\n      });\n      cleanup();\n    });\n    test('should not emit duplicate URL changes', () => {\n      const plugin = createUrlTrackingPlugin();\n      const cleanup = callObserver(plugin, mockGlobalScope);\n      mockCallback.mockClear();\n      // Try to navigate to the same URL - should not trigger callback\n      mockGlobalScope.history?.pushState({}, '', '/initial');\n      expect(mockCallback).not.toHaveBeenCalled();\n      cleanup();\n    });\n    test('should include viewport dimensions in URL change events', () => {\n      // Update viewport dimensions\n      mockGlobalScope.innerHeight = 600;\n      mockGlobalScope.innerWidth = 800;\n      const plugin = createUrlTrackingPlugin();\n      const cleanup = callObserver(plugin, mockGlobalScope);\n      mockCallback.mockClear();\n      // Simulate URL change\n      if (mockGlobalScope.location) mockGlobalScope.location.href = 'https://example.com/viewport-test';\n      if (mockGlobalScope.document) mockGlobalScope.document.title = 'Viewport Test';\n      mockGlobalScope.history?.pushState({}, '', '/viewport-test');\n      expect(mockCallback).toHaveBeenCalledWith({\n        href: 'https://example.com/viewport-test',\n        title: '', // Default behavior: no document title capture\n        viewportHeight: 600,\n        viewportWidth: 800,\n        type: 'url-change-event',\n      });\n      cleanup();\n    });\n  });\n\n  describe('hash routing detection (scenario 2)', () => {\n    test('should detect URL changes via hashchange event', () => {\n      const plugin = createUrlTrackingPlugin();\n      const cleanup = callObserver(plugin, mockGlobalScope);\n      mockCallback.mockClear();\n      // Simulate URL and title change\n      if (mockGlobalScope.location) mockGlobalScope.location.href = 'https://example.com/page#new-hash';\n      if (mockGlobalScope.document) mockGlobalScope.document.title = 'Hash Page';\n      // Find and trigger the hashchange event listener that was registered by the plugin\n      const hashchangeCall = mockGlobalScope.addEventListener.mock.calls.find(([event]) => event === 'hashchange');\n      const hashchangeListener = hashchangeCall?.[1];\n      if (hashchangeListener) hashchangeListener();\n      expect(mockCallback).toHaveBeenCalledWith({\n        href: 'https://example.com/page#new-hash',\n        title: '', // Default behavior: no document title capture\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        type: 'url-change-event',\n      });\n      cleanup();\n    });\n\n    test('should detect hash changes with document title capture enabled', () => {\n      const plugin = createUrlTrackingPlugin({ captureDocumentTitle: true });\n      const cleanup = callObserver(plugin, mockGlobalScope);\n      mockCallback.mockClear();\n      // Simulate URL and title change\n      if (mockGlobalScope.location) mockGlobalScope.location.href = 'https://example.com/page#new-hash';\n      if (mockGlobalScope.document) mockGlobalScope.document.title = 'Hash Page';\n      // Find and trigger the hashchange event listener\n      const hashchangeCall = mockGlobalScope.addEventListener.mock.calls.find(([event]) => event === 'hashchange');\n      const hashchangeListener = hashchangeCall?.[1];\n      if (hashchangeListener) hashchangeListener();\n      expect(mockCallback).toHaveBeenCalledWith({\n        href: 'https://example.com/page#new-hash',\n        title: 'Hash Page', // Document title captured when enabled\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        type: 'url-change-event',\n      });\n      cleanup();\n    });\n\n    test('should not emit duplicate hash changes', () => {\n      const plugin = createUrlTrackingPlugin();\n      const cleanup = callObserver(plugin, mockGlobalScope);\n      mockCallback.mockClear();\n      // Find the hashchange event listener\n      const hashchangeCall = mockGlobalScope.addEventListener.mock.calls.find(([event]) => event === 'hashchange');\n      const hashchangeListener = hashchangeCall?.[1];\n      expect(hashchangeListener).toBeDefined();\n      // Trigger hashchange with same URL - should not trigger callback\n      if (hashchangeListener) {\n        hashchangeListener();\n      }\n      expect(mockCallback).not.toHaveBeenCalled();\n      cleanup();\n    });\n\n    test('should handle hash changes in fallback mode (no history API)', () => {\n      const scope = createMockGlobalScope({ history: undefined });\n      const plugin = createUrlTrackingPlugin();\n      const cleanup = callObserver(plugin, scope);\n      mockCallback.mockClear();\n      // Simulate URL change\n      if (scope.location) scope.location.href = 'https://example.com/page#fallback-hash';\n      if (scope.document) scope.document.title = 'Fallback Hash';\n      // Find and trigger the hashchange event listener\n      const hashchangeCall = scope.addEventListener.mock.calls.find(([event]) => event === 'hashchange');\n      const hashchangeListener = hashchangeCall?.[1];\n      if (hashchangeListener) hashchangeListener();\n      expect(mockCallback).toHaveBeenCalledWith({\n        href: 'https://example.com/page#fallback-hash',\n        title: '', // Default behavior: no document title capture\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        type: 'url-change-event',\n      });\n      cleanup();\n    });\n\n    test('should not add hashchange listener in polling mode', () => {\n      const plugin = createUrlTrackingPlugin({ enablePolling: true });\n      const cleanup = callObserver(plugin, mockGlobalScope);\n      // Verify that hashchange event listener was not added in polling mode (polling covers everything)\n      const hashchangeCall = mockGlobalScope.addEventListener.mock.calls.find(([event]) => event === 'hashchange');\n      expect(hashchangeCall).toBeUndefined();\n      cleanup();\n    });\n  });\n\n  describe('hash routing only mode (scenario 3)', () => {\n    test('should handle hash changes when no history API available', () => {\n      const scope = createMockGlobalScope({ history: undefined });\n      const plugin = createUrlTrackingPlugin();\n      const cleanup = callObserver(plugin, scope);\n      mockCallback.mockClear();\n      // Simulate URL change\n      if (scope.location) scope.location.href = 'https://example.com/page#hash-only';\n      if (scope.document) scope.document.title = 'Hash Only';\n      // Find and trigger the hashchange event listener\n      const hashchangeCall = scope.addEventListener.mock.calls.find(([event]) => event === 'hashchange');\n      const hashchangeListener = hashchangeCall?.[1];\n      expect(hashchangeListener).toBeDefined();\n      if (hashchangeListener) {\n        hashchangeListener();\n      }\n      expect(mockCallback).toHaveBeenCalledWith({\n        href: 'https://example.com/page#hash-only',\n        title: '', // Default behavior: no document title capture\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        type: 'url-change-event',\n      });\n      cleanup();\n    });\n\n    test('should emit initial URL in hash routing only mode', () => {\n      const scope = createMockGlobalScope({ history: undefined });\n      const plugin = createUrlTrackingPlugin();\n      const cleanup = callObserver(plugin, scope);\n      // Should emit initial URL even when history API is not available\n      expect(mockCallback).toHaveBeenCalledWith({\n        href: 'https://example.com/initial',\n        title: '', // Default behavior: no document title capture\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        type: 'url-change-event',\n      });\n      cleanup();\n    });\n\n    test('should clean up hashchange listener in hash routing only mode', () => {\n      const scope = createMockGlobalScope({ history: undefined });\n      const plugin = createUrlTrackingPlugin();\n      const cleanup = callObserver(plugin, scope);\n      cleanup();\n      // Should remove hashchange event listener on cleanup\n      expect(scope.removeEventListener).toHaveBeenCalledWith('hashchange', expect.any(Function));\n    });\n  });\n\n  describe('document title capture', () => {\n    test('should not capture document title by default', () => {\n      const plugin = createUrlTrackingPlugin();\n      const cleanup = callObserver(plugin, mockGlobalScope);\n      expect(mockCallback).toHaveBeenCalledWith({\n        href: 'https://example.com/initial',\n        title: '',\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        type: 'url-change-event',\n      });\n      cleanup();\n    });\n\n    test('should capture document title when explicitly enabled', () => {\n      const plugin = createUrlTrackingPlugin({ captureDocumentTitle: true });\n      const cleanup = callObserver(plugin, mockGlobalScope);\n      expect(mockCallback).toHaveBeenCalledWith({\n        href: 'https://example.com/initial',\n        title: 'Initial Page',\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        type: 'url-change-event',\n      });\n      cleanup();\n    });\n\n    test('should not capture document title on URL changes by default', () => {\n      const plugin = createUrlTrackingPlugin();\n      const cleanup = callObserver(plugin, mockGlobalScope);\n      mockCallback.mockClear();\n      // Simulate URL and title change\n      if (mockGlobalScope.location) mockGlobalScope.location.href = 'https://example.com/new-page';\n      if (mockGlobalScope.document) mockGlobalScope.document.title = 'New Page';\n      // Trigger pushState which should be patched by the plugin\n      mockGlobalScope.history?.pushState({}, '', '/new-page');\n      expect(mockCallback).toHaveBeenCalledWith({\n        href: 'https://example.com/new-page',\n        title: '',\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        type: 'url-change-event',\n      });\n      cleanup();\n    });\n\n    test('should capture document title on URL changes when explicitly enabled', () => {\n      const plugin = createUrlTrackingPlugin({ captureDocumentTitle: true });\n      const cleanup = callObserver(plugin, mockGlobalScope);\n      mockCallback.mockClear();\n      // Simulate URL and title change\n      if (mockGlobalScope.location) mockGlobalScope.location.href = 'https://example.com/new-page';\n      if (mockGlobalScope.document) mockGlobalScope.document.title = 'New Page';\n      // Trigger pushState which should be patched by the plugin\n      mockGlobalScope.history?.pushState({}, '', '/new-page');\n      expect(mockCallback).toHaveBeenCalledWith({\n        href: 'https://example.com/new-page',\n        title: 'New Page', // Document title captured when enabled\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        type: 'url-change-event',\n      });\n      cleanup();\n    });\n  });\n\n  describe('UGC filtering', () => {\n    test('should apply UGC filtering when rules are provided', () => {\n      // Mock getPageUrl to return a filtered URL\n      (Helpers.getPageUrl as jest.Mock).mockReturnValue('https://example.com/filtered');\n      const plugin = createUrlTrackingPlugin({ ugcFilterRules: createMockUgcFilterRules() });\n      const cleanup = callObserver(plugin, mockGlobalScope);\n      mockCallback.mockClear();\n      // Simulate navigation to a sensitive URL\n      if (mockGlobalScope.location) mockGlobalScope.location.href = 'https://example.com/sensitive';\n      if (mockGlobalScope.document) mockGlobalScope.document.title = 'Sensitive';\n      mockGlobalScope.history?.pushState({}, '', '/sensitive');\n      // Verify that getPageUrl was called with the filtering rules\n      expect(Helpers.getPageUrl).toHaveBeenCalledWith('https://example.com/sensitive', createMockUgcFilterRules());\n      // Verify that the filtered URL was emitted\n      expect(mockCallback).toHaveBeenCalledWith({\n        href: 'https://example.com/filtered',\n        title: '', // Default behavior: no document title capture\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        type: 'url-change-event',\n      });\n      cleanup();\n    });\n    test('should not apply filtering when no rules are provided', () => {\n      const plugin = createUrlTrackingPlugin();\n      const cleanup = callObserver(plugin, mockGlobalScope);\n      mockCallback.mockClear();\n      // Simulate navigation to a URL\n      if (mockGlobalScope.location) mockGlobalScope.location.href = 'https://example.com/no-filtering';\n      if (mockGlobalScope.document) mockGlobalScope.document.title = 'No Filtering';\n      mockGlobalScope.history?.pushState({}, '', '/no-filtering');\n      // Verify that getPageUrl was not called (no filtering rules)\n      expect(Helpers.getPageUrl).not.toHaveBeenCalled();\n      // Verify that the original URL was emitted\n      expect(mockCallback).toHaveBeenCalledWith({\n        href: 'https://example.com/no-filtering',\n        title: '', // Default behavior: no document title capture\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        type: 'url-change-event',\n      });\n      cleanup();\n    });\n  });\n\n  describe('polling mode (scenario 1)', () => {\n    test('should enable polling when explicitly configured', () => {\n      const plugin = createUrlTrackingPlugin({ enablePolling: true });\n      const cleanup = callObserver(plugin, mockGlobalScope);\n      // Verify that setInterval was called with the default polling interval\n      expect(mockGlobalScope.setInterval).toHaveBeenCalledWith(expect.any(Function), 1000);\n      cleanup();\n    });\n    test('should use custom polling interval when specified', () => {\n      const plugin = createUrlTrackingPlugin({ enablePolling: true, pollingInterval: 2000 });\n      const cleanup = callObserver(plugin, mockGlobalScope);\n      // Verify that setInterval was called with the custom polling interval\n      expect(mockGlobalScope.setInterval).toHaveBeenCalledWith(expect.any(Function), 2000);\n      cleanup();\n    });\n    test('should detect URL changes via polling', () => {\n      const plugin = createUrlTrackingPlugin({ enablePolling: true });\n      const cleanup = callObserver(plugin, mockGlobalScope);\n      mockCallback.mockClear();\n      // Simulate URL change\n      if (mockGlobalScope.location) mockGlobalScope.location.href = 'https://example.com/polled';\n      if (mockGlobalScope.document) mockGlobalScope.document.title = 'Polled';\n      // Get the polling function and execute it manually\n      const pollingFunction = mockGlobalScope.setInterval.mock.calls[0]?.[0];\n      pollingFunction();\n      // Verify that the URL change was detected via polling\n      expect(mockCallback).toHaveBeenCalledWith({\n        href: 'https://example.com/polled',\n        title: '', // Default behavior: no document title capture\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        type: 'url-change-event',\n      });\n      cleanup();\n    });\n    test('should clear polling interval on cleanup', () => {\n      const plugin = createUrlTrackingPlugin({ enablePolling: true });\n      const cleanup = callObserver(plugin, mockGlobalScope);\n      cleanup();\n      // Verify that the polling interval was cleared\n      expect(mockGlobalScope.clearInterval).toHaveBeenCalledWith(123);\n    });\n\n    test('should handle null polling interval on cleanup', () => {\n      // Mock setInterval to return null\n      mockGlobalScope.setInterval.mockReturnValue(null as unknown as number);\n      const plugin = createUrlTrackingPlugin({ enablePolling: true });\n      const cleanup = callObserver(plugin, mockGlobalScope);\n      cleanup();\n      // Should not call clearInterval when interval is null\n      expect(mockGlobalScope.clearInterval).not.toHaveBeenCalled();\n    });\n\n    test('should detect URL changes via polling with document title capture enabled', () => {\n      const plugin = createUrlTrackingPlugin({ enablePolling: true, captureDocumentTitle: true });\n      const cleanup = callObserver(plugin, mockGlobalScope);\n      mockCallback.mockClear();\n      // Simulate URL change\n      if (mockGlobalScope.location) mockGlobalScope.location.href = 'https://example.com/polled';\n      if (mockGlobalScope.document) mockGlobalScope.document.title = 'Polled';\n      // Get the polling function and execute it manually\n      const pollingFunction = mockGlobalScope.setInterval.mock.calls[0]?.[0];\n      pollingFunction();\n      // Verify that the URL change was detected via polling with title captured\n      expect(mockCallback).toHaveBeenCalledWith({\n        href: 'https://example.com/polled',\n        title: 'Polled', // Document title captured when enabled\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        type: 'url-change-event',\n      });\n      cleanup();\n    });\n  });\n\n  describe('error handling', () => {\n    test('should handle missing global scope gracefully', () => {\n      const plugin = createUrlTrackingPlugin();\n      const cleanup = callObserver(plugin, undefined);\n      // Should not emit any events when global scope is missing\n      expect(mockCallback).not.toHaveBeenCalled();\n      expect(typeof cleanup).toBe('function');\n      cleanup();\n    });\n    test('should handle direct observer call with undefined globalScope', () => {\n      const plugin = createUrlTrackingPlugin();\n      const cleanup = plugin.observer?.(jest.fn(), undefined as unknown as IWindow, {});\n      // Should return a cleanup function even with undefined global scope\n      expect(typeof cleanup).toBe('function');\n      if (cleanup) cleanup();\n    });\n\n    // PARAMETERIZED: Location edge cases (missing/null/undefined/empty)\n    test.each([\n      [{ location: undefined }, 'missing location'],\n      [{ location: null }, 'null location'],\n      [{ location: { href: undefined } }, 'undefined href'],\n      [{ location: { href: null as unknown as string } }, 'null href'],\n      [{ location: { href: '' } }, 'empty string href'],\n    ])('should emit event with empty href for %s', (locationOverride, _label) => {\n      const scope = createMockGlobalScope(locationOverride);\n      const plugin = createUrlTrackingPlugin();\n      const cleanup = callObserver(plugin, scope);\n      expect(mockCallback).toHaveBeenCalledWith({\n        href: '',\n        title: '',\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        type: 'url-change-event',\n      });\n      cleanup();\n    });\n\n    test('should handle missing or null document', () => {\n      const testCases = [\n        { document: undefined, description: 'undefined document' },\n        { document: null, description: 'null document' },\n      ];\n\n      testCases.forEach(({ document }) => {\n        const scope = createMockGlobalScope({ document });\n        const plugin = createUrlTrackingPlugin();\n        const cleanup = callObserver(plugin, scope);\n        // Should emit event with empty title when document is missing or null\n        expect(mockCallback).toHaveBeenCalledWith({\n          href: 'https://example.com/initial',\n          title: '',\n          viewportHeight: 768,\n          viewportWidth: 1024,\n          type: 'url-change-event',\n        });\n        cleanup();\n        mockCallback.mockClear();\n      });\n    });\n    test('should handle document with undefined title', () => {\n      const scope = createMockGlobalScope({ document: { title: undefined } });\n      const plugin = createUrlTrackingPlugin();\n      const cleanup = callObserver(plugin, scope);\n      // Should emit event with empty title when document.title is undefined\n      expect(mockCallback).toHaveBeenCalledWith({\n        href: 'https://example.com/initial',\n        title: '',\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        type: 'url-change-event',\n      });\n      cleanup();\n    });\n    test('should handle missing history gracefully (falls back to scenario 3)', () => {\n      const scope = createMockGlobalScope({ history: undefined });\n      const plugin = createUrlTrackingPlugin();\n      const cleanup = callObserver(plugin, scope);\n      // Should still emit initial URL even when history is missing (scenario 3: hash routing only)\n      expect(mockCallback).toHaveBeenCalledWith({\n        href: 'https://example.com/initial',\n        title: '', // Default behavior: no document title capture\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        type: 'url-change-event',\n      });\n      cleanup();\n    });\n  });\n\n  // PARAMETERIZED: Document title edge cases\n  describe('document title edge cases', () => {\n    test.each([\n      [{ document: { title: undefined } }, 'undefined title'],\n      [{ document: { title: null as unknown as string } }, 'null title'],\n      [{ document: { title: '' } }, 'empty string title'],\n      [{ document: undefined }, 'undefined document'],\n    ])('should emit empty title for %s when captureDocumentTitle is true', (docOverride, _label) => {\n      const scope = createMockGlobalScope(docOverride);\n      const plugin = createUrlTrackingPlugin({ captureDocumentTitle: true });\n      const cleanup = callObserver(plugin, scope);\n      expect(mockCallback).toHaveBeenCalledWith({\n        href: 'https://example.com/initial',\n        title: '',\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        type: 'url-change-event',\n      });\n      cleanup();\n    });\n  });\n\n  // PARAMETERIZED: Consistency across modes\n  describe('URL consistency and temporal dead zone fixes', () => {\n    test('should handle temporal dead zone correctly - lastTrackedUrl accessible in emitUrlChange', () => {\n      const plugin = createUrlTrackingPlugin();\n      const cleanup = callObserver(plugin, mockGlobalScope);\n\n      // This test verifies that lastTrackedUrl is properly accessible\n      // The fact that we can call emitUrlChange without ReferenceError proves the fix works\n      mockCallback.mockClear();\n\n      // Simulate multiple URL changes to test lastTrackedUrl tracking\n      if (mockGlobalScope.location) mockGlobalScope.location.href = 'https://example.com/first';\n      mockGlobalScope.history?.pushState({}, '', '/first');\n\n      if (mockGlobalScope.location) mockGlobalScope.location.href = 'https://example.com/second';\n      mockGlobalScope.history?.pushState({}, '', '/second');\n\n      // Should emit both URL changes (no temporal dead zone error)\n      expect(mockCallback).toHaveBeenCalledTimes(2);\n      expect(mockCallback).toHaveBeenNthCalledWith(1, {\n        href: 'https://example.com/first',\n        title: '',\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        type: 'url-change-event',\n      });\n      expect(mockCallback).toHaveBeenNthCalledWith(2, {\n        href: 'https://example.com/second',\n        title: '',\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        type: 'url-change-event',\n      });\n\n      cleanup();\n    });\n\n    // PARAMETERIZED: Consistency across modes (undefined/null/empty)\n    test.each([\n      [undefined, 'undefined'],\n      [null, 'null'],\n      ['', 'empty string'],\n    ])('should handle %s location.href consistently across all modes', (hrefValue, _label) => {\n      const testCases = [{ options: { enablePolling: true } }, { options: {} }, { options: {}, history: undefined }];\n      testCases.forEach(({ options, history }) => {\n        const scope = createMockGlobalScope({\n          location: { href: hrefValue as string },\n          history: history !== undefined ? history : mockGlobalScope.history,\n        });\n        const plugin = createUrlTrackingPlugin(options);\n        const cleanup = callObserver(plugin, scope);\n        // Should emit event with empty href consistently across all modes\n        expect(mockCallback).toHaveBeenCalledWith({\n          href: '',\n          title: '',\n          viewportHeight: 768,\n          viewportWidth: 1024,\n          type: 'url-change-event',\n        });\n        cleanup();\n        mockCallback.mockClear();\n      });\n    });\n\n    test('should handle null location.href consistently across all modes', () => {\n      const testCases = [{ options: { enablePolling: true } }, { options: {} }, { options: {}, history: undefined }];\n\n      testCases.forEach(({ options, history }) => {\n        const scope = createMockGlobalScope({\n          location: { href: null as unknown as string },\n          history: history !== undefined ? history : mockGlobalScope.history,\n        });\n        const plugin = createUrlTrackingPlugin(options);\n        const cleanup = callObserver(plugin, scope);\n\n        // Should emit event with empty href consistently across all modes\n        expect(mockCallback).toHaveBeenCalledWith({\n          href: '',\n          title: '',\n          viewportHeight: 768,\n          viewportWidth: 1024,\n          type: 'url-change-event',\n        });\n\n        cleanup();\n        mockCallback.mockClear();\n      });\n    });\n\n    test('should handle empty string location.href consistently across all modes', () => {\n      const testCases = [{ options: { enablePolling: true } }, { options: {} }, { options: {}, history: undefined }];\n\n      testCases.forEach(({ options, history }) => {\n        const scope = createMockGlobalScope({\n          location: { href: '' },\n          history: history !== undefined ? history : mockGlobalScope.history,\n        });\n        const plugin = createUrlTrackingPlugin(options);\n        const cleanup = callObserver(plugin, scope);\n\n        // Should emit event with empty href consistently across all modes\n        expect(mockCallback).toHaveBeenCalledWith({\n          href: '',\n          title: '',\n          viewportHeight: 768,\n          viewportWidth: 1024,\n          type: 'url-change-event',\n        });\n\n        cleanup();\n        mockCallback.mockClear();\n      });\n    });\n\n    test('should prevent duplicate events when location.href transitions between undefined/empty values', () => {\n      const scope = createMockGlobalScope({ location: { href: undefined } });\n      const plugin = createUrlTrackingPlugin();\n      const cleanup = callObserver(plugin, scope);\n\n      // Initial call should emit empty href\n      expect(mockCallback).toHaveBeenCalledWith({\n        href: '',\n        title: '',\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        type: 'url-change-event',\n      });\n\n      mockCallback.mockClear();\n\n      // Change to empty string - should not emit duplicate\n      if (scope.location) scope.location.href = '';\n      scope.history?.pushState({}, '', '/');\n\n      // Should not emit duplicate event for same normalized URL\n      expect(mockCallback).not.toHaveBeenCalled();\n\n      // Change to actual URL - should emit\n      if (scope.location) scope.location.href = 'https://example.com/actual';\n      scope.history?.pushState({}, '', '/actual');\n\n      expect(mockCallback).toHaveBeenCalledWith({\n        href: 'https://example.com/actual',\n        title: '',\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        type: 'url-change-event',\n      });\n\n      cleanup();\n    });\n\n    test('should handle getCurrentUrl function behavior correctly', () => {\n      const testCases = [\n        { href: undefined, expected: '' },\n        { href: null, expected: '' },\n        { href: '', expected: '' },\n        { href: 'https://example.com/test', expected: 'https://example.com/test' },\n      ];\n\n      testCases.forEach(({ href, expected }) => {\n        const scope = createMockGlobalScope({ location: { href: href as string } });\n        const plugin = createUrlTrackingPlugin();\n        const cleanup = callObserver(plugin, scope);\n\n        // Should emit event with expected href\n        expect(mockCallback).toHaveBeenCalledWith({\n          href: expected,\n          title: '',\n          viewportHeight: 768,\n          viewportWidth: 1024,\n          type: 'url-change-event',\n        });\n\n        cleanup();\n        mockCallback.mockClear();\n      });\n    });\n  });\n\n  describe('shared subscription (subscribeToUrlChanges)', () => {\n    test('multiple plugin instances share a single history patch', () => {\n      const plugin = createUrlTrackingPlugin();\n      const cleanup1 = callObserver(plugin, mockGlobalScope);\n      const patchedPushState = mockGlobalScope.history?.pushState;\n      const patchedReplaceState = mockGlobalScope.history?.replaceState;\n\n      const cleanup2 = callObserver(plugin, mockGlobalScope);\n      expect(mockGlobalScope.history?.pushState).toBe(patchedPushState);\n      expect(mockGlobalScope.history?.replaceState).toBe(patchedReplaceState);\n\n      cleanup1();\n      cleanup2();\n    });\n\n    test('multiple plugin instances each receive URL change and share one patch', () => {\n      const scope = createMockGlobalScope() as unknown as MockGlobalScope;\n      const plugin1 = createUrlTrackingPlugin();\n      const plugin2 = createUrlTrackingPlugin();\n      const plugin3 = createUrlTrackingPlugin();\n      const cleanup1 = callObserver(plugin1, scope);\n      const cleanup2 = callObserver(plugin2, scope);\n      const cleanup3 = callObserver(plugin3, scope);\n\n      expect(scope.history?.pushState).toBeDefined();\n      mockCallback.mockClear();\n      // Trigger via popstate listener (subscription notifies all callbacks with current location.href)\n      if (scope.location) scope.location.href = 'https://example.com/multi-instance';\n      const popstateCalls = (scope.addEventListener as jest.Mock).mock.calls.filter(\n        (c: [string]) => c[0] === 'popstate',\n      );\n      const popstateListener = popstateCalls[0]?.[1];\n      expect(popstateListener).toBeDefined();\n      popstateListener?.();\n\n      expect(mockCallback).toHaveBeenCalledTimes(3);\n      expect(mockCallback).toHaveBeenCalledWith({\n        href: 'https://example.com/multi-instance',\n        title: '',\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        type: 'url-change-event',\n      });\n\n      cleanup1();\n      cleanup2();\n      cleanup3();\n    });\n\n    test('when plugin is the only subscriber, cleanup removes listeners but does not restore history', () => {\n      const plugin = createUrlTrackingPlugin();\n      const cleanup = callObserver(plugin, mockGlobalScope);\n      const patchedPushState = mockGlobalScope.history?.pushState;\n      const patchedReplaceState = mockGlobalScope.history?.replaceState;\n\n      cleanup();\n\n      // We do not restore history (other scripts may have patched); patch remains\n      expect(mockGlobalScope.history?.pushState).toBe(patchedPushState);\n      expect(mockGlobalScope.history?.replaceState).toBe(patchedReplaceState);\n      expect(mockGlobalScope.removeEventListener).toHaveBeenCalledWith('popstate', expect.any(Function));\n      expect(mockGlobalScope.removeEventListener).toHaveBeenCalledWith('hashchange', expect.any(Function));\n    });\n\n    test('when another subscriber exists, plugin cleanup leaves patch and listeners in place', () => {\n      const cb = jest.fn();\n      const unsubscribeTargeting = subscribeToUrlChanges(mockGlobalScope as unknown as Window, cb);\n      const plugin = createUrlTrackingPlugin();\n      const cleanupPlugin = callObserver(plugin, mockGlobalScope);\n      const patchedPushState = mockGlobalScope.history?.pushState;\n\n      cleanupPlugin();\n\n      expect(mockGlobalScope.history?.pushState).toBe(patchedPushState);\n      cb.mockClear();\n      if (mockGlobalScope.location) {\n        mockGlobalScope.location.href = 'https://example.com/after-plugin-cleanup';\n      }\n      if (mockGlobalScope.history?.pushState) {\n        mockGlobalScope.history.pushState({}, '', 'https://example.com/after-plugin-cleanup');\n      }\n      expect(cb).toHaveBeenCalledWith('https://example.com/after-plugin-cleanup');\n      unsubscribeTargeting();\n    });\n\n    test('should work correctly with different plugin options', () => {\n      const plugin1 = createUrlTrackingPlugin({ captureDocumentTitle: true });\n      const plugin2 = createUrlTrackingPlugin({ captureDocumentTitle: false });\n\n      const cleanup1 = callObserver(plugin1, mockGlobalScope);\n\n      // Store first patched methods\n      const firstPatchedPushState = mockGlobalScope.history?.pushState;\n\n      const cleanup2 = callObserver(plugin2, mockGlobalScope);\n\n      // Second plugin should detect existing patch and skip\n      expect(mockGlobalScope.history?.pushState).toBe(firstPatchedPushState);\n\n      // Test that functionality still works\n      mockCallback.mockClear();\n      if (mockGlobalScope.location) mockGlobalScope.location.href = 'https://example.com/options-test';\n      if (mockGlobalScope.document) mockGlobalScope.document.title = 'Options Test';\n      mockGlobalScope.history?.pushState({}, '', '/options-test');\n\n      // Should emit event (from the first plugin's configuration)\n      expect(mockCallback).toHaveBeenCalledWith({\n        href: 'https://example.com/options-test',\n        title: 'Options Test', // First plugin had captureDocumentTitle: true\n        viewportHeight: 768,\n        viewportWidth: 1024,\n        type: 'url-change-event',\n      });\n\n      cleanup1();\n      cleanup2();\n    });\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/utils/get-input-type.test.ts",
    "content": "import { getInputType, toLowerCase } from '../../src/utils/get-input-type';\n\ndescribe('getInputType', () => {\n  beforeEach(() => {\n    // Clear the DOM before each test\n    document.body.innerHTML = '';\n  });\n\n  describe('toLowerCase', () => {\n    test('should convert string to lowercase', () => {\n      expect(toLowerCase('TEXT')).toBe('text');\n      expect(toLowerCase('Password')).toBe('password');\n      expect(toLowerCase('EMAIL')).toBe('email');\n      expect(toLowerCase('MiXeD')).toBe('mixed');\n    });\n\n    test('should handle already lowercase strings', () => {\n      expect(toLowerCase('text')).toBe('text');\n      expect(toLowerCase('password')).toBe('password');\n    });\n\n    test('should handle empty string', () => {\n      expect(toLowerCase('')).toBe('');\n    });\n  });\n\n  describe('getInputType', () => {\n    test('should return null for non-input elements without type attribute', () => {\n      const div = document.createElement('div');\n      expect(getInputType(div)).toBeNull();\n    });\n\n    test('should return \"password\" for elements with data-rr-is-password attribute', () => {\n      const input = document.createElement('input');\n      input.type = 'text';\n      input.setAttribute('data-rr-is-password', '');\n\n      expect(getInputType(input)).toBe('password');\n    });\n\n    test('should return \"password\" for elements with data-rr-is-password attribute regardless of actual type', () => {\n      const input = document.createElement('input');\n      input.type = 'email';\n      input.setAttribute('data-rr-is-password', '');\n\n      expect(getInputType(input)).toBe('password');\n    });\n\n    test('should return lowercase type for input elements without data-rr-is-password', () => {\n      const input = document.createElement('input');\n      input.type = 'TEXT';\n\n      expect(getInputType(input)).toBe('text');\n    });\n\n    test('should return lowercase type for various input types', () => {\n      const testTypes = ['EMAIL', 'Password', 'Number', 'Tel', 'Url', 'Search'];\n\n      testTypes.forEach((type) => {\n        const input = document.createElement('input');\n        input.type = type;\n\n        expect(getInputType(input)).toBe(type.toLowerCase());\n      });\n    });\n\n    test('should return \"text\" for input elements without explicit type (default behavior)', () => {\n      const input = document.createElement('input');\n      // When no type is specified, HTMLInputElement.type defaults to 'text'\n\n      expect(getInputType(input)).toBe('text');\n    });\n\n    test('should handle elements that were originally password inputs but changed to text', () => {\n      const input = document.createElement('input');\n      input.type = 'text';\n      input.setAttribute('data-rr-is-password', 'true');\n\n      // This simulates the case where a password input was changed to text input\n      // but we still want to treat it as password for privacy\n      expect(getInputType(input)).toBe('password');\n    });\n\n    test('should return null for elements without type property', () => {\n      const span = document.createElement('span');\n\n      expect(getInputType(span)).toBeNull();\n    });\n\n    test('should handle mixed case types correctly', () => {\n      const input = document.createElement('input');\n      input.type = 'PaSSworD';\n\n      expect(getInputType(input)).toBe('password');\n    });\n\n    test('should prioritize data-rr-is-password over actual type', () => {\n      const input = document.createElement('input');\n      input.type = 'number';\n      input.setAttribute('data-rr-is-password', '');\n\n      expect(getInputType(input)).toBe('password');\n    });\n\n    test('should handle elements with falsy data-rr-is-password attribute values', () => {\n      const input = document.createElement('input');\n      input.type = 'text';\n      input.setAttribute('data-rr-is-password', 'false');\n\n      // hasAttribute returns true even if the value is 'false', since the attribute exists\n      expect(getInputType(input)).toBe('password');\n    });\n\n    test('should not treat elements without data-rr-is-password as password', () => {\n      const input = document.createElement('input');\n      input.type = 'password';\n      // No data-rr-is-password attribute\n\n      expect(getInputType(input)).toBe('password');\n    });\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/utils/is-abort-error.test.ts",
    "content": "import { logIdbError } from '../../src/utils/is-abort-error';\n\ndescribe('logIdbError', () => {\n  const mockLogger = {\n    debug: jest.fn(),\n    log: jest.fn(),\n    warn: jest.fn(),\n    error: jest.fn(),\n    enable: jest.fn(),\n    disable: jest.fn(),\n  };\n\n  beforeEach(() => jest.clearAllMocks());\n\n  test('should log at debug level for AbortError', () => {\n    const abortError = new DOMException('The transaction was aborted', 'AbortError');\n    logIdbError(mockLogger, 'idb failed', abortError);\n    expect(mockLogger.debug).toHaveBeenCalledWith('idb failed');\n    expect(mockLogger.warn).not.toHaveBeenCalled();\n  });\n\n  test('should log at debug level for plain object with name AbortError', () => {\n    const abortLike = { name: 'AbortError', message: 'aborted' };\n    logIdbError(mockLogger, 'idb failed', abortLike);\n    expect(mockLogger.debug).toHaveBeenCalledWith('idb failed');\n    expect(mockLogger.warn).not.toHaveBeenCalled();\n  });\n\n  test('should log at warn level for non-AbortError', () => {\n    logIdbError(mockLogger, 'idb failed', new Error('something broke'));\n    expect(mockLogger.warn).toHaveBeenCalledWith('idb failed');\n    expect(mockLogger.debug).not.toHaveBeenCalled();\n  });\n\n  test('should log at warn level when error is undefined', () => {\n    logIdbError(mockLogger, 'idb failed');\n    expect(mockLogger.warn).toHaveBeenCalledWith('idb failed');\n    expect(mockLogger.debug).not.toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/utils/rrweb.test.ts",
    "content": "import { getViewportHeight, getViewportWidth } from '../../src/utils/rrweb';\nimport { getGlobalScope } from '@amplitude/analytics-core';\n\n// Mock the getGlobalScope function\njest.mock('@amplitude/analytics-core', () => ({\n  getGlobalScope: jest.fn(),\n}));\n\nconst mockGetGlobalScope = getGlobalScope as jest.MockedFunction<typeof getGlobalScope>;\n\ndescribe('rrweb utils', () => {\n  beforeEach(() => {\n    jest.clearAllMocks();\n    // Reset document properties\n    Object.defineProperty(document, 'documentElement', {\n      writable: true,\n      value: document.documentElement,\n    });\n    Object.defineProperty(document, 'body', {\n      writable: true,\n      value: document.body,\n    });\n  });\n\n  describe('getViewportHeight', () => {\n    test('should return globalScope.innerHeight when available', () => {\n      mockGetGlobalScope.mockReturnValue({ innerHeight: 800 } as typeof globalThis);\n\n      expect(getViewportHeight()).toBe(800);\n    });\n\n    test('should return document.documentElement.clientHeight when globalScope is null', () => {\n      mockGetGlobalScope.mockReturnValue(undefined);\n      Object.defineProperty(document, 'documentElement', {\n        value: { clientHeight: 600 },\n        writable: true,\n      });\n\n      expect(getViewportHeight()).toBe(600);\n    });\n\n    test('should return document.documentElement.clientHeight when globalScope.innerHeight not available', () => {\n      mockGetGlobalScope.mockReturnValue({} as typeof globalThis);\n      Object.defineProperty(document, 'documentElement', {\n        value: { clientHeight: 600 },\n        writable: true,\n      });\n\n      expect(getViewportHeight()).toBe(600);\n    });\n\n    test('should return 0 when documentElement.clientHeight is 0 (not fallback to body.clientHeight)', () => {\n      mockGetGlobalScope.mockReturnValue({} as typeof globalThis);\n      Object.defineProperty(document, 'documentElement', {\n        value: { clientHeight: 0 },\n        writable: true,\n      });\n      Object.defineProperty(document, 'body', {\n        value: { clientHeight: 14000 },\n        writable: true,\n      });\n\n      expect(getViewportHeight()).toBe(0);\n    });\n\n    test('should return 0 when documentElement.clientHeight not available', () => {\n      mockGetGlobalScope.mockReturnValue({} as typeof globalThis);\n      Object.defineProperty(document, 'documentElement', {\n        value: null,\n        writable: true,\n      });\n\n      expect(getViewportHeight()).toBe(0);\n    });\n\n    test('should return 0 when no height sources are available', () => {\n      mockGetGlobalScope.mockReturnValue({} as typeof globalThis);\n      Object.defineProperty(document, 'documentElement', {\n        value: null,\n        writable: true,\n      });\n      Object.defineProperty(document, 'body', {\n        value: null,\n        writable: true,\n      });\n\n      expect(getViewportHeight()).toBe(0);\n    });\n  });\n\n  describe('getViewportWidth', () => {\n    test('should return globalScope.innerWidth when available', () => {\n      mockGetGlobalScope.mockReturnValue({ innerWidth: 1200 } as typeof globalThis);\n\n      expect(getViewportWidth()).toBe(1200);\n    });\n\n    test('should return document.documentElement.clientWidth when globalScope is null', () => {\n      mockGetGlobalScope.mockReturnValue(undefined);\n      Object.defineProperty(document, 'documentElement', {\n        value: { clientWidth: 1000 },\n        writable: true,\n      });\n\n      expect(getViewportWidth()).toBe(1000);\n    });\n\n    test('should return document.documentElement.clientWidth when globalScope.innerWidth not available', () => {\n      mockGetGlobalScope.mockReturnValue({} as typeof globalThis);\n      Object.defineProperty(document, 'documentElement', {\n        value: { clientWidth: 1000 },\n        writable: true,\n      });\n\n      expect(getViewportWidth()).toBe(1000);\n    });\n\n    test('should return 0 when documentElement.clientWidth is 0 (not fallback to body.clientWidth)', () => {\n      mockGetGlobalScope.mockReturnValue({} as typeof globalThis);\n      Object.defineProperty(document, 'documentElement', {\n        value: { clientWidth: 0 },\n        writable: true,\n      });\n      Object.defineProperty(document, 'body', {\n        value: { clientWidth: 10000 },\n        writable: true,\n      });\n\n      expect(getViewportWidth()).toBe(0);\n    });\n\n    test('should return 0 when documentElement.clientWidth not available', () => {\n      mockGetGlobalScope.mockReturnValue({} as typeof globalThis);\n      Object.defineProperty(document, 'documentElement', {\n        value: null,\n        writable: true,\n      });\n\n      expect(getViewportWidth()).toBe(0);\n    });\n\n    test('should return 0 when no width sources are available', () => {\n      mockGetGlobalScope.mockReturnValue({} as typeof globalThis);\n      Object.defineProperty(document, 'documentElement', {\n        value: null,\n        writable: true,\n      });\n      Object.defineProperty(document, 'body', {\n        value: null,\n        writable: true,\n      });\n\n      expect(getViewportWidth()).toBe(0);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/worker/compression.test.ts",
    "content": "import { eventWithTime } from '@amplitude/rrweb-types';\nimport { compressionOnMessage } from '../../src/worker/compression';\n\ndescribe('compression', () => {\n  test('should serialize event with type and timestamp first', async () => {\n    global.postMessage = jest.fn();\n\n    const testEvent: eventWithTime = {\n      timestamp: 1,\n      type: 4,\n      data: {\n        height: 1,\n        width: 1,\n        href: 'http://localhost',\n      },\n    };\n\n    // hack to make typescript not complain\n    (compressionOnMessage as (_: unknown) => void)({\n      data: {\n        event: testEvent,\n        sessionId: 1234,\n      },\n    });\n\n    // Key ordering: type and timestamp must appear first\n    const expected = JSON.stringify({ type: testEvent.type, timestamp: testEvent.timestamp, data: testEvent.data });\n    expect(global.postMessage).toHaveBeenCalledWith({\n      sessionId: 1234,\n      compressedEvent: expected,\n    });\n  });\n\n  test('should include delay field when present', async () => {\n    global.postMessage = jest.fn();\n\n    const testEventWithDelay = {\n      timestamp: 1,\n      type: 3,\n      delay: 50,\n      data: { source: 0 },\n    };\n\n    (compressionOnMessage as (_: unknown) => void)({\n      data: {\n        event: testEventWithDelay,\n        sessionId: 1234,\n      },\n    });\n\n    const expected = JSON.stringify({\n      type: testEventWithDelay.type,\n      timestamp: testEventWithDelay.timestamp,\n      delay: testEventWithDelay.delay,\n      data: testEventWithDelay.data,\n    });\n    expect(global.postMessage).toHaveBeenCalledWith({\n      sessionId: 1234,\n      compressedEvent: expected,\n    });\n  });\n\n  test('should serialize event from JSON string data when DataCloneError fallback is used', async () => {\n    global.postMessage = jest.fn();\n\n    const testEvent: eventWithTime = {\n      timestamp: 1,\n      type: 4,\n      data: {\n        height: 1,\n        width: 1,\n        href: 'http://localhost',\n      },\n    };\n\n    // Simulate the actual behavior: JSON.stringify produces a primitive string\n    const jsonData = JSON.stringify({\n      event: testEvent,\n      sessionId: 5678,\n    });\n\n    // Pass the primitive string as e.data (this is what actually happens with JSON.stringify fallback)\n    (compressionOnMessage as (_: unknown) => void)({\n      data: jsonData,\n    });\n\n    const expected = JSON.stringify({ type: testEvent.type, timestamp: testEvent.timestamp, data: testEvent.data });\n    expect(global.postMessage).toHaveBeenCalledWith({\n      sessionId: 5678,\n      compressedEvent: expected,\n    });\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/test/worker/track-destination.test.ts",
    "content": "import { trackDestinationOnMessage } from '../../src/worker/track-destination';\n\nconst SESSION_REPLAY_SERVER_URL = 'https://api-sr.amplitude.com/sessions/v2/track';\n\ntype OnMessageHandler = (e: MessageEvent) => Promise<void>;\n\nconst invokeOnMessage = async (data: Record<string, unknown>) => {\n  await (trackDestinationOnMessage as unknown as OnMessageHandler)({ data } as MessageEvent);\n};\n\ndescribe('worker/track-destination', () => {\n  let mockFetch: jest.Mock;\n  let mockPostMessage: jest.Mock;\n\n  beforeEach(() => {\n    mockFetch = jest.fn();\n    mockPostMessage = jest.fn();\n    global.fetch = mockFetch;\n    global.postMessage = mockPostMessage;\n  });\n\n  afterEach(() => {\n    jest.resetAllMocks();\n  });\n\n  const baseContext = {\n    apiKey: 'test-api-key',\n    deviceId: 'device-123',\n    sessionId: 456,\n    events: ['{\"type\":3,\"timestamp\":1}'],\n    eventType: 'replay',\n    flushMaxRetries: 2,\n    sampleRate: 1,\n    currentUrl: 'https://example.com',\n    sdkVersion: '1.0.0',\n  };\n\n  const basePayload = { version: 1, events: ['{\"type\":3,\"timestamp\":1}'] };\n\n  test('ignores messages with unknown type', async () => {\n    await invokeOnMessage({ type: 'unknown', id: '1', payload: basePayload, context: baseContext, useRetry: false });\n    expect(mockFetch).not.toHaveBeenCalled();\n    expect(mockPostMessage).not.toHaveBeenCalled();\n  });\n\n  test('sends fetch request and posts complete on success', async () => {\n    mockFetch.mockResolvedValueOnce({ status: 200 });\n    await invokeOnMessage({ type: 'send', id: '1', payload: basePayload, context: baseContext, useRetry: false });\n\n    expect(mockFetch).toHaveBeenCalledTimes(1);\n    const [url, options] = mockFetch.mock.calls[0] as [string, RequestInit];\n    expect(url).toContain(SESSION_REPLAY_SERVER_URL);\n    expect(url).toContain('device_id=device-123');\n    expect(url).toContain('session_id=456');\n    expect(url).toContain('type=replay');\n    expect((options.headers as Record<string, string>)['Authorization']).toBe('Bearer test-api-key');\n    expect(options.method).toBe('POST');\n    expect(options.keepalive).toBe(true);\n\n    expect(mockPostMessage).toHaveBeenCalledWith(\n      expect.objectContaining({ type: 'log', id: '1', message: expect.stringContaining('tracked successfully') }),\n    );\n    expect(mockPostMessage).toHaveBeenCalledWith({ type: 'complete', id: '1', skipCode: null });\n  });\n\n  test('posts warn and complete on non-retryable failure (4xx)', async () => {\n    mockFetch.mockResolvedValueOnce({ status: 400 });\n    await invokeOnMessage({ type: 'send', id: '2', payload: basePayload, context: baseContext, useRetry: true });\n\n    expect(mockFetch).toHaveBeenCalledTimes(1);\n    expect(mockPostMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'warn', id: '2' }));\n    expect(mockPostMessage).toHaveBeenCalledWith({ type: 'complete', id: '2' });\n  });\n\n  test.each([408, 429, 499])('retries on %i and succeeds on second attempt', async (statusCode) => {\n    const realSetTimeout = global.setTimeout;\n    jest\n      .spyOn(global, 'setTimeout')\n      .mockImplementation((fn) => realSetTimeout(fn, 0) as unknown as ReturnType<typeof setTimeout>);\n\n    mockFetch.mockResolvedValueOnce({ status: statusCode }).mockResolvedValueOnce({ status: 200 });\n\n    await invokeOnMessage({\n      type: 'send',\n      id: '3b',\n      payload: basePayload,\n      context: { ...baseContext, flushMaxRetries: 2 },\n      useRetry: true,\n    });\n\n    expect(mockFetch).toHaveBeenCalledTimes(2);\n    expect(mockPostMessage).toHaveBeenCalledWith(\n      expect.objectContaining({ type: 'log', id: '3b', message: expect.stringContaining('tracked successfully') }),\n    );\n    expect(mockPostMessage).toHaveBeenCalledWith({ type: 'complete', id: '3b', skipCode: null });\n  });\n\n  test('posts payload_too_large with isWaf=false for app-layer 413', async () => {\n    mockFetch.mockResolvedValueOnce({ status: 413, text: () => Promise.resolve('Payload Too Large') });\n    await invokeOnMessage({ type: 'send', id: '7', payload: basePayload, context: baseContext, useRetry: true });\n\n    expect(mockFetch).toHaveBeenCalledTimes(1);\n    expect(mockPostMessage).toHaveBeenCalledWith({ type: 'payload_too_large', id: '7', isWaf: false });\n    expect(mockPostMessage).not.toHaveBeenCalledWith(expect.objectContaining({ type: 'complete' }));\n  });\n\n  test('posts payload_too_large with isWaf=true for WAF 413', async () => {\n    mockFetch.mockResolvedValueOnce({\n      status: 413,\n      text: () => Promise.resolve('{\"error\":\"Payload exceeds the maximum allowed size of 10MB\"}'),\n    });\n    await invokeOnMessage({ type: 'send', id: '8', payload: basePayload, context: baseContext, useRetry: true });\n\n    expect(mockPostMessage).toHaveBeenCalledWith({ type: 'payload_too_large', id: '8', isWaf: true });\n  });\n\n  test('posts payload_too_large even when body read fails', async () => {\n    mockFetch.mockResolvedValueOnce({ status: 413, text: () => Promise.reject(new Error('stream error')) });\n    await invokeOnMessage({ type: 'send', id: '9', payload: basePayload, context: baseContext, useRetry: true });\n\n    expect(mockPostMessage).toHaveBeenCalledWith({ type: 'payload_too_large', id: '9', isWaf: false });\n  });\n\n  test('uses false for isWaf when result.isWaf is undefined', async () => {\n    // Simulate a response where text() succeeds but body is empty (isWaf will be false via ?? false)\n    mockFetch.mockResolvedValueOnce({ status: 413, text: () => Promise.resolve('') });\n    await invokeOnMessage({ type: 'send', id: '10', payload: basePayload, context: baseContext, useRetry: true });\n\n    expect(mockPostMessage).toHaveBeenCalledWith({ type: 'payload_too_large', id: '10', isWaf: false });\n  });\n\n  test('does not bisect on 413 when useRetry=false', async () => {\n    mockFetch.mockResolvedValueOnce({ status: 413, text: () => Promise.resolve('Payload Too Large') });\n    await invokeOnMessage({ type: 'send', id: '11', payload: basePayload, context: baseContext, useRetry: false });\n\n    expect(mockPostMessage).not.toHaveBeenCalledWith(expect.objectContaining({ type: 'payload_too_large' }));\n    expect(mockPostMessage).toHaveBeenCalledWith({ type: 'complete', id: '11' });\n  });\n\n  test('retries on 5xx and succeeds on second attempt', async () => {\n    // Use a real timer but patch setTimeout to fire immediately so the test is fast\n    const realSetTimeout = global.setTimeout;\n    jest\n      .spyOn(global, 'setTimeout')\n      .mockImplementation((fn) => realSetTimeout(fn, 0) as unknown as ReturnType<typeof setTimeout>);\n\n    mockFetch.mockResolvedValueOnce({ status: 500 }).mockResolvedValueOnce({ status: 200 });\n\n    await invokeOnMessage({\n      type: 'send',\n      id: '3',\n      payload: basePayload,\n      context: { ...baseContext, flushMaxRetries: 2 },\n      useRetry: true,\n    });\n\n    expect(mockFetch).toHaveBeenCalledTimes(2);\n    expect(mockPostMessage).toHaveBeenCalledWith(\n      expect.objectContaining({ type: 'log', id: '3', message: expect.stringContaining('tracked successfully') }),\n    );\n    expect(mockPostMessage).toHaveBeenCalledWith({ type: 'complete', id: '3', skipCode: null });\n  });\n\n  test('posts warn with max retries message when retries exhausted', async () => {\n    const realSetTimeout = global.setTimeout;\n    jest\n      .spyOn(global, 'setTimeout')\n      .mockImplementation((fn) => realSetTimeout(fn, 0) as unknown as ReturnType<typeof setTimeout>);\n\n    mockFetch.mockResolvedValue({ status: 500 });\n\n    await invokeOnMessage({\n      type: 'send',\n      id: '4',\n      payload: basePayload,\n      context: { ...baseContext, flushMaxRetries: 2 },\n      useRetry: true,\n    });\n\n    expect(mockFetch).toHaveBeenCalledTimes(2);\n    expect(mockPostMessage).toHaveBeenCalledWith(\n      expect.objectContaining({\n        type: 'warn',\n        id: '4',\n        message: 'Session replay event batch rejected due to exceeded retry count',\n      }),\n    );\n    expect(mockPostMessage).toHaveBeenCalledWith({ type: 'complete', id: '4' });\n  });\n\n  test('does not retry when useRetry is false', async () => {\n    mockFetch.mockResolvedValueOnce({ status: 500 });\n    await invokeOnMessage({\n      type: 'send',\n      id: '5',\n      payload: basePayload,\n      context: { ...baseContext, flushMaxRetries: 5 },\n      useRetry: false,\n    });\n\n    expect(mockFetch).toHaveBeenCalledTimes(1);\n    expect(mockPostMessage).toHaveBeenCalledWith({ type: 'complete', id: '5' });\n  });\n\n  test('posts warn and complete on fetch network error', async () => {\n    mockFetch.mockRejectedValueOnce(new Error('network failure'));\n    await invokeOnMessage({ type: 'send', id: '6', payload: basePayload, context: baseContext, useRetry: false });\n\n    expect(mockPostMessage).toHaveBeenCalledWith(\n      expect.objectContaining({ type: 'warn', id: '6', message: expect.stringContaining('network failure') }),\n    );\n    expect(mockPostMessage).toHaveBeenCalledWith({ type: 'complete', id: '6' });\n  });\n\n  test('uses EU server URL when serverZone is EU', async () => {\n    mockFetch.mockResolvedValueOnce({ status: 200 });\n    await invokeOnMessage({\n      type: 'send',\n      id: '7',\n      payload: basePayload,\n      context: { ...baseContext, serverZone: 'EU' },\n      useRetry: false,\n    });\n\n    const [url] = mockFetch.mock.calls[0] as [string];\n    expect(url).toContain('api-sr.eu.amplitude.com');\n  });\n\n  test('uses custom trackServerUrl when provided', async () => {\n    mockFetch.mockResolvedValueOnce({ status: 200 });\n    await invokeOnMessage({\n      type: 'send',\n      id: '8',\n      payload: basePayload,\n      context: { ...baseContext, trackServerUrl: 'https://custom.example.com/track' },\n      useRetry: false,\n    });\n\n    const [url] = mockFetch.mock.calls[0] as [string];\n    expect(url).toContain('https://custom.example.com/track');\n  });\n\n  test('uses staging URL when serverZone is STAGING', async () => {\n    mockFetch.mockResolvedValueOnce({ status: 200 });\n    await invokeOnMessage({\n      type: 'send',\n      id: '9',\n      payload: basePayload,\n      context: { ...baseContext, serverZone: 'STAGING' },\n      useRetry: false,\n    });\n\n    const [url] = mockFetch.mock.calls[0] as [string];\n    expect(url).toContain('api-sr.stag2.amplitude.com');\n  });\n\n  test('includes version library header when version is provided', async () => {\n    mockFetch.mockResolvedValueOnce({ status: 200 });\n    await invokeOnMessage({\n      type: 'send',\n      id: '10',\n      payload: basePayload,\n      context: { ...baseContext, version: { type: 'plugin', version: '2.0.0' } },\n      useRetry: false,\n    });\n\n    const [, options] = mockFetch.mock.calls[0] as [string, RequestInit];\n    expect((options.headers as Record<string, string>)['X-Client-Library']).toBe('plugin/2.0.0');\n  });\n\n  test('returns null result when fetch returns null', async () => {\n    mockFetch.mockResolvedValueOnce(null);\n    await invokeOnMessage({ type: 'send', id: '11', payload: basePayload, context: baseContext, useRetry: false });\n\n    expect(mockPostMessage).toHaveBeenCalledWith(\n      expect.objectContaining({ type: 'warn', id: '11', message: 'Unexpected error occurred' }),\n    );\n    expect(mockPostMessage).toHaveBeenCalledWith({ type: 'complete', id: '11' });\n  });\n\n  describe('X-Session-Replay-Event-Skipped header', () => {\n    test('forwards throttled (429) skip code on the complete message', async () => {\n      mockFetch.mockResolvedValueOnce({\n        status: 200,\n        headers: { get: jest.fn().mockReturnValue('429') },\n      });\n      await invokeOnMessage({ type: 'send', id: 's1', payload: basePayload, context: baseContext, useRetry: false });\n\n      expect(mockPostMessage).toHaveBeenCalledWith({ type: 'complete', id: 's1', skipCode: '429' });\n    });\n\n    test.each(['4004', '4005'])('forwards hard-kill skip code %s on the complete message', async (code) => {\n      mockFetch.mockResolvedValueOnce({\n        status: 200,\n        headers: { get: jest.fn().mockReturnValue(code) },\n      });\n      await invokeOnMessage({ type: 'send', id: 's2', payload: basePayload, context: baseContext, useRetry: false });\n\n      expect(mockPostMessage).toHaveBeenCalledWith({ type: 'complete', id: 's2', skipCode: code });\n    });\n\n    test('emits skipCode=null when 2xx has no skip header (header.get returns null)', async () => {\n      mockFetch.mockResolvedValueOnce({\n        status: 200,\n        headers: { get: jest.fn().mockReturnValue(null) },\n      });\n      await invokeOnMessage({ type: 'send', id: 's3', payload: basePayload, context: baseContext, useRetry: false });\n\n      expect(mockPostMessage).toHaveBeenCalledWith({ type: 'complete', id: 's3', skipCode: null });\n    });\n\n    test('omits skipCode field on non-2xx (failure) complete messages', async () => {\n      mockFetch.mockResolvedValueOnce({ status: 400 });\n      await invokeOnMessage({ type: 'send', id: 's4', payload: basePayload, context: baseContext, useRetry: false });\n\n      // Failure path emits a plain complete (no skipCode), so the main thread won't apply any directive.\n      expect(mockPostMessage).toHaveBeenCalledWith({ type: 'complete', id: 's4' });\n    });\n  });\n\n  test('falls back to uncompressed when CompressionStream throws', async () => {\n    class BrokenCompressionStream {\n      constructor() {\n        throw new Error('not supported');\n      }\n    }\n    (global as any).CompressionStream = BrokenCompressionStream;\n\n    try {\n      mockFetch.mockResolvedValueOnce({ status: 200 });\n      await invokeOnMessage({ type: 'send', id: '13', payload: basePayload, context: baseContext, useRetry: false });\n\n      expect(mockFetch).toHaveBeenCalledTimes(1);\n      const [, options] = mockFetch.mock.calls[0] as [string, RequestInit];\n      expect((options.headers as Record<string, string>)['Content-Encoding']).toBeUndefined();\n      expect(typeof options.body).toBe('string');\n    } finally {\n      delete (global as any).CompressionStream;\n    }\n  });\n\n  test('gzip-compresses payload when CompressionStream is available', async () => {\n    // Mock CompressionStream with mock reader/writer objects (avoids ReadableStream/WritableStream\n    // availability issues in the jsdom test environment).\n    const mockCompressed = new Uint8Array([0x1f, 0x8b]);\n    const mockWriter = { write: jest.fn().mockResolvedValue(undefined), close: jest.fn().mockResolvedValue(undefined) };\n    const mockReader = {\n      read: jest\n        .fn()\n        .mockResolvedValueOnce({ done: false, value: mockCompressed })\n        .mockResolvedValueOnce({ done: true, value: undefined }),\n    };\n    class MockCompressionStream {\n      writable = { getWriter: () => mockWriter };\n      readable = { getReader: () => mockReader };\n    }\n\n    // In jest+jsdom, 'CompressionStream' is checked via `'CompressionStream' in self`\n    // where `self === global`. Set it on global so the check passes.\n    (global as any).CompressionStream = MockCompressionStream;\n\n    try {\n      mockFetch.mockResolvedValueOnce({ status: 200 });\n      await invokeOnMessage({ type: 'send', id: '12', payload: basePayload, context: baseContext, useRetry: false });\n\n      expect(mockFetch).toHaveBeenCalledTimes(1);\n      const [, options] = mockFetch.mock.calls[0] as [string, RequestInit];\n      expect((options.headers as Record<string, string>)['Content-Encoding']).toBe('gzip');\n      expect(options.body).toEqual(mockCompressed);\n    } finally {\n      delete (global as any).CompressionStream;\n    }\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-browser/tsconfig.es5.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"exclude\": [\"src/worker/compression.ts\", \"src/worker/track-destination.ts\"],\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/cjs\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/session-replay-browser/tsconfig.esm.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"exclude\": [\"src/worker/compression.ts\", \"src/worker/track-destination.ts\"],\n  \"compilerOptions\": {\n    \"module\": \"es2020\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/esm\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/session-replay-browser/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src/**/*\", \"test/**/*\", \"e2e/**/*\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"esModuleInterop\": true,\n    \"lib\": [\"dom\"],\n    \"noEmit\": true,\n    \"rootDir\": \".\"\n  }\n}\n"
  },
  {
    "path": "packages/session-replay-browser/tsconfig.worker.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/worker/compression.ts\", \"src/worker/track-destination.ts\"],\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/cjs\",\n    \"rootDir\": \"./src\",\n    \"lib\": [\"ES2020\", \"WebWorker\"],\n    \"noUnusedLocals\": false,\n    \"noUnusedParameters\": false,\n    \"skipLibCheck\": true\n  }\n}\n"
  },
  {
    "path": "packages/session-replay-react-native/.gitattributes",
    "content": "*.pbxproj -text\n# specific for windows script files\n*.bat text eol=crlf"
  },
  {
    "path": "packages/session-replay-react-native/.gitignore",
    "content": "# OSX\n#\n.DS_Store\n\n# XDE\n.expo/\n\n# VSCode\n.vscode/\njsconfig.json\n\n# Xcode\n#\nbuild/\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\nxcuserdata\n*.xccheckout\n*.moved-aside\nDerivedData\n*.hmap\n*.ipa\n*.xcuserstate\nproject.xcworkspace\n\n# Android/IJ\n#\n.classpath\n.cxx\n.gradle\n.idea\n.project\n.settings\nlocal.properties\nandroid.iml\n\n# Cocoapods\n#\nexample/ios/Pods\n\n# Ruby\nexample/vendor/\n\n# node.js\n#\nnode_modules/\nnpm-debug.log\nyarn-debug.log\nyarn-error.log\n\n# BUCK\nbuck-out/\n\\.buckd/\nandroid/app/libs\nandroid/keystores/debug.keystore\n\n# Yarn\n.yarn/*\n!.yarn/patches\n!.yarn/plugins\n!.yarn/releases\n!.yarn/sdks\n!.yarn/versions\n\n# Expo\n.expo/\n\n# Turborepo\n.turbo/\n\n# generated by bob\nlib/\n\n# React Native Codegen\nios/generated\nandroid/generated\n"
  },
  {
    "path": "packages/session-replay-react-native/.nvmrc",
    "content": "v18\n"
  },
  {
    "path": "packages/session-replay-react-native/.watchmanconfig",
    "content": "{}\n"
  },
  {
    "path": "packages/session-replay-react-native/AmplitudeSessionReplayReactNative.podspec",
    "content": "require \"json\"\n\npackage = JSON.parse(File.read(File.join(__dir__, \"package.json\")))\nfolly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'\n\nPod::Spec.new do |s|\n  s.name         = \"AmplitudeSessionReplayReactNative\"\n  s.version      = package[\"version\"].split(/[-+]/).first\n  s.summary      = package[\"description\"]\n  s.homepage     = package[\"homepage\"]\n  s.license      = package[\"license\"]\n  s.authors      = package[\"author\"]\n\n  s.platforms    = { :ios => min_ios_version_supported }\n  s.source       = { :git => \"https://github.com/amplitude/Amplitude-TypeScript.git\", :tag => \"#{s.version}\" }\n\n  s.source_files = \"ios/**/*.{h,m,mm,swift}\"\n\n  s.dependency 'AmplitudeSessionReplay', '>=0.9.5'\n  s.dependency 'AmplitudeCore', '>=1.4.2'\n\n  # This code is to support RN prior to 0.71.0. Should be removed when we drop support for RN < 0.71.0.\n  # Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.\n  # See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.\n  if respond_to?(:install_modules_dependencies, true)\n    install_modules_dependencies(s)\n  else\n    s.dependency \"React-Core\"\n\n    # Don't install the dependencies when we run `pod install` in the old architecture.\n    if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then\n      s.compiler_flags = folly_compiler_flags + \" -DRCT_NEW_ARCH_ENABLED=1\"\n      s.pod_target_xcconfig    = {\n          \"HEADER_SEARCH_PATHS\" => \"\\\"$(PODS_ROOT)/boost\\\"\",\n          \"OTHER_CPLUSPLUSFLAGS\" => \"-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1\",\n          \"CLANG_CXX_LANGUAGE_STANDARD\" => \"c++17\"\n      }\n      s.dependency \"React-Codegen\"\n      s.dependency \"RCT-Folly\"\n      s.dependency \"RCTRequired\"\n      s.dependency \"RCTTypeSafety\"\n      s.dependency \"ReactCommon/turbomodule/core\"\n    end\n  end\nend\n"
  },
  {
    "path": "packages/session-replay-react-native/CHANGELOG.md",
    "content": "# Changelog\n\n## 0.0.1-beta.3 (2025-12-02)\n\n- Release 0.0.1-beta.3\n\n\n## 0.0.1-beta.2 (2025-07-08)\n\n- Release 0.0.1-beta.2\n\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n"
  },
  {
    "path": "packages/session-replay-react-native/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2024 Amplitude, Inc.\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "packages/session-replay-react-native/README.md",
    "content": "# @amplitude/session-replay-react-native\n\nAmplitude Session Replay for React Native\n\n## Installation\n\n```sh\nnpm install @amplitude/session-replay-react-native\n```\n\n## Usage\n\n### Session Replay React Native Standalone SDK\n\nInitialize SDK with your amplidude API Key\n```js\nimport { init, SessionReplayConfig } from '@amplitude/session-replay-react-native';\n\nconst config: SessionReplayConfig = { \n    apiKey: 'YOUR_API_KEY',\n    deviceId: 'YOUR_DEVICE_ID',\n    sessionId: Date.now()\n}\n\nawait init(config);\n```\n\n### Session Replay React Native Plugin\n\nAdd the session replay plugin to your Amplitude instance as follows\n\n```js\nimport { SessionReplayPlugin, SessionReplaPluginConfig } from '@amplitude/session-replay-react-native';\n\n// ...\n\nconst config: SessionReplaPluginConfig = {\n  enableRemoteConfig: true, // default true\n  sampleRate: 1, // default 0\n  logLevel: LogLevel.Warn, // default LogLevel.Warn\n};\nawait init('YOUR_API_KEY').promise;\nawait add(new SessionReplayPlugin(config)).promise;\n```\n\n## Masking views\n\nTo maks certain views, add the `AmpMaskView` tag with the mask property `amp-mask` around the section to be masked\n\n```js\nimport { AmpMaskView } from '@amplitude/session-replay-react-native';\n\n// ...\n\n<AmpMaskView mask=\"amp-mask\">\n  <Text\n    style={[\n      styles.sectionTitle,\n      {\n        color: isDarkMode ? Colors.white : Colors.black,\n      },\n    ]}\n  >\n    {title}\n  </Text>\n</AmpMaskView>;\n```\n\n## Unmasking views\n\nTo unmask views, add the `AmpMaskView` tag with the mask property `amp-unmask` around the section to be unmasked\n\n```js\nimport { AmpMaskView } from '@amplitude/session-replay-react-native';\n\n// ...\n\n<AmpMaskView mask=\"amp-unmask\">\n  <Text\n    style={[\n      styles.sectionTitle,\n      {\n        color: isDarkMode ? Colors.white : Colors.black,\n      },\n    ]}\n  >\n    {title}\n  </Text>\n</AmpMaskView>;\n```\n\n## Tracking Web Views (Beta)\n\nWeb views are blocked by default and will not be tracked. If you'd like webviews to be tracked, you can manually unmask\nthem by doing the following\n\n```js\n<AmpMaskView mask=\"amp-unmask\" style={{ flex: 1 }}>\n  <WebView source={{ uri: 'https://reactnative.dev/' }} style={{ flex: 1 }} />\n</AmpMaskView>\n```\n"
  },
  {
    "path": "packages/session-replay-react-native/android/build.gradle",
    "content": "def reactNativeArchitectures() {\n  def value = rootProject.getProperties().get(\"reactNativeArchitectures\")\n  return value ? value.split(\",\") : [\"armeabi-v7a\", \"x86\", \"x86_64\", \"arm64-v8a\"]\n}\n\ndef isNewArchitectureEnabled() {\n  return rootProject.hasProperty(\"newArchEnabled\") && rootProject.getProperty(\"newArchEnabled\") == \"true\"\n}\n\napply plugin: \"com.android.library\"\napply plugin: \"kotlin-android\"\n\nif (isNewArchitectureEnabled()) {\n  apply plugin: \"com.facebook.react\"\n}\n\ndef getExtOrDefault(name) {\n  return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties[\"SessionReplayReactNative_\" + name]\n}\n\ndef getExtOrIntegerDefault(name) {\n  return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties[\"SessionReplayReactNative_\" + name]).toInteger()\n}\n\ndef supportsNamespace() {\n  def parsed = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')\n  def major = parsed[0].toInteger()\n  def minor = parsed[1].toInteger()\n\n  // Namespace support was added in 7.3.0\n  return (major == 7 && minor >= 3) || major >= 8\n}\n\nandroid {\n  if (supportsNamespace()) {\n    namespace \"com.amplitude.sessionreplayreactnative\"\n\n    sourceSets {\n      main {\n        manifest.srcFile \"src/main/AndroidManifestNew.xml\"\n      }\n    }\n  }\n\n  compileSdkVersion getExtOrIntegerDefault(\"compileSdkVersion\")\n\n  defaultConfig {\n    minSdkVersion getExtOrIntegerDefault(\"minSdkVersion\")\n    targetSdkVersion getExtOrIntegerDefault(\"targetSdkVersion\")\n\n  }\n\n  buildTypes {\n    release {\n      minifyEnabled false\n    }\n  }\n\n  lintOptions {\n    disable \"GradleCompatible\"\n  }\n\n  compileOptions {\n    sourceCompatibility JavaVersion.VERSION_1_8\n    targetCompatibility JavaVersion.VERSION_1_8\n  }\n}\n\nrepositories {\n  mavenCentral()\n  google()\n}\n\ndef kotlin_version = getExtOrDefault(\"kotlinVersion\")\n\ndependencies {\n  implementation(\"com.amplitude:session-replay-android:[0.24.0,0.25.0)\")\n  implementation(\"com.amplitude:analytics-android:[1.25.0,1.26.0)\")\n\n  // For < 0.71, this will be from the local maven repo\n  // For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin\n  //noinspection GradleDynamicVersion\n  implementation \"com.facebook.react:react-native:+\"\n  implementation \"org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version\"\n}\n"
  },
  {
    "path": "packages/session-replay-react-native/android/gradle.properties",
    "content": "SessionReplayReactNative_kotlinVersion=1.7.0\nSessionReplayReactNative_minSdkVersion=21\nSessionReplayReactNative_targetSdkVersion=31\nSessionReplayReactNative_compileSdkVersion=31\nSessionReplayReactNative_ndkversion=21.4.7075529\n"
  },
  {
    "path": "packages/session-replay-react-native/android/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n          package=\"com.amplitude.sessionreplayreactnative\">\n</manifest>\n"
  },
  {
    "path": "packages/session-replay-react-native/android/src/main/AndroidManifestNew.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n</manifest>\n"
  },
  {
    "path": "packages/session-replay-react-native/android/src/main/java/com/amplitude/sessionreplayreactnative/SessionReplayReactNativeModule.kt",
    "content": "package com.amplitude.sessionreplayreactnative\n\nimport com.amplitude.android.sessionreplay.SessionReplay\nimport com.amplitude.android.sessionreplay.config.MaskLevel\nimport com.amplitude.android.sessionreplay.config.PrivacyConfig\nimport com.amplitude.common.Logger\nimport com.amplitude.common.android.LogcatLogger\nimport com.amplitude.core.ServerZone\nimport com.facebook.react.bridge.ReactApplicationContext\nimport com.facebook.react.bridge.ReactContextBaseJavaModule\nimport com.facebook.react.bridge.ReactMethod\nimport com.facebook.react.bridge.Promise\nimport com.facebook.react.bridge.WritableMap\nimport com.facebook.react.bridge.WritableNativeMap\nimport com.facebook.react.bridge.ReadableMap\n\nclass SessionReplayReactNativeModule(private val reactContext: ReactApplicationContext) :\n  ReactContextBaseJavaModule(reactContext) {\n  private lateinit var sessionReplay: SessionReplay\n\n  override fun getName(): String {\n    return \"AMPNativeSessionReplay\"\n  }\n\n  @ReactMethod\n  fun setup(config: ReadableMap, promise: Promise) {\n    try {\n      val apiKey = config.getString(\"apiKey\") ?: throw IllegalArgumentException(\"apiKey is required\")\n      val deviceId = config.getString(\"deviceId\")\n      val sessionId = config.getDouble(\"sessionId\").toLong()\n      val serverZone = config.getString(\"serverZone\") ?: \"US\"\n      val sampleRate = config.getDouble(\"sampleRate\")\n      val enableRemoteConfig = config.getBoolean(\"enableRemoteConfig\")\n      val logLevel = config.getInt(\"logLevel\")\n      val autoStart = config.getBoolean(\"autoStart\")\n      val optOut = config.getBoolean(\"optOut\")\n      val maskLevel = when ((config.getString(\"maskLevel\") ?: \"medium\").lowercase()) {\n        \"light\" -> MaskLevel.LIGHT\n        \"medium\" -> MaskLevel.MEDIUM\n        \"conservative\" -> MaskLevel.CONSERVATIVE\n        else -> MaskLevel.MEDIUM\n      }\n\n      LogcatLogger.logger.logMode = when (logLevel) {\n          0 -> Logger.LogMode.OFF\n          1 -> Logger.LogMode.ERROR\n          2 -> Logger.LogMode.WARN\n          3 -> Logger.LogMode.INFO\n          4 -> Logger.LogMode.DEBUG\n          else -> Logger.LogMode.WARN\n      }\n\n      LogcatLogger.logger.debug(\"\"\"\n          setup:\n          API Key: $apiKey\n          Device Id: $deviceId\n          Session Id: $sessionId\n          Server Zone: $serverZone\n          Sample Rate: $sampleRate\n          Enable Remote Config: $enableRemoteConfig\n          Log Level: $logLevel\n          Auto Start: $autoStart\n          Mask Level: $maskLevel\n          Opt Out: $optOut\n      \"\"\".trimIndent())\n\n      sessionReplay = SessionReplay(\n        apiKey = apiKey,\n        context = reactContext.applicationContext,\n        deviceId = deviceId ?: \"\",\n        sessionId = sessionId,\n        optOut = optOut,\n        sampleRate = sampleRate,\n        logger = LogcatLogger.logger,\n        enableRemoteConfig = enableRemoteConfig,\n        serverZone = when (serverZone) {\n          \"EU\" -> ServerZone.EU\n          else -> ServerZone.US\n        },\n        autoStart = autoStart,\n        privacyConfig = PrivacyConfig(maskLevel = maskLevel),\n      )\n      \n      promise.resolve(null)\n    } catch (e: Exception) {\n      promise.reject(\"SETUP_ERROR\", e.message, e)\n    }\n  }\n\n  @ReactMethod\n  fun setSessionId(sessionId: Double, promise: Promise) {\n    try {\n      sessionReplay.setSessionId(sessionId.toLong())\n      promise.resolve(null)\n    } catch (e: Exception) {\n      promise.reject(\"SET_SESSION_ID_ERROR\", e.message, e)\n    }\n  }\n\n  @ReactMethod\n  fun setDeviceId(deviceId: String?, promise: Promise) {\n    try {\n      sessionReplay.setDeviceId(deviceId ?: \"\")\n      promise.resolve(null)\n    } catch (e: Exception) {\n      promise.reject(\"SET_DEVICE_ID_ERROR\", e.message, e)\n    }\n  }\n\n  @ReactMethod\n  fun getSessionId(promise: Promise) {\n    try {\n      promise.resolve(sessionReplay.getSessionId().toDouble())\n    } catch (e: Exception) {\n      promise.reject(\"GET_SESSION_ID_ERROR\", e.message, e)\n    }\n  }\n\n  @ReactMethod\n  fun getSessionReplayProperties(promise: Promise) {\n    try {\n      val properties: Map<String, Any> = sessionReplay.getSessionReplayProperties()\n      val map: WritableMap = WritableNativeMap()\n      for ((key, value) in properties) {\n        if (value is String) {\n          map.putString(key, value)\n        } else if (value is Int) {\n          map.putInt(key, value)\n        } else if (value is Long) {\n          map.putDouble(key, value.toDouble())\n        } else if (value is Double) {\n          map.putDouble(key, value)\n        } else if (value is Boolean) {\n          map.putBoolean(key, value)\n        }\n      }\n      promise.resolve(map)\n    } catch (e: Exception) {\n      promise.reject(\"GET_PROPERTIES_ERROR\", e.message, e)\n    }\n  }\n  \n  @ReactMethod\n  fun start(promise: Promise) {\n    try {\n      sessionReplay.start()\n      promise.resolve(null)\n    } catch (e: Exception) {\n      promise.reject(\"START_ERROR\", e.message, e)\n    }\n  }\n\n  @ReactMethod\n  fun stop(promise: Promise) {\n    try {\n      sessionReplay.stop()\n      promise.resolve(null)\n    } catch (e: Exception) {\n      promise.reject(\"STOP_ERROR\", e.message, e)\n    }\n  }\n\n  @ReactMethod\n  fun flush(promise: Promise) {\n    try {\n      sessionReplay.flush()\n      promise.resolve(null)\n    } catch (e: Exception) {\n      promise.reject(\"FLUSH_ERROR\", e.message, e)\n    }\n  }\n\n  @ReactMethod\n  fun teardown() {\n    sessionReplay.shutdown()\n  }\n\n  override fun invalidate() {\n    if (::sessionReplay.isInitialized) {\n      sessionReplay.shutdown()\n    }\n  }\n}\n"
  },
  {
    "path": "packages/session-replay-react-native/android/src/main/java/com/amplitude/sessionreplayreactnative/SessionReplayReactNativePackage.kt",
    "content": "package com.amplitude.sessionreplayreactnative\n\nimport com.facebook.react.ReactPackage\nimport com.facebook.react.bridge.NativeModule\nimport com.facebook.react.bridge.ReactApplicationContext\nimport com.facebook.react.uimanager.ViewManager\n\n\nclass SessionReplayReactNativePackage : ReactPackage {\n  override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {\n    return listOf(SessionReplayReactNativeModule(reactContext))\n  }\n\n  override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {\n    return listOf(SessionReplayReactNativeViewManager())\n  }\n}\n"
  },
  {
    "path": "packages/session-replay-react-native/android/src/main/java/com/amplitude/sessionreplayreactnative/SessionReplayReactNativeViewManager.kt",
    "content": "package com.amplitude.sessionreplayreactnative\n\nimport android.view.ViewGroup\nimport com.amplitude.android.sessionreplay.SessionReplay\nimport com.facebook.react.uimanager.annotations.ReactProp\nimport com.facebook.react.views.view.ReactViewManager\n\nclass SessionReplayReactNativeViewManager : ReactViewManager() {\n\n    override fun getName(): String {\n        return \"AMPMaskComponentView\"\n    }\n\n    @ReactProp(name = \"mask\")\n    fun setMask(view: ViewGroup, ampMask: String) {\n        when (ampMask) {\n            \"amp-mask\" -> SessionReplay.mask(view)\n            \"amp-unmask\" -> SessionReplay.unmask(view)\n            \"amp-block\" -> SessionReplay.block(view)\n        }\n    }\n}\n"
  },
  {
    "path": "packages/session-replay-react-native/babel.config.js",
    "content": "module.exports = {\n  presets: ['module:metro-react-native-babel-preset'],\n};\n"
  },
  {
    "path": "packages/session-replay-react-native/ios/AMPNativeSessionReplay.mm",
    "content": "#import <React/RCTBridgeModule.h>\n\n@interface RCT_EXTERN_MODULE(AMPNativeSessionReplay, NSObject)\n\nRCT_EXTERN_METHOD(flush:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)\n\nRCT_EXTERN_METHOD(getSessionId:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)\n\nRCT_EXTERN_METHOD(getSessionReplayProperties:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)\n\nRCT_EXTERN_METHOD(setSessionId:(nonnull NSNumber)sessionId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)\n\nRCT_EXTERN_METHOD(setDeviceId:(NSString)deviceId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)\n\nRCT_EXTERN_METHOD(setup:(NSDictionary *)config resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)\n\nRCT_EXTERN_METHOD(start:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)\n\nRCT_EXTERN_METHOD(stop:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)\n\n@end\n"
  },
  {
    "path": "packages/session-replay-react-native/ios/NativeSessionReplay-Bridging-Header.h",
    "content": "#import <React/RCTBridgeModule.h>\n#import <React/RCTViewManager.h>\n"
  },
  {
    "path": "packages/session-replay-react-native/ios/NativeSessionReplay.swift",
    "content": "import Foundation\nimport AmplitudeSessionReplay\nimport AmplitudeCore\n\n@objc(AMPNativeSessionReplay)\nclass NativeSessionReplay: NSObject, RCTBridgeModule {\n    static func moduleName() -> String! {\n        \"AMPNativeSessionReplay\"\n    }\n    \n    var sessionReplay: SessionReplay!\n    var logger: CoreLogger!\n    \n    override init() {\n        print(\"NativeSessionReplay init\")\n    }\n    \n    @objc(setup:resolve:reject:)\n    func setup(_ config: NSDictionary, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {\n        guard let apiKey = config[\"apiKey\"] as? String,\n              let sessionId = config[\"sessionId\"] as? NSNumber,\n              let serverZone = config[\"serverZone\"] as? String,\n              let sampleRate = config[\"sampleRate\"] as? NSNumber,\n              let enableRemoteConfig = config[\"enableRemoteConfig\"] as? Bool,\n              let logLevel = config[\"logLevel\"] as? Int,\n              let autoStart = config[\"autoStart\"] as? Bool,\n              let maskLevel = config[\"maskLevel\"] as? String,\n              let optOut = config[\"optOut\"] as? Bool else {\n            reject(\"INVALID_CONFIG\", \"Invalid configuration parameters\", nil)\n            return\n        }\n        \n        let deviceId = config[\"deviceId\"] as? String\n        \n        logger = OSLogger(logLevel: LogLevel(rawValue: logLevel) ?? .warn)\n        \n        logger.log(message:\n            \"\"\"\n            setup:\n            API Key: \\(apiKey)\n            Device ID: \\(deviceId ?? \"null\")\n            Session ID: \\(sessionId)\n            Server Zone: \\(serverZone)\n            Sample Rate: \\(sampleRate)\n            Enable Remote Config: \\(enableRemoteConfig)\n            Log Level: \\(logLevel)\n            Auto Start: \\(autoStart)\n            Mask Level: \\(maskLevel)\n            Opt Out: \\(optOut)\n            \"\"\"\n        )\n        \n        sessionReplay = SessionReplay(\n            apiKey: apiKey,\n            deviceId: deviceId,\n            sessionId: sessionId.int64Value,\n            optOut: optOut,\n            sampleRate: Float(truncating: sampleRate),\n            logger: logger,\n            serverZone: serverZone == \"EU\" ? .EU : .US,\n            maskLevel: .fromString(maskLevel),\n            enableRemoteConfig: enableRemoteConfig\n        )\n        \n        if (autoStart) {\n            sessionReplay.start()\n        }\n        resolve(nil)\n    }\n    \n    @objc(setSessionId:resolve:reject:)\n    func setSessionId(_ sessionId: NSNumber, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {\n        logger.debug(message: \"setSessionId: \\(sessionId)\")\n        sessionReplay.sessionId = sessionId.int64Value\n        resolve(nil)\n    }\n    \n    @objc(setDeviceId:resolve:reject:)\n    func setDeviceId(_ deviceId: NSString, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {\n        logger.debug(message: \"setDeviceId: \\(deviceId)\")\n        sessionReplay.deviceId = deviceId as String?\n        resolve(nil)\n    }\n    \n    @objc(getSessionId:reject:)\n    func getSessionId(\n        _ resolve: RCTPromiseResolveBlock,\n        reject: RCTPromiseRejectBlock\n    ) {\n        logger.debug(message: \"getSessionId\")\n        resolve(NSNumber(value:sessionReplay.sessionId))\n    }\n    \n    @objc(getSessionReplayProperties:reject:)\n    func getSessionReplayProperties(\n        _ resolve: RCTPromiseResolveBlock,\n        reject: RCTPromiseRejectBlock\n    ) {\n        logger.debug(message: \"getSessionReplayProperties\")\n        resolve(sessionReplay.additionalEventProperties)\n    }\n    \n    @objc(start:reject:)\n    func start(_ resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {\n        logger.debug(message: \"start\")\n        sessionReplay.start()\n        print(sessionReplay.additionalEventProperties)\n        print(\n            \"SessionId: \\(sessionReplay.sessionId); DeviceId: \\(sessionReplay.deviceId ?? \"nil\")\"\n        )\n        resolve(nil)\n    }\n    \n    @objc(stop:reject:)\n    func stop(_ resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {\n        logger.debug(message: \"stop\")\n        sessionReplay.stop()\n        resolve(nil)\n    }\n    \n    @objc(flush:reject:)\n    func flush(_ resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {\n        logger.debug(message: \"flush\")\n        sessionReplay.flush()\n        resolve(nil)\n    }\n    \n    @objc(invalidate)\n    func invalidate() {\n        print(\"invalidate\")\n        // could be nil here\n        sessionReplay?.stop()\n        sessionReplay = nil\n    }\n}\n\nextension MaskLevel {\n    static func fromString(_ input: String) -> MaskLevel {\n        switch input.lowercased() {\n        case \"light\":\n            return .light\n        case \"medium\":\n            return .medium\n        case \"conservative\":\n            return .conservative\n        default:\n            return .medium\n        }\n    }\n}\n"
  },
  {
    "path": "packages/session-replay-react-native/ios/RCTAmpMaskViewManager.m",
    "content": "#import <React/RCTViewManager.h>\n#import <React/RCTView.h>\n@import AmplitudeSessionReplay;\n\n@interface AMPMaskComponentViewManager : RCTViewManager\n@end\n\n@implementation AMPMaskComponentViewManager\n\nRCT_EXPORT_MODULE(AMPMaskComponentView)\n\n- (UIView *)view\n{\n  return [[RCTView alloc] init];\n}\n\nRCT_CUSTOM_VIEW_PROPERTY(mask, NSString, RCTView)\n{\n  NSString* mask = [RCTConvert NSString:json];\n  if ([mask isEqualToString:@\"amp-mask\"]) {\n    view.amp_isBlocked = true;\n  } else if ([mask isEqualToString:@\"amp-block\"]) {\n    view.amp_isBlocked = true;\n  } else if ([mask isEqualToString:@\"amp-unmask\"]) {\n    view.amp_isBlocked = false;\n  }\n}\n\n@end\n"
  },
  {
    "path": "packages/session-replay-react-native/jest.config.js",
    "content": "const baseConfig = require('../../jest.config.js');\nconst package = require('./package');\n\nmodule.exports = {\n  ...baseConfig,\n  displayName: package.name,\n  rootDir: '.',\n  preset: 'react-native',\n  testEnvironment: 'jsdom',\n  modulePathIgnorePatterns: ['<rootDir>/lib/'],\n  moduleFileExtensions: ['tsx', 'ts', 'js', 'jsx', 'json'],\n  transformIgnorePatterns: [\n    'node_modules/(?!(.pnpm|@react-native|react-native|@segment)/)',\n  ],\n  // TODO: get full coverage\n  coverageThreshold: {\n    global: {\n      branches: 0,\n      functions: 0,\n      lines: 0,\n      statements: 0,\n    },\n  },\n};\n"
  },
  {
    "path": "packages/session-replay-react-native/package.json",
    "content": "{\n  \"name\": \"@amplitude/session-replay-react-native\",\n  \"version\": \"0.0.1-beta.3\",\n  \"description\": \"Amplitude Session Replay for React Native\",\n  \"keywords\": [\n    \"analytics\",\n    \"amplitude\",\n    \"react-native\",\n    \"ios\",\n    \"android\",\n    \"session-replay\"\n  ],\n  \"author\": \"Amplitude Inc\",\n  \"homepage\": \"https://github.com/amplitude/Amplitude-TypeScript\",\n  \"license\": \"MIT\",\n  \"main\": \"lib/commonjs/index\",\n  \"module\": \"lib/module/index\",\n  \"types\": \"lib/typescript/index.d.ts\",\n  \"react-native\": \"src/index\",\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"tag\": \"latest\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/amplitude/Amplitude-TypeScript.git\"\n  },\n  \"scripts\": {\n    \"build\": \"bob build\",\n    \"clean\": \"rimraf node_modules lib coverage\",\n    \"fix\": \"pnpm fix:eslint & pnpm fix:prettier\",\n    \"fix:eslint\": \"eslint '{src,test}/**/*.ts' --fix\",\n    \"fix:prettier\": \"prettier --write \\\"{src,test}/**/*.ts\\\"\",\n    \"lint\": \"pnpm lint:prettier && pnpm lint:eslint\",\n    \"lint:eslint\": \"eslint '{src,test}/**/*.ts'\",\n    \"lint:prettier\": \"prettier --check \\\"{src,test}/**/*.ts\\\"\",\n    \"test\": \"jest\",\n    \"typecheck\": \"tsc -p ./tsconfig.json\",\n    \"version\": \"pnpm version-file && pnpm build\",\n    \"version-file\": \"node -p \\\"'export const VERSION = \\\\'' + require('./package.json').version + '\\\\';'\\\" > src/version.ts\",\n    \"typescript\": \"tsc --noEmit\",\n    \"example\": \"yarn workspace @amplitude/plugin-session-replay-react-native-example\",\n    \"pods\": \"cd example && pod-install --quiet\"\n  },\n  \"source\": \"src/index\",\n  \"files\": [\n    \"src\",\n    \"lib\",\n    \"android\",\n    \"ios\",\n    \"cpp\",\n    \"*.podspec\",\n    \"!ios/build\",\n    \"!android/build\",\n    \"!android/gradle\",\n    \"!android/gradlew\",\n    \"!android/gradlew.bat\",\n    \"!android/local.properties\",\n    \"!test\",\n    \"!**/__tests__\",\n    \"!**/__fixtures__\",\n    \"!**/__mocks__\",\n    \"!**/.*\"\n  ],\n  \"bugs\": {\n    \"url\": \"https://github.com/amplitude/Amplitude-TypeScript/issues\"\n  },\n  \"dependencies\": {\n    \"@amplitude/analytics-types\": \"^1.3.4\"\n  },\n  \"devDependencies\": {\n    \"@types/react\": \"^18.0.26\",\n    \"react\": \"18.2.0\",\n    \"react-native\": \"0.73.0\",\n    \"react-native-builder-bob\": \"^0.20.3\"\n  },\n  \"peerDependencies\": {\n    \"react\": \"*\",\n    \"react-native\": \"*\"\n  },\n  \"react-native-builder-bob\": {\n    \"source\": \"src\",\n    \"output\": \"lib\",\n    \"targets\": [\n      \"commonjs\",\n      \"module\",\n      [\n        \"typescript\",\n        {\n          \"project\": \"tsconfig.build.json\"\n        }\n      ]\n    ]\n  },\n  \"private\": true\n}\n"
  },
  {
    "path": "packages/session-replay-react-native/src/amp-mask-view.tsx",
    "content": "import { requireNativeComponent, type ViewProps } from 'react-native';\n\ninterface AmpMaskViewProps extends ViewProps {\n  mask: 'amp-mask' | 'amp-unmask' | 'amp-block';\n}\n\nexport const AmpMaskView = requireNativeComponent<AmpMaskViewProps>('AMPMaskComponentView');\n"
  },
  {
    "path": "packages/session-replay-react-native/src/index.tsx",
    "content": "export {\n  init,\n  setSessionId,\n  getSessionId,\n  getSessionReplayProperties,\n  flush,\n  start,\n  stop,\n  setDeviceId,\n} from './session-replay';\nexport { type SessionReplayConfig, MaskLevel } from './session-replay-config';\n\nexport { SessionReplayPlugin } from './plugin-session-replay';\nexport type { SessionReplayPluginConfig } from './plugin-session-replay-config';\n\nexport { AmpMaskView } from './amp-mask-view';\n"
  },
  {
    "path": "packages/session-replay-react-native/src/logger.ts",
    "content": "import { LogLevel } from '@amplitude/analytics-types';\n\nconst PREFIX = 'Amplitude Session Replay ';\n\nexport const createSessionReplayLogger = () => {\n  let logLevel: LogLevel = LogLevel.Warn;\n\n  return {\n    setLogLevel: function setLogLevel(level: LogLevel): void {\n      logLevel = level;\n    },\n\n    log: function log(...args: unknown[]): void {\n      if (logLevel < LogLevel.Verbose) {\n        return;\n      }\n      console.log(`${PREFIX}[Log]:`, ...args);\n    },\n\n    warn: function warn(...args: unknown[]): void {\n      if (logLevel < LogLevel.Warn) {\n        return;\n      }\n      console.warn(`${PREFIX}[Warn]:`, ...args);\n    },\n\n    error: function error(...args: unknown[]): void {\n      if (logLevel < LogLevel.Error) {\n        return;\n      }\n      console.error(`${PREFIX}[Error]:`, ...args);\n    },\n\n    debug: function debug(...args: unknown[]): void {\n      if (logLevel < LogLevel.Debug) {\n        return;\n      }\n      console.log(`${PREFIX}[Debug]:`, ...args);\n    },\n  };\n};\n"
  },
  {
    "path": "packages/session-replay-react-native/src/native-module.ts",
    "content": "import { NativeModules, Platform } from 'react-native';\n\nconst LINKING_ERROR =\n  `The package '@amplitude/session-replay-react-native' doesn't seem to be linked. Make sure: \\n\\n` +\n  Platform.select({ ios: \"- You have run 'pod install'\\n\", default: '' }) +\n  '- You rebuilt the app after installing the package\\n' +\n  '- You are not using Expo Go\\n';\n\nexport const NativeSessionReplay = NativeModules.AMPNativeSessionReplay\n  ? (NativeModules.AMPNativeSessionReplay as NativeSessionReplaySpec)\n  : (new Proxy(\n      {},\n      {\n        get() {\n          throw new Error(LINKING_ERROR);\n        },\n      },\n    ) as NativeSessionReplaySpec);\n\n/**\n * Configuration interface for setting up the native iOS and Android session replay modules.\n * This interface defines all the parameters required to initialize the native session replay functionality.\n */\nexport interface NativeSessionReplayConfig {\n  /** Your Amplitude API key for authentication and data routing */\n  apiKey: string;\n  /** Whether to automatically start recording when the module is initialized */\n  autoStart: boolean;\n  /** Device identifier that matches the device ID sent with Amplitude events */\n  deviceId: string | null;\n  /** Whether to enable remote configuration for dynamic settings updates */\n  enableRemoteConfig: boolean;\n  /** Log level for native module logging (0=None, 1=Error, 2=Warn, 3=Log, 4=Debug) */\n  logLevel: 0 | 1 | 2 | 3 | 4;\n  /** Level of masking applied to sensitive content in recordings */\n  maskLevel: 'light' | 'medium' | 'conservative';\n  /** Whether the user has opted out of session replay recording */\n  optOut: boolean;\n  /** Sample rate for session replay (0.0 to 1.0) determining recording frequency */\n  sampleRate: number;\n  /** Amplitude server zone for data routing ('US' or 'EU') */\n  serverZone: 'US' | 'EU';\n  /** Current session identifier for correlating events with recordings */\n  sessionId: number;\n}\n\nexport interface NativeSessionReplayProperties {\n  [key: string]: string | number | boolean;\n}\n\n/**\n * Interface defining the native session replay module specification.\n * This interface provides the contract for communication between JavaScript and\n * the native iOS/Android session replay modules through React Native's bridge.\n *\n * All methods are asynchronous and return Promises to handle the bridge communication\n * between JavaScript and native code.\n */\nexport interface NativeSessionReplaySpec {\n  /**\n   * Flushes any pending session replay data to the server.\n   * Forces immediate upload of recorded session data that may be buffered locally.\n   */\n  flush(): Promise<void>;\n\n  /**\n   * Retrieves the current session identifier from the native module.\n   * @returns Promise resolving to the current session ID number\n   * @note OLD ARCH: ideally we want to cache that on JS side to avoid bridge overhead\n   */\n  getSessionId(): Promise<number>;\n\n  /**\n   * Retrieves session replay properties that should be attached to Amplitude events.\n   * These properties help correlate events with session recordings.\n   * @returns Promise resolving to an object containing session replay metadata\n   * @note OLD ARCH: ideally we want to cache that on JS side to avoid bridge overhead\n   */\n  getSessionReplayProperties(): Promise<NativeSessionReplayProperties>;\n\n  /**\n   * Updates the device identifier used for session replay tracking.\n   * @param deviceId - The device identifier string, or null to clear the device ID\n   * @note OLD ARCH: combine those into one method to avoid bridge overhead\n   */\n  setDeviceId(deviceId: string | null): Promise<void>;\n\n  /**\n   * Updates the session identifier used for session replay tracking.\n   * @param sessionId - The session identifier number\n   * @note OLD ARCH: combine those into one method to avoid bridge overhead\n   */\n  setSessionId(sessionId: number): Promise<void>;\n\n  /**\n   * Initializes the native session replay module with the provided configuration.\n   * This method must be called before any other session replay operations.\n   * @param config - Configuration object containing all necessary parameters for setup\n   */\n  setup(config: NativeSessionReplayConfig): Promise<void>;\n\n  /**\n   * Starts session replay recording.\n   * Begins capturing user interactions and screen content for replay.\n   */\n  start(): Promise<void>;\n\n  /**\n   * Stops session replay recording.\n   * Ends the current recording session and processes any captured data.\n   */\n  stop(): Promise<void>;\n}\n"
  },
  {
    "path": "packages/session-replay-react-native/src/plugin-session-replay-config.ts",
    "content": "import { LogLevel } from '@amplitude/analytics-types';\n\n/**\n * Configuration for Session Replay React Native Plugin\n */\nexport interface SessionReplayPluginConfig {\n  /**\n   * Sample rate for session replay (0.0 to 1.0)\n   * Determines what percentage of sessions will be recorded\n   * @default 0\n   */\n  sampleRate?: number;\n\n  /**\n   * Whether to enable remote configuration\n   * @default true\n   */\n  enableRemoteConfig?: boolean;\n\n  /**\n   * Log level for the SDK\n   * @default LogLevel.Warn\n   */\n  logLevel?: LogLevel;\n\n  /**\n   * Whether to automatically start recording when the plugin is added\n   * @default true\n   */\n  autoStart?: boolean;\n}\n\nexport const getDefaultSessionReplayPluginConfig: () => Required<SessionReplayPluginConfig> = () => {\n  return {\n    sampleRate: 0,\n    enableRemoteConfig: true,\n    logLevel: LogLevel.Warn,\n    autoStart: true,\n  };\n};\n"
  },
  {
    "path": "packages/session-replay-react-native/src/plugin-session-replay.ts",
    "content": "import {\n  type EnrichmentPlugin,\n  type Event,\n  type ReactNativeClient,\n  type ReactNativeConfig,\n} from '@amplitude/analytics-types';\n\nimport { SessionReplayPluginConfig, getDefaultSessionReplayPluginConfig } from './plugin-session-replay-config';\nimport { getSessionId, getSessionReplayProperties, privateInit, setSessionId, start, stop } from './session-replay';\nimport { createSessionReplayLogger } from './logger';\n\n/**\n * Session Replay Plugin for React Native Amplitude SDK.\n * This plugin automatically handles session replay recording and event correlation.\n *\n * The plugin automatically handles:\n * - Device ID and Session ID management\n * - Session ID changes\n * - Event property collection and tracking\n */\nexport class SessionReplayPlugin implements EnrichmentPlugin<ReactNativeClient, ReactNativeConfig> {\n  name = '@amplitude/plugin-session-replay-react-native';\n  type = 'enrichment' as const;\n\n  private config: ReactNativeConfig | null = null;\n  private isInitialized = false;\n\n  private sessionReplayConfig: Required<SessionReplayPluginConfig>;\n  private logger = createSessionReplayLogger();\n\n  /**\n   * Create a new Session Replay Plugin instance.\n   *\n   * @param config - Configuration options for the session replay plugin\n   *\n   * @example\n   * ```typescript\n   * const sessionReplayPlugin = new SessionReplayPlugin({\n   *   sampleRate: 0.1,\n   *   enableRemoteConfig: true,\n   *   logLevel: LogLevel.Warn,\n   *   autoStart: true\n   * });\n   * ```\n   */\n  constructor(config: SessionReplayPluginConfig = {}) {\n    this.sessionReplayConfig = {\n      ...getDefaultSessionReplayPluginConfig(),\n      ...config,\n    };\n\n    this.logger.setLogLevel(this.sessionReplayConfig.logLevel);\n    this.logger.log('Creating SessionReplayPlugin with config: ', this.sessionReplayConfig);\n  }\n\n  /**\n   * Set up the Session Replay Plugin with the Amplitude configuration.\n   * This method is called automatically by the Amplitude SDK during initialization.\n   *\n   * @param config - The React Native configuration from the Amplitude SDK\n   * @param _ - The React Native client instance (unused)\n   * @returns Promise that resolves when setup is complete\n   */\n  async setup(config: ReactNativeConfig, _: ReactNativeClient): Promise<void> {\n    this.config = config;\n    await privateInit(\n      {\n        apiKey: config.apiKey,\n        deviceId: config.deviceId,\n        sessionId: config.sessionId,\n        serverZone: config.serverZone as 'EU' | 'US',\n        sampleRate: this.sessionReplayConfig.sampleRate,\n        enableRemoteConfig: this.sessionReplayConfig.enableRemoteConfig,\n        logLevel: this.sessionReplayConfig.logLevel,\n        autoStart: this.sessionReplayConfig.autoStart,\n      },\n      this.logger,\n    );\n    this.isInitialized = true;\n  }\n\n  async execute(event: Event): Promise<Event | null> {\n    if (!this.isInitialized) {\n      return Promise.resolve(event);\n    }\n\n    // On event, synchronize the session id to the what's on the browserConfig (source of truth)\n    // Choosing not to read from event object here, concerned about offline/delayed events messing up the state stored\n    // in SR.\n    if (this.config?.sessionId && this.config.sessionId !== (await getSessionId())) {\n      await setSessionId(this.config.sessionId);\n    }\n    // Treating config.sessionId as source of truth, if the event's session id doesn't match, the\n    // event is not of the current session (offline/late events). In that case, don't tag the events\n    if (this.config?.sessionId && this.config.sessionId === event.session_id) {\n      const sessionRecordingProperties = await getSessionReplayProperties();\n      event.event_properties = {\n        ...event.event_properties,\n        ...sessionRecordingProperties,\n      };\n    }\n    return Promise.resolve(event);\n  }\n\n  /**\n   * Start session replay recording.\n   * Begins capturing user interactions and screen content for replay.\n   *\n   * @returns Promise that resolves when recording starts\n   */\n  async start(): Promise<void> {\n    if (this.isInitialized) {\n      await start();\n    }\n  }\n\n  /**\n   * Stop session replay recording.\n   * Ends the current recording session and processes any captured data.\n   *\n   * @returns Promise that resolves when recording stops\n   */\n  async stop(): Promise<void> {\n    if (this.isInitialized) {\n      await stop();\n    }\n  }\n\n  async teardown(): Promise<void> {\n    if (this.isInitialized) {\n      await stop();\n    }\n\n    this.config = null;\n    this.isInitialized = false;\n  }\n\n  /**\n   * Get session replay properties for manual event correlation.\n   * When you send events to Amplitude, call this method to get the most up-to-date session replay properties for the event.\n   *\n   * @returns Promise that resolves to an object containing session replay metadata\n   *\n   * @example\n   * ```typescript\n   * const sessionReplayProperties = await plugin.getSessionReplayProperties();\n   * analytics.track('Button Clicked', {\n   *   buttonName: 'submit',\n   *   ...sessionReplayProperties\n   * });\n   * ```\n   */\n  async getSessionReplayProperties() {\n    if (!this.isInitialized) {\n      return {};\n    }\n    return getSessionReplayProperties();\n  }\n}\n"
  },
  {
    "path": "packages/session-replay-react-native/src/session-replay-config.ts",
    "content": "import { LogLevel } from '@amplitude/analytics-types';\n\n/**\n * Masking levels for sensitive content in session replay\n */\nexport enum MaskLevel {\n  /**\n   * Light masking - minimal content is masked\n   */\n  Light = 'light',\n  /**\n   * Medium masking - balanced approach to content masking\n   */\n  Medium = 'medium',\n  /**\n   * Conservative masking - maximum content masking for privacy\n   */\n  Conservative = 'conservative',\n}\n\n/**\n * Configuration for Session Replay React Native SDK\n */\nexport interface SessionReplayConfig {\n  /**\n   * Your Amplitude API key\n   * @required\n   */\n  apiKey: string;\n\n  /**\n   * Whether to automatically start recording when the SDK is initialized\n   * @default true\n   */\n  autoStart?: boolean;\n\n  /**\n   * Device identifier that matches the device ID sent with Amplitude events\n   * Must match the Device ID passed as event properties to Amplitude\n   * @default null\n   */\n  deviceId?: string | null;\n\n  /**\n   * Whether to enable remote configuration\n   * @default true\n   */\n  enableRemoteConfig?: boolean;\n\n  /**\n   * Log level for the SDK\n   * @default LogLevel.Warn\n   */\n  logLevel?: LogLevel;\n\n  /**\n   * Level of masking applied to sensitive content\n   * @default MaskLevel.Medium\n   */\n  maskLevel?: MaskLevel;\n\n  /**\n   * Whether to opt out of session replay collection\n   * @default false\n   */\n  optOut?: boolean;\n\n  /**\n   * Sample rate for session replay (0.0 to 1.0)\n   * Determines what percentage of sessions will be recorded\n   * @default 0\n   */\n  sampleRate?: number;\n\n  /**\n   * Server zone for data processing\n   * @default 'US'\n   * @review: Verify EU server zone compliance and data residency requirements\n   */\n  serverZone?: 'EU' | 'US';\n\n  /**\n   * Session identifier that matches the session ID sent with Amplitude events\n   * Must match the Session ID passed as event properties to Amplitude\n   * @default -1\n   */\n  sessionId?: number;\n}\n\nexport const getDefaultConfig: () => Required<Omit<SessionReplayConfig, 'apiKey'>> = () => {\n  return {\n    autoStart: true,\n    deviceId: null,\n    enableRemoteConfig: true,\n    logLevel: LogLevel.Warn,\n    maskLevel: MaskLevel.Medium,\n    optOut: false,\n    sampleRate: 0,\n    serverZone: 'US',\n    sessionId: -1,\n  };\n};\nexport { LogLevel };\n"
  },
  {
    "path": "packages/session-replay-react-native/src/session-replay.ts",
    "content": "// @refresh reset\n\nimport { NativeSessionReplay, type NativeSessionReplayConfig } from './native-module';\nimport { getDefaultConfig, SessionReplayConfig } from './session-replay-config';\nimport { createSessionReplayLogger } from './logger';\nimport { VERSION } from './version';\n\nlet fullConfig: Required<SessionReplayConfig> | null = null;\nlet isInitialized = false;\nlet logger = createSessionReplayLogger();\n\n/**\n * Configure the SDK and begin collecting replays.\n * This function must be called before any other session replay operations.\n *\n * @param config - Configuration object containing API key, device ID, session ID, and other options\n * @returns Promise that resolves when initialization is complete\n * @throws Error if initialization fails\n *\n * @example\n * ```typescript\n * await init({\n *   apiKey: 'YOUR_API_KEY',\n *   deviceId: 'user-device-id',\n *   sessionId: Date.now(),\n *   sampleRate: 0.1\n * });\n * ```\n */\nexport async function init(config: SessionReplayConfig): Promise<void> {\n  if (isInitialized) {\n    logger.warn('SessionReplay is already initialized');\n    return;\n  }\n\n  fullConfig = {\n    ...getDefaultConfig(),\n    ...config,\n  };\n\n  logger.setLogLevel(fullConfig.logLevel);\n  logger.log(`initializing @amplitude/session-replay-react-native version: ${VERSION} with config: `, fullConfig);\n\n  try {\n    await NativeSessionReplay.setup(nativeConfig(fullConfig));\n    logger.log('SessionReplay initialized');\n    isInitialized = true;\n  } catch (error) {\n    logger.error('Error initializing SessionReplay', error);\n  }\n}\n\n/**\n * Call whenever the session ID changes.\n * The Session ID you pass to the SDK must match the Session ID sent as event properties to Amplitude.\n *\n * @param sessionId - The new session identifier number\n * @returns Promise that resolves when the session ID is updated\n *\n * @example\n * ```typescript\n * await setSessionId(Date.now());\n * ```\n */\nexport async function setSessionId(sessionId: number): Promise<void> {\n  if (!isInitialized) {\n    logger.warn('SessionReplay is not initialized');\n    return;\n  }\n  await NativeSessionReplay.setSessionId(sessionId);\n}\n\n/**\n * Update the device ID used for session replay tracking.\n * The Device ID you pass to the SDK must match the Device ID sent as event properties to Amplitude.\n *\n * @param deviceId - The device identifier string, or null to clear the device ID\n * @returns Promise that resolves when the device ID is updated\n *\n * @example\n * ```typescript\n * await setDeviceId('user-device-id');\n * // or clear device ID\n * await setDeviceId(null);\n * ```\n */\nexport async function setDeviceId(deviceId: string | null): Promise<void> {\n  if (!isInitialized) {\n    logger.warn('SessionReplay is not initialized');\n    return;\n  }\n  await NativeSessionReplay.setDeviceId(deviceId);\n}\n\n/**\n * Get the current session identifier from the session replay SDK.\n *\n * @returns Promise that resolves to the current session ID number, or null if not initialized\n *\n * @example\n * ```typescript\n * const sessionId = await getSessionId();\n * if (sessionId !== null) {\n *   console.log('Current session ID:', sessionId);\n * }\n * ```\n */\nexport async function getSessionId(): Promise<number | null> {\n  if (!isInitialized) {\n    logger.warn('SessionReplay is not initialized');\n    return null;\n  }\n  return await NativeSessionReplay.getSessionId();\n}\n\n/**\n * Interface for session replay properties that should be attached to Amplitude events.\n * These properties help correlate events with session recordings.\n */\nexport interface SessionReplayProperties {\n  [key: string]: string | boolean | null;\n}\n\n/**\n * When you send events to Amplitude, call this function to get the most up-to-date session replay properties for the event.\n * Collect Session Replay properties to send with other event properties.\n *\n * @returns Promise that resolves to an object containing session replay metadata\n *\n * @example\n * ```typescript\n * const sessionReplayProperties = await getSessionReplayProperties();\n * analytics.track('Button Clicked', {\n *   buttonName: 'submit',\n *   ...sessionReplayProperties // Merge session replay properties\n * });\n * ```\n */\nexport async function getSessionReplayProperties(): Promise<SessionReplayProperties> {\n  if (!isInitialized) {\n    logger.warn('SessionReplay is not initialized');\n    return {};\n  }\n  const properties = await NativeSessionReplay.getSessionReplayProperties();\n  return properties as SessionReplayProperties;\n}\n\n/**\n * Flush any pending session replay data to the server.\n * Forces immediate upload of recorded session data that may be buffered locally.\n *\n * @returns Promise that resolves when the flush operation is complete\n *\n * @example\n * ```typescript\n * // Flush data before app termination\n * await flush();\n * ```\n */\nexport async function flush(): Promise<void> {\n  if (!isInitialized) {\n    logger.warn('SessionReplay is not initialized');\n    return;\n  }\n  await NativeSessionReplay.flush();\n}\n\n/**\n * Start session replay recording.\n * Begins capturing user interactions and screen content for replay.\n * If autoStart is enabled in the configuration, this is called automatically during initialization.\n *\n * @returns Promise that resolves when recording starts\n *\n * @example\n * ```typescript\n * // Start recording manually if autoStart is false\n * await start();\n * ```\n */\nexport async function start(): Promise<void> {\n  if (!isInitialized) {\n    logger.warn('SessionReplay is not initialized');\n    return;\n  }\n  await NativeSessionReplay.start();\n}\n\n/**\n * Stop session replay recording.\n * Ends the current recording session and processes any captured data.\n *\n * @returns Promise that resolves when recording stops\n *\n * @example\n * ```typescript\n * // Stop recording when user logs out or app goes to background\n * await stop();\n * ```\n */\nexport async function stop(): Promise<void> {\n  if (!isInitialized) {\n    logger.warn('SessionReplay is not initialized');\n    return;\n  }\n  await NativeSessionReplay.stop();\n}\n\nfunction nativeConfig(config: Required<SessionReplayConfig>): NativeSessionReplayConfig {\n  return {\n    ...config,\n    logLevel: config.logLevel as NativeSessionReplayConfig['logLevel'],\n    maskLevel: config.maskLevel.toString() as NativeSessionReplayConfig['maskLevel'],\n  };\n}\n\nexport async function privateInit(\n  config: SessionReplayConfig,\n  newLogger: ReturnType<typeof createSessionReplayLogger>,\n): Promise<void> {\n  logger = newLogger;\n  return init(config);\n}\n"
  },
  {
    "path": "packages/session-replay-react-native/src/version.ts",
    "content": "// Autogenerated by `yarn version-file`. DO NOT EDIT\nexport const VERSION = '0.0.1-beta.3';\n"
  },
  {
    "path": "packages/session-replay-react-native/test/__mocks__/react-native.ts",
    "content": "// __mocks__/react-native.ts\nexport const NativeModules = {\n  AMPNativeSessionReplay: {\n    setup: jest.fn().mockResolvedValue(undefined),\n    start: jest.fn().mockResolvedValue(undefined),\n    stop: jest.fn().mockResolvedValue(undefined),\n    flush: jest.fn().mockResolvedValue(undefined),\n    getSessionId: jest.fn().mockResolvedValue(12345),\n    getSessionReplayProperties: jest.fn().mockResolvedValue({ replayId: 'test-id' }),\n    setDeviceId: jest.fn().mockResolvedValue(undefined),\n    setSessionId: jest.fn().mockResolvedValue(undefined),\n  },\n};\n\nexport const Platform = {\n  OS: 'ios' as 'ios' | 'android',\n  select: jest.fn((options: { ios?: string; android?: string; default?: string }) => {\n    return options.ios || options.default || '';\n  }),\n};\n\nexport const requireNativeComponent = jest.fn((_componentName: string) => _componentName);\n"
  },
  {
    "path": "packages/session-replay-react-native/test/index.test.ts",
    "content": "// FIXME: remove these eslint rules\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-unsafe-call */\n/* eslint-disable @typescript-eslint/no-unsafe-return */\n\n// Use the mock from __mocks__ directory\njest.mock('react-native');\n\n// Explicitly mock the logger module using the imported mock\njest.mock('../src/logger', (): any => require('./utils/logger'));\n\nimport {\n  init,\n  setSessionId,\n  getSessionId,\n  getSessionReplayProperties,\n  flush,\n  start,\n  stop,\n  setDeviceId,\n  SessionReplayPlugin,\n  AmpMaskView,\n  type SessionReplayConfig,\n  type SessionReplayPluginConfig,\n  MaskLevel,\n} from '../src/index';\nimport { NativeModules } from 'react-native';\nimport { LogLevel } from '@amplitude/analytics-types';\n\n// Mock the getSessionReplayProperties return value for our tests\nNativeModules.AMPNativeSessionReplay.getSessionReplayProperties.mockResolvedValue({ replayId: 'test-id' });\n\ndescribe('Index Exports', () => {\n  const testConfig: SessionReplayConfig = {\n    apiKey: 'test-api-key',\n    serverZone: 'US',\n    logLevel: LogLevel.Warn,\n  };\n\n  beforeEach(() => {\n    jest.clearAllMocks();\n    jest.resetModules();\n  });\n\n  describe('Function Exports', () => {\n    it('should export init function that initializes session replay', async () => {\n      await init(testConfig);\n      expect(NativeModules.AMPNativeSessionReplay.setup).toHaveBeenCalledWith(\n        expect.objectContaining({\n          apiKey: 'test-api-key',\n          serverZone: 'US',\n          logLevel: LogLevel.Warn,\n        }),\n      );\n    });\n\n    it('should export setSessionId function that updates session ID', async () => {\n      const testSessionId = 54321;\n      await init(testConfig); // Initialize first\n      await setSessionId(testSessionId);\n      expect(NativeModules.AMPNativeSessionReplay.setSessionId).toHaveBeenCalledWith(testSessionId);\n    });\n\n    it('should export getSessionId function that retrieves session ID', async () => {\n      await init(testConfig); // Initialize first\n      const sessionId = await getSessionId();\n      expect(NativeModules.AMPNativeSessionReplay.getSessionId).toHaveBeenCalled();\n      expect(sessionId).toBe(12345);\n    });\n\n    it('should export getSessionReplayProperties function', async () => {\n      await init(testConfig); // Initialize first\n      const properties = await getSessionReplayProperties();\n      expect(NativeModules.AMPNativeSessionReplay.getSessionReplayProperties).toHaveBeenCalled();\n      expect(properties).toEqual({ replayId: 'test-id' });\n    });\n\n    it('should export flush function that flushes session data', async () => {\n      await init(testConfig); // Initialize first\n      await flush();\n      expect(NativeModules.AMPNativeSessionReplay.flush).toHaveBeenCalled();\n    });\n\n    it('should export start function that starts recording', async () => {\n      await init(testConfig); // Initialize first\n      await start();\n      expect(NativeModules.AMPNativeSessionReplay.start).toHaveBeenCalled();\n    });\n\n    it('should export stop function that stops recording', async () => {\n      await init(testConfig); // Initialize first\n      await stop();\n      expect(NativeModules.AMPNativeSessionReplay.stop).toHaveBeenCalled();\n    });\n\n    it('should export setDeviceId function that updates device ID', async () => {\n      const testDeviceId = 'test-device-id';\n      await init(testConfig); // Initialize first\n      await setDeviceId(testDeviceId);\n      expect(NativeModules.AMPNativeSessionReplay.setDeviceId).toHaveBeenCalledWith(testDeviceId);\n    });\n  });\n\n  describe('Class Exports', () => {\n    it('should export SessionReplayPlugin class', () => {\n      const plugin = new SessionReplayPlugin();\n      expect(plugin).toBeInstanceOf(SessionReplayPlugin);\n      expect(plugin.name).toBe('@amplitude/plugin-session-replay-react-native');\n      expect(plugin.type).toBe('enrichment');\n    });\n\n    it('should export AmpMaskView component', () => {\n      expect(AmpMaskView).toBe('AMPMaskComponentView');\n    });\n  });\n\n  describe('Type Exports', () => {\n    it('should export SessionReplayConfig interface', () => {\n      const config: SessionReplayConfig = {\n        apiKey: 'test-api-key',\n        serverZone: 'US',\n        logLevel: LogLevel.Warn,\n        maskLevel: MaskLevel.Medium,\n        autoStart: true,\n        deviceId: 'test-device',\n        enableRemoteConfig: true,\n        optOut: false,\n        sampleRate: 1,\n        sessionId: 12345,\n      };\n      // TypeScript compilation is the test - if it compiles, the interface is correct\n      expect(config).toBeTruthy();\n    });\n\n    it('should export SessionReplayPluginConfig interface', () => {\n      const config: SessionReplayPluginConfig = {\n        sampleRate: 1,\n        enableRemoteConfig: true,\n        logLevel: LogLevel.Warn,\n        autoStart: true,\n      };\n      // TypeScript compilation is the test - if it compiles, the interface is correct\n      expect(config).toBeTruthy();\n    });\n\n    it('should export MaskLevel enum', () => {\n      expect(MaskLevel.Light).toBe('light');\n      expect(MaskLevel.Medium).toBe('medium');\n      expect(MaskLevel.Conservative).toBe('conservative');\n      expect(Object.keys(MaskLevel)).toHaveLength(3);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-react-native/test/logger.test.ts",
    "content": "import { createSessionReplayLogger } from '../src/logger';\nimport { LogLevel } from '@amplitude/analytics-types';\n\ndescribe('Logger', () => {\n  let logger: ReturnType<typeof createSessionReplayLogger>;\n  let consoleSpy: {\n    log: jest.SpyInstance;\n    warn: jest.SpyInstance;\n    error: jest.SpyInstance;\n  };\n\n  beforeEach(() => {\n    // Spy on console methods\n    consoleSpy = {\n      log: jest.spyOn(console, 'log').mockImplementation(() => undefined),\n      warn: jest.spyOn(console, 'warn').mockImplementation(() => undefined),\n      error: jest.spyOn(console, 'error').mockImplementation(() => undefined),\n    };\n\n    logger = createSessionReplayLogger();\n  });\n\n  afterEach(() => {\n    // Restore console methods\n    consoleSpy.log.mockRestore();\n    consoleSpy.warn.mockRestore();\n    consoleSpy.error.mockRestore();\n  });\n\n  describe('createSessionReplayLogger', () => {\n    it('should create a logger instance with default log level', () => {\n      expect(logger).toBeDefined();\n      expect(typeof logger.setLogLevel).toBe('function');\n      expect(typeof logger.log).toBe('function');\n      expect(typeof logger.warn).toBe('function');\n      expect(typeof logger.error).toBe('function');\n      expect(typeof logger.debug).toBe('function');\n    });\n\n    it('should have Warn as default log level', () => {\n      // At Warn level, debug and log should not output\n      logger.debug('debug message');\n      logger.log('log message');\n\n      expect(consoleSpy.log).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('setLogLevel', () => {\n    it('should change the log level', () => {\n      logger.setLogLevel(LogLevel.Debug);\n\n      // Now debug should work\n      logger.debug('debug message');\n      expect(consoleSpy.log).toHaveBeenCalledWith('Amplitude Session Replay [Debug]:', 'debug message');\n    });\n\n    it('should accept different log levels', () => {\n      logger.setLogLevel(LogLevel.Error);\n\n      // Only error should work, warn should not\n      logger.warn('warning message');\n      logger.error('error message');\n\n      expect(consoleSpy.warn).not.toHaveBeenCalled();\n      expect(consoleSpy.error).toHaveBeenCalledWith('Amplitude Session Replay [Error]:', 'error message');\n    });\n  });\n\n  describe('log', () => {\n    it('should log messages when log level is Verbose or lower', () => {\n      logger.setLogLevel(LogLevel.Verbose);\n      logger.log('test message');\n\n      expect(consoleSpy.log).toHaveBeenCalledWith('Amplitude Session Replay [Log]:', 'test message');\n    });\n\n    it('should not log when log level is higher than Verbose', () => {\n      logger.setLogLevel(LogLevel.Warn);\n      logger.log('test message');\n\n      expect(consoleSpy.log).not.toHaveBeenCalled();\n    });\n\n    it('should handle multiple arguments', () => {\n      logger.setLogLevel(LogLevel.Verbose);\n      logger.log('message', 'arg1', 'arg2');\n\n      expect(consoleSpy.log).toHaveBeenCalledWith('Amplitude Session Replay [Log]:', 'message', 'arg1', 'arg2');\n    });\n  });\n\n  describe('warn', () => {\n    it('should warn when log level is Warn or lower', () => {\n      logger.setLogLevel(LogLevel.Warn);\n      logger.warn('warning message');\n\n      expect(consoleSpy.warn).toHaveBeenCalledWith('Amplitude Session Replay [Warn]:', 'warning message');\n    });\n\n    it('should not warn when log level is higher than Warn', () => {\n      logger.setLogLevel(LogLevel.Error);\n      logger.warn('warning message');\n\n      expect(consoleSpy.warn).not.toHaveBeenCalled();\n    });\n\n    it('should handle multiple arguments', () => {\n      logger.setLogLevel(LogLevel.Warn);\n      logger.warn('warning', 'arg1', 'arg2');\n\n      expect(consoleSpy.warn).toHaveBeenCalledWith('Amplitude Session Replay [Warn]:', 'warning', 'arg1', 'arg2');\n    });\n  });\n\n  describe('error', () => {\n    it('should error when log level is Error or lower', () => {\n      logger.setLogLevel(LogLevel.Error);\n      logger.error('error message');\n\n      expect(consoleSpy.error).toHaveBeenCalledWith('Amplitude Session Replay [Error]:', 'error message');\n    });\n\n    it('should not error when log level is higher than Error', () => {\n      logger.setLogLevel(LogLevel.None);\n      logger.error('error message');\n\n      expect(consoleSpy.error).not.toHaveBeenCalled();\n    });\n\n    it('should handle multiple arguments', () => {\n      logger.setLogLevel(LogLevel.Error);\n      logger.error('error', 'arg1', 'arg2');\n\n      expect(consoleSpy.error).toHaveBeenCalledWith('Amplitude Session Replay [Error]:', 'error', 'arg1', 'arg2');\n    });\n\n    it('should handle Error objects', () => {\n      logger.setLogLevel(LogLevel.Error);\n      const testError = new Error('Test error');\n      logger.error('Error occurred:', testError);\n\n      expect(consoleSpy.error).toHaveBeenCalledWith('Amplitude Session Replay [Error]:', 'Error occurred:', testError);\n    });\n  });\n\n  describe('debug', () => {\n    it('should debug when log level is Debug or lower', () => {\n      logger.setLogLevel(LogLevel.Debug);\n      logger.debug('debug message');\n\n      expect(consoleSpy.log).toHaveBeenCalledWith('Amplitude Session Replay [Debug]:', 'debug message');\n    });\n\n    it('should not debug when log level is higher than Debug', () => {\n      logger.setLogLevel(LogLevel.Warn);\n      logger.debug('debug message');\n\n      expect(consoleSpy.log).not.toHaveBeenCalled();\n    });\n\n    it('should handle multiple arguments', () => {\n      logger.setLogLevel(LogLevel.Debug);\n      logger.debug('debug', 'arg1', 'arg2');\n\n      expect(consoleSpy.log).toHaveBeenCalledWith('Amplitude Session Replay [Debug]:', 'debug', 'arg1', 'arg2');\n    });\n  });\n\n  describe('log level hierarchy', () => {\n    it('should respect log level hierarchy', () => {\n      // Test at Debug level - all should work\n      logger.setLogLevel(LogLevel.Debug);\n\n      logger.debug('debug');\n      logger.log('log');\n      logger.warn('warn');\n      logger.error('error');\n\n      expect(consoleSpy.log).toHaveBeenCalledTimes(2); // debug + log\n      expect(consoleSpy.warn).toHaveBeenCalledTimes(1);\n      expect(consoleSpy.error).toHaveBeenCalledTimes(1);\n    });\n\n    it('should respect log level hierarchy at Verbose level', () => {\n      logger.setLogLevel(LogLevel.Verbose);\n\n      logger.debug('debug');\n      logger.log('log');\n      logger.warn('warn');\n      logger.error('error');\n\n      expect(consoleSpy.log).toHaveBeenCalledTimes(1); // only log (debug won't work at Verbose)\n      expect(consoleSpy.warn).toHaveBeenCalledTimes(1);\n      expect(consoleSpy.error).toHaveBeenCalledTimes(1);\n    });\n\n    it('should respect log level hierarchy at Warn level', () => {\n      logger.setLogLevel(LogLevel.Warn);\n\n      logger.debug('debug');\n      logger.log('log');\n      logger.warn('warn');\n      logger.error('error');\n\n      expect(consoleSpy.log).not.toHaveBeenCalled();\n      expect(consoleSpy.warn).toHaveBeenCalledTimes(1);\n      expect(consoleSpy.error).toHaveBeenCalledTimes(1);\n    });\n\n    it('should respect log level hierarchy at Error level', () => {\n      logger.setLogLevel(LogLevel.Error);\n\n      logger.debug('debug');\n      logger.log('log');\n      logger.warn('warn');\n      logger.error('error');\n\n      expect(consoleSpy.log).not.toHaveBeenCalled();\n      expect(consoleSpy.warn).not.toHaveBeenCalled();\n      expect(consoleSpy.error).toHaveBeenCalledTimes(1);\n    });\n\n    it('should respect log level hierarchy at None level', () => {\n      logger.setLogLevel(LogLevel.None);\n\n      logger.debug('debug');\n      logger.log('log');\n      logger.warn('warn');\n      logger.error('error');\n\n      expect(consoleSpy.log).not.toHaveBeenCalled();\n      expect(consoleSpy.warn).not.toHaveBeenCalled();\n      expect(consoleSpy.error).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('prefix formatting', () => {\n    it('should include correct prefix for all log levels', () => {\n      logger.setLogLevel(LogLevel.Debug);\n\n      logger.debug('debug message');\n      logger.log('log message');\n      logger.warn('warn message');\n      logger.error('error message');\n\n      expect(consoleSpy.log).toHaveBeenCalledWith('Amplitude Session Replay [Debug]:', 'debug message');\n      expect(consoleSpy.log).toHaveBeenCalledWith('Amplitude Session Replay [Log]:', 'log message');\n      expect(consoleSpy.warn).toHaveBeenCalledWith('Amplitude Session Replay [Warn]:', 'warn message');\n      expect(consoleSpy.error).toHaveBeenCalledWith('Amplitude Session Replay [Error]:', 'error message');\n    });\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-react-native/test/plugin-session-replay.test.ts",
    "content": "// FIXME: remove these eslint rules\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-unsafe-call */\n/* eslint-disable @typescript-eslint/no-unsafe-return */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-var-requires */\n\n// Use the mock from __mocks__ directory\njest.mock('react-native');\n\n// Explicitly mock the logger module using the imported mock\njest.mock('../src/logger', () => require('./utils/logger'));\n\nimport type { SessionReplayPluginConfig } from '../src/index';\nimport { LogLevel } from '@amplitude/analytics-types';\nimport type { ReactNativeConfig } from '@amplitude/analytics-types';\nimport mockReactNativeClient from './utils/reactNativeClient';\n\n// Minimal config with all required properties from ReactNativeConfig\nconst minimalConfig: ReactNativeConfig = {\n  apiKey: 'test-api-key',\n  serverZone: 'US',\n  deviceId: 'test-device-id',\n  sessionId: 12345,\n  userId: 'test-user-id',\n  optOut: false,\n  cookieExpiration: 0,\n  cookieSameSite: 'Lax',\n  cookieSecure: false,\n  cookieStorage: undefined as any,\n  cookieUpgrade: false,\n  disableCookies: false,\n  domain: 'test.com',\n  sessionTimeout: 1800000,\n  trackingOptions: {},\n  flushIntervalMillis: 10000,\n  flushMaxRetries: 5,\n  flushQueueSize: 10,\n  logLevel: LogLevel.Warn,\n  loggerProvider: undefined as any,\n  transportProvider: undefined as any,\n  useBatch: false,\n  attribution: undefined,\n  serverUrl: undefined,\n  appVersion: undefined,\n  lastEventTime: undefined,\n  lastEventId: undefined,\n  partnerId: undefined,\n  trackingSessionEvents: undefined,\n  migrateLegacyData: undefined,\n};\n\ndescribe('SessionReplayPlugin Integration', () => {\n  let SessionReplayPlugin: typeof import('../src/plugin-session-replay').SessionReplayPlugin;\n  let NativeModules: typeof import('react-native').NativeModules;\n\n  beforeEach(() => {\n    jest.resetModules();\n    // Re-import after resetting modules to clear module-level state and reapply mocks\n    SessionReplayPlugin = require('../src/plugin-session-replay').SessionReplayPlugin;\n    NativeModules = require('react-native').NativeModules;\n    jest.clearAllMocks();\n  });\n\n  it('should instantiate and setup with default config', async () => {\n    const plugin = new SessionReplayPlugin();\n    expect(plugin).toBeInstanceOf(SessionReplayPlugin);\n    expect(plugin.name).toBe('@amplitude/plugin-session-replay-react-native');\n    expect(plugin.type).toBe('enrichment');\n\n    // Setup with default config\n    await plugin.setup(minimalConfig, mockReactNativeClient);\n    expect(NativeModules.AMPNativeSessionReplay.setup).toHaveBeenCalledWith(\n      expect.objectContaining({ apiKey: 'test-api-key', serverZone: 'US' }),\n    );\n  });\n\n  it('should instantiate and setup with custom config', async () => {\n    const config: SessionReplayPluginConfig = {\n      sampleRate: 0.5,\n      enableRemoteConfig: false,\n      logLevel: LogLevel.Debug,\n      autoStart: false,\n    };\n    const plugin = new SessionReplayPlugin(config);\n    await plugin.setup({ ...minimalConfig, serverZone: 'EU' }, mockReactNativeClient);\n    expect(NativeModules.AMPNativeSessionReplay.setup).toHaveBeenCalledWith(\n      expect.objectContaining({ apiKey: 'test-api-key', serverZone: 'EU' }),\n    );\n  });\n\n  it('should call start, stop, and teardown', async () => {\n    const plugin = new SessionReplayPlugin();\n    await plugin.setup(minimalConfig, mockReactNativeClient);\n    await plugin.start();\n    expect(NativeModules.AMPNativeSessionReplay.start).toHaveBeenCalled();\n    await plugin.stop();\n    expect(NativeModules.AMPNativeSessionReplay.stop).toHaveBeenCalled();\n    await plugin.teardown();\n    // teardown should call stop again (idempotent)\n    expect(NativeModules.AMPNativeSessionReplay.stop).toHaveBeenCalledTimes(2);\n  });\n\n  it('should call getSessionReplayProperties', async () => {\n    const plugin = new SessionReplayPlugin();\n    await plugin.setup(minimalConfig, mockReactNativeClient);\n    const props = await plugin.getSessionReplayProperties();\n    expect(NativeModules.AMPNativeSessionReplay.getSessionReplayProperties).toHaveBeenCalled();\n    expect(props).toEqual({ replayId: 'test-id' });\n  });\n\n  it('should execute and enrich event if initialized', async () => {\n    const plugin = new SessionReplayPlugin();\n    await plugin.setup(minimalConfig, mockReactNativeClient);\n    const event = { event_type: 'test_event', event_properties: {} };\n    const enriched = await plugin.execute(event);\n    expect(enriched).toEqual(event); // Should return the same event (enrichment is a no-op in mock)\n  });\n\n  it('should not enrich event if not initialized', async () => {\n    const plugin = new SessionReplayPlugin();\n    await plugin.setup(minimalConfig, mockReactNativeClient);\n    const event = { event_type: 'test_event', event_properties: {} };\n    const enriched = await plugin.execute(event);\n    expect(enriched).toEqual(event); // Should return the same event\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-react-native/test/session-replay.test.ts",
    "content": "// FIXME: remove these eslint rules\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-unsafe-call */\n/* eslint-disable @typescript-eslint/no-unsafe-return */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n\n// Use the mock from __mocks__ directory\njest.mock('react-native');\n\n// Explicitly mock the logger module using the imported mock\njest.mock('../src/logger', () => require('./utils/logger'));\n\nimport { init, start, stop, getSessionId, getSessionReplayProperties, type SessionReplayConfig } from '../src/index';\nimport { NativeModules } from 'react-native';\nimport { LogLevel } from '@amplitude/analytics-types';\n\n// Mock the getSessionReplayProperties return value for our tests\nconst mockNativeModules = NativeModules as jest.Mocked<typeof NativeModules>;\nmockNativeModules.AMPNativeSessionReplay.getSessionReplayProperties.mockResolvedValue({ replayId: 'test-id' });\n\ndescribe('Session Replay Integration Tests', () => {\n  beforeEach(() => {\n    jest.clearAllMocks();\n    jest.resetModules();\n  });\n\n  it('should allow complete workflow using exported functions', async () => {\n    const testConfig: SessionReplayConfig = {\n      apiKey: 'test-api-key',\n      serverZone: 'US',\n      logLevel: LogLevel.Warn,\n    };\n\n    // Complete workflow test\n    await init(testConfig);\n    expect(mockNativeModules.AMPNativeSessionReplay.setup).toHaveBeenCalledWith(\n      expect.objectContaining({\n        apiKey: 'test-api-key',\n        serverZone: 'US',\n        logLevel: LogLevel.Warn,\n      }),\n    );\n\n    await start();\n    expect(mockNativeModules.AMPNativeSessionReplay.start).toHaveBeenCalled();\n\n    const sessionId = await getSessionId();\n    expect(sessionId).toBe(12345);\n    expect(mockNativeModules.AMPNativeSessionReplay.getSessionId).toHaveBeenCalled();\n\n    const properties = await getSessionReplayProperties();\n    expect(properties).toEqual({ replayId: 'test-id' });\n    expect(mockNativeModules.AMPNativeSessionReplay.getSessionReplayProperties).toHaveBeenCalled();\n\n    await stop();\n    expect(mockNativeModules.AMPNativeSessionReplay.stop).toHaveBeenCalled();\n\n    // Verify calls were made in sequence\n    const calls = jest.mocked(mockNativeModules.AMPNativeSessionReplay);\n    expect(calls.setup).toHaveBeenCalled();\n    expect(calls.start).toHaveBeenCalled();\n    expect(calls.getSessionId).toHaveBeenCalled();\n    expect(calls.getSessionReplayProperties).toHaveBeenCalled();\n    expect(calls.stop).toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "packages/session-replay-react-native/test/tsconfig.json",
    "content": "{\n    \"extends\": \"../tsconfig.json\",\n    \"compilerOptions\": {\n      \"types\": [\"jest\", \"node\"]\n    }\n  }\n  "
  },
  {
    "path": "packages/session-replay-react-native/test/utils/logger.ts",
    "content": "// __mocks__/logger.ts\n\n// Create mock functions for each log level\nconst mockDebug = jest.fn();\nconst mockWarn = jest.fn();\nconst mockError = jest.fn();\nconst mockLog = jest.fn();\nconst mockSetLogLevel = jest.fn();\n\nconst mockLogger = {\n  debug: mockDebug,\n  log: mockLog,\n  warn: mockWarn,\n  error: mockError,\n  setLogLevel: mockSetLogLevel,\n};\n\nexport const createSessionReplayLogger = jest.fn(() => {\n  return mockLogger;\n});\n"
  },
  {
    "path": "packages/session-replay-react-native/test/utils/reactNativeClient.ts",
    "content": "import type { ReactNativeClient } from '@amplitude/analytics-types';\n\nconst mockReactNativeClient: ReactNativeClient = {\n  init: jest.fn(),\n  add: jest.fn(),\n  remove: jest.fn(),\n  track: jest.fn(),\n  logEvent: jest.fn(),\n  identify: jest.fn(),\n  groupIdentify: jest.fn(),\n  setGroup: jest.fn(),\n  revenue: jest.fn(),\n  flush: jest.fn(),\n  getUserId: jest.fn(),\n  setUserId: jest.fn(),\n  getDeviceId: jest.fn(),\n  setDeviceId: jest.fn(),\n  reset: jest.fn(),\n  getSessionId: jest.fn(),\n  setSessionId: jest.fn(),\n  extendSession: jest.fn(),\n  setOptOut: jest.fn(),\n};\n\nexport default mockReactNativeClient;\n"
  },
  {
    "path": "packages/session-replay-react-native/tsconfig.build.json",
    "content": "{\n  \"extends\": \"./tsconfig\",\n  \"exclude\": [\"test\", \"example\", \"lib\"]\n}\n"
  },
  {
    "path": "packages/session-replay-react-native/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"paths\": {\n      \"@amplitude/session-replay-react-native\": [\"./src/index\"]\n    },\n    \"allowUnreachableCode\": false,\n    \"allowUnusedLabels\": false,\n    \"esModuleInterop\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"jsx\": \"react\",\n    \"lib\": [\"esnext\", \"dom\"],\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"noStrictGenericChecks\": false,\n    \"skipLibCheck\": true,\n    \"target\": \"es6\"\n  }\n}\n"
  },
  {
    "path": "packages/targeting/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# [0.2.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/targeting@0.1.1...@amplitude/targeting@0.2.0) (2024-07-01)\n\n### Features\n\n- **targeting:** add support for multiple events in targeting evaluation\n  ([fbe083e](https://github.com/amplitude/Amplitude-TypeScript/commit/fbe083e3782f07805b7f146778de663899b1afbd))\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [0.1.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/targeting@0.1.0...@amplitude/targeting@0.1.1) (2024-05-28)\n\n**Note:** Version bump only for package @amplitude/targeting\n\n# Change Log\n\nAll notable changes to this project will be documented in this file. See\n[Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n# 0.1.0 (2024-04-08)\n\n### Features\n\n- **targeting:** allow for bucketing on session id\n  ([288e95f](https://github.com/amplitude/Amplitude-TypeScript/commit/288e95f2fd24ed654567d40cf75e847fa5973351))\n- **targeting:** introduce new package for targeting\n  ([0da1316](https://github.com/amplitude/Amplitude-TypeScript/commit/0da131638fbd7b92386eb2897a8b689b09a7a22f))\n\n# Change Log\n"
  },
  {
    "path": "packages/targeting/README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://amplitude.com\" target=\"_blank\" align=\"center\">\n    <img src=\"https://static.amplitude.com/lightning/46c85bfd91905de8047f1ee65c7c93d6fa9ee6ea/static/media/amplitude-logo-with-text.4fb9e463.svg\" width=\"280\">\n  </a>\n  <br />\n</p>\n\n# @amplitude/targeting\n\nInternal Node package for Amplitude"
  },
  {
    "path": "packages/targeting/jest.config.js",
    "content": "const baseConfig = require('../../jest.config.js');\nconst package = require('./package');\n\nmodule.exports = {\n  ...baseConfig,\n  displayName: package.name,\n  rootDir: '.',\n  testEnvironment: 'jsdom',\n  coveragePathIgnorePatterns: ['index.ts'],\n  setupFilesAfterEnv: ['./test/jest-setup.js'],\n};\n"
  },
  {
    "path": "packages/targeting/package.json",
    "content": "{\n  \"name\": \"@amplitude/targeting\",\n  \"version\": \"0.2.0\",\n  \"description\": \"\",\n  \"author\": \"Amplitude Inc\",\n  \"homepage\": \"https://github.com/amplitude/Amplitude-TypeScript\",\n  \"license\": \"MIT\",\n  \"main\": \"lib/cjs/index.js\",\n  \"module\": \"lib/esm/index.js\",\n  \"types\": \"lib/esm/index.d.ts\",\n  \"sideEffects\": false,\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/amplitude/Amplitude-TypeScript.git\"\n  },\n  \"private\": true,\n  \"scripts\": {\n    \"build\": \"pnpm bundle && pnpm build:es5 && pnpm build:esm\",\n    \"bundle\": \"rollup --config rollup.config.js\",\n    \"build:es5\": \"tsc -p ./tsconfig.es5.json\",\n    \"build:esm\": \"tsc -p ./tsconfig.esm.json\",\n    \"clean\": \"rimraf node_modules lib coverage\",\n    \"fix\": \"pnpm fix:eslint & pnpm fix:prettier\",\n    \"fix:eslint\": \"eslint '{src,test}/**/*.ts' --fix\",\n    \"fix:prettier\": \"prettier --write \\\"{src,test}/**/*.ts\\\"\",\n    \"lint\": \"pnpm lint:eslint & pnpm lint:prettier\",\n    \"lint:eslint\": \"eslint '{src,test}/**/*.ts'\",\n    \"lint:prettier\": \"prettier --check \\\"{src,test}/**/*.ts\\\"\",\n    \"publish\": \"node ../../scripts/publish/upload-to-s3.js\",\n    \"test\": \"jest\",\n    \"typecheck\": \"tsc -p ./tsconfig.json\",\n    \"version\": \"pnpm version-file && pnpm build\",\n    \"version-file\": \"node -p \\\"'export const VERSION = \\\\'' + require('./package.json').version + '\\\\';'\\\" > src/version.ts\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/amplitude/Amplitude-TypeScript/issues\"\n  },\n  \"dependencies\": {\n    \"@amplitude/analytics-client-common\": \"workspace:*\",\n    \"@amplitude/analytics-core\": \"workspace:*\",\n    \"@amplitude/analytics-types\": \"workspace:*\",\n    \"@amplitude/experiment-core\": \"0.7.2\",\n    \"idb\": \"8.0.0\",\n    \"tslib\": \"^2.4.1\"\n  },\n  \"devDependencies\": {\n    \"@aws-sdk/client-s3\": \"^3.229.0\",\n    \"@rollup/plugin-commonjs\": \"^23.0.4\",\n    \"@rollup/plugin-node-resolve\": \"^15.0.1\",\n    \"@rollup/plugin-typescript\": \"^10.0.1\",\n    \"@types/core-js\": \"^2.5.8\",\n    \"fake-indexeddb\": \"4.0.2\",\n    \"rollup\": \"^2.79.1\",\n    \"rollup-plugin-execute\": \"^1.1.1\",\n    \"rollup-plugin-gzip\": \"^3.1.0\",\n    \"rollup-plugin-sourcemaps\": \"^0.6.3\",\n    \"rollup-plugin-terser\": \"^7.0.2\"\n  },\n  \"files\": [\n    \"lib\"\n  ]\n}\n"
  },
  {
    "path": "packages/targeting/rollup.config.js",
    "content": "import { iife, umd } from '../../scripts/build/rollup.config';\n\niife.input = umd.input;\niife.output.name = 'targeting';\n\nexport default [umd, iife];\n"
  },
  {
    "path": "packages/targeting/src/index.ts",
    "content": "import targeting from './targeting-factory';\nexport const { evaluateTargeting } = targeting;\nexport { TargetingFlag, TargetingParameters } from './typings/targeting';\n"
  },
  {
    "path": "packages/targeting/src/targeting-factory.ts",
    "content": "import { Targeting } from './targeting';\nimport { Targeting as AmplitudeTargeting } from './typings/targeting';\n\nconst createInstance: () => AmplitudeTargeting = () => {\n  const targeting = new Targeting();\n  return {\n    evaluateTargeting: targeting.evaluateTargeting.bind(targeting),\n  };\n};\n\nexport default createInstance();\n"
  },
  {
    "path": "packages/targeting/src/targeting-idb-store.ts",
    "content": "import { Logger as ILogger } from '@amplitude/analytics-types';\nimport { DBSchema, IDBPDatabase, IDBPTransaction, openDB } from 'idb';\n\nexport const MAX_IDB_STORAGE_LENGTH = 1000 * 60 * 60 * 24 * 2; // 2 days\n\n// This type is constructed to allow for future proofing - in the future we may want\n// to track how many of each event is fired, and we may want to track event properties\n// Any further fields, like event properties, can be added to this type without causing\n// a breaking change\ntype EventData = { event_type: string };\n\ntype EventTypeStore = { [event_type: string]: { [timestamp: number]: EventData } };\n\nexport interface TargetingDB extends DBSchema {\n  eventTypesForSession: {\n    key: string;\n    value: {\n      sessionId: string;\n      eventTypes: EventTypeStore;\n      lastUpdated: number;\n    };\n  };\n}\n\nexport class TargetingIDBStore {\n  dbs: { [apiKey: string]: IDBPDatabase<TargetingDB> } = {};\n\n  createStore = async (dbName: string) => {\n    return await openDB<TargetingDB>(dbName, 1, {\n      upgrade: (db: IDBPDatabase<TargetingDB>) => {\n        if (!db.objectStoreNames.contains('eventTypesForSession')) {\n          db.createObjectStore('eventTypesForSession', {\n            keyPath: 'sessionId',\n          });\n        }\n      },\n    });\n  };\n\n  openOrCreateDB = async (apiKey: string) => {\n    if (this.dbs && this.dbs[apiKey]) {\n      return this.dbs[apiKey];\n    }\n    const dbName = `${apiKey.substring(0, 10)}_amp_targeting`;\n    const db = await this.createStore(dbName);\n    this.dbs[apiKey] = db;\n\n    return db;\n  };\n\n  updateEventListForSession = async ({\n    sessionId,\n    eventType,\n    eventTime,\n    loggerProvider,\n    tx,\n  }: {\n    sessionId: string | number;\n    eventType: string;\n    eventTime: number;\n    loggerProvider: ILogger;\n    tx: IDBPTransaction<TargetingDB, ['eventTypesForSession'], 'readwrite'>;\n  }) => {\n    try {\n      const sessionIdStr = String(sessionId);\n      const sessionData = await tx.store.get(sessionIdStr);\n      const eventTypes = sessionData ? sessionData.eventTypes : {};\n      const eventTypeStore = eventTypes[eventType] || {};\n\n      const updatedEventTypes: EventTypeStore = {\n        ...eventTypes,\n        [eventType]: {\n          ...eventTypeStore,\n          [eventTime]: { event_type: eventType },\n        },\n      };\n\n      const updatedSessionData = {\n        sessionId: sessionIdStr,\n        eventTypes: updatedEventTypes,\n        lastUpdated: Date.now(),\n      };\n\n      await tx.store.put(updatedSessionData);\n      return updatedEventTypes;\n    } catch (e) {\n      loggerProvider.warn(`Failed to store events for targeting ${sessionId}: ${e as string}`);\n    }\n    return undefined;\n  };\n\n  deleteOldSessionEventTypes = async ({\n    currentSessionId,\n    loggerProvider,\n    tx,\n  }: {\n    currentSessionId: string | number;\n    loggerProvider: ILogger;\n    tx: IDBPTransaction<TargetingDB, ['eventTypesForSession'], 'readwrite'>;\n  }) => {\n    try {\n      const currentSessionIdStr = String(currentSessionId);\n      const allSessions = await tx.store.getAll();\n      for (let i = 0; i < allSessions.length; i++) {\n        const session = allSessions[i];\n        const amountOfTimeSinceSession = Date.now() - session.lastUpdated;\n        if (session.sessionId !== currentSessionIdStr && amountOfTimeSinceSession > MAX_IDB_STORAGE_LENGTH) {\n          await tx.store.delete(session.sessionId);\n        }\n      }\n    } catch (e) {\n      loggerProvider.warn(`Failed to clear old session event types for targeting: ${e as string}`);\n    }\n  };\n\n  storeEventTypeForSession = async ({\n    loggerProvider,\n    sessionId,\n    eventType,\n    eventTime,\n    apiKey,\n  }: {\n    loggerProvider: ILogger;\n    apiKey: string;\n    eventType: string;\n    eventTime: number;\n    sessionId: string | number;\n  }) => {\n    try {\n      const db = await this.openOrCreateDB(apiKey);\n\n      const tx = db.transaction<'eventTypesForSession', 'readwrite'>('eventTypesForSession', 'readwrite');\n      if (!tx) {\n        return;\n      }\n\n      // Update the list of events for the session\n      const updatedEventTypes = await this.updateEventListForSession({\n        sessionId,\n        tx,\n        loggerProvider,\n        eventType,\n        eventTime,\n      });\n\n      // Clear out sessions older than 2 days\n      await this.deleteOldSessionEventTypes({ currentSessionId: sessionId, tx, loggerProvider });\n\n      await tx.done;\n\n      return updatedEventTypes;\n    } catch (e) {\n      loggerProvider.warn(`Failed to store events for targeting ${sessionId}: ${e as string}`);\n    }\n    return undefined;\n  };\n}\n\nexport const targetingIDBStore = new TargetingIDBStore();\n"
  },
  {
    "path": "packages/targeting/src/targeting.ts",
    "content": "import { EvaluationEngine } from '@amplitude/experiment-core';\nimport { targetingIDBStore } from './targeting-idb-store';\nimport { Targeting as AmplitudeTargeting, TargetingParameters } from './typings/targeting';\n\nexport class Targeting implements AmplitudeTargeting {\n  evaluationEngine: EvaluationEngine;\n\n  constructor() {\n    this.evaluationEngine = new EvaluationEngine();\n  }\n\n  evaluateTargeting = async ({\n    apiKey,\n    loggerProvider,\n    event,\n    sessionId,\n    userProperties,\n    deviceId,\n    page,\n    flag,\n  }: TargetingParameters) => {\n    const eventTypes =\n      event && event.time\n        ? await targetingIDBStore.storeEventTypeForSession({\n            loggerProvider: loggerProvider,\n            apiKey: apiKey,\n            sessionId,\n            eventType: event.event_type,\n            eventTime: event.time,\n          })\n        : undefined;\n\n    const eventStrings = eventTypes && new Set(Object.keys(eventTypes));\n\n    const context = {\n      session_id: sessionId,\n      event,\n      event_types: eventStrings && Array.from(eventStrings),\n      user: {\n        ...userProperties,\n        device_id: deviceId,\n        user_properties: userProperties,\n      },\n      page: page,\n    };\n    const targetingBucket = this.evaluationEngine.evaluate(context, [flag]);\n    return targetingBucket;\n  };\n}\n"
  },
  {
    "path": "packages/targeting/src/typings/targeting.ts",
    "content": "import { Event, Logger } from '@amplitude/analytics-types';\nimport { EvaluationFlag, EvaluationVariant } from '@amplitude/experiment-core';\n\nexport type TargetingFlag = EvaluationFlag;\n\n/** Page data passed into targeting so the evaluator can use the current URL (or other page data). */\nexport interface TargetingPage {\n  url?: string;\n}\n\nexport interface TargetingParameters {\n  event?: Event;\n  userProperties?: { [key: string]: any };\n  deviceId?: string;\n  /**\n   * Page data (e.g. current page URL) for context in targeting evaluation.\n   * Used to populate context.page in the evaluation engine.\n   */\n  page?: TargetingPage;\n  flag: EvaluationFlag;\n  sessionId: string | number;\n  apiKey: string;\n  loggerProvider: Logger;\n}\n\nexport interface Targeting {\n  evaluateTargeting: (args: TargetingParameters) => Promise<Record<string, EvaluationVariant>>;\n}\n"
  },
  {
    "path": "packages/targeting/test/flag-config-data/catch-all.ts",
    "content": "export const flagCatchAll = {\n  key: 'sr_targeting_config',\n  variants: {\n    on: { key: 'on' },\n    off: { key: 'off' },\n  },\n  segments: [\n    {\n      metadata: { segmentName: 'sign in trigger' },\n      bucket: {\n        selector: ['context', 'session_id'],\n        salt: 'xdfrewd', // Different salt for each bucket to allow for fallthrough\n        allocations: [\n          {\n            range: [0, 19], // Selects 20% of users that match these conditions\n            distributions: [\n              {\n                variant: 'on',\n                range: [0, 42949673],\n              },\n            ],\n          },\n        ],\n      },\n      conditions: [\n        [\n          {\n            selector: ['context', 'event', 'event_type'],\n            op: 'is',\n            values: ['Sign In'],\n          },\n        ],\n      ],\n    },\n    {\n      metadata: { segmentName: 'multiple event trigger' },\n      bucket: {\n        selector: ['context', 'session_id'],\n        salt: 'xdfrewd', // Different salt for each bucket to allow for fallthrough\n        allocations: [\n          {\n            range: [0, 19], // Selects 20% of users that match these conditions\n            distributions: [\n              {\n                variant: 'on',\n                range: [0, 42949673],\n              },\n            ],\n          },\n        ],\n      },\n      conditions: [\n        [\n          {\n            selector: ['context', 'event_types'],\n            op: 'set contains',\n            values: ['Add to Cart', 'Purchase'],\n          },\n        ],\n      ],\n    },\n    {\n      metadata: { segmentName: 'user property' },\n      bucket: {\n        selector: ['context', 'session_id'],\n        salt: 'Rpr5h4vy', // Different salt for each bucket to allow for fallthrough\n        allocations: [\n          {\n            range: [0, 14], // Selects 15% of users that match these conditions\n            distributions: [\n              {\n                variant: 'on',\n                range: [0, 42949673],\n              },\n            ],\n          },\n        ],\n      },\n      conditions: [\n        [\n          {\n            selector: ['context', 'user', 'user_properties', 'country'],\n            op: 'set contains any',\n            values: ['united states'],\n          },\n        ],\n      ],\n    },\n    {\n      metadata: { segmentName: 'leftover allocation' },\n      bucket: {\n        selector: ['context', 'session_id'],\n        salt: 'T5lhyRo', // Different salt for each bucket to allow for fallthrough\n        allocations: [\n          {\n            range: [0, 9], // Selects 10% of users that match these conditions\n            distributions: [\n              {\n                variant: 'on',\n                range: [0, 42949673],\n              },\n            ],\n          },\n        ],\n      },\n    },\n    {\n      variant: 'off',\n    },\n  ],\n};\n"
  },
  {
    "path": "packages/targeting/test/flag-config-data/event-props.ts",
    "content": "import { TargetingFlag } from '../../src/typings/targeting';\n\nexport const flagEventProps: TargetingFlag = {\n  key: 'sr_targeting_config',\n  variants: {\n    off: {\n      key: 'off',\n    },\n    on: {\n      key: 'on',\n    },\n  },\n  segments: [\n    {\n      metadata: {\n        segmentName: 'Segment 1',\n        segmentId: 'uuid1',\n      },\n      bucket: {\n        selector: ['context', 'session_id'],\n        salt: 'sphIslYm',\n        allocations: [\n          {\n            distributions: [\n              {\n                range: [0, 42949673],\n                variant: 'on',\n              },\n            ],\n            range: [0, 51],\n          },\n        ],\n      },\n      conditions: [\n        [\n          {\n            selector: ['context', 'event', 'event_properties', '[Amplitude] Page URL'],\n            op: 'is',\n            values: ['http://localhost:3000/tasks-app'],\n          },\n        ],\n      ],\n    },\n  ],\n};\n"
  },
  {
    "path": "packages/targeting/test/flag-config-data/multiple-conditions.ts",
    "content": "export const flagConfigMultipleConditions = {\n  key: 'sr_targeting_config',\n  variants: {\n    on: { key: 'on' },\n    off: { key: 'off' },\n  },\n  segments: [\n    {\n      metadata: { segmentName: 'multiple condition trigger' },\n      bucket: {\n        selector: ['context', 'session_id'],\n        salt: 'xdfrewd',\n        allocations: [\n          {\n            range: [0, 99],\n            distributions: [\n              {\n                variant: 'on',\n                range: [0, 42949673],\n              },\n            ],\n          },\n        ],\n      },\n      conditions: [\n        [\n          {\n            selector: ['context', 'event', 'event_type'],\n            op: 'is',\n            values: ['Sign In'],\n          },\n        ],\n        [\n          {\n            selector: ['context', 'user', 'user_properties', 'name'],\n            op: 'is',\n            values: ['Banana'],\n          },\n        ],\n      ],\n    },\n    {\n      variant: 'off',\n    },\n  ],\n};\n"
  },
  {
    "path": "packages/targeting/test/flag-config-data/multiple-events.ts",
    "content": "import { TargetingFlag } from '../../src/typings/targeting';\n\nexport const flagConfigMultipleEvents: TargetingFlag = {\n  key: 'sr_targeting_config',\n  variants: {\n    on: { key: 'on' },\n    off: { key: 'off' },\n  },\n  segments: [\n    {\n      metadata: { segmentName: 'multiple event trigger' },\n      bucket: {\n        selector: ['context', 'session_id'],\n        salt: 'xdfrewd',\n        allocations: [\n          {\n            range: [0, 99],\n            distributions: [\n              {\n                variant: 'on',\n                range: [0, 42949673],\n              },\n            ],\n          },\n        ],\n      },\n      conditions: [\n        [\n          {\n            selector: ['context', 'event_types'],\n            op: 'set contains',\n            values: ['Add to Cart', 'Sign In'],\n          },\n        ],\n      ],\n    },\n    {\n      variant: 'off',\n    },\n  ],\n};\n"
  },
  {
    "path": "packages/targeting/test/flag-config-data/user-props.ts",
    "content": "import { TargetingFlag } from '../../src/typings/targeting';\n\nexport const flagUserProps: TargetingFlag = {\n  key: 'sr_targeting_config',\n  variants: {\n    off: {\n      key: 'off',\n    },\n    on: {\n      key: 'on',\n    },\n  },\n  segments: [\n    {\n      metadata: {\n        segmentName: 'Segment 1',\n        segmentId: 'uuid1',\n      },\n      bucket: {\n        selector: ['context', 'session_id'],\n        salt: 'sphIslYm',\n        allocations: [\n          {\n            distributions: [\n              {\n                range: [0, 42949673],\n                variant: 'on',\n              },\n            ],\n            range: [0, 51],\n          },\n        ],\n      },\n      conditions: [\n        [\n          {\n            op: 'contains',\n            selector: ['context', 'user', 'user_properties', 'plan_id'],\n            values: ['paid', 'free'],\n          },\n        ],\n      ],\n    },\n  ],\n};\n"
  },
  {
    "path": "packages/targeting/test/jest-setup.js",
    "content": "require('fake-indexeddb/auto');\nconst { IDBFactory } = require('fake-indexeddb');\nconst structuredClone = require('@ungap/structured-clone');\n\nglobal.structuredClone = structuredClone.default;\nglobal.beforeEach(() => {\n  global.indexedDB = new IDBFactory();\n});\n"
  },
  {
    "path": "packages/targeting/test/targeting-factory.test.ts",
    "content": "import targeting from '../src/targeting-factory';\n\ndescribe('targeting factory', () => {\n  describe('targeting instance', () => {\n    test('return an instance of the targeting class', async () => {\n      expect(Object.keys(targeting)).toEqual(['evaluateTargeting']);\n    });\n  });\n});\n"
  },
  {
    "path": "packages/targeting/test/targeting-idb-store.test.ts",
    "content": "/* eslint-disable @typescript-eslint/unbound-method */\nimport { Logger } from '@amplitude/analytics-types';\nimport { IDBPDatabase } from 'idb';\nimport { TargetingDB, targetingIDBStore } from '../src/targeting-idb-store';\n\ntype MockedLogger = jest.Mocked<Logger>;\n\ntype EventTypesEntry = {\n  eventTypes: Record<string, Record<number | string, { event_type: string }>>;\n  sessionId: string;\n  lastUpdated: number;\n};\n\ntype StoreEventParams = {\n  eventTime: number;\n  eventType: string;\n  sessionId: number | string;\n  apiKey?: string;\n  loggerProvider?: MockedLogger;\n};\n\n// Test constants\nconst TEST_API_KEY = 'static_key';\nconst TEST_EVENT_TIME = 123;\nconst TEST_SESSION_ID = 123;\n\n// Helper function to create a fresh mock logger\nconst createMockLogger = (): MockedLogger => ({\n  error: jest.fn(),\n  log: jest.fn(),\n  disable: jest.fn(),\n  enable: jest.fn(),\n  warn: jest.fn(),\n  debug: jest.fn(),\n});\n\n// Helper function to get all entries from the database\nasync function getAllEntriesTyped(db: IDBPDatabase<TargetingDB>): Promise<EventTypesEntry[]> {\n  const result = await db.getAll('eventTypesForSession');\n  if (Array.isArray(result)) {\n    return result.map((entry) => {\n      // Defensive: only return if entry has the expected shape\n      if (\n        typeof entry === 'object' &&\n        entry !== null &&\n        'eventTypes' in entry &&\n        'sessionId' in entry &&\n        'lastUpdated' in entry\n      ) {\n        return entry as EventTypesEntry;\n      }\n      throw new Error('Unexpected entry shape in getAllEntriesTyped');\n    });\n  }\n  return [];\n}\n\n// Helper function to store an event with default parameters\nconst storeEvent = async (params: Partial<StoreEventParams> = {}): Promise<MockedLogger> => {\n  const logger = createMockLogger();\n  await targetingIDBStore.storeEventTypeForSession({\n    eventTime: params.eventTime ?? TEST_EVENT_TIME,\n    eventType: params.eventType ?? 'Add to Cart',\n    sessionId: params.sessionId ?? TEST_SESSION_ID,\n    apiKey: params.apiKey ?? TEST_API_KEY,\n    loggerProvider: params.loggerProvider ?? logger,\n  });\n  return logger;\n};\n\n// Helper function to create a mock database that throws errors\nconst createMockDBWithError = (errorType: 'transaction' | 'put' | 'getAll'): IDBPDatabase<TargetingDB> => {\n  const mockStore = {\n    put: jest.fn().mockImplementation(() => (errorType === 'put' ? Promise.reject('put error') : Promise.resolve())),\n    getAll: jest\n      .fn()\n      .mockImplementation(() => (errorType === 'getAll' ? Promise.reject('getAll error') : Promise.resolve([]))),\n  };\n\n  const mockTransaction =\n    errorType === 'transaction'\n      ? undefined\n      : {\n          store: mockStore,\n        };\n\n  return {\n    transaction: jest.fn().mockImplementation(() => mockTransaction),\n  } as unknown as IDBPDatabase<TargetingDB>;\n};\n\ndescribe('targeting idb store', () => {\n  let db: IDBPDatabase<TargetingDB>;\n  let mockLogger: MockedLogger;\n  let dateNowSpy: jest.SpyInstance<number, []>;\n\n  beforeEach(async () => {\n    // Create fresh mock logger for each test\n    mockLogger = createMockLogger();\n\n    // Open database and clear it\n    db = await targetingIDBStore.openOrCreateDB(TEST_API_KEY);\n    await db.clear('eventTypesForSession');\n\n    // Reset all mocks\n    jest.clearAllMocks();\n  });\n\n  afterEach(async () => {\n    // Clean up database\n    if (db) {\n      await db.clear('eventTypesForSession');\n    }\n\n    // Restore any mocked timers\n    jest.useRealTimers();\n\n    // Restore Date.now spy if it exists\n    if (dateNowSpy) {\n      dateNowSpy.mockRestore();\n    }\n\n    // Clear all mocks\n    jest.clearAllMocks();\n  });\n\n  afterAll(async () => {\n    // Close database connections\n    if (db) {\n      db.close();\n    }\n  });\n\n  describe('storeEventTypeForSession', () => {\n    test('should add event to stored event list', async () => {\n      await storeEvent({ eventType: 'Add to Cart' });\n      await storeEvent({ eventType: 'Purchase' });\n\n      const allEntries = await getAllEntriesTyped(db);\n      expect(allEntries).toHaveLength(1);\n      expect(allEntries[0]).toMatchObject({\n        eventTypes: {\n          'Add to Cart': { [TEST_EVENT_TIME]: { event_type: 'Add to Cart' } },\n          Purchase: { [TEST_EVENT_TIME]: { event_type: 'Purchase' } },\n        },\n        sessionId: String(TEST_SESSION_ID),\n      });\n      expect(typeof allEntries[0].lastUpdated).toBe('number');\n    });\n\n    test('should handle adding the same event twice correctly', async () => {\n      await storeEvent({ eventType: 'Add to Cart' });\n      await storeEvent({ eventType: 'Add to Cart' });\n\n      const allEntries = await getAllEntriesTyped(db);\n      expect(allEntries).toHaveLength(1);\n      expect(allEntries[0]).toMatchObject({\n        eventTypes: {\n          'Add to Cart': { [TEST_EVENT_TIME]: { event_type: 'Add to Cart' } },\n        },\n        sessionId: String(TEST_SESSION_ID),\n      });\n      expect(typeof allEntries[0].lastUpdated).toBe('number');\n    });\n\n    test('should add the same event with different timestamps', async () => {\n      await storeEvent({ eventType: 'Add to Cart', eventTime: 123 });\n      await storeEvent({ eventType: 'Add to Cart', eventTime: 456 });\n\n      const allEntries = await getAllEntriesTyped(db);\n      expect(allEntries).toHaveLength(1);\n      expect(allEntries[0]).toMatchObject({\n        eventTypes: {\n          'Add to Cart': {\n            123: { event_type: 'Add to Cart' },\n            456: { event_type: 'Add to Cart' },\n          },\n        },\n        sessionId: String(TEST_SESSION_ID),\n      });\n      expect(typeof allEntries[0].lastUpdated).toBe('number');\n    });\n\n    test('should return updated list', async () => {\n      await storeEvent({ eventType: 'Add to Cart' });\n\n      const updatedList = await targetingIDBStore.storeEventTypeForSession({\n        eventTime: TEST_EVENT_TIME,\n        eventType: 'Purchase',\n        sessionId: TEST_SESSION_ID,\n        apiKey: TEST_API_KEY,\n        loggerProvider: mockLogger,\n      });\n\n      expect(updatedList).toEqual({\n        'Add to Cart': { [String(TEST_EVENT_TIME)]: { event_type: 'Add to Cart' } },\n        Purchase: { [String(TEST_EVENT_TIME)]: { event_type: 'Purchase' } },\n      });\n    });\n\n    test('should handle errors in updateEventListForSession', async () => {\n      const updateSpy = jest\n        .spyOn(targetingIDBStore, 'updateEventListForSession')\n        .mockRejectedValueOnce(new Error('update error'));\n\n      await storeEvent({ loggerProvider: mockLogger });\n\n      expect(mockLogger.warn).toHaveBeenCalledWith(expect.stringContaining('Failed to store events for targeting'));\n\n      updateSpy.mockRestore();\n    });\n\n    test('should handle errors on updating event list', async () => {\n      const mockDB = createMockDBWithError('put');\n      const openDBSpy = jest.spyOn(targetingIDBStore, 'openOrCreateDB').mockResolvedValue(mockDB);\n\n      await storeEvent({ loggerProvider: mockLogger });\n\n      expect(mockLogger.warn).toHaveBeenCalledWith(expect.stringContaining('Failed to store events for targeting'));\n\n      openDBSpy.mockRestore();\n    });\n\n    test('should handle undefined transaction', async () => {\n      const mockDB = createMockDBWithError('transaction');\n      const openDBSpy = jest.spyOn(targetingIDBStore, 'openOrCreateDB').mockResolvedValue(mockDB);\n\n      const updatedEventTypes = await targetingIDBStore.storeEventTypeForSession({\n        eventTime: TEST_EVENT_TIME,\n        eventType: 'Add to Cart',\n        sessionId: TEST_SESSION_ID,\n        apiKey: TEST_API_KEY,\n        loggerProvider: mockLogger,\n      });\n\n      expect(updatedEventTypes).toBeUndefined();\n\n      openDBSpy.mockRestore();\n    });\n\n    test('should delete old sessions', async () => {\n      // Set up fake timers\n      const oldSessionTime = new Date('2023-07-25 08:30:00').getTime();\n      jest.useFakeTimers().setSystemTime(oldSessionTime);\n      dateNowSpy = jest.spyOn(Date, 'now');\n\n      // Create old session\n      dateNowSpy.mockReturnValueOnce(oldSessionTime);\n      const oldSessionId = oldSessionTime;\n      await storeEvent({\n        sessionId: oldSessionId,\n        loggerProvider: mockLogger,\n      });\n\n      let allEntries = await getAllEntriesTyped(db);\n      expect(allEntries).toHaveLength(1);\n      expect(allEntries[0]).toMatchObject({\n        eventTypes: { 'Add to Cart': { [TEST_EVENT_TIME]: { event_type: 'Add to Cart' } } },\n        sessionId: String(oldSessionId),\n      });\n      expect(allEntries[0].lastUpdated).toBe(oldSessionTime);\n\n      // Advance time by 6 days (more than 2 days)\n      const newSessionTime = oldSessionTime + 1000 * 60 * 60 * 24 * 6;\n      jest.setSystemTime(newSessionTime);\n      dateNowSpy.mockReturnValueOnce(newSessionTime);\n\n      const newSessionId = new Date('2023-07-31 07:30:00').getTime();\n      await storeEvent({\n        sessionId: newSessionId,\n        loggerProvider: mockLogger,\n      });\n\n      allEntries = await getAllEntriesTyped(db);\n      expect(allEntries).toHaveLength(1);\n      expect(allEntries[0]).toMatchObject({\n        eventTypes: { 'Add to Cart': { [TEST_EVENT_TIME]: { event_type: 'Add to Cart' } } },\n        sessionId: String(newSessionId),\n      });\n      expect(allEntries[0].lastUpdated).toBe(newSessionTime);\n    });\n\n    test('should log error if deleteOldSessionEventTypes throws', async () => {\n      const txUnknown: unknown = {\n        store: {\n          getAll: jest.fn().mockImplementation(() => {\n            throw new Error('getAll error');\n          }),\n          delete: jest.fn(),\n        },\n      };\n      const tx = txUnknown as Parameters<typeof targetingIDBStore.deleteOldSessionEventTypes>[0]['tx'];\n\n      await targetingIDBStore.deleteOldSessionEventTypes({\n        currentSessionId: '1',\n        loggerProvider: mockLogger,\n        tx,\n      });\n\n      expect(mockLogger.warn).toHaveBeenCalledWith(\n        expect.stringContaining('Failed to clear old session event types for targeting:'),\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "packages/targeting/test/targeting.test.ts",
    "content": "import { Logger } from '@amplitude/analytics-types';\nimport { Targeting } from '../src/targeting';\nimport { targetingIDBStore } from '../src/targeting-idb-store';\nimport { flagCatchAll } from './flag-config-data/catch-all';\nimport { flagEventProps } from './flag-config-data/event-props';\nimport { flagConfigMultipleConditions } from './flag-config-data/multiple-conditions';\nimport { flagConfigMultipleEvents } from './flag-config-data/multiple-events';\nimport { flagUserProps } from './flag-config-data/user-props';\n\ntype MockedLogger = jest.Mocked<Logger>;\nconst mockEvent = {\n  event_type: 'sign_in',\n  time: 123,\n};\nconst mockUserProperties = {};\n\nconst mockLoggerProvider: MockedLogger = {\n  error: jest.fn(),\n  log: jest.fn(),\n  disable: jest.fn(),\n  enable: jest.fn(),\n  warn: jest.fn(),\n  debug: jest.fn(),\n};\ndescribe('targeting', () => {\n  describe('evaluateTargeting', () => {\n    test('should call evaluation engine evaluate', async () => {\n      const targeting = new Targeting();\n      const mockEngineEvaluate = jest.fn();\n      targeting.evaluationEngine.evaluate = mockEngineEvaluate;\n      await targeting.evaluateTargeting({\n        deviceId: '1a2b3c',\n        userProperties: mockUserProperties,\n        flag: flagCatchAll,\n        sessionId: 123,\n        apiKey: 'static_key',\n        loggerProvider: mockLoggerProvider,\n      });\n      expect(mockEngineEvaluate).toHaveBeenCalledWith(\n        {\n          user: {\n            device_id: '1a2b3c',\n            user_properties: mockUserProperties,\n          },\n          session_id: 123,\n          event_types: undefined,\n        },\n        [flagCatchAll],\n      );\n    });\n    test('should pass a list of event types to the evaluation engine evaluate', async () => {\n      jest.spyOn(targetingIDBStore, 'storeEventTypeForSession').mockResolvedValueOnce({\n        'Add to Cart': { 123: { event_type: 'Add to Cart' } },\n        Purchase: { 123: { event_type: 'Purchase' } },\n      });\n      const targeting = new Targeting();\n      const mockEngineEvaluate = jest.fn();\n      targeting.evaluationEngine.evaluate = mockEngineEvaluate;\n      await targeting.evaluateTargeting({\n        deviceId: '1a2b3c',\n        event: mockEvent,\n        userProperties: mockUserProperties,\n        flag: flagCatchAll,\n        sessionId: 123,\n        apiKey: 'static_key',\n        loggerProvider: mockLoggerProvider,\n      });\n      expect(mockEngineEvaluate).toHaveBeenCalledWith(\n        {\n          event: mockEvent,\n          user: {\n            device_id: '1a2b3c',\n            user_properties: mockUserProperties,\n          },\n          session_id: 123,\n          event_types: ['Add to Cart', 'Purchase'],\n        },\n        [flagCatchAll],\n      );\n    });\n\n    test('should pass page to the evaluation engine when provided', async () => {\n      const targeting = new Targeting();\n      const mockEngineEvaluate = jest.fn();\n      targeting.evaluationEngine.evaluate = mockEngineEvaluate;\n      const page = { url: 'https://example.com/analytics/dashboard' };\n      await targeting.evaluateTargeting({\n        deviceId: '1a2b3c',\n        userProperties: mockUserProperties,\n        flag: flagCatchAll,\n        sessionId: 123,\n        apiKey: 'static_key',\n        loggerProvider: mockLoggerProvider,\n        page,\n      });\n      expect(mockEngineEvaluate).toHaveBeenCalledWith(\n        expect.objectContaining({\n          page,\n          user: {\n            device_id: '1a2b3c',\n            user_properties: mockUserProperties,\n          },\n          session_id: 123,\n        }),\n        [flagCatchAll],\n      );\n    });\n\n    test('should flatten user properties onto context.user for targeting selectors', async () => {\n      const targeting = new Targeting();\n      const mockEngineEvaluate = jest.fn();\n      targeting.evaluationEngine.evaluate = mockEngineEvaluate;\n      const userProperties = {\n        country: 'Canada',\n        subscription_tier: 'paid',\n      };\n\n      await targeting.evaluateTargeting({\n        deviceId: '1a2b3c',\n        userProperties,\n        flag: flagCatchAll,\n        sessionId: 123,\n        apiKey: 'static_key',\n        loggerProvider: mockLoggerProvider,\n      });\n\n      expect(mockEngineEvaluate).toHaveBeenCalledWith(\n        expect.objectContaining({\n          user: expect.objectContaining({\n            device_id: '1a2b3c',\n            user_properties: userProperties,\n            country: 'Canada',\n            subscription_tier: 'paid',\n          }),\n        }),\n        [flagCatchAll],\n      );\n    });\n\n    test('should not allow user properties to overwrite internal user context fields', async () => {\n      const targeting = new Targeting();\n      const mockEngineEvaluate = jest.fn();\n      targeting.evaluationEngine.evaluate = mockEngineEvaluate;\n      const userProperties = {\n        country: 'Canada',\n        device_id: 'malicious-device-id',\n        user_properties: { spoofed: true },\n      };\n\n      await targeting.evaluateTargeting({\n        deviceId: '1a2b3c',\n        userProperties,\n        flag: flagCatchAll,\n        sessionId: 123,\n        apiKey: 'static_key',\n        loggerProvider: mockLoggerProvider,\n      });\n\n      expect(mockEngineEvaluate).toHaveBeenCalledWith(\n        expect.objectContaining({\n          user: expect.objectContaining({\n            country: 'Canada',\n            device_id: '1a2b3c',\n            user_properties: userProperties,\n          }),\n        }),\n        [flagCatchAll],\n      );\n    });\n  });\n\n  describe('condition tests', () => {\n    test('should work with event properties', async () => {\n      const targeting = new Targeting();\n      const targetingBucket = await targeting.evaluateTargeting({\n        deviceId: '1a2b3c',\n        userProperties: mockUserProperties,\n        flag: flagEventProps,\n        sessionId: 123,\n        apiKey: 'static_key',\n        loggerProvider: mockLoggerProvider,\n        event: {\n          event_type: 'Purchase',\n          event_properties: {\n            '[Amplitude] Page URL': 'http://localhost:3000/tasks-app',\n          },\n        },\n      });\n      expect(targetingBucket['sr_targeting_config'].key).toEqual('on');\n    });\n    test('should work with a user property condition', async () => {\n      const targeting = new Targeting();\n      const targetingBucket = await targeting.evaluateTargeting({\n        deviceId: '1a2b3c',\n        userProperties: {\n          plan_id: 'paid',\n        },\n        flag: flagUserProps,\n        sessionId: 123,\n        apiKey: 'static_key',\n        loggerProvider: mockLoggerProvider,\n      });\n      expect(targetingBucket['sr_targeting_config'].key).toEqual('on');\n    });\n    test('should work with multiple events', async () => {\n      const targeting = new Targeting();\n      const targetingBucket = await targeting.evaluateTargeting({\n        deviceId: '1a2b3c',\n        userProperties: {},\n        event: {\n          event_type: 'Add to Cart',\n          time: 123,\n        },\n        flag: flagConfigMultipleEvents,\n        sessionId: 123,\n        apiKey: 'static_key',\n        loggerProvider: mockLoggerProvider,\n      });\n      // Should not match with only one event\n      expect(targetingBucket['sr_targeting_config'].key).toEqual('off');\n      const updatedTargetingBucket = await targeting.evaluateTargeting({\n        deviceId: '1a2b3c',\n        userProperties: {},\n        event: {\n          event_type: 'Sign In',\n          time: 123,\n        },\n        flag: flagConfigMultipleEvents,\n        sessionId: 123,\n        apiKey: 'static_key',\n        loggerProvider: mockLoggerProvider,\n      });\n      console.log('targetingBucket', targetingBucket);\n      expect(updatedTargetingBucket['sr_targeting_config'].key).toEqual('on');\n    });\n    test('should work with multiple conditions in a segment - user property and event', async () => {\n      const targeting = new Targeting();\n      // Only user properties match the flag config here, bucket should be on\n      const userPropertyTargetingBucket = await targeting.evaluateTargeting({\n        deviceId: '1a2b3c',\n        userProperties: {\n          name: 'Banana',\n        },\n        flag: flagConfigMultipleConditions,\n        sessionId: 123,\n        apiKey: 'static_key',\n        loggerProvider: mockLoggerProvider,\n      });\n      expect(userPropertyTargetingBucket['sr_targeting_config'].key).toEqual('on');\n      // Only the event type matches the flag config here, bucket should be on\n      const eventTargetingBucket = await targeting.evaluateTargeting({\n        deviceId: '1a2b3c',\n        userProperties: {},\n        event: {\n          event_type: 'Sign In',\n          time: 123,\n        },\n        flag: flagConfigMultipleConditions,\n        sessionId: 123,\n        apiKey: 'static_key',\n        loggerProvider: mockLoggerProvider,\n      });\n      expect(eventTargetingBucket['sr_targeting_config'].key).toEqual('on');\n    });\n  });\n});\n"
  },
  {
    "path": "packages/targeting/test/tsconfig.json",
    "content": "{\n  \"extends\": \"../tsconfig.json\",\n  \"include\": [\"**/*\"],\n  \"compilerOptions\": {\n    \"types\": [\"jest\", \"node\"]\n  }\n}\n"
  },
  {
    "path": "packages/targeting/tsconfig.es5.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/cjs\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/targeting/tsconfig.esm.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"es6\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/esm\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/targeting/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src/**/*\", \"test/**/*\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"esModuleInterop\": true,\n    \"lib\": [\"dom\", \"es2020\"],\n    \"noEmit\": true,\n    \"rootDir\": \".\"\n  }\n}\n"
  },
  {
    "path": "packages/unified/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [1.1.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.1.6...@amplitude/unified@1.1.7) (2026-05-14)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n## [1.1.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.1.5...@amplitude/unified@1.1.6) (2026-05-13)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n## [1.1.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.1.4...@amplitude/unified@1.1.5) (2026-05-11)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n## [1.1.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.1.3...@amplitude/unified@1.1.4) (2026-05-11)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n## [1.1.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.1.2...@amplitude/unified@1.1.3) (2026-05-08)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n## [1.1.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.1.1...@amplitude/unified@1.1.2) (2026-05-07)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n## [1.1.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.1.0...@amplitude/unified@1.1.1) (2026-05-06)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n# [1.1.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.20...@amplitude/unified@1.1.0) (2026-04-28)\n\n\n### Features\n\n* remove experimental request body compression backdoor ([#1699](https://github.com/amplitude/Amplitude-TypeScript/issues/1699)) ([98ecb9d](https://github.com/amplitude/Amplitude-TypeScript/commit/98ecb9dc1f3658cf6d0dfae1e9784335c9d33b5e))\n\n\n\n\n\n## [1.0.20](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.19...@amplitude/unified@1.0.20) (2026-04-22)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n## [1.0.19](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.18...@amplitude/unified@1.0.19) (2026-04-21)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n## [1.0.18](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.17...@amplitude/unified@1.0.18) (2026-04-16)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n## [1.0.17](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.16...@amplitude/unified@1.0.17) (2026-04-14)\n\n\n### Bug Fixes\n\n* **unified:** export public unified types ([#1664](https://github.com/amplitude/Amplitude-TypeScript/issues/1664)) ([daf5137](https://github.com/amplitude/Amplitude-TypeScript/commit/daf51376a5ac2b8b4abbf0c5c37a9da3a9d75c17))\n\n\n\n\n\n## [1.0.16](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.15...@amplitude/unified@1.0.16) (2026-04-09)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n## [1.0.15](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.14...@amplitude/unified@1.0.15) (2026-04-01)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n## [1.0.14](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.13...@amplitude/unified@1.0.14) (2026-03-26)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n## [1.0.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.12...@amplitude/unified@1.0.13) (2026-03-24)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n## [1.0.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.11...@amplitude/unified@1.0.12) (2026-03-24)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n## [1.0.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.10...@amplitude/unified@1.0.11) (2026-03-23)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n## [1.0.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.9...@amplitude/unified@1.0.10) (2026-03-20)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n## [1.0.9](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.8...@amplitude/unified@1.0.9) (2026-03-19)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n## [1.0.8](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.7...@amplitude/unified@1.0.8) (2026-03-17)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n## [1.0.7](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.6...@amplitude/unified@1.0.7) (2026-03-16)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n## [1.0.6](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.5...@amplitude/unified@1.0.6) (2026-03-13)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n## [1.0.5](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.4...@amplitude/unified@1.0.5) (2026-03-12)\n\n\n### Bug Fixes\n\n* **unified:** should not throw an error on multiple initAll calls ([#1585](https://github.com/amplitude/Amplitude-TypeScript/issues/1585)) ([10e191a](https://github.com/amplitude/Amplitude-TypeScript/commit/10e191a24600ebe767040d58e231852185f07a30))\n\n\n\n\n\n## [1.0.4](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.3...@amplitude/unified@1.0.4) (2026-03-11)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n## [1.0.3](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.2...@amplitude/unified@1.0.3) (2026-03-09)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n## [1.0.2](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.1...@amplitude/unified@1.0.2) (2026-03-06)\n\n\n### Bug Fixes\n\n* **session-replay:** guarantee in-order batch delivery including retries ([#1576](https://github.com/amplitude/Amplitude-TypeScript/issues/1576)) ([0afcac6](https://github.com/amplitude/Amplitude-TypeScript/commit/0afcac6cd42b999b74ba797717f7cf0d447029ef))\n\n\n\n\n\n## [1.0.2-beta.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.1...@amplitude/unified@1.0.2-beta.0) (2026-03-06)\n\n\n### Bug Fixes\n\n* **session-replay:** guarantee in-order batch delivery including retries ([#1576](https://github.com/amplitude/Amplitude-TypeScript/issues/1576)) ([0afcac6](https://github.com/amplitude/Amplitude-TypeScript/commit/0afcac6cd42b999b74ba797717f7cf0d447029ef))\n\n\n\n\n\n## [1.0.2-in-order.0](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.1...@amplitude/unified@1.0.2-in-order.0) (2026-03-06)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n## [1.0.1](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.41...@amplitude/unified@1.0.1) (2026-03-05)\n\n\n### Bug Fixes\n\n* **unified:** promote to GA ([#1574](https://github.com/amplitude/Amplitude-TypeScript/issues/1574)) ([0021158](https://github.com/amplitude/Amplitude-TypeScript/commit/00211581ed150b3f8ad55a15876522c2b37e9c50))\n\n\n\n\n\n# [1.0.0-beta.41](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.40...@amplitude/unified@1.0.0-beta.41) (2026-03-05)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n# [1.0.0-beta.40](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.39...@amplitude/unified@1.0.0-beta.40) (2026-03-03)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n# [1.0.0-beta.39](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.38...@amplitude/unified@1.0.0-beta.39) (2026-03-03)\n\n\n### Features\n\n* manual opt in gzip ([#1568](https://github.com/amplitude/Amplitude-TypeScript/issues/1568)) ([303c130](https://github.com/amplitude/Amplitude-TypeScript/commit/303c130429c51b0913f3903db4ace5263e1c78e7))\n\n\n\n\n\n# [1.0.0-beta.38](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.37...@amplitude/unified@1.0.0-beta.38) (2026-02-26)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n# [1.0.0-beta.37](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.36...@amplitude/unified@1.0.0-beta.37) (2026-02-24)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n# [1.0.0-beta.36](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.35...@amplitude/unified@1.0.0-beta.36) (2026-02-20)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n# [1.0.0-beta.35](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.34...@amplitude/unified@1.0.0-beta.35) (2026-02-19)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n# [1.0.0-beta.34](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.33...@amplitude/unified@1.0.0-beta.34) (2026-02-17)\n\n\n### Features\n\n* **analytics-browser:** add setIdentity() ([#1517](https://github.com/amplitude/Amplitude-TypeScript/issues/1517)) ([314b3c1](https://github.com/amplitude/Amplitude-TypeScript/commit/314b3c1b7ee5b0ef135848a66156eb2874daec5f))\n\n\n\n\n\n# [1.0.0-beta.33](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.32...@amplitude/unified@1.0.0-beta.33) (2026-02-10)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n# [1.0.0-beta.32](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.31...@amplitude/unified@1.0.0-beta.32) (2026-01-26)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n# [1.0.0-beta.31](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.30...@amplitude/unified@1.0.0-beta.31) (2026-01-21)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n# [1.0.0-beta.30](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.29...@amplitude/unified@1.0.0-beta.30) (2026-01-15)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n# [1.0.0-beta.29](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.28...@amplitude/unified@1.0.0-beta.29) (2026-01-14)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n# [1.0.0-beta.28](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.27...@amplitude/unified@1.0.0-beta.28) (2026-01-14)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n# [1.0.0-beta.27](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.26...@amplitude/unified@1.0.0-beta.27) (2025-12-30)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n# [1.0.0-beta.26](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.25...@amplitude/unified@1.0.0-beta.26) (2025-12-24)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n# [1.0.0-beta.25](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.24...@amplitude/unified@1.0.0-beta.25) (2025-12-22)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n# [1.0.0-beta.24](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.23...@amplitude/unified@1.0.0-beta.24) (2025-12-16)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n# [1.0.0-beta.23](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.22...@amplitude/unified@1.0.0-beta.23) (2025-12-12)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n# [1.0.0-beta.22](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.21...@amplitude/unified@1.0.0-beta.22) (2025-12-09)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n# [1.0.0-beta.21](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.20...@amplitude/unified@1.0.0-beta.21) (2025-12-08)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n# [1.0.0-beta.20](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.19...@amplitude/unified@1.0.0-beta.20) (2025-12-05)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n# [1.0.0-beta.19](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.18...@amplitude/unified@1.0.0-beta.19) (2025-11-21)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n# [1.0.0-beta.18](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.17...@amplitude/unified@1.0.0-beta.18) (2025-11-20)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n# [1.0.0-beta.17](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.16...@amplitude/unified@1.0.0-beta.17) (2025-11-17)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n# [1.0.0-beta.16](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.15...@amplitude/unified@1.0.0-beta.16) (2025-11-17)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n# [1.0.0-beta.15](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.14...@amplitude/unified@1.0.0-beta.15) (2025-11-05)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n# [1.0.0-beta.14](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.13...@amplitude/unified@1.0.0-beta.14) (2025-10-29)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n# [1.0.0-beta.13](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.12...@amplitude/unified@1.0.0-beta.13) (2025-10-23)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n# [1.0.0-beta.12](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.11...@amplitude/unified@1.0.0-beta.12) (2025-10-23)\n\n\n### Bug Fixes\n\n* **unified:** export Identify and Revenue ([#1363](https://github.com/amplitude/Amplitude-TypeScript/issues/1363)) ([a47b8c9](https://github.com/amplitude/Amplitude-TypeScript/commit/a47b8c9fb0f59567ef7afb00f70aede885d949d1))\n\n\n\n\n\n# [1.0.0-beta.11](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.10...@amplitude/unified@1.0.0-beta.11) (2025-10-21)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n# [1.0.0-beta.10](https://github.com/amplitude/Amplitude-TypeScript/compare/@amplitude/unified@1.0.0-beta.9...@amplitude/unified@1.0.0-beta.10) (2025-10-17)\n\n**Note:** Version bump only for package @amplitude/unified\n\n\n\n\n\n# Changelog\n\n## 1.0.0-beta.9 (2025-10-06)\n\n- Release 1.0.0-beta.9\n\n\n## 1.0.0-beta.7 (2025-10-06)\n\n- Release 1.0.0-beta.7\n\n\n## 1.0.0-beta.6 (2025-10-02)\n\n- Release 1.0.0-beta.6\n\n\n## 1.0.0-beta.5 (2025-06-25)\n\n- Release 1.0.0-beta.5\n\n\n## 1.0.0-beta.4 (2025-06-25)\n\n- Release 1.0.0-beta.4\n\n\n## 1.0.0-beta.3 (2025-06-25)\n\n- Release 1.0.0-beta.3\n"
  },
  {
    "path": "packages/unified/README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://amplitude.com\" target=\"_blank\" align=\"center\">\n    <img src=\"https://static.amplitude.com/lightning/46c85bfd91905de8047f1ee65c7c93d6fa9ee6ea/static/media/amplitude-logo-with-text.4fb9e463.svg\" width=\"280\">\n  </a>\n  <br />\n</p>\n\n# @amplitude/unified\n\nOfficial Amplitude SDK for Web analytics, experiment, session replay, Guides and Surveys, and more.\n\n## Installation\n\nThis package is published on NPM registry and is available to be installed using npm and yarn.\n\n```sh\n# npm\nnpm install @amplitude/unified\n\n# yarn\nyarn add @amplitude/unified\n```\n\n## Usage\n\nThe Unified SDK provides a single entry point for all Amplitude features, including Analytics, Experiment, and Session Replay. It simplifies the integration process by handling the initialization and configuration of all components.\n\n### 1. Import Amplitude Unified SDK\n\n```typescript\nimport { initAll } from '@amplitude/unified';\n```\n\n### 2. Initialize the SDK\n\n```typescript\ninitAll('YOUR_API_KEY', {\n  // Shared options for all SDKs (optional)\n  serverZone: 'US', // or 'EU'\n  instanceName: 'my-instance',\n\n  // Analytics options\n  analytics: {\n    // Analytics configuration options\n  },\n\n  // Session Replay options\n  sessionReplay: {\n    // Session Replay configuration options\n  },\n\n  // Experiment options\n  experiment: {\n    // Experiment configuration options\n  },\n\n  // Guides and Surveys options\n  engagement: {\n    // Guides and Surveys configuration options\n  },\n});\n```\n\n### 3. Access SDK Features\n\nThe Unified SDK provides access to all Amplitude features through a single interface:\n\n```typescript\nimport {\n  track,\n  identify,\n  experiment,\n  sessionReplay\n} from '@amplitude/unified';\n\n// Track events\ntrack('Button Clicked', { buttonName: 'Sign Up' });\n\n// Identify users\nidentify(new Identify().set('userType', 'premium'));\n\n// Access Experiment features\nconst variant = await experiment.fetch('experiment-key');\n\n// Access Session Replay features\nsessionReplay.flush();\n\n// Access Guides and Surveys features via engagement global\nconst activeGuidesAndSurveys = await engagement.gs.list();\n```\n\n## Configuration Options\n\n### Shared Options\n\n| Name           | Type             | Default     | Description                                 |\n| -------------- | ---------------- | ----------- | ------------------------------------------- |\n| `serverZone`   | `'US'` or `'EU'` | `'US'`      | The server zone to use for all SDKs.        |\n| `instanceName` | `string`         | `undefined` | A unique name for this instance of the SDK. |\n\n### Analytics Options\n\nAll options from `@amplitude/analytics-browser` are supported. See the [Analytics Browser SDK documentation](https://www.docs.developers.amplitude.com/analytics/browser/) for details.\n\n### Session Replay Options\n\nAll options from `@amplitude/plugin-session-replay-browser` are supported. See the [Session Replay documentation](https://www.docs.developers.amplitude.com/session-replay/) for details.\n\n### Experiment Options\n\nAll options from `@amplitude/plugin-experiment-browser` are supported. See the [Experiment documentation](https://www.docs.developers.amplitude.com/experiment/) for details.\n\n### Guides and Surveys Options\n\nAll options from `@amplitude/engagement-browser` are supported. See the [Guides and Surveys documentation](hhttps://amplitude.com/docs/guides-and-surveys/sdk) for details.\n\n## Learn More\n\n- [Analytics Browser SDK Documentation](https://amplitude.com/docs/sdks/analytics/browser/browser-sdk-2)\n- [Session Replay Documentation](https://amplitude.com/docs/session-replay/session-replay-standalone-sdk)\n- [Experiment Documentation](https://amplitude.com/docs/sdks/experiment-sdks/experiment-javascript)\n- [Guides and Surveys SDK Documentation](https://amplitude.com/docs/guides-and-surveys/sdk)\n"
  },
  {
    "path": "packages/unified/__mocks__/@amplitude/engagement-browser.js",
    "content": "// Manual mock for @amplitude/engagement-browser\n// This prevents the engagement plugin from loading external scripts during tests.\n// The engagement plugin loads external scripts from a CDN during initialization,\n// which causes issues in jsdom test environment:\n// 1. jsdom doesn't actually fetch/execute external scripts\n// 2. Script onload events never fire, causing promises to hang indefinitely\n// 3. Tests would timeout waiting for initialization that never completes\n// This mock provides a simple plugin interface that resolves immediately.\n\nmodule.exports = {\n    plugin: jest.fn(() => ({\n        name: '@amplitude/engagement-plugin',\n        type: 'enrichment',\n        setup: jest.fn().mockResolvedValue(undefined),\n        execute: jest.fn().mockResolvedValue(undefined),\n    })),\n};\n"
  },
  {
    "path": "packages/unified/jest.config.js",
    "content": "const baseConfig = require('../../jest.config.js');\nconst package = require('./package');\n\nmodule.exports = {\n  ...baseConfig,\n  displayName: package.name,\n  rootDir: '.',\n  testEnvironment: 'jsdom',\n  coveragePathIgnorePatterns: ['index.ts'],\n};\n"
  },
  {
    "path": "packages/unified/package.json",
    "content": "{\n  \"name\": \"@amplitude/unified\",\n  \"version\": \"1.1.7\",\n  \"description\": \"Official Amplitude SDK for Web analytics, experiment, session replay, and more.\",\n  \"keywords\": [\n    \"amplitude\",\n    \"analytics\",\n    \"experiment\",\n    \"session replay\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/amplitude/Amplitude-TypeScript.git\"\n  },\n  \"author\": \"Amplitude Inc\",\n  \"license\": \"MIT\",\n  \"main\": \"lib/cjs/index.js\",\n  \"module\": \"lib/esm/index.js\",\n  \"types\": \"lib/esm/index.d.ts\",\n  \"sideEffects\": false,\n  \"bugs\": {\n    \"url\": \"https://github.com/amplitude/Amplitude-TypeScript/issues\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"tag\": \"latest\"\n  },\n  \"files\": [\n    \"lib\"\n  ],\n  \"scripts\": {\n    \"build\": \"pnpm bundle && pnpm build:es5 && pnpm build:esm\",\n    \"bundle\": \"rollup --config rollup.config.js\",\n    \"build:es5\": \"tsc -p ./tsconfig.es5.json\",\n    \"build:esm\": \"tsc -p ./tsconfig.esm.json\",\n    \"watch\": \"tsc -p ./tsconfig.esm.json --watch\",\n    \"clean\": \"rimraf node_modules lib coverage\",\n    \"fix\": \"pnpm fix:eslint & pnpm fix:prettier\",\n    \"fix:eslint\": \"eslint '{src,test}/**/*.ts' --fix\",\n    \"fix:prettier\": \"prettier --write \\\"{src,test}/**/*.ts\\\"\",\n    \"lint\": \"pnpm lint:eslint & pnpm lint:prettier\",\n    \"lint:eslint\": \"eslint '{src,test}/**/*.ts'\",\n    \"lint:prettier\": \"prettier --check \\\"{src,test}/**/*.ts\\\"\",\n    \"test\": \"jest\",\n    \"typecheck\": \"tsc -p ./tsconfig.json\",\n    \"version\": \"pnpm version-file && GENERATE_SNIPPET=true pnpm build\",\n    \"version-file\": \"echo '// Autogenerated by `pnpm version-file`. DO NOT EDIT' > src/version.ts && node -p \\\"'export const VERSION = \\\\'' + require('./package.json').version + '\\\\';'\\\" >> src/version.ts\"\n  },\n  \"dependencies\": {\n    \"@amplitude/analytics-browser\": \"workspace:*\",\n    \"@amplitude/analytics-core\": \"workspace:*\",\n    \"@amplitude/engagement-browser\": \"^1.0.3\",\n    \"@amplitude/plugin-experiment-browser\": \"workspace:*\",\n    \"@amplitude/plugin-session-replay-browser\": \"workspace:*\"\n  },\n  \"devDependencies\": {\n    \"rollup\": \"^2.79.1\"\n  }\n}\n"
  },
  {
    "path": "packages/unified/rollup.config.js",
    "content": "import { umd } from '../../scripts/build/rollup.config';\n\n// Disable dynamic imports to avoid issues with the session replay browser\nexport default [{\n    ...umd,\n    inlineDynamicImports: true,\n}];\n"
  },
  {
    "path": "packages/unified/src/index.ts",
    "content": "/* eslint-disable @typescript-eslint/unbound-method */\nimport client from './unified-client-factory';\nexport { createInstance } from './unified-client-factory';\nexport type { UnifiedClient, UnifiedOptions, UnifiedSharedOptions } from './unified';\nexport const {\n  _setDiagnosticsSampleRate,\n  initAll,\n  experiment,\n  sessionReplay,\n  add,\n  extendSession,\n  flush,\n  getDeviceId,\n  getIdentity,\n  getOptOut,\n  getSessionId,\n  getUserId,\n  groupIdentify,\n  identify,\n  logEvent,\n  remove,\n  reset,\n  revenue,\n  setDeviceId,\n  setGroup,\n  setIdentity,\n  setOptOut,\n  setSessionId,\n  setTransport,\n  setUserId,\n  track,\n} = client;\nexport { Types, Revenue, Identify } from '@amplitude/analytics-browser';\n"
  },
  {
    "path": "packages/unified/src/library.ts",
    "content": "import { Types } from '@amplitude/analytics-browser';\nimport { VERSION } from './version';\n\nconst LIBPREFIX = 'amplitude-ts-unified';\n\nexport const libraryPlugin = (): Types.EnrichmentPlugin => {\n  return {\n    type: 'enrichment',\n    name: '@amplitude/unified-library-plugin',\n    async execute(event: Types.Event): Promise<Types.Event | null> {\n      event.library = `${LIBPREFIX}/${VERSION}-${event.library ?? ''}`;\n      return event;\n    },\n  };\n};\n"
  },
  {
    "path": "packages/unified/src/unified-client-factory.ts",
    "content": "import { AmplitudeUnified, UnifiedClient } from './unified';\nimport { debugWrapper, getClientLogConfig, getClientStates } from '@amplitude/analytics-core';\n\nexport const createInstance = (): UnifiedClient => {\n  const client = new AmplitudeUnified();\n  return {\n    _setDiagnosticsSampleRate: debugWrapper(\n      client._setDiagnosticsSampleRate.bind(client),\n      '_setDiagnosticsSampleRate',\n      getClientLogConfig(client),\n      getClientStates(client, ['config']),\n    ),\n    experiment: debugWrapper(\n      client.experiment.bind(client),\n      'experiment',\n      getClientLogConfig(client),\n      getClientStates(client, ['config']),\n    ),\n    sessionReplay: debugWrapper(\n      client.sessionReplay.bind(client),\n      'sessionReplay',\n      getClientLogConfig(client),\n      getClientStates(client, ['config']),\n    ),\n    initAll: debugWrapper(\n      client.initAll.bind(client),\n      'initAll',\n      getClientLogConfig(client),\n      getClientStates(client, ['config']),\n    ),\n    init: debugWrapper(\n      client.init.bind(client),\n      'init',\n      getClientLogConfig(client),\n      getClientStates(client, ['config']),\n    ),\n    add: debugWrapper(\n      client.add.bind(client),\n      'add',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.plugins']),\n    ),\n    remove: debugWrapper(\n      client.remove.bind(client),\n      'remove',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.plugins']),\n    ),\n    track: debugWrapper(\n      client.track.bind(client),\n      'track',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.queue.length']),\n    ),\n    logEvent: debugWrapper(\n      client.logEvent.bind(client),\n      'logEvent',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.queue.length']),\n    ),\n    identify: debugWrapper(\n      client.identify.bind(client),\n      'identify',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.queue.length']),\n    ),\n    groupIdentify: debugWrapper(\n      client.groupIdentify.bind(client),\n      'groupIdentify',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.queue.length']),\n    ),\n    setGroup: debugWrapper(\n      client.setGroup.bind(client),\n      'setGroup',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.queue.length']),\n    ),\n    revenue: debugWrapper(\n      client.revenue.bind(client),\n      'revenue',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.queue.length']),\n    ),\n    flush: debugWrapper(\n      client.flush.bind(client),\n      'flush',\n      getClientLogConfig(client),\n      getClientStates(client, ['config.apiKey', 'timeline.queue.length']),\n    ),\n    getUserId: debugWrapper(\n      client.getUserId.bind(client),\n      'getUserId',\n      getClientLogConfig(client),\n      getClientStates(client, ['config', 'config.userId']),\n    ),\n    setUserId: debugWrapper(\n      client.setUserId.bind(client),\n      'setUserId',\n      getClientLogConfig(client),\n      getClientStates(client, ['config', 'config.userId']),\n    ),\n    getDeviceId: debugWrapper(\n      client.getDeviceId.bind(client),\n      'getDeviceId',\n      getClientLogConfig(client),\n      getClientStates(client, ['config', 'config.deviceId']),\n    ),\n    setDeviceId: debugWrapper(\n      client.setDeviceId.bind(client),\n      'setDeviceId',\n      getClientLogConfig(client),\n      getClientStates(client, ['config', 'config.deviceId']),\n    ),\n    reset: debugWrapper(\n      client.reset.bind(client),\n      'reset',\n      getClientLogConfig(client),\n      getClientStates(client, ['config', 'config.userId', 'config.deviceId']),\n    ),\n    getSessionId: debugWrapper(\n      client.getSessionId.bind(client),\n      'getSessionId',\n      getClientLogConfig(client),\n      getClientStates(client, ['config']),\n    ),\n    setSessionId: debugWrapper(\n      client.setSessionId.bind(client),\n      'setSessionId',\n      getClientLogConfig(client),\n      getClientStates(client, ['config']),\n    ),\n    extendSession: debugWrapper(\n      client.extendSession.bind(client),\n      'extendSession',\n      getClientLogConfig(client),\n      getClientStates(client, ['config']),\n    ),\n    setOptOut: debugWrapper(\n      client.setOptOut.bind(client),\n      'setOptOut',\n      getClientLogConfig(client),\n      getClientStates(client, ['config']),\n    ),\n    getOptOut: debugWrapper(\n      client.getOptOut.bind(client),\n      'getOptOut',\n      getClientLogConfig(client),\n      getClientStates(client, ['config']),\n    ),\n    setTransport: debugWrapper(\n      client.setTransport.bind(client),\n      'setTransport',\n      getClientLogConfig(client),\n      getClientStates(client, ['config']),\n    ),\n    getIdentity: debugWrapper(\n      client.getIdentity.bind(client),\n      'getIdentity',\n      getClientLogConfig(client),\n      getClientStates(client, ['config']),\n    ),\n    setIdentity: debugWrapper(\n      client.setIdentity.bind(client),\n      'setIdentity',\n      getClientLogConfig(client),\n      getClientStates(client, ['config', 'config.userId', 'config.deviceId']),\n    ),\n  };\n};\n\nexport default createInstance();\n"
  },
  {
    "path": "packages/unified/src/unified.ts",
    "content": "import { AmplitudeBrowser } from '@amplitude/analytics-browser';\nimport {\n  AmplitudeSessionReplay,\n  SessionReplayOptions,\n  sessionReplayPlugin,\n  SessionReplayPlugin,\n} from '@amplitude/plugin-session-replay-browser';\nimport {\n  IExperimentClient,\n  ExperimentPluginConfig,\n  ExperimentPlugin,\n  experimentPlugin,\n} from '@amplitude/plugin-experiment-browser';\nimport { InitOptions, plugin as EngagementPlugin } from '@amplitude/engagement-browser';\nimport { BrowserClient, BrowserOptions } from '@amplitude/analytics-core';\nimport { libraryPlugin } from './library';\n\nexport interface UnifiedSharedOptions {\n  serverZone?: 'US' | 'EU';\n  instanceName?: string;\n}\n\nexport type UnifiedOptions = UnifiedSharedOptions & {\n  analytics?: BrowserOptions;\n  sessionReplay?: Omit<SessionReplayOptions, keyof UnifiedSharedOptions>;\n  experiment?: Omit<ExperimentPluginConfig, keyof UnifiedSharedOptions>;\n  engagement?: Omit<InitOptions, keyof UnifiedSharedOptions>;\n};\n\nexport interface UnifiedClient extends BrowserClient {\n  initAll(apiKey: string, unifiedOptions?: UnifiedOptions): Promise<void>;\n  sessionReplay(): AmplitudeSessionReplay;\n  experiment(): IExperimentClient | undefined;\n}\n\nexport class AmplitudeUnified extends AmplitudeBrowser implements UnifiedClient {\n  // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n  // @ts-ignore\n  private _sessionReplay: AmplitudeSessionReplay;\n  private _initAllPromise?: Promise<void>;\n\n  sessionReplay(): AmplitudeSessionReplay {\n    return this._sessionReplay;\n  }\n\n  experiment(): IExperimentClient | undefined {\n    // Return when init() or initAll() is not called\n    if (this.config === undefined) {\n      return undefined;\n    }\n\n    const expPlugins = this.plugins(ExperimentPlugin);\n    if (expPlugins.length === 0) {\n      this.config.loggerProvider.debug(`${ExperimentPlugin.pluginName} plugin is not found.`);\n      return undefined;\n    } else if (expPlugins.length === 1) {\n      return expPlugins[0].experiment;\n    } else {\n      this.config.loggerProvider.debug(`Multiple instances of ${ExperimentPlugin.pluginName} are found.`);\n      return undefined;\n    }\n  }\n\n  /**\n   * Initialize SDKs with configuration options.\n   *\n   * @param apiKey Amplitude API key.\n   * @param analyticsOptions Analytics configuration options. Refer to {@link https://amplitude.com/docs/sdks/analytics/browser/browser-sdk-2#configure-the-sdk here} for more info.\n   * @param unifiedOptions Shared configuration for all SDKs and for blade SDKs.\n   */\n  async initAll(apiKey: string, unifiedOptions?: UnifiedOptions) {\n    if (this._initAllPromise) {\n      return this._initAllPromise;\n    }\n\n    this._initAllPromise = (async () => {\n      const sharedOptions = {\n        serverZone: unifiedOptions?.serverZone,\n        instanceName: unifiedOptions?.instanceName,\n      };\n\n      super.add(libraryPlugin());\n\n      await super.init(apiKey, { ...unifiedOptions?.analytics, ...sharedOptions }).promise;\n\n      await super.add(sessionReplayPlugin({ ...unifiedOptions?.sessionReplay, ...sharedOptions })).promise;\n\n      await super.add(experimentPlugin({ ...unifiedOptions?.experiment, ...sharedOptions })).promise;\n\n      const srPlugin = this.plugin(SessionReplayPlugin.pluginName);\n      if (srPlugin === undefined) {\n        this.config.loggerProvider.debug(`${SessionReplayPlugin.pluginName} plugin is not found.`);\n      } else {\n        this._sessionReplay = (srPlugin as SessionReplayPlugin).sessionReplay;\n      }\n\n      await super.add(\n        EngagementPlugin({\n          ...unifiedOptions?.engagement,\n          ...sharedOptions,\n        }),\n      ).promise;\n    })().finally(() => {\n      this._initAllPromise = undefined;\n    });\n\n    return this._initAllPromise;\n  }\n\n  /**\n   * Only analytics SDK is initialized. Use initAll() instead to initialize all blade SDKs.\n   */\n  /* istanbul ignore next */\n  init(apiKey = '', userIdOrOptions?: string | BrowserOptions, maybeOptions?: BrowserOptions) {\n    const res = super.init(apiKey, userIdOrOptions, maybeOptions);\n    return res;\n  }\n}\n"
  },
  {
    "path": "packages/unified/src/version.ts",
    "content": "// Autogenerated by `pnpm version-file`. DO NOT EDIT\nexport const VERSION = '1.1.7';\n"
  },
  {
    "path": "packages/unified/test/index.test.ts",
    "content": "import * as amplitude from '../src/index';\nimport { sessionReplay, experiment } from '../src/index';\nimport type { UnifiedClient, UnifiedOptions, UnifiedSharedOptions } from '../src/index';\n\ntest('should return non undefined sessionReplay and experiment after initAll() by import method 1 & 2', async () => {\n  // Test that methods work before and after initAll()\n  expect(amplitude.sessionReplay()).toBeUndefined();\n  expect(amplitude.experiment()).toBeUndefined();\n\n  await amplitude.initAll('test-api-key');\n\n  // Method 1: import * as amplitude should work\n  expect(amplitude.sessionReplay()).toBeDefined();\n  expect(amplitude.experiment()).toBeDefined();\n  // Method 2: named imports { initAll, sessionReplay, experiment } should work\n  expect(sessionReplay()).toBeDefined();\n  expect(experiment()).toBeDefined();\n});\n\ntest('should export unified public types from the package entry point', () => {\n  const sharedOptions: UnifiedSharedOptions = {\n    serverZone: 'US',\n  };\n  const options: UnifiedOptions = {\n    ...sharedOptions,\n    analytics: {},\n  };\n  const client: UnifiedClient = amplitude.createInstance();\n\n  expect(options).toBeDefined();\n  expect(client).toBeDefined();\n});\n"
  },
  {
    "path": "packages/unified/test/library.test.ts",
    "content": "import { libraryPlugin } from '../src/library';\nimport { Types } from '@amplitude/analytics-browser';\nimport { VERSION } from '../src/version';\n\ndescribe('libraryPlugin', () => {\n  test('should prepend the correct library prefix and version to an event', async () => {\n    const plugin = libraryPlugin();\n    const originalLibrary = 'amplitude-ts/2.11.0';\n    const event: Types.Event = { event_type: 'test_event', library: originalLibrary };\n    const result = await plugin.execute?.(event);\n\n    expect(result?.library).toMatch(`amplitude-ts-unified/${VERSION}-${originalLibrary}`);\n  });\n\n  test('should handle when library is undefined', async () => {\n    const plugin = libraryPlugin();\n    const event: Types.Event = { event_type: 'test_event' };\n    const result = await plugin.execute?.(event);\n\n    expect(result?.library).toMatch(`amplitude-ts-unified/${VERSION}-`);\n  });\n\n  it('should have the correct plugin type and name', () => {\n    const plugin = libraryPlugin();\n\n    expect(plugin.type).toBe('enrichment');\n    expect(plugin.name).toBe('@amplitude/unified-library-plugin');\n  });\n});\n"
  },
  {
    "path": "packages/unified/test/unified-client-factory.test.ts",
    "content": "import instance from '../src/unified-client-factory';\n\ntest('should create a UnifiedClient instance with expected methods', () => {\n  expect(instance).toHaveProperty('experiment');\n  expect(instance).toHaveProperty('sessionReplay');\n  expect(typeof instance.initAll).toBe('function');\n  expect(typeof instance.init).toBe('function');\n  expect(typeof instance.add).toBe('function');\n  expect(typeof instance.remove).toBe('function');\n  expect(typeof instance.track).toBe('function');\n  expect(typeof instance.logEvent).toBe('function');\n  expect(typeof instance.identify).toBe('function');\n  expect(typeof instance.groupIdentify).toBe('function');\n  expect(typeof instance.setGroup).toBe('function');\n  expect(typeof instance.revenue).toBe('function');\n  expect(typeof instance.flush).toBe('function');\n  expect(typeof instance.getUserId).toBe('function');\n  expect(typeof instance.setUserId).toBe('function');\n  expect(typeof instance.getDeviceId).toBe('function');\n  expect(typeof instance.setDeviceId).toBe('function');\n  expect(typeof instance.reset).toBe('function');\n  expect(typeof instance.getSessionId).toBe('function');\n  expect(typeof instance.setSessionId).toBe('function');\n  expect(typeof instance.extendSession).toBe('function');\n  expect(typeof instance.setOptOut).toBe('function');\n  expect(typeof instance.setTransport).toBe('function');\n});\n\ntest('should return non undefined sessionReplay and experiment after initAll() by import method 3', async () => {\n  // Method 3: import {createInstance} from '@amplitude/unified'\n  // Test that sessionReplay and experiment are undefined before initAll()\n  expect(instance.sessionReplay()).toBeUndefined();\n  expect(instance.experiment()).toBeUndefined();\n\n  // Initialize with a test API key\n  await instance.initAll('test-api-key');\n\n  // Test that sessionReplay and experiment are defined after initAll()\n  expect(instance.sessionReplay()).toBeDefined();\n  expect(instance.experiment()).toBeDefined();\n});\n"
  },
  {
    "path": "packages/unified/test/unified-constructor-coverage.test.ts",
    "content": "jest.mock('@amplitude/analytics-browser', () => {\n  function AmplitudeBrowserMock() {\n    return undefined;\n  }\n\n  return {\n    AmplitudeBrowser: AmplitudeBrowserMock,\n  };\n});\n\nimport { AmplitudeUnified } from '../src/unified';\n\ndescribe('AmplitudeUnified instantiation coverage', () => {\n  test('covers class instantiation when super call returns undefined', () => {\n    const client = new AmplitudeUnified();\n    expect(client).toBeDefined();\n  });\n});\n"
  },
  {
    "path": "packages/unified/test/unified.test.ts",
    "content": "import { AmplitudeUnified } from '../src/unified';\nimport { AmplitudeBrowser } from '@amplitude/analytics-browser';\nimport { ILogger } from '@amplitude/analytics-core';\nimport { SessionReplayPlugin } from '@amplitude/plugin-session-replay-browser';\nimport { experimentPlugin, ExperimentPlugin } from '@amplitude/plugin-experiment-browser';\nimport * as libraryModule from '../src/library';\n\ntype MockedLogger = jest.Mocked<ILogger>;\n\ndescribe('AmplitudeUnified', () => {\n  const mockLoggerProviderDebug = jest.fn();\n  const mockLoggerProvider: MockedLogger = {\n    error: jest.fn(),\n    log: jest.fn(),\n    disable: jest.fn(),\n    enable: jest.fn(),\n    warn: jest.fn(),\n    debug: mockLoggerProviderDebug,\n  };\n\n  describe('constructor', () => {\n    test('should construct client with no in-flight initAll promise', () => {\n      const client = new AmplitudeUnified() as unknown as { _initAllPromise?: Promise<void> };\n      expect(client._initAllPromise).toBeUndefined();\n    });\n  });\n\n  describe('initAll', () => {\n    test.each([\n      {\n        analytics: {\n          loggerProvider: mockLoggerProvider,\n        },\n      },\n      undefined,\n    ])('should initialize all plugins and assign sr and experiment properties', async (unifiedOptions) => {\n      const client = new AmplitudeUnified();\n      expect(client.sessionReplay()).toBeUndefined();\n      expect(client.experiment()).toBeUndefined();\n\n      await client.initAll('test-api-key', unifiedOptions);\n\n      expect(client.sessionReplay()).toBeDefined();\n      expect(client.experiment()).toBeDefined();\n    });\n\n    test('should log when sr plugin is not found', async () => {\n      const client = new AmplitudeUnified();\n      const originalPlugin = client.plugin.bind(client);\n      jest.spyOn(client, 'plugin').mockImplementation((name) => {\n        if (name === SessionReplayPlugin.pluginName) return undefined;\n        return originalPlugin(name);\n      });\n      expect(client.sessionReplay()).toBeUndefined();\n      expect(client.experiment()).toBeUndefined();\n\n      await client.initAll('test-api-key', {\n        analytics: {\n          loggerProvider: mockLoggerProvider,\n        },\n      });\n\n      expect(client.sessionReplay()).toBeUndefined();\n      expect(mockLoggerProviderDebug).toHaveBeenCalledWith(`${SessionReplayPlugin.pluginName} plugin is not found.`);\n      expect(client.experiment()).toBeDefined();\n    });\n\n    test('should log when experiment plugin is not found', async () => {\n      const client = new AmplitudeUnified();\n      jest.spyOn(client, 'plugins').mockImplementation((_) => {\n        return [];\n      });\n      expect(client.sessionReplay()).toBeUndefined();\n      expect(client.experiment()).toBeUndefined();\n\n      await client.initAll('test-api-key', {\n        analytics: {\n          loggerProvider: mockLoggerProvider,\n        },\n      });\n\n      expect(client.sessionReplay()).toBeDefined();\n      expect(client.experiment()).toBeUndefined();\n      expect(mockLoggerProviderDebug).toHaveBeenCalledWith(`${ExperimentPlugin.pluginName} plugin is not found.`);\n    });\n\n    test('should log when multiple experiment instances are not found', async () => {\n      const client = new AmplitudeUnified();\n      jest.spyOn(client, 'plugins').mockImplementation((_) => {\n        return [];\n      });\n      expect(client.sessionReplay()).toBeUndefined();\n      expect(client.experiment()).toBeUndefined();\n\n      await client.initAll('test-api-key', {\n        analytics: {\n          loggerProvider: mockLoggerProvider,\n        },\n      });\n\n      expect(client.sessionReplay()).toBeDefined();\n      expect(client.experiment()).toBeUndefined();\n      expect(mockLoggerProviderDebug).toHaveBeenCalledWith(`${ExperimentPlugin.pluginName} plugin is not found.`);\n    });\n\n    test('should add library plugin', async () => {\n      const spy = jest.spyOn(libraryModule, 'libraryPlugin');\n      const client = new AmplitudeUnified();\n\n      await client.initAll('test-api-key');\n\n      expect(spy).toHaveBeenCalled();\n    });\n\n    test('should not throw when called concurrently without await', async () => {\n      const client = new AmplitudeUnified();\n      const p1 = client.initAll('test-api-key');\n      const p2 = client.initAll('test-api-key');\n      await expect(Promise.all([p1, p2])).resolves.toEqual([undefined, undefined]);\n    });\n\n    test('should wait for in-flight initAll for concurrent callers', async () => {\n      const client = new AmplitudeUnified();\n      const originalInit = (AmplitudeBrowser.prototype as any)._init as (...args: any[]) => Promise<void>;\n\n      let unblockInit: () => void;\n      const initBlocked = new Promise<void>((resolve) => {\n        unblockInit = resolve;\n      });\n\n      const initSpy = jest\n        .spyOn(AmplitudeBrowser.prototype as any, '_init')\n        .mockImplementation(async function (this: AmplitudeBrowser, ...args: unknown[]) {\n          await initBlocked;\n          return originalInit.apply(this, args);\n        });\n\n      const p1 = client.initAll('test-api-key');\n      const p2 = client.initAll('test-api-key');\n\n      let secondCallResolved = false;\n      void p2.then(() => {\n        secondCallResolved = true;\n      });\n\n      await Promise.resolve();\n      expect(secondCallResolved).toBe(false);\n\n      unblockInit!();\n      await Promise.all([p1, p2]);\n      expect(initSpy).toHaveBeenCalledTimes(1);\n    });\n  });\n\n  describe('init', () => {\n    test('init should initialize only analytics SDK and log', () => {\n      const client = new AmplitudeUnified();\n\n      const res = client.init('test-api-key', {\n        loggerProvider: mockLoggerProvider,\n      });\n      expect(res).toBeDefined();\n    });\n  });\n\n  describe('experiment method', () => {\n    test('should return undefined and log when multiple experiment instances', async () => {\n      const client = new AmplitudeUnified();\n      const experimentPlugin2 = experimentPlugin();\n      // Have to change name because plugin with existing name will be ignored at registration\n      experimentPlugin2.name = '@amplitude/experiment-analytics-plugin-2';\n\n      await client.initAll('test-api-key', {\n        analytics: {\n          loggerProvider: mockLoggerProvider,\n        },\n      });\n      await client.add(experimentPlugin2).promise;\n\n      expect(client.plugin('@amplitude/experiment-analytics-plugin-2')).toBeDefined();\n      expect(client.experiment()).toBeUndefined();\n      expect(mockLoggerProviderDebug).toHaveBeenCalledWith(\n        `Multiple instances of ${ExperimentPlugin.pluginName} are found.`,\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "packages/unified/tsconfig.es5.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/cjs\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/unified/tsconfig.esm.json",
    "content": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"src/**/*\"],\n  \"compilerOptions\": {\n    \"module\": \"es6\",\n    \"noEmit\": false,\n    \"outDir\": \"lib/esm\",\n    \"rootDir\": \"./src\"\n  }\n}\n"
  },
  {
    "path": "packages/unified/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src/**/*\", \"test/**/*\"],\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"esModuleInterop\": true,\n    \"lib\": [\"dom\"],\n    \"noEmit\": true,\n    \"rootDir\": \".\",\n  }\n}\n"
  },
  {
    "path": "playwright.config.ts",
    "content": "import { defineConfig, devices } from '@playwright/test';\n\nexport default defineConfig({\n  testDir: '.',\n  fullyParallel: true,\n  forbidOnly: !!process.env.CI,\n  retries: process.env.CI ? 2 : 0,\n  workers: process.env.CI ? 1 : undefined,\n  reporter: process.env.CI ? [['html'], ['github']] : 'html',\n  use: {\n    baseURL: 'http://localhost:5173',\n    trace: process.env.CI ? 'on' : 'on-first-retry',\n    actionTimeout: 30000,\n    navigationTimeout: 30000,\n    ignoreHTTPSErrors: true,\n    // Capture screenshot on failure\n    screenshot: 'only-on-failure',\n    // Record video for all tests in CI\n    video: process.env.CI ? 'on' : 'retain-on-failure',\n  },\n  projects: [\n    {\n      name: 'chromium',\n      use: { ...devices['Desktop Chrome'] },\n    },\n    // TODO: Get this working again\n    // {\n    //   name: 'firefox',\n    //   use: {\n    //     ...devices['Desktop Firefox'],\n    //     launchOptions: {\n    //       firefoxUserPrefs: {\n    //         'network.http.connection-retry-timeout': 0,\n    //         'network.http.max-connections-per-server': 10,\n    //       },\n    //     },\n    //   },\n    // },\n    {\n      name: 'webkit',\n      use: { ...devices['Desktop Safari'] },\n    },\n  ],\n  webServer: {\n    command: 'yarn start',\n    url: 'http://localhost:5173',\n    reuseExistingServer: true,\n    timeout: 120000,\n  },\n  testMatch: '**/e2e/**/*.spec.ts',\n  testIgnore: [\n    '**/test-server/dist/**',\n    // session-replay-browser e2e tests are local sanity checks only — not yet\n    // wired into CI (requires a real remote config + SR API setup). Run manually\n    // with `npx playwright test packages/session-replay-browser/e2e/`.\n    '**/session-replay-browser/e2e/**',\n  ],\n  timeout: 30000,\n});\n"
  },
  {
    "path": "pnpm-workspace.yaml",
    "content": "packages:\n  - packages/*\n  - apps/*\n  - examples/react-native/app\n\nblockExoticSubdeps: true\n\nminimumReleaseAge: 4320\n\nminimumReleaseAgeExclude:\n  - '@amplitude/*'\n\n# These are dependencies that run the postinstall script\n# Only add dependencies to this if they have been vetted for security\nonlyBuiltDependencies:\n  - core-js\n  - esbuild\n  - msw\n  - nx\n  - unrs-resolver\n\ntrustPolicy: true\n"
  },
  {
    "path": "scripts/README.md",
    "content": "# Scripts\n\nThis directory contains utility scripts for the Amplitude TypeScript monorepo.\n\n## check-deprecated-packages.sh\n\nRuns in CI to prevent new dependencies on deprecated packages.\n\n**Deprecated packages:**\n- `@amplitude/analytics-types`\n- `@amplitude/analytics-client-common`\n- `@amplitude/analytics-remote-config`\n\n**Replacements:**\n- For `@amplitude/analytics-types` and `@amplitude/analytics-client-common`: Use `@amplitude/analytics-core`\n- For `@amplitude/analytics-remote-config`: Use the new remote config client in `@amplitude/analytics-core`\n\n**How it works:**\n- Compares `package.json` files between the base branch and PR branch\n- Detects new dependencies on deprecated packages\n- Allows existing dependencies to remain (grandfathered in)\n- Fails the CI build if new usage is detected\n\n**Running locally:**\n```bash\n# Requires a git repository with a base branch to compare against\nGITHUB_BASE_REF=main bash scripts/check-deprecated-packages.sh\n```\n\n**Testing the script:**\nTo test if the check would catch a new dependency:\n1. Add a deprecated package to a `package.json` file\n2. Run the script with your base branch: `GITHUB_BASE_REF=main bash scripts/check-deprecated-packages.sh`\n3. The script should fail and report the new dependency\n4. Revert your test changes\n\n**CI Integration:**\nThis check runs automatically on all pull requests via the `check-deprecated-packages` job in `.github/workflows/ci-nx.yml`.\n\n"
  },
  {
    "path": "scripts/build/rollup.config.js",
    "content": "import typescript from '@rollup/plugin-typescript';\nimport commonjs from '@rollup/plugin-commonjs';\nimport resolve from '@rollup/plugin-node-resolve';\nimport { terser } from 'rollup-plugin-terser';\nimport gzip from 'rollup-plugin-gzip';\nimport execute from 'rollup-plugin-execute';\nimport json from '@rollup/plugin-json';\nimport sourcemaps from 'rollup-plugin-sourcemaps';\nimport { exec } from 'child_process';\nimport fs from 'fs';\nimport { brotliCompress } from 'zlib';\nimport { promisify } from 'util';\n\nconst brotliPromise = promisify(brotliCompress);\n\n// The paths are relative to process.cwd(), which are packages/*\nconst base = '../..';\n\nconst createSnippet = () => {\n  return {\n    name: 'amplitude-snippet',\n    options: (opt) => {\n      return new Promise((resolve) => {\n        opt.input = 'generated/amplitude-snippet.js';\n        if (process.env.GENERATE_SNIPPET !== 'true') return resolve(opt);\n        exec(`node ${base}/scripts/version/create-snippet.js`, (err) => {\n          if (err) {\n            throw err;\n          }\n          resolve(opt);\n        });\n      });\n    },\n  };\n};\n\nexport const umd = {\n  input: 'src/index.ts',\n  output: {\n    name: 'amplitude',\n    file: 'lib/scripts/amplitude-min.umd.js',\n    format: 'umd',\n  },\n  plugins: [\n    typescript({\n      module: 'es2020',\n      noEmit: false,\n      outDir: 'lib/umd',\n      rootDir: 'src',\n    }),\n    resolve({\n      browser: true,\n    }),\n    commonjs(),\n    terser({\n      output: {\n        comments: false,\n      },\n    }),\n    gzip(),\n  ],\n};\n\nconst updateLibPrefix = (isUndo) => {\n  const path = 'src/lib-prefix.ts'\n  if (!fs.existsSync(path)) {\n    // Supported in rollup 4, we're currently rollup 2\n    // this.error(`File not found: ${path}`);\n    return;\n  }\n\n  let content = fs.readFileSync(path, 'utf-8');\n  let updatedContent;\n  if (isUndo) {\n    updatedContent = content.replace(/amplitude-ts-sdk-script/g, 'amplitude-ts');\n  } else {\n    updatedContent = content.replace(/amplitude-ts/g, 'amplitude-ts-sdk-script');\n  }\n\n  fs.writeFileSync(path, updatedContent, 'utf-8');\n  // Supported in rollup 4, we're currently rollup 2\n  // this.info(`File updated: ${path}`);\n}\n\n\nconst updateLibPrefixPlugin = () => {\n  return {\n    name: 'update-lib-prefix',\n    buildStart() {\n      updateLibPrefix(false);\n    },\n    buildEnd() {\n      updateLibPrefix(true);\n    }\n  };\n}\n\nexport const iife = {\n  input: 'src/snippet-index.ts',\n  output: {\n    name: 'amplitude',\n    file: 'lib/scripts/amplitude-min.js',\n    format: 'iife',\n    sourcemap: true,\n  },\n  plugins: [\n    updateLibPrefixPlugin(),\n    typescript({\n      module: 'es2020',\n      noEmit: false,\n      outDir: 'lib/script',\n      rootDir: 'src',\n    }),\n    resolve({\n      browser: true,\n    }),\n    commonjs(),\n    // Flatten source maps: Dependencies like @amplitude/analytics-core are pre-compiled by\n    // TypeScript to lib/esm/*.js with corresponding lib/esm/*.js.map files that point back to\n    // the original .ts sources. When Rollup bundles these, the sourcemaps() plugin reads those\n    // intermediate source maps and chains them together. The result is a final source map that\n    // points directly to the original .ts files, enabling one-step unminification from CDN.\n    // Note: lib/cjs/ is for Node.js and not used in the browser IIFE bundle.\n    sourcemaps(),\n    terser({\n      output: {\n        comments: false,\n      },\n    }),\n    gzip(),\n  ],\n};\n\nexport const snippet = {\n  output: {\n    name: 'amplitude',\n    file: 'lib/scripts/amplitude-snippet-min.js',\n    format: 'iife',\n  },\n  plugins: [\n    createSnippet(),\n    terser(),\n    execute(\n      `node ${base}/scripts/version/create-snippet-instructions.js && node ${base}/scripts/version/update-readme.js`,\n    ),\n  ],\n};\n\nconst createGTMSnippet = () => {\n  return {\n    name: 'amplitude-gtm-snippet',\n    options: (opt) => {\n      return new Promise((resolve) => {\n        opt.input = 'generated/amplitude-gtm-snippet.js';\n        if (process.env.GENERATE_SNIPPET !== 'true') return resolve(opt);\n        exec(\n          `node ${base}/scripts/version/create-snippet.js --inputFile=amplitude-gtm-min.js --outputFile=amplitude-gtm-snippet.js --globalVar=amplitudeGTM --nameSuffix=-gtm`,\n          (err) => {\n            if (err) {\n              throw err;\n            }\n            resolve(opt);\n          },\n        );\n      });\n    },\n  };\n};\n\nexport const iifeGTM = {\n  input: 'src/gtm-snippet-index.ts',\n  output: {\n    name: 'amplitudeGTM',\n    file: 'lib/scripts/amplitude-gtm-min.js',\n    format: 'iife',\n    sourcemap: true,\n  },\n  plugins: [\n    typescript({\n      module: 'es2020',\n      noEmit: false,\n      outDir: 'lib/script',\n      rootDir: 'src',\n    }),\n    resolve({\n      browser: true,\n    }),\n    commonjs(),\n    // Flatten source maps: Dependencies like @amplitude/analytics-core are pre-compiled by\n    // TypeScript to lib/esm/*.js with corresponding lib/esm/*.js.map files that point back to\n    // the original .ts sources. When Rollup bundles these, the sourcemaps() plugin reads those\n    // intermediate source maps and chains them together. The result is a final source map that\n    // points directly to the original .ts files, enabling one-step unminification from CDN.\n    // Note: lib/cjs/ is for Node.js and not used in the browser IIFE bundle.\n    sourcemaps(),\n    terser({\n      output: {\n        comments: false,\n      },\n    }),\n    gzip(),\n  ],\n};\n\nexport const snippetGTM = {\n  output: {\n    name: 'amplitudeGTM', // the name of the window variable\n    file: 'lib/scripts/amplitude-gtm-snippet-min.js',\n    format: 'iife',\n  },\n  plugins: [createGTMSnippet(), terser()],\n};\n\n// Input: bookmarklet js template + amplitude js\n// Output: bookmarklet js snippet\nconst createBookmarkletSnippet = () => {\n  return {\n    name: 'amplitude-bookmarklet-snippet',\n    options: (opt) => {\n      return new Promise((resolve) => {\n        opt.input = 'generated/amplitude-bookmarklet-snippet.js';\n        if (process.env.GENERATE_SNIPPET !== 'true') return resolve(opt);\n        exec(`node ${base}/scripts/version/create-bookmarklet-snippet.js`, (err) => {\n          if (err) {\n            throw err;\n          }\n          resolve(opt);\n        });\n      });\n    },\n  };\n};\n\n// Input: bookmarklet js snippet\n// Output: bookmarklet prefix + bookmarklet js snippet (url encoded)\nexport const bookmarklet = {\n  output: {\n    name: 'amplitude',\n    file: 'lib/scripts/amplitude-bookmarklet-snippet-min.js',\n    format: 'iife',\n  },\n  plugins: [createBookmarkletSnippet(), terser(), execute(`node ${base}/scripts/version/create-bookmarklet.js`)],\n};\n\nexport const gtmSnippetBundle = {\n  input: 'lib/amplitude-wrapper.js', // TODO: move this around\n  output: {\n    name: 'amplitudeGTM',\n    file: 'lib/scripts/analytics-browser-gtm-wrapper.min.js',\n    format: 'iife',\n    sourcemap: true,\n  },\n  plugins: [\n    terser({\n      output: {\n        comments: false,\n      },\n    }),\n    gzip(),\n    gzip({\n      customCompression: (content) => brotliPromise(Buffer.from(content)),\n      fileName: '.br',\n    }),\n    json(),\n  ],\n}\n"
  },
  {
    "path": "scripts/check-deprecated-packages.sh",
    "content": "#!/bin/bash\n\n# Script to check for new usage of deprecated packages in PRs\n# Exits with error if:\n# - New dependencies on deprecated packages are detected\n# - Code changes are made to deprecated package directories\n\nset -e\n\nDEPRECATED_PACKAGES=(\"@amplitude/analytics-types\" \"@amplitude/analytics-client-common\" \"@amplitude/analytics-remote-config\")\nDEPRECATED_PACKAGE_DIRS=(\"packages/analytics-types\" \"packages/analytics-client-common\")\nFAILED=0\n\necho \"Checking for new usage of deprecated packages...\"\n\n# Check for code changes in deprecated package directories\necho \"Checking for code changes in deprecated packages...\"\nfor DIR in \"${DEPRECATED_PACKAGE_DIRS[@]}\"; do\n  CHANGED_IN_DIR=$(git diff --name-only origin/${GITHUB_BASE_REF:-main}...HEAD | grep \"^$DIR/\" || true)\n  \n  if [ -n \"$CHANGED_IN_DIR\" ]; then\n    echo \"❌ ERROR: Code changes detected in deprecated package '$DIR'\"\n    echo \"Changed files:\"\n    echo \"$CHANGED_IN_DIR\" | sed 's/^/   - /'\n    echo \"\"\n    FAILED=1\n  fi\ndone\n\n# Get the list of changed package.json files\nCHANGED_FILES=$(git diff --name-only origin/${GITHUB_BASE_REF:-main}...HEAD | grep 'package.json$' || true)\n\nif [ -z \"$CHANGED_FILES\" ]; then\n  echo \"✓ No package.json files changed\"\nelse\n  echo \"Changed package.json files:\"  \n  echo \"$CHANGED_FILES\"\n  echo \"\"\nfi\n\nfor FILE in $CHANGED_FILES; do\n  if [ ! -f \"$FILE\" ]; then\n    echo \"Skipping deleted file: $FILE\"\n    continue\n  fi\n\n  echo \"Checking $FILE...\"\n  \n  for PACKAGE in \"${DEPRECATED_PACKAGES[@]}\"; do\n    # Check if the package is present in the current version\n    CURRENT_HAS=$(grep -c \"\\\"$PACKAGE\\\"\" \"$FILE\" || true)\n    \n    # Check if the package was present in the base branch\n    BASE_HAS=$(git show origin/${GITHUB_BASE_REF:-main}:\"$FILE\" 2>/dev/null | grep -c \"\\\"$PACKAGE\\\"\" || true)\n    \n    # If it's newly added (present now but not before)\n    if [ \"$CURRENT_HAS\" -gt 0 ] && [ \"$BASE_HAS\" -eq 0 ]; then\n      echo \"❌ ERROR: New dependency on deprecated package '$PACKAGE' detected in $FILE\"\n      if [ \"$PACKAGE\" = \"@amplitude/analytics-remote-config\" ]; then\n        echo \"   Please use the new remote config client in @amplitude/analytics-core instead\"\n      else\n        echo \"   Please use @amplitude/analytics-core instead\"\n      fi\n      FAILED=1\n    elif [ \"$CURRENT_HAS\" -gt 0 ] && [ \"$BASE_HAS\" -gt 0 ]; then\n      echo \"   ℹ️  Existing dependency on '$PACKAGE' found (grandfathered in)\"\n    fi\n  done\ndone\n\nif [ \"$FAILED\" -eq 1 ]; then\n  echo \"\"\n  echo \"==========================================\"\n  echo \"DEPRECATED PACKAGE CHECK FAILED\"\n  echo \"==========================================\"\n  echo \"The following packages are deprecated:\"\n  for PACKAGE in \"${DEPRECATED_PACKAGES[@]}\"; do\n    echo \"  - $PACKAGE\"\n  done\n  echo \"\"\n  echo \"Restrictions:\"\n  echo \"  • No new dependencies on these packages are allowed\"\n  echo \"  • No code changes to packages/analytics-types or packages/analytics-client-common are allowed\"\n  echo \"\"\n  echo \"For @amplitude/analytics-types and @amplitude/analytics-client-common:\"\n  echo \"  → Use @amplitude/analytics-core instead\"\n  echo \"\"\n  echo \"For @amplitude/analytics-remote-config:\"\n  echo \"  → Use the new remote config client in @amplitude/analytics-core instead\"\n  echo \"\"\n  echo \"If you believe this is a false positive, please contact the team.\"\n  exit 1\nfi\n\necho \"\"\necho \"✓ No new usage of deprecated packages detected\"\necho \"✓ No code changes in deprecated packages detected\"\nexit 0\n\n"
  },
  {
    "path": "scripts/dev/generate-signed-cert.sh",
    "content": "#!/bin/bash\n\nCERT_DIR=~/certs/local-website\nCERT_FILE=$CERT_DIR/cert.pem\nKEY_FILE=$CERT_DIR/key.pem\n\necho \"\"\necho \"Step 2: Checking SSL certificates...\"\n\n# Check if certificates already exist\nif [ -f \"$CERT_FILE\" ] && [ -f \"$KEY_FILE\" ]; then\n    echo \"✓ SSL certificates already exist\"\n    exit 0\nfi\n\necho \"\"\necho \"🔐 Generating SSL certificates for local.website.com...\"\necho \"   (This may take a moment)\"\necho \"\"\n\nmkdir -p \"$CERT_DIR\"\ncd \"$CERT_DIR\"\n\nopenssl req -x509 -out cert.pem -keyout key.pem \\\n  -newkey rsa:2048 -nodes -sha256 \\\n  -subj \"/CN=local.website.com\" \\\n  -addext \"subjectAltName=DNS:local.website.com\" \\\n  -days 365 2>/dev/null\n\nif [ $? -eq 0 ]; then\n    echo \"\"\n    echo \"✓ SSL certificates generated successfully\"\n    echo \"\"\n    echo \"📍 Certificates location: $CERT_DIR\"\n    echo \"\"\n    echo \"⚠️  Note: Your browser will show a security warning because this is a\"\n    echo \"   self-signed certificate. Click 'Advanced' and proceed anyway, or\"\n    echo \"   trust the certificate in your system keychain.\"\nelse\n    echo \"✗ Failed to generate SSL certificates\"\n    exit 1\nfi"
  },
  {
    "path": "scripts/dev/setup-dev-ssh.sh",
    "content": "#!/bin/bash\n\n# Run setup scripts\nsh ./scripts/dev/setup-local-domain.sh\nif [ $? -ne 0 ]; then\n    exit 1\nfi\n\nsh ./scripts/dev/generate-signed-cert.sh\nif [ $? -ne 0 ]; then\n    exit 1\nfi\n\n# Show completion message\necho \"\"\necho \"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\"\necho \"✅ Setup complete! Ready for HTTPS development.\"\necho \"\"\necho \"🚀 Starting dev server at https://local.website.com:5173\"\necho \"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\"\necho \"\"\n\n"
  },
  {
    "path": "scripts/dev/setup-local-domain.sh",
    "content": "#!/bin/bash\n\n# Script to setup local.website.com domain in /etc/hosts\nDOMAIN=\"local.website.com\"\nHOSTS_FILE=\"/etc/hosts\"\nHOSTS_ENTRY=\"127.0.0.1 $DOMAIN\"\n\necho \"\"\necho \"🔧 Setting up local HTTPS development environment...\"\necho \"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\"\necho \"\"\necho \"Step 1: Checking if $DOMAIN is configured...\"\n\n# Check if the domain already exists in hosts file\nif grep -q \"$DOMAIN\" \"$HOSTS_FILE\"; then\n    echo \"✓ $DOMAIN is already configured\"\n    exit 0\nelse\n    echo \"✗ $DOMAIN not found in $HOSTS_FILE\"\n    echo \"\"\n    echo \"📝 Adding $DOMAIN to $HOSTS_FILE...\"\n    echo \"   (This requires sudo - you may be prompted for your password)\"\n    echo \"\"\n    \n    # Add the entry to hosts file\n    echo \"$HOSTS_ENTRY\" | sudo tee -a \"$HOSTS_FILE\" > /dev/null\n    \n    if [ $? -eq 0 ]; then\n        echo \"✓ Successfully added $DOMAIN to $HOSTS_FILE\"\n    else\n        echo \"✗ Failed to add $DOMAIN to $HOSTS_FILE\"\n        exit 1\n    fi\nfi\n\n"
  },
  {
    "path": "scripts/publish/check-ref-not-advanced.sh",
    "content": "#!/bin/bash\n\n# Guard against the race where a PR merges to the publish ref between\n# the e2e job's checkout and the lerna version push. If the ref has\n# advanced past the SHA E2E ran against, the chore(release): publish\n# commit would land on top of code this run never tested in E2E, making\n# the git history misleading. Re-dispatch is the right recovery — it\n# re-runs E2E against the new HEAD.\n#\n# Required env vars:\n#   EXPECTED_SHA - the SHA the ref is expected to still be at\n#                  (typically the e2e job's HEAD after checkout)\n#   REF          - the branch name to compare against (e.g. main)\n\nset -euo pipefail\n\nif [ -z \"${EXPECTED_SHA:-}\" ] || [ -z \"${REF:-}\" ]; then\n  echo \"❌ EXPECTED_SHA and REF must be set in the environment.\"\n  exit 1\nfi\n\n# Validate REF as a branch name to prevent it being interpreted as a git\n# flag (e.g. a value starting with '-') or a tag with the same short name.\nif ! git check-ref-format --branch \"$REF\" >/dev/null 2>&1; then\n  echo \"❌ REF is not a valid branch name: $REF\"\n  exit 1\nfi\n\n# Read the current remote SHA directly. A plain `git fetch <refspec>`\n# without an explicit destination is not guaranteed to update\n# refs/remotes/origin/$REF, so reading the remote-tracking ref afterwards\n# can return a stale SHA and defeat the guard. Capture the command's\n# exit status explicitly so transient/auth failures surface a\n# diagnosable error rather than just a bare non-zero exit from set -e.\n# stderr is left to flow to the runner log so git's own error message\n# (auth failure, network error, etc.) is visible above our own.\nif ! LS_OUTPUT=$(git ls-remote origin \"refs/heads/$REF\"); then\n  echo \"❌ git ls-remote failed for origin refs/heads/$REF (see error above)\"\n  exit 1\nfi\n\nREMOTE_SHA=$(echo \"$LS_OUTPUT\" | awk '{print $1}')\n\nif [ -z \"$REMOTE_SHA\" ]; then\n  echo \"❌ Could not resolve remote SHA for refs/heads/$REF on origin\"\n  exit 1\nfi\n\nif [ \"$REMOTE_SHA\" != \"$EXPECTED_SHA\" ]; then\n  echo \"❌ $REF has advanced since this run's E2E checkout.\"\n  echo \"   Expected SHA: $EXPECTED_SHA\"\n  echo \"   Current $REF: $REMOTE_SHA\"\n  echo \"\"\n  echo \"A commit landed on $REF while this workflow was running. The\"\n  echo \"chore(release): publish commit would appear after it in history,\"\n  echo \"falsely implying the new commit was tested by this run's E2E.\"\n  echo \"\"\n  echo \"Re-dispatch this workflow to include the new commits and re-run E2E.\"\n  exit 1\nfi\n\necho \"✅ $REF is still at expected SHA: $EXPECTED_SHA\"\n"
  },
  {
    "path": "scripts/publish/upload-to-s3.js",
    "content": "const fs = require('fs');\nconst path = require('path');\nconst { S3Client, PutObjectCommand, HeadObjectCommand } = require('@aws-sdk/client-s3');\nconst { getName, getVersion } = require('../utils');\n\nconst bucket = process.env.S3_BUCKET_NAME;\nconst location = path.join(process.cwd(), 'lib', 'scripts');\nconst isAnalyticsBrowser = location.includes('analytics-browser');\n\n// Minified JS files to upload (gzipped)\nconst jsFiles = ['amplitude-min.js.gz', 'amplitude-min.umd.js.gz'];\nif (isAnalyticsBrowser) {\n  jsFiles.push('amplitude-gtm-min.js.gz');\n}\n\n// Source map files to upload (for stack trace unminification)\nconst sourceMapFiles = ['amplitude-min.js.map'];\nif (isAnalyticsBrowser) {\n  sourceMapFiles.push('amplitude-gtm-min.js.map');\n}\n\nlet deployedCount = 0;\nlet totalFiles = 0;\n\n/**\n * Upload a file to S3 if it doesn't already exist\n */\nasync function uploadFile(file, contentType, contentEncoding) {\n  const filePath = path.join(location, file);\n  \n  if (!fs.existsSync(filePath)) {\n    console.log(`[Publish to AWS S3] ${file} not found. Skipping.`);\n    return;\n  }\n\n  totalFiles++;\n  const body = fs.readFileSync(filePath);\n  const isGtm = file.includes('-gtm-');\n  const suffix = isGtm ? `-gtm` : ``;\n  const replacement = isGtm ? `amplitude-gtm` : `amplitude`;\n  const key = `libs/${file.replace(replacement, `${getName()}${suffix}-${getVersion()}`)}`;\n  const client = new S3Client();\n\n  const headObject = new HeadObjectCommand({\n    Bucket: bucket,\n    Key: key,\n  });\n\n  console.log(`[Publish to AWS S3] Checking if ${key} exists in target bucket...`);\n\n  try {\n    await client.send(headObject);\n    console.log(`[Publish to AWS S3] ${key} exists in target bucket. Skipping upload.`);\n  } catch {\n    console.log(`[Publish to AWS S3] ${key} does not exist. Uploading to S3...`);\n    const putObjectParams = {\n      ACL: 'public-read',\n      Body: body,\n      Bucket: bucket,\n      CacheControl: 'max-age=31536000',\n      ContentType: contentType,\n      Key: key,\n    };\n    if (contentEncoding) {\n      putObjectParams.ContentEncoding = contentEncoding;\n    }\n    const putObject = new PutObjectCommand(putObjectParams);\n    try {\n      await client.send(putObject);\n      console.log(`[Publish to AWS S3] Upload success for ${key}.`);\n      deployedCount++;\n    } catch (err) {\n      console.error(`[Publish to AWS S3] Upload failed for ${key}:`, err.message);\n    }\n  }\n}\n\nasync function main() {\n  console.log('[Publish to AWS S3] START');\n  console.log(`[Publish to AWS S3] Package: ${getName()} v${getVersion()}`);\n\n  // Upload minified JS files (gzipped)\n  for (const file of jsFiles) {\n    await uploadFile(file, 'application/javascript', 'gzip');\n  }\n\n  // Upload source map files (for stack trace unminification)\n  for (const file of sourceMapFiles) {\n    await uploadFile(file, 'application/json', null);\n  }\n\n  if (deployedCount === 0) {\n    console.log(`[Publish to AWS S3] Complete! Nothing to deploy.`);\n  } else {\n    console.log(`[Publish to AWS S3] Success! Deployed ${deployedCount}/${totalFiles} files.`);\n  }\n  console.log('[Publish to AWS S3] END');\n}\n\nmain().catch((err) => {\n  console.error('[Publish to AWS S3] Error:', err);\n  process.exit(1);\n});\n"
  },
  {
    "path": "scripts/templates/browser-bookmarklet.template.js",
    "content": "const snippet = (\n  name,\n  integrity,\n  version,\n  globalVar,\n  apiKey,\n  userId,\n  serverZone,\n  ingestionSourceName,\n  ingestionSourceVersion,\n  autoTrackingPluginVersion,\n) => `\n!(function (window, document) {\n  var amplitude = window.${globalVar} || { _q: [], _iq: {} };\n  if (amplitude.invoked) window.console && console.error && console.error('Amplitude snippet has been loaded.');\n  else {\n    amplitude.invoked = true;\n    var s = document.getElementsByTagName('script')[0];\n    var autoTrackingPluginScript = document.createElement('script');\n    autoTrackingPluginScript.src = 'https://cdn.amplitude.com/libs/plugin-autocapture-browser-${autoTrackingPluginVersion}-min.js.gz';\n    autoTrackingPluginScript.async = false;\n    s.parentNode.insertBefore(autoTrackingPluginScript, s);\n    var as = document.createElement('script');\n    as.type = 'text/javascript';\n    as.integrity = '${integrity}';\n    as.crossOrigin = 'anonymous';\n    as.async = false;\n    as.src = 'https://cdn.amplitude.com/libs/${name}-${version}-min.js.gz';\n    as.onload = function () {\n      if (!window.${globalVar}.runQueuedFunctions) {\n        console.log('[Amplitude] Error: could not load SDK');\n      }\n      window.${globalVar}.init('${apiKey}', '${userId}', {\n        instanceName: 'amplitude-bookmarklet',\n        serverZone: '${serverZone}',\n        ingestionMetadata: {\n          sourceName: '${ingestionSourceName}',\n          sourceVersion: '${ingestionSourceVersion}',\n        },\n        optOut: false,\n      });\n      if (amplitudeAutocapturePlugin && amplitudeAutocapturePlugin.autocapturePlugin && typeof amplitudeAutocapturePlugin.autocapturePlugin === 'function') {\n        window.${globalVar}.add(amplitudeAutocapturePlugin.autocapturePlugin());\n      }\n      alert('Amplitude is now tracking events!');\n    };\n    s.parentNode.insertBefore(as, s);\n    function proxy(obj, fn) {\n      obj.prototype[fn] = function () {\n        this._q.push({\n          name: fn,\n          args: Array.prototype.slice.call(arguments, 0),\n        });\n        return this;\n      };\n    }\n    var Identify = function () {\n      this._q = [];\n      return this;\n    };\n    var identifyFuncs = [\n      'add',\n      'append',\n      'clearAll',\n      'prepend',\n      'set',\n      'setOnce',\n      'unset',\n      'preInsert',\n      'postInsert',\n      'remove',\n      'getUserProperties',\n    ];\n    for (var i = 0; i < identifyFuncs.length; i++) {\n      proxy(Identify, identifyFuncs[i]);\n    }\n    amplitude.Identify = Identify;\n    var Revenue = function () {\n      this._q = [];\n      return this;\n    };\n    var revenueFuncs = [\n      'getEventProperties',\n      'setProductId',\n      'setQuantity',\n      'setPrice',\n      'setRevenue',\n      'setRevenueType',\n      'setReceipt',\n      'setReceiptSig',\n      'setCurrency',\n      'setEventProperties',\n    ];\n    for (var j = 0; j < revenueFuncs.length; j++) {\n      proxy(Revenue, revenueFuncs[j]);\n    }\n    amplitude.Revenue = Revenue;\n    var funcs = [\n      'getDeviceId',\n      'setDeviceId',\n      'getSessionId',\n      'setSessionId',\n      'getUserId',\n      'setUserId',\n      'setOptOut',\n      'setTransport',\n      'reset',\n      'extendSession',\n    ];\n    var funcsWithPromise = [\n      'init',\n      'add',\n      'remove',\n      'track',\n      'logEvent',\n      'identify',\n      'groupIdentify',\n      'setGroup',\n      'revenue',\n      'flush',\n    ];\n    function getPromiseResult(instance, fn, args) {\n      return function (resolve) {\n        instance._q.push({\n          name: fn,\n          args: Array.prototype.slice.call(args, 0),\n          resolve: resolve,\n        });\n      };\n    }\n    function proxyMain(instance, fn, isPromise) {\n      instance[fn] = function () {\n        if (isPromise) return {\n          promise: new Promise(getPromiseResult(instance, fn, Array.prototype.slice.call(arguments))),\n        };\n      };\n    }\n    function setUpProxy(instance) {\n      for (var k = 0; k < funcs.length; k++) {\n        proxyMain(instance, funcs[k], false);\n      }\n      for (var l = 0; l < funcsWithPromise.length; l++) {\n        proxyMain(instance, funcsWithPromise[l], true);\n      }\n    }\n    setUpProxy(amplitude);\n    amplitude.createInstance = function (instanceName) {\n      amplitude._iq[instanceName] = { _q: [] };\n      setUpProxy(amplitude._iq[instanceName]);\n      return amplitude._iq[instanceName];\n    };\n    window.${globalVar} = amplitude;\n    ${\n      globalVar !== 'amplitude'\n        ? `if (!window.amplitude) {\n      window.amplitude = window.${globalVar};\n    }`\n        : ``\n    }\n  }\n})(window, document);\n`;\n\nexports.snippet = snippet;\n"
  },
  {
    "path": "scripts/templates/browser-snippet.template.js",
    "content": "const snippet = (name, integrity, version, globalVar) => `\n!(function (window, document) {\n  var amplitude = window.${globalVar} || { _q: [], _iq: {} };\n  if (amplitude.invoked) window.console && console.error && console.error('Amplitude snippet has been loaded.');\n  else {\n    amplitude.invoked = true;\n    var as = document.createElement('script');\n    as.type = 'text/javascript';\n    as.integrity = '${integrity}';\n    as.crossOrigin = 'anonymous';\n    as.async = true;\n    as.src = 'https://cdn.amplitude.com/libs/${name}-${version}-min.js.gz';\n    as.onload = function () {\n      if (!window.${globalVar}.runQueuedFunctions) {\n        console.log('[Amplitude] Error: could not load SDK');\n      }\n    };\n    var s = document.getElementsByTagName('script')[0];\n    s.parentNode.insertBefore(as, s);\n    function proxy(obj, fn) {\n      obj.prototype[fn] = function () {\n        this._q.push({\n          name: fn,\n          args: Array.prototype.slice.call(arguments, 0),\n        });\n        return this;\n      };\n    }\n    var Identify = function () {\n      this._q = [];\n      return this;\n    };\n    var identifyFuncs = [\n      'add',\n      'append',\n      'clearAll',\n      'prepend',\n      'set',\n      'setOnce',\n      'unset',\n      'preInsert',\n      'postInsert',\n      'remove',\n      'getUserProperties',\n    ];\n    for (var i = 0; i < identifyFuncs.length; i++) {\n      proxy(Identify, identifyFuncs[i]);\n    }\n    amplitude.Identify = Identify;\n    var Revenue = function () {\n      this._q = [];\n      return this;\n    };\n    var revenueFuncs = [\n      'getEventProperties',\n      'setProductId',\n      'setQuantity',\n      'setPrice',\n      'setRevenue',\n      'setRevenueType',\n      'setReceipt',\n      'setReceiptSig',\n      'setCurrency',\n      'setEventProperties',\n    ];\n    for (var j = 0; j < revenueFuncs.length; j++) {\n      proxy(Revenue, revenueFuncs[j]);\n    }\n    amplitude.Revenue = Revenue;\n    var funcs = [\n      'getDeviceId',\n      'setDeviceId',\n      'getSessionId',\n      'setSessionId',\n      'getUserId',\n      'setUserId',\n      'setOptOut',\n      'setTransport',\n      'reset',\n      'extendSession',\n    ];\n    var funcsWithPromise = [\n      'init',\n      'add',\n      'remove',\n      'track',\n      'logEvent',\n      'identify',\n      'groupIdentify',\n      'setGroup',\n      'revenue',\n      'flush',\n    ];\n    function getPromiseResult(instance, fn, args) {\n      return function (resolve) {\n        instance._q.push({\n          name: fn,\n          args: Array.prototype.slice.call(args, 0),\n          resolve: resolve,\n        });\n      };\n    }\n    function proxyInstance(instance, fn, args) {\n      instance._q.push({\n        name: fn,\n        args: Array.prototype.slice.call(args, 0),\n      });\n    }\n    function proxyMain(instance, fn, isPromise) {\n      instance[fn] = function () {\n        if (isPromise) return {\n          promise: new Promise(getPromiseResult(instance, fn, Array.prototype.slice.call(arguments))),\n        };\n        proxyInstance(instance, fn, Array.prototype.slice.call(arguments));\n      };\n    }\n    function setUpProxy(instance) {\n      for (var k = 0; k < funcs.length; k++) {\n        proxyMain(instance, funcs[k], false);\n      }\n      for (var l = 0; l < funcsWithPromise.length; l++) {\n        proxyMain(instance, funcsWithPromise[l], true);\n      }\n    }\n    setUpProxy(amplitude);\n    amplitude.createInstance = function (instanceName) {\n      amplitude._iq[instanceName] = { _q: [] };\n      setUpProxy(amplitude._iq[instanceName]);\n      return amplitude._iq[instanceName];\n    };\n    window.${globalVar} = amplitude;\n    ${\n      globalVar !== 'amplitude'\n        ? `if (!window.amplitude) {\n      window.amplitude = window.${globalVar};\n    }`\n        : ``\n    }\n  }\n})(window, document);\n`;\n\nexports.snippet = snippet;\n"
  },
  {
    "path": "scripts/utils.js",
    "content": "const path = require('path');\nconst pkg = require(path.join(process.cwd(), 'package.json'));\n\nexports.getName = () => pkg.name.substring('@amplitude/'.length);\n\nexports.getVersion = () => pkg.version;\n"
  },
  {
    "path": "scripts/version/create-bookmarklet-snippet.js",
    "content": "const crypto = require('crypto');\nconst fs = require('fs');\nconst path = require('path');\nconst { snippet } = require('../templates/browser-bookmarklet.template');\nconst { getName, getVersion } = require('../utils');\nconst babel = require('@babel/core');\nconst yargs = require('yargs/yargs');\nconst { hideBin } = require('yargs/helpers');\nconst argv = yargs(hideBin(process.argv)).argv;\n\n// Setup input\nconst inputDir = 'lib/scripts';\nconst inputFile = argv.inputFile ?? 'amplitude-min.js';\nconst inputPath = path.join(process.cwd(), inputDir, inputFile);\n\n// Setup output\nconst outputDir = 'generated/';\nconst outputFile = argv.outputFile ?? 'amplitude-bookmarklet-snippet.js';\nconst outputPath = path.join(process.cwd(), outputDir, outputFile);\n\nconst globalVar = argv.globalVar ?? 'amplitude';\nconst nameSuffix = argv.nameSuffix ?? '';\n\nconst apiKey = argv.apiKey ?? 'YOUR_API_KEY';\nconst userId = argv.userId ?? 'YOUR_USER_ID';\nconst serverZone = argv.serverZone ?? 'YOUR_SERVER_ZONE';\n\n// Generate output contents\nconst header = `/**\n * Create a bookmark with this code snippet in the browser, update the apiKey, userId, and serverZone, and click the bookmark on any website to run.\n * Script will fail to load if the website has a Content Security Policy (CSP) that blocks third-party inline scripts.\n */`;\nconst algorithm = 'sha384';\nconst encoding = 'base64';\nconst inputText = fs.readFileSync(inputPath, 'utf-8');\nconst integrity = algorithm + '-' + crypto.createHash(algorithm).update(inputText).digest(encoding);\nconst version = getVersion() || '';\nconst ingestionSourceName = 'browser-typescript-bookmarklet';\nconst ingestionSourceVersion = '1.0.0';\nconst autoTrackingPluginVersion = '0.9.0';\nconst outputText =\n  header +\n  snippet(\n    getName() + nameSuffix,\n    integrity,\n    version,\n    globalVar,\n    apiKey,\n    userId,\n    serverZone,\n    ingestionSourceName,\n    ingestionSourceVersion,\n    autoTrackingPluginVersion,\n  );\nconst { code: transpiledOutputText } = babel.transformSync(outputText, {\n  presets: ['env'],\n});\n\n// Write to disk\nfs.writeFileSync(outputPath, transpiledOutputText);\nconsole.log(`Generated ${outputFile}`);\n"
  },
  {
    "path": "scripts/version/create-bookmarklet.js",
    "content": "const fs = require('fs');\nconst path = require('path');\n\nconst cwd = process.cwd();\n\n// Setup input\nconst inputDir = 'lib/scripts';\nconst inputFile = 'amplitude-bookmarklet-snippet-min.js';\nconst inputPath = path.join(cwd, inputDir, inputFile);\n\n// Setup output\nconst outputDir = 'lib/scripts';\nconst outputFile = 'amplitude-bookmarklet.html';\nconst outputPath = path.join(cwd, outputDir, outputFile);\n\n// Generate output contents\nconst inputText = fs.readFileSync(inputPath, 'utf-8');\nconst outputText = `javascript:${encodeURIComponent(inputText)}`;\n\n// Write to disk\nfs.writeFileSync(outputPath, outputText);\n\nconsole.log(`Generated ${outputFile}`);\n"
  },
  {
    "path": "scripts/version/create-snippet-instructions.js",
    "content": "const fs = require('fs');\nconst path = require('path');\n\nconst cwd = process.cwd();\n\n// Setup input\nconst inputDir = 'lib/scripts';\nconst inputFile = 'amplitude-snippet-min.js';\nconst inputPath = path.join(cwd, inputDir, inputFile);\n\n// Setup output\nconst outputDir = 'lib/scripts';\nconst outputFile = 'amplitude-snippet-instructions.html';\nconst outputPath = path.join(cwd, outputDir, outputFile);\n\n// Generate output contents\nconst inputText = fs.readFileSync(inputPath, 'utf-8');\nconst outputText = `<script type=\"text/javascript\">\n${inputText}\namplitude.init(\"<YOUR_API_KEY>\");\n</script>\n`;\n\n// Write to disk\nfs.writeFileSync(outputPath, outputText);\n\nconsole.log(`Generated ${outputFile}`);\n"
  },
  {
    "path": "scripts/version/create-snippet.js",
    "content": "const crypto = require('crypto');\nconst fs = require('fs');\nconst path = require('path');\nconst { snippet } = require('../templates/browser-snippet.template');\nconst { getName, getVersion } = require('../utils');\nconst babel = require('@babel/core');\nconst yargs = require('yargs/yargs');\nconst { hideBin } = require('yargs/helpers');\nconst argv = yargs(hideBin(process.argv)).argv;\n\n// Setup input\nconst inputDir = 'lib/scripts';\nconst inputFile = argv.inputFile ?? 'amplitude-min.js';\nconst inputPath = path.join(process.cwd(), inputDir, inputFile);\n\n// Setup output\nconst outputDir = 'generated/';\nconst outputFile = argv.outputFile ?? 'amplitude-snippet.js';\nconst outputPath = path.join(process.cwd(), outputDir, outputFile);\n\nconst globalVar = argv.globalVar ?? 'amplitude';\nconst nameSuffix = argv.nameSuffix ?? '';\n\n// Generate output contents\nconst header = `/**\n * Imported in client browser via <script> tag\n * Async capabilities: Interally creates stubbed window.${globalVar} object until real SDK loaded\n * Stubbed functions keep track of funciton calls and their arguments\n * These are sent once real SDK loaded through another <script> tag\n */`;\nconst algorithm = 'sha384';\nconst encoding = 'base64';\nconst inputText = fs.readFileSync(inputPath, 'utf-8');\nconst integrity = algorithm + '-' + crypto.createHash(algorithm).update(inputText).digest(encoding);\nconst version = getVersion() || '';\nconst outputText = header + snippet(getName() + nameSuffix, integrity, version, globalVar);\nconst { code: transpiledOutputText } = babel.transformSync(outputText, {\n  presets: ['env'],\n});\n\n// Write to disk\nfs.writeFileSync(outputPath, transpiledOutputText);\nconsole.log(`Generated ${outputFile}`);\n"
  },
  {
    "path": "scripts/version/update-readme.js",
    "content": "const fs = require('fs');\nconst path = require('path');\n\n// Setup input\nconst inputDir = 'lib/scripts';\nconst inputFile = 'amplitude-snippet-instructions.html';\nconst inputPath = path.join(process.cwd(), inputDir, inputFile);\n\n// Setup output\nconst outputDir = '';\nconst outputFile = 'README.md';\nconst outputPath = path.join(process.cwd(), outputDir, outputFile);\n\n// Generate output contents\nconst inputText = fs.readFileSync(inputPath, 'utf-8');\nconst oldOutputText = fs.readFileSync(outputPath, 'utf-8');\nconst regexpPattern = /(<!-- README_SNIPPET_BLOCK -->)((?:.|\\n)*)(<!-- \\/ OF README_SNIPPET_BLOCK -->)/m;\nconst outputText = oldOutputText.replace(regexpPattern, '$1\\n```html\\n' + inputText + '```\\n$3');\n\n// Write to disk\nfs.writeFileSync(outputPath, outputText);\n\nconsole.log(`Generated ${outputFile}`);\n"
  },
  {
    "path": "test-server/.gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\ndist\ndist-ssr\n*.local\n\n# Editor directories and files\n.vscode/*\n!.vscode/extensions.json\n.idea\n.DS_Store\n*.suo\n*.ntvs*\n*.njsproj\n*.sln\n*.sw?\n.env"
  },
  {
    "path": "test-server/README.md",
    "content": "# TEST SERVER\n\nThis is a test server that serves HTML pages from this directory using Vite. The HTML pages are tagged with scripts that reference JS files from the packages directory.\n\nIf you have any use-cases of the SDK that you'd like to test, please add a new HTML page to this project and test it from there.\n\n## DEV\n\nTo run this in 'dev' mode, from the root of this project, run `pnpm dev`. This will both watch for changes to the packages and update them as they change; and it will run a Vite dev server. This means that as you make changes to any of the JS files (or downstream files) that are referenced by the HTML page, the changes will be reflected immediately and the page will do a hot reload.\n\n## PROD\n\nTo run this in 'prod' mode, run `pnpm build` and then run `pnpm start`. This will build the assets and serve the statically. This mode currently has no use-case, but could be used in the future to run end-to-end tests. This will likely never be served in production as a web page because it's only for testing.\n\n# HTTPS\n\nTo run the server as HTTPS follow these steps\n\n1. add \"local.website.com\" to `/etc/hosts`\n2. generate the certificates using the script \"npm run generate-signed-cert\"\n3. add the cert.pem (at ~/certs/local-website/cert.pem) to the macOS keychain so that it's trusted by your browser\n4. run `pnpm dev:ssh` and it will open the website at https://local.website.com\n\n## TIPS\n* You can enable a \"Workspace\" in Chrome on this site, which allows you to edit the files from inside the browser\n"
  },
  {
    "path": "test-server/analytics-browser-local.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Analytics Browser Local Test (Autocapture)</title>\n  </head>\n  <body>\n    <h1>Analytics Browser Local Test</h1>\n    <p>This page loads the analytics-browser bundle from <code>packages/analytics-browser/lib/scripts/</code> and runs with autocapture enabled.</p>\n    <button id=\"testButton\">Click me (autocapture test)</button>\n    <p id=\"status\">SDK loading…</p>\n\n    <!-- Built bundle from packages/analytics-browser/lib/scripts/ (served as /analytics-browser/lib/scripts/amplitude-min.js) -->\n    <script src=\"/analytics-browser/lib/scripts/amplitude-min.js\"></script>\n    <script type=\"module\">\n      window.API_KEY = import.meta.env.VITE_AMPLITUDE_API_KEY;\n      window.USER_ID = import.meta.env.VITE_AMPLITUDE_USER_ID || 'analytics-browser-local-test-user';\n    </script>\n    <script type=\"module\">\n      (function () {\n        var amplitude = window.amplitude;\n        if (!amplitude) {\n          document.getElementById('status').textContent = 'Error: window.amplitude not found. Run \"pnpm build\" in packages/analytics-browser first.';\n          return;\n        }\n\n        // Use test defaults; set VITE_AMPLITUDE_API_KEY in .env when using the Vite dev server with module-based pages\n        var apiKey = import.meta.env.VITE_AMPLITUDE_API_KEY;\n        var userId = import.meta.env.VITE_AMPLITUDE_USER_ID || 'analytics-browser-local-test-user';\n\n        amplitude.init(apiKey, userId, {\n          logLevel: 'debug',\n          autocapture: {\n            networkTracking: true,\n            frustrationInteractions: true,\n            elementInteractions: true,\n            pageViews: true,\n            sessions: true,\n            fileDownloads: true,\n            formInteractions: true,\n            attribution: {\n              excludeReferrers: [],\n              excludeInternalReferrers: true,\n            },\n            webVitals: true,\n          }\n        });\n\n        // add test instances to test concurrency issues\n        // amplitude.createInstance('newInstance1').init(apiKey, userId);\n        document.getElementById('status').textContent = 'SDK initialized with autocapture enabled.';\n\n        document.getElementById('testButton').addEventListener('click', function () {\n          amplitude.track('local_test_button_clicked');\n          document.getElementById('status').textContent = 'Tracked \"local_test_button_clicked\". Check Network/Amplitude for autocapture and this event.';\n        });\n      })();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/analytics-snippet/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <title>Analytics Snippet Test</title>\n  <script>\n    let VERSION = '2.35.2';\n    !function(){\"use strict\";!function(e,t){var n=e.amplitude||{_q:[],_iq:{}};if(n.invoked)e.console&&console.error&&console.error(\"Amplitude snippet has been loaded.\");else{var r=function(e,t){e.prototype[t]=function(){return this._q.push({name:t,args:Array.prototype.slice.call(arguments,0)}),this}},s=function(e,t,n){return function(r){e._q.push({name:t,args:Array.prototype.slice.call(n,0),resolve:r})}},o=function(e,t,n){e[t]=function(){if(n)return{promise:new Promise(s(e,t,Array.prototype.slice.call(arguments)))}}},i=function(e){for(var t=0;t<m.length;t++)o(e,m[t],!1);for(var n=0;n<y.length;n++)o(e,y[n],!0)};n.invoked=!0;var a=t.createElement(\"script\");a.type=\"text/javascript\",a.crossOrigin=\"anonymous\",a.async=!0,a.src=\"https://cdn.amplitude.com/libs/analytics-browser-\" + VERSION +  \"-min.js.gz\",a.onload=function(){e.amplitude.runQueuedFunctions||console.log(\"[Amplitude] Error: could not load SDK\")};var c=t.getElementsByTagName(\"script\")[0];c.parentNode.insertBefore(a,c);for(var u=function(){return this._q=[],this},l=[\"add\",\"append\",\"clearAll\",\"prepend\",\"set\",\"setOnce\",\"unset\",\"preInsert\",\"postInsert\",\"remove\",\"getUserProperties\"],p=0;p<l.length;p++)r(u,l[p]);n.Identify=u;for(var d=function(){return this._q=[],this},f=[\"getEventProperties\",\"setProductId\",\"setQuantity\",\"setPrice\",\"setRevenue\",\"setRevenueType\",\"setEventProperties\"],v=0;v<f.length;v++)r(d,f[v]);n.Revenue=d;var m=[\"getDeviceId\",\"setDeviceId\",\"getSessionId\",\"setSessionId\",\"getUserId\",\"setUserId\",\"setOptOut\",\"setTransport\",\"reset\",\"extendSession\"],y=[\"init\",\"add\",\"remove\",\"track\",\"logEvent\",\"identify\",\"groupIdentify\",\"setGroup\",\"revenue\",\"flush\"];i(n),n.createInstance=function(e){return n._iq[e]={_q:[]},i(n._iq[e]),n._iq[e]},e.amplitude=n}}(window,document)}();\n  </script>\n</head>\n<body>\n  <h1>Analytics Snippet Test</h1>\n  <p>Check the console and network tab for output.</p>\n  <button>Rage click me!</button>\n  <button onClick=\"throw new Error('test error')\">Error/Dead Click me</button>\n  <script type=\"module\">\n    const config = {\n      autocapture: true,\n    }\n    amplitude.init(import.meta.env.VITE_AMPLITUDE_API_KEY, config);\n    amplitude.track('DUMMY EVENT', { name: 'HTML' });\n    amplitude.identify(new amplitude.Identify().set('role', 'engineer'));\n    amplitude.setGroup('org', 'engineering');\n    amplitude.groupIdentify('org', 'engineering', new amplitude.Identify().set('technology', 'react.js'));\n  </script>\n</body>\n</html>\n\n"
  },
  {
    "path": "test-server/attribution/default-tracking.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/amplitude.png\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <meta name=\"viewport\" content=\"width=device-width, user-scalable=no\" />\n    <title>Attribution Test</title>\n    <style>\n      /* Layout */\n      .container {\n        max-width: 800px;\n        margin: 0 auto;\n        padding: 20px;\n      }\n\n      /* Common styles */\n      .border {\n        border: 1px solid #ccc;\n        border-radius: 4px;\n      }\n\n      .padding {\n        padding: 8px;\n      }\n\n      .padding-lg {\n        padding: 20px;\n      }\n\n      .margin {\n        margin: 5px;\n      }\n\n      .margin-lg {\n        margin: 20px 0;\n      }\n\n      /* Interactive elements */\n      .interactive-section {\n        composes: border padding-lg margin-lg;\n      }\n\n      .btn {\n        composes: border padding margin;\n        cursor: pointer;\n      }\n\n      .input {\n        composes: border padding margin;\n      }\n\n      .clickable-div {\n        composes: border padding margin;\n        background-color: #f0f0f0;\n        cursor: pointer;\n      }\n\n      /* Table styles */\n      .table {\n        width: 100%;\n        border-collapse: collapse;\n        margin-bottom: 20px;\n      }\n\n      .table th,\n      .table td {\n        composes: border padding;\n      }\n\n      .table th {\n        text-align: left;\n      }\n\n      .table td.center {\n        text-align: center;\n      }\n\n      /* Role-based elements */\n      .role-element {\n        display: inline-block;\n        background: #eee;\n        padding: 4px 10px;\n        border-radius: 4px;\n      }\n\n      .role-link {\n        display: inline-block;\n        color: #1976d2;\n        text-decoration: underline;\n      }\n\n      /* Media elements */\n      .media-controls {\n        width: 60px;\n      }\n    </style>\n  </head>\n  <body>\n    <div class=\"container\">\n      <h1>Attribution bug test</h1>\n    </div>\n\n    <script type=\"module\">\n      import * as amplitude from '@amplitude/analytics-browser';\n    \n      amplitude.init(import.meta.env.VITE_AMPLITUDE_API_KEY, undefined, {\n        fetchRemoteConfig: false,\n        autocapture: {\n          resetSessionOnNewCampaign: true\n        },\n      });\n    </script>\n    <span>In incognito open</span>\n    <span>http://localhost:5173/attribution/default-tracking.html?utm_campaign=helloworld224</span>\n  </body>\n</html>"
  },
  {
    "path": "test-server/attribution/event-property-tracking.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/amplitude.png\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Attribution Event Property Test</title>\n    <style>\n      body {\n        font-family: monospace;\n        margin: 24px;\n        line-height: 1.5;\n      }\n\n      main {\n        max-width: 820px;\n      }\n\n      code,\n      pre {\n        background: #f5f5f5;\n        border-radius: 4px;\n      }\n\n      code {\n        padding: 2px 4px;\n      }\n\n      pre {\n        padding: 12px;\n        overflow: auto;\n      }\n\n      button {\n        margin-right: 12px;\n        margin-bottom: 12px;\n        padding: 8px 12px;\n        cursor: pointer;\n      }\n\n      .panel {\n        border: 1px solid #ddd;\n        border-radius: 6px;\n        padding: 16px;\n        margin-top: 20px;\n      }\n\n      .muted {\n        color: #666;\n      }\n    </style>\n  </head>\n  <body>\n    <main>\n      <h1>Attribution Event Property Test</h1>\n      <p class=\"muted\">\n        This page is a simple manual test for event-property attribution persistence in the Browser SDK.\n      </p>\n\n      <div class=\"panel\">\n        <h2>Simple test</h2>\n        <ol>\n          <li>\n            Open this page with campaign params, for example:\n            <code>/attribution/event-property-tracking.html?utm_source=google&utm_campaign=spring-launch</code>\n          </li>\n          <li>Click <strong>Track Event</strong> and confirm the event includes the current campaign params.</li>\n          <li>\n            Reload the page with a different query string if you want to validate a different campaign payload.\n          </li>\n        </ol>\n      </div>\n\n      <div class=\"panel\">\n        <h2>Controls</h2>\n        <button id=\"track\">Track Event</button>\n      </div>\n\n      <div class=\"panel\">\n        <h2>Current URL</h2>\n        <pre id=\"current-url\"></pre>\n      </div>\n\n      <div class=\"panel\">\n        <h2>Last action</h2>\n        <pre id=\"last-action\">Page loaded.</pre>\n      </div>\n    </main>\n\n    <script type=\"module\">\n      import * as amplitude from '@amplitude/analytics-browser';\n\n      const currentUrl = document.getElementById('current-url');\n      const lastAction = document.getElementById('last-action');\n\n      const renderUrl = () => {\n        currentUrl.textContent = window.location.href;\n      };\n\n      const logAction = (message, extra = {}) => {\n        lastAction.textContent = JSON.stringify(\n          {\n            message,\n            url: window.location.href,\n            extra,\n          },\n          null,\n          2,\n        );\n      };\n\n      window.amplitude = amplitude;\n\n      amplitude.init(import.meta.env.VITE_AMPLITUDE_API_KEY, undefined, {\n        fetchRemoteConfig: false,\n        autocapture: {\n          pageViews: true,\n          pageUrlEnrichment: false,\n          attribution: {\n            trackingMethod: 'eventProperty',\n            fallbackAttributionEvent: false,\n          },\n        },\n      });\n\n      document.getElementById('track').addEventListener('click', () => {\n        amplitude.track('Manual Attribution Event Property Test');\n        logAction('Tracked event. Inspect the outgoing event payload in the network tab.');\n      });\n\n      renderUrl();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/autocapture/element-interactions.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/amplitude.png\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <meta name=\"viewport\" content=\"width=device-width, user-scalable=no\" />\n    <title>Element Interactions Test</title>\n    <style>\n      /* Layout */\n      .container {\n        max-width: 800px;\n        margin: 0 auto;\n        padding: 20px;\n      }\n\n      /* Common styles */\n      .border {\n        border: 1px solid #ccc;\n        border-radius: 4px;\n      }\n\n      .padding {\n        padding: 8px;\n      }\n\n      .padding-lg {\n        padding: 20px;\n      }\n\n      .margin {\n        margin: 5px;\n      }\n\n      .margin-lg {\n        margin: 20px 0;\n      }\n\n      /* Interactive elements */\n      .interactive-section {\n        composes: border padding-lg margin-lg;\n      }\n\n      .btn {\n        composes: border padding margin;\n        cursor: pointer;\n      }\n\n      .input {\n        composes: border padding margin;\n      }\n\n      .clickable-div {\n        composes: border padding margin;\n        background-color: #f0f0f0;\n        cursor: pointer;\n      }\n\n      /* Table styles */\n      .table {\n        width: 100%;\n        border-collapse: collapse;\n        margin-bottom: 20px;\n      }\n\n      .table th,\n      .table td {\n        composes: border padding;\n      }\n\n      .table th {\n        text-align: left;\n      }\n\n      .table td.center {\n        text-align: center;\n      }\n\n      /* Role-based elements */\n      .role-element {\n        display: inline-block;\n        background: #eee;\n        padding: 4px 10px;\n        border-radius: 4px;\n      }\n\n      .role-link {\n        display: inline-block;\n        color: #1976d2;\n        text-decoration: underline;\n      }\n\n      /* Media elements */\n      .media-controls {\n        width: 60px;\n      }\n    </style>\n  </head>\n  <body>\n    <div class=\"container\">\n      <h1>Element Interactions Test Page</h1>\n      <p>This page contains various interactive elements to test Amplitude's autocapture functionality.</p>\n\n      <div class=\"interactive-section\">\n        <h2>Clickable Elements Reference</h2>\n        <table class=\"table\">\n          <thead>\n            <tr>\n              <th>Element/Selector</th>\n              <th class=\"center\">Should be Clickable?</th>\n              <th>Notes</th>\n            </tr>\n          </thead>\n          <tbody>\n            <tr>\n              <td><a href=\"#\" class=\"role-link\">Link</a></td>\n              <td class=\"center\">Yes</td>\n              <td>Always, unless <code>tabindex=\"-1\"</code> or <code>disabled</code></td>\n            </tr>\n            <tr>\n              <td><button class=\"btn\">Button</button></td>\n              <td class=\"center\">Yes</td>\n              <td>Always</td>\n            </tr>\n            <tr>\n              <td><input type=\"button\" value=\"Input Button\" class=\"btn\"></td>\n              <td class=\"center\">Yes</td>\n              <td>Always</td>\n            </tr>\n            <tr>\n              <td><input type=\"submit\" value=\"Submit\" class=\"btn\"></td>\n              <td class=\"center\">Yes</td>\n              <td>Always</td>\n            </tr>\n            <tr>\n              <td><input type=\"reset\" value=\"Reset\" class=\"btn\"></td>\n              <td class=\"center\">Yes</td>\n              <td>Always</td>\n            </tr>\n            <tr>\n              <td><input type=\"image\" src=\"https://via.placeholder.com/40x20?text=Img\" alt=\"Input Image\" class=\"btn\"></td>\n              <td class=\"center\">Yes</td>\n              <td>Always</td>\n            </tr>\n            <tr>\n              <td><div role=\"button\" class=\"role-element\">Role Button</div></td>\n              <td class=\"center\">Yes</td>\n              <td>ARIA role, any element</td>\n            </tr>\n            <tr>\n              <td><div role=\"link\" class=\"role-link\">Role Link</div></td>\n              <td class=\"center\">Yes</td>\n              <td>ARIA role, any element</td>\n            </tr>\n            <tr>\n              <td><div role=\"menuitem\" class=\"role-element\">Role Menuitem</div></td>\n              <td class=\"center\">Yes</td>\n              <td>ARIA role, any element</td>\n            </tr>\n            <tr>\n              <td><div role=\"option\" class=\"role-element\">Role Option</div></td>\n              <td class=\"center\">Yes</td>\n              <td>ARIA role, any element</td>\n            </tr>\n            <tr>\n              <td><div role=\"tab\" class=\"role-element\">Role Tab</div></td>\n              <td class=\"center\">Yes</td>\n              <td>ARIA role, any element</td>\n            </tr>\n            <tr>\n              <td><div role=\"treeitem\" class=\"role-element\">Role Treeitem</div></td>\n              <td class=\"center\">Yes</td>\n              <td>ARIA role, any element</td>\n            </tr>\n            <tr>\n              <td><div contenteditable=\"true\" class=\"role-element\">Editable</div></td>\n              <td class=\"center\">Yes</td>\n              <td>Editable elements</td>\n            </tr>\n            <tr>\n              <td><div class=\"role-element\">Div</div></td>\n              <td class=\"center\">Sometimes</td>\n              <td>Only if it has click handler or ARIA role</td>\n            </tr>\n            <tr>\n              <td><span class=\"role-element\">Span</span></td>\n              <td class=\"center\">Sometimes</td>\n              <td>Only if it has click handler or ARIA role</td>\n            </tr>\n            <tr>\n              <td><label>Label</label></td>\n              <td class=\"center\">Yes</td>\n              <td>Clickable, focuses associated input</td>\n            </tr>\n            <tr>\n              <td>\n                <video class=\"media-controls\" controls><source src=\"\" type=\"video/mp4\">Video</video>\n                <audio class=\"media-controls\" controls><source src=\"\" type=\"audio/mpeg\">Audio</audio>\n              </td>\n              <td class=\"center\">Sometimes</td>\n              <td>If controls are present</td>\n            </tr>\n            <tr>\n              <td>\n                <div class=\"role-element\" style=\"cursor: pointer;\">Cursor Pointer</div>\n              </td>\n              <td class=\"center\">Yes</td>\n              <td>If controls are present</td>\n            </tr>\n          </tbody>\n        </table>\n      </div>\n\n      <div class=\"interactive-section\">\n        <h2>Buttons</h2>\n        <button id=\"primary-button\" class=\"btn\">Primary Button</button>\n        <button class=\"btn secondary-button\">Secondary Button</button>\n        <button class=\"btn\" data-test-id=\"test-button\">Test Button</button>\n        <button data-dd-action-name=\"hello\">Hello</button>\n      </div>\n\n      <div class=\"interactive-section\">\n        <h2>Form Elements</h2>\n        <form id=\"test-form\">\n          <input type=\"text\" class=\"input\" placeholder=\"Text input\" />\n          <input type=\"email\" class=\"input\" placeholder=\"Email input\" />\n          <select class=\"input\">\n            <option value=\"\">Select an option</option>\n            <option value=\"1\">Option 1</option>\n            <option value=\"2\">Option 2</option>\n          </select>\n          <button type=\"submit\" class=\"btn\">Submit Form</button>\n        </form>\n      </div>\n\n      <div class=\"interactive-section\">\n        <h2>Clickable Elements</h2>\n        <div class=\"clickable-div\" data-test-id=\"clickable-div-1\" id=\"dynamic-div\">Active Div</div>\n        <div class=\"clickable-div\" data-test-id=\"clickable-div-2\">Do nothing div</div>\n        <a href=\"https://amplitude.com\" class=\"role-link\" target=\"_blank\">Open New Page</a>\n        <a href=\"#\" class=\"role-link\" data-test-id=\"test-link\">Test Link</a>\n        <a href=\"data:image/png;base64,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\n\" class=\"role-link\" data-test-id=\"large-data-uri-link\" download=\"test-image.svg\">Large Data URI Link (Download)</a>\n        <div id=\"dynamic-content\" class=\"border padding\" style=\"margin-top: 10px; display: none;\">\n          This content was dynamically added after clicking the div!\n        </div>\n      </div>\n\n      <div class=\"interactive-section\">\n        <h2>Content Changing Button</h2>\n        <!-- TODO: Make two content changers; 1 button 1 div -->\n        <button id=\"content-changer\" class=\"btn\">Change Content</button>\n        <div id=\"content-changer-div\" class=\"btn\">Change Content</div>\n        <div id=\"content-display\" class=\"border padding\" style=\"margin-top: 10px; min-height: 50px; background-color: #f9f9f9;\">\n          <p>This content will change when you click the button or div above.</p>\n        </div>\n      </div>\n    </div>\n\n    <script type=\"module\">\n      import * as amplitude from '@amplitude/analytics-browser';\n    \n      window.amplitude = amplitude;\n      const frustrationInteractions = {\n        deadClicks: true,\n        rageClicks: true,\n      };\n      const identify = new amplitude.Identify();\n      identify.set('testing', 'testing');\n      amplitude.track('hello', 'world');\n      amplitude.identify(identify);\n      amplitude.init(\n        import.meta.env.VITE_AMPLITUDE_API_KEY,\n        import.meta.env.VITE_AMPLITUDE_USER_ID || 'amplitude-typescript test user',\n        {\n          fetchRemoteConfig: false,\n          logLevel: 'debug',\n          autocapture: {\n            attribution: {\n              excludeReferrers: [\n                /\\.google.com$/,\n              ],\n              excludeInternalReferrers: {\n                condition: 'ifEmptyCampaign',\n                //condition: 'always',\n              },\n              //excludeInternalReferrers: false,\n            },\n            elementInteractions: {\n              debounceTime: 1000,\n            },\n            frustrationInteractions,\n            sessions: true,\n          },\n        }\n      );\n\n      // Add click handler for the first clickable div\n      document.getElementById('dynamic-div').addEventListener('click', () => {\n        setTimeout(() => {\n          const content = document.getElementById('dynamic-content');\n          content.style.display = content.style.display === 'none' ? 'block' : 'none';\n        }, 100);\n      });\n\n      // Add click handler for the content changer button\n      document.getElementById('content-changer').addEventListener('click', () => {\n        const display = document.getElementById('content-display');\n        const now = new Date();\n        const timeString = now.toLocaleTimeString();\n        display.innerHTML = `<p>Content changed at ${timeString}!</p>`;\n      });\n\n      // Add click handler for the content changer div\n      document.getElementById('content-changer-div').addEventListener('click', () => {\n        const display = document.getElementById('content-display');\n        const now = new Date();\n        const timeString = now.toLocaleTimeString();\n        display.innerHTML = `<p>Content changed at ${timeString}!</p>`;\n      });\n\n      // Prevent form submission from refreshing the page\n      document.getElementById('test-form').addEventListener('submit', (event) => {\n        event.preventDefault();\n        console.log('Form submitted');\n      });\n    </script>\n\n    <script>\n    // Remove the click handlers and background color toggle effect\n    document.addEventListener('DOMContentLoaded', function() {\n      // Keep the form submission prevention\n      document.getElementById('test-form').addEventListener('submit', (event) => {\n        event.preventDefault();\n        console.log('Form submitted');\n      });\n    });\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/autocapture/error-click.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <title>Error Click Test</title>\n  </head>\n  <body>\n    <h1>Error Click Test</h1>\n\n    <button id=\"console-error\">Click for console.error (1s delay)</button>\n    <br /><br />\n\n    <button id=\"uncaught-exception\">Click for uncaught exception (1s delay)</button>\n    <br /><br />\n\n    <button id=\"unhandled-rejection\">Click for unhandled rejection (1s delay)</button>\n    <br /><br />\n\n    <button id=\"counter\">Click to increment counter</button>\n    <span id=\"count\">0</span>\n\n    <script>\n      document.getElementById('console-error').addEventListener('click', function () {\n        setTimeout(function () {\n          console.error('This is a console error triggered by click');\n        }, 1000);\n      });\n\n      document.getElementById('uncaught-exception').addEventListener('click', function () {\n        setTimeout(function () {\n          throw new Error('This is an uncaught exception triggered by click');\n        }, 1000);\n      });\n\n      document.getElementById('unhandled-rejection').addEventListener('click', function () {\n        setTimeout(function () {\n          Promise.reject(new Error('This is an unhandled rejection triggered by click'));\n        }, 1000);\n      });\n\n      var count = 0;\n      document.getElementById('counter').addEventListener('click', function () {\n        count++;\n        document.getElementById('count').textContent = count;\n      });\n    </script>\n\n    <script type=\"module\">\n        import * as amplitude from '@amplitude/analytics-browser';\n        window.amplitude = amplitude;\n        amplitude.init(\n          import.meta.env.VITE_AMPLITUDE_API_KEY,\n          import.meta.env.VITE_AMPLITUDE_USER_ID || 'amplitude-typescript test user',\n          {\n            autocapture: {\n              frustrationInteractions: {\n                deadClicks: false,\n                rageClicks: false,\n                errorClicks: true,\n              },\n            },\n          }\n        );\n    </script>\n  </body>\n</html>\n\n"
  },
  {
    "path": "test-server/autocapture/long-task.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <title>Main Thread Block Test</title>\n    <style>\n      body { font-family: monospace; margin: 20px; }\n      h2 { margin-top: 32px; }\n      button { margin: 4px 0; display: block; }\n      #source-badge { font-weight: bold; margin-bottom: 16px; color: #1a73e8; }\n      .log { margin-top: 24px; background: #f4f4f4; padding: 12px; border-radius: 4px; min-height: 60px; white-space: pre-wrap; font-size: 13px; max-height: 400px; overflow-y: auto; }\n    </style>\n  </head>\n  <body>\n    <h1>Main Thread Block Test</h1>\n    <div id=\"source-badge\">Detecting API support...</div>\n    <p>Open the Network tab or Amplitude debugger to see <strong>[Amplitude] Main Thread Block</strong> events. The on-page log below also mirrors each event.</p>\n\n    <h2>1. Basic block (no measure)</h2>\n    <p>Blocks for 200ms. Expect: event with no <code>[Amplitude] Main Thread Block Measures</code>.</p>\n    <button id=\"basic\">Trigger 200ms block</button>\n\n    <h2>2. Block with measure correlation</h2>\n    <p>Wraps the work in a <code>performance.measure()</code>. Expect: <code>Measures: [\"heavy-calculation\"]</code>.</p>\n    <button id=\"measured\">Trigger block with measure</button>\n\n    <h2>3. Block after a click</h2>\n    <p>Simulates a slow click handler. Lets you correlate the task with a user action in Amplitude.</p>\n    <button id=\"click-block\">Click me (triggers block after 50ms)</button>\n\n    <h2>4. Multiple overlapping measures</h2>\n    <p>Two measures overlap the same block. Expect: <code>Measures: [\"step-one\", \"step-two\"]</code>.</p>\n    <button id=\"multi-measure\">Trigger block with multiple measures</button>\n\n    <h2>5. Short task (should NOT fire)</h2>\n    <p>Blocks for only 10ms — below the 50ms threshold. Expect: no event.</p>\n    <button id=\"short\">Trigger 10ms block (no event expected)</button>\n\n    <div class=\"log\" id=\"log\">Waiting for events...</div>\n\n    <script>\n      function blockMainThread(ms) {\n        const start = performance.now();\n        while (performance.now() - start < ms) { /* busy wait */ }\n      }\n\n      function log(msg) {\n        const el = document.getElementById('log');\n        el.textContent = new Date().toISOString().slice(11, 23) + '  ' + msg + '\\n' + el.textContent;\n      }\n\n      document.getElementById('basic').addEventListener('click', () => {\n        log('Triggering 200ms block...');\n        blockMainThread(200);\n      });\n\n      document.getElementById('measured').addEventListener('click', () => {\n        log('Triggering block with measure \"heavy-calculation\"...');\n        performance.mark('heavy-calculation-start');\n        blockMainThread(200);\n        performance.mark('heavy-calculation-end');\n        performance.measure('heavy-calculation', 'heavy-calculation-start', 'heavy-calculation-end');\n      });\n\n      document.getElementById('click-block').addEventListener('click', () => {\n        log('Click captured — triggering block in 50ms...');\n        setTimeout(() => blockMainThread(200), 50);\n      });\n\n      document.getElementById('multi-measure').addEventListener('click', () => {\n        log('Triggering block with measures \"step-one\" and \"step-two\"...');\n        performance.mark('step-one-start');\n        blockMainThread(100);\n        performance.mark('step-one-end');\n        performance.measure('step-one', 'step-one-start', 'step-one-end');\n\n        performance.mark('step-two-start');\n        blockMainThread(100);\n        performance.mark('step-two-end');\n        performance.measure('step-two', 'step-two-start', 'step-two-end');\n      });\n\n      document.getElementById('short').addEventListener('click', () => {\n        log('Triggering 10ms block (no event expected)...');\n        blockMainThread(10);\n      });\n    </script>\n\n    <script type=\"module\">\n      import * as amplitude from '@amplitude/analytics-browser';\n      import { performancePlugin } from '@amplitude/plugin-autocapture-browser';\n\n      window.amplitude = amplitude;\n\n      // Show which API is being used\n      const supported = PerformanceObserver.supportedEntryTypes;\n      const source = supported.includes('long-animation-frame')\n        ? 'long-animation-frame (LoAF)'\n        : supported.includes('longtask')\n        ? 'long-task (fallback)'\n        : 'not supported in this browser';\n      document.getElementById('source-badge').textContent = `Tracking via: ${source}`;\n\n      amplitude.add({\n        name: 'main-thread-block-logger',\n        type: 'enrichment',\n        execute: async (event) => {\n          if (event.event_type === '[Amplitude] Main Thread Block') {\n            const p = event.event_properties ?? {};\n            const parts = [\n              `source: ${p['[Amplitude] Main Thread Block Source']}`,\n              `duration: ${Math.round(p['[Amplitude] Main Thread Block Duration'])}ms`,\n              `blocking: ${Math.round(p['[Amplitude] Main Thread Block Blocking Duration'])}ms`,\n            ];\n            const measures = p['[Amplitude] Main Thread Block Measures'];\n            if (measures?.length) parts.push(`measures: [${measures.join(', ')}]`);\n            const scripts = p['[Amplitude] Main Thread Block Script Count'];\n            if (scripts != null) parts.push(`scripts: ${scripts}`);\n            const invokers = p['[Amplitude] Main Thread Block Invokers'];\n            if (invokers?.length) parts.push(`invokers: [${invokers.join(', ')}]`);\n            const attribution = p['[Amplitude] Main Thread Block Attribution'];\n            if (attribution?.length) parts.push(`attribution: [${attribution.join(', ')}]`);\n            document.getElementById('log').textContent =\n              new Date().toISOString().slice(11, 23) + '  [Amplitude] Main Thread Block — ' + parts.join(' | ') + '\\n' +\n              document.getElementById('log').textContent;\n          }\n          return event;\n        },\n      });\n\n      const plugin = performancePlugin({\n        mainThreadBlock: { durationThreshold: 50 },\n      });\n\n      amplitude.init(\n        import.meta.env.VITE_AMPLITUDE_API_KEY,\n        import.meta.env.VITE_AMPLITUDE_USER_ID || 'amplitude-typescript test user',\n      );\n\n      amplitude.add(plugin);\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/browser-sdk/cookie-consent.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/amplitude.png\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Amplitude SDK - Cookie Consent Example</title>\n    <style>\n      body {\n        font-family: Arial, sans-serif;\n        margin: 0;\n        padding: 20px;\n        background-color: #f5f5f5;\n      }\n      \n      .container {\n        max-width: 800px;\n        margin: 0 auto;\n        background: white;\n        padding: 30px;\n        border-radius: 10px;\n        box-shadow: 0 2px 10px rgba(0,0,0,0.1);\n      }\n      \n      h1 {\n        color: #333;\n        text-align: center;\n        margin-bottom: 30px;\n      }\n      \n      .section {\n        margin: 20px 0;\n        padding: 15px;\n        border: 1px solid #ddd;\n        border-radius: 5px;\n        background-color: #f9f9f9;\n      }\n      \n      .section h3 {\n        margin-top: 0;\n        color: #555;\n      }\n      \n      button {\n        background-color: #007bff;\n        color: white;\n        border: none;\n        padding: 10px 20px;\n        border-radius: 5px;\n        cursor: pointer;\n        margin: 5px;\n        font-size: 14px;\n      }\n      \n      button:hover {\n        background-color: #0056b3;\n      }\n      \n      button:disabled {\n        background-color: #ccc;\n        cursor: not-allowed;\n      }\n      \n      .status {\n        padding: 10px;\n        border-radius: 5px;\n        margin: 10px 0;\n        font-weight: bold;\n      }\n      \n      .status.success {\n        background-color: #d4edda;\n        color: #155724;\n        border: 1px solid #c3e6cb;\n      }\n      \n      .status.warning {\n        background-color: #fff3cd;\n        color: #856404;\n        border: 1px solid #ffeaa7;\n      }\n      \n      .status.error {\n        background-color: #f8d7da;\n        color: #721c24;\n        border: 1px solid #f5c6cb;\n      }\n      \n      /* Cookie Consent Banner */\n      .cookie-banner {\n        position: fixed;\n        bottom: 0;\n        left: 0;\n        right: 0;\n        background-color: #333;\n        color: white;\n        padding: 20px;\n        box-shadow: 0 -2px 10px rgba(0,0,0,0.3);\n        z-index: 1000;\n        display: none;\n      }\n      \n      .cookie-banner.show {\n        display: block;\n      }\n      \n      .cookie-banner-content {\n        max-width: 1200px;\n        margin: 0 auto;\n        display: flex;\n        align-items: center;\n        justify-content: space-between;\n        flex-wrap: wrap;\n        gap: 15px;\n      }\n      \n      .cookie-banner-text {\n        flex: 1;\n        min-width: 300px;\n      }\n      \n      .cookie-banner-buttons {\n        display: flex;\n        gap: 10px;\n        flex-wrap: wrap;\n      }\n      \n      .cookie-banner button {\n        background-color: #28a745;\n        padding: 8px 16px;\n        font-size: 14px;\n      }\n      \n      .cookie-banner button.decline {\n        background-color: #dc3545;\n      }\n      \n      .cookie-banner button:hover {\n        opacity: 0.8;\n      }\n      \n      .event-log {\n        background-color: #f8f9fa;\n        border: 1px solid #dee2e6;\n        border-radius: 5px;\n        padding: 15px;\n        margin: 10px 0;\n        max-height: 300px;\n        overflow-y: auto;\n        font-family: monospace;\n        font-size: 12px;\n      }\n      \n      .event-log .event {\n        margin: 5px 0;\n        padding: 5px;\n        border-left: 3px solid #007bff;\n        background-color: white;\n      }\n      \n      .event-log .event.error {\n        border-left-color: #dc3545;\n        background-color: #fff5f5;\n      }\n    </style>\n  </head>\n  <body>\n    <div class=\"container\">\n      <h1>Amplitude SDK - Cookie Consent Example</h1>\n      \n      <div class=\"section\">\n        <h3>Cookie Consent Status</h3>\n        <div id=\"consent-status\" class=\"status warning\">\n          Cookie consent not given yet\n        </div>\n        <div id=\"sdk-status\" class=\"status warning\">\n          Amplitude SDK not initialized\n        </div>\n      </div>\n      \n      <div class=\"section\">\n        <h3>Test Actions</h3>\n        <button id=\"track-before-consent-btn\">Track Event \"before cookie consent\"</button>\n      </div>\n      \n      <div class=\"section\">\n        <h3>Event Log</h3>\n        <div id=\"event-log\" class=\"event-log\">\n          <div class=\"event\">Page loaded - waiting for cookie consent...</div>\n        </div>\n      </div>\n    </div>\n    \n    <!-- Cookie Consent Banner -->\n    <div id=\"cookie-banner\" class=\"cookie-banner\">\n      <div class=\"cookie-banner-content\">\n        <div class=\"cookie-banner-text\">\n          <strong>Cookie Consent</strong><br>\n          We use cookies and similar technologies to improve your experience and analyze site usage. \n          By clicking \"Accept\", you consent to the use of cookies for analytics and tracking purposes.\n        </div>\n        <div class=\"cookie-banner-buttons\">\n          <button id=\"accept-cookies-btn\">Accept</button>\n          <button id=\"decline-cookies-btn\" class=\"decline\">Decline</button>\n        </div>\n      </div>\n    </div>\n\n    <script type=\"module\">\n      import * as amplitude from '@amplitude/analytics-browser';\n      import { stubPlugin } from '@amplitude/plugin-stub-browser';\n      \n      // Global state\n      let isConsentGiven = false;\n      let isSDKInitialized = false;\n      \n      // DOM elements\n      const consentStatus = document.getElementById('consent-status');\n      const sdkStatus = document.getElementById('sdk-status');\n      const eventLog = document.getElementById('event-log');\n      const cookieBanner = document.getElementById('cookie-banner');\n      const trackBeforeConsentBtn = document.getElementById('track-before-consent-btn');\n      const acceptCookiesBtn = document.getElementById('accept-cookies-btn');\n      const declineCookiesBtn = document.getElementById('decline-cookies-btn');\n      \n      // Utility functions\n      function logEvent(message, isError = false) {\n        const eventDiv = document.createElement('div');\n        eventDiv.className = `event ${isError ? 'error' : ''}`;\n        eventDiv.textContent = `${new Date().toLocaleTimeString()}: ${message}`;\n        eventLog.appendChild(eventDiv);\n        eventLog.scrollTop = eventLog.scrollHeight;\n        console.log(message);\n      }\n      \n      function updateStatus() {\n        // Update consent status\n        if (isConsentGiven) {\n          consentStatus.textContent = 'Cookie consent given ✓';\n          consentStatus.className = 'status success';\n        } else {\n          consentStatus.textContent = 'Cookie consent not given yet';\n          consentStatus.className = 'status warning';\n        }\n        \n        // Update SDK status\n        if (isSDKInitialized) {\n          sdkStatus.textContent = 'Amplitude SDK initialized ✓';\n          sdkStatus.className = 'status success';\n        } else {\n          sdkStatus.textContent = 'Amplitude SDK not initialized';\n          sdkStatus.className = 'status warning';\n        }\n      }\n      \n      function showCookieBanner() {\n        cookieBanner.classList.add('show');\n        logEvent('Cookie consent banner displayed');\n      }\n      \n      function hideCookieBanner() {\n        cookieBanner.classList.remove('show');\n      }\n      \n      async function initializeAmplitudeSDK() {\n        try {\n          \n          // Initialize Amplitude SDK\n          await amplitude.init(\n            import.meta.env.VITE_AMPLITUDE_API_KEY,\n            'test-user-cookie-consent',\n            {\n              autocapture: false,\n              logLevel: 'debug'\n            }\n          );\n          \n          isSDKInitialized = true;\n          logEvent('Amplitude SDK initialized successfully');\n          updateStatus();\n          \n          // Track an initialization event\n          amplitude.track('SDK Initialized After Consent', {\n            consent_method: 'cookie_banner',\n            timestamp: new Date().toISOString()\n          });\n          \n          logEvent('Tracked \"SDK Initialized After Consent\" event');\n          \n        } catch (error) {\n          logEvent(`Error initializing Amplitude SDK: ${error.message}`, true);\n        }\n      }\n      \n      // Event handlers\n      trackBeforeConsentBtn.addEventListener('click', () => {\n        try {\n          // This will fail gracefully since SDK is not initialized\n          amplitude.track('before cookie consent', {\n            page: 'cookie-consent-demo',\n            timestamp: new Date().toISOString(),\n            consent_status: 'not_given'\n          });\n          \n          logEvent('Attempted to track \"before cookie consent\" event (SDK not initialized)');\n        } catch (error) {\n          logEvent(`Error tracking event before consent: ${error.message}`, true);\n        }\n      });\n      \n      acceptCookiesBtn.addEventListener('click', async () => {\n        isConsentGiven = true;\n        hideCookieBanner();\n        logEvent('Cookie consent accepted by user');\n        updateStatus();\n        \n        // Initialize Amplitude SDK after consent\n        await initializeAmplitudeSDK();\n      });\n      \n      declineCookiesBtn.addEventListener('click', () => {\n        hideCookieBanner();\n        logEvent('Cookie consent declined by user');\n        logEvent('Amplitude SDK will not be initialized');\n      });\n      \n      // Initialize page\n      window.addEventListener('load', () => {\n        updateStatus();\n        logEvent('Page loaded - Amplitude SDK not initialized yet');\n        \n        // Show cookie banner after a short delay\n        setTimeout(() => {\n          showCookieBanner();\n        }, 1000);\n      });\n      \n      // Make amplitude available globally for debugging\n      window.amplitude = amplitude;\n      window.debugInfo = {\n        isConsentGiven: () => isConsentGiven,\n        isSDKInitialized: () => isSDKInitialized,\n        forceInitialize: initializeAmplitudeSDK\n      };\n    </script>\n  </body>\n</html> "
  },
  {
    "path": "test-server/browser-sdk/events-precision.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Amplitude Events Test</title>\n    <style>\n        .status {\n            margin: 10px 0;\n            padding: 10px;\n            border-radius: 4px;\n        }\n        .pending {\n            background-color: #fff3cd;\n        }\n        .complete {\n            background-color: #d4edda;\n        }\n    </style>\n    <script type=\"module\" src=\"/helpers/tough-cookie\"></script>\n</head>\n<body>\n    <h1>Amplitude Events Test Page</h1>\n    <div id=\"status\">\n        <div id=\"event1-status\" class=\"status pending\">Waiting to track Event 1...</div>\n        <div id=\"event2-status\" class=\"status pending\">Waiting to track Event 2...</div>\n        <div id=\"event3-status\" class=\"status pending\">Waiting to track Event 3...</div>\n        <div id=\"event4-status\" class=\"status pending\">Waiting to track Event 4...</div>\n    </div>\n\n    <script type=\"module\">\n        import * as amplitude from '@amplitude/analytics-browser';\n        const apiKey = import.meta.env.VITE_AMPLITUDE_API_KEY;\n\n        // Initialize Amplitude\n        amplitude.init(apiKey, 'test-user', {\n            defaultTracking: false,\n            logLevel: amplitude.Types.LogLevel.Debug\n        });\n\n        // Helper function to update status\n        function updateStatus(id, status, message) {\n            const element = document.getElementById(id);\n            element.className = `status ${status}`;\n            element.textContent = message;\n        }\n\n        // Track events in sequence\n        async function trackEvents() {\n            const events = [\n                { id: 'event1-status', name: 'Event 1' },\n                { id: 'event2-status', name: 'Event 2' },\n                { id: 'event3-status', name: 'Event 3' },\n                { id: 'event4-status', name: 'Event 4' }\n            ];\n\n            for (const event of events) {\n                updateStatus(event.id, 'pending', `Tracking ${event.name}...`);\n                await amplitude.track(event.name);\n                updateStatus(event.id, 'complete', `Tracked ${event.name}`);\n            }\n        }\n        // Start tracking events\n        trackEvents();\n    </script>\n</body>\n</html> "
  },
  {
    "path": "test-server/browser-sdk/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/amplitude.png\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Browser SDK Test</title>\n\n    <!-- script to enhance cookie enforcement-->\n    <script type=\"module\" src=\"/helpers/tough-cookie\"></script>\n  </head>\n  <body>\n    <div id=\"app\">\n      Basic test page for the Amplitude Browser SDK\n      <button id=\"clearCookies\" style=\"margin-top: 10px;\">Clear Amplitude Cookies</button>\n    </div>\n    <script type=\"module\">\n      import * as amplitude from '@amplitude/analytics-browser';\n      import { stubPlugin } from '@amplitude/plugin-stub-browser';\n      window.amplitude = amplitude;\n      amplitude.add(stubPlugin());\n      amplitude.init(\n        import.meta.env.VITE_AMPLITUDE_API_KEY,\n        import.meta.env.VITE_AMPLITUDE_USER_ID || 'amplitude-typescript test user',\n        {\n          autocapture: {\n            // networkTracking: true,\n            networkTracking: {\n              ignoreAmplitudeßRequests: false,\n              ignoreHosts: [],\n              captureRules: [\n                {hosts: ['*.amplitude.com'], statusCodeRange: '400-599'},\n                {hosts: ['httpstat.us'], statusCodeRange: '400-599'},\n              ],\n            },\n          },\n        }\n      );\n\n      // Add cookie clearing functionality\n      document.getElementById('clearCookies').addEventListener('click', async () => {\n        try {\n          const cookies = await cookieStore.getAll();\n          const amplitudeCookies = cookies.filter(cookie => cookie.name.startsWith('AMP_'));\n          \n          await Promise.all(\n            amplitudeCookies.map(cookie => \n              cookieStore.delete(cookie.name)\n            )\n          );\n          \n          alert('Amplitude cookies cleared!');\n        } catch (error) {\n          console.error('Error clearing cookies:', error);\n          alert('Failed to clear cookies. See console for details.');\n        }\n      });\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/browser-sdk/page-url-enrichment-mpa-a.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/amplitude.png\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <script type=\"module\" src=\"/helpers/tough-cookie\"></script>\n    <title>Page URL Enrichment — MPA repro: Page A</title>\n    <style>\n      body { font-family: system-ui, sans-serif; padding: 24px; max-width: 900px; }\n      h1 { margin-bottom: 4px; }\n      nav a { margin-right: 12px; }\n      .panel { border: 1px solid #ccc; border-radius: 6px; padding: 12px; margin-top: 16px; }\n      .panel h3 { margin: 0 0 8px; font-size: 14px; color: #555; text-transform: uppercase; }\n      pre { background: #f5f5f5; padding: 8px; border-radius: 4px; overflow: auto; margin: 0; }\n      button { margin-right: 8px; }\n    </style>\n  </head>\n  <body>\n    <h1>Page A (MPA repro)</h1>\n\n    <nav>\n      <a href=\"/browser-sdk/page-url-enrichment-mpa-a.html\">→ Page A</a>\n      <a href=\"/browser-sdk/page-url-enrichment-mpa-b.html\">→ Page B</a>\n      <a href=\"/browser-sdk/page-url-enrichment-mpa-c.html\">→ Page C</a>\n    </nav>\n\n    <div class=\"panel\">\n      <h3>Live sessionStorage[AMP_URL_INFO]</h3>\n      <pre id=\"storage\"></pre>\n    </div>\n\n    <div class=\"panel\">\n      <h3>Events tracked from this page</h3>\n      <button id=\"wipe\">Wipe AMP_URL_INFO</button>\n      <pre id=\"events\">(none yet — page-view events from autocapture will show here too)</pre>\n    </div>\n\n    <script type=\"module\">\n      import * as amplitude from '@amplitude/analytics-browser';\n\n      const STORAGE_KEY = 'AMP_URL_INFO';\n      const storageEl = document.getElementById('storage');\n      const eventsEl = document.getElementById('events');\n\n      const renderStorage = () => {\n        const raw = sessionStorage.getItem(STORAGE_KEY);\n        try {\n          storageEl.textContent = raw ? JSON.stringify(JSON.parse(raw), null, 2) : '(empty)';\n        } catch {\n          storageEl.textContent = raw ?? '(empty)';\n        }\n      };\n      renderStorage();\n      setInterval(renderStorage, 250);\n\n      // Inline enrichment plugin so we can see exactly what event properties\n      // each tracked event ends up with — without leaving the page.\n      const inspectorPlugin = {\n        name: 'mpa-repro-inspector',\n        type: 'enrichment',\n        setup: async () => {},\n        execute: async (event) => {\n          const summary = {\n            type: event.event_type,\n            'Page Location': event.event_properties?.['[Amplitude] Page Location'],\n            'Previous Page Location': event.event_properties?.['[Amplitude] Previous Page Location'],\n            'Previous Page Type': event.event_properties?.['[Amplitude] Previous Page Type'],\n          };\n          const line = `[${new Date().toLocaleTimeString()}] ${JSON.stringify(summary, null, 2)}`;\n          eventsEl.textContent =\n            eventsEl.textContent.startsWith('(none')\n              ? line\n              : `${line}\\n\\n${eventsEl.textContent}`;\n          return event;\n        },\n      };\n\n      amplitude.init(\n        import.meta.env.VITE_AMPLITUDE_API_KEY,\n        import.meta.env.VITE_AMPLITUDE_USER_ID || 'amplitude-typescript test user',\n        {\n          autocapture: {\n            pageViews: true,\n            pageUrlEnrichment: true,\n          },\n        },\n      );\n      amplitude.add(inspectorPlugin);\n\n      document.getElementById('wipe').addEventListener('click', () => {\n        sessionStorage.removeItem(STORAGE_KEY);\n        renderStorage();\n      });\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/browser-sdk/page-url-enrichment-mpa-b.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/amplitude.png\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <script type=\"module\" src=\"/helpers/tough-cookie\"></script>\n    <title>Page URL Enrichment — MPA repro: Page B</title>\n    <style>\n      body { font-family: system-ui, sans-serif; padding: 24px; max-width: 900px; }\n      h1 { margin-bottom: 4px; }\n      nav a { margin-right: 12px; }\n      .panel { border: 1px solid #ccc; border-radius: 6px; padding: 12px; margin-top: 16px; }\n      .panel h3 { margin: 0 0 8px; font-size: 14px; color: #555; text-transform: uppercase; }\n      pre { background: #f5f5f5; padding: 8px; border-radius: 4px; overflow: auto; margin: 0; }\n      button { margin-right: 8px; }\n    </style>\n  </head>\n  <body>\n    <h1>Page B (MPA repro)</h1>\n\n    <nav>\n      <a href=\"/browser-sdk/page-url-enrichment-mpa-a.html\">→ Page A</a>\n      <a href=\"/browser-sdk/page-url-enrichment-mpa-b.html\">→ Page B</a>\n      <a href=\"/browser-sdk/page-url-enrichment-mpa-c.html\">→ Page C</a>\n    </nav>\n\n    <div class=\"panel\">\n      <h3>Live sessionStorage[AMP_URL_INFO]</h3>\n      <pre id=\"storage\"></pre>\n    </div>\n\n    <div class=\"panel\">\n      <h3>Events tracked from this page</h3>\n      <button id=\"wipe\">Wipe AMP_URL_INFO</button>\n      <pre id=\"events\">(none yet — page-view events from autocapture will show here too)</pre>\n    </div>\n\n    <script type=\"module\">\n      import * as amplitude from '@amplitude/analytics-browser';\n\n      const STORAGE_KEY = 'AMP_URL_INFO';\n      const storageEl = document.getElementById('storage');\n      const eventsEl = document.getElementById('events');\n\n      const renderStorage = () => {\n        const raw = sessionStorage.getItem(STORAGE_KEY);\n        try {\n          storageEl.textContent = raw ? JSON.stringify(JSON.parse(raw), null, 2) : '(empty)';\n        } catch {\n          storageEl.textContent = raw ?? '(empty)';\n        }\n      };\n      renderStorage();\n      setInterval(renderStorage, 250);\n\n      const inspectorPlugin = {\n        name: 'mpa-repro-inspector',\n        type: 'enrichment',\n        setup: async () => {},\n        execute: async (event) => {\n          const summary = {\n            type: event.event_type,\n            'Page Location': event.event_properties?.['[Amplitude] Page Location'],\n            'Previous Page Location': event.event_properties?.['[Amplitude] Previous Page Location'],\n            'Previous Page Type': event.event_properties?.['[Amplitude] Previous Page Type'],\n          };\n          const line = `[${new Date().toLocaleTimeString()}] ${JSON.stringify(summary, null, 2)}`;\n          eventsEl.textContent =\n            eventsEl.textContent.startsWith('(none')\n              ? line\n              : `${line}\\n\\n${eventsEl.textContent}`;\n          return event;\n        },\n      };\n\n      amplitude.init(\n        import.meta.env.VITE_AMPLITUDE_API_KEY,\n        import.meta.env.VITE_AMPLITUDE_USER_ID || 'amplitude-typescript test user',\n        {\n          autocapture: {\n            pageViews: true,\n            pageUrlEnrichment: true,\n          },\n        },\n      );\n      amplitude.add(inspectorPlugin);\n\n      document.getElementById('wipe').addEventListener('click', () => {\n        sessionStorage.removeItem(STORAGE_KEY);\n        renderStorage();\n      });\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/browser-sdk/page-url-enrichment-mpa-c.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/amplitude.png\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <script type=\"module\" src=\"/helpers/tough-cookie\"></script>\n    <title>Page URL Enrichment — MPA repro: Page C</title>\n    <style>\n      body { font-family: system-ui, sans-serif; padding: 24px; max-width: 900px; }\n      h1 { margin-bottom: 4px; }\n      nav a { margin-right: 12px; }\n      .panel { border: 1px solid #ccc; border-radius: 6px; padding: 12px; margin-top: 16px; }\n      .panel h3 { margin: 0 0 8px; font-size: 14px; color: #555; text-transform: uppercase; }\n      pre { background: #f5f5f5; padding: 8px; border-radius: 4px; overflow: auto; margin: 0; }\n      button { margin-right: 8px; }\n    </style>\n  </head>\n  <body>\n    <h1>Page C (MPA repro)</h1>\n\n    <nav>\n      <a href=\"/browser-sdk/page-url-enrichment-mpa-a.html\">→ Page A</a>\n      <a href=\"/browser-sdk/page-url-enrichment-mpa-b.html\">→ Page B</a>\n      <a href=\"/browser-sdk/page-url-enrichment-mpa-c.html\">→ Page C</a>\n    </nav>\n\n    <div class=\"panel\">\n      <h3>Live sessionStorage[AMP_URL_INFO]</h3>\n      <pre id=\"storage\"></pre>\n    </div>\n\n    <div class=\"panel\">\n      <h3>Events tracked from this page</h3>\n      <button id=\"wipe\">Wipe AMP_URL_INFO</button>\n      <pre id=\"events\">(none yet — page-view events from autocapture will show here too)</pre>\n    </div>\n\n    <script type=\"module\">\n      import * as amplitude from '@amplitude/analytics-browser';\n\n      const STORAGE_KEY = 'AMP_URL_INFO';\n      const storageEl = document.getElementById('storage');\n      const eventsEl = document.getElementById('events');\n\n      const renderStorage = () => {\n        const raw = sessionStorage.getItem(STORAGE_KEY);\n        try {\n          storageEl.textContent = raw ? JSON.stringify(JSON.parse(raw), null, 2) : '(empty)';\n        } catch {\n          storageEl.textContent = raw ?? '(empty)';\n        }\n      };\n      renderStorage();\n      setInterval(renderStorage, 250);\n\n      const inspectorPlugin = {\n        name: 'mpa-repro-inspector',\n        type: 'enrichment',\n        setup: async () => {},\n        execute: async (event) => {\n          const summary = {\n            type: event.event_type,\n            'Page Location': event.event_properties?.['[Amplitude] Page Location'],\n            'Previous Page Location': event.event_properties?.['[Amplitude] Previous Page Location'],\n            'Previous Page Type': event.event_properties?.['[Amplitude] Previous Page Type'],\n          };\n          const line = `[${new Date().toLocaleTimeString()}] ${JSON.stringify(summary, null, 2)}`;\n          eventsEl.textContent =\n            eventsEl.textContent.startsWith('(none')\n              ? line\n              : `${line}\\n\\n${eventsEl.textContent}`;\n          return event;\n        },\n      };\n\n      amplitude.init(\n        import.meta.env.VITE_AMPLITUDE_API_KEY,\n        import.meta.env.VITE_AMPLITUDE_USER_ID || 'amplitude-typescript test user',\n        {\n          autocapture: {\n            pageViews: true,\n            pageUrlEnrichment: true,\n          },\n        },\n      );\n      amplitude.add(inspectorPlugin);\n\n      document.getElementById('wipe').addEventListener('click', () => {\n        sessionStorage.removeItem(STORAGE_KEY);\n        renderStorage();\n      });\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/browser-sdk/page-url-enrichment.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/amplitude.png\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <script type=\"module\" src=\"/helpers/tough-cookie\"></script>\n    <title>Page Url Previous Page tracking</title>\n  </head>\n  <body>\n    <h1>Page 1</h1>\n    <div>\n      When clicking on the button below, it will change the URL to /new-page{n}, without reloading the page. The page\n      url enrichment plugin will track this change and augment events with the previous page url.\n    </div>\n    <button id=\"navigate\">Go to next page</button>\n    <div style=\"margin-top: 20px\">This button will navigate back to the previous page.</div>\n    <button id=\"navigate-back\">Go back</button>\n    <div style=\"margin-top: 20px\">This button will replace the current state with a new state.</div>\n    <button id=\"replace-state\">Replace state</button>\n\n    <div style=\"margin-top: 20px\">This button will track a precise event.</div>\n    <button id=\"precise-event\">Add to cart</button>\n\n    <script>\n      document.getElementById('precise-event').addEventListener('click', function () {\n        amplitude.track('Add to cart', {\n          price: 100,\n        });\n      });\n    </script>\n    <script>\n      let counter = 1;\n      document.getElementById('navigate').addEventListener('click', function () {\n        counter += 1;\n        const newUrl = '/new-page' + counter;\n\n        // Push new state to the browser history\n        history.pushState({ page: 'new-page' + counter }, 'New Page', newUrl);\n\n        // Optionally, update the content without reloading\n        document.querySelector('h1').innerText = 'Page ' + counter;\n      });\n\n      document.getElementById('navigate-back').addEventListener('click', function () {\n        // go back a page\n        history.back();\n\n        counter -= 1;\n\n        // update the content without reloading\n        document.querySelector('h1').innerText = 'Page ' + counter;\n      });\n\n      document.getElementById('replace-state').addEventListener('click', function () {\n        // replace state\n        history.replaceState(\n          { page: 'new-page' + counter + 'replaced' },\n          'New Page',\n          '/new-page' + counter + 'replaced',\n        );\n      });\n    </script>\n    <script type=\"module\">\n      import * as amplitude from '@amplitude/analytics-browser';\n      import { pageViewTrackingPlugin } from '@amplitude/plugin-page-view-tracking-browser';\n      import { pageUrlEnrichmentPlugin } from '@amplitude/plugin-page-url-enrichment-browser';\n      window.amplitude = amplitude;\n      const pageViewPlugin = pageViewTrackingPlugin({\n        trackHistoryChanges: 'all',\n      });\n      const pageUrlPlugin = pageUrlEnrichmentPlugin();\n\n      amplitude.init(\n        import.meta.env.VITE_AMPLITUDE_API_KEY,\n        import.meta.env.VITE_AMPLITUDE_USER_ID || 'amplitude-typescript test user',\n        {\n          autocapture: {\n            pageViews: true,\n            pageUrlEnrichment: true,\n          },\n        }\n      );\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/browser-sdk/page-view-history.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/amplitude.png\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <script type=\"module\" src=\"/helpers/tough-cookie\"></script>\n    <title>Page View with History Push State tracking</title>\n  </head>\n  <body>\n    <h1>Page One</h1>\n    <div id=\"app\">\n      Page View with History Push State tracking\n    </div>\n    <div>\n      When clicking on the button below, it will change the URL to /new-page,\n      without reloading the page. The page view plugin will track this change\n      and send an event to Amplitude with the new URL.\n    </div>\n    <button id=\"navigate\">Go to /new-page</button>\n    <div style=\"margin-top: 20px;\">\n      Clicking the button below will tear down the page view plugin. So that\n      if you visit /new-page again, it will not track the page view.\n    </div>\n    <button id=\"teardown\">Tear down page view plugin</button>\n\n    <script>\n      document.getElementById('navigate').addEventListener('click', function() {\n        const newUrl = '/new-page';\n        \n        // Push new state to the browser history\n        history.pushState({ page: 'new-page' }, 'New Page', newUrl);\n  \n        // Optionally, update the content without reloading\n        document.querySelector('h1').innerText = 'Page 2: ' + location.pathname;\n  \n        // Dispatch a popstate event if your routing or tracking system needs it\n        const popStateEvent = new PopStateEvent('popstate', { state: { page: 'new-page' } });\n        dispatchEvent(popStateEvent);\n      });\n    </script>\n    <script type=\"module\">\n      import * as amplitude from '@amplitude/analytics-browser';\n      import { pageViewTrackingPlugin } from '@amplitude/plugin-page-view-tracking-browser';\n      window.amplitude = amplitude;\n      const pageViewPlugin = pageViewTrackingPlugin({\n        trackHistoryChanges: 'all',\n      });\n      amplitude.init(\n        import.meta.env.VITE_AMPLITUDE_API_KEY,\n        import.meta.env.VITE_AMPLITUDE_USER_ID || 'amplitude-typescript test user',\n      );\n      amplitude.add(pageViewPlugin);\n\n      document.getElementById('teardown').addEventListener('click', function() {\n        // Remove the page view plugin\n        pageViewPlugin.teardown();\n        console.log('Page view plugin removed');\n      });\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/browser-sdk/request-compression.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/amplitude.png\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Request Body Compression + Transport Test</title>\n    <style>\n      body {\n        font-family: system-ui, sans-serif;\n        max-width: 640px;\n        margin: 20px auto;\n        padding: 0 16px;\n      }\n      h1 {\n        font-size: 1.25rem;\n      }\n      .section {\n        margin: 16px 0;\n      }\n      label {\n        display: block;\n        margin: 8px 0 4px;\n        font-weight: 500;\n      }\n      select,\n      input[type=\"text\"] {\n        width: 100%;\n        padding: 8px;\n        box-sizing: border-box;\n      }\n      .hint {\n        font-size: 0.875rem;\n        color: #666;\n        margin-top: 4px;\n      }\n      button {\n        padding: 8px 16px;\n        margin: 4px 4px 4px 0;\n        cursor: pointer;\n      }\n      #status {\n        margin-top: 16px;\n        padding: 12px;\n        border-radius: 6px;\n        font-size: 0.875rem;\n      }\n      #status.info {\n        background: #e3f2fd;\n        color: #1565c0;\n      }\n      #status.success {\n        background: #e8f5e9;\n        color: #2e7d32;\n      }\n      #status.warn {\n        background: #fff3e0;\n        color: #e65100;\n      }\n      .instructions {\n        background: #f5f5f5;\n        padding: 12px;\n        border-radius: 6px;\n        font-size: 0.875rem;\n        margin-top: 16px;\n      }\n      .instructions ul {\n        margin: 8px 0 0;\n        padding-left: 20px;\n      }\n    </style>\n  </head>\n  <body>\n    <h1>Request Body Compression + Transport Test</h1>\n    <p>\n      Test <code>enableRequestBodyCompression</code> with different transports (fetch, xhr, beacon).\n      Use DevTools → Network to verify the outgoing batch request.\n    </p>\n\n    <div class=\"section\">\n      <label for=\"transport\">Transport</label>\n      <select id=\"transport\">\n        <option value=\"fetch\">fetch</option>\n        <option value=\"xhr\">xhr</option>\n        <option value=\"beacon\">beacon</option>\n      </select>\n      <div class=\"hint\">Which HTTP transport the SDK uses to send events.</div>\n    </div>\n\n    <div class=\"section\">\n      <label>\n        <input type=\"checkbox\" id=\"enableCompression\" checked />\n        Enable request body compression\n      </label>\n      <div class=\"hint\">\n        When enabled (and transport supports it), the request body is gzip-compressed with\n        <code>Content-Encoding: gzip</code>. Note: with default server URL, Amplitude always compresses;\n        this option only applies when a custom server URL is set.\n      </div>\n    </div>\n\n    <div class=\"section\">\n      <label for=\"serverUrl\">Custom server URL (optional)</label>\n      <input type=\"text\" id=\"serverUrl\" placeholder=\"e.g. https://api.amplitude.com\" />\n      <div class=\"hint\">\n        Leave empty to use the default Amplitude endpoint (compression is always on). Set a custom URL\n        to make compression follow the checkbox above.\n      </div>\n    </div>\n\n    <div class=\"section\">\n      <button id=\"initBtn\">Apply config &amp; init</button>\n      <button id=\"sendBtn\" disabled>Send test event</button>\n    </div>\n\n    <div id=\"status\" class=\"info\">\n      Choose options and click \"Apply config &amp; init\", then \"Send test event\". Check the Network\n      tab for the batch request (type: fetch/xhr or sendBeacon) and request headers (Content-Encoding: gzip when compressed).\n    </div>\n\n    <div class=\"instructions\">\n      <strong>How to verify</strong>\n      <ul>\n        <li><strong>Transport:</strong> In Network tab, find the request to <code>.../batch</code> (or similar). Request type will be XHR, Fetch, or (for beacon) a beacon request.</li>\n        <li><strong>Compression:</strong> In the request headers, look for <code>Content-Encoding: gzip</code>. Fetch and XHR support it; SendBeacon cannot set headers, so compression is not applied for beacon.</li>\n      </ul>\n    </div>\n\n    <script type=\"module\">\n      import * as amplitude from '@amplitude/analytics-browser';\n      window.amplitude = amplitude;\n\n      const transportSelect = document.getElementById('transport');\n      const enableCompressionCheckbox = document.getElementById('enableCompression');\n      const serverUrlInput = document.getElementById('serverUrl');\n      const initBtn = document.getElementById('initBtn');\n      const sendBtn = document.getElementById('sendBtn');\n      const statusEl = document.getElementById('status');\n\n      function setStatus(message, type = 'info') {\n        statusEl.textContent = message;\n        statusEl.className = type;\n      }\n\n      function getConfig() {\n        const transport = transportSelect.value;\n        const enableRequestBodyCompression = enableCompressionCheckbox.checked;\n        const serverUrl = serverUrlInput.value.trim() || undefined;\n        return {\n          transport,\n          enableRequestBodyCompression,\n          serverUrl,\n        };\n      }\n\n      initBtn.addEventListener('click', () => {\n        const { transport, enableRequestBodyCompression, serverUrl } = getConfig();\n        try {\n          amplitude.reset();\n          amplitude.init(\n            import.meta.env.VITE_AMPLITUDE_API_KEY,\n            import.meta.env.VITE_AMPLITUDE_USER_ID || 'request-compression-test-user',\n            {\n              transport,\n              enableRequestBodyCompression,\n              ...(serverUrl ? { serverUrl } : {}),\n            }\n          );\n          setStatus(\n            `Initialized with transport=${transport}, enableRequestBodyCompression=${enableRequestBodyCompression}${serverUrl ? `, serverUrl=${serverUrl}` : ' (default server)'}. Send a test event and check the Network tab.`,\n            'success'\n          );\n          sendBtn.disabled = false;\n        } catch (e) {\n          setStatus(`Init failed: ${e.message}`, 'warn');\n        }\n      });\n\n      sendBtn.addEventListener('click', () => {\n        amplitude.track('Request Compression Test Event', {\n          transport: transportSelect.value,\n          enableRequestBodyCompression: enableCompressionCheckbox.checked,\n          timestamp: new Date().toISOString(),\n        });\n        setStatus('Test event sent. Check Network tab for the batch request.', 'success');\n      });\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/browser-sdk/reset-test.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/amplitude.png\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Reset and OnReset Test</title>\n    <style>\n      body {\n        font-family: Arial, sans-serif;\n        max-width: 800px;\n        margin: 50px auto;\n        padding: 20px;\n      }\n      h1 {\n        color: #333;\n      }\n      .section {\n        margin: 20px 0;\n        padding: 15px;\n        border: 1px solid #ddd;\n        border-radius: 5px;\n        background-color: #f9f9f9;\n      }\n      button {\n        margin: 5px;\n        padding: 10px 15px;\n        background-color: #007bff;\n        color: white;\n        border: none;\n        border-radius: 4px;\n        cursor: pointer;\n        font-size: 14px;\n      }\n      button:hover {\n        background-color: #0056b3;\n      }\n      button.danger {\n        background-color: #dc3545;\n      }\n      button.danger:hover {\n        background-color: #c82333;\n      }\n      button.success {\n        background-color: #28a745;\n      }\n      button.success:hover {\n        background-color: #218838;\n      }\n      #identity {\n        font-family: monospace;\n        background-color: #e9ecef;\n        padding: 10px;\n        border-radius: 4px;\n        margin-top: 10px;\n      }\n      #logs {\n        font-family: monospace;\n        background-color: #f8f9fa;\n        padding: 10px;\n        border-radius: 4px;\n        max-height: 300px;\n        overflow-y: auto;\n        margin-top: 10px;\n      }\n      .log-entry {\n        margin: 5px 0;\n        padding: 5px;\n        border-left: 3px solid #007bff;\n        background-color: white;\n      }\n      .log-reset {\n        border-left-color: #dc3545;\n      }\n      .log-callback {\n        border-left-color: #28a745;\n      }\n    </style>\n  </head>\n  <body>\n    <h1>Reset and Plugin onReset Test</h1>\n    <p>This page demonstrates the <code>reset()</code> functionality and how plugins can respond to reset events via the <code>onReset()</code> plugin hook.</p>\n\n    <div class=\"section\">\n      <h3>Current Identity</h3>\n      <button id=\"refreshIdentity\" class=\"success\">Refresh Identity</button>\n      <div id=\"identity\">Loading...</div>\n    </div>\n\n    <div class=\"section\">\n      <h3>Actions</h3>\n      <button id=\"trackEvent\">Track Test Event</button>\n      <button id=\"addPlugin\" class=\"success\">Add Plugin with onReset Hook</button>\n      <button id=\"removePlugin\" class=\"danger\">Remove Plugin</button>\n      <button id=\"reset\" class=\"danger\">Call reset()</button>\n    </div>\n\n    <div class=\"section\">\n      <h3>Logs</h3>\n      <button id=\"clearLogs\" class=\"danger\">Clear Logs</button>\n      <div id=\"logs\"></div>\n    </div>\n\n    <script type=\"module\">\n      import * as amplitude from '@amplitude/analytics-browser';\n      window.amplitude = amplitude;\n\n      let pluginAdded = false;\n      let resetCount = 0;\n\n      // Helper function to add log entries\n      function addLog(message, type = '') {\n        const logsDiv = document.getElementById('logs');\n        const entry = document.createElement('div');\n        entry.className = `log-entry ${type}`;\n        entry.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;\n        logsDiv.appendChild(entry);\n        logsDiv.scrollTop = logsDiv.scrollHeight;\n      }\n\n      // Helper function to update identity display\n      function updateIdentity() {\n        const identity = amplitude.getIdentity();\n        const identityDiv = document.getElementById('identity');\n        identityDiv.innerHTML = `\n          <strong>User ID:</strong> ${identity.userId || '(not set)'}<br>\n          <strong>Device ID:</strong> ${identity.deviceId || '(not set)'}\n        `;\n        addLog(`Identity refreshed - UserId: ${identity.userId || '(not set)'}, DeviceId: ${identity.deviceId}`);\n      }\n\n      // Create a plugin that responds to reset events\n      const resetListenerPlugin = {\n        name: 'reset-listener-plugin',\n        type: 'enrichment',\n        \n        setup: async (config) => {\n          addLog('✓ Plugin setup completed', 'log-callback');\n        },\n        \n        execute: async (event) => {\n          // Pass through all events unchanged\n          return event;\n        },\n        \n        onReset: async () => {\n          resetCount++;\n          addLog(`✓ Plugin onReset() hook called (count: ${resetCount})`, 'log-callback');\n          \n          // Update identity display after reset\n          setTimeout(updateIdentity, 100);\n        },\n        \n        teardown: async () => {\n          addLog('✓ Plugin teardown completed', 'log-callback');\n        }\n      };\n\n      // Initialize Amplitude\n      amplitude.init(\n        import.meta.env.VITE_AMPLITUDE_API_KEY,\n        import.meta.env.VITE_AMPLITUDE_USER_ID || 'reset-test-user',\n        {\n          logLevel: 'DEBUG'\n        }\n      );\n\n      addLog('Amplitude SDK initialized');\n      updateIdentity();\n\n      // Track Event button\n      document.getElementById('trackEvent').addEventListener('click', () => {\n        amplitude.track('Test Event', { timestamp: Date.now() });\n        addLog('Event tracked: Test Event');\n      });\n\n      // Refresh Identity button\n      document.getElementById('refreshIdentity').addEventListener('click', () => {\n        updateIdentity();\n      });\n\n      // Add Plugin button\n      document.getElementById('addPlugin').addEventListener('click', async () => {\n        if (pluginAdded) {\n          addLog('⚠️ Plugin already added! Remove it first.');\n          return;\n        }\n\n        resetCount = 0;\n        await amplitude.add(resetListenerPlugin).promise;\n        pluginAdded = true;\n        addLog('✓ Plugin added with onReset hook', 'log-callback');\n      });\n\n      // Remove Plugin button\n      document.getElementById('removePlugin').addEventListener('click', async () => {\n        if (!pluginAdded) {\n          addLog('⚠️ No plugin to remove.');\n          return;\n        }\n\n        await amplitude.remove('reset-listener-plugin').promise;\n        pluginAdded = false;\n        addLog('✓ Plugin removed', 'log-callback');\n      });\n\n      // Reset button\n      document.getElementById('reset').addEventListener('click', () => {\n        addLog('Calling reset()...', 'log-reset');\n        amplitude.reset();\n        addLog('✓ reset() completed', 'log-reset');\n        \n        // Update identity display after reset\n        setTimeout(updateIdentity, 100);\n      });\n\n      // Clear logs button\n      document.getElementById('clearLogs').addEventListener('click', () => {\n        document.getElementById('logs').innerHTML = '';\n      });\n    </script>\n  </body>\n</html>\n\n"
  },
  {
    "path": "test-server/browser-sdk/web-vitals.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/amplitude.png\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <script type=\"module\" src=\"/helpers/tough-cookie\"></script>\n    <title>Web Vitals</title>\n  </head>\n  <body>\n    <script>\n        let inpDelay = 100;\n        document.querySelector('#inp-tester').addEventListener('click', () => {\n          const list = document.querySelector('#list');\n          const newChild = document.createElement('li');\n          newChild.textContent = 'Another element to trigger INP';\n          setTimeout(() => {\n            list.appendChild(newChild);\n            inpDelay += 100;\n          }, inpDelay);\n        });\n    </script>\n    <script type=\"module\">\n      import * as amplitude from '@amplitude/analytics-browser';\n      import { webVitalsPlugin } from '@amplitude/plugin-web-vitals-browser';\n      window.amplitude = amplitude;\n      const plugin = webVitalsPlugin();\n      amplitude.init(\n        import.meta.env.VITE_AMPLITUDE_API_KEY,\n        import.meta.env.VITE_AMPLITUDE_USER_ID || 'amplitude-typescript test user',\n        {},\n      );\n      amplitude.add(plugin);\n    </script>\n    <h1>Simulate Interaction to Next Paint > 300ms</h1>\n    <button id=\"simulate-btn\">Click Me</button>\n    <div id=\"result\"></div>\n  \n    <script>\n      let timeout = 100;\n      document.getElementById('simulate-btn').addEventListener('click', () => {\n        const resultEl = document.getElementById('result');\n        resultEl.textContent = '';\n  \n        // Block main thread for ~350ms to simulate poor responsiveness\n        const start = performance.now();\n        while (performance.now() - start < timeout) {\n          // Busy-wait loop\n        }\n  \n        // Simulated paint update\n        resultEl.textContent = 'Interaction complete ' + timeout + 'ms';\n        timeout += 100;\n      });\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/cookies/is-enabled.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>cookie isEnabled</title>\n</head>\n<body>\n  <pre id=\"out\"></pre>\n  <script type=\"module\">\n    import { CookieStorage } from '@amplitude/analytics-core';\n    import { getTopLevelDomain } from '@amplitude/analytics-browser/lib/esm/config';\n\n    const out = document.getElementById('out');\n\n    function log(msg) {\n      out.textContent += msg + '\\n';\n    }\n\n    async function run() {\n      const promises = [];\n\n      // call isEnabled many times concurrently to stress test the re-entrancy issue\n      // that was fixed by fixed by https://github.com/amplitude/Amplitude-TypeScript/pull/1539\n      const RUNS = 1000;\n      for (let i = 0; i < RUNS; i++) {\n        const c = new CookieStorage();\n        promises.push(c.isEnabled());\n      }\n\n      // call getTopLevelDomain many times concurrently to stress test the re-entrancy issue\n      const tldPromises = [];\n      if (!window.IS_PLAYWRIGHT) {\n        for (let i = 0; i < RUNS; i++) {\n          const tld = getTopLevelDomain(undefined, undefined);\n          tldPromises.push(tld);\n        }\n      }\n\n\n      const results = await Promise.all(promises);\n      const tldResults = await Promise.all(tldPromises);\n      \n      log(`All ${RUNS} calls to CookieStorage.prototype.isEnabled returned true: ${results.every((result) => result === true)}`);\n      log(`All ${RUNS} calls to getTopLevelDomain returned: ${tldResults.every((result) => result !== '')}`);\n      \n      // Assert that all of the concurrent calls returned true\n      let failureCount = 0;\n      for (const result of results) {\n        if (!result) {\n          const errorMessage = `isEnabled returned '${result}'. Test failed.`;\n          console.error(errorMessage);\n          failureCount++;\n        }\n      }\n\n      let tldFailureCount = 0;\n      for (const tldResult of tldResults) {\n        if (tldResult === '') {\n          const errorMessage = `getTopLevelDomain returned ''. Test failed.`;\n          tldFailureCount++;\n        }\n      }\n\n      // test all TLD results are the same\n      const allSame = tldResults.every((result) => result === tldResults[0]);\n      log(`All TLD results are the same: ${allSame}`);\n      if (!allSame) {\n        throw new Error(`getTopLevelDomain: all TLD results are not the same`);\n      }\n\n      log(`Failure count: ${failureCount}`);\n      if (failureCount > 0) {\n        throw new Error(`isEnabled: ${failureCount} / ${RUNS} failures occurred`);\n      }\n      log(`TLD failure count: ${tldFailureCount}`);\n      if (tldFailureCount > 0) {\n        throw new Error(`getTopLevelDomain: ${tldFailureCount} / ${RUNS} failures occurred`);\n      }\n    }\n    run();\n  </script>\n</body>\n</html>\n"
  },
  {
    "path": "test-server/cookies/transaction-test.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>cookie transaction test</title>\n  <body>Open the console to see stuff -></body>\n</head>\n<body>\n  <script type=\"module\">\n    import { CookieStorage } from '@amplitude/analytics-core';\n\n    const cookies = new CookieStorage({}, {});\n\n    // stress test the transaction function\n    function incrementValue() {\n      return cookies.transaction('incrementing_value', (storageSync) => {\n        const currentValue = storageSync.get();\n        const nextValue = currentValue ? Number(currentValue) + 1 : 1;\n        storageSync.set(nextValue);\n        return storageSync.get();\n      });\n    }\n\n    let previousResult, result;\n    const promises = [];\n\n    promises.push(cookies.transaction('incrementing_value', (storageSync) => {\n      storageSync.set(0);\n      return 0;\n    }));\n\n    const TRANSACTIONS = 1000;\n\n    for (let i = 0; i < TRANSACTIONS; i++) {\n      promises.push(incrementValue())\n    }\n    \n    Promise.all(promises)\n      .then((res) => {\n        console.log('values after all transactions', JSON.stringify(res, null, 2));\n        for (let i = 0; i < res.length; i++) {\n          if (res[i] !== i) {\n            throw new Error('Result is not the expected value. Synchronization issue:', res[i], i + 1);\n          }\n        }\n        console.info('Test passed');\n      })\n      .catch((err) => {\n        throw err;\n      });\n\n  </script>\n</body>\n</html>\n"
  },
  {
    "path": "test-server/diagnostics.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/amplitude.png\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>SDK Diagnostics Test</title>\n    <style>\n      body {\n        font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n        padding: 2rem;\n        max-width: 720px;\n        margin: 0 auto;\n        background-color: #f5f6fa;\n        color: #222;\n      }\n      .section {\n        margin-bottom: 2rem;\n      }\n      .actions {\n        display: flex;\n        gap: 1rem;\n        margin-bottom: 1rem;\n        flex-wrap: wrap;\n      }\n      button {\n        padding: 0.75rem 1.5rem;\n        border-radius: 6px;\n        border: none;\n        cursor: pointer;\n        font-size: 1rem;\n      }\n      .init-btn {\n        background-color: #37b24d;\n        color: white;\n      }\n      .plugin-btn {\n        background-color: #1c7ed6;\n        color: white;\n      }\n      .sdk-error-btn {\n        background-color: #f59f00;\n        color: white;\n      }\n      .not-captured-btn {\n        background-color: #fa5252;\n        color: white;\n      }\n      .log {\n        background: #0c111b;\n        color: #f1f3f5;\n        padding: 1rem;\n        min-height: 200px;\n        border-radius: 8px;\n        overflow: auto;\n        font-size: 0.85rem;\n        white-space: pre-wrap;\n        word-break: break-all;\n      }\n      code {\n        background: #e9ecef;\n        padding: 0.2rem 0.4rem;\n        border-radius: 4px;\n      }\n      h3 {\n        margin-top: 1.5rem;\n        margin-bottom: 0.5rem;\n      }\n    </style>\n  </head>\n  <script src=\"/analytics-browser/lib/scripts/amplitude-min.js\"></script>\n  <script type=\"module\">\n    // Expose env vars to window for use in regular scripts\n    window.AMPLITUDE_API_KEY = import.meta.env.VITE_AMPLITUDE_API_KEY;\n  </script>\n  <script>\n    // Helper to log messages\n    function logMessage(message) {\n      var logElement = document.getElementById('log');\n      if (!logElement) return;\n      var timestamp = new Date().toISOString();\n      logElement.textContent = '[' + timestamp + '] ' + message + '\\n' + logElement.textContent;\n    }\n\n    // Register global error handlers to see what's happening\n    window.addEventListener('error', function(event) {\n      logMessage('[window.error] ' + event.message + ' (' + (event.filename || 'unknown') + ')');\n    });\n\n    window.addEventListener('unhandledrejection', function(event) {\n      logMessage('[unhandledrejection] ' + String(event.reason));\n    });\n  </script>\n  <body>\n    <h1>SDK Diagnostics Test</h1>\n    <p>This page tests SDK diagnostics including uncaught SDK error capture. SDK is loaded via <code>&lt;script&gt;</code> tag.</p>\n\n    <div class=\"section\">\n      <h3>SDK Initialization</h3>\n      <div class=\"actions\">\n        <button id=\"initButton\" class=\"init-btn\">Initialize SDK</button>\n        <button id=\"addPluginButton\" class=\"plugin-btn\">Add Plugin (Remove User/Device ID)</button>\n      </div>\n    </div>\n\n    <div class=\"section\">\n      <h3>Uncaught SDK Error Tests</h3>\n      <div class=\"actions\">\n        <button class=\"sdk-error-btn\" onclick=\"triggerSdkSetupError()\">SDK Error: Setup Error</button>\n        <button class=\"not-captured-btn\" onclick=\"setupCustomPluginClickHandler()\">Custom Plugin Click Handler (Not Captured)</button>\n        <button id=\"custom-plugin-click-target\" class=\"not-captured-btn\" style=\"display:none;\">Click to Throw Error</button>\n        <button class=\"not-captured-btn\" onclick=\"triggerAppError()\">App Error (Not Captured)</button>\n      </div>\n    </div>\n\n    <h3>Event Log</h3>\n    <pre id=\"log\" class=\"log\"></pre>\n\n    <h3>Instructions</h3>\n    <ul>\n      <li>Click <strong>Initialize SDK</strong> first to set up Amplitude</li>\n      <li>Open Developer Tools → Network tab to see diagnostics requests</li>\n      <li><strong>SDK Error: Setup Error</strong> - Plugin setup returns a rejected promise (should be captured - error originates from SDK code)</li>\n      <li><strong>Custom Plugin Click Handler</strong> - Custom plugin sets up a click handler that throws (NOT captured - error originates from this page's code, not SDK)</li>\n      <li><strong>App Error</strong> - Throws error from application code (NOT captured - error originates from this page's code)</li>\n    </ul>\n\n    <script>\n      // Create plugin that removes user_id and device_id from events\n      function removeIdsPlugin() {\n        return {\n          name: 'remove-ids-plugin',\n          type: 'before',\n          execute: function(event) {\n            delete event.user_id;\n            delete event.device_id;\n            logMessage('Plugin: Removed user_id and device_id from event');\n            return Promise.resolve(event);\n          }\n        };\n      }\n\n      document.getElementById('initButton').addEventListener('click', function() {\n        var apiKey = window.AMPLITUDE_API_KEY;\n        \n        if (!apiKey) {\n          alert('Please set VITE_AMPLITUDE_API_KEY in .env');\n          return;\n        }\n        \n        amplitude._setDiagnosticsSampleRate(1);\n        amplitude.init(apiKey, undefined, {\n            autocapture: true,\n        });\n        logMessage('SDK initialized with API key: ' + apiKey.substring(0, 10) + '...');\n      });\n      \n      document.getElementById('addPluginButton').addEventListener('click', function() {\n        amplitude.add(removeIdsPlugin());\n        logMessage('Plugin added: remove-ids-plugin');\n      });\n\n      // Uncaught SDK error test functions\n      function triggerSdkSetupError() {\n        logMessage('Adding plugin that throws in setup...');\n        amplitude.add({\n          name: 'plugin-setup-error',\n          type: 'before',\n          setup: function() {\n            return Promise.reject(new Error('Plugin setup error'));\n          },\n          execute: function(event) {\n            return Promise.resolve(event);\n          }\n        });\n      }\n\n      function setupCustomPluginClickHandler() {\n        logMessage('Adding custom plugin that sets up a click handler...');\n        amplitude.add({\n          name: 'custom-plugin-click-handler',\n          type: 'before',\n          setup: function() {\n            var btn = document.getElementById('custom-plugin-click-target');\n            btn.style.display = 'inline-block';\n            btn.addEventListener('click', function() {\n              logMessage('Click handler throwing error (from custom plugin code, not SDK)...');\n              throw new Error('Error from custom plugin click handler');\n            });\n            logMessage('Plugin setup complete. Click the red \"Click to Throw Error\" button.');\n            return Promise.resolve();\n          },\n          execute: function(event) {\n            return Promise.resolve(event);\n          }\n        });\n      }\n\n      function triggerAppError() {\n        logMessage('Throwing error from application code...');\n        throw new Error('Application level error');\n      }\n\n      logMessage('Page loaded. Click \"Initialize SDK\" to start.');\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/form-test.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Form Test with Performance Tracking</title>\n    <style>\n        body {\n            font-family: Arial, sans-serif;\n            max-width: 800px;\n            margin: 0 auto;\n            padding: 20px;\n        }\n        .form-group {\n            margin-bottom: 15px;\n        }\n        label {\n            display: block;\n            margin-bottom: 5px;\n        }\n        input, select, textarea {\n            width: 100%;\n            padding: 8px;\n            margin-bottom: 10px;\n            border: 1px solid #ddd;\n            border-radius: 4px;\n        }\n        button {\n            background-color: #4CAF50;\n            color: white;\n            padding: 10px 20px;\n            border: none;\n            border-radius: 4px;\n            cursor: pointer;\n        }\n        button:hover {\n            background-color: #45a049;\n        }\n        #result {\n            margin-top: 20px;\n            padding: 15px;\n            border: 1px solid #ddd;\n            border-radius: 4px;\n            display: none;\n        }\n        #performance-metrics {\n            margin-top: 20px;\n            padding: 15px;\n            background-color: #f8f9fa;\n            border-radius: 4px;\n        }\n    </style>\n</head>\n<body>\n    <h1>Form Test with Performance Tracking</h1>\n    \n    <form id=\"testForm\" novalidate>\n        <div class=\"form-container-wrapper\">\n            <div class=\"form-section-primary\">\n                <div class=\"input-group-container\">\n                    <div class=\"form-field-wrapper\">\n                        <div class=\"input-label-container\">\n                            <label for=\"text\">Text Input:</label>\n                        </div>\n                        <div class=\"input-element-wrapper\">\n                            <input type=\"text\" id=\"text\" name=\"text\" required>\n                        </div>\n                    </div>\n                </div>\n\n                <div class=\"input-group-container\">\n                    <div class=\"form-field-wrapper\">\n                        <div class=\"input-label-container\">\n                            <label for=\"email\">Email:</label>\n                        </div>\n                        <div class=\"input-element-wrapper\">\n                            <input type=\"email\" id=\"email\" name=\"email\" required>\n                        </div>\n                    </div>\n                </div>\n\n                <div class=\"input-group-container\">\n                    <div class=\"form-field-wrapper\">\n                        <div class=\"input-label-container\">\n                            <label for=\"number\">Number:</label>\n                        </div>\n                        <div class=\"input-element-wrapper\">\n                            <input type=\"number\" id=\"number\" name=\"number\" min=\"0\" max=\"100\">\n                        </div>\n                    </div>\n                </div>\n            </div>\n\n            <div class=\"form-section-secondary\">\n                <div class=\"input-group-container\">\n                    <div class=\"form-field-wrapper\">\n                        <div class=\"input-label-container\">\n                            <label for=\"date\">Date:</label>\n                        </div>\n                        <div class=\"input-element-wrapper\">\n                            <input type=\"date\" id=\"date\" name=\"date\">\n                        </div>\n                    </div>\n                </div>\n\n                <div class=\"input-group-container\">\n                    <div class=\"form-field-wrapper\">\n                        <div class=\"input-label-container\">\n                            <label for=\"color\">Color:</label>\n                        </div>\n                        <div class=\"input-element-wrapper\">\n                            <input type=\"color\" id=\"color\" name=\"color\">\n                        </div>\n                    </div>\n                </div>\n\n                <div class=\"input-group-container\">\n                    <div class=\"form-field-wrapper\">\n                        <div class=\"input-label-container\">\n                            <label for=\"range\">Range:</label>\n                        </div>\n                        <div class=\"input-element-wrapper\">\n                            <input type=\"range\" id=\"range\" name=\"range\" min=\"0\" max=\"100\">\n                        </div>\n                    </div>\n                </div>\n            </div>\n\n            <div class=\"form-section-tertiary\">\n                <div class=\"input-group-container\">\n                    <div class=\"form-field-wrapper\">\n                        <div class=\"input-label-container\">\n                            <label for=\"select\">Select:</label>\n                        </div>\n                        <div class=\"input-element-wrapper\">\n                            <select id=\"select\" name=\"select\">\n                                <option value=\"\">Choose an option</option>\n                                <option value=\"1\">Option 1</option>\n                                <option value=\"2\">Option 2</option>\n                                <option value=\"3\">Option 3</option>\n                            </select>\n                        </div>\n                    </div>\n                </div>\n\n                <div class=\"input-group-container\">\n                    <div class=\"form-field-wrapper\">\n                        <div class=\"input-label-container\">\n                            <label for=\"textarea\">Textarea:</label>\n                        </div>\n                        <div class=\"input-element-wrapper\">\n                            <textarea id=\"textarea\" name=\"textarea\" rows=\"4\"></textarea>\n                        </div>\n                    </div>\n                </div>\n            </div>\n\n            <div class=\"form-section-quaternary\">\n                <div class=\"input-group-container\">\n                    <div class=\"form-field-wrapper\">\n                        <div class=\"input-label-container\">\n                            <label>Checkboxes:</label>\n                        </div>\n                        <div class=\"input-element-wrapper\">\n                            <div class=\"checkbox-group\">\n                                <div class=\"checkbox-item\">\n                                    <input type=\"checkbox\" id=\"checkbox1\" name=\"checkbox1\">\n                                    <label for=\"checkbox1\">Option 1</label>\n                                </div>\n                                <div class=\"checkbox-item\">\n                                    <input type=\"checkbox\" id=\"checkbox2\" name=\"checkbox2\">\n                                    <label for=\"checkbox2\">Option 2</label>\n                                </div>\n                            </div>\n                        </div>\n                    </div>\n                </div>\n\n                <div class=\"input-group-container\">\n                    <div class=\"form-field-wrapper\">\n                        <div class=\"input-label-container\">\n                            <label>Radio Buttons:</label>\n                        </div>\n                        <div class=\"input-element-wrapper\">\n                            <div class=\"radio-group\">\n                                <div class=\"radio-item\">\n                                    <input type=\"radio\" id=\"radio1\" name=\"radio\" value=\"1\">\n                                    <label for=\"radio1\">Option 1</label>\n                                </div>\n                                <div class=\"radio-item\">\n                                    <input type=\"radio\" id=\"radio2\" name=\"radio\" value=\"2\">\n                                    <label for=\"radio2\">Option 2</label>\n                                </div>\n                            </div>\n                        </div>\n                    </div>\n                </div>\n            </div>\n\n            <div class=\"form-submit-container\">\n                <button type=\"submit\">Submit Form</button>\n            </div>\n        </div>\n    </form>\n\n    <div id=\"result\"></div>\n    <div id=\"performance-metrics\"></div>\n    \n    <div style=\"margin-top: 20px;\">\n        <button type=\"button\" id=\"blockButton\" style=\"background-color: #f44336;\">Block for 3 Seconds</button>\n    </div>\n\n    <script type=\"module\">\n        import * as amplitude from '@amplitude/analytics-browser';\n        import { stubPlugin } from '@amplitude/plugin-stub-browser';\n\n        // Get URL parameters\n        const urlParams = new URLSearchParams(window.location.search);\n\n        // Initialize Amplitude\n        window.amplitude = amplitude;\n        const apiKey = import.meta.env.VITE_AMPLITUDE_API_KEY;\n        amplitude.add(stubPlugin());\n        amplitude.init(apiKey, 'test-user', {\n            fetchRemoteConfig: false,\n            autocapture: {\n                pageViews: false,\n                elementInteractions: false,\n                formInteractions: {\n                    shouldTrackSubmit: (event) => {\n                        const form = event.target;\n                        const isValid = form.checkValidity();\n                        console.log('Custom form validity check:', isValid);\n                        return isValid;\n                    }\n                },\n            },\n            logLevel: 4,\n        });\n\n        // Performance tracking\n        let startTime;\n        let tbt = 0;\n        let longTasks = [];\n\n        // Set up PerformanceObserver for long tasks\n        const longTaskObserver = new PerformanceObserver((list) => {\n            for (const entry of list.getEntries()) {\n                console.log('Long task', entry);\n                longTasks.push(entry);\n            }\n        });\n        longTaskObserver.observe({ entryTypes: ['longtask'] });\n\n        // Function to calculate Total Blocking Time\n        function calculateTBT() {\n            return longTasks.reduce((total, entry) => total + entry.duration, 0);\n        }\n\n        // Function to block the main thread\n        function blockThread(duration) {\n            const start = performance.now();\n            while (performance.now() - start < duration) {\n                // Busy loop to block the thread\n            }\n        }\n\n        // Add click handler for block button\n        document.getElementById('blockButton').addEventListener('click', () => {\n            blockThread(3000); // Block for 3 seconds\n        });\n\n        // Start performance tracking when the page loads\n        window.addEventListener('load', () => {\n            startTime = performance.now();\n        });\n\n        // Handle form submission\n        document.getElementById('testForm').addEventListener('submit', function(e) {\n            e.preventDefault();\n            \n            // Calculate final TBT\n            tbt = calculateTBT();\n            \n            // Show submission result\n            const resultDiv = document.getElementById('result');\n            resultDiv.style.display = 'block';\n            resultDiv.innerHTML = '<h3>Form Submitted Successfully!</h3>';\n            \n            // Display performance metrics\n            const metricsDiv = document.getElementById('performance-metrics');\n            metricsDiv.innerHTML = `\n                <h3>Performance Metrics:</h3>\n                <p>Total Blocking Time (TBT): <span id=\"tbt\">${tbt.toFixed(2)}</span>ms</p>\n                <p>Number of Long Tasks: ${longTasks.length}</p>\n            `;\n        });\n    </script>\n</body>\n</html> "
  },
  {
    "path": "test-server/gtm/browser-gtm-wrapper.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/amplitude.png\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Browser SDK Test</title>\n  </head>\n  <body>\n    <div id=\"app\">\n      Test Browser SDK via loading from CDN with GTM Wrapper\n    </div>\n    <script src=\"https://cdn.amplitude.com/libs/analytics-browser-gtm-wrapper-3.15.0.js.br\"></script>\n    <script type=\"module\">\n        window.API_KEY = import.meta.env.VITE_AMPLITUDE_API_KEY;\n\n        // config values\n        var ampAPIkey = window.API_KEY;\n        var instanceName = 'allAmp';\n        var ampUserID = 'fake-user';\n        var ampOptions = {\n        instanceName: instanceName,\n        autocapture: {\n            attribution: {\n            resetSessionOnNewCampaign: true,\n            },\n            sessions: true,\n            pageViews: false,\n            formInteractions: false,\n            fileDownloads: false,\n            elementInteractions: false,\n        }\n        };\n    \n        // Amp init  \n        var ampGTMInstance = amplitudeGTM.createInstance(instanceName);\n        ampGTMInstance.init(ampAPIkey, ampUserID, ampOptions).promise.then(function(result){\n          console.log('Amp GTM initializated');\n          console.log(\"Amp sessionID: \" + amplitudeGTM._iq[instanceName].getSessionId());\n          console.log(\"Amp getDeviceId: \" + amplitudeGTM._iq[instanceName].getDeviceId());\n          console.log(\"Amp getUserId: \" + amplitudeGTM._iq[instanceName].getUserId());\n        });\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/gtm/gtm.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/amplitude.png\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Browser SDK Test</title>\n    <!-- Google Tag Manager -->\n    <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':\n    new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],\n    j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=\n    'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);\n    })(window,document,'script','dataLayer','%VITE_GTM_CONTAINER_ID%');</script>\n    <!-- End Google Tag Manager -->\n  </head>\n  <body>\n    <div id=\"app\">\n      GTM test page. Run this page from tagmanager.google.com\n    </div>\n    <!-- Google Tag Manager (noscript) -->\n    <noscript><iframe src=\"https://www.googletagmanager.com/ns.html?id=%VITE_GTM_CONTAINER_ID%\"\n    height=\"0\" width=\"0\" style=\"display:none;visibility:hidden\"></iframe></noscript>\n    <!-- End Google Tag Manager (noscript) -->\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/gtm-snippet/gtm-snippet.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/amplitude.png\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <script src=\"/gtm-snippet/lib/scripts/analytics-browser-gtm-wrapper.min.js.gz\"></script>\n    <script type=\"module\">\n      amplitude.init(import.meta.env.VITE_AMPLITUDE_API_KEY);\n      amplitude.track('GTM Snippet Test');\n    </script>\n    <title>GTM Snippet Test</title>\n    \n  </head>\n  <body>\n    <div id=\"app\">\n      GTM Snippet Test\n      This tests packages/gtm-snippet/lib/scripts/analytics-browser-gtm-wrapper.min.js.gz\n    </div>\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/helpers/tough-cookie.js",
    "content": "// legal cookie names\n// do not add or remove from this unless you're certain the new\n// cookie names will be accepted in a strict cookie environment\nconst LEGAL_COOKIE_PATTERNS = [\n  'AMP_TEST', 'AMP_TLDTEST',\n  /^AMP_MKTG_[A-Za-z0-9]{10}$/,\n  /^AMP_[A-Za-z0-9]{10}$/,\n];\n\nconst desc = Object.getOwnPropertyDescriptor(Document.prototype, \"cookie\");\n\nObject.defineProperty(document, \"cookie\", {\n  configurable: true,\n  enumerable: true,\n  get() {\n    return desc.get.call(document);\n  },\n  set(value) {\n    const name = value.split(\"=\")[0].trim();\n    if (!LEGAL_COOKIE_PATTERNS.some((pattern) => {\n      if (pattern instanceof RegExp) {\n        return pattern.test(name);\n      }\n      return pattern === name;\n    })) {\n      throw new Error(`Illegal cookie name: ${name}`)\n    }\n    return desc.set.call(document, value);\n  },\n});"
  },
  {
    "path": "test-server/iframe-sandbox/child.html",
    "content": "<!doctype html>\n<html>\n  <head>\n    <meta charset=\"UTF-8\" />\n    <script type=\"text/javascript\" src=\"/analytics-browser/lib/scripts/amplitude-min.js\"></script>\n    <script type=\"text/javascript\">\n      window.addEventListener('message', function (event) {\n        if (event.data?.type === 'AMPLITUDE_INIT' && window.amplitude) {\n          window.amplitude.init(event.data.apiKey, event.data.userId, {\n            autocapture: true,\n            //identityStorage: 'localStorage',\n          });\n          window.amplitude.track('test');\n        }\n      });\n    </script>\n  </head>\n  <body>\n    <h2>Child frame that resembles Shopify's iframe sandbox</h2>\n    <p>This page is loaded inside the host shell iframe</p>\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/iframe-sandbox/parent.html",
    "content": "<!doctype html>\n<html>\n  <body>\n    <h1>Host shell</h1>\n\n    <iframe\n      id=\"child-frame\"\n      src=\"/iframe-sandbox/child.html\"\n      sandbox=\"allow-scripts allow-forms\"\n      style=\"width:100%;height:400px;border:1px solid #ccc\"\n    ></iframe>\n\n    <script type=\"module\">\n      const apiKey = import.meta.env.VITE_AMPLITUDE_API_KEY;\n      const userId = import.meta.env.VITE_AMPLITUDE_USER_ID || 'analytics-browser-local-test-user';\n      const iframe = document.getElementById('child-frame');\n      iframe.addEventListener('load', () => {\n        iframe.contentWindow?.postMessage(\n          { type: 'AMPLITUDE_INIT', apiKey, userId },\n          '*'\n        );\n      });\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"UTF-8\" />\n    <title>Amplitude Typescript SDK: Test Server Home Page</title>\n    <style>\n      body {\n        font-family: monospace;\n        margin: 20px;\n      }\n      a {\n        color: #0000EE;\n        text-decoration: none;\n      }\n      a:hover {\n        text-decoration: underline;\n      }\n      h1 {\n        font-size: 1.2em;\n        margin-bottom: 20px;\n      }\n      .directory {\n        margin-bottom: 10px;\n      }\n      .directory-name {\n        font-weight: bold;\n      }\n      .file {\n        margin-left: 20px;\n      }\n      .file-item, .dir-item {\n        padding: 2px 0;\n      }\n      .description {\n        margin-bottom: 20px;\n        color: #666;\n      }\n    </style>\n  </head>\n  <body>\n    <h1>Amplitude Typescript SDK: Test Server Home Page</h1>\n    <div class=\"description\">\n      To add new test pages, add HTML files to the \"test-server/\" directory or any of its subdirectories. \n      They will automatically appear in this listing.\n    </div>\n    <div id=\"fileList\">\n      <!-- File list will be populated by JavaScript -->\n    </div>\n\n    <script>\n      async function loadFileList() {\n        try {\n          const response = await fetch('/api/list-files');\n          const files = await response.json();\n          const fileList = document.getElementById('fileList');\n          \n          // Create a tree structure for directories and files\n          const tree = {};\n          \n          files.forEach(file => {\n            const pathParts = file.path.split('/').filter(Boolean);\n            let current = tree;\n            \n            // Build the tree structure\n            for (let i = 0; i < pathParts.length; i++) {\n              const part = pathParts[i];\n              if (i === pathParts.length - 1) {\n                // This is a file\n                if (!current.files) current.files = [];\n                current.files.push(file);\n              } else {\n                // This is a directory\n                if (!current.dirs) current.dirs = {};\n                if (!current.dirs[part]) current.dirs[part] = {};\n                current = current.dirs[part];\n              }\n            }\n          });\n\n          function renderTree(node, path = '', indent = 0) {\n            const container = document.createElement('div');\n            \n            // First render files\n            if (node.files) {\n              node.files.sort((a, b) => a.path.localeCompare(b.path));\n              node.files.forEach(file => {\n                const fileDiv = document.createElement('div');\n                fileDiv.style.marginLeft = `${indent * 20}px`;\n                fileDiv.className = 'file-item';\n                \n                const link = document.createElement('a');\n                link.href = file.path;\n                link.textContent = file.path.split('/').pop();\n                \n                fileDiv.appendChild(link);\n                container.appendChild(fileDiv);\n              });\n            }\n            \n            // Then render directories\n            if (node.dirs) {\n              const sortedDirs = Object.keys(node.dirs).sort();\n              sortedDirs.forEach(dir => {\n                const dirDiv = document.createElement('div');\n                dirDiv.style.marginLeft = `${indent * 20}px`;\n                dirDiv.className = 'dir-item';\n                \n                const dirName = document.createElement('div');\n                dirName.className = 'directory-name';\n                dirName.textContent = `${dir}/`;\n                dirDiv.appendChild(dirName);\n                \n                container.appendChild(dirDiv);\n                container.appendChild(renderTree(node.dirs[dir], path + dir + '/', indent + 1));\n              });\n            }\n            \n            return container;\n          }\n          \n          fileList.appendChild(renderTree(tree));\n        } catch (error) {\n          console.error('Error loading file list:', error);\n          document.getElementById('fileList').innerHTML = 'Error loading file list';\n        }\n      }\n\n      document.addEventListener('DOMContentLoaded', loadFileList);\n    </script>\n  </body>\n</html>"
  },
  {
    "path": "test-server/mock-api.js",
    "content": "import { SourceMapConsumer } from 'source-map';\nimport https from 'https';\n\n// Mock API endpoints for Vite dev server\nexport function createMockApi() {\n  return {\n    name: 'mock-api',\n    configureServer(server) {\n      configureMockApiMiddleware(server.middlewares);\n      configureUnminifyMiddleware(server.middlewares);\n    },\n    configurePreviewServer(server) {\n      configureMockApiMiddleware(server.middlewares);\n      configureUnminifyMiddleware(server.middlewares);\n    }\n  };\n}\n\n// Function to configure mock API middleware that can be used by both dev and preview servers\nexport function configureMockApiMiddleware(middlewares) {\n  // Status code endpoint - responds with the status code specified in the URL\n  middlewares.use((req, res, next) => {\n    const statusMatch = req.url.match(/^\\/api\\/status\\/(\\d+)/);\n    \n    if (statusMatch) {\n      const statusCode = parseInt(statusMatch[1]);\n      \n      // Parse sleep parameter from query string\n      const url = new URL(req.url, `http://${req.headers.host}`);\n      const sleepMs = parseInt(url.searchParams.get('sleep')) || 0;\n      \n      // Set CORS headers\n      res.setHeader('Access-Control-Allow-Origin', '*');\n      res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS, HEAD, PATCH');\n      res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With');\n      res.setHeader('Authorization', 'SECRET TOKEN, THIS SHOULD NEVER BE CAPTURED BY AMPLITUDE');\n\n      // Handle preflight requests\n      if (req.method === 'OPTIONS') {\n        res.statusCode = 200;\n        res.end();\n        return;\n      }\n\n      // Create response based on status code\n      const response = {\n        status: statusCode,\n        message: getStatusMessage(statusCode),\n        method: req.method,\n        timestamp: new Date().toISOString(),\n        url: req.url,\n        sleep: sleepMs\n      };\n\n      // If sleep parameter is provided, delay the response\n      if (sleepMs > 0) {\n        setTimeout(() => {\n          res.statusCode = statusCode;\n          res.setHeader('Content-Type', 'application/json');\n          res.end(JSON.stringify(response));\n        }, sleepMs);\n      } else {\n        // Set the status code from the URL\n        res.statusCode = statusCode;\n        res.setHeader('Content-Type', 'application/json');\n        res.end(JSON.stringify(response));\n      }\n      \n      return;\n    }\n    \n    next();\n  });\n\n  // Simple test endpoint\n  middlewares.use('/api/test', (req, res) => {\n    res.setHeader('Content-Type', 'application/json');\n    res.setHeader('Access-Control-Allow-Origin', '*');\n    \n    if (req.method === 'GET') {\n      res.end(JSON.stringify({ \n        message: 'Hello from mock API!',\n        method: 'GET',\n        timestamp: new Date().toISOString()\n      }));\n    } else if (req.method === 'POST') {\n      res.end(JSON.stringify({ \n        message: 'Data received!',\n        method: 'POST',\n        timestamp: new Date().toISOString()\n      }));\n    }\n  });\n\n  // CORS error endpoint - only allows CORS from non-localhost domains\n  middlewares.use('/api/cors-error', (req, res) => {\n    const origin = req.headers.origin;\n    \n    // Set CORS headers only for non-localhost origins\n    if (origin && !origin.includes('localhost') && !origin.includes('127.0.0.1')) {\n      res.setHeader('Access-Control-Allow-Origin', origin);\n      res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS, HEAD, PATCH');\n      res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With');\n    }\n    \n    // Handle preflight requests\n    if (req.method === 'OPTIONS') {\n      if (origin && !origin.includes('localhost') && !origin.includes('127.0.0.1')) {\n        res.statusCode = 200;\n        res.end();\n      } else {\n        res.statusCode = 403; // Forbidden for localhost\n        res.end();\n      }\n      return;\n    }\n    \n    res.setHeader('Content-Type', 'application/json');\n    \n    if (req.method === 'GET') {\n      res.end(JSON.stringify({ \n        message: 'This endpoint only allows CORS from non-localhost domains',\n        method: 'GET',\n        timestamp: new Date().toISOString(),\n        note: 'This should cause a CORS error when accessed from localhost',\n        origin: origin || 'No origin header'\n      }));\n    } else if (req.method === 'POST') {\n      res.end(JSON.stringify({ \n        message: 'This endpoint only allows CORS from non-localhost domains',\n        method: 'POST',\n        timestamp: new Date().toISOString(),\n        note: 'This should cause a CORS error when accessed from localhost',\n        origin: origin || 'No origin header'\n      }));\n    }\n  });\n}\n\n// Helper function to get status message\nfunction getStatusMessage(statusCode) {\n  const messages = {\n    200: 'OK',\n    201: 'Created',\n    204: 'No Content',\n    301: 'Moved Permanently',\n    302: 'Found',\n    304: 'Not Modified',\n    400: 'Bad Request',\n    401: 'Unauthorized',\n    403: 'Forbidden',\n    404: 'Not Found',\n    405: 'Method Not Allowed',\n    408: 'Request Timeout',\n    409: 'Conflict',\n    429: 'Too Many Requests',\n    500: 'Internal Server Error',\n    501: 'Not Implemented',\n    502: 'Bad Gateway',\n    503: 'Service Unavailable',\n    504: 'Gateway Timeout'\n  };\n  \n  return messages[statusCode] || `Status ${statusCode}`;\n}\n\n/**\n * Parse a CDN URL to extract package name, version, and file suffix\n * Example: https://cdn.amplitude.com/libs/analytics-browser-2.33.5-min.js.gz:1:54975\n * Returns: { packageName: 'analytics-browser', version: '2.33.5', suffix: 'min', line: 1, column: 54975 }\n */\nfunction parseCdnUrl(stacktraceLine) {\n  // Pattern: https://cdn.amplitude.com/libs/{name}-{version}-{suffix}.js.gz:{line}:{column}\n  // The suffix could be 'min' or 'gtm-min' etc.\n  const regex = /https?:\\/\\/cdn\\.amplitude\\.com\\/libs\\/([a-z-]+)-([\\d.]+)-([a-z-]+)\\.js(?:\\.gz|\\.br)?:(\\d+):(\\d+)/i;\n  const match = stacktraceLine.match(regex);\n  \n  if (!match) {\n    return null;\n  }\n  \n  return {\n    packageName: match[1],\n    version: match[2],\n    suffix: match[3],\n    line: parseInt(match[4], 10),\n    column: parseInt(match[5], 10),\n    originalUrl: stacktraceLine\n  };\n}\n\n/**\n * Build CDN URL for the source map based on parsed URL info\n * Example: analytics-browser-2.33.5-min.js.gz → https://cdn.amplitude.com/libs/analytics-browser-2.33.5-min.js.map\n */\nfunction getSourceMapCdnUrl(parsedUrl) {\n  const { packageName, version, suffix } = parsedUrl;\n  return `https://cdn.amplitude.com/libs/${packageName}-${version}-${suffix}.js.map`;\n}\n\n/**\n * Fetch source map from CDN using Node.js https module\n */\nfunction fetchSourceMapFromCdn(sourceMapUrl) {\n  return new Promise((resolve, reject) => {\n    https.get(sourceMapUrl, (res) => {\n      const { statusCode } = res;\n      \n      if (statusCode === 404 || statusCode === 403) {\n        res.resume(); // Consume response to free up memory\n        const error = new Error('SOURCE_MAP_NOT_FOUND');\n        error.status = statusCode;\n        error.sourceMapUrl = sourceMapUrl;\n        reject(error);\n        return;\n      }\n      \n      if (statusCode !== 200) {\n        res.resume();\n        reject(new Error(`Failed to fetch source map: ${statusCode}`));\n        return;\n      }\n\n      let data = '';\n      res.on('data', (chunk) => { data += chunk; });\n      res.on('end', () => {\n        try {\n          resolve(JSON.parse(data));\n        } catch (e) {\n          reject(new Error(`Failed to parse source map JSON: ${e.message}`));\n        }\n      });\n    }).on('error', (err) => {\n      reject(new Error(`Network error fetching source map: ${err.message}`));\n    });\n  });\n}\n\n/**\n * Clean up source path from flattened source map\n * The flattened source map paths are relative to packages/{package}/lib/scripts/\n * Example: ../../../analytics-core/src/diagnostics/diagnostics-client.ts\n *       -> packages/analytics-core/src/diagnostics/diagnostics-client.ts\n * Example: ../../../src/index.ts (same package)\n *       -> packages/analytics-browser/src/index.ts\n */\nfunction resolveSourcePath(sourcePath, parsedUrl) {\n  // Handle node_modules paths - these are external dependencies\n  if (sourcePath.includes('node_modules')) {\n    return {\n      relativePath: sourcePath,\n      isExternal: true,\n      isTypeScript: false\n    };\n  }\n\n  // Clean up the relative path\n  // Paths like ../../../analytics-core/src/... need to be converted to packages/analytics-core/src/...\n  // Paths like ../../../src/... refer to the same package (e.g., analytics-browser)\n  let cleanPath = sourcePath;\n  \n  // Remove leading ../ segments and extract the package-relative path\n  const pathParts = sourcePath.split('/');\n  let i = 0;\n  while (i < pathParts.length && pathParts[i] === '..') {\n    i++;\n  }\n  \n  const remainingPath = pathParts.slice(i).join('/');\n  \n  // Check if this is a path within a specific package (e.g., analytics-core/src/...)\n  // or within the current package (e.g., src/...)\n  if (remainingPath.startsWith('src/')) {\n    // This is a path within the current package (e.g., analytics-browser)\n    cleanPath = `packages/${parsedUrl.packageName}/${remainingPath}`;\n  } else {\n    // This is a path to another package (e.g., analytics-core/src/...)\n    cleanPath = `packages/${remainingPath}`;\n  }\n\n  const isTypeScript = cleanPath.endsWith('.ts') || cleanPath.endsWith('.tsx');\n\n  return {\n    relativePath: cleanPath,\n    isExternal: false,\n    isTypeScript\n  };\n}\n\n/**\n * Configure the unminify API middleware\n */\nexport function configureUnminifyMiddleware(middlewares) {\n  middlewares.use('/api/unminify', async (req, res) => {\n    // Set CORS headers\n    res.setHeader('Access-Control-Allow-Origin', '*');\n    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');\n    res.setHeader('Access-Control-Allow-Headers', 'Content-Type');\n    res.setHeader('Content-Type', 'application/json');\n\n    // Handle preflight\n    if (req.method === 'OPTIONS') {\n      res.statusCode = 200;\n      res.end();\n      return;\n    }\n\n    if (req.method !== 'POST') {\n      res.statusCode = 405;\n      res.end(JSON.stringify({ success: false, error: 'Method not allowed. Use POST.' }));\n      return;\n    }\n\n    // Read request body\n    let body = '';\n    for await (const chunk of req) {\n      body += chunk;\n    }\n\n    let requestData;\n    try {\n      requestData = JSON.parse(body);\n    } catch (e) {\n      res.statusCode = 400;\n      res.end(JSON.stringify({ success: false, error: 'Invalid JSON body' }));\n      return;\n    }\n\n    const { stacktraceLine } = requestData;\n    if (!stacktraceLine) {\n      res.statusCode = 400;\n      res.end(JSON.stringify({ success: false, error: 'Missing stacktraceLine in request body' }));\n      return;\n    }\n\n    // Parse the CDN URL\n    const parsed = parseCdnUrl(stacktraceLine);\n    if (!parsed) {\n      res.statusCode = 400;\n      res.end(JSON.stringify({ \n        success: false, \n        error: 'Could not parse stack trace line. Expected format: https://cdn.amplitude.com/libs/{package}-{version}-{suffix}.js.gz:{line}:{column}' \n      }));\n      return;\n    }\n\n    // Build the source map CDN URL\n    const sourceMapUrl = getSourceMapCdnUrl(parsed);\n\n    let consumer;\n    try {\n      // Fetch source map from CDN\n      const rawSourceMap = await fetchSourceMapFromCdn(sourceMapUrl);\n      consumer = await new SourceMapConsumer(rawSourceMap);\n\n      // Look up the original position\n      const original = consumer.originalPositionFor({\n        line: parsed.line,\n        column: parsed.column\n      });\n\n      if (!original.source) {\n        res.end(JSON.stringify({\n          success: false,\n          error: 'Could not find original position for the given line and column',\n          minified: {\n            url: parsed.originalUrl,\n            line: parsed.line,\n            column: parsed.column\n          },\n          sourceMapUrl\n        }));\n        return;\n      }\n\n      // Resolve the source path (now directly from flattened source map)\n      const sourceInfo = resolveSourcePath(original.source, parsed);\n      \n      // Build GitHub link using the version tag from the CDN URL\n      // The tag is always @amplitude/{cdnPackageName}@{version} (e.g., @amplitude/analytics-browser@2.33.5)\n      let githubLink = null;\n      if (sourceInfo.relativePath && !sourceInfo.isExternal) {\n        const tag = `@amplitude/${parsed.packageName}@${parsed.version}`;\n        githubLink = `https://github.com/amplitude/Amplitude-TypeScript/blob/${encodeURIComponent(tag)}/${sourceInfo.relativePath}#L${original.line}`;\n      }\n\n      res.end(JSON.stringify({\n        success: true,\n        original: {\n          source: original.source,\n          line: original.line,\n          column: original.column,\n          name: original.name\n        },\n        typescript: {\n          relativePath: sourceInfo.relativePath,\n          isExternal: sourceInfo.isExternal,\n          isTypeScript: sourceInfo.isTypeScript,\n          githubLink\n        },\n        minified: {\n          url: parsed.originalUrl,\n          line: parsed.line,\n          column: parsed.column\n        },\n        sourceMapUrl\n      }));\n    } catch (error) {\n      if (error.message === 'SOURCE_MAP_NOT_FOUND') {\n        res.statusCode = 404;\n        res.end(JSON.stringify({ \n          success: false, \n          error: 'Source map not found on CDN',\n          sourceMapNotFound: true,\n          sourceMapUrl,\n          instructions: {\n            summary: `The source map for version ${parsed.version} has not been uploaded to CDN yet.`,\n            steps: [\n              `1. Build the package: cd packages/${parsed.packageName} && pnpm build`,\n              `2. Find the source map: packages/${parsed.packageName}/lib/scripts/amplitude-${parsed.suffix}.js.map`,\n              `3. Upload to S3/CDN with the name: ${parsed.packageName}-${parsed.version}-${parsed.suffix}.js.map`\n            ]\n          }\n        }));\n      } else {\n        res.statusCode = 500;\n        res.end(JSON.stringify({ \n          success: false, \n          error: `Error processing source map: ${error.message}`,\n          sourceMapUrl \n        }));\n      }\n    } finally {\n      if (consumer && typeof consumer.destroy === 'function') {\n        consumer.destroy();\n      }\n    }\n  });\n} "
  },
  {
    "path": "test-server/network-capture/fetch.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <title>Fetch Network Tracking Test</title>\n    <style>\n      .result-item {\n        margin: 10px 0;\n        padding: 10px;\n        border: 1px solid #ccc;\n        border-radius: 4px;\n      }\n      .success {\n        border-left: 4px solid #4CAF50;\n      }\n      .error {\n        border-left: 4px solid #f44336;\n      }\n      .result-url {\n        font-weight: bold;\n        word-break: break-all;\n      }\n      .result-status {\n        margin: 5px 0;\n      }\n      .result-details {\n        font-family: monospace;\n        white-space: pre-wrap;\n        background: #f5f5f5;\n        padding: 10px;\n        border-radius: 4px;\n      }\n      #completion-indicator {\n        padding: 10px;\n        margin: 10px 0;\n        border-radius: 4px;\n        background-color: #e3f2fd;\n        color: #1565c0;\n        font-weight: bold;\n      }\n      #completion-indicator[data-complete=\"true\"] {\n        background-color: #e8f5e9;\n        color: #2e7d32;\n      }\n    </style>\n  </head>\n  <body>\n    <h1>Fetch Network Tracking Test</h1>\n    <div id=\"completion-indicator\" data-complete=\"false\">Running tests...</div>\n    <div id=\"app\">\n      <p>\n        This tests the autocapture.networkTracking feature and the fetch API.\n        It will make a series of requests to various endpoints and display the results\n        to verify that the fetch override is working.\n      </p>\n      <div id=\"results\"></div>\n    </div>\n    <script type=\"module\">\n      import * as amplitude from '@amplitude/analytics-browser';\n      window.amplitude = amplitude;\n\n      amplitude.init(\n        import.meta.env.VITE_AMPLITUDE_API_KEY,\n        import.meta.env.VITE_AMPLITUDE_USER_ID || 'amplitude-typescript test user',\n        {\n          autocapture: {\n            networkTracking: {\n              ignoreAmplitudeRequests: false,\n              ignoreHosts: [],\n              captureRules: [\n                {\n                  hosts: ['*.amplitude.com'],\n                  statusCodeRange: '400-599',\n                  requestHeaders: true,\n                  responseHeaders: true,\n                },\n                {\n                  hosts: ['localhost', '127.0.0.1'],\n                  statusCodeRange: '0,400-599',\n                  requestHeaders: true,\n                  responseHeaders: true,\n                },\n                {\n                  hosts: ['*'],\n                  statusCodeRange: '0,300-599',\n                  requestHeaders: true,\n                  responseHeaders: true,\n                  responseBody: {\n                    allowlist: ['status', 'message', 'method'],\n                  },\n                  requestBody: {\n                    allowlist: ['**'],\n                  },\n                },\n              ],\n            },\n          },\n        }\n      );\n\n      const displayResult = ({res, data, url, options, error}) => {\n        const resultsContainer = document.getElementById('results');\n        const resultItem = document.createElement('div');\n        resultItem.className = `result-item ${error ? 'error' : 'success'}`;\n        \n        const status = error ? 'Error' : res.status;\n        const statusText = error ? error.name : res.statusText;\n        \n        resultItem.innerHTML = `\n          <div class=\"result-url\">${url}</div>\n          <div class=\"result-status\">Status: ${status} ${statusText}</div>\n          <div class=\"result-details\">\n            Method: ${options?.method || 'GET'}\n            ${data ? `\\nResponse: ${JSON.stringify(data, null, 2)}` : ''}\n            ${error ? `\\nError: ${error.message}` : ''}\n          </div>\n        `;\n        \n        resultsContainer.appendChild(resultItem);\n      };\n\n      const makeRequest = async (url, options) => {\n        try {\n          console.log('fetching', url, options);\n          const res = await fetch(url, options);\n          const contentType = res.headers.get('content-type') || '';\n          let data = null;\n          \n          // Don't try to parse body for HEAD requests\n          if (options?.method !== 'HEAD') {\n            data = contentType.includes('application/json') ? await res.json() : await res.text();\n          }\n          \n          const result = {res, data, url, options};\n          displayResult(result);\n          return result;\n        } catch (error) {\n          console.error('Fetch error:', error);\n          const result = { status: 0, error, url, options };\n          displayResult(result);\n          return result;\n        }\n      };\n\n      function assert(result, expectedStatus) {\n        // Handle error case\n        if (result.error) {\n          if (expectedStatus !== 0) {\n            throw new Error(`Expected status code ${expectedStatus} but got error: ${result.error.message}`);\n          }\n          return true;\n        }\n\n        // Handle Response case\n        const res = result.res;\n        if (!(res instanceof Response)) {\n          throw new Error(`Test failed to receive a Response object`);\n        }\n\n        // Check that the response has required properties\n        if (typeof res.status !== 'number') {\n          throw new Error(`Response missing status code`);\n        }\n\n        if (typeof res.statusText !== 'string') {\n          throw new Error(`Response missing status text`);\n        }\n\n        if (!(res.headers instanceof Headers)) {\n          throw new Error(`Response missing headers`);\n        }\n\n        // Check that the response has a valid status code\n        if (res.status < 0 || res.status > 599) {\n          throw new Error(`Invalid status code: ${res.status}`);\n        }\n\n        // Check that the status code matches the expected status\n        if (res.status !== expectedStatus) {\n          throw new Error(`Expected status code ${expectedStatus} but got ${res.status}`);\n        }\n\n        // For HEAD requests, don't require content-type or body\n        if (['HEAD', 'OPTIONS'].includes(result.options?.method)) {\n          return true;\n        }\n\n        // Check that the response has content-type header (except for certain status codes)\n        const contentType = res.headers.get('content-type');\n        console.log('contentType', contentType);\n        if (!contentType && res.status !== 204 && res.status !== 304) {\n          throw new Error(`Response missing content-type header`);\n        }\n\n        // Check that the response has a valid body (except for certain status codes)\n        if (!res.body && res.status !== 204 && res.status !== 304) {\n          throw new Error(`Response missing body`);\n        }\n\n        return true;\n      }\n\n      function updateCompletionIndicator(success, message) {\n        const indicator = document.getElementById('completion-indicator');\n        indicator.dataset.complete = success ? 'true' : 'false';\n        indicator.textContent = message;\n        indicator.style.backgroundColor = success ? '#e8f5e9' : '#ffebee';\n        indicator.style.color = success ? '#2e7d32' : '#c62828';\n      }\n\n      setTimeout(async () => {\n        let res;\n        let testFailed = false;\n        let failureMessage = '';\n\n        try {\n          const controller = new AbortController();\n          setTimeout(() => controller.abort(), 10); // abort after 10ms\n\n          try {\n            const abortedRes = await fetch('http://localhost:5173/api/status/200', {\n              method: 'POST',\n              body: 'This request will be aborted',\n              headers: { 'Content-Type': 'text/plain' },\n              signal: controller.signal,\n            });\n            const result = await abortedRes.text();\n            console.log('Response:', result);\n          } catch (err) {\n            console.error('Aborted request error:', err.name);  // Should print \"AbortError\"\n          }\n\n          // Original test cases\n          res = await makeRequest('http://localhost:5173/api/status/500', { method: 'POST', body: 'Hello', headers: { 'Content-Type': 'text/plain' } });\n          assert(res, 500);\n          \n          res = await makeRequest('http://localhost:5173/api/status/501', { method: 'POST', body: JSON.stringify({ message: 'Hello', count: 42 }), headers: { 'Content-Type': 'application/json' } });\n          assert(res, 501);\n          \n          const formData = new FormData();\n          formData.append('text', 'Hello from FormData');\n          formData.append('file', new Blob(['Hello from Blob'], { type: 'text/plain' }));\n          res = await makeRequest('http://localhost:5173/api/status/502', { method: 'POST', body: formData });\n          assert(res, 502);\n          \n          const params = new URLSearchParams();\n          params.append('param1', 'value1');\n          params.append('param2', 'value2');\n          res = await makeRequest('http://localhost:5173/api/status/503', { method: 'POST', body: params });\n          assert(res, 503);\n          \n          res = await makeRequest('http://localhost:5173/api/status/504', { method: 'POST', body: new ArrayBuffer(8) });\n          assert(res, 504);\n          \n          res = await makeRequest('http://localhost:5173/api/status/505', { method: 'POST', body: new Blob(['Hello from Blob'], { type: 'text/plain' }) });\n          assert(res, 505);\n          \n          const encoder = new TextEncoder();\n          res = await makeRequest('http://localhost:5173/api/status/506', { method: 'POST', body: encoder.encode('Hello from Stream') });\n          assert(res, 506);\n          \n          res = await makeRequest('http://localhost:5173/api/status/507', { method: 'GET' });\n          assert(res, 507);\n          \n          res = await makeRequest('http://localhost:5173/api/status/200', { method: 'GET' });\n          assert(res, 200);\n\n          // Additional test cases\n          res = await makeRequest('http://localhost:5173/api/status/200', { method: 'HEAD' });\n          assert(res, 200);\n          \n          res = await makeRequest('http://localhost:5173/api/status/200', { method: 'OPTIONS' });\n          assert(res, 200);\n          \n          res = await makeRequest('http://localhost:5173/api/status/200', { method: 'DELETE' });\n          assert(res, 200);\n          \n          res = await makeRequest('http://localhost:5173/api/status/200', { method: 'PUT', body: JSON.stringify({ message: 'Update' }), headers: { 'Content-Type': 'application/json' } });\n          assert(res, 200);\n          \n          res = await makeRequest('/api/test', { method: 'GET' }); // Relative URL, expect 404 or dev server response\n          assert(res, 200);\n          \n          res = await makeRequest('https://notrealdomain'); // Unresolvable domain\n          assert(res, 0); // Network errors have status 0\n          \n          res = await makeRequest('http://localhost:5173/api/status/200?sleep=5000'); // Slow request\n          assert(res, 200);\n\n          updateCompletionIndicator(true, 'All tests completed successfully!');\n        } catch (error) {\n          testFailed = true;\n          failureMessage = `Test failed: ${error.message}`;\n          updateCompletionIndicator(false, failureMessage);\n          console.error(failureMessage);\n        }\n      }, 100);\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/network-capture/xhr.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <title>XHR Network Tracking Test</title>\n    <script src=\"https://cdn.jsdelivr.net/npm/axios@1.9.0/dist/axios.js\"></script>\n    <style>\n      .result-item {\n        margin: 10px 0;\n        padding: 10px;\n        border: 1px solid #ccc;\n        border-radius: 4px;\n      }\n      .success {\n        border-left: 4px solid #4CAF50;\n      }\n      .error {\n        border-left: 4px solid #f44336;\n      }\n      .result-url {\n        font-weight: bold;\n        word-break: break-all;\n      }\n      .result-status {\n        margin: 5px 0;\n      }\n      .result-details {\n        font-family: monospace;\n        white-space: pre-wrap;\n        background: #f5f5f5;\n        padding: 10px;\n        border-radius: 4px;\n      }\n      #completion-indicator {\n        padding: 10px;\n        margin: 10px 0;\n        border-radius: 4px;\n        background-color: #e3f2fd;\n        color: #1565c0;\n        font-weight: bold;\n      }\n      #completion-indicator[data-complete=\"true\"] {\n        background-color: #e8f5e9;\n        color: #2e7d32;\n      }\n    </style>\n  </head>\n  <body>\n    <h1>XHR Network Tracking Test</h1>\n    <div id=\"completion-indicator\" data-complete=\"false\">Running tests...</div>\n    <div id=\"app\">\n      <p>\n        This tests the autocapture.networkTracking feature and the XHR API.\n        It will make a series of requests to various endpoints and display the results\n        to verify that the XHR override is working.\n      </p>\n      <div id=\"results\"></div>\n    </div>\n    <script type=\"module\">\n      import * as amplitude from '@amplitude/analytics-browser';\n      window.amplitude = amplitude;\n\n      // Base URL configuration for absolute URLs\n      const BASE_URL = 'http://localhost:5173';\n\n      axios.defaults.validateStatus = () => true;\n\n      amplitude.init(\n        import.meta.env.VITE_AMPLITUDE_API_KEY,\n        import.meta.env.VITE_AMPLITUDE_USER_ID || 'amplitude-typescript test user',\n        {\n          autocapture: {\n            networkTracking: true,\n          },\n          networkTrackingOptions: {\n            ignoreAmplitudeRequests: false,\n            ignoreHosts: [],\n            captureRules: [\n              { hosts: ['*.amplitude.com'], statusCodeRange: '400-599' },\n              { hosts: ['localhost', '127.0.0.1'], statusCodeRange: '0,400-599' },\n              {\n                hosts: ['*'],\n                statusCodeRange: '0,300-599',\n                responseHeaders: true,\n                requestHeaders: true,\n                responseBody: { allowlist: ['*'] },\n                requestBody: { allowlist: ['*'] },\n              },\n            ],\n          },\n        }\n      );\n\n      function displayResult({res, error, url, options}) {\n        const resultsContainer = document.getElementById('results');\n        const resultItem = document.createElement('div');\n        resultItem.className = `result-item ${error ? 'error' : 'success'}`;\n        \n        const status = error ? 'Error' : res.status;\n        const statusText = error ? error.message : res.statusText;\n        \n        resultItem.innerHTML = `\n          <div class=\"result-url\">${url}</div>\n          <div class=\"result-status\">Status: ${status} ${statusText}</div>\n          <div class=\"result-details\">\n            Method: ${options?.method || 'GET'}\n            ${res?.data ? `\\nResponse: ${JSON.stringify(res.data, null, 2)}` : ''}\n            ${error ? `\\nError: ${error.message}` : ''}\n          </div>\n        `;\n        \n        resultsContainer.appendChild(resultItem);\n      }\n\n      function assert(result, expectedStatus) {\n        // Handle error case\n        if (result.error) {\n          if (expectedStatus !== 0) {\n            throw new Error(`Expected status code ${expectedStatus} but got error: ${result.error.message}`);\n          }\n          return true;\n        }\n\n        // Handle Response case\n        const res = result.res;\n        if (!res || typeof res.status !== 'number') {\n          throw new Error(`Invalid response object`);\n        }\n\n        // Check that the status code matches the expected status\n        if (res.status !== expectedStatus) {\n          throw new Error(`Expected status code ${expectedStatus} but got ${res.status}`);\n        }\n\n        return true;\n      }\n\n      function updateCompletionIndicator(success, message) {\n        const indicator = document.getElementById('completion-indicator');\n        indicator.dataset.complete = success ? 'true' : 'false';\n        indicator.textContent = message;\n        indicator.style.backgroundColor = success ? '#e8f5e9' : '#ffebee';\n        indicator.style.color = success ? '#2e7d32' : '#c62828';\n      }\n\n      setTimeout(async () => {\n        let res;\n        let testFailed = false;\n        let failureMessage = '';\n\n        try {\n          const controller = new AbortController();\n          const signal = controller.signal;\n          try {\n            res = axios.post(`${BASE_URL}/api/status/200`, 'This request will be aborted', { signal });\n            controller.abort();\n            const awaitedRes = await res;\n            displayResult({res: awaitedRes, url: `${BASE_URL}/api/status/200`, options: { method: 'POST' }});\n          } catch (err) {\n            displayResult({error: err, url: `${BASE_URL}/api/status/200`, options: { method: 'POST' }});\n          }\n\n          // Basic GET 200\n          res = await axios.get(`${BASE_URL}/api/status/200`);\n          displayResult({res, url: `${BASE_URL}/api/status/200`, options: { method: 'GET' }});\n          assert({res}, 200);\n\n          // Get 500 with responseType = json, raw XMLHttpRequest\n          const xhr = new XMLHttpRequest();\n          xhr.open('GET', `${BASE_URL}/api/status/500`);\n          xhr.responseType = 'json';\n          xhr.send();\n          xhr.onload = () => {\n            displayResult({res: xhr, url: `${BASE_URL}/api/status/500`, options: { method: 'GET', responseType: 'json' }});\n            assert({res: xhr}, 500);\n          };\n\n          // String body\n          res = await axios.post(`${BASE_URL}/api/status/500`, 'Hello, this is a test body');\n          displayResult({res, url: `${BASE_URL}/api/status/500`, options: { method: 'POST' }});\n          assert({res}, 500);\n\n          // JSON object body\n          res = await axios.post(`${BASE_URL}/api/status/501`, { message: 'Hello', count: 42 });\n          displayResult({res, url: `${BASE_URL}/api/status/501`, options: { method: 'POST' }});\n          assert({res}, 501);\n\n          // FormData body\n          const formData = new FormData();\n          formData.append('text', 'Hello from FormData');\n          formData.append('file', new Blob(['Hello from Blob'], { type: 'text/plain' }));\n          res = await axios.post(`${BASE_URL}/api/status/502`, formData);\n          displayResult({res, url: `${BASE_URL}/api/status/502`, options: { method: 'POST' }});\n          assert({res}, 502);\n\n          // URLSearchParams body\n          const params = new URLSearchParams();\n          params.append('param1', 'value1');\n          params.append('param2', 'value2');\n          res = await axios.post(`${BASE_URL}/api/status/504`, params);\n          displayResult({res, url: `${BASE_URL}/api/status/504`, options: { method: 'POST' }});\n          assert({res}, 504);\n\n          // ArrayBuffer body\n          const buffer = new ArrayBuffer(8);\n          res = await axios.post(`${BASE_URL}/api/status/505`, buffer);\n          displayResult({res, url: `${BASE_URL}/api/status/505`, options: { method: 'POST' }});\n          assert({res}, 505);\n\n          // Blob body\n          const blob = new Blob(['Hello from Blob'], { type: 'text/plain' });\n          res = await axios.post(`${BASE_URL}/api/status/506`, blob);\n          displayResult({res, url: `${BASE_URL}/api/status/506`, options: { method: 'POST' }});\n          assert({res}, 506);\n\n          // Stream body (Not natively supported by Axios, but included to match fetch tests)\n          try {\n            const stream = new ReadableStream({\n              start(controller) {\n                controller.enqueue('Hello from Stream');\n                controller.close();\n              },\n            });\n            res = await axios.post(`${BASE_URL}/api/status/507`, stream);\n            displayResult({res, url: `${BASE_URL}/api/status/507`, options: { method: 'POST' }});\n            assert({res}, 507);\n          } catch (err) {\n            displayResult({error: err, url: `${BASE_URL}/api/status/507`, options: { method: 'POST' }});\n          }\n\n          // GET 508\n          res = await axios.get(`${BASE_URL}/api/status/508`);\n          displayResult({res, url: `${BASE_URL}/api/status/508`, options: { method: 'GET' }});\n          assert({res}, 508);\n\n          // Additional HTTP Methods\n          res = await axios.head(`${BASE_URL}/api/status/200`);\n          displayResult({res, url: `${BASE_URL}/api/status/200`, options: { method: 'HEAD' }});\n          assert({res}, 200);\n\n          res = await axios.options(`${BASE_URL}/api/status/200`);\n          displayResult({res, url: `${BASE_URL}/api/status/200`, options: { method: 'OPTIONS' }});\n          assert({res}, 200);\n\n          res = await axios.delete(`${BASE_URL}/api/status/200`);\n          displayResult({res, url: `${BASE_URL}/api/status/200`, options: { method: 'DELETE' }});\n          assert({res}, 200);\n\n          res = await axios.put(`${BASE_URL}/api/status/200`, { update: true });\n          displayResult({res, url: `${BASE_URL}/api/status/200`, options: { method: 'PUT' }});\n          assert({res}, 200);\n\n          // Relative URL (likely 404)\n          try {\n            res = await axios.get('/api/test');\n            displayResult({res, url: '/api/test', options: { method: 'GET' }});\n            assert({res}, 200);\n          } catch (err) {\n            displayResult({error: err, url: `${BASE_URL}/api/test`, options: { method: 'GET' }});\n          }\n\n          // Network failure (invalid domain)\n          try {\n            res = await axios.get('https://notrealdomain');\n            displayResult({res, url: 'https://notrealdomain', options: { method: 'GET' }});\n            assert({res}, 0);\n          } catch (err) {\n            displayResult({error: err, url: 'https://notrealdomain', options: { method: 'GET' }});\n            assert({error: err}, 0);\n          }\n\n          // Delayed response\n          res = await axios.get(`${BASE_URL}/api/status/200?sleep=5000`);\n          displayResult({res, url: `${BASE_URL}/api/status/200?sleep=5000`, options: { method: 'GET' }});\n          assert({res}, 200);\n\n          updateCompletionIndicator(true, 'All tests completed successfully!');\n        } catch (error) {\n          testFailed = true;\n          failureMessage = `Test failed: ${error.message}`;\n          updateCompletionIndicator(false, failureMessage);\n          console.error(failureMessage);\n        }\n      }, 100);\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/observables/mouse-direction-change-observable.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Mouse Direction Change Observables Test</title>\n  </head>\n  <body>\n    <h1>Mouse Direction Change Observables Test</h1>\n    <p>Move your mouse around to see direction changes logged</p>\n    <div id=\"output\"></div>\n    <script type=\"module\">\n      import { createMouseMoveObservable } from '@amplitude/plugin-autocapture-browser/src/observables';\n      import { createMouseDirectionChangeObservable } from '@amplitude/plugin-autocapture-browser/src/autocapture/track-thrashed-cursor';\n      \n      const mouseMoveObservable = createMouseMoveObservable();\n      const allWindowObservables = {\n        mouseMoveObservable,\n      };\n      \n      const mouseDirectionChangeObservable = createMouseDirectionChangeObservable({\n        allWindowObservables,\n      });\n      const output = document.getElementById('output');\n      \n      let directionChangeCount = 0;\n      mouseDirectionChangeObservable.subscribe((axis) => {\n        const log = `#${directionChangeCount++} Direction changed on ${axis} axis`;\n        console.log(log);\n        if (output) {\n          output.textContent = log;\n        }\n      });\n    </script>\n  </body>\n</html>\n\n"
  },
  {
    "path": "test-server/observables/mouse-observables.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Mouse Move Observables Test</title>\n  </head>\n  <body>\n    <h1>Mouse Move Observables Test</h1>\n    <p>Move your mouse around to see events logged</p>\n    <div id=\"output\"></div>\n    <script type=\"module\">\n      import { createMouseMoveObservable } from '@amplitude/plugin-autocapture-browser/src/observables';\n      \n      const mouseMoveObservable = createMouseMoveObservable();\n      const output = document.getElementById('output');\n      \n      mouseMoveObservable.subscribe((event) => {\n        const log = `Mouse moved: x=${event.clientX}, y=${event.clientY}`;\n        console.log(log);\n        if (output) {\n          output.textContent = log;\n        }\n      });\n    </script>\n  </body>\n</html>\n\n"
  },
  {
    "path": "test-server/observables/thrashed-cursor-observable.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Thrashed Cursor Observables Test</title>\n  </head>\n  <body>\n    <h1>Thrashed Cursor Observables Test</h1>\n    <p>Move your mouse around quickly to see thrashed cursor events logged</p>\n    <div id=\"output\"></div>\n    <script type=\"module\">\n      import { createMouseMoveObservable } from '@amplitude/plugin-autocapture-browser/src/observables';\n      import { createMouseDirectionChangeObservable, createThrashedCursorObservable } from '@amplitude/plugin-autocapture-browser/src/autocapture/track-thrashed-cursor';\n      \n      const mouseMoveObservable = createMouseMoveObservable();\n      const allWindowObservables = {\n        mouseMoveObservable,\n      };\n      \n      const mouseDirectionChangeObservable = createMouseDirectionChangeObservable({\n        allWindowObservables,\n      });\n      \n      const thrashedCursorObservable = createThrashedCursorObservable({\n        mouseDirectionChangeObservable,\n      });\n      \n      const output = document.getElementById('output');\n      \n      let thrashedCursorCount = 0;\n      thrashedCursorObservable.subscribe((eventTime) => {\n        const log = `#${thrashedCursorCount++} Thrashed cursor detected`;\n        console.log(log, +(Date.now()) - eventTime);\n        if (output) {\n          output.textContent = log;\n        }\n      });\n    </script>\n  </body>\n</html>\n\n"
  },
  {
    "path": "test-server/observers/console.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/public/amplitude.png\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Console Observer Test</title>\n  </head>\n  <script src=\"/analytics-browser/lib/scripts/amplitude-min.js\"></script>\n  <script type=\"module\">\n    window.AMPLITUDE_API_KEY = import.meta.env.VITE_AMPLITUDE_API_KEY;\n  </script>\n  <script type=\"module\">\n    import { consoleObserver } from '@amplitude/analytics-core/src/observers/console';\n    const callback = (logLevel, args) => {\n      console.error(`Echoing the error: ${args.join(' ')}`);\n    };\n    consoleObserver.addListener('error', callback);\n    setTimeout(() => {\n      consoleObserver.removeListener(callback);\n      console.log('Disconnected');\n    }, 8000);\n  </script>\n  <body>\n    <h1>Console Observer Test</h1>\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/opt-out/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>Opt Out Test</title>\n</head>\n<body>\n  <h1>Opt Out Test</h1>\n  <p>This page initializes Amplitude with optOut enabled.</p>\n  <div>\n    <button id=\"setOptOutBtn\">Turn off opt out</button>\n    <button id=\"initAgain\">Call init again with optOut false</button>\n  </div>\n  <div style=\"margin-top: 10px;\">\n    <button onClick=\"amplitude.track('test event')\" id=\"Track Event\">Track Event</button>\n  </div>\n  <p id=\"isOptedIn\">Not opted in</p>\n  \n  <script type=\"module\">\n    import * as amplitude from '@amplitude/analytics-browser';\n\n    const ident = new amplitude.Identify();\n    ident.set('test-property', 'test-value');\n\n    const baseConfig = {\n      autocapture: {\n        sessions: true,\n        pageViews: true,\n        attribution: true,\n      },\n      identify: ident,\n      //identityStorage: 'memory', // set to memory so easy to test session on each page\n    };\n    \n    // Initialize Amplitude with optOut enabled\n    amplitude.init(import.meta.env.VITE_AMPLITUDE_API_KEY, {\n      ...baseConfig,\n      optOut: true,\n    });\n    \n    // Make amplitude available globally for debugging\n    window.amplitude = amplitude;\n    \n    // Button click handler\n    document.getElementById('setOptOutBtn').addEventListener('click', () => {\n      amplitude.setOptOut(false);\n      console.log('setOptOut(false) called');\n      document.getElementById('isOptedIn').textContent = 'Opted in';\n    });\n\n    document.getElementById('initAgain').addEventListener('click', () => {\n      amplitude.init(import.meta.env.VITE_AMPLITUDE_API_KEY, {\n        ...baseConfig,\n        optOut: false,\n      });\n      console.log('init again called');\n      document.getElementById('isOptedIn').textContent = 'Opted in';\n    });\n  </script>\n</body>\n</html>\n\n"
  },
  {
    "path": "test-server/proxy-test.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/amplitude.png\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Amplitude Proxy Server Test</title>\n  </head>\n  <body>\n    <h1>🚀 Amplitude Proxy Server Test</h1>\n    <p>\n      This page is used to test the proxy server.\n      Run the proxy server with the command 'pnpm proxy:dev' in the root of this repo\n    </p>\n    <p>Open your console and run test events to see that it works</p>\n\n    <script type=\"module\">\n      import * as amplitude from '@amplitude/analytics-browser';\n      import { stubPlugin } from '@amplitude/plugin-stub-browser';\n      \n      // Make amplitude available globally for debugging\n      window.amplitude = amplitude;\n      \n      // Configuration\n      const PROXY_SERVER_URL = 'http://localhost:3001/2/httpapi';\n      const API_KEY = import.meta.env.VITE_AMPLITUDE_API_KEY || 'test-api-key';\n      const USER_ID = import.meta.env.VITE_AMPLITUDE_USER_ID || 'proxy-test-user-' + Date.now();\n      \n      // Initialize Amplitude with proxy server\n      amplitude.add(stubPlugin());\n      amplitude.init(API_KEY, USER_ID, {\n        serverUrl: PROXY_SERVER_URL,\n        serverZone: 'US',\n        logLevel: 1, // Debug level\n        trackingSessionEvents: true,\n        trackingPlan: {\n          version: '1',\n          rules: []\n        }\n      });\n    </script>\n  </body>\n</html> "
  },
  {
    "path": "test-server/remote-config-test.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/amplitude.png\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Remote Config Test</title>\n    <style>\n      body {\n        font-family: Arial, sans-serif;\n        margin: 20px;\n        line-height: 1.6;\n      }\n      .container {\n        max-width: 800px;\n        margin: 0 auto;\n      }\n      .status {\n        padding: 10px;\n        margin: 10px 0;\n        border-radius: 4px;\n        font-weight: bold;\n      }\n      .success {\n        background-color: #d4edda;\n        color: #155724;\n        border: 1px solid #c3e6cb;\n      }\n      .info {\n        background-color: #d1ecf1;\n        color: #0c5460;\n        border: 1px solid #bee5eb;\n      }\n      .warning {\n        background-color: #fff3cd;\n        color: #856404;\n        border: 1px solid #ffeaa7;\n      }\n      button {\n        background-color: #007bff;\n        color: white;\n        border: none;\n        padding: 10px 20px;\n        margin: 5px;\n        border-radius: 4px;\n        cursor: pointer;\n      }\n      button:hover {\n        background-color: #0056b3;\n      }\n      .log {\n        background-color: #f8f9fa;\n        border: 1px solid #dee2e6;\n        border-radius: 4px;\n        padding: 10px;\n        margin: 10px 0;\n        font-family: monospace;\n        font-size: 12px;\n        max-height: 300px;\n        overflow-y: auto;\n      }\n    </style>\n  </head>\n  <body>\n    <div class=\"container\">\n      <h1>Amplitude Remote Config Test</h1>\n      <p>This page tests Amplitude initialization with <code>fetchRemoteConfig: true</code>.</p>\n      \n      <div id=\"interactive-section\">\n        <h3>Interactive Section</h3>\n        <div id=\"interactive-content\">\n          <p>This is the interactive section.</p>\n        </div>\n        <button id=\"interactive-button\">Interactive Button</button>\n      </div>\n    </div>\n    <script type=\"module\">\n      let queryParams = new URLSearchParams(window.location.search);\n      window.AMPLITUDE_VERSION = queryParams.get('amplitudeVersion') || 'latest';\n      window.API_KEY = queryParams.get('apiKey') || '77de0b7de6157d5e7ca409c81778f28e';\n      window.SERVER_ZONE = queryParams.get('serverZone') || 'US';\n\n      const REMOTE_STAGING = {\n        US: 'https://sr-client-cfg.amplitude.com/',\n        EU: 'https://sr-client-cfg.eu.amplitude.com/',\n        STAGING: 'https://sr-client-cfg.stag2.amplitude.com/',\n      };\n\n      const API_ENDPOINTS = {\n        US: 'https://api2.amplitude.com/2/httpapi',\n        EU: 'https://api.eu.amplitude.com/2/httpapi',\n        STAGING: 'https://api.stag2.amplitude.com/2/httpapi',\n      };\n\n      window.SERVER_URL = API_ENDPOINTS[window.SERVER_ZONE?.toUpperCase()];\n\n      if (window.AMPLITUDE_VERSION !== 'latest') {\n        \n        !function (window, document) {\n          var amplitude = window.amplitude || {\n            _q: [],\n            _iq: {}\n          };\n          if (amplitude.invoked) window.console && console.error && console.error('Amplitude snippet has been loaded.');else {\n            var proxy = function proxy(obj, fn) {\n              obj.prototype[fn] = function () {\n                this._q.push({\n                  name: fn,\n                  args: Array.prototype.slice.call(arguments, 0)\n                });\n                return this;\n              };\n            };\n            var getPromiseResult = function getPromiseResult(instance, fn, args) {\n              return function (resolve) {\n                instance._q.push({\n                  name: fn,\n                  args: Array.prototype.slice.call(args, 0),\n                  resolve: resolve\n                });\n              };\n            };\n            var proxyInstance = function proxyInstance(instance, fn, args) {\n              instance._q.push({\n                name: fn,\n                args: Array.prototype.slice.call(args, 0)\n              });\n            };\n            var proxyMain = function proxyMain(instance, fn, isPromise) {\n              instance[fn] = function () {\n                if (isPromise) return {\n                  promise: new Promise(getPromiseResult(instance, fn, Array.prototype.slice.call(arguments)))\n                };\n                proxyInstance(instance, fn, Array.prototype.slice.call(arguments));\n              };\n            };\n            var setUpProxy = function setUpProxy(instance) {\n              for (var k = 0; k < funcs.length; k++) {\n                proxyMain(instance, funcs[k], false);\n              }\n              for (var l = 0; l < funcsWithPromise.length; l++) {\n                proxyMain(instance, funcsWithPromise[l], true);\n              }\n            };\n            amplitude.invoked = true;\n            var as = document.createElement('script');\n            as.type = 'text/javascript';\n            as.crossOrigin = 'anonymous';\n            as.async = true;\n            as.src = `https://cdn.amplitude.com/libs/analytics-browser-${AMPLITUDE_VERSION}-min.js.gz`;\n            console.log('[Amplitude] Loading SDK from', as.src);\n            as.onload = function () {\n              console.log('[Amplitude] SDK loaded');\n              if (!window.amplitude.runQueuedFunctions) {\n                console.log('[Amplitude] Error: could not load SDK');\n              }\n            };\n            var s = document.getElementsByTagName('script')[0];\n            s.parentNode.insertBefore(as, s);\n            var Identify = function Identify() {\n              this._q = [];\n              return this;\n            };\n            var identifyFuncs = ['add', 'append', 'clearAll', 'prepend', 'set', 'setOnce', 'unset', 'preInsert', 'postInsert', 'remove', 'getUserProperties'];\n            for (var i = 0; i < identifyFuncs.length; i++) {\n              proxy(Identify, identifyFuncs[i]);\n            }\n            amplitude.Identify = Identify;\n            var Revenue = function Revenue() {\n              this._q = [];\n              return this;\n            };\n            var revenueFuncs = ['getEventProperties', 'setProductId', 'setQuantity', 'setPrice', 'setRevenue', 'setRevenueType', 'setReceipt', 'setReceiptSig', 'setCurrency', 'setEventProperties'];\n            for (var j = 0; j < revenueFuncs.length; j++) {\n              proxy(Revenue, revenueFuncs[j]);\n            }\n            amplitude.Revenue = Revenue;\n            var funcs = ['getDeviceId', 'setDeviceId', 'getSessionId', 'setSessionId', 'getUserId', 'setUserId', 'setOptOut', 'setTransport', 'reset', 'extendSession'];\n            var funcsWithPromise = ['init', 'add', 'remove', 'track', 'logEvent', 'identify', 'groupIdentify', 'setGroup', 'revenue', 'flush'];\n            setUpProxy(amplitude);\n            amplitude.createInstance = function (instanceName) {\n              amplitude._iq[instanceName] = {\n                _q: []\n              };\n              setUpProxy(amplitude._iq[instanceName]);\n              return amplitude._iq[instanceName];\n            };\n            window.amplitude = amplitude;\n          }\n        }(window, document);\n      }\n    </script>\n\n    <script type=\"module\">\n      import * as amplitudeModule from '@amplitude/analytics-browser';\n      \n      if (window.AMPLITUDE_VERSION === 'latest') {\n        window.amplitude = amplitudeModule;\n      }\n      console.log('Starting Amplitude initialization with fetchRemoteConfig: true');\n      \n      // Initialize Amplitude with fetchRemoteConfig set to true\n      window.amplitude.init(\n        window.API_KEY,\n        'remote-config-test-user',\n        {\n          serverUrl: window.SERVER_URL,\n          fetchRemoteConfig: true,\n          logLevel: 'Debug', // Enable debug logging to see remote config activity\n          autocapture: {\n            // Enable autocapture to test remote config overrides\n            elementInteractions: true,\n            pageViews: true,\n          },\n        }\n      ).promise.then(() => {\n        console.log('Amplitude initialized successfully with remote config enabled');\n        \n        // Track an initial event\n        amplitude.track('Remote Config Test Page Loaded', {\n          fetchRemoteConfig: true,\n          timestamp: new Date().toISOString()\n        });\n        console.log('Tracked initial page load event');\n        \n      }).catch((error) => {\n        console.error(`Amplitude initialization failed: ${error.message}`);\n        console.error(`Initialization error: ${error.message}`);\n      });\n      \n      // Listen for remote config updates\n      let remoteConfigReceived = false;\n      \n      document.getElementById('interactive-button').addEventListener('click', () => {\n        document.getElementById('interactive-content').innerHTML = 'Interactive content has been changed.';\n      });\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/sampling-test.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Sampling Test</title>\n    <style>\n        body {\n            font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif;\n            margin: 2rem;\n        }\n        .pass {\n            color: #2e7d32;\n        }\n        .fail {\n            color: #c62828;\n        }\n        code {\n            background: #f6f8fa;\n            padding: 0.2rem 0.4rem;\n            border-radius: 4px;\n        }\n        pre {\n            background: #f6f8fa;\n            padding: 1rem;\n            border-radius: 8px;\n            overflow: auto;\n        }\n        button {\n            padding: 0.6rem 1rem;\n            border: 0;\n            border-radius: 8px;\n            cursor: pointer;\n        }\n        h2 {\n            margin-top: 2rem;\n        }\n        .separator {\n            border-top: 2px solid #ddd;\n            margin: 1rem 0;\n            padding-top: 0.5rem;\n        }\n    </style>\n</head>\n<body>\n    <h1>Sampling Test</h1>\n    <p>This page runs the sampling test, import from local sampling.ts. in analytics-core</p>\n    <div style=\"margin-bottom: 1rem;\">\n        <label for=\"sessionCount\">Number of sessions to test: </label>\n        <input type=\"number\" id=\"sessionCount\" value=\"10000\" min=\"100\" max=\"10000000\" style=\"padding: 0.4rem; border: 1px solid #ccc; border-radius: 4px; width: 120px;\">\n    </div>\n    <button id=\"run\">Run Tests</button>\n    <div id=\"results\" style=\"margin-top:1rem;\"></div>\n\n    <h2>How the Test Works</h2>\n    <p>\n        Each test generates sequential session IDs (timestamps starting from <code>Date.now()</code>)\n        and checks whether each one passes the sampling filter. The test measures the actual sample rate and \n        compares it to the expected rate with a <strong>±5% tolerance</strong>. You can configure the number\n        of sessions to test above (default: 10,000).\n    </p>\n\n    <h2>Why Bucket Size Matters</h2>\n    <p>\n        The two functions differ in their <strong>bucket size</strong> (the modulo value):\n    </p>\n    <ul>\n        <li><code>isTimestampInSample</code> uses <strong>1,000,000 buckets</strong> (<code>% 1000000</code>)</li>\n        <li><code>isTimestampInSampleTemp</code> uses <strong>100,000 buckets</strong> (<code>% 100000</code>)</li>\n    </ul>\n\n    <h3>The Problem with 1,000,000 Buckets</h3>\n    <p>\n        The hash function (<code>generateHashCode</code>) is like a <strong>bad dice</strong> - it wasn't designed \n        for fair random distribution, just for organizing items in hash tables. When you try to use this bad dice \n        to fill 1 million buckets:\n    </p>\n    <ul>\n        <li><strong>Biased distribution:</strong> The dice doesn't land evenly across all buckets</li>\n        <li><strong>Limited entropy:</strong> The 32-bit hash wraps and repeats, losing randomness</li>\n        <li><strong>Periodic patterns:</strong> Consecutive timestamps fall into \"bad zones\" where sampling fails</li>\n    </ul>\n    <p>\n        For example, with <code>sampleRate = 0.1</code> (10%), you need the hash to land in buckets 0-99,999. \n        But the bad dice often <strong>never lands there</strong>, resulting in 0% sampling instead of 10%.\n    </p>\n\n    <h3>Why 100,000 Buckets Works Better</h3>\n    <p>\n        With a smaller bucket size (100,000), the same biased hash function works \"good enough\":\n    </p>\n    <ul>\n        <li><strong>Faster cycling:</strong> The hash cycles through all buckets more quickly</li>\n        <li><strong>Better coverage:</strong> Even with bias, the smaller space gets filled more evenly</li>\n        <li><strong>More consistent:</strong> Less dependent on which timestamp range you're testing</li>\n    </ul>\n\n    <h3>What You'll Observe</h3>\n    <p>\n        Try testing with different session counts:\n    </p>\n    <ul>\n        <li><strong>10,000 sessions:</strong> <code>isTimestampInSample</code> often fails (exposes periodic bias)</li>\n        <li><strong>100,000+ sessions:</strong> Both might pass (averaging hides the bias, but it's still there!)</li>\n        <li><code>isTimestampInSampleTemp</code> is more reliable across all scales</li>\n    </ul>\n\n    <script type=\"module\">\n        // Import the sampling functions from the source\n        import { isTimestampInSample, isTimestampInSampleTemp, generateHashCode } from '@amplitude/analytics-core/src/utils/sampling';\n\n        // Make functions available globally\n        window.isTimestampInSample = isTimestampInSample;\n        window.isTimestampInSampleTemp = isTimestampInSampleTemp;\n        window.generateHashCode = generateHashCode;\n\n        console.log('Sampling functions loaded successfully');\n    </script>\n\n    <script>\n        \"use strict\";\n\n        // === Test harness ===\n        function sample({ sessionCount, sampleRate, sampleFn }) {\n            const start = Date.now();\n            let totalSampled = 0;\n            for (let sessionId = start; sessionId < start + sessionCount; sessionId++) {\n                if (sampleFn(sessionId, sampleRate)) totalSampled++;\n            }\n            return totalSampled / sessionCount;\n        }\n\n        function assertEqual(actual, expected, msg) {\n            if (actual !== expected) {\n                throw new Error(`${msg} — expected ${expected}, got ${actual}`);\n            }\n        }\n\n        function assertApprox(actual, expected, accuracy, msg) {\n            if (Math.abs(actual - expected) > accuracy) {\n                throw new Error(`${msg} — expected ${expected} ± ${accuracy}, got ${actual}`);\n            }\n        }\n\n        function runTests() {\n            const out = [];\n            let passed = 0, failed = 0;\n\n            // Get session count from input\n            const sessionCount = parseInt(document.getElementById(\"sessionCount\").value) || 10000;\n            console.log('sessionCount', sessionCount);\n\n            function test(name, fn) {\n                try {\n                    fn();\n                    out.push(`<div class=\"pass\">✔ ${name}</div>`);\n                    passed++;\n                } catch (e) {\n                    out.push(`<div class=\"fail\">✘ ${name}<br><small>${e.message}</small></div>`);\n                    failed++;\n                }\n            }\n\n            // Test isTimestampInSample\n            test(\"sample(sampleRate: 1.0) == 1.0\", () => {\n                const val = sample({ sessionCount, sampleRate: 1.0, sampleFn: window.isTimestampInSample });\n                assertEqual(Number(val.toFixed(6)), 1.0, \"All sessions should be sampled at 1.0\");\n            });\n\n            test(\"sample(sampleRate: 0.0) == 0.0\", () => {\n                const val = sample({ sessionCount, sampleRate: 0.0, sampleFn: window.isTimestampInSample });\n                assertEqual(Number(val.toFixed(6)), 0.0, \"No sessions should be sampled at 0.0\");\n            });\n\n            test(\"sample(sampleRate: 0.5) ≈ 0.5 ± 0.05\", () => {\n                const val = sample({ sessionCount, sampleRate: 0.5, sampleFn: window.isTimestampInSample });\n                assertApprox(val, 0.5, 0.05, \"Half of sessions should be sampled\");\n            });\n\n            test(\"sample(sampleRate: 0.1) ≈ 0.1 ± 0.05\", () => {\n                const val = sample({ sessionCount, sampleRate: 0.1, sampleFn: window.isTimestampInSample });\n                assertApprox(val, 0.1, 0.05, \"10% of sessions should be sampled\");\n            });\n\n            test(\"sample(sampleRate: 0.9) ≈ 0.9 ± 0.05\", () => {\n                const val = sample({ sessionCount, sampleRate: 0.9, sampleFn: window.isTimestampInSample });\n                assertApprox(val, 0.9, 0.05, \"90% of sessions should be sampled\");\n            });\n\n            // Add separator between the two function tests\n            out.push('<div class=\"separator\"></div>');\n\n            // Test isTimestampInSampleTemp\n            test(\"[Temp] sample(sampleRate: 1.0) == 1.0\", () => {\n                const val = sample({ sessionCount, sampleRate: 1.0, sampleFn: window.isTimestampInSampleTemp });\n                assertEqual(Number(val.toFixed(6)), 1.0, \"All sessions should be sampled at 1.0\");\n            });\n\n            test(\"[Temp] sample(sampleRate: 0.0) == 0.0\", () => {\n                const val = sample({ sessionCount, sampleRate: 0.0, sampleFn: window.isTimestampInSampleTemp });\n                assertEqual(Number(val.toFixed(6)), 0.0, \"No sessions should be sampled at 0.0\");\n            });\n\n            test(\"[Temp] sample(sampleRate: 0.5) ≈ 0.5 ± 0.05\", () => {\n                const val = sample({ sessionCount, sampleRate: 0.5, sampleFn: window.isTimestampInSampleTemp });\n                assertApprox(val, 0.5, 0.05, \"Half of sessions should be sampled\");\n            });\n\n            test(\"[Temp] sample(sampleRate: 0.1) ≈ 0.1 ± 0.05\", () => {\n                const val = sample({ sessionCount, sampleRate: 0.1, sampleFn: window.isTimestampInSampleTemp });\n                assertApprox(val, 0.1, 0.05, \"10% of sessions should be sampled\");\n            });\n\n            test(\"[Temp] sample(sampleRate: 0.9) ≈ 0.9 ± 0.05\", () => {\n                const val = sample({ sessionCount, sampleRate: 0.9, sampleFn: window.isTimestampInSampleTemp });\n                assertApprox(val, 0.9, 0.05, \"90% of sessions should be sampled\");\n            });\n\n            document.getElementById(\"results\").innerHTML =\n                `<p><strong>Passed:</strong> ${passed} &nbsp; <strong>Failed:</strong> ${failed} &nbsp; (tested with ${sessionCount.toLocaleString()} sessions)</p>` + out.join(\"\");\n        }\n\n        document.getElementById(\"run\").addEventListener(\"click\", runTests);\n    </script>\n</body>\n</html>\n\n"
  },
  {
    "path": "test-server/scroll-test.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Scroll Test Page</title>\n    <style>\n      body {\n        margin: 0;\n        padding: 20px;\n        background: white;\n        font-family: sans-serif;\n        min-height: 15000px;\n      }\n      \n      h1 {\n        margin-bottom: 20px;\n      }\n      \n      .marker {\n        padding: 10px;\n        margin: 500px 0;\n        background: #f0f0f0;\n        border-left: 4px solid #333;\n      }\n    </style>\n  </head>\n  <body>\n    <h1>Scroll Test Page</h1>\n    <p>This page has a height of ~15,000px for scroll testing.</p>\n    \n    <div class=\"marker\">1000px</div>\n    <div class=\"marker\">2000px</div>\n    <div class=\"marker\">3000px</div>\n    <div class=\"marker\">4000px</div>\n    <div class=\"marker\">5000px</div>\n    <div class=\"marker\">6000px</div>\n    <div class=\"marker\">7000px</div>\n    <div class=\"marker\">8000px</div>\n    <div class=\"marker\">9000px</div>\n    <div class=\"marker\">10000px</div>\n    <div class=\"marker\">11000px</div>\n    <div class=\"marker\">12000px</div>\n    <div class=\"marker\">13000px</div>\n    <div class=\"marker\">14000px</div>\n    <div class=\"marker\">End</div>\n\n    <script type=\"module\">\n      import * as amplitude from '@amplitude/analytics-browser';\n      \n      window.amplitude = amplitude;\n      \n      amplitude.init(\n        import.meta.env.VITE_AMPLITUDE_API_KEY,\n        import.meta.env.VITE_AMPLITUDE_USER_ID || 'scroll-test-user',\n        {\n          autocapture: {\n            frustrationInteractions: {\n              rageClicks: true,\n            }\n          }\n        }\n      );\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/segment.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\" />\n  <title>Segment + Amplitude Autocapture</title>\n  <script>\n    !function(){var analytics=window.analytics=window.analytics||[];\n    if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error(\"Segment snippet included twice.\");\n    else{analytics.invoked=!0;analytics.methods=[\"trackSubmit\",\"trackClick\",\"trackLink\",\"trackForm\",\"pageview\",\"identify\",\n    \"reset\",\"group\",\"track\",\"ready\",\"alias\",\"debug\",\"page\",\"once\",\"off\",\"on\"];\n    analytics.factory=function(t){return function(){var e=Array.prototype.slice.call(arguments);e.unshift(t);analytics.push(e);return analytics}};\n    for(var t=0;t<analytics.methods.length;t++){var e=analytics.methods[t];analytics[e]=analytics.factory(e)}\n    analytics.load=function(t){var e=document.createElement(\"script\");\n    e.type=\"text/javascript\";e.async=!0;e.src=\"https://cdn.segment.com/analytics.js/v1/\" + t + \"/analytics.min.js\";\n    var n=document.getElementsByTagName(\"script\")[0];n.parentNode.insertBefore(e,n)};\n    analytics.SNIPPET_VERSION=\"4.13.2\";}}();\n  </script>\n\n  <script type=\"module\">\n    // Load Amplitude SDK and initialize with AutoCapture\n    import * as amplitude from 'https://cdn.skypack.dev/@amplitude/analytics-browser';\n    window.amplitude = amplitude;\n    analytics.load(import.meta.env.SEGMENT_API_KEY); // Your Segment write key\n    analytics.page();\n\n    amplitude.init(import.meta.env.VITE_AMPLITUDE_API_KEY, null, {\n      autocapture: {\n        pageViews: true,\n        sessions: true,\n      },\n      logLevel: 'DEBUG',\n      flushIntervalMillis: 1000,\n      networkTrackingOptions: {\n        ignoreAmplitudeRequests: false,\n        ignoreHosts: [],\n        captureRules: [\n          { hosts: ['*.amplitude.com'], statusCodeRange: '400-599' },\n          { hosts: ['httpstat.us'], statusCodeRange: '400-599' },\n        ],\n      },\n    });\n\n    window.sendSegmentEvent = (event) => {\n      const sessionId = amplitude.getSessionId();\n      const deviceId = amplitude.getDeviceId();\n      analytics.track(event, {\n        source: 'button',\n      }, {\n        context: {\n        //   device: {\n        //     id: deviceId,\n        //   },\n        },\n        integrations: {\n          Amplitude: {\n            session_id: sessionId, // session_id goes here\n          },\n        }\n      });\n    };\n  </script>\n</head>\n\n<body>\n  <h1>Segment + Amplitude</h1>\n  <div>\n    This is a test page for Segment + Amplitude integration with AutoCapture.\n    To make this work, you need to set the environment variables in your `.env` file:\n    <ul>\n      <li><code>VITE_AMPLITUDE_API_KEY</code> - Your Amplitude API key</li>\n      <li><code>VITE_SEGMENT_API_KEY</code> - Your Segment write key</li>\n    </ul>\n  </div>\n  <button onclick=\"sendSegmentEvent();\">\n    Track Event\n  </button>\n</body>\n</html>\n"
  },
  {
    "path": "test-server/session-replay-browser/sr-capture-test.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>SR Capture Test</title>\n  </head>\n  <body>\n    <div id=\"status\">loading</div>\n    <input id=\"test-input\" type=\"text\" placeholder=\"Enter your email\" style=\"display:block\" />\n    <button id=\"test-button\" aria-label=\"Submit form\">Submit</button>\n    <script type=\"module\">\n      import * as sessionReplay from '@amplitude/session-replay-browser';\n\n      window.sessionReplay = sessionReplay;\n\n      const params = new URLSearchParams(location.search);\n      const sampleRate = params.has('sampleRate') ? Number(params.get('sampleRate')) : 1.0;\n      const optOut = params.get('optOut') === 'true';\n      const sessionId = params.has('sessionId') ? Number(params.get('sessionId')) : Date.now();\n      const deviceId = params.get('deviceId') ?? 'test-device-id';\n      const logLevel = params.has('logLevel') ? Number(params.get('logLevel')) : 0;\n      const useWebWorker = params.get('useWebWorker') === 'true';\n      const mergeMutations = params.get('mergeMutations') === 'true';\n      const storeType = params.get('storeType') ?? undefined;\n\n      void (async () => {\n        try {\n          await sessionReplay.init('d90c5cf09ca2546a1626272906b99a76', {\n            deviceId,\n            sessionId,\n            sampleRate,\n            optOut,\n            logLevel,\n            useWebWorker,\n            performanceConfig: { enabled: true, mergeMutations },\n            ...(storeType ? { storeType } : {}),\n          }).promise;\n        } catch (err) {\n          document.getElementById('status').textContent = 'error: ' + err.message;\n          window.srError = err.message;\n        }\n\n        window.srReady = true;\n        document.getElementById('status').textContent = 'ready';\n      })();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/session-replay-browser/sr-cross-origin-iframe-child.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <title>SR Cross-Origin Iframe Child</title>\n  </head>\n  <body>\n    <div id=\"child-content\">Child iframe unique content</div>\n    <div id=\"status\">loading</div>\n    <script>\n      // Set up the start-signal listener BEFORE the SDK loads so we never miss a message\n      // even if the parent's coordinator fires before the SDK is fully initialized.\n      window.receivedStartSignal = false;\n      window.receivedStopSignal = false;\n      window.addEventListener('message', function (event) {\n        if (event.data && event.data.type === 'amplitude-sr-iframe') {\n          if (event.data.action === 'start') window.receivedStartSignal = true;\n          if (event.data.action === 'stop') window.receivedStopSignal = true;\n        }\n      });\n\n      window.childModeDetected = window.parent !== window;\n    </script>\n    <script type=\"module\">\n      import * as sessionReplay from '@amplitude/session-replay-browser';\n\n      window.sessionReplay = sessionReplay;\n\n      const params = new URLSearchParams(location.search);\n      const sessionId = params.has('sessionId') ? Number(params.get('sessionId')) : Date.now();\n      const deviceId = params.get('deviceId') ?? 'test-device-id';\n\n      void (async () => {\n        try {\n          await sessionReplay.init('d90c5cf09ca2546a1626272906b99a76', {\n            deviceId,\n            sessionId,\n            sampleRate: 1,\n            crossOriginIframes: { enabled: true },\n          }).promise;\n        } catch (err) {\n          document.getElementById('status').textContent = 'error: ' + err.message;\n          window.srError = err.message;\n        }\n\n        window.srReady = true;\n        document.getElementById('status').textContent = 'ready';\n      })();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/session-replay-browser/sr-cross-origin-iframe-parent.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <title>SR Cross-Origin Iframe Parent</title>\n  </head>\n  <body>\n    <div id=\"parent-content\">Parent page content</div>\n    <div id=\"status\">loading</div>\n    <script type=\"module\">\n      import * as sessionReplay from '@amplitude/session-replay-browser';\n\n      window.sessionReplay = sessionReplay;\n\n      const params = new URLSearchParams(location.search);\n      const sessionId = params.has('sessionId') ? Number(params.get('sessionId')) : Date.now();\n      const deviceId = params.get('deviceId') ?? 'test-device-id';\n      const coordinateChildren = params.get('coordinateChildren') !== 'false';\n      // Child URL may be a different origin to test real cross-origin behaviour.\n      // Defaults to the same origin so CI works without a second server.\n      const childSrc = params.get('childSrc') ?? '/session-replay-browser/sr-cross-origin-iframe-child.html';\n\n      void (async () => {\n        try {\n          await sessionReplay.init('d90c5cf09ca2546a1626272906b99a76', {\n            deviceId,\n            sessionId,\n            sampleRate: 1,\n            crossOriginIframes: { enabled: true, coordinateChildren },\n          }).promise;\n        } catch (err) {\n          document.getElementById('status').textContent = 'error: ' + err.message;\n          window.srError = err.message;\n        }\n\n        window.srReady = true;\n        document.getElementById('status').textContent = 'ready';\n\n        // Add the child iframe dynamically so the MutationObserver picks it up\n        // after the coordinator has started. This is the canonical usage pattern.\n        const iframe = document.createElement('iframe');\n        iframe.id = 'child-frame';\n        iframe.src =\n          childSrc +\n          '?sessionId=' +\n          sessionId +\n          '&deviceId=' +\n          deviceId;\n        iframe.style.width = '100%';\n        iframe.style.height = '200px';\n        document.body.appendChild(iframe);\n        window.iframeAdded = true;\n      })();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/session-replay-browser/sr-plugin-with-analytics-sdk.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/amplitude.png\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Session Replay Plugin Test</title>\n    <style>\n      body {\n        font-family: Arial, sans-serif;\n        max-width: 600px;\n        margin: 50px auto;\n        padding: 20px;\n      }\n      h1 {\n        color: #333;\n      }\n      button {\n        background: #0066cc;\n        color: white;\n        border: none;\n        padding: 12px 24px;\n        margin: 10px 5px;\n        border-radius: 4px;\n        cursor: pointer;\n        font-size: 16px;\n      }\n      button:hover {\n        background: #0052a3;\n      }\n      .status {\n        padding: 10px;\n        margin: 10px 0;\n        border-radius: 4px;\n        background: #f0f0f0;\n        font-family: monospace;\n      }\n      input {\n        padding: 8px;\n        margin: 5px;\n        font-size: 14px;\n        width: 300px;\n      }\n      .section {\n        margin: 20px 0;\n        padding: 20px;\n        background: #f9f9f9;\n        border-radius: 8px;\n      }\n    </style>\n  </head>\n  <body>\n    <h1>Session Replay Plugin Test</h1>\n    \n    <div class=\"status\" id=\"status\">Status: Not initialized</div>\n    \n    <input type=\"text\" id=\"apiKey\" placeholder=\"API Key (optional)\" />\n    <br />\n    <button id=\"initBtn\">Initialize Analytics + Session Replay Plugin</button>\n\n    <div class=\"section\">\n      <h2>Test Events</h2>\n      <button id=\"trackBtn\">Track Event</button>\n      <button id=\"getInfoBtn\">Get Session Info</button>\n    </div>\n\n    <script type=\"module\">\n      import * as amplitude from '@amplitude/analytics-browser';\n      import { sessionReplayPlugin } from '@amplitude/plugin-session-replay-browser';\n      \n      window.amplitude = amplitude;\n      \n      const statusEl = document.getElementById('status');\n      const apiKeyEl = document.getElementById('apiKey');\n      const initBtn = document.getElementById('initBtn');\n      const trackBtn = document.getElementById('trackBtn');\n      const getInfoBtn = document.getElementById('getInfoBtn');\n\n      function updateStatus(message) {\n        statusEl.textContent = `Status: ${message}`;\n        console.log('[Status]', message);\n      }\n\n      // Auto-fill API key from environment\n      if (import.meta.env.VITE_AMPLITUDE_API_KEY) {\n        apiKeyEl.value = import.meta.env.VITE_AMPLITUDE_API_KEY;\n      }\n\n      initBtn.addEventListener('click', async () => {\n        const apiKey = apiKeyEl.value || import.meta.env.VITE_AMPLITUDE_API_KEY || 'test-api-key';\n        \n        try {\n          updateStatus('Initializing Analytics Browser SDK...');\n          \n          console.log('[Init] Starting with API key:', apiKey);\n          \n          // Create and add Session Replay plugin\n          console.log('[Plugin] Creating Session Replay plugin...');\n          const sessionReplayTracking = sessionReplayPlugin({\n            sampleRate: 1.0,\n            logLevel: 'debug',\n          });\n          amplitude.add(sessionReplayTracking);\n\n          // Initialize Analytics Browser SDK\n          amplitude.init(apiKey, 'test-user@amplitude.com', {\n            logLevel: amplitude.Types.LogLevel.Debug,\n          });\n          \n          const sessionId = amplitude.getSessionId();\n          const deviceId = amplitude.getDeviceId();\n          \n          updateStatus(`✓ Initialized! Session ID: ${sessionId}`);\n          \n          console.log('[Success] All initialized');\n          console.log('[Session ID]', sessionId);\n          console.log('[Device ID]', deviceId);\n        } catch (error) {\n          updateStatus(`✗ Error: ${error.message}`);\n          console.error('[Error]', error);\n        }\n      });\n\n      trackBtn.addEventListener('click', () => {\n        console.log('[Track] Tracking test event...');\n        amplitude.track('Test Event', {\n          property: 'test-value',\n          timestamp: Date.now(),\n        });\n        updateStatus('✓ Event tracked');\n      });\n\n      getInfoBtn.addEventListener('click', () => {\n        const sessionId = amplitude.getSessionId();\n        const deviceId = amplitude.getDeviceId();\n        const userId = amplitude.getUserId();\n        \n        console.log('=== Session Info ===');\n        console.log('Session ID:', sessionId);\n        console.log('Device ID:', deviceId);\n        console.log('User ID:', userId);\n        \n        updateStatus(`Session: ${sessionId}`);\n      });\n\n      updateStatus('Ready to initialize. Check browser console for debug logs.');\n      console.log('[Ready] Session Replay Plugin test loaded. Click \"Initialize\" to start.');\n    </script>\n  </body>\n</html>\n\n"
  },
  {
    "path": "test-server/session-replay-browser/sr-privacy-test.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>SR Privacy Test</title>\n  </head>\n  <body>\n    <!-- Plain text — visible under 'light'/'medium', masked under 'conservative' -->\n    <p id=\"plain-text\">Hello visible world</p>\n\n    <!-- Text masked via CSS class (rrweb maskTextClass) -->\n    <p id=\"amp-mask-text\" class=\"amp-mask\">Secret masked text</p>\n\n    <!-- Element blocked via CSS class (rrweb blockClass) -->\n    <div id=\"amp-block-element\" class=\"amp-block\">Blocked content</div>\n\n    <!-- Masked container with an explicitly unmasked child -->\n    <div id=\"masked-container\" class=\"amp-mask\">\n      Outer masked text\n      <span id=\"unmask-span\">Inner visible text</span>\n    </div>\n\n    <!-- Text input: masked in 'medium'/'conservative', not in 'light' -->\n    <input id=\"text-input\" type=\"text\" value=\"visible input value\" />\n\n    <!-- Password input: always masked ('light' and above) -->\n    <input id=\"password-input\" type=\"password\" value=\"secret123\" />\n\n    <!-- Textarea: under medium/conservative, value is masked; under light (non-sensitive), visible -->\n    <textarea id=\"text-area\">multi-line textarea content</textarea>\n\n    <!-- Select: under medium/conservative, value is masked -->\n    <select id=\"select-input\"><option value=\"option-one\" selected>option-one</option></select>\n\n    <!-- Element for selector-based blocking via privacyConfig.blockSelector -->\n    <div id=\"selector-blocked\">Selector blocked content</div>\n\n    <!-- Text with amp-unmask class: should be visible under conservative masking\n         without requiring an explicit unmaskSelector in privacyConfig (SR-2945) -->\n    <p id=\"amp-unmask-text\" class=\"amp-unmask\">Unmask class visible text</p>\n\n    <div id=\"status\">loading</div>\n    <script type=\"module\">\n      import * as sessionReplay from '@amplitude/session-replay-browser';\n\n      window.sessionReplay = sessionReplay;\n\n      const params = new URLSearchParams(location.search);\n      const sessionId = params.has('sessionId') ? Number(params.get('sessionId')) : Date.now();\n      const deviceId = params.get('deviceId') ?? 'test-device-id';\n      const logLevel = params.has('logLevel') ? Number(params.get('logLevel')) : 0;\n      const privacyConfig = params.has('privacyConfig') ? JSON.parse(params.get('privacyConfig')) : undefined;\n      const apiKey = params.get('apiKey') ?? 'd90c5cf09ca2546a1626272906b99a76';\n\n      void (async () => {\n        try {\n          await sessionReplay\n            .init(apiKey, {\n              deviceId,\n              sessionId,\n              logLevel,\n              privacyConfig,\n            })\n            .promise;\n        } catch (err) {\n          document.getElementById('status').textContent = 'error: ' + err.message;\n          window.srError = err.message;\n        }\n\n        window.srReady = true;\n        document.getElementById('status').textContent = 'ready';\n      })();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/session-replay-browser/sr-shadow-dom-test.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>SR Shadow DOM Test</title>\n  </head>\n  <body>\n    <div id=\"status\">loading</div>\n    <!--\n      Shadow host: a custom element with an adoptedStyleSheet and content inside\n      the shadow root. Used to verify captureAdoptedStyleSheets wiring.\n    -->\n    <div id=\"shadow-host\"></div>\n    <script type=\"module\">\n      import * as sessionReplay from '@amplitude/session-replay-browser';\n\n      window.sessionReplay = sessionReplay;\n\n      const params = new URLSearchParams(location.search);\n      const sessionId = params.has('sessionId') ? Number(params.get('sessionId')) : Date.now();\n      const deviceId = params.get('deviceId') ?? 'test-device-id';\n      const logLevel = params.has('logLevel') ? Number(params.get('logLevel')) : 0;\n      // captureAdoptedStyleSheets: omit param → SDK default (true); pass 'false' to opt out\n      const captureAdoptedStyleSheetsParam = params.get('captureAdoptedStyleSheets');\n      const captureAdoptedStyleSheets =\n        captureAdoptedStyleSheetsParam === null ? undefined : captureAdoptedStyleSheetsParam !== 'false';\n\n      // Build a shadow root with an adoptedStyleSheet before the SDK initializes\n      // so that the full-snapshot captures it.\n      const host = document.getElementById('shadow-host');\n      const shadow = host.attachShadow({ mode: 'open' });\n      const sheet = new CSSStyleSheet();\n      sheet.replaceSync('#shadow-content { color: red; font-size: 14px; }');\n      shadow.adoptedStyleSheets = [sheet];\n      const inner = document.createElement('span');\n      inner.id = 'shadow-content';\n      inner.textContent = 'hello from shadow DOM';\n      shadow.appendChild(inner);\n\n      void (async () => {\n        try {\n          const initOptions = {\n            deviceId,\n            sessionId,\n            sampleRate: 1.0,\n            logLevel,\n          };\n          if (captureAdoptedStyleSheets !== undefined) {\n            initOptions.captureAdoptedStyleSheets = captureAdoptedStyleSheets;\n          }\n          await sessionReplay.init('d90c5cf09ca2546a1626272906b99a76', initOptions).promise;\n        } catch (err) {\n          document.getElementById('status').textContent = 'error: ' + err.message;\n          window.srError = err.message;\n        }\n\n        window.srReady = true;\n        document.getElementById('status').textContent = 'ready';\n      })();\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/session-replay-browser/sr-standalone-sdk.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/amplitude.png\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Session Replay Test</title>\n    <style>\n      body {\n        font-family: Arial, sans-serif;\n        max-width: 600px;\n        margin: 50px auto;\n        padding: 20px;\n      }\n      h1 {\n        color: #333;\n      }\n      button {\n        background: #0066cc;\n        color: white;\n        border: none;\n        padding: 12px 24px;\n        margin: 10px 5px;\n        border-radius: 4px;\n        cursor: pointer;\n        font-size: 16px;\n      }\n      button:hover {\n        background: #0052a3;\n      }\n      .status {\n        padding: 10px;\n        margin: 10px 0;\n        border-radius: 4px;\n        background: #f0f0f0;\n        font-family: monospace;\n      }\n      input {\n        padding: 8px;\n        margin: 5px;\n        font-size: 14px;\n        width: 300px;\n      }\n    </style>\n  </head>\n  <body>\n    <h1>Session Replay Test</h1>\n    \n    <div class=\"status\" id=\"status\">Status: Not initialized</div>\n    \n    <input type=\"text\" id=\"apiKey\" placeholder=\"API Key (optional)\" />\n    <br />\n    <button id=\"initBtn\">Initialize Session Replay (Debug Mode)</button>\n\n    <script type=\"module\">\n      import * as sessionReplay from '@amplitude/session-replay-browser';\n      \n      window.sessionReplay = sessionReplay;\n      \n      const statusEl = document.getElementById('status');\n      const apiKeyEl = document.getElementById('apiKey');\n      const initBtn = document.getElementById('initBtn');\n\n      function updateStatus(message) {\n        statusEl.textContent = `Status: ${message}`;\n        console.log('[Status]', message);\n      }\n\n      // Auto-fill API key from environment\n      if (import.meta.env.VITE_AMPLITUDE_API_KEY) {\n        apiKeyEl.value = import.meta.env.VITE_AMPLITUDE_API_KEY;\n      }\n\n      initBtn.addEventListener('click', async () => {\n        const apiKey = apiKeyEl.value || import.meta.env.VITE_AMPLITUDE_API_KEY || 'test-api-key';\n        \n        try {\n          updateStatus('Initializing...');\n          \n          console.log('[Init] Starting with config:', {\n            apiKey,\n            deviceId: 'test-device',\n            sampleRate: 1.0,\n            logLevel: 'debug',\n          });\n          \n          await sessionReplay.init(apiKey, {\n            deviceId: 'test-device',\n            sampleRate: 1.0,\n            logLevel: 'debug',\n          }).promise;\n          \n          const sessionId = sessionReplay.getSessionId();\n          const properties = sessionReplay.getSessionReplayProperties();\n          \n          updateStatus(`✓ Initialized! Session ID: ${sessionId}`);\n          \n          console.log('[Success] Session Replay initialized');\n          console.log('[Session ID]', sessionId);\n          console.log('[Properties]', properties);\n        } catch (error) {\n          updateStatus(`✗ Error: ${error.message}`);\n          console.error('[Error]', error);\n        }\n      });\n\n      updateStatus('Ready to initialize. Check browser console for debug logs.');\n      console.log('[Ready] Session Replay SDK loaded. Click \"Initialize\" to start.');\n    </script>\n  </body>\n</html>\n\n"
  },
  {
    "path": "test-server/snippets/cookie-deduplication.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Cookie Deduplication Test</title>\n    <script>\n    // de-duplicate cookies\n    // TODO: make this available as a plugin\n    const duplicateCookieFix = async () => {\n        const defaultWindow = window;\n        if (!(\"cookieStore\" in defaultWindow)) return;\n        const cookies = await defaultWindow.cookieStore.getAll();\n        const ampCookies = cookies.filter((cookie) => cookie.name.includes(\"AMP_\"));\n        const bestCookiesMap = new Map();\n\n        // Step 1: Deduplicate by name\n        for (const cookie of ampCookies) {\n            const key = cookie.name;\n            const currentBest = bestCookiesMap.get(key);\n            const isTopLevel = /^[^.]+\\.[^.]+$/.test(cookie.domain);\n\n            if (!currentBest) {\n                bestCookiesMap.set(key, { cookie, isTopLevel });\n            } else {\n                if (isTopLevel) {\n                    bestCookiesMap.set(key, { cookie, isTopLevel });\n                }\n            }\n        }\n\n        // Step 2: Extract deduplicated list\n        const deduped = Array.from(bestCookiesMap.values()).map(\n            (entry) => entry.cookie\n        );\n\n        // Step 3: Delete duplicates\n        const keepSet = new Set(deduped.map((c) => `${c.name}|${c.domain}`));\n\n        await Promise.all(\n            ampCookies\n                .filter((c) => !keepSet.has(`${c.name}|${c.domain}`))\n                .map((c) => {\n                    return defaultWindow.cookieStore.delete(c.name, {\n                        domain: c.domain,\n                        path: c.path,\n                    });\n                })\n        );\n    };\n    duplicateCookieFix();\n    </script>\n    <style>\n        body {\n            font-family: Arial, sans-serif;\n            max-width: 800px;\n            margin: 0 auto;\n            padding: 20px;\n            background-color: #f5f5f5;\n        }\n        .container {\n            background: white;\n            padding: 30px;\n            border-radius: 8px;\n            box-shadow: 0 2px 10px rgba(0,0,0,0.1);\n        }\n        h1 {\n            color: #333;\n            margin-bottom: 20px;\n        }\n        .button {\n            background-color: #007bff;\n            color: white;\n            border: none;\n            padding: 12px 24px;\n            border-radius: 4px;\n            cursor: pointer;\n            font-size: 16px;\n            margin: 10px 0;\n        }\n        .button:hover {\n            background-color: #0056b3;\n        }\n        .button:disabled {\n            background-color: #6c757d;\n            cursor: not-allowed;\n        }\n        .info {\n            background-color: #e9ecef;\n            padding: 15px;\n            border-radius: 4px;\n            margin: 15px 0;\n        }\n        .success {\n            background-color: #d4edda;\n            color: #155724;\n            border: 1px solid #c3e6cb;\n        }\n        .error {\n            background-color: #f8d7da;\n            color: #721c24;\n            border: 1px solid #f5c6cb;\n        }\n        .cookie-info {\n            background-color: #f8f9fa;\n            padding: 10px;\n            border-radius: 4px;\n            margin: 10px 0;\n            font-family: monospace;\n            font-size: 14px;\n        }\n    </style>\n</head>\n<body>\n    <div class=\"container\">\n        <h1>Cookie Deduplication Test</h1>\n        \n        <div class=\"info\">\n            <strong>Instructions:</strong> This tool helps copy Amplitude cookies from full domain scope to subdomain scope.\n            <br><br>\n            <strong>How it works:</strong>\n            <ol>\n                <li>Click the button below to scan for cookies matching the pattern <code>AMP_*</code></li>\n                <li>The tool will copy each found cookie and create a new version with the subdomain scope</li>\n                <li>For example: <code>.website.com</code> → <code>local.website.com</code></li>\n                <li>Refresh the page to see the updated cookies</li>\n            </ol>\n        </div>\n\n        <button id=\"dedupeButton\" class=\"button\" onclick=\"copyCookiesToSubdomain()\">\n            Copy AMP Cookies to Subdomain\n        </button>\n\n        <div id=\"status\"></div>\n        <div id=\"cookieList\"></div>\n    </div>\n\n    <script>\n        function copyCookiesToSubdomain() {\n            const button = document.getElementById('dedupeButton');\n            const status = document.getElementById('status');\n            const cookieList = document.getElementById('cookieList');\n            \n            button.disabled = true;\n            button.textContent = 'Processing...';\n            status.innerHTML = '';\n            cookieList.innerHTML = '';\n\n            try {\n                // Get all cookies\n                const allCookies = document.cookie.split(';');\n                const ampCookies = [];\n                \n                // Find cookies that start with AMP_\n                allCookies.forEach(cookie => {\n                    const trimmed = cookie.trim();\n                    if (trimmed.startsWith('AMP_')) {\n                        ampCookies.push(trimmed);\n                    }\n                });\n\n                if (ampCookies.length === 0) {\n                    status.innerHTML = '<div class=\"info error\">No AMP_* cookies found. Make sure you have Amplitude cookies set on this domain.</div>';\n                    button.disabled = false;\n                    button.textContent = 'Copy AMP Cookies to Subdomain';\n                    return;\n                }\n\n                let successCount = 0;\n                let errorCount = 0;\n                const results = [];\n\n                // Process each AMP cookie\n                ampCookies.forEach(cookieStr => {\n                    try {\n                        const [nameValue, ...rest] = cookieStr.split(';');\n                        const [name, value] = nameValue.split('=');\n                        \n                        if (!name || !value) {\n                            results.push(`<div class=\"cookie-info\">❌ Invalid cookie format: ${cookieStr}</div>`);\n                            errorCount++;\n                            return;\n                        }\n\n                        // Get current domain\n                        const currentDomain = window.location.hostname;\n                        \n                        // Set the new cookie with subdomain scope (no domain attribute = current domain)\n                        const cookieOptions = rest.join(';');\n                        \n                        // Set the new cookie with subdomain scope (current domain)\n                        window.cookieStore.set(name, value, { path: '/', domain: currentDomain, ...cookieOptions });\n                        \n                        results.push(`\n                            <div class=\"cookie-info\">\n                                ✅ Copied: <strong>${name}</strong><br>\n                                From: <code>.website.com</code> (full domain)<br>\n                                To: <code>${currentDomain}</code> (subdomain)<br>\n                                Value: <code>${value.substring(0, 50)}${value.length > 50 ? '...' : ''}</code>\n                            </div>\n                        `);\n                        successCount++;\n                        \n                    } catch (error) {\n                        results.push(`<div class=\"cookie-info\">❌ Error processing cookie: ${cookieStr}<br>Error: ${error.message}</div>`);\n                        errorCount++;\n                    }\n                });\n\n                // Display results\n                cookieList.innerHTML = results.join('');\n                \n                if (successCount > 0) {\n                    status.innerHTML = `<div class=\"info success\">✅ Successfully copied ${successCount} cookie(s) to subdomain scope.</div>`;\n                }\n                \n                if (errorCount > 0) {\n                    status.innerHTML += `<div class=\"info error\">❌ Failed to copy ${errorCount} cookie(s).</div>`;\n                }\n\n            } catch (error) {\n                status.innerHTML = `<div class=\"info error\">❌ Error: ${error.message}</div>`;\n            } finally {\n                button.disabled = false;\n                button.textContent = 'Copy AMP Cookies to Subdomain';\n            }\n        }\n\n        // Display current cookies on page load\n        window.addEventListener('load', function() {\n            const allCookies = document.cookie.split(';');\n            const ampCookies = allCookies.filter(cookie => cookie.trim().startsWith('AMP_'));\n            \n            if (ampCookies.length > 0) {\n                const cookieList = document.getElementById('cookieList');\n                cookieList.innerHTML = `\n                    <div class=\"info\">\n                        <strong>Current AMP cookies found:</strong>\n                        ${ampCookies.map(cookie => `<div class=\"cookie-info\">${cookie.trim()}</div>`).join('')}\n                    </div>\n                `;\n            }\n        });\n    </script>\n</body>\n</html>\n"
  },
  {
    "path": "test-server/spa-test.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <link rel=\"icon\" type=\"image/svg+xml\" href=\"/amplitude.png\" />\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>SPA Test - Single Page Application</title>\n  <style>\n    body {\n      font-family: Arial, sans-serif;\n      max-width: 800px;\n      margin: 50px auto;\n      padding: 20px;\n      background-color: #f5f5f5;\n    }\n    \n    .container {\n      background: white;\n      padding: 30px;\n      border-radius: 8px;\n      box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n    }\n    \n    h1 {\n      color: #333;\n      margin-bottom: 10px;\n    }\n    \n    .current-route {\n      background: #e3f2fd;\n      padding: 10px;\n      border-radius: 4px;\n      margin: 20px 0;\n      font-family: monospace;\n    }\n    \n    .nav {\n      display: flex;\n      gap: 15px;\n      margin: 20px 0;\n      flex-wrap: wrap;\n    }\n    \n    .nav a {\n      padding: 10px 20px;\n      background: #2196F3;\n      color: white;\n      text-decoration: none;\n      border-radius: 4px;\n      transition: background 0.3s;\n    }\n    \n    .nav a:hover {\n      background: #1976D2;\n    }\n    \n    .content {\n      margin-top: 30px;\n      padding: 20px;\n      background: #f9f9f9;\n      border-radius: 4px;\n      min-height: 150px;\n    }\n    \n    .info {\n      margin-top: 30px;\n      padding: 15px;\n      background: #fff3cd;\n      border-radius: 4px;\n      border-left: 4px solid #ffc107;\n    }\n    \n    .info p {\n      margin: 5px 0;\n    }\n  </style>\n</head>\n<body>\n  <div class=\"container\">\n    <h1>SPA Test Page</h1>\n    <p>This simulates a Single Page Application with client-side routing using the History API. Navigate between routes and reload the page - you'll stay on the same route!</p>\n    <p>IMPORTANT: This page is best tested with \"dev:ssh\" to simulate document.referrer being preserved upon reload</p>\n    <div class=\"current-route\">\n      Current Route: <strong id=\"current-path\">/</strong>\n    </div>\n    \n    <div class=\"nav\">\n      <a href=\"/spa-test.html\" class=\"spa-link\">Home</a>\n      <a href=\"/spa-test.html/about\" class=\"spa-link\">About</a>\n      <a href=\"/spa-test.html/products\" class=\"spa-link\">Products</a>\n      <a href=\"/spa-test.html/products?category=electronics&sort=price\" class=\"spa-link\">Products (with params)</a>\n      <a href=\"/spa-test.html/contact\" class=\"spa-link\">Contact</a>\n      <a href=\"/spa-test.html/profile/user123\" class=\"spa-link\">Profile</a>\n      <a href=\"/spa-test.html/profile/user123?tab=settings\" class=\"spa-link\">Profile (with params)</a>\n    </div>\n    \n    <div class=\"content\" id=\"content\">\n      <!-- Content will be dynamically updated here -->\n    </div>\n    \n    <div class=\"info\">\n      <strong>How it works (History API):</strong>\n      <p>• Click any link above to navigate (using <code>pushState</code> and <code>popstate</code>)</p>\n      <p>• The URL path will change without page reload (e.g., <code>/spa-test.html/about</code>)</p>\n      <p>• The page content updates dynamically via JavaScript</p>\n      <p>• Browser back/forward buttons work correctly</p>\n      <p>• <strong>Query parameters are preserved</strong> - try adding ?param=value after the route</p>\n      <p>• <strong>Amplitude autocapture is enabled</strong> - tracking element interactions, page views, sessions, and form interactions</p>\n      <br>\n      <p><strong>⚠️ Server Configuration Needed for Reloads:</strong></p>\n      <p style=\"font-size: 0.9em; color: #666;\">For reloading to work, your server must be configured to serve <code>spa-test.html</code> for all <code>/spa-test.html/*</code> routes. See below for Vite configuration.</p>\n    </div>\n  </div>\n\n  <script type=\"module\">\n    import * as amplitude from '@amplitude/analytics-browser';\n    \n    // Make amplitude available globally for debugging\n    window.amplitude = amplitude;\n\n    // do not $unset campaign to empty\n    amplitude.add({\n        type: 'before',\n        execute(event) {\n            // pass through any non-identify events\n            if (event.event_type !== \"$identify\") {\n            return event;\n            }    \n\n            // get the $set keys\n            const userProps = event['user_properties'] || {};\n            const setProps = userProps['$set'] || {};\n\n            // if there's any non-referral keys being $set than pass-through the event\n            const nonReferralKeys = Object.keys(setProps).filter(\n                (key) => key !== 'referrer' && key !== 'referring_domain'\n            );\n            if (nonReferralKeys.length === 0) {\n                delete event['user_properties']['$unset'];\n            }\n            return event;\n        },\n        name: 'no-unset-campaign-to-empty',\n    });\n    \n    // Initialize Amplitude with autocapture enabled\n    amplitude.init(\n      import.meta.env.VITE_AMPLITUDE_API_KEY,\n      undefined,\n      {\n        fetchRemoteConfig: false,\n        autocapture: {\n          elementInteractions: true,\n          pageViews: true,\n          sessions: true,\n          formInteractions: true,\n        },\n      }\n    );\n    \n    console.log('Amplitude initialized with autocapture enabled');\n\n    // Base path for the SPA (used to strip from routes)\n    const BASE_PATH = '/spa-test.html';\n    \n    // Define content for different routes (relative to BASE_PATH)\n    const routes = {\n      '/': {\n        title: 'Home',\n        content: '<h2>Welcome Home!</h2><p>This is the home page of the SPA test. Click any link above to navigate to different routes without reloading the page.</p>'\n      },\n      '/about': {\n        title: 'About',\n        content: '<h2>About Us</h2><p>This is the about page. Notice how the URL changed but the page did not reload.</p>'\n      },\n      '/products': {\n        title: 'Products',\n        content: '<h2>Our Products</h2><p>Browse our amazing products. The route changed via pushState!</p>'\n      },\n      '/contact': {\n        title: 'Contact',\n        content: '<h2>Contact Us</h2><p>Get in touch with us. Single page application routing in action!</p>'\n      },\n      '/profile/user123': {\n        title: 'User Profile',\n        content: '<h2>User Profile</h2><p>Viewing profile for user123. Dynamic routes work too!</p>'\n      }\n    };\n\n    // Helper function to parse query parameters\n    function parseQueryParams(search) {\n      const params = {};\n      if (search) {\n        const urlParams = new URLSearchParams(search);\n        for (const [key, value] of urlParams) {\n          params[key] = value;\n        }\n      }\n      return params;\n    }\n\n    // Helper function to get relative route path (strip base path)\n    function getRelativeRoute(pathname) {\n      if (pathname.startsWith(BASE_PATH)) {\n        const relative = pathname.slice(BASE_PATH.length) || '/';\n        return relative;\n      }\n      return pathname;\n    }\n\n    // Function to render content based on current path and query params\n    function renderRoute(pathname, search = '') {\n      const contentDiv = document.getElementById('content');\n      const pathDisplay = document.getElementById('current-path');\n      \n      // Get relative route and parse query params\n      const relativePath = getRelativeRoute(pathname);\n      const queryParams = parseQueryParams(search);\n      const fullPath = relativePath + (search ? '?' + search.slice(1) : '');\n      \n      // Update path display (showing full path with query params)\n      pathDisplay.textContent = pathname + search;\n      \n      // Get route content or show 404\n      const route = routes[relativePath] || {\n        title: '404',\n        content: '<h2>404 - Not Found</h2><p>The route \"' + relativePath + '\" does not exist.</p>'\n      };\n      \n      // Build content with query parameters display\n      let content = route.content;\n      if (Object.keys(queryParams).length > 0) {\n        content += '<div style=\"margin-top: 20px; padding: 15px; background: #e8f5e9; border-radius: 4px;\">';\n        content += '<strong>Query Parameters:</strong><ul style=\"margin: 10px 0 0 0;\">';\n        for (const [key, value] of Object.entries(queryParams)) {\n          content += '<li><code>' + key + '</code> = <code>' + value + '</code></li>';\n        }\n        content += '</ul></div>';\n      }\n      \n      // Add reload notice with server config info\n      content += '<div style=\"margin-top: 20px; padding: 15px; background: #fff3e0; border-radius: 4px; border-left: 4px solid #ff9800;\">';\n      content += '<strong>🔄 Try it:</strong> Reload the page (F5 or Cmd+R) - if the server is configured correctly, you\\'ll stay on this route!<br>';\n      content += '<small style=\"color: #666; margin-top: 8px; display: block;\">Note: This requires server-side configuration to serve spa-test.html for all /spa-test.html/* routes.</small>';\n      content += '</div>';\n      \n      // Update content\n      contentDiv.innerHTML = content;\n      document.title = 'SPA Test - ' + route.title;\n      \n      console.log('Navigated to:', pathname + search, 'Relative route:', relativePath, 'Query params:', queryParams);\n    }\n\n    // Handle link clicks (intercept and use History API)\n    document.addEventListener('click', function(e) {\n      // Check if clicked element is a SPA link\n      if (e.target.matches('.spa-link')) {\n        e.preventDefault();\n        const url = new URL(e.target.href);\n        \n        // Update browser history using pushState\n        window.history.pushState(\n          { pathname: url.pathname, search: url.search },\n          '',\n          url.pathname + url.search\n        );\n        \n        // Render the new route\n        renderRoute(url.pathname, url.search);\n      }\n    });\n\n    // Handle browser back/forward buttons (popstate event)\n    window.addEventListener('popstate', function(e) {\n      if (e.state) {\n        renderRoute(e.state.pathname, e.state.search);\n      } else {\n        // Fallback to current location\n        renderRoute(window.location.pathname, window.location.search);\n      }\n    });\n\n    // Initial render on page load\n    (function() {\n      const pathname = window.location.pathname;\n      const search = window.location.search;\n      \n      // Set initial state\n      window.history.replaceState(\n        { pathname: pathname, search: search },\n        '',\n        pathname + search\n      );\n      \n      renderRoute(pathname, search);\n      console.log('SPA loaded with History API routing. Current route:', pathname + search);\n    })();\n  </script>\n</body>\n</html>\n\n"
  },
  {
    "path": "test-server/unified/unified.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/amplitude.png\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Browser SDK Test</title>\n  </head>\n  <body>\n    <div id=\"app\">\n      Test page for Unified SDK\n    </div>\n    <script type=\"module\">  \n      import * as amplitudeUnified from '@amplitude/unified';\n      const { initAll, track, identify, Identify } = amplitudeUnified;\n      initAll(import.meta.env.VITE_AMPLITUDE_API_KEY);\n      initAll(import.meta.env.VITE_AMPLITUDE_API_KEY);\n      track('test event');\n      identify(new Identify().set('email', 'test@test.com'));\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/unified-script.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Unified Script Test</title>\n  <script type=\"module\">\n    const apiKey = import.meta.env.VITE_AMPLITUDE_API_KEY;\n    const script = document.createElement('script');\n    script.src = `https://cdn.amplitude.com/script/${apiKey}.js`;\n    document.head.appendChild(script);\n  </script>\n</head>\n<body>\n  <h1>Unified Script</h1>\n  <p>Open the browser DevTools Network tab to see all scripts loading.</p>\n</body>\n</html>\n"
  },
  {
    "path": "test-server/unminifier/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Stack Trace Unminifier</title>\n    <style>\n      * {\n        box-sizing: border-box;\n      }\n      \n      body {\n        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;\n        max-width: 900px;\n        margin: 0 auto;\n        padding: 20px;\n        background: #f5f5f5;\n      }\n      \n      h1 {\n        color: #333;\n        margin-bottom: 10px;\n      }\n      \n      .description {\n        color: #666;\n        margin-bottom: 20px;\n      }\n      \n      .input-section {\n        background: white;\n        padding: 20px;\n        border-radius: 8px;\n        box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n        margin-bottom: 20px;\n      }\n      \n      label {\n        display: block;\n        font-weight: 600;\n        margin-bottom: 8px;\n        color: #333;\n      }\n      \n      input[type=\"text\"] {\n        width: 100%;\n        padding: 12px;\n        font-size: 14px;\n        font-family: monospace;\n        border: 1px solid #ddd;\n        border-radius: 4px;\n        margin-bottom: 15px;\n      }\n      \n      input[type=\"text\"]:focus {\n        outline: none;\n        border-color: #4CAF50;\n        box-shadow: 0 0 0 2px rgba(76, 175, 80, 0.2);\n      }\n      \n      button {\n        background: #4CAF50;\n        color: white;\n        border: none;\n        padding: 12px 24px;\n        font-size: 16px;\n        border-radius: 4px;\n        cursor: pointer;\n        transition: background 0.2s;\n      }\n      \n      button:hover {\n        background: #45a049;\n      }\n      \n      button:disabled {\n        background: #ccc;\n        cursor: not-allowed;\n      }\n      \n      .result-section {\n        background: white;\n        padding: 20px;\n        border-radius: 8px;\n        box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n      }\n      \n      .result-section h2 {\n        margin-top: 0;\n        color: #333;\n        font-size: 18px;\n      }\n      \n      .result-item {\n        margin: 15px 0;\n        padding: 15px;\n        border-radius: 4px;\n        background: #f8f9fa;\n      }\n      \n      .result-item.success {\n        border-left: 4px solid #4CAF50;\n      }\n      \n      .result-item.error {\n        border-left: 4px solid #f44336;\n      }\n      \n      .result-label {\n        font-weight: 600;\n        color: #555;\n        margin-bottom: 5px;\n      }\n      \n      .result-value {\n        font-family: monospace;\n        word-break: break-all;\n        color: #333;\n      }\n      \n      .result-grid {\n        display: grid;\n        grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n        gap: 15px;\n      }\n      \n      .result-card {\n        background: #fff;\n        border: 1px solid #e0e0e0;\n        padding: 12px;\n        border-radius: 4px;\n      }\n      \n      .result-card .label {\n        font-size: 12px;\n        color: #888;\n        text-transform: uppercase;\n        margin-bottom: 4px;\n      }\n      \n      .result-card .value {\n        font-family: monospace;\n        font-size: 14px;\n        color: #333;\n        word-break: break-all;\n      }\n      \n      .error-message {\n        color: #c62828;\n        background: #ffebee;\n        padding: 15px;\n        border-radius: 4px;\n        margin-top: 10px;\n      }\n      \n      .empty-state {\n        text-align: center;\n        color: #888;\n        padding: 40px;\n      }\n      \n      .loading {\n        display: inline-block;\n        width: 20px;\n        height: 20px;\n        border: 2px solid #fff;\n        border-radius: 50%;\n        border-top-color: transparent;\n        animation: spin 1s linear infinite;\n        margin-right: 8px;\n        vertical-align: middle;\n      }\n      \n      @keyframes spin {\n        to { transform: rotate(360deg); }\n      }\n      \n      .example {\n        font-size: 12px;\n        color: #888;\n        margin-top: 5px;\n      }\n      \n      .example code {\n        background: #f0f0f0;\n        padding: 2px 6px;\n        border-radius: 3px;\n        font-family: monospace;\n      }\n\n      .copy-btn {\n        background: #2196F3;\n        padding: 6px 12px;\n        font-size: 12px;\n        margin-left: 10px;\n      }\n      \n      .copy-btn:hover {\n        background: #1976D2;\n      }\n      \n      .github-link {\n        display: inline-flex;\n        align-items: center;\n        background: #24292e;\n        color: white;\n        padding: 10px 16px;\n        border-radius: 6px;\n        text-decoration: none;\n        font-size: 14px;\n        font-weight: 500;\n        transition: background 0.2s;\n      }\n      \n      .github-link:hover {\n        background: #444d56;\n      }\n    </style>\n  </head>\n  <body>\n    <h1>Stack Trace Unminifier</h1>\n    <p class=\"description\">\n      Paste a minified stack trace line from Amplitude CDN and get the original source location.\n    </p>\n    \n    <div class=\"input-section\">\n      <label for=\"stacktrace-input\">Stack Trace Line</label>\n      <input \n        type=\"text\" \n        id=\"stacktrace-input\" \n        value=\"https://cdn.amplitude.com/libs/analytics-browser-2.33.5-min.js.gz:1:56244\"\n      />\n      <button id=\"unminify-btn\" onclick=\"unminify()\">Unminify</button>\n    </div>\n    \n    <div class=\"result-section\">\n      <h2>Result</h2>\n      <div id=\"result-container\">\n        <div class=\"empty-state\">\n          Enter a stack trace line above and click \"Unminify\" to see the original source location.\n        </div>\n      </div>\n    </div>\n\n    <script>\n      async function unminify() {\n        const input = document.getElementById('stacktrace-input');\n        const btn = document.getElementById('unminify-btn');\n        const container = document.getElementById('result-container');\n        const stacktraceLine = input.value.trim();\n        \n        if (!stacktraceLine) {\n          container.innerHTML = '<div class=\"error-message\">Please enter a stack trace line.</div>';\n          return;\n        }\n        \n        // Show loading state\n        btn.disabled = true;\n        btn.innerHTML = '<span class=\"loading\"></span>Processing...';\n        container.innerHTML = '<div class=\"empty-state\">Looking up source map...</div>';\n        \n        try {\n          const response = await fetch('/api/unminify', {\n            method: 'POST',\n            headers: { 'Content-Type': 'application/json' },\n            body: JSON.stringify({ stacktraceLine })\n          });\n          \n          const data = await response.json();\n          \n          if (data.success) {\n            const isExternal = data.typescript?.isExternal;\n            const isTypeScript = data.typescript?.isTypeScript;\n            const githubLink = data.typescript?.githubLink;\n            const sourceLabel = isExternal ? 'External Dependency' : (isTypeScript ? 'TypeScript Source' : 'Source');\n            container.innerHTML = `\n              <div class=\"result-item success\">\n                <div class=\"result-label\">${sourceLabel}</div>\n                <div class=\"result-grid\">\n                  <div class=\"result-card\" style=\"grid-column: 1 / -1;\">\n                    <div class=\"label\">File Path</div>\n                    <div class=\"value\" style=\"color: ${isExternal ? '#888' : '#2e7d32'}\">\n                      ${escapeHtml(data.typescript?.relativePath || 'N/A')}\n                    </div>\n                  </div>\n                  <div class=\"result-card\">\n                    <div class=\"label\">Line</div>\n                    <div class=\"value\">${data.original.line}</div>\n                  </div>\n                  <div class=\"result-card\">\n                    <div class=\"label\">Column</div>\n                    <div class=\"value\">${data.original.column}</div>\n                  </div>\n                  ${data.original.name ? `\n                  <div class=\"result-card\">\n                    <div class=\"label\">Symbol Name</div>\n                    <div class=\"value\">${escapeHtml(data.original.name)}</div>\n                  </div>\n                  ` : ''}\n                </div>\n                ${githubLink ? `\n                <div style=\"margin-top: 15px;\">\n                  <a href=\"${escapeHtml(githubLink)}\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"github-link\">\n                    <svg height=\"16\" width=\"16\" viewBox=\"0 0 16 16\" style=\"vertical-align: text-bottom; margin-right: 6px;\">\n                      <path fill=\"currentColor\" d=\"M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z\"></path>\n                    </svg>\n                    View on GitHub\n                  </a>\n                </div>\n                ` : ''}\n              </div>\n\n              <div class=\"result-item\" style=\"border-left: 4px solid #ff9800;\">\n                <div class=\"result-label\">Raw Source Map Entry</div>\n                <div class=\"result-grid\">\n                  <div class=\"result-card\" style=\"grid-column: 1 / -1;\">\n                    <div class=\"label\">Source Path (as in source map)</div>\n                    <div class=\"value\">${escapeHtml(data.original.source)}</div>\n                  </div>\n                </div>\n              </div>\n              \n              <div class=\"result-item\" style=\"border-left: 4px solid #2196F3;\">\n                <div class=\"result-label\">Minified Location</div>\n                <div class=\"result-grid\">\n                  <div class=\"result-card\">\n                    <div class=\"label\">URL</div>\n                    <div class=\"value\">${escapeHtml(data.minified.url)}</div>\n                  </div>\n                  <div class=\"result-card\">\n                    <div class=\"label\">Line</div>\n                    <div class=\"value\">${data.minified.line}</div>\n                  </div>\n                  <div class=\"result-card\">\n                    <div class=\"label\">Column</div>\n                    <div class=\"value\">${data.minified.column}</div>\n                  </div>\n                </div>\n              </div>\n              \n              <div class=\"result-item\" style=\"border-left: 4px solid #9e9e9e;\">\n                <div class=\"result-label\">Source Map URL</div>\n                <div class=\"result-value\"><a href=\"${escapeHtml(data.sourceMapUrl)}\" target=\"_blank\" rel=\"noopener noreferrer\">${escapeHtml(data.sourceMapUrl)}</a></div>\n              </div>\n            `;\n          } else if (data.sourceMapNotFound && data.instructions) {\n            container.innerHTML = `\n              <div class=\"result-item error\">\n                <div class=\"error-message\">${escapeHtml(data.error)}</div>\n                <div style=\"margin-top: 15px; padding: 15px; background: #fff3e0; border-radius: 4px; border-left: 4px solid #ff9800;\">\n                  <div style=\"font-weight: 600; margin-bottom: 10px; color: #e65100;\">\n                    ${escapeHtml(data.instructions.summary)}\n                  </div>\n                  <div style=\"font-weight: 600; margin-bottom: 8px; color: #333;\">To upload the source map:</div>\n                  <ol style=\"margin: 0; padding-left: 20px; font-family: monospace; font-size: 13px; line-height: 1.8;\">\n                    ${data.instructions.steps.map(step => `<li>${escapeHtml(step.substring(3))}</li>`).join('')}\n                  </ol>\n                </div>\n                ${data.sourceMapUrl ? `\n                <div style=\"margin-top: 10px; font-size: 12px; color: #666;\">\n                  Expected source map URL: <code>${escapeHtml(data.sourceMapUrl)}</code>\n                </div>\n                ` : ''}\n              </div>\n            `;\n          } else {\n            container.innerHTML = `\n              <div class=\"result-item error\">\n                <div class=\"error-message\">${escapeHtml(data.error)}</div>\n                ${data.sourceMapUrl ? `\n                <div style=\"margin-top: 10px; font-size: 12px; color: #666;\">\n                  Source map URL: <code>${escapeHtml(data.sourceMapUrl)}</code>\n                </div>\n                ` : ''}\n              </div>\n            `;\n          }\n        } catch (error) {\n          container.innerHTML = `\n            <div class=\"result-item error\">\n              <div class=\"error-message\">Network error: ${escapeHtml(error.message)}</div>\n            </div>\n          `;\n        } finally {\n          btn.disabled = false;\n          btn.textContent = 'Unminify';\n        }\n      }\n      \n      function escapeHtml(text) {\n        if (!text) return '';\n        const div = document.createElement('div');\n        div.textContent = text;\n        return div.innerHTML;\n      }\n      \n      // Allow pressing Enter to submit\n      document.getElementById('stacktrace-input').addEventListener('keypress', (e) => {\n        if (e.key === 'Enter') {\n          unminify();\n        }\n      });\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/video-analytics/track-embedded-video.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <title>Track Embedded Mux Video Test</title>\n  </head>\n  <body>\n    <h1>Track Embedded Mux Video Test</h1>\n    <iframe\n      id=\"player\"\n      src=\"https://player.mux.com/dE02GfTAlJD4RcqNAlgiS2m00LqbdFqlBm?&metadata-video-title=All about thumbnails&metadata-user-id=user-1138\"\n      style=\"width: 100%; border: none; aspect-ratio: 16/9;\"\n      allow=\"autoplay; encrypted-media; picture-in-picture;\"\n      allowfullscreen\n    ></iframe>\n    <button id=\"stop-video\">Stop Capturing</button>\n    <script src=\"https://cdn.jsdelivr.net/npm/player.js@latest/dist/player.min.js\"></script>\n    <script type=\"module\">\n      import * as amplitude from '@amplitude/analytics-browser';\n\n      // generate a View Session ID to be used for Mux and Amplitude\n      // so that views can be linked together\n      const muxViewSessionId = Date.now();\n\n      // the User ID of the logged-in user (if available)\n      // (do not use an ID with PII)\n      const userId = 'random-user-id';\n      \n      const iframe = document.getElementById('player');\n      const player = new playerjs.Player(iframe);\n      \n      // AMPLITUDE VIDEO ANALYTICS\n\n      // initialize Amplitude\n      amplitude.setUserId(userId);\n      amplitude.init(import.meta.env.VITE_AMPLITUDE_API_KEY, {\n        fetchRemoteConfig: false,\n        autocapture: false,\n      }).promise.then(() => {\n        // TODO: see if it's possible to update the player data with Amplitude data\n        // player.updateData({\n        //   custom_1: amplitude.getDeviceId(),\n        //   custom_2: amplitude.getSessionId(),\n        // });\n      });\n\n      // capture analytics events for Video Start and Video Stop\n      const stopVideoCapture = amplitude.trackVideo(amplitude, player, {\n        vendor: 'mux',\n        extraEventProperties: {\n          // capture this so client and server events can be linked together\n          mux_view_session_id: muxViewSessionId,\n        },\n      });\n\n      document.getElementById('stop-video').addEventListener('click', () => {\n        stopVideoCapture();\n      });\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "test-server/video-analytics/track-html-video.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <title>Track HTML Video Test</title>\n  </head>\n  <body>\n    <video id=\"video\" controls width=\"640\" preload=\"metadata\" metadata-video-title=\"My Video\" metadata-video-id=\"video-123\">\n      <source src=\"https://stream.mux.com/iBXEG00ifc9cPSv005eKgQ01g3w42LUGdlFWlmeosVuGfU.m3u8\" type=\"video/mp4\">\n      Your browser does not support the video tag.\n    </video>\n    <button id=\"stop-video\">Stop Capturing</button>\n    <script src=\"https://cdn.jsdelivr.net/npm/@mux/mux-player\" defer></script>\n    <script src=\"https://cdn.jsdelivr.net/npm/mux-embed@latest/dist/mux.min.js\"></script>\n    <h1>Track HTML Video Test</h1>\n    <script type=\"module\">\n      import * as amplitude from '@amplitude/analytics-browser';\n\n      // generate a View Session ID to be used for Mux and Amplitude\n      // so that views can be linked together\n      const muxViewSessionId = Date.now();\n\n      // the User ID of the logged-in user (if available)\n      // (do not use an ID with PII)\n      const userId = 'random-user-id';\n      \n      const video = document.getElementById('video');\n      \n      // MUX VIDEO MONITORING\n      // monitor the video for Mux analytics\n      mux.monitor(video, {\n        data: {\n          view_session_id: muxViewSessionId,\n          viewer_user_id: userId,\n        },\n      });\n\n      // AMPLITUDE VIDEO ANALYTICS\n\n      // initialize Amplitude\n      amplitude.setUserId(userId);\n      amplitude.init(import.meta.env.VITE_AMPLITUDE_API_KEY, {\n        fetchRemoteConfig: false,\n        autocapture: false,\n      }).promise.then(() => {\n        mux.updateData(video, {\n          custom_1: amplitude.getDeviceId(),\n          custom_2: amplitude.getSessionId(),\n        });\n      });\n\n      // capture analytics events for Video Start and Video Stop\n      const stopVideoCapture = amplitude.trackVideo(amplitude, video, {\n        vendor: 'mux',\n        extraEventProperties: {\n          mux_view_session_id: muxViewSessionId,\n        },\n      });\n\n      document.getElementById('stop-video').addEventListener('click', () => {\n        stopVideoCapture();\n      });\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"alwaysStrict\": false,\n    \"declaration\": true,\n    \"declarationMap\": true,\n    \"downlevelIteration\": true,\n    \"inlineSources\": true,\n    \"importHelpers\": true,\n    \"lib\": [\"es2021\", \"dom\"],\n    \"module\": \"es2020\",\n    \"moduleResolution\": \"node\",\n    \"noEmitHelpers\": true,\n    \"noFallthroughCasesInSwitch\": true,\n    \"noImplicitAny\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"pretty\": true,\n    \"sourceMap\": true,\n    \"resolveJsonModule\": true,\n    \"strict\": true,\n    \"strictBindCallApply\": true,\n    \"target\": \"es5\",\n    \"types\": [\"jest\", \"node\"],\n  }\n}\n"
  },
  {
    "path": "typedoc.json",
    "content": "{\n  \"entryPoints\": [\n    \"packages/analytics-browser\",\n    \"packages/analytics-node\"\n  ],\n  \"entryPointStrategy\": \"packages\",\n  \"logLevel\": \"Error\",\n  \"name\": \"Amplitude SDK\",\n  \"out\": \"docs\",\n  \"readme\": \"./README.md\"\n}\n"
  },
  {
    "path": "vite.config.js",
    "content": "// vite.config.js\nimport { defineConfig } from 'vite';\nimport path from 'path';\nimport fs from 'fs';\nimport glob from 'fast-glob';\nimport { createMockApi } from './test-server/mock-api.js';\n\nconst packagesDir = path.resolve(__dirname, 'packages');\nconst testServerDir = path.resolve(__dirname, 'test-server');\n\nconst ignorePkg = (pkgName) => {\n  return pkgName.startsWith('.') ||\n    pkgName === 'analytics-browser-test' ||\n    pkgName === 'analytics-node-test';\n}\n\nfunction htmlEntriesPlugin(pattern = '**/*.html', { cwd }) {\n  return {\n    name: 'vite-html-entries',\n    config: () => ({\n      build: {\n        rollupOptions: {\n          input: Object.fromEntries(\n            require('fast-glob').sync(pattern, { cwd }).map(f => [\n              f.replace(/\\.html$/, ''),              // key without \".html\"\n              require('path').join(cwd, f)           // absolute file path\n            ])\n          )\n        }\n      }\n    })\n  };\n}\n\nfunction gzipServePlugin() {\n  return {\n    name: 'gzip-serve',\n    configureServer(server) {\n      server.middlewares.use((req, res, next) => {\n        if (req.url && req.url.endsWith('.gz')) {\n          // Set Content-Encoding header for gzip files\n          res.setHeader('Content-Encoding', 'gzip');\n          \n          // Determine the original content type by removing .gz extension\n          const originalPath = req.url.replace(/\\.gz$/, '');\n          if (originalPath.endsWith('.js')) {\n            res.setHeader('Content-Type', 'application/javascript');\n          } else if (originalPath.endsWith('.css')) {\n            res.setHeader('Content-Type', 'text/css');\n          } else if (originalPath.endsWith('.html')) {\n            res.setHeader('Content-Type', 'text/html');\n          } else if (originalPath.endsWith('.json')) {\n            res.setHeader('Content-Type', 'application/json');\n          } else {\n            res.setHeader('Content-Type', 'application/octet-stream');\n          }\n          \n          // Add Vary header to indicate that the response varies by Accept-Encoding\n          res.setHeader('Vary', 'Accept-Encoding');\n        }\n        next();\n      });\n    }\n  };\n}\n\nfunction fileListingPlugin() {\n  return {\n    name: 'file-listing',\n    configureServer(server) {\n      server.middlewares.use('/api/list-files', async (req, res) => {\n        try {\n          const files = await glob('**/*.html', {\n            cwd: testServerDir,\n            absolute: false,\n            ignore: ['**/dist/**']\n          });\n          \n          const fileList = files.map(file => ({\n            name: path.basename(file, '.html'),\n            path: '/' + file,\n          }));\n\n          res.setHeader('Content-Type', 'application/json');\n          res.end(JSON.stringify(fileList));\n        } catch (error) {\n          console.error('Error listing files:', error);\n          res.statusCode = 500;\n          res.end(JSON.stringify({ error: 'Failed to list files' }));\n        }\n      });\n    }\n  };\n}\n\nfunction spaRoutingPlugin() {\n  return {\n    name: 'spa-routing',\n    configureServer(server) {\n      server.middlewares.use((req, res, next) => {\n        // Handle SPA routes - serve spa-test.html for all /spa-test.html/* routes\n        if (req.url && req.url.startsWith('/spa-test.html/')) {\n          req.url = '/spa-test.html';\n        }\n        next();\n      });\n    }\n  };\n}\n\nconst amplitudeAliases = fs.readdirSync(packagesDir).reduce((aliases, pkgName) => {\n  const fullPath = path.join(packagesDir, pkgName);\n  if (ignorePkg(pkgName)) {\n    return aliases;\n  }\n  const key = `@amplitude/${pkgName}`;\n  aliases[key] = fullPath;\n  return aliases;\n}, {});\n\nexport default defineConfig({\n  envDir: path.resolve(__dirname),\n  root: testServerDir,\n  publicDir: packagesDir,\n  resolve: {\n    alias: amplitudeAliases\n  },\n  server: {\n    host: process.env.SSH ? 'local.website.com' : undefined,\n    https: process.env.SSH ? {\n      key: fs.readFileSync(path.resolve(process.env.HOME, 'certs/local-website/key.pem')),\n      cert: fs.readFileSync(path.resolve(process.env.HOME, 'certs/local-website/cert.pem')),\n    } : undefined,\n    fs: {\n      allow: [\n        packagesDir,\n        testServerDir,\n      ]\n    },\n    watch: {\n      usePolling: true,\n      interval: 100,\n      ignored: ['**/node_modules/**', '**/dist/**'],\n    },\n  },\n  preview: {\n    port: 5173,\n    host: true,\n  },\n  plugins: [\n    htmlEntriesPlugin('**/*.html', { cwd: path.resolve(__dirname, 'test-server') }),\n    gzipServePlugin(),\n    fileListingPlugin(),\n    spaRoutingPlugin(),\n    createMockApi(),\n  ],\n});\n"
  }
]